Share
Embed
FlutterKaigi Day1「Dart のこれから」
2021 年、Dart 2.12 で Null safety がデフォルトで有効になり、とても快適に開発できるようになってきました。
Null safety 以降もさまざまな機能が追加され、Dart はまだまだ進化を続けています。
このセッションでは、近年の進化の振り返りを簡単にした後、Dart の進化プロセスの紹介をして、これから Dart がどんな進化をしていくのかをできる限り詳しく紹介します。
トーク内容
01 近年、どのような進化を遂げてきたか
02 Dart の進化プロセス
03 仕様化を進めている新機能
・Views on an object without a wrapper object
・Static Metaprogramming
・Sound declaration-site variance
・Patterns and related features
04 おわりに
対象者
・Dart の近年追加された機能について振り返りたい方
・Dart の進化プロセスに興味のある方
・Dart のこれからに興味のある方
おかやまん
November 16, 2022
Transcript
91 slides
-
Agenda 01 近年、どのような進化を遂げてきたか 02 Dart の進化プロセス 03 仕様化を進めている新機能 ・Patterns and
related features ・Static Metaprogramming ・Views on an object without a wrapper object ・Sound declaration-site variance 04 おわりに -
Agenda 01 近年、どのような進化を遂げてきたか 02 Dart の進化プロセス 03 仕様化を進めている新機能 ・Patterns and
related features ・Static Metaprogramming ・Views on an object without a wrapper object ・Sound declaration-site variance 04 おわりに -
bool isEmpty(String s) => s.length == 0; void main() {
// Runtime error isEmpty(null); } Dart 2.12 - Null safety bool isEmpty(String s) => s.length == 0; void main() { // Compile-time error isEmpty(null); } 01 近年、どのような進化を遂げてきたか https://github.com/dart-lang/sdk/blob/main/CHANGELOG.md#2120---2021-03-03 -
bool isEmpty(String s) => s.length == 0; void main() {
// Runtime error isEmpty(null); } Dart 2.12 - Null safety bool isEmpty(String s) => s.length == 0; void main() { // Compile-time error isEmpty(null); } 01 近年、どのような進化を遂げてきたか https://github.com/dart-lang/sdk/blob/main/CHANGELOG.md#2120---2021-03-03 -
class A { int x; A(this.x); A.fromString(String s) : x
= int.parse(s); } void main() { final listOfInts = [1, 2, 3]; final listOfStrings = ["1", "2", "3"]; for(final a in listOfInts.map((x) => A(x))) { print(a.x); } for(final a in listOfStrings.map((x) => A.fromString(x))) { print(a.x); } } Dart 2.15 - Constructor tear-offs class A { int x; A(this.x); A.fromString(String s) : x = int.parse(s); } void main() { final listOfInts = [1, 2, 3]; final listOfStrings = ["1", "2", "3"]; for(final a in listOfInts.map(A.new)) { print(a.x); } for(final a in listOfStrings.map(A.fromString)) { print(a.x); } } 01 近年、どのような進化を遂げてきたか https://github.com/dart-lang/sdk/blob/main/CHANGELOG.md#2150---2021-12-08 -
class A { int x; A(this.x); A.fromString(String s) : x
= int.parse(s); } void main() { final listOfInts = [1, 2, 3]; final listOfStrings = ["1", "2", "3"]; for(final a in listOfInts.map((x) => A(x))) { print(a.x); } for(final a in listOfStrings.map((x) => A.fromString(x))) { print(a.x); } } Dart 2.15 - Constructor tear-offs class A { int x; A(this.x); A.fromString(String s) : x = int.parse(s); } void main() { final listOfInts = [1, 2, 3]; final listOfStrings = ["1", "2", "3"]; for(final a in listOfInts.map(A.new)) { print(a.x); } for(final a in listOfStrings.map(A.fromString)) { print(a.x); } } 01 近年、どのような進化を遂げてきたか https://github.com/dart-lang/sdk/blob/main/CHANGELOG.md#2150---2021-12-08 -
enum Status { success, failure } extension StatusToCode on Status
{ int get code { switch (this) { case Status.success: return 0; case Status.failure: return 1; } } } Dart 2.17 - Enhanced enums with members enum Status { success(0), failure(1); final int code; const Status(this.code); } 01 近年、どのような進化を遂げてきたか https://github.com/dart-lang/sdk/blob/main/CHANGELOG.md#2170---2022-05-11 -
enum Status { success, failure } extension StatusToCode on Status
{ int get code { switch (this) { case Status.success: return 0; case Status.failure: return 1; } } } Dart 2.17 - Enhanced enums with members enum Status { success(0), failure(1); final int code; const Status(this.code); } 01 近年、どのような進化を遂げてきたか https://github.com/dart-lang/sdk/blob/main/CHANGELOG.md#2170---2022-05-11 -
class CupertinoPage<T> extends Page<T> { const CupertinoPage({ required this.child, this.maintainState
= true, this.title, this.fullscreenDialog = false, LocalKey? key, String? name, Object? arguments, String? restorationId, }) : super( key: key, name: name, arguments: arguments, restorationId: restorationId, ); // ... } Dart 2.17 - Super parameters class CupertinoPage<T> extends Page<T> { const CupertinoPage({ required this.child, this.maintainState = true, this.title, this.fullscreenDialog = false, super.key, super.name, super.arguments, super.restorationId, }); // ... } 01 近年、どのような進化を遂げてきたか https://github.com/dart-lang/sdk/blob/main/CHANGELOG.md#2170---2022-05-11 -
class CupertinoPage<T> extends Page<T> { const CupertinoPage({ required this.child, this.maintainState
= true, this.title, this.fullscreenDialog = false, LocalKey? key, String? name, Object? arguments, String? restorationId, }) : super( key: key, name: name, arguments: arguments, restorationId: restorationId, ); // ... } Dart 2.17 - Super parameters class CupertinoPage<T> extends Page<T> { const CupertinoPage({ required this.child, this.maintainState = true, this.title, this.fullscreenDialog = false, super.key, super.name, super.arguments, super.restorationId, }); // ... } 01 近年、どのような進化を遂げてきたか https://github.com/dart-lang/sdk/blob/main/CHANGELOG.md#2170---2022-05-11 -
main() { test('A test description', () { // Very long
function body here... }, skip: true); } Dart 2.17 - Named args everywhere main() { test(skip: true, 'A test description', () { // Very long function body here... }); } 01 近年、どのような進化を遂げてきたか https://github.com/dart-lang/sdk/blob/main/CHANGELOG.md#2170---2022-05-11 -
main() { test('A test description', () { // Very long
function body here... }, skip: true); } Dart 2.17 - Named args everywhere main() { test(skip: true, 'A test description', () { // Very long function body here... }); } 01 近年、どのような進化を遂げてきたか https://github.com/dart-lang/sdk/blob/main/CHANGELOG.md#2170---2022-05-11 -
• Dart 2.18 ◦ Enhanced type inference for generic invocations
with function literals • Dart 2.17 ◦ Enhanced enums with members ◦ Super parameters ◦ Named args everywhere • Dart 2.15 ◦ Constructor tear-offs ◦ Generic type literals ◦ Explicit generic method instantiations ◦ Generic instantiation of function objects • Dart 2.14 ◦ Unsigned shift operator ◦ Removed some restrictions on type arguments • Dart 2.13 ◦ Non-function type aliases • Dart 2.12 ◦ Null safety 01 近年、どのような進化を遂げてきたか https://github.com/dart-lang/sdk/blob/main/CHANGELOG.md -
Agenda 01 近年、どのような進化を遂げてきたか 02 Dart の進化プロセス 03 仕様化を進めている新機能 ・Patterns and
related features ・Static Metaprogramming ・Views on an object without a wrapper object ・Sound declaration-site variance 04 おわりに -
Dart の言語チーム ※ 2020 年 6 月時点 leafpetersen
lrhn eernstg munificent natebosch jakemac53 stereotype441 mit-mit 02 Dart の進化プロセス https://github.com/dart-lang/language/blob/master/README.md#dart-language-team -
機能が追加されるまでの流れ 02 Dart の進化プロセス ※ 2022 年 10 月時点
https://github.com/dart-lang/language/projects/1 -
Agenda 01 近年、どのような進化を遂げてきたか 02 Dart の進化プロセス 03 仕様化を進めている新機能 ・Patterns and
related features ・Static Metaprogramming ・Views on an object without a wrapper object ・Sound declaration-site variance 04 おわりに -
Patterns and related features 03 仕様化を進めている新機能 - Patterns and related features
https://github.com/dart-lang/language/projects/1 -
Patterns and related features 03 仕様化を進めている新機能 - Patterns and related features
https://github.com/dart-lang/language/issues/546 -
コンセプト • パターン • パターンマッチング • 網羅性 • 分割代入 •
タプル • 代数的データ型 • データクラス 03 仕様化を進めている新機能 - Patterns and related features -
Record 機能 - 提案の動機 03 仕様化を進めている新機能 - Patterns and related features
Future<String> getPersonName() async => 'John'; Future<int> getUnreadCount() async => 10; void main() async { // List<Object> final result = await Future.wait([ getPersonName(), getUnreadCount(), ]); final personName = result[0] as String; final unreadCount = result[1] as int; final lowOrHigh = unreadCount < 10 ? 'low' : 'high'; // John's unread count is high. print("$personName’s unread count is $lowOrHigh."); } -
Record 機能 - 提案の動機 03 仕様化を進めている新機能 - Patterns and related features
Future<String> getPersonName() async => 'John'; Future<int> getUnreadCount() async => 10; void main() async { // List<Object> final result = await Future.wait([ getPersonName(), getUnreadCount(), ]); final personName = result[0] as String; final unreadCount = result[1] as int; final lowOrHigh = unreadCount < 10 ? 'low' : 'high'; // John's unread count is high. print("$personName's unread count is $lowOrHigh."); } -
Record 機能 - 提案の動機 03 仕様化を進めている新機能 - Patterns and related features
Future<String> getPersonName() async => 'John'; Future<int> getUnreadCount() async => 10; void main() async { // List<Object> final result = await Future.wait([ getPersonName(), getUnreadCount(), ]); final personName = result[0] as String; final unreadCount = result[1] as int; final lowOrHigh = unreadCount < 10 ? 'low' : 'high'; // John's unread count is high. print("$personName's unread count is $lowOrHigh."); } -
Record 機能 - 概要 03 仕様化を進めている新機能 - Patterns and related features
var tuple = ("first", 2, true); var record = (number: 123, name: "Main", type: "Street"); var record = ("first", number: 123, 2, name: "Main", true, type: "Street"); -
Record 機能 - 概要 03 仕様化を進めている新機能 - Patterns and related features
var record = (1, a: 2, 3, b: 4); print(record.$0); // Prints "1". print(record.a); // Prints "2". print(record.$1); // Prints "3". print(record.b); // Prints "4". -
Record 機能 - 概要 03 仕様化を進めている新機能 - Patterns and related features
var record = (1, a: 2, 3, b: 4); print(record.$0); // Prints "1". print(record.a); // Prints "2". print(record.$1); // Prints "3". print(record.b); // Prints "4". -
Record 機能 - 概要 03 仕様化を進めている新機能 - Patterns and related features
var record = (1, a: 2, 3, b: 4); print(record.$0); // Prints "1". print(record.a); // Prints "2". print(record.$1); // Prints "3". print(record.b); // Prints "4". -
Record 機能 - 概要 03 仕様化を進めている新機能 - Patterns and related features
var record = (1, a: 2, 3, b: 4); print(record.$0); // Prints "1". print(record.a); // Prints "2". print(record.$1); // Prints "3". print(record.b); // Prints "4". -
Record 機能 - 注釈 03 仕様化を進めている新機能 - Patterns and related features
(int, String name, bool) triple; ({int n, String s}) pair; (bool, num, {int n, String s}) quad; -
Record 機能 - 注釈 03 仕様化を進めている新機能 - Patterns and related features
(int, String name, bool) triple; ({int n, String s}) pair; (bool, num, {int n, String s}) quad; -
Record 機能 - 注釈 03 仕様化を進めている新機能 - Patterns and related features
(int, String name, bool) triple; ({int n, String s}) pair; (bool, num, {int n, String s}) quad; -
Record 機能 - 注釈 03 仕様化を進めている新機能 - Patterns and related features
(int, String name, bool) triple; ({int n, String s}) pair; (bool, num, {int n, String s}) quad; -
Record 機能 - 注釈 03 仕様化を進めている新機能 - Patterns and related features
(int, String name, bool) triple; ({int n, String s}) pair; (bool, num, {int n, String s}) quad; -
Record 機能 - 注釈 03 仕様化を進めている新機能 - Patterns and related features
@metadata (a, b) function() {} -
Record 機能 - 注釈 03 仕様化を進めている新機能 - Patterns and related features
@metadata (a, b) function() {} -
Record 機能 - 注釈 03 仕様化を進めている新機能 - Patterns and related features
@metadata (a, b) function() {} -
Record 機能 - toString() 03 仕様化を進めている新機能 - Patterns and related features
// デバッグビルド print((1, 2, 3).toString()); // "(1, 2, 3)". print((a: 'str', 'int').toString()); // "(a: str, int)". -
Record 機能 - 等価性 03 仕様化を進めている新機能 - Patterns and related features
var a = (x: 1, 2); var b = (2, x: 1); print(a == b); // true. -
Record 機能 - with() 03 仕様化を進めている新機能 - Patterns and related features
void main() { (int, int, {Color color}) x = (0, 1, color: Color.red); var x2 = x.with(7); // Just changes x[0]. var x3 = x.with(_, 3); // Just changes x[1]. var x4 = x.with(1: 3); // Also just changes x[1]. var x5 = x.with(color: Color.Blue); // Just changes x.color. } -
Pattern 機能 - 提案の動機 03 仕様化を進めている新機能 - Patterns and related features
void main() async { try { await fetchData(); } on SocketException { handleException(); } on TimeoutException { handleException(); } } -
Pattern 機能 - 提案の動機 03 仕様化を進めている新機能 - Patterns and related features
void main() async { try { await fetchData(); } on SocketException, TimeoutException { handleException(); } } -
Pattern 機能 - 概要 03 仕様化を進めている新機能 - Patterns and related features
パターンに関する基本的な考え方 • パターンが値と一致するかどうかを判断するために、ある値に対してテストすること ができる • いくつかのパターンは、マッチした場合、マッチした値からデータを取り出すことに よって、マッチした値を再構築する • 変数パターンは、マッチした値または非構造化された値に新しい変数をバインドす る。変数は、パターンがマッチしたときにのみ到達可能なコード領域内にスコープさ れる -
Pattern 機能 - 概要 03 仕様化を進めている新機能 - Patterns and related features
種類 例 論理和 subpattern1 | subpattern2 論理積 subpattern1 & subpattern2 関連 == expression, < expression キャスト foo as String null チェック subpattern? null アサート subpattern! 定数 123, null, 'string', math.pi, SomeClass.constant, const Thing(1, 2), const (1 + 2) 変数 foo, var bar, String str, _, int _ 括弧付き (subpattern) List [subpattern1, subpattern2] Map {"key": subpattern1, someConst: subpattern2} Record (subpattern1, subpattern2), (x: subpattern1, y: subpattern2) 抽出 SomeClass(x: subpattern1, y: subpattern2) https://github.com/dart-lang/language/blob/master/working/0546-patterns/patterns-feature-specification.md -
Pattern 機能 - 論理和パターン 03 仕様化を進めている新機能 - Patterns and related features
var isPrimary = switch (color) { case Color.red | Color.yellow | Color.blue => true; default => false; }; -
Pattern 機能 - 論理和パターン 03 仕様化を進めている新機能 - Patterns and related features
var isPrimary = switch (color) { case Color.red | Color.yellow | Color.blue => true; default => false; }; -
Pattern 機能 - 論理和パターン 03 仕様化を進めている新機能 - Patterns and related features
switch (shape) { case Square(size: var s) | Circle(size: var s) when s > 0: print('Non-empty symmetric shape'); case Square() | Circle(): print('Empty symmetric shape'); default: print('Asymmetric shape'); } -
Pattern 機能 - 論理和パターン 03 仕様化を進めている新機能 - Patterns and related features
switch (shape) { case Square(size: var s) | Circle(size: var s) when s > 0: print('Non-empty symmetric shape'); case Square() | Circle(): print('Empty symmetric shape'); default: print('Asymmetric shape'); } -
Pattern 機能 - 論理和パターン 03 仕様化を進めている新機能 - Patterns and related features
switch (list) { // Matches a two-element list whose first element is 'a' or 'b': case ['a' | 'b', var c]: } -
網羅性チェック - 概要 03 仕様化を進めている新機能 - Patterns and related features
• 網羅性 • 到達可能性 switch (b) { case true: print('yes'); case false: print('no'); } switch (b) { case true: print('yes'); case false: print('no'); case bool b: print('unreachable'); } -
マクロ - 提案の動機 03 仕様化を進めている新機能 - Static Metaprogramming data class
User(val name: String, val age: Int) -
マクロ - 提案の動機 03 仕様化を進めている新機能 - Static Metaprogramming @immutable class
User { const User({ required this.name, required this.age, }); final String name; final int age; @override bool operator ==(Object other) => other is User && other.runtimeType == runtimeType && other.name == name && other.age == age; @override int get hashCode => Object.hash( runtimeType, name, age, ); @override String toString() => 'User(' 'name=$name, ' 'age=$age' ')'; User copy({ String? name, int? age, }) => User( name: name ?? this.name, age: age ?? this.age, ); } -
マクロ - 提案の動機 03 仕様化を進めている新機能 - Static Metaprogramming import 'package:freezed_annotation/freezed_annotation.dart';
part 'user.freezed.dart'; @freezed class User with _$User { const factory User({ required String name, required int age, }) = _User; } -
マクロ - 概要 03 仕様化を進めている新機能 - Static Metaprogramming macro class
DataClass implements ClassDeclarationsMacro, ClassDefinitionMacro { const DataClass(); @override Future<void> buildDeclarationsForClass( ClassDeclaration clazz, ClassMemberDeclarationBuilder context) async { await Future.wait([ const AutoConstructor().buildDeclarationsForClass(clazz, context), const CopyWith().buildDeclarationsForClass(clazz, context), const HashCode().buildDeclarationsForClass(clazz, context), const Equality().buildDeclarationsForClass(clazz, context), const ToString().buildDeclarationsForClass(clazz, context), ]); } @override Future<void> buildDefinitionForClass( ClassDeclaration clazz, ClassDefinitionBuilder builder) async { await Future.wait([ const HashCode().buildDefinitionForClass(clazz, builder), const Equality().buildDefinitionForClass(clazz, builder), const ToString().buildDefinitionForClass(clazz, builder), ]); } } -
マクロ - 概要 03 仕様化を進めている新機能 - Static Metaprogramming macro class
DataClass implements ClassDeclarationsMacro, ClassDefinitionMacro { const DataClass(); @override Future<void> buildDeclarationsForClass( ClassDeclaration clazz, ClassMemberDeclarationBuilder context) async { await Future.wait([ const AutoConstructor().buildDeclarationsForClass(clazz, context), const CopyWith().buildDeclarationsForClass(clazz, context), const HashCode().buildDeclarationsForClass(clazz, context), const Equality().buildDeclarationsForClass(clazz, context), const ToString().buildDeclarationsForClass(clazz, context), ]); } @override Future<void> buildDefinitionForClass( ClassDeclaration clazz, ClassDefinitionBuilder builder) async { await Future.wait([ const HashCode().buildDefinitionForClass(clazz, builder), const Equality().buildDefinitionForClass(clazz, builder), const ToString().buildDefinitionForClass(clazz, builder), ]); } } -
Views on an object without a wrapper object 03 仕様化を進めている新機能 -
Views on an object without a wrapper object https://github.com/dart-lang/language/projects/1 -
Views on an object without a wrapper object 03 仕様化を進めている新機能 -
Views on an object without a wrapper object https://github.com/dart-lang/language/issues/1474 -
View - 提案の動機 03 仕様化を進めている新機能 - Views on an object without
a wrapper object • 拡張メソッドのように、ラッパーオブジェクトなしで、ゼロコストで特定のオブジェクト を拡張したい • ラッピングすることで、不適切な操作を禁止したり、回帰的な処理をより便利かつ安 全に実装したりしたい -
View - 概要 03 仕様化を進めている新機能 - Views on an object without
a wrapper object view class IdNumber(int i) { operator <(IdNumber other) => i < other.i; bool verify(Some parameters) => ...; } -
View - 概要 03 仕様化を進めている新機能 - Views on an object without
a wrapper object view class IdNumber(int i) { operator <(IdNumber other) => i < other.i; bool verify(Some parameters) => ...; } -
View - 概要 03 仕様化を進めている新機能 - Views on an object without
a wrapper object view class IdNumber(int i) { operator <(IdNumber other) => i < other.i; bool verify(Some parameters) => ...; } -
View - 概要 03 仕様化を進めている新機能 - Views on an object without
a wrapper object view class IdNumber(int i) { operator <(IdNumber other) => i < other.i; bool verify(Some parameters) => ...; } void main() { int myUnsafeId = 42424242; var safeId = IdNumber(42424242); safeId + 10; // Compile-time error 10 + safeId; // Compile-time error myUnsafeId = safeId; // Compile-time error } -
View - 概要 03 仕様化を進めている新機能 - Views on an object without
a wrapper object view class IdNumber(int i) { operator <(IdNumber other) => i < other.i; bool verify(Some parameters) => ...; } void main() { int myUnsafeId = 42424242; var safeId = IdNumber(42424242); safeId + 10; // Compile-time error 10 + safeId; // Compile-time error myUnsafeId = safeId; // Compile-time error } -
提案の動機 03 仕様化を進めている新機能 - Sound declaration-site variance class Writer<T> {
void write(T x) => print(x); } void main() { Writer<Object> objectWriter = Writer<int>(); // Runtime error objectWriter.write("I'm a string!"); } -
提案の動機 03 仕様化を進めている新機能 - Sound declaration-site variance class Writer<T> {
void write(T x) => print(x); } void main() { Writer<Object> objectWriter = Writer<int>(); // Runtime error objectWriter.write("I'm a string!"); } -
概要 03 仕様化を進めている新機能 - Sound declaration-site variance class Writer<in T>
{ void write(T x) => print(x); } void main() { // Compile-time error Writer<Object> objectWriter = Writer<int>(); objectWriter.write("I'm a string!"); } -
概要 03 仕様化を進めている新機能 - Sound declaration-site variance class Writer<in T>
{ void write(T x) => print(x); } void main() { // Compile-time error Writer<Object> objectWriter = Writer<int>(); objectWriter.write("I'm a string!"); } -
Agenda 01 近年、どのような進化を遂げてきたか 02 Dart の進化プロセス 03 仕様化を進めている新機能 ・Patterns and
related features ・Static Metaprogramming ・Views on an object without a wrapper object ・Sound declaration-site variance 04 おわりに