2013年8月28日水曜日

Dart Editor をプロキシ経由で更新する

このエントリーをはてなブックマークに追加
Dart Editor はメニューの Tools - Preferences あるいは Help - About Dart Editor で更新できますが、プロキシ経由でインターネットにアクセスする環境では、更新サーバーに接続できずエラーになる場合があります。この場合は次の方法を試してみてください。
  1. Dart Editor を終了する。
  2. Dart Editor の実行ファイルと同じ場所にある DartEditor.ini ファイルをテキストエディタで開く。
  3. 「-Dhttp.proxyHost=」「-Dhttp.proxyPort=」という行を追加し、設定を書く。認証が必要なプロキシの場合は「-Dhttp.prxyUser=」「-Dhttp.proxyPassword=」も設定する。
  4. DartEditor.ini ファイルを保存する。

設定すると DartEditor.ini は次のようになります。
(前半省略)
-Xms40m
-Xmx1000m
-Dhttp.proxyHost=proxy.example.com
-Dhttp.proxyPort=8080
-Dhttp.proxyUser=account_name
-Dhttp.proxyPassword=account_password
Dart Editor 0.6.21_r26639 と、Windows XP および Ubuntu 13.04 の環境で確認しました。

2013年5月8日水曜日

Future を使いこなす(3)

このエントリーをはてなブックマークに追加
目次
  • Future を使いこなす(1)
    • Future とは何か(おさらい)
    • 基本の Future の書き方
    • エラー発生時の処理を記述する
  • Future を使いこなす(2)
    • Future を続けて処理する
    • 連結時のエラー処理を実装する
    • リストの要素を Future で順に処理する
    • 複数の Future をまとめて待つ
  • Future を使いこなす(3)
    • Future を返す関数を実装する
    • Future をテストする

Future を返す関数を実装する

非同期処理の関数を実装するときには Future のインスタンスを返すようにします。 関数の中で別の非同期処理関数を呼び出して適切な Future を返すということが多いと思いますが、場合によっては自分で非同期処理を書いて Future を返すこともあるでしょう。

自分で Future を生成するときには Completer を使います。
import ('dart:async');

Future<String> asyncTask() {
  var c = new Completer<String>();

  // ここで非同期処理を実行する。

  // Completer#future を返す。
  return c.future;
}

void main() {
  asyncTask()
    .then(print)
    .catchError((e) => print('ERROR: $e'));
}
非同期処理が完了したことを通知するためには Completer#complete を使います。 同じように、エラーが発生したことを通知するためには Completer#completeError を使います。

では試しに、Timer を使って非同期処理を作ってみます。
import ('dart:async');

Future<String> asyncTask() {
  var c = new Completer<String>();

  // 非同期処理
  const ONE_SEC = const Duration(seconds: 1);
  new Timer(ONE_SEC, () {
    c.complete('Pass');
    // エラーの時は
    // c.completeError('Fail');
  });

  // Completer#future を返す。
  return c.future;
}

void main() {
  asyncTask()
    .then(print)
    .catchError((e) => print('ERROR: $e'));
}
実行すると 1 秒後に then で登録した関数が呼びだされ、結果が表示されます。

Future をテストする

自動テストを実行するには unittest ライブラリを使います。 pubspec.yaml に unittest を追加してください。 Dart Editor ならば GUI で設定できます。 テキストエディターで変更する場合は、次のように dependencies に unittest を追加します。
dependencies:
  unittest: any
できたら pub install を実行します(Dart Editor の場合は自動で実行されます)。

まず同期処理の場合のテストコードです。
import 'dart:async';
import 'package:unittest/unittest.dart';

String syncTask() => 'Pass';

void main() {
  test('Test a function', () {
    expect(syncTask(), equals('Pass'));
  });
}
これに対して非同期処理のテストコードは次のようになります。
import 'dart:async';
import 'package:unittest/unittest.dart';

Future<String> asyncTask() {
  var c = new Completer<String>();

  const ONE_SEC = const Duration(seconds: 1);
  new Timer(ONE_SEC, () => c.complete('Pass'));

  return c.future;
}

void main() {
  // テスト
  test('Test a future', () {
    asyncTask().then(
      expectAsync1(
        (e) => expect(e, equals('Pass'))));
  });
}
Future#then や Future#catchError などに expectAsync1(1 は引数の個数)で取得した関数を渡してテストします。 同期処理のテストと若干が違いますが、おおよそ似たような形で書くことができます。

ただし expectAsync1 は今後の言語仕様の変更にともなって呼び出し方が変更される可能性があります。 あまり気にすることはないと思いますが、覚えておくと良いかもしれません。

Future を使いこなす(2)

このエントリーをはてなブックマークに追加
目次
  • Future を使いこなす(1)
    • Future とは何か(おさらい)
    • 基本の Future の書き方
    • エラー発生時の処理を記述する
  • Future を使いこなす(2)
    • Future を続けて処理する
    • 連結時のエラー処理を実装する
    • リストの要素を Future で順に処理する
    • 複数の Future をまとめて待つ
  • Future を使いこなす(3)
    • Future を返す関数を実装する
    • Future をテストする

Future を続けて処理する

ある Future の結果を元に、別の Future を使った処理を呼び出したいことがあります。その時は次のように書くことができます。
import ('dart:async');

Future<String> asyncTask1() { /* ... */ }
Future<String> asyncTask2(String s) { /* ... */ }

main() {
  Future<String> f1 = asyncTask1();
  Future<String> f2 = f1.then((s) {
    return asyncTask2(s);
  });
  f2.then((s) => print(s));
}
Future#then に指定したコールバック関数が Future のインスタンスを返す場合(つまりこのコードの return asyncTask2(s) のようになっている場合)、元々の Future(f1)と連結された新しい Future が then の戻り値(f2)となります。 したがってこのように書くと、asyncTask1 で生成された Future の処理が完了したあとに asyncTask2 で生成された Future が続けて処理されるようになります。

このコードは、より簡潔に次のように書くこともできます。
import ('dart:async');

Future<String> asyncTask1() { /* ... */ }
Future<String> asyncTask2(String s) { /* ... */ }

main() {
  asyncTask1()
    .then((s) => asyncTask2(s))
    .then((s) => print(s));

  // あるいは

  asyncTask1()
    .then(asyncTask2)
    .then(print);
}

連結時のエラー処理を実装する

Future を連結させた場合、どの Future で発生したエラーも最後の Future で受け取ることができます。 つまり次のように書けるということです。
import ('dart:async');

Future<String> asyncTask1() {
  // ここでエラーが発生しても...
}
Future<String> asyncTask2(String s) {
  // ここでエラーが発生しても...
}

main() {
  asyncTask1()
    .then(asyncTask2)
    .catchError((e) { /* ここでエラーが処理できる。 */ })
    .whenComplete(() { /* ここは最後に実行される。 */ });
}
見た目は少し異なりますが、try-catch と同じように扱えると考えれば迷わないでしょう。

リストの要素を Future で順に処理する

一つずつ Future を連結していくこともできますが、List のような Iterable な構造に入っているデータを順に Future で処理させるときには Future#forEach が使えます。
import ('dart:async');

Future asyncTask(String s) { /* ... */ }

main() {
  List<String> strs = ['a', 'b', 'c'];

  // strs の要素が一つずつ渡されて処理される。
  Future f = Future.forEach(strs, asyncTask);

  // 最後の要素が処理されると呼び出される。
  f.then((_) => print('Completed.'));
}
Future を then でつなげていった時と同じように、'a' の処理が終わったら 'b'、'b' の処理が終わったら 'c'、すべて終わったら最後の then という順番で処理されます。

途中の Future で値が返ってきてもそれらは捨てられてしまいますので、結果を受け取りたい場合には呼び出し元と呼び出し先で共通に参照できるオブジェクトを用意して、そこに結果を格納していくなどの方法を取る必要があります。

複数の Future をまとめて待つ

今度は Future をつなげて順に処理させるのではなく、複数の非同期で処理されている Future の完了をまとめて待つ方法です。 このような場合には Future#wait が使えます。
import ('dart:async');

Future asyncTask(String s) { /* ... */ }

main() {
  // List に複数の Future を入れておく。
  List<Future> fs = [
    asyncTask('a'),
    asyncTask('b'),
    asyncTask('c')
  ];

  // まとめて待つ。
  Future f = Future.wait(fs);
  f.then((_) => print('Completed.'));
}
List に入っている3つの Future はそれぞれ非同期に実行され、すべての Future が完了した時点で最後の Future の then に登録した関数が呼ばれます。 それぞれの結果はやはり捨てられますので、結果は別のオブジェクトに保存するなどしてください。

Future を使いこなす(3) へ続く

Future を使いこなす(1)

このエントリーをはてなブックマークに追加
Dart の Future についてはだいぶ前に解説(Dartで未来(Future)の処理を実装する)を書きましたが、それから使い方が少し変わっていますので、現時点での最新仕様(Milestone 4)をベースに改めて説明を書きました。

目次
  • Future を使いこなす(1)
    • Future とは何か(おさらい)
    • 基本の Future の書き方
    • エラー発生時の処理を記述する
  • Future を使いこなす(2)
    • Future を続けて処理する
    • 連結時のエラー処理を実装する
    • リストの要素を Future で順に処理する
    • 複数の Future をまとめて待つ
  • Future を使いこなす(3)
    • Future を返す関数を実装する
    • Future をテストする

Future とは何か(おさらい)

Future は Dart のライブラリとして提供されている、非同期処理のための機能です。結果がすぐに得られるかわからない処理を同期的に書いてしまうと、その処理が終わるまで次の処理がブロックされてしまいます。例えば Web からリソースを取得するとき、いつ結果が返ってくるか(あるいはエラーになるのか)を予測してプログラミングすることはほとんど不可能です。

それでは都合が悪いので、どのくらい時間がかかるかわからないような処理は非同期で実行し、結果が出た時にそれに対応する処理を実行させるということをよくやります。これを実現するための機能が Future です。

基本の Future の書き方

Future の機能は dart:async ライブラリで提供されていますので、プログラムの先頭で import する必要があります。
import ('dart:async');

void main() { /* ... */ }
同期的な関数は戻り値として処理結果を返します。エラーが発生した場合には例外を送出します。
// 同期的な関数
String concat(String a, String b) {
  return a + b;
}

void main() {
  // Hello world
  print(concat('Hello ', 'world'));
}
concat 関数から戻った時点で print 関数へ渡す結果が出ています。これに対して非同期的な関数では、関数から戻った時点では結果が出ているかどうか分かりません。そのような場合、Dart の関数は Future のインスタンスが返るようになっています。処理が終わると Future#then で指定した関数がコールバックされますので、そこに結果の処理を記述します。
import ('dart:async');

// 非同期的な関数
Future<String> asyncTask() { /* ... */ }

void main() {
  // Future を受け取る。
  var f = asyncTask();

  // Future#then に完了時の処理を書く。
  f.then((String s) => print(s));
}
実践的なプログラミングでは次のように短く書かれます。
import ('dart:async');

Future<String> asyncTask() { /* ... */ }

void main() {
  asyncTask().then(print);
}

エラー発生時の処理を記述する

非同期処理の中でエラーが発生した時や、then で登録したコールバック関数が例外を送出した時には、then の onError 引数に指定した関数が呼ばれます。
import ('dart:async');

Future<String> asyncTask() {
  // 非同期処理中にエラーが発生したり...
}

void main() {
  asyncTask().then(
    (s) {
      // コールバック関数内で例外が発生すると...
    },
    // onError が呼び出される。
    onError: (e) => print('ERROR: $e'));
}
あるいは Future#catchError を使って次のように書くこともできます。
import ('dart:async');

Future<String> asyncTask() { /* ... */ }

void main() {
  asyncTask()
    .then(print)
    .catchError((e) => print('ERROR: $e'));
}
エラーの処理では、エラーの型や内容によって処理を分けることがよくあります。Future#catchError では test 引数に bool 型の戻り値を持つ関数を渡し、そのコールバック関数でエラーを処理するかどうかを決められます。test 引数で指定した関数が true を返すとコールバック関数が呼び出され、false を返すと呼び出されません。
import ('dart:async');

Future<String> asyncTask() { /* ... */ }

void main() {
  asyncTask()
    .then(print)
    // int の場合はこちら
    .catchError((e) => print('ERROR No.$e'),
                test: (e) => e is int)
    // String の場合はこちら
    .catchError((e) => print('ERROR Message: $e'),
                test: (e) => e is String);
}
then と catchError を使った書き方は、同期処理における try-catch 構文に相当します。非同期処理と then で登録する関数は try ブロック、catchError で登録する関数は catch ブロックの処理に対応しています。そして finally に相当する Future#whenComplete も用意されています。
import ('dart:async');

Future<String> asyncTask() { /* ... */ }

void main() {
  asyncTask()
    .then(print)
    .catchError((e) => print('ERROR No.$e'),
                test: (e) => e is int)
    .catchError((e) => print('ERROR Message: $e'),
                test: (e) => e is String)
    .whenComplete(() => print('Completed.'));
}
正常に終了した場合は then と whenComplete、エラーが発生した場合は catchError と whenComplete で登録した関数が順に呼ばれます。

Future を使いこなす(2) へ続く

2013年4月3日水曜日

カスケード呼び出しを使う

このエントリーをはてなブックマークに追加
ひとつのオブジェクトに対して複数のメソッドを呼び出す処理を書くことは多いと思います。このような操作をカスケード呼び出しと言いますが、Dart ではこの呼び出し方を専用の書き方を使って簡潔に書くことができます。

ここに動物のリストがあったとします。
<ul>
  <li id="bull">Bull<li>
  <li id="cat">Cat<li>
  <li id="dog">Dog<li>
</ul>
人気投票をしたところ Cat が 1 位になったので、太字にして王冠のイラストを追加してみましょう。
var licat = document.query('#cat');
licat.append(new Element.html('<img src="crown.png">'))
licat.style.fontWeight = 'bold';
カスケード呼び出し(..)を使うと次のように書くことができます。
document.query('#cat')
    ..append(new Element.html('<img src="crown.png">'))
    ..style.fontWeight = 'bold';
先のコードに比べて読みやすい形で表現されていると思います。呼び出すメソッドの数が増えるほどカスケード呼び出しを使うメリットが増えます。

ここで document.query('#cat') の戻り値は li 要素になります。子要素を追加する append メソッドを普通に呼び出すと、その戻り値は追加した要素、つまりここでは img 要素です。しかし .. を使って呼び出すと、元々のメソッドの戻り値は無視され、元のオブジェクトが返ってきます。
var img = new Element.html('<img src="crown.png">');

// e は追加した子要素(つまり img 要素)
var e = document.query('#cat').append(img);

// f は document.query('#cat') の値(li 要素)
var f = document.query('#cat')..append(img);
カスケード オペレーターでは結果が元のオブジェクトになるので、同じオブジェクトに対して次のメソッドを呼び出すことができるわけです。

.. は [] にも使うことができます。
document.query('#cat').attributes
    ..['style'] = 'color: red'
    ..['title'] = 'popular';

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は同梱されていません。しかしナイトリービルドではすでに同梱されるようになっていますので、近いうちにリリース版がダウンロードできるようになるでしょう。