fluttercommunity / redux.dart

Redux for Dart
https://pub.dev/packages/redux
MIT License
515 stars 61 forks source link

should compare by hashCode. #48

Closed phamnhuvu-dev closed 5 years ago

phamnhuvu-dev commented 5 years ago

We need to receive changed state when update collection variables(List, Map, .v.v...) same reference. All are ok if I clone collection variables are like List.from() but the complex time is O(n). It isn't good for the performance of large collection variables

So I get hashCode before state pass to reducers then compares with new hashCode after update collection variables.

Please check my repo to see different between redux: 3.0.0 and my contribution.

Check redux:3.0.0 please comment dependency_overrides then run flutter packages get Check my contribution please uncomment dependency_overrides then run flutter packages get

https://github.com/phamnhuvu-dev/flutter_card_list_redux

phamnhuvu-dev commented 5 years ago

@johnpryan Please help me review it.

johnpryan commented 5 years ago

I don't think this package should assume how users want to compare state objects. If this is something you need, why not compare using the hash code in your == method?

phamnhuvu-dev commented 5 years ago

why not compare using the hash code in your == method?

@johnpryan I have an example with the state have a list variable:

import 'package:equatable/equatable.dart';
class A extends Equatable {
  final List<int> list;

  A({this.list}) : super([list]);

  A copyWith({List<int> list}) {
    return A(list: list ?? this.list);
  }
}

A reducerUpdateList_1(A state) {
  // Update list
  List<int> list = state.list;
  list.add(10);
  return state.copyWith(list: list);
}

A reducerUpdateList_2(A state) {
  // Update list from new List is created by `List.from`
  List<int> list = List.from(state.list);
  list.add(10);
  return state.copyWith(list: list);
}

My expect is after list updated something in its an element, The compare return false without creating new instance list..

Compare by "==" operator

void main() {
  A _state1 = A(list: List());
  final state1 = reducerUpdateList_1(_state1);

  print(_state1 == state1); // return true;

  A _state2 = A(list: List());
  final state2 = reducerUpdateList_2(_state2); // Create new List by List.from()

  print(_state2 == state2); // return false;
}

Compare by hashCode

void main() {
  A _state1 = A(list: List());
  final oldHashCode = _state1.hashCode;
  final state1 = reducerUpdateList_1(_state1);

  print(oldHashCode == state1.hashCode); // return false;
}

Benchmark between Compare by "==" operator with Create new List by List.from() and Compare by hashCode

// A list 100000000 item
List<int> getList() {
  List<int> list = List();
  for (int i = 0; i < 100000000; i++) {
    list.add(i);
  }
  return list;
}

void main() {
  A _state1 = A(list: getList());

  // Start time
  int time1 = getCurrentTime();
  final oldHashCode = _state1.hashCode;
  final state1 = reducerUpdateList_1(_state1);

  print(oldHashCode == state1.hashCode); // return false;

  int time2 = getCurrentTime();
  print(time2 - time1);

  A _state2 = A(list: getList());

  // Start time
  int time3 = getCurrentTime();
  final state2 = reducerUpdateList_2(_state2);

  print(_state2 == state2); // return false;

  int time4 = getCurrentTime();
  print(time4 - time3);
} 

The time check different by hashCode: ~1600 The time check different by creating new List: ~3700

phamnhuvu-dev commented 5 years ago

Override hashCode method: https://github.com/felangel/equatable/blob/master/lib/src/equatable_utils.dart#L3-L24

phamnhuvu-dev commented 5 years ago

I updated Benchmark between Compare by "==" operator with Create new List by List.from() and Compare by hashCode. @johnpryan Please help me review it.

johnpryan commented 5 years ago

It looks like package:equatable overrides == and =hashCode. If you are seeing better performance comparing hashCodes you could just compare hashCodes that in your == method instead.


operator ==(Object other) {
  return other.hashCode == hashCode;
}