-
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
Need a way to avoid some type checks without implicit downcasts #31428
Comments
+1. Straightforward to implement/execute migration. 'unsafe' prefix will prevent overuse. |
Is the intention that dart2js always treat this cast as a no-op, or only when the Dart 2.0 equivalent of |
I believe you can achieve the behavior you want as follows: T unsafeCast<T>(dynamic any) {
T anyAsT = any;
return anyAsT;
} Doing so will have the following behavior:
I don't believe we need to put this function in package:meta though, dart2js is not treating it specially in any way, so this can live directly in a private library of your package instead, or you can use that pattern in general in regular code. In your original example, ths might look like this: import 'dart:html';
var _map = <String, dynamic/*Element|OtherClass*/>{};
Element readElement(String key) {
Element value = _map[key] as dynamic;
return value;
} The only difference with the 1.0 code is that we added |
*edit: we don't even need the |
If Is there is some other reason you want It seems like package/meta is the wrong place for something that is not an annotation. |
Always. Or at least by default (start on the "golden path").
I'm not convinced it's an objective of Dart4Web to prevent any undefined behavior. We already use
I'm trying to avoid that. There is no reason to need
Coupled with my extremely popular proposal to remove implicit downcasts, I don't want to rely on Dart2JS disabling functionality of the language to get a performance boost.
Yes.
No. We don't document usage of
Fine to add to |
I'm not sure this is a good idea. The concern I would have here is that we are giving customers no indications that they are not getting Dart semantics, and that code which they have developed and tested using dart2js will not run on other platforms. |
They already don't get Dart semantics if they use |
I'm lost. I understood the piece of text that I quoted to be suggesting that dart2js should ship with the 2.0 equivalent of |
Sorry I didn't make this clear enough, specifically:
I had a nice chat with @kevmoo about this. When you look in AngularDart and see: void doThing() {
_doThing();
return null;
return null;
return null;
} What does that mean? Well, it means "don't inline". We'd prefer to write: import 'package:meta/dart2js.dart';
@noInline
void doThing() {
_doThing();
} Similarly, if you see the following: void doThing(dynamic /*A|B*/ element) {
if (element is A) {
// ...
} else (element == null) {
// ...
} else {
// We guarantee this is always B, but we can't prove it statically.
B bElement = element;
}
} We'd prefer to write: import 'package:js/js.dart';
void doThing(dynamic /*A|B*/ element) {
if (element is A) {
// ...
} else (element == null) {
// ...
} else {
// We guarantee this is always B, but we can't prove it statically.
var bElement = unsafeCast<B>(element);
}
} This is clear to code reviewers, and people browsing the source code that we are making an explicit choice to either opt-out of inlining or perform an unsafe cast for performance reasons. In large companies like Google code conventions pass by word-of-mouth as much as they do official style guides. We now have folks telling each-other to "use implicit casts because it is faster". This is terrible advice, goes against the style guide, and is completely wrong. Let me know if we should VC to chat in person and explain it further. |
Ok, I think we're on the same page then. |
This has come up again in user code. An internal user using a combination of GWT/JS/Dart has an "extension manager", which relies on reading/writing between GWT, JS, and Dart. An abstract example is the following JavaScript code: // May be read/write/replaced by either a JS App, GWT App, or Dart App.
window.extensions = [
'foo',
'bar',
]; In both GWT, JS, and Dart 1.x (and early DDC) this is fine. In Dart 2.x (and newer DDC) this throws In this case (and honestly |
There are two separate use cases here:
1. Doing a cast, but have the cast be compiled to a no-op. Something has
the static type Object but you know it is really a String. This is what
unsafeCast would do, and could be made safe by doing the check, for
example, DDC might do this to keep the unsafeCast honest. We can support
this.
2. Pretending the type is something that can't be verified by a type check
(i.e. a lie).
On Fri, Feb 16, 2018 at 9:24 AM, Matan Lurey ***@***.***> wrote:
This has come up again in user code.
An internal user using a combination of GWT/JS/Dart has an "extension
manager", which relies on reading/writing between GWT, JS, and Dart. An
abstract example is the following JavaScript code:
// May be read/write/replaced by either a JS App, GWT App, or Dart App.window.extensions = [
'foo',
'bar',
];
In both GWT, JS, and Dart 1.x (and early DDC) this is fine.
In Dart 2.x (and newer DDC) this throws JSArray is not a List<String>.
The issue here is that the user will have to read this file and cast it
(via .map/.cast) on *every* read, because it could have been changed by
another (non-Dart) application.
In this case (and honestly String.split too), it would be great to be
able to "force" the cast and/or "ignore" type arguments - that is, pretend
this is a List<String> even though it is likely a JSArray<dynamic>.
This is the second case, telling a lie. Pretending the type is List<String>
will be hard to make work because there is independent code that can check
the type and catch you out in the lie. For example, if you call a method on
the list and the method inspects the class type parameter, it will still be
dynamic. You will have to unsafeCast the elements as you take them out of
the list.
Regarding String.split, I recently committed an optimization to leave off
the type argument on the result if we can see that the type is unused. A
little over a third of cases get optimized. If all you do is for-in or
index the list in the same function as the .split() call, it works great.
After Dart 2, we can consider a more general form of this optimization.
… —
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#31428 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ACAtlVYeJfhZI3J5MAIoie1oxSMaU156ks5tVbmwgaJpZM4QmSbG>
.
|
Yup, we already do this here speculatively:
I guess what I (might?) be asking for is a "secret" type, that will always pass for the following check: if (list is List<AnythingICheck>) {
// Always true if list is a List, regardless of List<T>.
}
Yeah, we might do that for now, but that isn't really ergonomic for users.
Not a bad start, but I'm worried we will still need an "opt-out" for cases such as the GWT/JS interop ones I listed above. |
Any thoughts here in the last few months? We're already using this pattern, ourselves: In conjunction with the various |
I closed #31142 to open this instead.
EDIT: This is considered a blocking dependency of working on #31410.
In Dart 1.x + Dart2JS +
--trust-type-annotations
, the following was "free":In Dart 2.x, this roughly translates to:
... where
as
has both a runtime and code-size cost:Proposal
Add
unsafeCase
(or similar) topackage:meta/dart2js.dart
orpackage:js
.At a later point of time (before
2.0
-on-by-default in google3, for example), Dart2JS would have a compiler intrinsic specifically for this function call, where-as the body of the function is not used, and instead it would similarly to--trust-type-annotations
in Dart 1.x.So, the above example would be re-written as:
DDC would continue to just use the function as-is so tests and dev-mode is protected.
/cc @leafpetersen @vsmenon
@hterkelsen @sigmundch @rakudrama WDUT? Happy to send a CL to add to pkg/meta.
The text was updated successfully, but these errors were encountered: