2012年8月17日金曜日

マイルストーン1を追いかける

このエントリーをはてなブックマークに追加
GoogleのDart開発者たちは、マイルストーン1という区切りへ向けて開発を進めています。Dart EditorやEclipse用Dartプラグインのような開発環境や、Dart VMやdart2jsのような言語環境は日々更新されており、そしてDart言語仕様についても変更が予定されています。

言語仕様についてはBugs and Feature Requestsメーリングリストで議論されており、マイルストーン1に向けての大きなトピックがMilestone 1 Language Changesという文書でまとめて公開されています。

ただしマイルストーン1の内容がすべて固まっているわけではなく、2012年8月17日現在で公開されている言語仕様は0.10ですが、マイルストーン1の内容は含んでいません。近いうちに0.11が公開されることになっていて、その内容はほぼマイルストーン1の仕様を反映したものになるようです。

特にcode.google.comに公開されているBugs and Feature RequestsのページではDartのバグや要求がIssuesとして公開されており、これを見るとプロジェクトの進み具合がなんとなく分かります。マイルストーン1に向けたIssuesはhttp://code.google.com/p/dart/issues/list?can=2&q=milestone=M1というURLで確認できます。

また、この内容をChromeのボタンで監視できるサードパーティー製のエクステンションがDart Milestone 1 monitorという名前で公開されており、これをインストールするとChromeでIssuesの数を見ることができます。まだ300個前後を行き来していますので収束するにはしばらくかかりそうですが、なんとなく見ているのも面白いと思います。

英語の得意な方は、Dart開発者のビデオキャストやポッドキャストDartisansをチェックするのもよいでしょう。

XMLHttpRequestがHttpRequestになります

このエントリーをはてなブックマークに追加
XMLHttpRequest といえば、スクリプト内からサーバーへデータを要求するためによく使われる手段の一つですが、名前に反してデータの形式はXMLに限られているわけではありません。もちろんXMLもよく使われる形式ですが、最近はどちらかというとJSONの方が多くなっています。

というわけで、Dartの XMLHttpRequest は HttpRequest に名前を変えようという話になっているようです(Issue 912 - Rename "XMLHttpRequest" -> "HttpRequest" in dart:html)。今後どこかのタイミングで変更されることになりそうですが、変更されると今までのスクリプトを対応させる必要がありますので、覚えておくとよいでしょう。

2012年8月14日火曜日

Eclipse用Dartプラグインを試す

このエントリーをはてなブックマークに追加
Eclipse用のDartプラグインがプレビューとして公開されました。

Dartの開発環境としてはEclipseベースのDart Editorがありましたが、プラグインではなく単体のアプリケーションという形で配布されていました。それに対してコミュニティーから多くの要望があったためか、今回Eclipseプラグインが公開されました。

現時点ではプレビューという扱いになっていますので、普段利用している環境へはインストールしないほうが良いでしょう。とはいえ、Eclipseの豊富なプラグインが使えるのは魅力的ですので、今後に期待したいところです。

アップデート サイトはこちらです。 http://www.dartlang.org/eclipse/update/

以下、実際にUbuntuでEclipseとDartプラグインをインストールしてみます。WindowsやMac OSでも同じようにインストールできるはずです。

まずはEclipseをインストールします。Eclipseの動作に必要なJavaランタイムをインストールしましょう。Eclipseは Eclipse Downloads からダウンロードできます。



現時点(2012/8/14)での最新版はEclipse Juno(4.2)です。ダウンロードしたファイルを展開し、Eclipseを実行しましょう。


Eclipseのメインメニューから Window - Preferences を選びます。


Install/Update - Available Software Site を選び、アップデート サイトを登録します。Nameは「Dart plugin for Eclipse」、Locationは「http://www.dartlang.org/eclipse/update/」にしましょう。


次に、Eclipseのメイン画面に戻って、メニューの Help - Install New Software... を選びます。


Installウィンドウの Work with: で、先ほど登録したアップデート サイトを選びます。すると画面の下部にDart Editorが現れますので、選択して次へ進みます。


インストールが済むと再起動の確認が表示されますので、Yes を押して再起動します。


Eclipseが再起動すると、自動的にDart SDKのダウンロードが始まります。画面右下に進捗が表示されます。


Dart SDKのダウンロードが終わったら、もう一度Eclipseを再起動させたほうが良いようです。それが済めばプラグインのインストールは完了です。

まず、設定画面を開いてみましょう。メニューの Window - Preferences の画面から、Dart を選択します。


設定項目はDart Editorとほぼ同じです。ただしSDKという項目が増えており、ここでDart SDKの更新が行えるようです。Dartプラグインをインストールすれば、別途Dart SDKをダウンロードする必要はありません。


Dart用のパースペクティブも用意されています。


新規プロジェクトにもDartが追加されます。


Dart Editorで使えるリファクタリングやデバッグの機能も使えますし、もちろんEclipseの他の機能やプラグインも使えます。

短い時間ですが試してみた限りでも、いくつかよくわからない動作をする点も見られますが、やはりEclipse上で使えるという利点は大きいと思います。Eclipseに慣れている人であれば、Dart Editorよりもこちらを使ったほうが良さそうです。

2012年5月30日水曜日

スクリプトの情報(引数など)を取得する

このエントリーをはてなブックマークに追加
Dartではdart:coreのOptionsを使うと、dartコマンドのパスや、スクリプトのパス、スクリプト起動時の引数を取得することができます。
void main() {
  Options opt = new Options();
  print("executable=${opt.executable}");
  print("script=${opt.script}");
  opt.arguments.forEach((e) => print("argument=$e"));
}
このコードをDart Editor上で実行してみましょう。スクリプトへの引数はManage LaunchesのウィンドウからScript arguments欄に設定することができます。

ここでは引数として「abc 123」と指定してみました。結果は次のようになります
executable=/home/dart-ing/Downloads/dart/dart-sdk/bin/dart
script=/home/dart-ing/dart/OptionsTest/OptionsTest.dart
argument=abc
argument=123

2012年5月22日火曜日

IntelliJ IDEAのDartプラグインを使ってみる

このエントリーをはてなブックマークに追加
JetBrainsが提供している統合開発環境のIntelliJ IDEA 11に、Dart用のプラグインがあります。以前から提供されていましたが、最近バージョンアップされたので使ってみました。

このプラグインはプラグインリポジトリに登録されていますので、IntelliJ IDEA上からインストールすることができます。リポジトリの一覧を開いて Dart で検索するとプラグインが見つかります。


プラグインをインストールすると、.dart ファイルをDartファイルとして認識します。


文法もある程度認識しており、途中まで入力したクラスやメソッドを補完することもできます。


今のところあまり機能は多くないため本格的な開発に使うというわけにはいきませんが、Dart Editor以外の選択肢として期待したいと思います。

2012年5月16日水曜日

Dartで例外を処理する

このエントリーをはてなブックマークに追加
Dartには例外処理の機能が備わっています。

例外を受け取る

発生した例外を受け取るには、try - catch を使います。サンプルコード
void main() {
  int a = 0;
  try {
    a.length;
  } catch (final NoSuchMethodException e) {
    print(e);
  }
}
このコードではint型の変数のlengthプロパティを参照していますが、そのようなプロパティ(getterメソッド)はint型には存在しないので NoSuchMethodException が発生します。これを catch で受け取っています。

catch に型を指定しないこともでき、そうすることであらゆる型のオブジェクトを受け取ることができます。また、1つの try に対して複数の catch を書くこともできます。その場合は、上から順に見て行って最初に型が一致したものが実行されます。
void main() {
  int a = 0;

  try {
    a.length;
  } catch (final var e) {
    /* ここが実行されます。 */
  }

  try {
    a.length;
  } catch (final NoSuchMethodException e) {
    /* ここが実行されます。 */
  } catch (final e) {
    /* ここは実行されません。 */
  }
}
例外発生箇所のスタックトレースを受け取るには、catch の2つめの要素として指定します。
void main() {
  int a = 0;
  try {
    a.length;
  } catch (final NoSuchMethodException e, var stack) {
    print("exception: $e");
    print("stack: $stack");
    /*
exception: NoSuchMethodException : method not found: 'get:length'
Receiver: 0
Arguments: []
stack: 0. Function: 'Object.noSuchMethod' url: 'bootstrap' line:2698 col:3
 1. Function: '::main' url: 'file:///home/dart-ing/dart/ExceptionTest/ExceptionTest.dart' line:4 col:13
     */
  }
}
このように例外を簡単に受け取ることができますが、実際には例外の発生を予期するのは難しいことです。コードの中で受け取られなかった例外は、実行環境側へ渡されて Unhandled exception としてそれぞれの方法で処理されます。

後処理を実装する

try を抜けた時に必ず実行されるコードを finally に書くことができます。サンプルコード
void main() {
  int a = 0;
  try {
    a.length;
  } catch (final NoSuchMethodException e) {
    print(e);
  }
  finally {
    print("finally");
  }
}
この場合、catch による例外処理が行われてから、最後に finally が実行されます。

例外を発生させる

例外を発生させるには throw を使います。サンプルコード
void main() {
  try {
    throw new Exception("message");
  } catch (final Exception e) {
    print(e); // Exception: message
  }
}

標準APIでの例外

Dartの標準API(dart:coreなど)にはあらかじめいくつかの例外が用意されています。それらはすべて Exception から派生した型になっています。例外についてはいろいろな考え方がありますが、自分で例外を用意する場合には Exception から派生した型を使ったほうがわかりやすいでしょう。

非同期処理でも例外を処理する必要があります。例えばファイルI/Oなどです。Dartでは File の非同期処理を Future を使って実装しているため、ファイルI/Oの例外処理をするならば Future の例外処理について知る必要があります。といっても特に難しいものではなく、例外が発生すると Future.handleException に指定した関数が呼ばれますので、そこで処理することになります。Future については以前の記事(Dartで未来(Future)の処理を実装する)も参考にしてください。

2012年5月1日火曜日

dart:domは使えなくなります

このエントリーをはてなブックマークに追加
公式サイトの情報(Deprecation notice: Migrate from dart:dom to dart:html)によるとdart:domライブラリはdart:htmlライブラリに統合され、今後は使用できなくなります。もともとdart:htmlの使用が推奨されていましたし、dart:domを使ったプログラムを作りこまれている方は少ないとは思いますが、もしdart:domを使用していた場合にはdart:htmlへ移行する必要があります。

dart:domからdart:htmlへの移行にあたっては、緊急避難として "$dom_古い名前" という形式のメソッド(例えば、Node.childNodes は Node.$dom_childNodes)としてdart:htmlライブラリ内に残されますが、いずれ消えることになりそうです。

今後は、dart:domの代わりにdart:htmlを使用します。dart:htmlの使用方法については Improving the DOM が詳しいです。簡単に説明すると次のように使います。
  • HTMLElementのようなHTMLXxxという名前の代わりに、単にXxxとなっています(例:ElementAnchorElement)。ちなみにSVGXxxはそのままSVGXxxです。
  • ノードを取り出すには getElementById などに代わって、Document.query と Element.queryAll という2つのメソッドを使います。
  • コレクションはDOMのものではなく、DartネイティブのListやMapが使われます。
  • 新規の要素を作るのにdocument.createElementとする必要はなく、Element.tag と Element.html コンストラクタを使用します。(例:new Document.tag('a') )
  • イベントは Document.on で取得した ElementEvents に設定します。

2012年4月30日月曜日

UbuntuのUnityランチャーへDart Editorを登録する

このエントリーをはてなブックマークに追加
UbuntuのUnityランチャー(画面左側に表示されているアプリケーション ランチャー)へ Dart Editor を登録する方法です。


現在のところLinux版のDart Editorは、debパッケージではなくzipファイルとして配布されています。そのため、そのままではUnityランチャーへ登録できません。登録するためには、.desktopファイルを用意する必要があります。

ここでは次の環境で確認しました。
  • Ubuntu 12.04
  • Dart Editor (build 6943)

まず、Text Editorを起動します。


エディターに次の内容を入力ます。
[Desktop Entry]
Version=1.0
Type=Application
Terminal=false
StartupNotify=true
Icon=Dartを展開したパス/icon.xpm
Name=Dart Editor
Comment=Dart IDE
Exec=Dartを展開したパス/DartEditor
Categories=Development;IDE;
IconとExecに設定するパスは環境にあわせて設定してください。例えば、私の場合は /home/dart/Downloads にダウンロードしてその場所で展開しましたので、次のようになりました。


.desktopファイルについてより詳しくは知るには、Desktop Entry Specification (freedesktop.org)を参照してください。

入力できたらそのファイルを Dart Editor.desktop という名前で保存します。とりあえずDesktopに保存しましょう。


ただし、このままでは実行できません。実行するにはファイルの実行属性を設定する必要があります。保存したファイルを右クリックしてPropertiesを選択します。


プロパティのPermissionsタブで、Allow executing file as program にチェックを入れます。


これでもう一度 Dart Editor.desktop ファイルを見ると、アイコンが Dart のものに変わっていると思います。これをダブルクリックするとDart Editorが起動します。


Dart Editor.desktopファイルからDart Editorが起動できることを確認したら、Unityランチャーへ登録しましょう。まず、Dart Editor.desktopファイルを $HOME/.local/share/applications へ移動します。フォルダを開いてメニューから Go - Location... を選択するとパスが指定できますので、.local/share/applications を開きます。 applicationsがない場合は新規に作成します。ここへDart Editor.desktopを置きます。


最後に、UnityランチャーへDart Editorを登録しましょう。 $HOME/.local/share/applications へ移動した Dart Editor.desktop を、Unityランチャーへドラッグ&ドロップすると登録されます。Dart Editorを起動してから、Dartのアイコンを右クリックして Lock to Launcher を選択しても構いません。


これでUnityランチャーからDart Editorを起動できるようになります。

2012年4月23日月曜日

Dartでフィボナッチ数

このエントリーをはてなブックマークに追加
Dartの練習です。初期配列を与えてnacci関数を呼び出すと、そのフィボナッチ数列を返すクロージャーを返します。Dartboardで実行
nacci(List sequence) {
  int type = sequence.length;
  return calc(int n) {
    if (sequence.length < n + 1) {
      int value = 0;
      for (int i = 1; i <= type; i++) {
        value += calc(n - i);
      }
      sequence.add(value);
    }
    return sequence[n];
  };
}

void main() {
  var fibo = nacci([0, 1]);
  var tri = nacci([0, 0, 1]);
  var tetra = nacci([0, 0, 0, 1]);
  var lucas = nacci([2, 1]);
  for (int i = 0; i <= 10; i++) {
    print("$i : ${fibo(i)}, ${tri(i)}, ${tetra(i)}, ${lucas(i)}");
  }
}
実行結果:
0 : 0, 0, 0, 2
1 : 1, 0, 0, 1
2 : 1, 1, 0, 3
3 : 2, 1, 1, 4
4 : 3, 2, 1, 7
5 : 5, 4, 2, 11
6 : 8, 7, 4, 18
7 : 13, 13, 8, 29
8 : 21, 24, 15, 47
9 : 34, 44, 29, 76
10 : 55, 81, 56, 123

参考:wikipedia:フィボナッチ数

文字列と数値を変換する

このエントリーをはてなブックマークに追加
Dartで文字列(String)と数値(num)を変換するには次のようにします。

文字列から数値を得る

整数(int)を得る場合はMath.parseInt、小数を得る場合には Math.parseDouble を使います。サンプルコード
main() {
  int i = Math.parseInt("123");
  double d = Math.parseDouble("1.23");
  print("i=$i, d=$d");
}
変換に失敗するとBadNumberFormatException例外が発生します。

数値リテラルとして表現可能な文字列が変換可能なようですので、次のような変換もできます。サンプルコード
main() {
  // 大きな数(1e+30)
  print(Math.parseInt("1000000000000000000000000000000"));
  // 16進数(10)
  print(Math.parseInt("0xA"));
  // 指数表現(10)
  print(Math.parseDouble("1e+1"));
}

数値から文字列を得る

単純に文字列リテラルとして、あるいはtoStringメソッドで変換できます。
main() {
  int i = 1;
  print("$i, ${i.toString()}"); // 1, 1
}
書式を指定するにはnumクラスに用意されている次のメソッドを使います。

toRadixString
指定の進数の文字列
toStringAsExponential
指定した指数値を持つ文字列
toStringAsFixed
指定桁数の小数部を持つ文字列
toStringAsPrecision
指定精度の文字列

サンプルコード
void main() {
  print("123=${123.toRadixString(10)}(10)"); // 123(10)
  print("123=${123.toRadixString(16)}(16)"); // 7b(16)
  print("123=${123.toStringAsExponential(1)}"); // 1.2e+2
  print("123=${123.toStringAsExponential(2)}"); // 1.23e+2
  print("123=${123.toStringAsExponential(3)}"); // 1.230e+2
  print("123.45=${(123.45).toStringAsFixed(1)}"); // 123.5
  print("123.45=${(123.45).toStringAsFixed(2)}"); // 123.45
  print("123.45=${(123.45).toStringAsFixed(3)}"); // 123.450
  print("123.45=${(123.45).toStringAsPrecision(2)}"); // 1.2e+2
  print("123.45=${(123.45).toStringAsPrecision(3)}"); // 123
  print("123.45=${(123.45).toStringAsPrecision(4)}"); // 123.5
}

2012年4月17日火曜日

クラスのインターフェイスを利用する

このエントリーをはてなブックマークに追加
Javaでテストコードを書いたことのある人は、次のようなコードをたくさん書いたことがあると思います。
// テストコードを含む典型的なJavaのコード

// インターフェイス
interface IDuck {
  void quack();
}

// 実装クラス
class Duck implements IDuck {
  void quack() { /* ... */ }
}

// テスト用のモック クラス
class MockDuck implements IDuck {
  void quack() { /* ... */ }
}
本来、実装に必要なのはDuckクラスだけですが、自動テストのためにIDuckインターフェイスを作り、そこからテスト用のモック クラスを用意しています。モックを自動生成するライブラリもいくつかありますが、設定の手間が必要だったり、コードがJavaの言語仕様からみると不自然な感じになったりしてしまいます。(それでも便利ですが)

Dartでも同じように書くことはできますが、Dartではクラスをインターフェイスとして利用できます。つまり、モックを作るためにインターフェイスを用意する必要はなく、クラスから直接モック クラスを作ることができます。サンプルコード
// 実装クラス
class Duck {
  quack() => 'complicated enterprise n-tier quack';
}

// テスト用のモック クラス
// Duckクラスを実装(implements)する。
class MockDuck implements Duck {
  quack() => 'quack for testing';
}

main() {
  Duck duck = new MockDuck();
  print(duck is Duck); // true
  print(duck.quack()); // quack for testing
}
MockDuckクラスはDuckクラスを実装(implements)しています。もちろん、MockDuckではquackメソッドを実装する必要があります。

なお、この機能は、Dartboard(try.dartlang.org)では問題なく利用できますが、現在公開されている最新のDart Editor(ビルド6479、2012/4/12公開)では不具合があるため利用できません。すでに修正されていますので次のリリースから利用できると思います。

2012年4月11日水曜日

Dartをチェックモードで動かす方法(更新版)

このエントリーをはてなブックマークに追加
Dartの実行モードには、プロダクション モードとチェック モードがあります。プロダクション モードでは、変数の代入などについて型による制限はありませんが、チェック モードでは型のチェックがコンパイル時と実行時に行われます。

開発時はチェック モードで動作させ、製品リリース後はプロダクション モードで動かす、といった使い方が想定されます。

そのため何も指定せずにDartスクリプトを実行するとプロダクション モードで動きます。チェック モードで動かす方法は次のとおりです。

Dart Editorの場合

スクリプトの実行設定画面の Run in checked mode のチェックを入れます。



Dartboard (try.dartlang.org)の場合

画面左上にあるChecked Modeにチェックを入れます。


dart(Dart VM)の場合

--enable_checked_mode フラグを指定します。--enable-checked-mode や --enable_checked_mode=true でも同じです。
$ cat test.dart
main() { int a = 'a'; }
$ dart --enable_checked_mode test.dart
Unhandled exception:
type 'OneByteString' is not a subtype of type 'int' of 'a'.
 0. Function: '::main' url: 'file:///test.dart' line:1 col:18

frogc( Dart-to-JavaScript compiler)の場合

デフォルトで有効になっています。
$ cat test.dart
main() { int a = 'a'; }
$ frogc test.dart
test.dart:1:18: warning: type "dart:core.String" is not assignable to "dart:core.int"
main() { int a = 'a'; }
                 ^^^


こちらもどうぞ

2012年4月10日火曜日

Dartで未来(Future)の処理を実装する

このエントリーをはてなブックマークに追加
この記事の内容は古くなっていますので、新しい解説記事を書きました(2013/5/8)Future を使いこなす

Dartでは、「まだ受け取っていない(未来の)値をどのように処理するか」を記述することができます。

まずは逐次型処理から考えてみましょう。ひとつの処理が終わってから次の処理を行う逐次型処理は、次のように記述できます。
void main() {
  // 処理1
  // 処理2
}
このプログラムは、処理1が終わってから処理2が実行されます。処理2が処理1の結果を受け取って処理される(処理2は処理1の結果に依存している)のであれば、この順で書くしかありません。たとえば次のような例が考えられます。
void main() {
  double a, b;
  a = Math.random(); // 処理1
  b = a * 2; // 処理2
}
このプログラムは、処理1の結果であるaの値が定まらないと、処理2の結果であるbの値も定まりません。

ここで、処理1と処理2を別々に書きたい場合があります。つまり、例えば次のように書きたいということです。
void main() {
  // 処理2
  // 処理1
}
もしこのように書けるのであれば、処理1を別の関数やクラスに追い出すこともできます。しかし逐次型プログラミングではこのような書き方はできません。

まだ計算されていない未来の結果に対して処理を記述したいという要求は、処理1が複雑だったり、処理1の途中でエラーが発生する可能性があるような場合に出てきます。たとえば通信の入出力処理と、その結果を加工するような処理です。もし複雑な処理1とそれが終わった時の処理2を別々に記述することができるのであれば、見通しのよいプログラムを書くことができます。

このような要求はfutureと呼ばれるプログラミング パターンによって解決できます。DartではFuture<T>Completer<T>でこれを実現します。サンプルコード
void main() {
  final Completer<double> comp = new Completer<double>();
  final Future<double> fut = comp.future;
  fut.then((double a) {
    // 処理2
    double b = a * 2;
    print("b=${b}");
  });
  
  // 処理1
  double a = Math.random();
  print("a=${a}");
  comp.complete(a);
}
実行例
a=0.00013735424727201462
b=0.00027470849454402924
Completer<T>の型パラメーターTは、処理が終わったあとに受け取る値の型です。Completerのfutureプロパティで、そのCompleterで処理が終わったときに呼び出されるFutureのインスタンスが取得できます。このFutureインスタンスの型パラメーターもTになります。

処理が終わったらCompleterのcompleteメソッドを、処理結果とともに呼び出します。これによってFutureのthenメソッドに渡した関数が呼び出されます。

Futureを用いた実装では、処理2を処理1より前に書くことができています。このまま処理1を別の関数やクラスに持っていくこともでき、呼び出し側は処理2が終わったらその結果を受け取った時の処理だけを書くことができるようになるのです。


処理中のエラーを補足する

処理の途中で発生したエラー(例外)をFutureへ伝えるには、CompleterのcompleteExceptionを呼び出します。この例外はFutureのhandleExceptionメソッドで受け取ることができます。handleExceptionメソッドでtrueを返すと、そこで例外の処理が完了したことを通知します。サンプルコード
void main() {
  final Completer comp = new Completer();
  final Future fut = comp.future;
  fut.then((double a) {
    double b = a * 2;
    print("b=${b}");
  });
  fut.handleException((Object exception) {
    print("exception=${exception}"); // exception=Error!
    return true;
  });
  
  // 処理で発生したエラーをFutureに伝える。
  comp.completeException("Error!");
}

複数のFutureの処理を続けて行う

2つのCompleterが存在し、それぞれ処理が終わったところでなにかの処理を順番に行わせるためには、Futureのchainメソッドを利用します。この機能を利用すると、複数のCompleterで処理を行わせ、その結果を順次処理できます。

chainメソッドの戻り値として次に呼び出されるべきFutureを返します。
void main() {
  final Completer<int> comp1 = new Completer<int>();
  final Completer<int> comp2 = new Completer<int>();

  comp1.future.chain((int a) {
    print("a=${a}");
    return comp2.future;
  }).then((int b) {
    print("b=${b}");
  });

  // comp1とcomp2のcomplete順を入れ替えても結果は同じ。
  // a=1
  // b=2
  comp1.complete(1);
  comp2.complete(2);
}

結果を変換するFutureを作る

Futureのtransformメソッドを使うと、結果の値を変換して格納することができます。transformに変換処理を行う関数を渡して呼び出すと、その変換処理を伴うFutureが返ります。
void main() {
  final Completer comp = new Completer();

  // 単純なFuture
  comp.future.then((int a) { print("a=${a}"); });

  // 変換処理を伴うFuture
  final Future tf = comp.future.transform((int a) => a * 2);
  tf.then((int b) { print("b=${b}"); });
  
  comp.complete(1);
}
実行結果
a=1
b=2

複数のFutureの結果を待つ

複数のFutureがすべて完了するのを待つためにはFuturesのwaitメソッドを使います。Futureのリストを渡すと、すべてのFutureの完了を待つ新しいFutureが返りますので、そのFutureインスタンスに対してthenメソッドを呼び出します。サンプルコード
void main() {
  final Completer<int> comp1 = new Completer<int>();
  final Completer<int> comp2 = new Completer<int>();
  
  // 複数のFutureがすべて完了するまで待つ。
  final Future<List<int>> fs =
    Futures.wait([ comp1.future, comp2.future ]);
  fs.then((List<int> results) {
    // 結果をすべて表示する。
    for (int result in results) {
      print("result=${result}");
    }
  });

  // 完了
  comp1.complete(1);
  comp2.complete(2);
}
実行結果
result=1
result=2

Futureのプロパティ

Futureには結果や状態を知るためのプロパティが用意されていますので、これらの動作をよく理解することがFutureを使いこなすことにつながります。

なおここで処理中とは、completeあるいはcompleteExceptionメソッドが呼び出される前、正常終了後はcompleteメソッドが呼び出されたあと、エラー発生後はcompleteExceptionが呼び出されたあとのことです。
isComplete
処理中:false
正常終了後:true
エラー発生後:true
hasValue
処理中:false
正常終了後:true
エラー発生後:false
value
処理中:FutureNotCompleteException例外がスローされる
正常終了後:結果の値
エラー発生後:エラーの値(completeExceptionの引数)
exception
処理中:FutureNotCompleteException例外がスローされる
正常終了後:null
エラー発生後:エラーの値(completeExceptionの引数)

2012年4月5日木曜日

Windows版DartiumがDart Editorに同梱されました

このエントリーをはてなブックマークに追加
Dart Editorの最新版(ビルド6167)が公開され、Dart VMを搭載したWebブラウザDartiumが、Windws版Dart Editorの配布物にも同梱されるようになりました。これでLinuxやMacと同じように、Windowsでもフル機能を使った開発が行えるようになりました。

Linux版やMac版も新しいバージョンが公開されています。すでに使われている方も、ぜひ更新して使ってみましょう。

Dart Editorは公式サイトからダウンロードできます。

Tutorial: Dart Editor

ダウンロードしたファイルを展開すると、dartフォルダーの下にDartEditorの実行ファイルがありますので実行します。


Dart Editorのウィンドウが開きます。


サンプルのClockを開いてみましょう。


ツールバーの緑の矢印ボタンで実行します。


Dartiumが開いて実行されます。


Manage Launches(実行構成管理)にあるEnable debuggingのチェックボックスをチェックしてから実行すると、デバッグ実行ができます。


ブレークポイントを設定してステップ実行したり、


実行中のコードにある変数の値を見ることもできます。


どうでしょうか。とても便利に使える開発環境になってきたと思います。

2012年4月4日水曜日

DartiumのWindows版がダウンロードできるようになっています

このエントリーをはてなブックマークに追加
Dart VMを搭載したChromiumブラウザのDartiumですが今まではLinux版とMac版だけが公開されていて、Windowsで利用するには自分でソースコードからビルドする必要がありました。

最近になって、Windows版のDartiumもバイナリーがビルドされるようになり、公式サイトからダウンロードできるようになっています。

Chromium with the Dart VM


少し確認した限りでは、半月ほど前と比べて格段に安定して動くようになっています。

現時点ではDartium単体でダウンロードできるものの、Dartの開発環境であるDart EditorのWindows版にはDartiumは同梱されていません。しかしナイトリービルドではすでに同梱されるようになっていますので、近いうちにリリース版がダウンロードできるようになるでしょう。


2012年3月21日水曜日

新しいDart Editor(ビルド5549)が公開されています

このエントリーをはてなブックマークに追加
新しいDart Editor(ビルド5549)が公開されています。

ダウンロードはこちらから。
Tutorial: Dart Editor : Dart : Structured web programming

FileビューでDartのライブラリが参照できるようになっています。以前のLibraryビューのように使えるようになりました。

2012年3月18日日曜日

DartiumのWindows版ビルド済みバイナリが公開されています

このエントリーをはてなブックマークに追加
Dart VMを搭載したWebブラウザDartiumのWindows版ビルド済みバイナリが公開されています。MacOS X版とLinux版のバイナリはすでに公開されていましたが、これでWindowsでも気軽に試せるようになります。

今確認したところでは公式ページの Chromium with the Dart VM からはまだダウンロードできませんが、そのうちダウンロードできるようになるでしょう。現時点ではこちらからダウンロードできます。

http://gsdview.appspot.com/dartium-archive/continuous/

追記
まだおかしいですね。一応実行まではできましたが簡単にクラッシュしてしまいますし、公式ページからダウンロードできるようになるまでもう少し待ったほうがいいかもしれません。


こちらもどうぞ

2012年3月16日金曜日

新しいDart Editor(ビルド5427)が公開されています

このエントリーをはてなブックマークに追加
新しいDart Editor(ビルド5427)が公開されています。

ダウンロードはこちらから。
Tutorial: Dart Editor : Dart : Structured web programming

隣り合った文字列の連結ができるようになっています。

main() {
  String abcdef = 'abc' 'def';
  String html = "<p>"
                "  <em>Hello</em>"
                "  <i>World</i>"
                "</p>";
}

そのほかの変更点や詳細はDart News & Updatesの記事を参照して下さい。 New Dart Editor builds supports adjacent string literals


こちらもどうぞ

2012年3月13日火曜日

Dartにおけるゲッター(get)とセッター(set)

このエントリーをはてなブックマークに追加
Dartではクラスのメンバーにgetとset(いわゆるゲッターとセッター)を定義することができます。ゲッターとセッターで定義されたメンバーは、あたかもメンバー変数と同じようにアクセスできますが、変数への代入だけではなく、ほかの処理を追加することもできます。

ゲッターとセッターはメソッドと同じような形で、戻り値の方の後にgetあるいはsetを付けます。 ゲッターは仮引数を持たず、適切な値を返します。セッターは適切な仮引数を1つ持ち、値は返しません。 アクセスするときには、メンバー変数へアクセスするときと同じ方法で参照できます。
class Line {
  Line(this.start, this.end);
  int start, end;
  int get length() => end - start;
  void set length(int len) {
    end = start + len;
  }
}

main() {
  Line line = new Line(1, 3);

  // ほかのメンバー変数(line.startなど)と同じ方法で参照できる。
  // 出力: (1, 3) : length=2
  print('(${line.start}, ${line.end}) : length=${line.length}');

  // メンバー変数と同じ方法で代入もできる。
  line.length = 5;

  // 出力: (1, 6) : length=5
  print('(${line.start}, ${line.end}) : length=${line.length}');
}
この例のように同じ名前のゲッターとセッターを1つのクラス内で定義することができます。しかし同じ名前のメンバー変数やメソッドを持つことはできません。
class Line1 {
  int length;
  int get length() => /* ... */; // エラー!
}

class Line2 {
  int length() { /* ... */ }
  int get length() => /* ... */ ; // エラー!
}
このような場合には、メンバー変数をプライベートにする(_lengthにする)と良いでしょう。

また、ゲッターとセッターはオーバーライドすることができません。
class Line {
  int get length() => /* ... */;
  String get length() => /* ... */; // エラー!
}
ゲッターとセッターの定義の前にstaticを付けると、静的なゲッターとセッターを定義することもできます。

こちらもどうぞ

2012年3月12日月曜日

Dartで関数型のエイリアスを使う

このエントリーをはてなブックマークに追加
Dartではtypedefで型のエイリアス(別名)を定義できます。
// 「num型の引数を2つ受け取りbool型の値を返す」関数型のエイリアス
typedef bool Comparator(num, num);

void func(Comparator c) {
  // 処理
}

main() {
  Comparator c = (a, b) => a > b;
  func(c);
}
typedefによって定義されたエイリアスも型ですので、isによる型の判定ができます。
print(c is Comparator); // true
ただし現時点では関数型だけに使えます。今後は他の型でも使えるようになるかもしれません。

2012年3月11日日曜日

Dartコードの実行時間を計測する

このエントリーをはてなブックマークに追加
Dartコードの実行時間を計測するにはStopwatchライブラリが使えます。
main() {
  Stopwatch sw = new Stopwatch.start();
  // 計測したい処理
  sw.stop();
  print('${sw.elapsedInMs()} ms');
}


こちらもどうぞ

プロダクションモードとチェックモード

このエントリーをはてなブックマークに追加
Dartのコンパイルと実行には、プロダクションモードとチェックモードがあります。夫々次のような特徴があります。

プロダクションモードチェックモード
静的型無視(Dynamic)チェック
動的型チェックなしあり
assert無視有効
優先事項起動時間、実行速度潜在的な問題の検出
デフォルトV

プロダクションモードでは、プログラムの実行を継続できないエラーが発生しない限り、なるべくエラーを無視してそのまま実行を続けようとします。また、できるだけ速く実行するために、型のチェックなども行われません。

一方チェックモードでは、バグの原因と考えられる問題をなるべく早く検出するため、静的な型のチェックだけでなく、動的な方のチェックやassertによるチェックも有効になります。

したがって、開発時はチェックモードを、リリース時はプロダクションモードを使用しましょう。どのVMもデフォルトはプロダクションモードなので、開発時にチェックモードにする意識さえあれば良いはずです。


こちらもどうぞ

2012年3月9日金曜日

Dartで文字列を連結する

このエントリーをはてなブックマークに追加
Dartで文字列を連結するにはいくつ方法があります。

一番単純なものはプラス + によるものです。
String a = "abc" + "def"; // "abcdef"
文字列補間を使って次のように書くこともできます。
String a = "abc";
String d = "def";
String ad = "${a}${d}"; // "abcdef"
プラスによる単純な連結で十分な場合はそれで良いと思いますが、文字列補間はたいへん便利な機能なので、ぜひ使っていきたいところです。文字列連結だけではなく、様々な処理を簡単に書くことができます。

さらに、現時点(言語仕様 0.07)ではできませんが、隣接した文字列リテラル同士も連結されるようになるそうです。これはまだ推測ですが、おそらく次のように書けるようになると思います。
String a = "abc" "def"; // "abcdef"
追記
Dart Editor ビルド5427からできるようになりました。


こちらもどうぞ

2012年3月8日木曜日

新しいDart Editor(ビルド5104)が公開されています

このエントリーをはてなブックマークに追加
新しいDart Editor(ビルド5104)が公開されています。

ダウンロードはこちらから。
Tutorial: Dart Editor : Dart : Structured web programming

もっとも大きな変更点は、従来のライブラリビューがなくなり、新たにファイルビューが用意されたことです。Dart Editorを起動すると左にファイルビューが表示されます。スクリーンショットはサンプルのclockを開いた状態です。

ひとつ前のバージョン(ビルド4760)では次のようになっていました。

パッと見て2つ気が付きます。

  • 標準のライブラリが表示されないようになった
  • Dartライブラリではないもの(ディレクトリや画像ファイルなど)が表示されるようになった
ファイルビューには標準のライブラリが表示されないため、ライブラリビューからそのソースを表示できなくなったのですが、コードから追っていくことは可能です。

開きたいファイルが書かれた #import ディレクティブを右クリックし、メニューから Open Declaration を選択すると、今まで通り指定のライブラリ ファイルが開かれます。

2012年3月7日水曜日

Dartの関数宣言と呼び出し

このエントリーをはてなブックマークに追加
Dartの関数はJavaやCなどに近い書き方で記述します。
String greeting(String name) {
  String words = 'Hello, ${name}!';
  print(words);
  return words;
}
return文を通らずに関数を抜けた場合(例外が発生した場合を除く)、エラーにはならずnullが返ります。

関数の中に式がひとつしかないときは、次のような書き方もできます。この場合、関数の戻り値は式の値になります。
String greeting(String name) => 'Hello, ${name}!';
無名関数も同じように書くことができます。
main() {
  Function greeting1 = (name) { return 'Hello, ${name}!'; };
  print(greeting1('world'));
  // 書き方が違うだけで同じ。
  Function greeting2 = (name) => 'Hello, ${name}!';
  print(greeting2('world'));
}
無名関数はコレクションの処理ではよく使われます。サンプルコード
main() {
  var even = [1, 2, 3, 4].filter((e) => e % 2 == 0);
  even.forEach((e) => print(e)); // 2 4
}
関数を返す関数も書くことができます。クロージャとしての使い方も可能です。サンプルコード
newCounter() {
  var i = 0;
  return () => ++i;
}

main() {
  var c = newCounter();
  print(c()); // 1
  print(c()); // 2
  print(c()); // 3
}
関数には省略可能なパラメーターが指定できます。省略可能なものについてはかっこ [] で囲います。また、省略可能なパラメーターにはデフォルト値が指定できます。省略可能なパラメーターで、デフォルト値がないものについて省略した場合、nullが設定されます。サンプルコード
// 仮引数twoとthreeは省略可能。
void printNumber(int one, [int two, int three = 3]) {
  print('${one}, ${two}, ${three}');
}

main() {
  printNumber(1, 2, 3); // 1, 2, 3 
  printNumber(1, 2);    // 1, 2, 3
  printNumber(1);       // 1, null, 3
                        // デフォルト値がない引数が省略されるとnullになる。
}
ただし、インターフェイスや抽象メソッドではデフォルト値を指定できません。サンプルコード
interface I {
  // void greeting([String name = 'world']);
  // 上の宣言はエラー。次のようにデフォルト値がなければ問題ない。
  void greeting([String name]);
}

class C implements I {
  // 抽象メソッドでなければデフォルト値を指定可能。
  void greeting([String name = 'world']) {
    print('Hello, ${name}!');
  }
}

main() {
  new C().greeting(); // Hello, world!
}
また、省略可能なパラメーターは名前付きの引数指定に対応します。サンプルコード
void printNumber(int one, [int two, int three]) {
  print('${one}, ${two}, ${three}');
}

main() {
  printNumber(1, three: 3);    // 1, null, 3
}


こちらもどうぞ

2012年3月6日火曜日

Dartでクラスや変数の見え方を制御する

このエントリーをはてなブックマークに追加
Dartでは、識別子の前にアンダーバー _ をつけると、識別子を定義したライブラリ内でしか見えなくなり、ライブラリの外から参照しようとするとエラーになります。いわゆるプライベートです。

mylib.dart
#library('my_lib');
class A {
  String x;
  String _y;
}
#import('mylib.dart');
main() {
  A a = new A();   // OK
  a.x = 'a';       // OK
  a._y = 'a';      // NG
}
メンバー変数だけではなく、メンバー関数や、トップレベルのクラス、関数、変数も同様の方法でプライベートにすることができます。

なお、この機能はライブラリ外から見えなくなるだけで、メンバーをプライベートにしても、同じライブラリ内からは別のクラスからでも参照することができます。
#library('my_lib_2');
class A {
  String x;
  String _y;
}

class _B {}

class Test1 {
  void test() {
    A a = new A();   // OK
    a.x = 'a';       // OK
    a._y = 'a';      // OK

    _B b = new _B(); // OK
  }
}

class Test2 extends A {
  void test() {
    x = 'a';  // OK
    _y = 'a'; // OK
  }
}


こちらもどうぞ

Dartのライブラリとスクリプト

このエントリーをはてなブックマークに追加
Dartではライブラリという単位で構成を管理します。ライブラリ単位でスクリプトにインポートしたり、ライブラリ単位で名前空間を分けたりします。クラスや変数をプライベートにすることで外部から見えなくなりますが、その単位がライブラリでもあります。

ライブラリはファイルの先頭に #library ディレクティブを指定して作成します。

mylib.dart
#library('my_greeting_lib');
class Greeting {
  void hello(String name) => print('Hello, ${name}!');
}
作成したライブラリは別のコードから #import ディレクティブを使ってインポートし、使用します。
#import('mylib.dart');
main() {
  Greeting g = new Greeting();
  g.hello('world'); // Hello, world!
}
ただしこのままですと、複数のライブラリで同じ名前のクラスが定義されていたときに混乱してしまいます。そこでライブラリをインポートするときにはプレフィックス(接頭子)を指定できます。mylib.dart以外のライブラリをインポートするときに別のプレフィックスを指定すれば、そのライブラリが別のGreetingクラスを定義していたとしても、混乱せずに使い分けることができます。
#import('mylib.dart', prefix:'mylib');
main() {
  mylib.Greeting g = new mylib.Greeting();
  g.hello('world'); // Hello, world!
}
ライブラリとしてではなく、コードの一部として別のファイルを取り込むには、#source ディレクティブを使用します。ライブラリとして取り込むと取り込んだ側のコードのスコープから見えるようになるだけですが、ソースとして取り込むと取り込んだ側のコードの一部として扱われ、プライベートとして指定していないと取り込んだライブラリの外にも公開されます。

mysource.dart
class MySouce {}
mynestedlib.dart
#library('my_nested_lib');
class MyNestedLib {}
mylib.dart
#library('my_lib');
#import('mynestedlib.dart');
#source('mysource.dart');
class Greeting {
  void hello() {
    new MySource(); // OK
    new MyNestedLib(); // OK
  }
}
#import('mylib.dart', prefix:'mylib');
main() {
  new mylib.Greeting.hello(); // OK
  new mylib.MySource(); // OK
  new mylib.MyNestedLib(); // NG
}
なお、ライブラリの中でもトップレベルのmain関数を含むものをスクリプトと呼びます。


こちらもどうぞ

2012年3月5日月曜日

Dartのコンストラクタ

このエントリーをはてなブックマークに追加
Dartはクラスベースのオブジェクト指向言語です。この仕組みはJavaなどの他の静的なクラスベースの言語に近いものですが、動的な言語であるDartのコンストラクタには面白い機能があります。

まずは基本的なコンストラクタの書き方です。
class Dog {
  String name;

  // コンストラクタ
  Dog(String name) {
    this.name = name;
  }
}

main() {
  Dog afriend = new Dog('Taro');
}
コンストラクタはクラス名と同じ名前のメソッドです。戻り値は書きません。

コンストラクタを書かなかった場合は Dog() : super() {} というコンストラクタがあるものとして扱われます。super() はスーパークラスの引数なしコンストラクタの呼び出しです。

コンストラクタを省略した場合や、コンストラクタの中でメンバー変数を初期化しなかった場合、その変数の値はデフォルトの値(null)になります。

コロンに続く部分はイニシャライザー・リストと呼び、スーパークラスのコンストラクタの呼び出しやメンバーの初期化を行います。C++にあるものとほぼ同じです。ただしメンバーの初期化は、代入と同じで等号 = によって書きます。
class Dog {
  String name;
  Dog(String name) : this.name = name;
}
さらに、コンストラクタの引数をインスタンス変数に代入するというよく行われる処理を、より簡単に書くことができます。
class Dog {
  String name;
  Dog(this.name);
}
この例では、Dogクラスのコンストラクタで引数として受け取った値を、nameフィールドに代入しています。

ここまで見てきたコンストラクタの他に、名前付きコンストラクタファクトリー・コンストラクタというものがあります。

名前付きコンストラクタは、異なるパラメータでコンストラクタを呼び出すときに使います。Dartではメソッドのオーバーロードができないため、パラメータの異なるコンストラクタを用意したい場合には、名前付きコンストラクタを使います。
class Dog {
  String name;
  int age = 0;
  Dog(String this.name);

  // 引数なし。
  Dog.wild() : name = 'Unknown', age = -1;

  // 名前と、年齢を誕生日で指定。
  // 年齢の計算方法は大雑把なので参考にしないでください。
  Dog.pet(String this.name, Date birth)
    : age = new Date.now().difference(birth).inDays ~/ 365;
}

main() {
  // "Unknown age=unknown" (-1)
  Dog w = new Dog.wild();
  // "Taro age=6"
  Dog p = new Dog.pet('Taro', new Date(2005, 10, 1, 0, 0, 0, 0));

  for (Dog dog in <Dog>[w, p]) {
    print('${dog.name} age=${dog.age < 0 ? "unknown" : dog.age}');
  }
}
ファクトリー・コンストラクタは、ファクトリー・パターンを実現するものです。インスタンスの生成に関する詳細をファクトリー・メソッドに委譲します。

ファクトリー・コンストラクタを作るには、まず通常のコンストラクタに factory キーワードをつけます。そしてコンストラクタの中でインスタンスを生成し、呼び出し側に返します。例えば次の例のように、生成したオブジェクトをキャッシュしておいて、状況に応じてキャッシュされたインスタンスを返すなどの実装が考えられます。
class BinChar {
  String c;

  // キャッシュ
  // バイナリーを表す文字を保持する2つのインスタンスをキャッシュする。
  static BinChar zero, one;

  // 通常のコンストラクタ
  BinChar._internal(String this.c);

  // ファクトリー・コンストラクタ
  // 初めての呼び出しの時は通常のコンストラクタを呼び出してインスタンスを生成しキャッシュに保存する。
  // 2度目以降の呼び出しではキャッシュの値を返す。
  factory BinChar(int bin) {
    if (bin == 0) {
      if (zero == null) {
        zero = new BinChar._internal('-');
      }
      return zero;
    } else {
      if (one == null) {
        one = new BinChar._internal('*');
      }
      return one;
    }
  }
}

main() {
  // 通常のインスタンスの生成とまったく同じ。
  BinChar a = new BinChar(1);
  print('1 = ${a.c}');
}
ファクトリー・コンストラクタを使ってインスタンスを生成する場合でも、クライアント側のコードは通常のコンストラクタを使った場合と変わりません。

ファクトリー・コンストラクタは派生クラスのインスタンスを生成することもできます。ファクトリー・コンストラクタを使って、引数に応じて処理方法を変えたハッシュ テーブルの実装を返すなど、柔軟な実装もできます。

なお、インターフェイスにデフォルトのファクトリー・クラスを指定した場合には、インターフェイスにおいてコンストラクタの形式を指定する必要があります。
interface Animal default Dog {
  Animal(String name); // デフォルトのファクトリー・クラスのコンストラクタを指定する。
}

class Dog implements Animal {
  String name;
  Dog(String this.name); // インターフェイスのコンストラクタと同じ形式のコンストラクタを用意する。
}
また、定数しか持たないクラスのインスタンスを作るため、constコンストラクタ(定数コンストラクタ)というものもあります。
class Point {
  final num x, y;
  const Point(this.x, this.y);
} 

main() {
  Point a = const Point(1, 2);
  print('(x, y) = (${a.x}, ${a.y})'); // (x, y) = (1, 2)
}
constコンストラクタでは定数を作るために使います。したがって次のような制約があります。
  • constコンストラクタを持つクラスでは、finalではないメンバーを持つことができません。
  • constコンストラクタには本体を持つことができませんので、初期化リストなどを用いてメンバー変数の値を初期化することになります。
  • constコンストラクタの呼び出しには、コンパイル時定数しか渡すことができません。


こちらもどうぞ

2012年3月4日日曜日

Dart Editorの新しいバージョンが公開されています

このエントリーをはてなブックマークに追加
Dart Editorの新しいバージョン、ビルド4760が公開されています。

新しい機能は次のとおりです。

  • Dartiumを起動する機能が向上しました
  • コンソールビューでDart VMのスタックトレースにハイパーリンクがつくようになりました
  • UIとサンプルが更新されました
  • dart:isolateライブラリが登場しました

ダウンロードはDart Editorのページから。

ただしプロジェクトが開けないなどの問題がいくつかの環境で報告されている(Issue 1962 - dart - DartEditor does not open projects, broken from 4908 to latest DartBuild MacOSX)ようですので、そのような場合は1つ前のバージョンを使うか、より新しいナイトリービルドを使うのが良いでしょう。

クラスとインターフェイス

このエントリーをはてなブックマークに追加
Dart はクラスベースのオブジェクト指向言語です。クラス、そしてインターフェイスという、他のオブジェクト指向言語と似た仕組みを持ちます。
  • クラスは他のひとつのクラスを拡張(extends)します。多重継承はできません。
  • クラスの定義で extends を省略したときは、Object を拡張することになります。
  • クラスは複数のインターフェイスを実装(implements)できます。
  • インターフェイスは複数のインターフェイスを拡張(extends)できます。
// 動物インターフェイス
interface Animal {
  void cry();
}

// 犬は動物を継承
class Dog implements Animal {
  void cry() { print("Bark!"); }
}

// 猫も動物を継承
class Cat implements Animal {
  void cry() { print("Mew!"); }
}

// ライオンはネコ科
class Lion extends Cat {
  void cry() { print("Roar!"); }
}

// 動物園で吠えます。
void zoo(Animal a) {
  a.cry();
}

main() {
  zoo(new Dog()); // Bark!
  zoo(new Cat()); // Mew!
  zoo(new Lion()); // Roar!
}
このあたりの仕組みはJavaとほぼ同じですので、Javaに慣れている人はとっつきやすいと思います。

他にも次のような特徴があります。
  • クラスは型変数を extends できません。(class A<T> extends T ということはできない)
  • インターフェイスはデフォルトのファクトリー・クラスを指定できます。
  • インターフェイスには定数の宣言を含むことができます。(static ABC = "ABC";
インターフェイスにデフォルトのファクトリー・クラスが指定できるのは面白い機能です。例としてリストを見てみましょう。DartのListは次のようにインターフェイスとして定義されています。
interface List extends Collection default ListFactory {
...
}
デフォルトのファクトリー・クラスは default キーワードに続けて指定します。

DartのListでは、デフォルトのファクトリー・クラスとして ListFactory クラスが指定されています。デフォルトのファクトリー・クラスが指定されているインターフェイスは、そのままインスタンスを生成することができます。サンプルコード
main() {
  List animals = new List();
  animals.add(new Dog());
  animals.add(new Cat());
  animals.add(new Lion());
  for (Animal a in animals) {
    a.cry();
  }
}


こちらもどうぞ

2012年3月2日金曜日

Dartで変数の型を調べる

このエントリーをはてなブックマークに追加
Dart において変数の型を調べるには、is 演算子を使います。
var a = 1;
print('a is int: ${a is int}'); // true
型Aが型Bから派生して作られている場合は、A is B は true となります。
class B {}
class A extends B {}
main () {
  var a = new A();
  print('a is B: ${a is B}'); // true
  var b = new B();
  print('b is A: ${b is A}'); // false
}
Dart におけるすべての型は Object クラスを継承するので、is Object とすると比較対象がどのような型であっても常に true になります。
print('1 is Object: ${1 is Object}'); // true
print('"a" is Object: ${"a" is Object}'); // true
対象が null であっても is Object の結果は true です。
print('null is Object: ${null is Object}'); // true
したがって、変数がnullかどうかのチェックをするのに is Object は使えません。null と直接比較しましょう。
func(var x) {
  if (x is Object) { /* たとえxがnullであっても、ここは常に実行される。 */ }
  if (x != null) { /* xがnull以外の場合のみ実行される。 */ }
}

Dartをチェックモードで動かす方法

このエントリーをはてなブックマークに追加
この情報は古くなっています。新しい記事を書きましたのでそちらを参照してください。: Dartをチェックモードで動かす方法(更新版)


Dartの実行モードには、プロダクション モードとチェック モードがあります。プロダクション モードでは、変数の代入などについて型による制限はありませんが、チェック モードでは型のチェックがコンパイル時と実行時に行われます。

開発時はチェック モードで動作させ、製品リリース後はプロダクション モードで動かす、といった使い方が想定されます。

そのため何も指定せずにDartスクリプトを実行するとプロダクション モードで動きます。チェック モードで動かす方法は次のとおりです。

Dartboard の場合

画面左上にあるChecked Modeにチェックを入れます。

dart(Dart VM)の場合

--enable_type_checks フラグを指定します。
$ cat test.dart
main() { int a = 'a'; }
$ dart --enable_type_checks test.dart
'test.dart': Failed type check: line 1 pos 18: type 'OneByteString' is not assignable to type 'int' of 'a'.
 0. Function: '::main' url: 'test.dart' line:1 col:18

frogc( Dart-to-JavaScript compiler)の場合

Dart VMと同じ --enable_type_checks フラグ、または --checked フラグを指定します。
$ cat test.dart
main() { int a = 'a'; }
$ frogc --enable_type_checks test.dart
test.dart:1:18: warning: type "dart:core.String" is not assignable to "dart:core.int"
main() { int a = 'a'; }
                 ^^^

Dartium (Chromium with the Dart VM)の場合

Dartium内蔵のDart VMに渡すフラグは、DART_FLAGS環境変数で指定できます。ここにDart VMと同じフラグを指定します。

Ubuntuの場合は次のようになります。
DART_FLAGS='--enable_type_checks' chrome


Dart Editorの場合

スクリプトの実行設定画面の Run in check mode のチェックを入れます。



こちらもどうぞ

Dartium を使ってみる

このエントリーをはてなブックマークに追加
Dartium は、Dart VM が組み込まれた Chromium です。Chromium は Chrome Webブラウザのオープンソース版です。

Dartium を使えば Dart をWebブラウザ上で試すことができます。現在のところDartiumのLinux版とMacOS X版のバイナリーが公開されていて、Dartの公式サイト内にある Chromium with the Dart VM のページからダウンロードすることができます。Windowsでも自分でビルドすれば動くと思いますし、遠くないうちに提供されるのではないかと思います。

Dartium を起動するとこんなかんじです。

Chromiumとほとんど変わりません。aboutの画面はこんなかんじです。

Dartのサンプルに含まれている dart/samples/hi を表示してみましょう。Dart VMが組み込まれていない通常のChromeですとこうなります。

Dartiumですとこうなります。

Dart言語の部分のコードはこうなっています。
#library('hi');

#import('dart:html');

main() {
  document.query('#status').innerHTML = 'Hi, Dart';
}
このサンプルから呼び出されている dart.js のコードを見ると、JavaScriptからDartのコードを開始していることがわかります。該当部分を抜粋したものが次のコード片です。
if (navigator.webkitStartDart) {
  navigator.webkitStartDart();
}
navigator.webkitStartDart() を呼び出すことで、Dartのmain関数が呼び出されるようです。


こちらもどうぞ