{"action":"opened","issue":{"url":"https://api.github.com/repos/dart-lang/sdk/issues/33841","repository_url":"https://api.github.com/repos/dart-lang/sdk","labels_url":"https://api.github.com/repos/dart-lang/sdk/issues/33841/labels{/name}","comments_url":"https://api.github.com/repos/dart-lang/sdk/issues/33841/comments","events_url":"https://api.github.com/repos/dart-lang/sdk/issues/33841/events","html_url":"https://github.com/dart-lang/sdk/issues/33841","id":340809227,"node_id":"MDU6SXNzdWUzNDA4MDkyMjc=","number":33841,"title":"Its is too hard to use `<Iterable>.firstWhere(orElse: ...)`","user":{"login":"matanlurey","id":168174,"node_id":"MDQ6VXNlcjE2ODE3NA==","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":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2018-07-12T21:44:03Z","updated_at":"2018-07-12T21:44:03Z","closed_at":null,"author_association":"CONTRIBUTOR","body":"Similar issues:\r\n* https://github.com/dart-lang/sdk/issues/33119#issuecomment-401203174\r\n* https://github.com/dart-lang/sdk/issues/33697\r\n* https://github.com/dart-lang/sdk/issues/33812 (/cc @joeconwaystk)\r\n\r\nConsider the following, fairly simple example of using [`<Iterable>.firstWhere`][1]:\r\n\r\n[1]: https://api.dartlang.org/dev/2.0.0-dev.68.0/dart-core/Iterable/firstWhere.html\r\n\r\n```dart\r\nclass Asset {\r\n  final String name;\r\n  Asset(this.name);\r\n  void printMe() => print('$name <$runtimeType>');\r\n}\r\n\r\nvoid main() {\r\n  final assets = [Asset('A'), Asset('B')];\r\n  printBestAsset(assets);\r\n}\r\n\r\nvoid printBestAsset(List<Asset> assets) {\r\n  assets\r\n    .firstWhere((a) => a.name == 'A', orElse: () => assets.first)\r\n    .printMe();\r\n}\r\n```\r\n\r\nThis properly prints, as expected, `A <Asset>`. Neat! Let's get _polymorphic_.\r\n\r\n![image](https://user-images.githubusercontent.com/168174/42660866-393d6ef6-85e1-11e8-9a70-1dec8eeb9167.png)\r\n\r\n```dart\r\nclass Asset {\r\n  final String name;\r\n  Asset(this.name);\r\n  void printMe() => print('$name <$runtimeType>');\r\n}\r\n\r\n// The irony of \"Sound\" is semi-intentional.\r\nclass SoundAsset extends Asset {\r\n  SoundAsset(String name) : super(name);\r\n}\r\n\r\nvoid main() {\r\n  final assets = [SoundAsset('A'), SoundAsset('B')];\r\n  printBestAsset(assets);\r\n}\r\n\r\nvoid printBestAsset(List<Asset> assets) {\r\n  //  ERROR:\r\n  // TypeError: Closure 'printBestAsset_closure0': \r\n  //     type '() => Asset' is not a subtype of type '() => SoundAsset'\r\n  assets\r\n    .firstWhere((a) => a.name == 'A', orElse: () => assets.first)\r\n    .printMe();\r\n}\r\n```\r\n\r\n![image](https://user-images.githubusercontent.com/168174/42660971-93601fa0-85e1-11e8-9213-d1e9e8ad87eb.png)\r\n\r\nI looked at this with 3 other Google/Dart team engineers, until @alorenzen mentioned \"well, that's why Java has `? extends T`\". Here is the page from \"Effective Java\", highlighting exactly that:\r\n\r\n![screen shot 2018-07-12 at 2 34 11 pm](https://user-images.githubusercontent.com/168174/42661008-ba29d2d4-85e1-11e8-9cc0-d5eb64255172.png)\r\n\r\n... and we realized we could write this in Dart too:\r\n\r\n```dart\r\nclass Asset {\r\n  final String name;\r\n  Asset(this.name);\r\n  void printMe() => print('$name <$runtimeType>');\r\n}\r\n\r\n// The irony of \"Sound\" is semi-intentional.\r\nclass SoundAsset extends Asset {\r\n  SoundAsset(String name) : super(name);\r\n}\r\n\r\nvoid main() {\r\n  final assets = [SoundAsset('A'), SoundAsset('B')];\r\n  printBestAsset(assets);\r\n}\r\n\r\nvoid printBestAsset<A extends Asset>(List<A> assets) {\r\n  assets\r\n    .firstWhere((a) => a.name == 'A', orElse: () => assets.first)\r\n    .printMe();\r\n}\r\n```\r\n\r\n... though, contrast this with Java's API of `List<? extends Asset>`, which seems more obvious.\r\n\r\n## Questions:\r\n\r\n* [ ] Where in the language tour or style guide do we have suggestions to help here?\r\n* [ ] Can we have lints or strict warnings that aid the user to write this? It was hard for _3_ of us."}}
{"actor":{"display_login":"matanlurey"}}