Contents

avoid_implementing_value_types

Contents

Don't implement classes that override ==.

This rule is available as of Dart 2.1.

Details

#

DON'T implement classes that override ==.

The == operator is contractually required to be an equivalence relation; that is, symmetrically for all objects o1 and o2, o1 == o2 and o2 == o1 must either both be true, or both be false.

NOTE: Dart does not have true value types, so instead we consider a class that implements == as a proxy for identifying value types.

When using implements, you do not inherit the method body of ==, making it nearly impossible to follow the contract of ==. Classes that override == typically are usable directly in tests without creating mocks or fakes as well. For example, for a given class Size:

dart
class Size {
  final int inBytes;
  const Size(this.inBytes);

  @override
  bool operator ==(Object other) => other is Size && other.inBytes == inBytes;

  @override
  int get hashCode => inBytes.hashCode;
}

BAD:

dart
class CustomSize implements Size {
  final int inBytes;
  const CustomSize(this.inBytes);

  int get inKilobytes => inBytes ~/ 1000;
}

BAD:

dart
import 'package:test/test.dart';
import 'size.dart';

class FakeSize implements Size {
  int inBytes = 0;
}

void main() {
  test('should not throw on a size >1Kb', () {
    expect(() => someFunction(FakeSize()..inBytes = 1001), returnsNormally);
  });
}

GOOD:

dart
class ExtendedSize extends Size {
  ExtendedSize(int inBytes) : super(inBytes);

  int get inKilobytes => inBytes ~/ 1000;
}

GOOD:

dart
import 'package:test/test.dart';
import 'size.dart';

void main() {
  test('should not throw on a size >1Kb', () {
    expect(() => someFunction(Size(1001)), returnsNormally);
  });
}

Usage

#

To enable the avoid_implementing_value_types rule, add avoid_implementing_value_types under linter > rules in your analysis_options.yaml file:

analysis_options.yaml
yaml
linter:
  rules:
    - avoid_implementing_value_types