avoid-implementing-value-types

Same as avoid_implementing_value_types in Dart lints

Group
Style
Path
lint/style/avoid-implementing-value-types
Default
Off, opt in
Origin
Dart lints
Rule
72 of 512

Flags implements of a class that overrides ==.

A class that overrides == is a value type: its equality depends on private state and invariants that an implementing class cannot see. Implementing its interface yields an object that claims to be equal-comparable with the original but cannot honor that contract, so == becomes asymmetric. Extend the value type, or compose it, instead of implementing it.

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;
}

class CustomSize implements Size { ... } // flagged

Only class declarations are checked. An inherited or abstract ==, including one supplied by a mixin, counts when its declaring library is not dart:core. Unresolved external interfaces remain silent.

Invalid

example.dartdart
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;
}

class CustomSize implements Size {
  @override
  int get inBytes => 0;
}

// `==` inherited from a superclass still makes it a value type.
class Kilobytes extends Size {
  const Kilobytes(int kb) : super(kb * 1024);
}

class FakeKilobytes implements Kilobytes {
  @override
  int get inBytes => 1024;
}

class Other {}

class Both implements Other, Size {
  @override
  int get inBytes => 1;
}

mixin SizeLike implements Size {}

enum Unit implements Size {
  byte;

  @override
  int get inBytes => 1;
}

abstract class Measured implements Kilobytes {}

abstract class Comparable2 {
  @override
  bool operator ==(Object other);
}
class Impl implements Comparable2 {}

mixin Equality {
  @override
  bool operator ==(Object other) => true;
}
class Point implements Equality {}
Classes that override `==` should not be implemented.
11
12class CustomSize implements Size {
Classes that override `==` should not be implemented.
21
22class FakeKilobytes implements Kilobytes {
Classes that override `==` should not be implemented.
28
29class Both implements Other, Size {
Classes that override `==` should not be implemented.
42
43abstract class Measured implements Kilobytes {}
Classes that override `==` should not be implemented.
48}
49class Impl implements Comparable2 {}
Classes that override `==` should not be implemented.
54}
55class Point implements Equality {}

Valid

example.dartdart
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;
}

// Extending a value type is fine.
class Kilobytes extends Size {
  const Kilobytes(int kb) : super(kb * 1024);
}

// Implementing a class that keeps identity equality is fine.
abstract class Shape {
  double get area;
}

class Square implements Shape {
  @override
  double get area => 1;
}


// SDK types keep the platform's `==`.
class MyException implements Exception {}

// Unresolved interfaces stay silent.
class Remote implements SomeUnknownType {}

// Only class declarations participate in the official lint.
mixin SizeInterface implements Size {}
enum SizeEnum implements Size {
  byte;
  @override
  int get inBytes => 1;
}

Configure avoid-implementing-value-types

Set its severity in falcon.json. See the configuration guide.

falcon.jsonjson
{
  "linter": {
    "rules": {
      "style": {
        "avoid-implementing-value-types": "error"
      }
    }
  }
}

Or silence one occurrence with a suppression comment; the reason is required.

example.dartdart
// falcon-ignore lint/style/avoid-implementing-value-types: <reason>