Nagoya.dart #0 - Dartを正しく知る - 資料

published date : 2013-07-27

参加者募集ページ

Nagoya.dartとは

構造化Webプログラミング言語Dart及びそのエコシステムについて、 学習したりOSSに貢献したりといった活動を名古屋を中心に行なっていきます。


第0回でやること

  1. Dart Ecosystem概略
  2. Hello, world と Optional Typing
  3. どこでもDart

以下、参加して頂いてる方の意見を加味&時間があったら。

  • Twitterクライアントを作ってみる?
  • TodoMVCを一から書いてみる?

事前準備

DartEditorをインストールしておきます。

こちらからダウンロード後、展開するだけでOK。

・・・この初めやすさもDartの利点のひとつですね:)

DartEditorはEclipseベースなので、貧弱なPCだとすぐに重くなってしまいます。
(昔はもっと軽かったんだけど・・・)
そういう場合はVimあたりを使いましょう。
機能はそれなりですが、一応公式プラグインが存在します。


1. Dart Ecosystem概略

Dartとは

  • 任意型付オブジェクト指向プログラミング言語
  • Webアプリケーション開発にフォーカス
  • Source Code VMによるコンパイルレスな開発
  • 各種ツールによる開発のサポート

資料

準備

環境変数にDartツールへのパスを追加しておきます。

例) MacとかLinuxの場合

DART_SDK=/Applications/dart/dart-sdk
export PATH=$PATH:$DART_SDK/bin

任意のディレクトリで適当にコマンド叩いて確認。

$ dart --version
Dart VM version: 0.6.5.0_r25017 (Mon Jul 15 14:56:53 2013) on "macos_ia32"

作業用ディレクトリを作っておきます。

$ mkdir nagoyadart_0
$ cd nagoyadart_0
$ git init

2. Hello, world と Optional Typing

hello.dartファイルを作り、お好きなエディタでHello, worldを書いてみましょう。

main() {
  int msg = "Hello, world!";  // int型の変数に文字列!!
  print(msg);
}

dartコマンドで、実際にDartプログラムを動かしてみましょう。

$ dart hello.dart
Hello, world!

動きました。オプションを変えてみます。

$ dart -c hello.dart
Unhandled exception:
type 'String' is not a subtype of type 'int' of 'msg'.
#0      main (file:///Users/t_hara/work/events/nagoyadart_0/hello.dart:2:12)

-cオプションによって、実行時に型チェックが動くようになったのが分かります。
int msg = …の前に適当なprint入れると分かりやすい)

対して、dartanalyzerはプログラムを実行せずに型チェックをしてくれます。

$ dartanalyzer hello.dart
Analyzing hello.dart...
[warning] A value of type 'String' cannot be assigned to a variable of type 'int' (/Users/t_hara/work/events/nagoyadart_0/hello.dart, line 2, col 12)
1 warning found.

このdartanalyzerは、人間が読むよりも他のプログラムから使われることを意図して設計されています。
実際に、DartEditorやIntelliJ IDEAのDartプラグインなどが このdartanalyzerを使用しています。
(Java製なので、起動が若干重いです)

ここまでで、2つの実行方法とソース解析ツールを学びました。
Dartでプログラミングする際には、それらを適材適所で使用することで
開発者・開発チームに合った開発方法を選択できます。

それぞれにメリット・デメリットをまとめます。

dart(オプション無し)=> production mode

  • 型の不一致によるエラーが無いため、Duck typing可能。
  • プロトタイプ開発に適する。
  • 本来、型があれば未然に防げるようなバグを発生させる可能性がある。
  • 型情報を全く持たなくなる訳ではない(JITコンパイラによる最適化は効く)
  • RubyやPython、JSと同じような感覚。インタプリタ的。

dart -c => checked mode

  • コーディング時に、開発環境の自動構文解析でツールがもっさりするのが我慢できない人向け。
  • Duck typingはできないが、型システムの恩恵を受けられる。(Implicit InterfacesMix-inなど)
  • 型の不一致による予期せぬバグの発生確立が減る。
  • assertも効くように。
  • RubyやPython、JSよりも少し安心感がある。インタプリタ的。

dartanalyzer => IDEによる開発

  • プログラムを実行せずに型検査を行うことで、プログラムの安全性が高まる。
  • IDEに対する入力として用いられる。(--machineオプション)
  • ツールの恩恵を最大限に受けられる。
  • マシンスペックによっては、動作が重くなり、フラストレーションになることも。
  • JavaやC#などのコンパイラ言語を使用している感覚。

3. どこでもDart

Dartの実行環境には、主に以下の3つが挙げられます。

  • サーバーサイドでDart VM上で動作(コンソールアプリケーション)
  • Webブラウザに組込まれたDart VM上で動作(Dartium)
  • WebブラウザでJSとして動作(dart2js)

それぞれで同じDartコードを利用できることを確認しましょう。

3-1. Webアプリケーションのひな形を作成

Dart Editorのメニューから、File > New Applicationを選択。
以下を入力して、Finishをクリック。

Application name : hello_world(任意)
Parent directory : nagoyadart_0ディレクトリを作った場所
Sample Content   : Generate sample contentにチェック
                   Web Applicaitonを選択

ディレクトリ構成を一度、確認します。

(project root)
  |--- pubspec.yaml
  |--- web
        |--- hello_world.dart
        |--- hello_world.html

では、ここでサンプルプログラムの動作確認してみましょう。
Dart Editorでweb/hello_world.htmlを開いてCtl + Rというショートカットキーを押すと、
Dartiumが別プロセスで立ち上がります。
web/hello_world.htmlが無事実行されたら、OKです。

3-2. 依存ライブラリの設定

先ほど作成したhello_worldプロジェクトの直下に、pubspec.yamlというファイルが存在するのが確認できます。
このファイルは、PubというDartのパッケージマネージャの設定ファイルで、 当ライブラリの名前や、依存ライブラリの指定をします。

このプロジェクトでは、以下のように編集します。

name: hello_world
description: A sample web application
dependencies:
  browser: any
  polymer: any

3-3. 共通ライブラリ作成

Dartコードは、先に挙げた環境で動作しますが、
各環境に依存するライブラリをimportしなければ、 どの環境でも動作するコードを容易に書けます。

まず、プロジェクト直下にlibディレクトリを作成します。
(この構成は、Pubの規定されているディレクトリ構成に準拠しています)

libディレクトリの配下にhello.dartを作成し、以下の内容を記述します。

library hello;

class Message {
  String text;
}

ごく単純なlibraryですが、
このMessageクラスをコンソールアプリケーションと、Webブラウザ上のクライアントアプリケーションで再利用してみます。

3-4. コンソールアプリケーションの作成

では、コンソールアプリケーションを作成して、先ほどのMessageクラスを使ってみます。

プロジェクト直下にbinディレクトリを作成します。
(この構成も、Pubの規定されているディレクトリ構成に準拠しているものです)

そして、以下のようなprintHello.dartをその直下に作成し、Ctl + Rで実行してみます。

import "package:hello_world/hello.dart";

main () {
  var msg = new Message()..text = 'world';
  print("Hello ${msg.text}");
}

Dart Editorのコンソールビューに予想通りの結果が出力されたことを確認しましょう。

3-5. Dart VM組込みWebブラウザ用アプリケーションの作成

ではところ変わって、DartVM組込みWebブラウザであるDartium上で動作するアプリケーションを作成しましょう。

webディレクトリ配下にindex.htmlを以下の内容で作成します。

<!DOCTYPE html>
<html>
  <head>
    <title>index</title>
  </head>
  <body>   
    <template id="tmpl" bind>
      <p>Hello {{"{{text"}}}}</p>
    </template>
    <script type="application/dart" src="index.dart"></script>
    <script src="packages/browser/dart.js"></script>
  </body>
</html>

ポイントとなるのは、templateタグとscirptタグです。

templateタグはPolymer JSのDart版であるPolymer.dartの機能の一つで、
MDV(Model-Driven View)を実現します。

scirptタグでは、type="application/dart"という指定がなされていますが、
これはDart VM組込みWebブラウザに対して、src属性に指定したファイルがDartプログラムであることを通知します。
もう一方のscirptタグでは、src="packages/browser/dart.js"の指定がありますが、
DartをWebブラウザ上で動作させるためのおまじない、という認識で問題ありません。

では、プログラム本体であるindex.dartを以下の内容で作成しましょう。

import 'dart:html';
import 'package:mdv/mdv.dart' as mdv;

import 'package:hello_world/hello.dart';

main() {
  mdv.initialize();

  var msg = new Message()..text = 'world';
  query('#tmpl').model = msg;
    }

Webブラウザ上でのmain関数は、DOMのロードが完了した時点で呼ばれます。 (jQueryの$.readyと同様のタイミング)

query関数はjQueryの$関数相当のもので、セレクタを指定してDOM要素をオブジェクトとして取得できます。

index.htmlまたはindex.dartどちらかを開いた状態で、
Ctl + Rで実行し、予想通りの結果であることを確認しましょう。

3-6. Webブラウザ用JavaScriptアプリケーションの作成

DartVM組込みWebブラウザであるDartium上で動作させる場合、
altJSとは異なり、JavaScriptへのコンパイルが不要であるため迅速な開発が見込めます。

しかし、Dart VMがサポートされていないブラウザが一般的ですので、
プロダクション環境にデプロイする場合にはDartコードをdart2jsというツールで
JavaScriptに変換する必要があります。

Dart Editorからもできますが、折角なのでターミナルからdart2jsを実行してみましょう。

webディレクトリ配下で以下のコマンドを実行します。

$ dart2js --out=index.dart.js index.dart
packages/observe/src/path_observer.dart:83:46: Hint: Using "new Symbol" may result in larger output.
Use "const Symbol" if possible.
    segments.add(index != null ? index : new Symbol(segment));
                                         ^^^
/Applications/dart/dart-sdk/lib/collection/list.dart:32:15: Internal error: code is 0 (class(ListMixin)/field(ListMixin#_toStringList))
  static List _toStringList = new List();
          ^^^^^^^^^^^^^
Dart file index.dart compiled to JavaScript: out.js

何かエラーっぽいのが出ていますが、今回のアプリケーションとは関係無いところなので、とりあえず置いときましょう。

以下のファイルが作成されていることを確認します。

index.dart.js
index.dart.js.deps
index.dart.js.map

では、実際に実行してみます。
Dart Editor上からでもWebブラウザを起動できますが、
折角なのでFinderなどからindex.htmlをWebブラウザにドラッグ・アンド・ドロップして、内容を確認しましょう。

3.7 どこでもDart まとめ

前述した3つの環境で、実際に動作させてみました。

それぞれの環境に特化したアプリケーションにもできますし、
フルスタックなDart製Webアプリケーションにもできます。
(コンソールアプリケーションでWebサーバーを起動する)

また、開発時は基本Dartiumを使用、
統合テスト等ではdart2jsを使って別のブラウザを使用することで、
開発効率を下げずにJavaScriptアプリケーションを作成できます。

このように、
昨今の複雑になりがちなWebアプリケーション開発をシンプルにしてくれるのが
Dartの大きな強みの一つです。