dart-lang/sdk/CHANGELOG.md 1.22.0

## 1.22.0

### 言語仕様

  * 破壊的変更:['Generalized tear-offs'](https://github.com/gbracha/generalizedTearOffs/blob/master/proposal.md)は今回からサポートせず、エラーになります。1.21で既に言語仕様を変更し警告を追加していましたが、これがサポート完全終了の最終ステップです。なお、以前のバージョンではVMでのみのサポートでした。

  * `assert()` がオプショナルの第2引数 `message` を採れるよう拡張されました。 (SDK issue [27342](https://github.com/dart-lang/sdk/issues/27342)).

    メッセージは `assert` が失敗したときに表示されます。メッセージは任意のオブジェクトで良く、また、`AssertionError.message`でこれにアクセスできます。これはよりユーザフレンドリーな例外出力に利用できます。例えば、次のアサート

    ```dart
    assert(configFile != null, "Tool config missing. Please see https://goo.gl/k8iAi for details.");
    ```

    は次のような例外を出力します。

    ```
    Unhandled exception:
    'file:///Users/mit/tmp/tool/bin/main.dart': Failed assertion: line 9 pos 10: 
    'configFile != null': Tool config missing. Please see https://goo.gl/k8iAi for details.
    #0      _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:33)
    #1      _AssertionError._throwNew (dart:core-patch/errors_patch.dart:29)
    #2      main (file:///Users/mit/tmp/tool/bin/main.dart:9:10)
    ```

  * `Null` 型を型階層の「ボトム」に移動しました。これにより、`Null`は全ての型のサブタイプとして認識されます。 リテラル `null` は常に全てのクラスのサブタイプのインスタンスとして扱われていましたが、今回から `Null`クラスも全てのクラスのサブタイプになります。

    ```dart
    const empty = <Null>[];

    String concatenate(List<String> parts) => parts.join();
    int sum(List<int> numbers) => numbers.fold(0, (sum, n) => sum + n);

    concatenate(empty); // OK.
    sum(empty); // OK.
    ```

  * `covariant` パラメタ修飾子を導入しました。これを指定することでメソッドのパラメタ(とそれをオーバライドするメッソドの対応するパラメタ)のオーバライド規則を緩和します。Strong Modeでは健全性のために実行時型チェックが必要となりますが、ある種のコードで有用な構造化が可能になります。

    次のように、あるクラスファミリーに特定できるようになります。

    ```dart
    abstract class Predator {
      void chaseAndEat(covariant Prey p);
    }

    abstract class Prey {}

    class Mouse extends Prey {}

    class Seal extends Prey {}

    class Cat extends Predator {
      void chaseAndEat(Mouse m) => ...
    }

    class Orca extends Predator {
      void chaseAndEat(Seal s) => ...
    }
    ```

    これは静的に型安全ではありません。というのも、次のように書けるからです。

    ```dart
    Predator predator = new Cat(); // Upcast.
    predator.chaseAndEat(new Seal()); // Cats can't eat seals!
    ```

    Strong Modeの健全性を保つため、共変のオーバライドを用いるメソッド(ここでは`Cat.chaseAndEat()`)のボディにコンパイラが自動的にパラメタが期待される型であることをチェックするコードを挿入します。つまり、コンパイラが下記相当を提供します。

    ```dart
    class Cat extends Predator {
      void chaseAndEat(o) {
        var m = o as Mouse;
        ...
      }
    }
    ```

    標準仕様モード(訳注:Productionモード、Checkedモード)では、ユーザは滅多に必要としないにも関わらず、全てのパラメタでこのような不健全な振る舞いを許しています。Strong Modeは当初は全てで禁止していました。今回、この修飾子でどちらかを選べるようになりました。Strong Mode以外ではこの修飾子を無視します。

  * Strong Modeにおけるジェネリックスタイプの型引数の具体化時の般化限界規則を変更しました。型引数を省略した場合、コンパイラは何らかの型を想定する必要があります。Dart 1.0では単純に`dynamic`を想定していましたが、これでは型健全性がありません。

    ```dart
    class Abser<T extends num> {
       void absThis(T n) { n.abs(); }
    }

    var a = new Abser(); // Abser<dynamic>.
    a.absThis("not a num");
    ```

    `absThis()`のボディを型安全にするには`n`は少なくとも`num`との仮定が必要ですが、これが`T`に何らかの制約を設ける理由です。型引数として`dynamic`を想定するとこの例は破綻しますので。

    Strong Modeではこの般化限界を導入します。上記の例では、`num`が補完され、2行目でStringが渡される部分は正しく静的エラーとなります。

    とはいえ、あるケースではデフォルトの上限を見出すことが困難です。

    ```dart
    class RuhRoh<T extends Comparable<T>> {}
    ```

    初期のStrong Modeの振る舞いは意外で、意図しない結果となりました。1.22ではよりシンプルなアプローチを取り、妥当なデフォルト型引数(般化限界)が見つからない場合はエラーとなります。

### コアライブラリ

  * ある型の`Future`か即時値のいずれでも動作するコードの為に`FutureOr<T>`を定義しました。例えば、多くのテキスト操作(swizzler)があり、それらを連続して実行する手頃な関数(swizzle)がほしいとします。

    ```dart
    typedef String StringSwizzler(String input);

    String swizzle(String input, List<StringSwizzler> swizzlers) {
      var result = input;
      for (var swizzler in swizzlers) {
        result = swizzler(result);
      }

      return result;
    }
    ```

    これは上手く動作します。

    ```dart
    main() {
      var result = swizzle("input", [
        (s) => s.toUpperCase(),
        (s) => () => s * 2)
      ]);
      print(result); // "INPUTINPUT".
    }
    ```

    後に、非同期(例えばオンラインで同義語を検索するような)な操作をサポートしたいとします。`swizzle`のAPIを厳格に非同期化することも可能ですが、単純な同期型操作の戻り値をも手作業で`Future.value()`でくるむ必要が出てきます。`swizzle()`関数が同期性に対してポリモーフィックであれば理想的です。つまり、同期操作と非同期操作を同時に許すということです。なお、`await`は即時値でも許容されるので、これまでも動的に実装することは容易でした。

    ```dart
    Future<String> swizzle(String input, List<StringSwizzler> swizzlers) async {
      var result = input;
      for (var swizzler in swizzlers) {
        result = await swizzler(result);
      }

      return result;
    }

    main() async {
      var result = swizzle("input", [
        (s) => s.toUpperCase(),
        (s) => new Future.delayed(new Duration(milliseconds: 40), () => s * 2)
      ]);
      print(await result);
    }
    ```

    さて、`StringSwizzler`の型は何であるべきでしょうか。これまでは`dynamic`または`Object`を使う必要がありましたが、表現力を欠いていました。今回からはこのような書き方ができます。

    ```dart
    typedef FutureOr<String> StringSwizzler(String input);
    ```

    名前が示す通り、`FutureOr<String>`はユニオンタイプです。`String`か`Future<String>`にはなりえ、他のものにはなりえません。この例では、単によりコードの詳細な型情報を読者に提示すること以外に、特段利用価値が高いものではありません。戻り値について若干良いエラーチェックを提供しますが。

    `FutureOr<T>`は`Fufure.then()`のような *ジェネリック* なメッソッドで本当に重要になります。このケースでは、この特別なユニオンタイプは`then()`の型引数を渡されたクロージャーを元にシステムが型推論することを助けます。

    以前、Strong Modeは`Future.then()`を扱うための特別なルールを実装していました。`FutureOr<T>`は、第三者APIもこの恩恵に預かるための機能の一般公開でもあります。

### ツールの変更

* Dart2Js

  * (長い間非推奨だった) mixin typedefを削除します。

* Pub

  * 実際にトランスフォーマを利用しない限り、実行形式のためのバーバックアセットサーバを利用する必要がなくなりました。これによりプレコンパイルは大幅に高速化し、失敗時のエラーメッセージはわかりやすくなり、グローバルに実行する実行形式からも`Isolate.resolvePackageUri()` APIを一貫して使えるようになります。

  * Linuxにおいて元々設定されたパッケージのファイルのオーナーとパーミッションをパッケージ抽出時は常に無視するようになります。これは既に殆どの環境でデフォルトの動作でした。

  * パケージのキャッシュから出力される構文エラーをよりエレガントに扱います。pubspecが解析できないパッケージは、今回から`pub get --offline`と`pub cache repair`において無視されます。

  * `pub run`で起動した子プロセスの標準入力を適正にクローズするようになりました。

  * `pub serve`実行時にdart2jsから出力されるソースマップを修正しました。パッケージが提供するアセットへのURLが`pub serve`が提供する場所と一致するようになります(`../packages/package_name/`に代わり`packages/package_name`)。

### インフラ変更
* SDKはgypに代わりGNを使うようになり、ninja専用になります。ドキュメントは[wiki](https://github.com/dart-lang/sdk/wiki/Building-with-GN)にあります。`tools/gn.py`もヘルプも参照ください。この変更はgypの非推奨化に対応するものです。本バージョンでは`gclient sync`または`gclient runhooks`を実行する前に環境変数`DART_USE_GYP`を設定することでgypによるビルドファイルの生成が可能ですが、これも将来は削除されます。