-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Behavior around upcasts in Dart2 are not documented well #33947
Comments
Hi @RedBrogdon! (For those that don't know, @RedBrogdon is on the Flutter DevRel team. Welcome!) A couple of things. Thanks for filing, and if you think docs could be improved anywhere in the future please file some issues.
nit: In Dart2 this is the same as: var listOfSquares = [Square(1), Square(2), Square(3)]; It's easy to get tripped up in Dart2 if you try to manually specify types. The various style guides on the subject have been moving to being more authoritative to trust type inference. I personally recommend (re)-reading the Types section of effective Dart.
This is fine because it is an upcast, a
Ok, so you ran into a combination of bugs and misconceptions around Dart2. First, The way I explained it to myself (and others) is covariance is safe for reads, not writes. That is, it's reasonable to expose a If Dart ever gets immutable data structures or ways to specify variance, it could help:
... so, tl;dr, in "correct" implementations of Dart2, the list
Careful with this language. What a cast is in Dart2 can be a little confusing. For example: var x = <num>[1, 2, 3];
List<int> x = y as List<int>; ... is invalid (a runtime error). To cast generic data structures, the rules are a little different:
This is because function types are contravariant, which hits an error case because it is (at runtime) a
I also filed a request for more docs. |
/cc @munificent, you might want to merge this with dart-lang/site-www#1017. |
Thanks for all the detail! I've taken another look at this now that I have some time on the shuttle (and after, admittedly, refreshing myself on co- and contravariance), and I think I've got a grasp of it. Dart's notion of covariance allows me to upcast lists and read from them: final listOfSquares = [Square(1), Square(2), Square(3)];
final listOfShapes = listOfSquares as List<Shape>;
listOfShapes.forEach((s) => s.log()); But should stop me from doing this: final listOfSquares = [Square(1), Square(2), Square(3)];
final listOfShapes = listOfSquares as List<Shape>;
listOfShapes.add(Shape(4)); And contravariance of function types allows me to do something like this: final listOfSquares = [Square(1), Square(2), Square(3)];
listOfSquares.forEach((Shape s) => s.log()); What I still don't understand is this bit at the end of my original question (which I now realize I should have foregrounded, since it's the reason I posted this whole thing):
If you run the code I posted above in DartPad, you get this output:
If you uncomment the four lines toward the end, wrapping the last statement in a try/catch, and re-run it, you get this:
I don't understand how uncommenting code at the end of |
The current version of DartPad is based on a buggy version of Dart2 on Dart2JS. I believe the VM has the correct behavior of the newer versions of Dart2JS mimic the VM. |
Any more to do on this issue? The only thing I see remaining is perhaps an article on casting in Dart? |
Without additional information, we are unfortunately not sure how to resolve this issue. We are therefore reluctantly going to close this bug for now. Please don't hesitate to comment on the bug if you have any more information for us; we will reopen it right away! |
I have the following code running in DartPad (Chrome, OSX, Dart SDK 2.0.0-dev.63.0):
In short, it creates a list of a subtype, uses
as
to cast it to the supertype, then adds a new instance of the super type to the new list reference. I would expect this to always fail at Step 3, when the new item is added to the new list reference. It's a casted version and still backed by the original, which can't accept an instance of the supertype.Instead, this code fails at Step 4, when it tries to print out the original list. If I remove the comments, adding a try/catch around Step 4, then it begins to fail at Step 3, which is just weird.
FWIW, this issue does not occur in a Flutter unit test. If executed in that environment, it always fails as expected at Step 3.
The text was updated successfully, but these errors were encountered: