-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Self type leads to typing problems #60088
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
Summary: Self-referential type parameters in Dart cause type inference issues. Using |
This is all working as specified and intended. abstract class Foo<Self extends Foo<Self>> {
final bool property;
const Foo(this.property);
Self copyWith(bool property);
Self toggle() {
return copyWith(!property);
}
}
class Bar extends Foo<Bar> {
const Bar(super.property);
@override
Bar copyWith(bool property) {
return Bar(property);
}
}
class Baz extends Foo<Baz> {
const Baz(super.property);
@override
Baz copyWith(bool property) {
return Baz(property);
}
}
var b = true; // Random.
void main() {
// Note that the type annotation `Foo` means `Foo<Foo<dynamic>>`, no
// matter how it's initialized. So let's write that out explicitly.
// With that, you can certainly have multiple subclasses of `Foo`
// and abstract over them using a type like `Foo<Foo<dynamic>>`.
Foo<Foo<dynamic>> someFoo = b ? const Bar(true) : Baz(false);
// But you can't assign a `Foo<dynamic>` to a variable of type
// `Foo<Foo<dynamic>>`, because `dynamic` must then be a subtype
// of `Foo<dynamic>` (which it isn't). So this is an error:
someFoo = someFoo.toggle();
} Here is the other example, adjusted similarly: abstract class Foo<Self extends Foo<Self>> {
final bool property;
const Foo(this.property);
Self copyWith(bool property);
Self toggle() {
return copyWith(!property);
}
}
class Bar extends Foo<Bar> {
const Bar(super.property);
@override
Bar copyWith(bool property) {
return Bar(property);
}
}
void main() {
Bar someBar = const Bar(true);
someBar = someBar.toggle();
} In this case (and in general, actually) you should change the return type of the methods from This means that it's just a needless waste of typing precision to specify the return type Finally, note that you're using an F-bounded type variable which is not a complete and faithful replacement for a real Self type. (In particular, the pseudo-variable |
The advantage I found in using I don't understand why it would be a needless waste of typing precision if it solves this problem. |
Uh oh!
There was an error while loading. Please reload this page.
When trying to define a self type like this
class Foo<Self extends Foo<Self>>
it is unclear if the methods of the class that return instances of itself should useSelf
orFoo<Self>
as the return type.Self
as the return type might cause issues when you need to use the typeFoo
. This will happen when you know only at runtime which subclass ofFoo
is used.The static analysis fails because when applying the
toggle
method the type becomesFoo<dynamic>
instead ofFoo<Foo<dynamic>>
.Foo<Self>
as the return type doesn't mix well with using the name of the subclass as the type. In this example, it would preferable to be able to use the typeBar
for the variablesomeFoo
but this is not possible as thetoggle
method has a return typeFoo<Bar>
.The static analysis fails because
someFoo.toggle()
uses the typeFoo<Bar>
and the variablesomeFoo
is defined with typeBar
.Related to dart-lang/language#3025
The text was updated successfully, but these errors were encountered: