-
Notifications
You must be signed in to change notification settings - Fork 1.7k
What is the intended behavior of C.toString() where C is a class? #26024
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
I think you are right. The sentence that avoids looking up static members on
might need to be extended to handle the other direction too:
This would avoid |
The Type objects are too complicated. They are first class objects that have different rules for method lookup depending on their syntactic context. My reading with your suggested amendment is that If there's a literal in a context where it's followed by a dot (.) or hash (#) then the actual methods of the Type object cannot be found by lookup but the synthetic forwarding methods can. If an expression in any other context evaluates to a Type object, then the actual methods will be found by lookup and the synthetic methods will not. That's a strange Dart object! It suggests to me that in all the cases where the lookup finds the synthetic forwarding methods and not the actual methods, you don't really want the Type object at all. To me, it's much cleaner to just say that in e.x where e is a type literal, it's a static invocation, the subexpression e is unevaluated, and the static method is looked up in the class e. That matches what an implementation would do because it's simpler in terms of the object model (objects just obey the normal lookup rules), safer (there's no possibility that the synthetic methods leak where they shouldn't because they don't exist), and no more complicated in terms of implementation (the spec requires you to peek at the syntactic form of e in e.x anyway, either to lookup up static method x in the class e, my suggestion, or else to use special lookup rules to lookup x in the Type reifying class e, currently). The spec reads like it's specifying an implementation of something that's unobservable, and that nobody would implement that way. I don't think the spec is giving a simpler model for programmers, either. Suggestion: simplify static lookup so it happens on classes, not reified type objects. Remove the synthetic methods from Type objects. There is a related problem with instances of Type in generalized closurization. C#m evaluates C to an object o which is an instance of Type, binds a fresh variable u to o and then produces a closure (args...) { return u.m(args...); }. But when the closure is applied lookup of the method m in the type object bound to u finds a method that forwards to a static method, so lookup fails because u is a variable and not a type literal. |
I agree that it's (too) complicated. I guess that the long-term design goal is that The current specification has all the plumbing to allow that, and therefore needs to add extra rules to keep the existing behavior where To enable the prepared behavior, all you need to do is to remove the restriction that makes lookup of a static method fail on a non-class-literal. The rest of the specification will should then still work as written (barring other missing cases). |
Hmmm. But an implementor or programmer reading the spec today (4th edition) just sees unnecessary complexity. And we've inadvertently specified that the instance members of Type are static members of every class and that closurization does not work for static members. It might be better to add this machinery when it's needed rather than preemptively. |
We've also inadvertently specified that the static type of a static method invocation is From 16.17.1 Ordinary Invocation:
From 16.33 Identifier Reference:
Back to 16.17.1:
Unless we want Type to have members for every static method in the program, T.m will not exist and the type of the invocation will be dynamic. We've also changed the no such method behavior to invoke noSuchMethod on Type instead of throwing NoSuchMethodError, but I guess that doesn't make as much difference. |
No milestone now: This is not blocking Dart 2. |
Closing: I believe the case targeted by the title of this issue is covered today. Here is the error for
And here is the corresponding error for
I looked at the description here suggesting that we need to consider a lot of other steps, but I actually think we should just apply the above rules as the first step, and then note that we've found a compile-time error. @kmillikin, please re-open give me a heads up if you think that line of reasoning does not suffice. Another matter is that this should be a compile-time error reporting that this construct is simply outlawed as such. Currently (version 2.1.0-dev.4.0) both the vm and dart2js report a different error (using the phrase 'Method not found'), which seems to indicate that the common front end searches for a class method and doesn't find it. I've reported that as a new issue #34492. |
Both the VM and dart2js throw a NoSuchMethodError, but I can't quite see where the spec mandates that.
From 16.14.4 Function Expression Invocation we have:
So this is not a function expression invocation and is instead an ordinary method invocation.
From 16.17.1 Ordinary Invocation we have:
The expression C is evaluated to a value vo. From 16.33 Identifier Reference we have:
So vo is an instance of class Type or a subclass thereof reifying C. From 16.15.1 Method Lookup we have:
And https://api.dartlang.org/stable/1.15.0/dart-core/Type-class.html seems to indicate that the lookup will find the method toString from a superclass.
All the stuff about parameter matching seems to succeed and we get back to 16.17.1 Ordinary Invocation:
In this case vo is an instance of Type but o is a constant type literal, so we're OK and we should invoke the method toString from a superclass.
The text was updated successfully, but these errors were encountered: