Slide 1

Slide 1 text

Dart言語仕様 Pick-up tomochikahara @zetta1985

Slide 2

Slide 2 text

Agenda ● Method Cascading ● Named / Factory Constructor ● Const Variable ● Implicit Interfaces / Mix-in

Slide 3

Slide 3 text

Method Cascading

Slide 4

Slide 4 text

● クエリ・コマンド分離原則に反する ○ 状態を変えるメソッドなのに戻り値がある ○ 戻り値がCalleeと同じ参照であることをシグネチャが表 現していない ● 専用のシグネチャが必要 ○ ライブラリ提供者の意図を汲む必要がある ○ 専用のシグネチャを持たないメソッドはMethod Chainで きない ○ 変更に弱い ※ Method Chain != Fluent Interface 従来のMethod Chainへの批判

Slide 5

Slide 5 text

● 全てのメソッドをMethod Chainできる ○ 戻り値を捨てる ○ 代わりにMethod Cascading式で返される値がCalleeに なる ○ 専用のシグネチャを定義する必要無し ○ Method Chainするか否かはライブラリ利用者が自由に 決める ● 使い道 ○ DOM APIをjQuery-likeに ○ 複数の副作用メソッドの呼び出しを一つの式に Method Cascadingでの解決

Slide 6

Slide 6 text

var tokai = (new StringBuffer("[") ..writeAll(["Aichi", "Gifu", "Mie"], ",") ..write("]")).toString(); Method Cascadingの例 query("#sample_text_id") ..text = "Click me!" ..onClick.listen(reverseText); var person = (new PersonBuilder()..name = "to_hara"..age = 13).build();

Slide 7

Slide 7 text

Named / Factory Constructor

Slide 8

Slide 8 text

Constructorの基本 class Person { final bool isAdult; Person(this.isAdult); } 仮引数の定義とフィールドの初期化 class Person { final bool isAdult; Person(int age) : this.isAdult = age >= 20; } class Person { bool isAdult; Person(int age) : this.isAdult = age >= 20 { assert(age < 20 == !isAdult); } } フィールド初期化式リスト (コンストラクタのリダイレクト含む) オブジェクト初期化子 (finalフィールドへの初期化はできない)

Slide 9

Slide 9 text

● コンストラクタに任意の名前を付けられる ○ Dartは動的言語なので、パラメータの型によるコンストラ クタのオーバーロードができない ○ 複数のコンストラクタを定義するときは名前を付ける Named Constructor (名前付きコンストラクタ) class Person { final String name; Person(this.name); Person.copy(Person original) : this.name = original.name; } var hara = new Person("Hara"); var hara2 = new Person.copy(hara);

Slide 10

Slide 10 text

● コンストラクタの実装をFactory Methodで ○ クライアントからはGenerative / Factoryの違いはわか らない ○ インスタンスのキャッシュ、パラメータから実クラスの選 定、DIコンテナへの委譲など Factory Constructor abstract class Person { final int age; Person._internal(this.age); factory Person(int age) => age < 20 ? new Young(age) : new Adult(age); } class Young extends Person { Young(int age) : super._internal(age); } class Adult extends Person { Adult(int age) : super._internal(age); }

Slide 11

Slide 11 text

Const Variable

Slide 12

Slide 12 text

● コンパイル時にオブジェクト生成式を評価 ○ 言語仕様によるFlyweightパターンの実装 ○ 動作時の不変性が保証される ● 用途 ○ 不変性の明示?パフォーマンス? ○ ぶっちゃけ用途がわからない・・・ ○ finalではインライン展開されないことを厳密に既定し かった? ■ Javaはプリミティブなfinal変数がインライン展開される。外部jar内のプ リミティブなfinal変数を参照、コンパイルした後、外部jar内のプリミティ ブなfinal変数の値を変えた場合、コンパイルしなおす必要がある 変数のインライン展開

Slide 13

Slide 13 text

● const初期化を可能にするコンストラクタ ○ 要求(制限) ■ 全てのフィールドにfinalがついていること ■ 全てのフィールドの値がconst初期化できること ■ オブジェクト初期化子が記述されていないこと ■ Factory Constructor ではないこと Const Constructor class Location { final String name; const Location(this.name); } var l3 = const Location("Aichi"); var l4 = const Location("Aichi"); print( identical( l3, l4 ) ); // true

Slide 14

Slide 14 text

Implicit Interfaces / Mix-in

Slide 15

Slide 15 text

Implicit Interfaces (暗黙的Interface) ● あらゆるクラスが暗黙的にインタフェースをもつ ○ インタフェース=Java等と同じ ■ 型名とメソッドのシグネチャのみが定義される class Person { final bool isAdult; Person(int age) : this.isAdult = age < 20; } class Young implements Person { // getterのオーバーライド bool get isAdult => false; }

Slide 16

Slide 16 text

Mix-in Application ● クラスに振るまいを追加する ○ 任意のクラスをMix-in可能にするための制限 ■ コンストラクタが定義されていないこと ■ Objectクラスを継承していること ■ super呼び出しがされていないこと class Printable { void printMe() => print(this.toString()); } class Person extends Object with Printable { final int age; Person(this.age); String toString() => "I'm $age years old."; }

Slide 17

Slide 17 text

Implicit Interfaces & Mix - inの実用例 Dependency Injection : Cake Pattern class Repository { List find() => ["data1", "data2"]; } class Service { Repository get repository => new Repository(); void execute() => print(repository.find()); } class AwesomeRepository implements Repository { List find() => ["awesomeData1", "awesomeData2"]; } abstract class AwesomeRepositoryModule { Repository get repository => new AwesomeRepository(); } typedef AwesomeService = Service with AwesomeRepositoryModule;