Boilerplate mixin for poor man's hashCode, operator== and toString methods #19181
Labels
area-core-library
SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries.
closed-not-planned
Closed as we don't intend to take action on the reported issue
type-enhancement
A request for a change that isn't a bug
This issue was originally filed by ochafik@google.com
Implementing boilerplate methods is cumbersome and error-prone, despite nice building blocks in quiver-dart and collection/equality.dart.
Relying on IDEs to generate them doesn't quite solve code bloat / maintenance issues, and relying on protobufs is a bit overkill / not idiomatic.
I propose to add a very simple
Boilerplate
mixin that implements these methods using collection/equality.dart on a list of public field values (see boilerplate.dart in attachment).The list of field values can either be inferred using mirrors, or provided explicitly with a dedicated override (this override being shorter than the methods it helps implement).
This proposal addresses the general bean-like boilerplate but could be optimized for immutable types (Issue #10551, Issue #501) by caching the hashCode (either explicitly or by detecting the absence of setters).
Long story short, here's how Boilerplate could be used:
With mirrors:
@MirrorsUsed(targets: const[Foo, Bar], override: "*")
import 'dart:mirrors';
import 'boilerplate.dart';
class Bar extends Boilerplate {
final int i;
Bar(this.i);
}
class Foo extends Bar {
final int j;
final String s;
Foo(int i, this.j, this.s): super(i);
}
print(new Bar(1)); // "Bar { i: 1 }"
print(new Foo(1, 2, "3")); // "Foo { i: 1, j: 2, s: 3 }"
assert(new Bar(1) == new Bar(1));
assert(new Bar(1) != new Bar(2));
Without mirrors:
import 'boilerplate.dart';
class Bar extends Boilerplate {
final int i;
Bar(this.i);
@override get fields => { "i": i };
@override get className => "Bar";
}
class Foo extends Bar {
final int j;
final String s;
Foo(int i, this.j, this.s): super(i);
@override get fields => { "i": i, "j": j, "s": s };
@override get className => "Foo";
}
Note that Boilerplate can be safely mixed in at any level:
class A extends Boilerplate {}
class B extends A with Boilerplate {}
I understand this doesn't solve all the potential use cases, but I think it's acceptable enough to make it to some pub package, for users who agree with the following explicit limitations:
Attachment:
boilerplate.dart (6.25 KB)
The text was updated successfully, but these errors were encountered: