{"action":"created","issue":{"url":"https://api.github.com/repos/dart-lang/sdk/issues/31428","repository_url":"https://api.github.com/repos/dart-lang/sdk","labels_url":"https://api.github.com/repos/dart-lang/sdk/issues/31428/labels{/name}","comments_url":"https://api.github.com/repos/dart-lang/sdk/issues/31428/comments","events_url":"https://api.github.com/repos/dart-lang/sdk/issues/31428/events","html_url":"https://github.com/dart-lang/sdk/issues/31428","id":275814596,"number":31428,"title":"Dart2JS/DDC: Add \"unsafeCast\" to pkg/js","user":{"login":"matanlurey","id":168174,"avatar_url":"https://avatars2.githubusercontent.com/u/168174?v=4","gravatar_id":"","url":"https://api.github.com/users/matanlurey","html_url":"https://github.com/matanlurey","followers_url":"https://api.github.com/users/matanlurey/followers","following_url":"https://api.github.com/users/matanlurey/following{/other_user}","gists_url":"https://api.github.com/users/matanlurey/gists{/gist_id}","starred_url":"https://api.github.com/users/matanlurey/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/matanlurey/subscriptions","organizations_url":"https://api.github.com/users/matanlurey/orgs","repos_url":"https://api.github.com/users/matanlurey/repos","events_url":"https://api.github.com/users/matanlurey/events{/privacy}","received_events_url":"https://api.github.com/users/matanlurey/received_events","type":"User","site_admin":false},"labels":[{"id":437839480,"url":"https://api.github.com/repos/dart-lang/sdk/labels/Customer-Angular","name":"Customer-Angular","color":"006b75","default":false},{"id":219928173,"url":"https://api.github.com/repos/dart-lang/sdk/labels/area-dart2js","name":"area-dart2js","color":"c7def8","default":false},{"id":219928212,"url":"https://api.github.com/repos/dart-lang/sdk/labels/dart2js-optimization","name":"dart2js-optimization","color":"d4c5f9","default":false},{"id":219928417,"url":"https://api.github.com/repos/dart-lang/sdk/labels/pkg-js","name":"pkg-js","color":"d4c5f9","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":13,"created_at":"2017-11-21T18:27:02Z","updated_at":"2018-02-16T21:24:46Z","closed_at":null,"author_association":"CONTRIBUTOR","body":"I closed https://github.com/dart-lang/sdk/issues/31142 to open this instead.\r\n\r\n**EDIT**: This is considered a blocking dependency of working on https://github.com/dart-lang/sdk/issues/31410.\r\n\r\nIn Dart 1.x + Dart2JS + `--trust-type-annotations`, the following was \"free\":\r\n\r\n```dart\r\nimport 'dart:html';\r\n\r\nvar _map = <String, dynamic/*Element|OtherClass*/>{};\r\n\r\nElement readElement(String key) {\r\n  Element value = _map[key];\r\n  return value;\r\n}\r\n```\r\n\r\nIn Dart 2.x, this roughly translates to:\r\n\r\n```dart\r\nimport 'dart:html';\r\n\r\nvar _map = <String, dynamic/*Element|OtherClass*/>{};\r\n\r\nElement readElement(String key) {\r\n  var value = _map[key] as Element;\r\n  return value;\r\n}\r\n```\r\n\r\n... where `as` has both a runtime and code-size cost:\r\n\r\n```dart\r\nvoid main(dynamic input) {\r\n  print((input as String).toUpperCase());\r\n}\r\n```\r\n\r\n```js\r\nmain: [function(input) {\r\n  P.print(H.stringTypeCast(input).toUpperCase());\r\n}, \"call$1\", \"main__main$closure\", 2, 0, 7]\r\n```\r\n\r\n## Proposal\r\n\r\nAdd `unsafeCase` (or similar) to `package:meta/dart2js.dart` or `package:js`.\r\n\r\n```dart\r\n/// Returns [any] casted to the type [T].\r\n///\r\n/// ```dart\r\n/// import 'package:meta/dart2js.dart';\r\n///\r\n/// void main(List<dynamic> input) {\r\n///   // I know the first element of this is list is _always_ a String.\r\n///   var element = unsafeCast<String>(input)\r\n/// }\r\n/// ```\r\n///\r\n/// Optimizing compilers, such as dart2js, may choose to omit the explicit\r\n/// cast, substituting safety for a bit faster runtime performance and less\r\n/// omitted code. Like `--trust-type-annotations` from Dart 1.x, this should\r\n/// be used sparingly as it can cause your application to fail in undefined ways\r\n/// in release mode.\r\nT unsafeCast<T>(Object any) => any/* as T*/;\r\n```\r\n\r\nAt 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.\r\n\r\nSo, the above example would be re-written as:\r\n\r\n```dart\r\nimport 'dart:html';\r\n\r\nimport 'package:meta/dart2js.dart';\r\n\r\nvar _map = <String, dynamic/*Element|OtherClass*/>{};\r\n\r\nElement readElement(String key) {\r\n  var value = unsafeCast<Element>(_map[key]);\r\n  return value;\r\n}\r\n```\r\n\r\nDDC would continue to just use the function as-is so tests and dev-mode is protected.\r\n/cc @leafpetersen @vsmenon \r\n\r\n@hterkelsen @sigmundch @rakudrama WDUT? Happy to send a CL to add to pkg/meta."},"comment":{"url":"https://api.github.com/repos/dart-lang/sdk/issues/comments/366362663","html_url":"https://github.com/dart-lang/sdk/issues/31428#issuecomment-366362663","issue_url":"https://api.github.com/repos/dart-lang/sdk/issues/31428","id":366362663,"user":{"login":"matanlurey","id":168174,"avatar_url":"https://avatars2.githubusercontent.com/u/168174?v=4","gravatar_id":"","url":"https://api.github.com/users/matanlurey","html_url":"https://github.com/matanlurey","followers_url":"https://api.github.com/users/matanlurey/followers","following_url":"https://api.github.com/users/matanlurey/following{/other_user}","gists_url":"https://api.github.com/users/matanlurey/gists{/gist_id}","starred_url":"https://api.github.com/users/matanlurey/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/matanlurey/subscriptions","organizations_url":"https://api.github.com/users/matanlurey/orgs","repos_url":"https://api.github.com/users/matanlurey/repos","events_url":"https://api.github.com/users/matanlurey/events{/privacy}","received_events_url":"https://api.github.com/users/matanlurey/received_events","type":"User","site_admin":false},"created_at":"2018-02-16T21:24:46Z","updated_at":"2018-02-16T21:24:46Z","author_association":"CONTRIBUTOR","body":"> Doing a cast, but have the cast be compiled to a no-op. Something has\r\nthe static type Object but you know it is really a String. This is what\r\nunsafeCast would do, and could be made safe by doing the check, for\r\nexample, DDC might do this to keep the unsafeCast honest. We can support\r\nthis.\r\n\r\nYup, we already do this here speculatively: \r\n\r\nhttps://github.com/dart-lang/angular/blob/37612b46ed820d4682d798e4a65eed973426e0f9/angular/lib/src/runtime/optimizations.dart#L25-L39\r\n\r\n> This is the second case, telling a lie. Pretending the type is List<String>\r\nwill be hard to make work because there is independent code that can check\r\nthe type and catch you out in the lie. For example, if you call a method on\r\nthe list and the method inspects the class type parameter, it will still be\r\ndynamic. You will have to unsafeCast the elements as you take them out of\r\nthe list.\r\n\r\nI guess what I (might?) be asking for is a \"secret\" type, that will always pass for the following check:\r\n\r\n```dart\r\nif (list is List<AnythingICheck>) {\r\n  // Always true if list is a List, regardless of List<T>.\r\n}\r\n```\r\n\r\n> You will have to unsafeCast the elements as you take them out of\r\nthe list.\r\n\r\nYeah, we might do that for now, but that isn't really ergonomic for users.\r\n\r\n> Regarding String.split, I recently committed an optimization to leave off\r\nthe type argument on the result if we can see that the type is unused. A\r\nlittle over a third of cases get optimized.\r\n\r\nNot 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."}}
{"actor":{"display_login":"matanlurey"}}