Comments (9)
We know, and this is a very interesting problem! ;-)
With pre-transform code, the 'dart:mirrors' based invocation can use the built-in semantics to determine that a given method is not supported by the given receiver, such that we can get the standard noSuchMethodError
. With post-transform code the situation is as follows: An invocation of a method 'message' has been requested, and there is no generated code for performing such an invocation. This could be because the capabilities specified that only a subset of the available methods should be supported, and this one is not among them, or it could be because it is a non-existing method. We cannot distinguish these two situations without storing information about all methods that we do not support.
That is not a very attractive thing to do, given that we don't want to spend a lot of resources (program size) on things for which we do not have any capabilities.
This is a known problem, and it is not obvious how we could solve it in a good way. So we are not going to have a solution at this point.
Do you think it would be better to always throw a NoSuchMethodError
, even though it might as well be a NoSuchCapability
problem?
Another issue which is related is that we cannot invoke noSuchMethod
, because that method needs a Symbol
indicating which selector (method name) to use for the invocation, and we don't want to introduce dynamic creation of Symbol
values. (Essentially, the runtime state must then include a complete mapping from String
values to the corresponding minified Symbol
values, which would take up a significant amount of space, and it would potentially also be an unintended-deobfuscation issue).
Keeping the issue open as a reminder (would label it, but there is no "not right now" label).
from reflectable.dart.
We cannot distinguish these two situations without storing information about all methods that we do not support.
What if instead of storing information about each method, you just stored information about the capabilities that were originally supplied? This info would be relatively compact and should allow you to distinguish the two cases?
Do you think it would be better to always throw a NoSuchMethodError, even though it might as well be a NoSuchCapability problem?
This is a really hard question :(. In the case of Polymer this caused a post-transformation bug because I was catching NoSuchMethodError since it was much faster than actually checking if a setter exists. The opposite situation could easily happen as well though, where somebody was trying to catch a NoSuchCapability error and instead it threw a NoSuchMethodError. Therefore, I don't think one is better than the other.
Keeping the issue open as a reminder (would label it, but there is no "not right now" label).
You can add one here ;) https://github.com/dart-lang/reflectable/labels
from reflectable.dart.
We'll explore that idea. Keeping the issue open (without the "not right now", just open, but we'll fix some more bugs first ;).
from reflectable.dart.
This actually is going to be more important going forward, since we are requiring annotations on all properties/methods now. It would be really great to be able to distinguish the case where the method actually didn't exist, versus it just needing an annotation.
from reflectable.dart.
Returning to this issue, I cannot see how we can distinguish "this method does not exist" from "this method exists, but you haven't asked for the capability to call it" by consulting things like a RegExp
stored in an instance of InstanceInvokeCapability
or a Type
stored in a StaticInvokeMetaCapability
.
Even if we know that we can invoke methods whose name matches "^fo.*ar$" and methods carrying metadata of type D
or a subtype thereof, we cannot know whether or not there is a method called foobar
accepting 3 positional arguments and two named arguments with names #baz
and #blit
even if we stare really hard at that RegExp
and that Type
. ;-)
We'd have to store information about every non-covered method in the target class itself as well as every superclass: name plus parameter list shape (including all the names of its named optional parameters), and then we'd have to check that each invocation where the lookup fails has a matching name and a conforming parameter list shape among the non-covered methods, in which case it's NoSuchCapabilityError
; otherwise the method just isn't there, and it's noSuchMethod
.
My gut feeling is that we should not store a large amount of information about stuff that the explicitly specified capabilities have rejected, given that the starting point for the package reflectable is to save space.
This gives rise to another idea: We could declare that there is no capability for reflectively invoking methods that do not exist, just like there is no capability for invoking methods that exist but fail to match the criteria (RegExp
, Type
of metadata), and then we would throw a NoSuchCapabilityError
in both cases. That's a simple and consistent rule, and I don't think the alternatives are obviously more "correct".
Another matter is that it might be useful to be able to make queries about supported methods for a given instance/class mirror. We can do this today, indirectly: With a given instance mirror, we could obtain the corresponding class mirror, get its instanceMembers
, and search for the existence of a method with a given name; similarly, we could search the staticMembers
of a given class mirror. But then we'd need to manually inspect the formal parameter list and check whether the intended actual argument list conforms to the formal list, and then we can conclude "yes, we have that method" or "no, we don't".
Wouldn't it work at least equally well to simply try invoking the method as planned, and then catching NoSuchCapabilityError
? ;-)
from reflectable.dart.
I kind of like the idea of just always throwing a NoSuchCapabilityError
actually... at least everything is consistent that way.
Another matter is that it might be useful to be able to make queries about supported methods for a given instance/class mirror. We can do this today, indirectly: With a given instance mirror, we could obtain the corresponding class mirror, get its instanceMembers, and search for the existence of a method with a given name; similarly, we could search the staticMembers of a given class mirror. But then we'd need to manually inspect the formal parameter list and check whether the intended actual argument list conforms to the formal list, and then we can conclude "yes, we have that method" or "no, we don't".
I was doing basically this originally, but it was prohibitively slow. I didn't spend a lot of time trying to figure out exactly which part was slow, but just catching the error was definitely a lot faster (at least a few months ago).
from reflectable.dart.
The approach taken in CL https://codereview.chromium.org/1485193002/ is exactly this: Always throw NoSuchCapabilityError
when a method is invoked, but not present. The underlying motto would be "reflectable and noSuchMethod
do not mix". That CL eliminates the associated test failures (which had been failing for many months because we had no solution until now) so we can now close this issue. ;-)
from reflectable.dart.
We are finally making progress on this. The commit 5a835be contains a large number of changes related to the treatment of no-such-method events in transformed code. CL https://codereview.chromium.org/1512033002/ contains the corresponding changes for doing the same in untransformed code. The resulting semantics is as follows:
The core concept is a no-such-method situation. That is a reflectable invocation (that is, an invoke
, invokeGetter
, invokeSetter
, delegate
, or newInstance
on an InstanceMirror
, ClassMirror
, or LibraryMirror
) that fails because the specified method/getter/setter does not exist, or an argument list was provided which had a non-conforming number of positional arguments, or a named argument was specified whose name isn't defined for that method. When such a no-such-method situation arises, reflectable throws a ReflectableNoSuchMethodError
containing a StringInvocation
(just like an Invocation
but with a string rather than a symbol as the memberName
). This means that it is possible to catch that exception and invoke whatever-stand-in-for-noSuchMethod you wish to use.
from reflectable.dart.
CL https://codereview.chromium.org/1512033002/ was landed as commit 45214a1. The approach of consistently throwing ReflectableNoSuchMethod
in no-such-method situations for reflectable invocations is now in place, so we will close this issue.
There is a lot of new code involved, though. Please create new issues if you spot any buggy behaviors.
from reflectable.dart.
Related Issues (20)
- [question] - Is it possible to have Annotations with Parameters? HOT 2
- [Question] - how to get Constructor arguments? HOT 2
- [Bug?] ERROR: This requires the 'constructor-tearoffs' language feature to be enabled. HOT 12
- [Question] - Listening to Method invocation HOT 6
- [Question] - Stats on Bundle Sizes and Performance Implications/metrics of using Reflectable ? HOT 1
- Cannot reflect ```flutter/material.dart``` URIs for ```Container``` type HOT 12
- This reflector does not match anything HOT 11
- Reflectable is not a know builder HOT 1
- Unsupported operation: location HOT 4
- Reflectable don't find "main" but im using in my library not an application HOT 5
- How to generate code according to filter rules HOT 2
- The build_runner those not generate anything HOT 1
- Annotated parameter and Functions
- Include annotated types that are not imported to `main.dart` HOT 2
- Severe error during build with @reflector and @JsonKey on the same class. HOT 1
- isSubtype exception for classes without parents HOT 2
- Where is initializeReflectable method? HOT 3
- Error: Reflecting on un-marked type "Type" HOT 2
- bug: issue with using mixins HOT 5
- importing private libaries during build_runner build HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from reflectable.dart.