Description
It'd be nice if a type could reliably refer to an implicit generic type argument representing the type of the instance.
Today you have to do something like:
abstract class Foo<Self extends Foo<Self>> { }
Now subclasses have to specify themselves as the type argument:
class BarFoo extends Foo<BarFoo> { }
This leads to some weird errors when people aren't explicit about types (see dart-lang/sdk#52204).
It also isn't completely safe. For example, I could copy and paste BarFoo
to make BazFoo
and make a mistake and not notice for a while:
class BazFoo extends Foo<BarFoo> { } // no error, but the Self type is wrong
Use case
I use this for classes that declare an API that I want to use in other generic contexts, e.g.:
@immutable
abstract class Status<S extends Status<S>> {
const Status();
S copyWith();
S lerpTo(S other, double t);
bool matches(S other);
@override
operator ==(Object other) {
if (other.runtimeType != runtimeType)
return false;
return matches(other as S);
}
}
Now I have a type that I know I can clone, lerp, and compare, and so algorithms that are generic over that API can work on all the various subclasses of this type without needing to worry about the details.
(Obviously, true metaclasses would make this even more powerful, but I think this stands alone even without metaclasses.)