-
Notifications
You must be signed in to change notification settings - Fork 213
Self type #3025
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
An example of this in production is https://master-api.flutter.dev/flutter/material/ThemeExtension-class.html |
Another, this one from the Dart SDK: https://master-api.flutter.dev/flutter/dart-collection/LinkedListEntry-class.html |
The DevTools code also uses this pattern: https://github.com/flutter/devtools/blob/master/packages/devtools_app/lib/src/shared/primitives/trees.dart |
The language team has had some discussions about this feature a while ago. I think it shouldn't be too hard to support it in Dart. The notion of Self types is traditionally considered tricky (for example, Subtyping is not a good "Match" for However, Dart already routinely handles types with a similar nature: Dynamically checked covariant type variables. So we can (and we'll have to) insert dynamic checks in almost all situations where |
I actually don't think a But outside of this it feels like a footgun wrt covariance, and the lack of type parameters in this situation prevents safe usage. What even is To avoid confusion it's better to pass |
Could an assert possibly catch this? Like: abstract class Foo<Self extends Foo<Self>> {
Foo() {
assert(Self == runtimeType);
}
} This doesn't work with const constructors though |
Another place where a pattern that would benefit from |
What about when abstract class Clone {
Self clone();
}
class A implements Clone { ... } // clone returns A
class B extends A {} // clone still returns A, but it needs to return B For Do we have any option other than rejecting inheriting members that use |
Exactly. It is not a common concept, but it should not be hard to implement: An instance member may or may not be inherited by subclasses, in which case a member may be considered unimplemented even though there is a superclass which has an implementation. It is then an error for that subclass to be concrete, unless it declares an overriding implementation (in this case: that returns It would make sense to require a special modifier on those non-inheritable members, and it would then be a compile-time error if a member has return type By the way, the body of a class that uses the So it is certainly not the same thing to have support for |
I'm not sure why you ask "other than rejecting". Rejecting is exactly the right answer for the use cases where the With the current state of things, I imagine most people will start marking |
No need for extension LetNullable<T extends Object> on T? {
R? let<R>(R function(T) f) => switch (this) {
var v? => f(v),
_ => null,
}; |
Sorry... I deleted my original comment because I posted it mistakenly. I actually did find a solution, and it looks very similar to yours. Today I learned Dart is cool because you can write extensions for generic types! Whaaaat? extension ObjectLet<ObjT extends Object> on ObjT {
RetT? let<RetT>(RetT Function(ObjT) application) => application(this);
} You actually don't need to even pass the non-null Anyway, just for reference (since you're just replying to the void now), what I posted before was a "possible use case" of extension ObjectLet on Object? {
RetT? use<RetT>(RetT Function(Self) application) =>
this != null ? application(this) : null;
} |
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:
Now subclasses have to specify themselves as the type argument:
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 makeBazFoo
and make a mistake and not notice for a while:Use case
I use this for classes that declare an API that I want to use in other generic contexts, e.g.:
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.)
The text was updated successfully, but these errors were encountered: