LoginSignup
8
1

More than 5 years have passed since last update.

dart-lang/sdk/CHANGELOG.md 1.22.0

Posted at

1.22.0

言語仕様

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

  • assert() がオプショナルの第2引数 message を採れるよう拡張されました。 (SDK issue 27342).

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

    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クラスも全てのクラスのサブタイプになります。

    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では健全性のために実行時型チェックが必要となりますが、ある種のコードで有用な構造化が可能になります。

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

    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) => ...
    }
    

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

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

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

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

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

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

    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が渡される部分は正しく静的エラーとなります。

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

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

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

コアライブラリ

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

    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;
    }
    

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

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

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

    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を使う必要がありましたが、表現力を欠いていました。今回からはこのような書き方ができます。

    typedef FutureOr<String> StringSwizzler(String input);
    

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

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

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

ツールの変更

  • Dart2Js

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

    • 実際にトランスフォーマを利用しない限り、実行形式のためのバーバックアセットサーバを利用する必要がなくなりました。これによりプレコンパイルは大幅に高速化し、失敗時のエラーメッセージはわかりやすくなり、グローバルに実行する実行形式からもIsolate.resolvePackageUri() APIを一貫して使えるようになります。
    • Linuxにおいて元々設定されたパッケージのファイルのオーナーとパーミッションをパッケージ抽出時は常に無視するようになります。これは既に殆どの環境でデフォルトの動作でした。
    • パケージのキャッシュから出力される構文エラーをよりエレガントに扱います。pubspecが解析できないパッケージは、今回からpub get --offlinepub cache repairにおいて無視されます。
    • pub runで起動した子プロセスの標準入力を適正にクローズするようになりました。
    • pub serve実行時にdart2jsから出力されるソースマップを修正しました。パッケージが提供するアセットへのURLがpub serveが提供する場所と一致するようになります(../packages/package_name/に代わりpackages/package_name)。

インフラ変更

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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
1