-
Notifications
You must be signed in to change notification settings - Fork 214
[extension-types] Should an explicit extension type be able to "override" members of Object?
?
#1462
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
That was not the entire rationale. As you write, the same could be said for any extension member with the same name as a member of its The real reason is that members of That is also the issue here: extension Money on int {
String toString() => this < 0 ? "(${-this})" : this.toString();
}
void main() {
Money e = -42;
print(e);
print("$e");
print(e.toString());
} Will these
If the The only way to win is not to play. The risk of user confusion is an argument against allowing It's plainly impossible to allow (Overriding Nits: int i = 42;
i.isOdd; // Error, `E` does not allow for implicit invocations. It's not an error because
I'd expect an explicitly declared member to automatically hide any instance member which isn't explicitly shown. extension OpaqueString on String hide length, operator[] {
...
OpaqueIndex indexOf(Pattern pattern, [int start = 0]) { .... }
...
} and then also have to add a |
About this: E2 x = 10;
print(x.toString()); // "Something"
print(x); // print 10 @tatumizer wrote:
This kind of confusion is certainly the main reason why we would not want to have a member name
Later, @lrhn writes: extension Money on int {
String toString() => this < 0 ? "(${-this})" : this.toString();
}
void main() {
Money e = -42;
print(e);
print("$e");
print(e.toString());
}
The proposal only allows an extension member named extension type Money on int {
String toString() => this < 0 ? "(${-this})" : this.toString();
} With this declaration, I agree that
The language specification explicitly says that If we consider that to be a syntactic desugaring step then it is not unreasonable to say that It is still true that So
We could then simply allow |
Object?
?Object?
?
One might argue that the boxed entity should support overriding any and all of the So do we want to introduce a mechanism that allows us to write declarations for extension type Money on int {
} class {
String toString() => this < 0 ? "(${-this})" : this.toString();
void whatEverExtrasYouWantInTheBoxedObject() {}
} |
Indeed! ;-) But this kind of scenario is exactly the reason why I think it is so important to make sure the distinction between a dynamic mechanism like classes and methods is kept visibly distinct from a static mechanism like extensions (extension methods as well as extension types). I do not think it's going to get easier to handle if we try to hide that distinction by using implicit coercions all over the place. The point is performance. If you're willing to pay the time and space needed to create a real wrapper object then you will get a more robust entity to work on, no question about that. But if you want to impose a certain discipline on the use of some existing objects (especially a whole object graph where you wouldn't want to wrap each object as you traverse the structure) then the extension types provide a way to do it. |
Closing: We decided that extension types should not have the ability to redeclare the five members of |
Uh oh!
There was an error while loading. Please reload this page.
An extension declaration, as supported by Dart 2.6 and up, makes it an error for a member to have the same name as a member of
Object?
. The rationale is that extension methods are generally invoked implicitly, and atoString
on an extensionE
wouldn't ever be called because every object has a statically knowntoString
instance method, and instance methods always win.(Exception: we could do
E(o).toString()
to invoke an extension member namedtoString
explicitly, but that was considered too inconvenient to have in practice).However, extension types (as proposed in #1452, cf. #1426) include a variant called 'explicit extension types', and they have the property that implicit invocations are impossible.
This makes it possible and practical to declare and use extension members even in the case where their name is already the name of an instance member. For example,
E
can "override"isEven
on anint
. This would be a very brittle design with the existing extension methods feature, because we would have to remember to invokeisEven
explicitly (likeE(i).isEven
, noti.isEven
) all the time, and if we forget it somewhere then we'll (silently) get the instance member instead. But when we're using an explicit extension type we're forced to useE
as the static type of the receiver, and then we don't have to remember to do anything special in order to invokeisEven
(as an extension method).This also means that we could allow explicit extensions to declare members with the same name as members of
Object?
:As we can see, this allows an explicit extension type to "override" even members of
Object?
, as long as the static type of the receiver is the extension type.(It is required that we include the
hide
clause to hidetoString
, because the members ofObject?
are made available in the interface of the extension type by default, and we need to remove the one fromObject?
to avoid a name clash).However, even though both
isEven
andtoString
can be "overridden" (in quotes because it's resolved statically), we can use a cast to access the underlying object under its run-time type (or a supertype thereof), and then we'll have standard object-oriented late binding, and we'll call the most specific instance member for the given run-time type.We could make extension types even more strict and prohibit all declarations of members whose basename is already the basename of a member of the on-type (but that would be a breaking change for existing extension methods), in which case we wouldn't have this dichotomy of "if this static type run the extension method, otherwise run the instance method".
We could also keep the permission to declare instance members that "statically override" instance members. But in this case it seems inconsistent if we make an exception for members of
Object?
.The current proposal allows extension members that "statically override" members of the on-type, including the ones that are also members of
Object?
.The text was updated successfully, but these errors were encountered: