Javascriptでオブジェクトの出身(クラス)を調べる(instanceof演算子)

例えば、次のように配列を生成し、
instanceofに同じウィンドウのArrayクラスを指定すると、
結果はtrueになります。

// ChromeのJavascript Consoleで実行
> var a = [1, 2, 3, 4, 5];
undefined
> a instanceof Array
true

しかし、instanceofに別ウィンドウのArrayクラスに指定すると、
falseになります。

> var a = [1, 2, 3, 4, 5];
undefined
> var w = window.open("");
undefined
> a instanceof w.Array 

たとえ、名前が同じクラス(constructor)のオブジェクトでも、
ウインドウが違ったら、出身が違うオブジェクトになるということですね。

では、クラスの名前(と、できれば中身まで)が同じなら、ウインドウ区別なく
同じ出身にしたい場合、どうすればいいか?

配列オブジェクトの場合、
ECMAScript5をサポートする環境(最新ブラウザ、NodeJSなど)なら、
Array.isArrayという関数を使えばいいです。

次のコードを見ますと、配列aに対して、同じウインドウ上でも、別のウインドウ上でも
isArray関数はtrueを返すことが分かります。

> var a = [1, 2, 3, 4, 5];
undefined
> var w = window.open(""); // 別ウインドウ
undefined
> Array.isArray(a);
true
> w.Array.isArray(a);
true

Array以外のオブジェクトについてはどうすればいいか?
正解は分かりませんが、オブジェクトのconstructor.name属性を調べれば、
大体は対応できると思います。

> var w = window.open("");
undefined
> w.a = [1, 2, 3, 4];
[1, 2, 3, 4]
> w.a.constructor.name === "Array"
true

ただ、文字列ベースの比較なので、中身が偽者の場合、
仕方がありません。
しかし、意図的に偽者を作らない限り、また、セキュリティ(XSS)の脆弱性がない限り、
上記の方法で問題ないと思います。

そもそも、最近、別ウインドウを開くブラウザアプリは、
あまり見なくなったので、いらない内容かも?とも思いましたが、
いざそういうケースに遭うと、面倒なので、この記事を書きました。

この本(Effective Javavscript)が参考になりました。

Effective JavaScript JavaScriptを使うときに知っておきたい68の冴えたやり方

Effective JavaScript JavaScriptを使うときに知っておきたい68の冴えたやり方

Erlang 基礎ポイント5 - 並列処理2

今日はErlangの並行処理における例外処理について勉強したいと思います。

並行処理での例外処理

Erlang 基礎ポイント4で並行処理プログラムの作成が可能になりました。
しかし、現在実行中のErlangプロセス(=Pといいます)から子Erlangプロセス(=Cといいます)を起動し、
そのCからエラーが発生した時の対処方法はまだ勉強していません。
これができないと、Erlangプロセス全体が一つの塊として、機能するのは難しいですね。
まるで細胞同士が協力し、一つの大きい生き物が成り立つのに似ていると思います。

リンク

PからCを生成し、PとCは何の関係もないならば、それまです。
こういう場合、PやCに何かエラーが起こってもお互いは何の関係も影響もありません。

しかし、Cにエラーが起きて、Pも一緒にエラーを起こすか、エラーを修復する処理を
したい場合、PとCの間にリンクを作らなければなりません。
リンクは言葉通りにPとCが繋がっているのを意味し、
一方のErlangプロセスに何か起きた場合、
他方のプロセスにそれが伝わり、他方が自分も終了させたり他の処理をしたい時、使われます。

普通のErlangプロセスを生成する時は、spawn()関数を使いますが、
リンク付きのErlangプロセスを生成したい場合、spawn_link()関数を使います。
以下のサンプルでspawn()とspawn_link()を比較してみましょう。
生成した子Erlangプロセスでエラーが起きた時の動作の違いが分かります。

まず、spawnを使うサンプルです。

% spawn_sub.erlファイルです。
% spawn_test.erlとspawn_link_test.erlで共通で使うための関数を持っています。
-module(spawn_sub).
-export([loop/1]).

% 2秒おきにメッセージ出力
loop(Msg) ->
  receive
    % 終了処理
    exit ->
      exit;
    % わざと、0で割ってエラーを起こす。
    % コンパイル時、警告が出ますが、学習用なので、無視して下さい。
    error ->
      1 / 0
  after 2000 ->
    io:format("Process ~p ~n", [Msg]),
    loop(Msg)
  end.

% spawn_test.erlファイルです。
-module(spawn_test).
-import(spawn_sub, [loop/1]).
-export([spawn_test/0]).

% テストメソッド
spawn_test() ->
  spawn(fun p/0).

% 親Erlangプロセス
p() ->
  CPid = spawn(fun c/0),
  % 後でchildと言う名前で子Erlangプロセスにerrorメッセージを送れるようになる。
  register(child, CPid),
  loop("Parent").

% 子Erlangプロセス
c() ->
  loop("Child").

% REPL環境で試したものです。
1> c(spawn_sub).
./spawn_sub.erl:15: Warning: this expression will fail with a 'badarith' exception
{ok,spawn_sub}
2> c(spawn_test). 
{ok,spawn_test}
3> spawn_test:spawn_test().
<0.44.0>
Process "Child" 
Process "Parent" 
Process "Parent" 
Process "Child" 
Process "Child" 
Process "Parent" 
4> child ! error.% 子Erlangプロセスにエラーを起こします。

=ERROR REPORT==== 24-Jun-2014::10:12:28 ===
Error in process <0.45.0> with exit value: {badarith,[{spawn_sub,loop,1}]}

error
Process "Parent" % Childが出力されなくなりました。しかし、Parentは出力し続けています。
Process "Parent" 
Process "Parent" 

次はspawn_linkを使うサンプルです。

% spawn_link_test.erlファイルです。
-module(spawn_link_test).
-import(spawn_sub, [loop/1]).
-export([spawn_link_test/0]).

spawn_link_test() ->
  spawn(fun p/0).

p() ->
  CPid = spawn_link(fun c/0),  % ここだけがspawn_testと違います。
  register(child, CPid),
  loop("Parent").

c() ->
  loop("Child").

% REPL環境で試したものです。
1> c(spawn_sub).
./spawn_sub.erl:15: Warning: this expression will fail with a 'badarith' exception
{ok,spawn_sub}
2> c(spawn_link_test).
{ok,spawn_link_test}
3> spawn_link_test:spawn_link_test().
<0.44.0>
Process "Child" 
Process "Parent" 
Process "Parent" 
Process "Child" 
Process "Child"  
Process "Parent" 
Process "Parent" 
Process "Child"  
4> child ! error. % 子Erlangプロセスにエラーを起こします。

=ERROR REPORT==== 28-May-2014::13:41:59 === % 親Erlangプロセスも子Erlangプロセスも終了してしまいました。
Error in process <0.45.0> with exit value: {badarith,[{spawn_sub,loop,1}]} 

error
5> 

spawnの方はCが死んでも、Pは動き続けていることが分かります。
つまり、CがどうなってもPは構いません。
なんというか、単細胞がただ分裂するような感じですね。
Javaでたとえると、単純にスレッドを起こしてそれでおしまいという感じです。

逆にspawn_linkの方はCが死んだら、Pも死ぬことが分かります。
プロセスが全部死ぬので、実際のシステムだったら、システムの停止を意味するので、まずいでしょうが、
spawnの代わりにspawn_linkを使うだけで、複数Erlangプロセスがひとかたまりとして、
動く(... 死ぬ)ようになる点はすごいと思います。
Javaでこれをやるためには親スレッドと子スレッドが通信するための何らかの
仕組み(フラグ変数、ブロッキングキュー、Latch等)が必要になってくるでしょう。

システムプロセス

spawn_linkを使って、PとCの間にリンクが置けることが分かりました。
しかし、それだけでは、Cにエラーが起きて死んだ場合、Pも死ぬだけです。
Cが死んで、Pも死んで、PのPも死んで... 結果的にシステムが停止...
これでは実用性がないですし、耐久性があるシステムとはいえないですね。
システムのどこかにエラーが起きた場合、それを捕らえて、修復したり、一部の機能を停止したりして、
システムが動き続けるようにするのが理想的でしょう。

Cにエラーが起きて、Cが死んだ場合、Pも一緒に死ぬのではなく、
PがCのエラーを捕らえて何かをしたい場合、Pをシステムプロセスに指定する必要があります。
Pをシステムプロセスにすると、Cのエラーを捕らえて何かをすることができます。
以下のサンプルを見てみましょう。

% system_process_test.erlファイルです。
-module(system_process_test).
-export([test/0]).

test() ->
  spawn(fun p/0).

p() ->
  % システムプロセスに変身します。
  process_flag(trap_exit, true),
  CPid = spawn_link(fun c/0),
  register(child, CPid),
  loop("Parent").

c() ->
  loop("Child").

loop(Msg) ->
  receive
    {'EXIT', Pid, Reason} ->
      io:format("We catched error(Pid:~p, Reason:~p)~n", [Pid, Reason]),
      loop(Msg);
    exit ->
      exit;
    error ->
      1 / 0 
  after 2000 ->
    io:format("Process ~p ~n", [Msg]),
    loop(Msg)
  end.

% REPL環境で試したものです。
2> c(system_process_test).
./system_process_test.erl:25: Warning: this expression will fail with a 'badarith' exception
{ok,system_process_test}
3> system_process_test:test().
<0.43.0>
Process "Child" 
Process "Parent" 
Process "Parent"Process "Child" 
Process "Child" 
Process "Parent" 
4> child ! error. % 子Erlangプロセスにエラーを起こします。

=ERROR REPORT==== 28-May-2014::13:55:31 ===  % エラーは発生しますが...
Error in process <0.44.0> with exit value: {badarith,[{system_process_test,loop,1}]}

We catched error(Pid:<0.44.0>, Reason:{badarith,  % PでCのエラーをちゃんと捕らえています。
                                       [{system_process_test,loop,1}]})
error
Process "Parent"  % エラーを捕らえた後もPは動きつづけています。
Process "Parent" 
Process "Parent" 
Process "Parent" 

システムプロセスにしたい場合、process_flag(trap_exit, true)を呼び出せばいいです。
trueの代わりにfalseにすると、普通のErlangプロセスになりますが、
falseに指定することはあまりないと思います。
そもそもprocess_flag自体を呼び出さなければ、普通のErlangプロセスになるからです。

明示的なリンクの作成

spawn_linkでなく、spawnでErlangプロセスを作成しましたが、
後で親Erlangプロセスと子Erlangプロセスの間に
リンクを作成したい場合、link関数を使えばいいです。
以下のサンプルを参考して下さい。

% link_test.erlファイルです。
-module(link_test).
-import(spawn_sub, [loop/1]).
-export([test/0]).

test() ->
  spawn(fun p/0).

p() ->
  CPid = spawn(fun c/0),
  link(CPid), % 明示的にリンクを作成します。
  register(child, CPid),
  loop("Parent").

c() ->
  loop("Child").

% REPL環境で試したものです。
1> c(link_test).
{ok,link_test}
2> c(spawn_sub).
./spawn_sub.erl:15: Warning: this expression will fail with a 'badarith' exception
{ok,spawn_sub}
3> link_test:test().
<0.44.0>
Process "Child" 
Process "Parent" 
Process "Parent" 
Process "Child" 
Process "Child" 
Process "Parent" 
Process "Parent" 
Process "Child" 
4> child ! error. % 子Erlangプロセスにエラーを起こします。

=ERROR REPORT==== 28-May-2014::14:01:20 === % 親Erlangプロセスも子Erlangプロセスも止まりました。
Error in process <0.45.0> with exit value: {badarith,[{spawn_sub,loop,1}]}

error
5> 

注意すべきは一見、spawn_linkはspawn + linkで代替できそうですが、実はそうではありません。
spawn_linkはErlangプロセスの生成とリンクの作成が原子的に実行されますが、
spawn + linkはErlangプロセスの生成(spawn)とリンクの作成(link)の間に隙があるので、
原子的に動くのではないからです。
spawnでErlangプロセスを生成した後、linkが実行される前のほんの少しの間に
生成したErlangプロセスが死ぬことがありえます。

今日はここまでにします。
ここまで勉強すると、ある程度、Erlangで並行処理プログラムを作れるのではないでしょうか。
Erlangは並行処理プログラムの作成がとても簡単ですね。
次は並行処理の続きでモニタについて勉強したいと思います。

参考書

プログラミングErlang

プログラミングErlang

Erlang 基礎ポイント4 - 並行処理1

今日はErlangで並行処理プログラムを作成する方法を勉強します。

並行処理

並行処理とは、一つのプログラムの中で複数の処理を同時に実行させることです。
WindowsLinuxなどのOSでは、複数のプログラムが複数のプロセスとして同時に実行されます。
Apache TomcatなどのAPサーバの内部では、複数の処理単位(リクエスト、サーバ)が複数のスレッドとして同時に実行されます。

Erlangでは、複数の処理が複数のプロセスとして実行されます。
しかし、名前はプロセスですが、ErlangのプロセスはOSのプロセスとは違います
あくまでErlang内に存在するプロセスなのです。
これからErlangの並行処理に登場するプロセスは、Erlangプロセスと意識するようにしましょう。

基本

Erlangで作成する並行処理プログラムはJavaなどの言語で記述するスレッド基盤のプログラムとは記述方法が違います。
が、プログラム(又はメインスレッド・メインプロセス)の実行中にいきなり並行に何か(Erlangプロセス)を起動するということは同じです。

Erlangで並行処理プログラムを書くのはとても簡単ですが、それでも掘り下げると色々出てきます。
ここでは最小限の説明だけをします。後はマニュアルや他のウェブサイトを参考して、知識を拡張していけばいいと思います。

まずは、サンプルプログラムを分析し、その後、並行処理プログラムの作成方法を整理してみましょう。

% concurrent.erl
-module(concurrent).
-export([start/0]).
start() -> 
  % A
  spawn(fun() -> echo(1) end).

echo(NoMsgCnt) ->
  % B
  receive
    shutdown ->
      io:format("Shutdown echo~n");
    {one, Msg} ->
      io:format("One Msg ~p~n", [Msg]),
      echo(NoMsgCnt);
    {two, Msg} ->
      io:format("Two Msg ~p~n", [Msg]),
      echo(NoMsgCnt);
    Unknown ->
      io:format("Unknown Msg ~p~n", [Unknown]),
      echo(NoMsgCnt)
  after
  % C
    7000 ->
      io:format("No Msg ~p~n",[NoMsgCnt]),
      echo(NoMsgCnt + 1)
  end.

まず、start関数内のコメントAを見てみましょう。
spawn関数が見えますね。
spawn関数を呼び出すと、引数に指定した関数が処理内容として新しいErlangプロセスが生成及び実行されます
新しいErlangプロセスが生成されると、spawn関数を実行したErlangプロセスと新しいErlangプロセスが同時、つまり、並行で
実行されるようになります。
spawn関数はErlangプロセスのID(PID)を返します。PIDは後ほど、Erlangプロセスと通信する時に必要です。

spawn関数に指定した関数の内部ではecho関数を呼び出しています。
echo関数の内部を見てみましょう。新しいErlangの文法が出てきました。
receiveafterですね。
基本的にspawn関数に指定する関数の内容は何でもいいです。
非同期で何かの処理を分散して行うように、新しいErlangプロセスを実行した後、そのErlangプロセスを忘れてもいい場面もあるでしょうが、
自分を実行した親Erlangプロセスはもちろんのこと、他のErlangプロセスと通信する必要がある場面がもっと多いと思います。

プロセス間の通信のため、Javaでしたら、同期しながら、変数を値を調べるとか...色々と頭が痛くなりますが、
(concurrentパッケージにあるクラスを使えば大体解決できますが、Erlangよりは確かに冗長です)
Erlangでは非常に単純にErlangプロセス間の通信が実現できます。

新しいErlangプロセスが立ち上がると、そのErlangプロセスのためのメールボックスが用意されます。
形こそ、hotmailgmailのようなメールとは違いますが、概念的には同じです。
receive文が実行されると、メールボックスにメッセージが入ってくるまで待機(ブロッキング)状態になります。
メッセージが同時に多数届いた場合、それぞれのメッセージが非同期で処理され、処理が終わったメッセージは削除されます。
メッセージはreceive内のパターンと照合され、マッチしたパターンの処理内容が実行されます。
もし、どのパターンにもマッチしなかった場合、何も実行されません。

afterには一定の時間がすぎるまでメッセージが届いていない場合、つまり、タイムアウトした場合、
処理される内容が置かれます。単位はmsです。
上記には7000とあるので、7秒間、メッセージが届かない場合、No Msg Xと表示されます。

receive内の各パターン及びafterの処理内容を見ると、処理内容の最後に再帰呼出(echo関数の呼出)をしているのが分かります。
これはまた次のメッセージを待つためです。再帰呼出をしないと、そのままErlangプロセスが終了してしまいますので、ご注意下さい。
shutdownパターンには再帰呼出がないことから、Erlangプロセスを終了するということが分かります。
パターンにあるアトムがshutdownですから、意図的ですね。

これでErlangで並行処理を記述することができました。

次は並行処理を実行し、Erlangプロセスと通信する方法を勉強しましょう。
以下は上記のconcurrentモジュールをREPL環境でテストしたものです。

1> c(concurrent).
{ok,concurrent}
2> P = concurrent:start().
<0.39.0>
No Msg 1          
3> P ! {one, "Hello"}.
One Msg "Hello"
{one,"Hello"}
4> P ! {two, "Hello"}.
Two Msg "Hello"
{two,"Hello"}
5> P ! {three, "Hello"}.
Unknown Msg {three,"Hello"}
{three,"Hello"}
No Msg 2                
No Msg 3        
6> P ! shutdown.
Shutdown echo
shutdown
7> 

concurrentモジュールをコンパイルし、start関数を呼び出しました。
戻り値のPIDを変数Pに代入しました。
PはPIDですが、Erlangプロセスへの電話だと考えればいいです。
Pへの連絡はどうすればいいか? ビックリマーク(!)を使えばいいです。

PID ! メッセージ

です。これがErlangプロセスにメッセージを送る方法です。簡単でしょう?
これでメッセージが該当PIDのErlangプロセスに送られると、
メッセージとErlangプロセスのreceive内にあるパターンとの照合が行われ、
マッチしたパターンの処理内容が実行されます。

整理してみましょう。

% 新しいErlangプロセスの生成は
PID = spawn(fun() -> xxx(引数...) end)

% Erlangプロセスでメッセージを受け取るには
xxx(引数...) ->
  receive
    パターン1 ->
      処理1,
      ...
      処理x,
      xxx(引数...); % xxx()を再帰呼出しないと、終了してしまう。
    ...
    パターンx ->
      処理1,
      ...
      処理x,
      xxx(引数...) % 最後のパターンにはセミコロンを書かない
  after % afterは省略可能
    タイムアウト値(ms) ->
      処理
     xxx(引数...)
  end.

% Erlangプロセスと通信するためには
PID ! メッセージ 

さらに

これで、Erlangで動く並行処理プログラムを書けるようになりましたが、
ちょっと足りない部分があります。
それぞれのErlangプロセスとやり取りするため、メッセージを送る時にspawn関数から返されるPidが必要ですが、
Pidをいちいち覚えておくのは面倒です。
そこで、ErlangにはPidを意味ある名前で登録できるようにする関数が用意されています。
その関数でPidを名前に登録しておき、後でその名前でErlangプロセスにメッセージを送ればいいです。

使い方は簡単です。以下のようにすればいいです。

register(名前を表すアトム, Pid)

反対に登録した名前を解除する関数もあります。

unregister(名前を表すアトム)

簡単ですね。

以下は基本で示したサンプルプログラムをregisterを使うように修正し、REPL環境で試したものです。

% concurrent2.erl
-module(concurrent2).
-export([start/0]).
start() -> 
  P = spawn(fun() -> echo(1) end),
  register(test_echo, P).

echo(NoMsgCnt) ->
  receive
    shutdown ->
      io:format("Shutdown echo~n");
    {one, Msg} ->
      io:format("One Msg ~p~n", [Msg]),
      echo(NoMsgCnt);
    {two, Msg} ->
      io:format("Two Msg ~p~n", [Msg]),
      echo(NoMsgCnt);
    Unknown ->
      io:format("Unknown Msg ~p~n", [Unknown]),
      echo(NoMsgCnt)
  after
    7000 ->
      io:format("No Msg ~p~n",[NoMsgCnt]),
      echo(NoMsgCnt + 1)
  end.

% REPL環境でテスト。
1> c(concurrent2).
{ok,concurrent2}
2> concurrent2:start().
true
No Msg 1        
No Msg 2        
No Msg 3                
3> test_echo ! {one, "Hello"}.
One Msg "Hello"
{one,"Hello"}
4> test_echo ! {two, "Hello"}.
Two Msg "Hello"
{two,"Hello"}
5> test_echo ! {three, "Hello"}.
Unknown Msg {three,"Hello"}
{three,"Hello"}
No Msg 4                        
6> test_echo ! shutdown.
Shutdown echo
shutdown
7> 

PIDでなく、test_echoという分かりやすい名前でErlangプロセスと通信できていますね。

Erlangプロセスは他の言語のスレッドやOSのプロセスより早くて効率がいいです。
数万・数十万個のプロセスも問題なく処理できるそうだから、すごいですね。
自分でErlangの威力が直接感じられるプログラムが書けたらいいですね。
イデアが浮かんだら、ぜひやってみたいと思います。
ちなみにErlangでネットワークプログラムを作ると、NodeJSと比べてどうでしょうか。
メリットが少し似ているようが気がします。ググれば出るのかな...

今日はここまでにします。
元々今日でErlang 基礎ポイントを最後にしようと思いましたが、
並行処理での例外処理について意外と書くことが多くて、
次の記事に続けて書くことにします。
最後になるかどうかは分かりません。これはあくまで個人的な理由で書くものですから...笑

Erlang 基礎ポイント3 - case式, if式 例外

case式

Erlang 基礎ポイント2 - DukeLabでパターン集合について説明しました。
パターン集合の結果から処理を複数の関数に分けることができましたが、
関数の数が無駄に多くなる恐れがありますね。

もちろん、プログラムの処理は可能な限り小さくした方が
モジュール化側面でいいでしょうが、やりすぎると、
かえって複雑なプログラムになりかねないですね。

case式を使うと、一つの関数内で処理部を分けておくことができます。
Javaのswitch caseのようなものですが、判断条件に固定値だけでなく、パターンが使えるので、
もっと強力です。

まず、例をみてみましょう。
前のguard_module.erlがErlang 基礎ポイント2 - DukeLabのパターン集合節で紹介したもので
後のcase_test.erlがcase式を使うように修正したものです。

% guard_module.erl
-module(guard_module).
-export([guard_test/1]).

guard_test(X) when X < 5, X > 1 -> X * X;
guard_test(X) when X >= 5; X < 10 -> X - 2;
guard_test(X) -> X - 2.

% case_test.erl
-module(case_test).
-export([guard_test/1]).

guard_test(X) ->
  case X of
    X when X < 5, X > 1 -> X * X;
    X when X >= 5; X < 10 -> X - 2;
    X -> X - 2 
  end.

caseの使い方は次のようです。
他のプログラミングの経験があるなら、問題ないでしょう。

case 評価対象 of
  パターン1 [when ガード...] -> 結果;
  ...

  パターンn [when ガード...] -> 結果
end   

最後のパターンにはセミコロンをつけないことに注意して下さい。
評価対象に判断対象(関数引数・変数など)を指定し、
パターンnに判断対象と照合するパターンを書きます。
必要ならガードに追加条件を指定できますが、ガードは省略可能です。
評価対象がパターンに一致すれば、結果が返されます。
一致するパターンがないと、例外が発生するので、注意しましょう。

caseの方が関数の長さが増えましたが、関数の数は減りましたね。
どちらも優先的に使うのではなく、関数の数とcaseの数をバランスよく
配置すればいいと思います。

if式

他のプログラミング言語のif文と同じですが、違いは式なので、戻り値があるということです。
上記のcase式のサンプルをif式に修正したものを載せます。

% if_test.erl
-module(if_test).
-export([if_test/1]).

if_test(X) ->
  if 
    X < 5, X > 1 ->
      X * X;
    X >= 5, X < 10 ->
      X - 2;
    true ->
      X - 3;
  end.

% if_testをREPL環境で試す。
19> c(if_test).        
{ok,if_test}
20> if_test:if_test(7).
5
21> c(if_test).        
{ok,if_test}
22> if_test:if_test(3).
9
23> if_test:if_test(6).
4
24> if_test:if_test(-1).
-4

if式の文法は他のプログラミング言語のif文と似ていますが、ちょっと違いますね。
まず、複数個の条件を書く時、ifと複数書く必要がありません。
最初にifと書いて、case式のように条件と結果を次々と書いていけばいいです。
それから、最後の条件にtrueと書きましたね。これはelseと考えればいいです。
Erlangのifにはelseがありません。なので、全ての条件に一致しない時の条件を
直接書く必要がありますが、trueと書いておけばOKです。

case 評価対象 ->
  パターン1 [when ガード...] -> 結果;
  ...

  パターンn [when ガード...] -> 結果
end   

trueを書かないで、全ての条件に一致しない場合、例外が発生しますので、注意しましょう。

例外

Erlangで例外処理は、ちょっと形式は違いますが、Javaと同じくtry-catch式を使います。
以下の例を見ながら、try-catchを身につけましょう。

% trycatch.erl
-module(trycatch).
-export([go/1]).

go(X) ->
    try test(X) of
        Val -> {value, Val}
    catch
        throw:exception1 -> io:format("Catch Exception_Test1~n");
        throw:exception2 -> io:format("Catch Exception_Test2~n");
        exit:_           -> io:format("Catch Exit~n");
        error:_          -> io:format("Catch Error~n")
    after
        io:format("After~n")
    end
.

test(X) ->
    case X of
        1 -> throw(exception1);
        2 -> throw(exception2);
        3 -> exit(unknown);
        4 -> error(unknown)
    end
.

% trycatchをREPL環境で試す。
1> c(trycatch).
{ok,trycatch}
2> trycatch:go(1).
Catch Exception_Test1
After
ok
3> trycatch:go(2).
Catch Exception_Test2
After
ok
4> trycatch:go(3).
Catch Exit
After
ok
5> trycatch:go(4).
Catch Error
After
ok

関数goに1から4までの数字を入れると、例外(throw)2種類、プロセス終了(exit)1種類、エラー(error)1種類を演じてくれます。
throwは呼出元が例外を処理することを期待する時、呼出元に対してエラーをなげる関数です。JavaのChecked Exceptionと似ていますね。
但し、throwでエラーを発生させても、呼出元がtry-catchでエラーを捉えなくても実行はできます
Javaのようにコンパイルエラーは発生しません。
プログラムで捉えられなかったエラーはErlangが捉えます。その場合、スタックトレースのようなものが表示されるでしょう。

exitはプロセスを終了させたい時、呼出元にエラーをなげる関数です。try-catchでこのエラーを捉えないと、プロセスが終了してしまいます。

errorは呼出元が例外を処理できないような致命的なエラーが発生したことを知らせるため関数です。
Javaでいうと、RuntimeExceptionのようなものでしょうか。

よく見るとErlangのtry-catchはcaseと似ていることが分かります。
tryとcatchの間のコードがまさにcaseのような形式、その後、catchとafterが追加されていますね。
catchはJavaのcatchと同じで、afterはJavaのfinallyのようなものです。

以下はtry-catch式の使い方です。

try 評価対象 of
  パターン1 [when ガード...] -> 結果;
  ...

  パターンn [when ガード...] -> 結果
catch
    例外種類1(throw, exit, error): 例外パターン1 [when ガード1] -> 結果1;
    ...
    例外種類n(throw, exit, error): 例外パターンn [when ガードn] -> 結果n
after
    catch結果に関係なく、返す結果
end

Erlangのtry-catchはJavaと違って、式なので戻り値があります

今日はここまで。
次はErlangでの並行処理について書きます。

[WebSocket] [Java] WebSocketを試す

WebSocketとは

HTML5仕様を構成する要素の一つで一方向通信しかできなかった既存のHTML通信とは違って、
JavascriptのWebSocket APIとサーバサイドのWebSocket機能でクライアントとサーバ間の両方向通信を可能にする技術だ。

WebSocketの特徴

WebSocketは、通信ごとにHTTPコネクションを開く・閉じるのを繰り返すのではなく、
いったんHTTPコネクションを開いたら、コネクションを開いたままにしておいて、データをやりとりする。

コネクションが維持される間は、Ajaxのようにクライアントからサーバへの通信だけでなく、
サーバからクライアントに直接データを送ることもできる。

以下は、ChromeでWebSocketの公式サイトにあるデモを試したキャプチャである。
"Rock it with HTML5 WebSocket"という文字列を何回もSendしているのにコネクションは一つ(?encoding=text)しか発生していない。
通信の内容はFramesタブをクリックすれば、分かる。
f:id:jeongman7:20140222213222j:plain

WebSocketのAPIについて

サーバAPI

昔はサーブレットコンテナごとに違うWebSocketのAPIがあったが、
今は、JSR 356: JavaTM API for WebSocketという標準ができて、
各ベンダが自分たちのサーブレットコンテナに実装している。
標準APIがあるので、ベンダ依存のAPIは使わないこと。

WebSocketサーバプログラムはWeb(サーブレットJSP)でもStandalone(mainメソッド)でも作れる。

JavaでWebSocketサーバプログラムを実装するために以下のアノテーションとクラスを使用する。

  • @ServerEndPoint
  • @OnOpen
  • @OnMessage
  • @OnClose
  • @PathParam
  • Encoder
  • Decoder
  • 他にも色々。

クライアントAPI

WebSocketのクライアントプログラムはどの言語でも作れるが、ここではJavascriptを取り上げる。
Javascriptでは以下のように非常に単純で分かりやすいAPIが存在する。

  • WebSocket(url)
  • WebSocket.send
  • WebSocket.onopen
  • WebSocket.onmessage
  • WebSocket.onerror
  • WebSocket.onclose

サンプル作成

必要なもの

  • WebSocketをサポートするサブレットコンテナ(Tomcat8, GlassFish、Jetty等)
  • サーバプログラム(JavaJSP)
  • クライアントプログラム(Javascript)

サンプル作成スタート

時間を節約するため、サンプルは早く作りたい。
今回はNetBeansを利用してサンプル作ろう。
Netbeansをダウンロード・インストールし、立ち上げて新規プロジェクトを作成する。
カテゴリでJava Web→Webアプリケーションを選択し、次へ、プロジェクト名を入力し、次へ、
サーバーと設定画面で終了ボタンを押すと、プロジェクトが作成される。

さあ、コーディングをしてみよう。

サーバプログラム

送ったメッセージをそのまま返すだけである。

package dukelab.websocket.demo;

import javax.websocket.OnMessage;
import javax.websocket.server.ServerEndpoint;

/**
 * WebSocketデモ。
 *
 * @author DukeLab
 */
// Webソケットのサーバ側クラスであること表すアノテーション。
// 引数(wsdemo)はクライアントから接続時、使われるURIを表す。
@ServerEndpoint(value = "/wsdemo")
public class WebSocketDemo {

    @OnMessage
    public String onMessage(String text) {
        return text;
    }
    
}

WebSocketのサーバプログラムは@ServerEndpointアノテーションをつけることで始まる。
@ServerEndpointの引数valueにはクライアントから接続時、使われるURIを指定する。
URIは/で始まらなければならない
例えば、ウェブアプリケーションがlocalhost:8080で動いていてコンテキストパスがtestなら、
上記のサーバプログラムへのURLはws://localhost:8080/test/wsdemoになる。

ここでは指定していないが、@ServerEndpointアノテーションへの引数に、
メッセージ変換のためのencoder、decoderも指定できる。
本格的なアプリケーションを作る時に、encoderとdecoderが必要になりそうだ

それから、@OnMessageアノテーションをメッセージを受信するメソッドに指定する。
メソッドの引数textがクライアントから受信したデータということだ。
onMessageメソッド内で色々処理を行って、その応答をreturnすればいい。

@OnMessageアノテーション以外に@OnOpen、@OnCloseもある。
@Onxxxアノテーションがつくメソッド(例 : onMessage(String Text))の引数や応答を返す方法は上記以外にもある。
リクエストが来た時だけでなく、サーバから自発的に送ることもできる。
それらは実装の状況に応じてドキュメントを参照すればいいだろう。

ここでは至極簡単なサンプルサーバプログラムを作った。
上記のクラスだけだ。
web.xmlとかサーブレットは要らない。
本当に便利だ。

クライアントプログラム

サンプルを実行したブラウザはChrome 33.0.1750.117である。

<!DOCTYPE html>
<html>
    <head>
        <title>WebSocketDemo Client</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <script type="text/javascript">
            WebSocketDemo = {};
            (function(d) {
                function $(query) {
                    return document.querySelector(query);
                }
                function printMessage(msg) {
                    $("#msgbox").innerHTML += "<div>" + msg + "</div>";
                }
                d.connect = function() {
                    var ws = new WebSocket("ws://localhost:8080/WebApplication3/wsdemo");
                    ws.onmessage = function(event) {
                        printMessage("Server : " + event.data);
                    };
                    d.webSocket = ws;
                    $("#connect").disabled = true;
                    $("#send").disabled = false;
                };
                d.send = function() {
                    var msg = $("#msg").value;
                    d.webSocket.send(msg);
                    printMessage("Client : " + msg);
                };
            }) (WebSocketDemo);
        </script>
        <form action="javascript:void(0);">
            <input type="text" id="msg" size="20"> 
            <input type="button" id="connect" value="Connect" onclick="WebSocketDemo.connect();">
            <input type="button" id="send" value="Send" onclick="WebSocketDemo.send();" disabled>
        </form>
        <div id="msgbox" style="border-style: solid;width: 500px;height: 400px"></div>
    </body>
</html>

Connectボタンを押すと、WebSocketオブジェクトを生成する。
WebSocketのコンストラクタにはスキームがws://又はwss://(SSLの場合)で始まるURLを指定する。
後、サーバからメッセージを受信すると、onmessageハンドラーが呼ばれる。
引数のオブジェクトのdataプロパティからメッセージの取得ができる。

Sendボタンを押すと、WebSocketオブジェクトのsendメソッドを呼び出してメッセージをサーバに送信する。
サーバより実装が簡単だ。

注意点は、IEの場合、WebSocketから使えるのはIE10からだということだ。
IE9まではWebSocketが使えない。

実行結果

NetBeansで実行ボタンを押せばいい。NetBeans、結構使えるじゃん!
f:id:jeongman7:20140223212045j:plain

さらに進化したサンプル

上記までは、内部的にやり取りされるのが変わっただけで、既存のAjaxでも同じ機能のアプリケーションは作ることができる。
ここで、サーバから自発的にクライアントにメッセージを送る機能をつけてみよう。いわゆるPUSH型通信。
これはAjaxではできないのだ。
setIntervalで周期的にサーバに見に行くしかないのだ。いわゆるPULL型通信。
Ajax以外にCometというのもあるが、これはコネクション確立後、ただ、Pendingして待つだけだ。
実際の通信が送られるまで待つので、通信量を減らすことはできるが、サーバから応答が返ってくると、
また次のHTTPコネクションを確立しなければならない。
ずっと通信を確立しているWebSocketはAjaxとCometとは歴然と違うのだ。

このさらに進化したサンプルでは、制御用JSPを一個作って、そのJSPで何かを入力すると、
サーバから全てのクライアントにメッセージが送信される機能をつける。

以下は上記のWebSocketDemoクラスに機能を追加したものだ。

package dukelab.websocket.demo;

import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

/**
 * WebSocketデモ。
 *
 * @author dukelab
 */
@ServerEndpoint(value = "/wsdemo")
public class WebSocketDemo {

    private static Set<Session> ses = new CopyOnWriteArraySet<>();

    @OnOpen
    public void onOpen(Session session) {
        System.out.println("onOpen : " + session);
        ses.add(session);
    }
   
    @OnMessage
    public String onMessage(String text) {
        return "echo => " + text;
    }
    
    @OnClose
    public void onClose(Session session) {
        System.out.println("onClose : " + session);
        ses.remove(session);
    }
    
    public static void sendMessage(String msg) {
        for (Session ses : ses) {
            ses.getAsyncRemote().sendText(msg);
        }
    }
    
}

要は、接続時(onOpen)にセッションをスレッドセーフなコレクションに入れておいて、
そのセッションに対して操作をすればいい。
切断時(onClose)にセッションをスレッドセーフなコレクションから削除する処理は忘れないように

以下は制御用JSP(control.jsp)である。

<%@page import="dukelab.websocket.demo.WebSocketDemo"%>
<%@page contentType="text/html" pageEncoding="utf-8"%>
<!DOCTYPE html>
<%
    boolean isPOST = request.getMethod().toLowerCase().equals("post");
    if (isPOST) {
        WebSocketDemo.sendMessage(request.getParameter("msg"));
    }
%>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <title>WebSocketDemo Control</title>
    </head>
    <body>
        <%= isPOST ? "Message was sent." : "" %>
        <form action="" method="post">
            <input type="text" name="msg">
            <input type="submit" name="submit" value="Send">
        </form>
    </body>
</html>

以下の画面で、左が制御用JSPで、右がエコデモである。
制御用JSPでメッセージを入力し、Sendボタンを押すと、全てのクライアントにメッセージが送信される
これは、なかなか面白い。
f:id:jeongman7:20140223212109j:plain

まとめ

WebSocketに関する概念やAPI、そしてサンプルを作ってみた。
APIが分かりやすいので、サーバプログラム・クライアントプログラムの作成も簡単にできる。
JavaやCで使ってきたTCP/IPソケットに比べると、遊び水準だ。
IEのサポートが乏しいのが残念なところだが、IE10以上が広がっていくと、問題ないだろう。
いまだIE6のユーザがあって、それがいつになるか分からないが...
これから色々なアイデアのアプリケーションの実現に役立ちそうだ。

Erlang 基礎ポイント2 - プログラムの形式, 無名関数, パターン照合など

Erlangプログラムの形式

REPL環境でなく、ソースファイル(erlファイル)から実行するためには
以下の形式に従う。

-module(test).
-export([func1/0,func3/1,func4/3]).
func1() -> func2() + 5.
func2() -> 3.
func3(X) ->
    Y = X * 2,
    Y * 2.
func4(plus, X, Y) -> X + Y;
func4(minus, X, Y) -> X - Y;
func4(_, _, _) -> "nothing".
% コメント

まず、module文にモジュール名を書く。
モジュール名はソースコードを含んでいるファイル名(拡張子はerl)にする。
モジュールはErlangコードの基本単位だ。

export文には外部からアクセスを許容する関数名・引数の数を記述する。
Javaにおけるpublicといえば、分かりやすい。
コンマで区切って複数指定可能。

次はJavaのようにメンバー変数が来そうだが、そんなものはない。
すぐ処理ロジックを含む関数が来る。
関数のシグネチャにリターンタイプとか、引数の型の指定がない。
関数名と引数名だけを書いて、->の後、すぐ処理内容を記述する。
関数の処理内容は行ごとにコンマで区切って、関数の最後にピリオドを打つ。

引数の数が同じ関数を複数(いわゆる、オーバーロード)書く場合、
各関数の終わりにコンマでなくセミコロンを書く。
但し、最後の関数の終わりにはコンマを書く。

型のチェックは実行時に行われる。
つまり、Erlangは動的型付け言語である。
コメントは%の後に書く。

無名関数

Erlangでは関数を無名で宣言して、変数に代入したり関数の引数や戻り値として使用することができる。

1> F = fun(A) -> A * A end.
#Fun<erl_eval.6.80247286>
2> F(2).
4
3> Y = F.
#Fun<erl_eval.6.80247286>
4> Y(4).
16

funで始まって、end.(ピリオドがあることに注意)で終わる。
次は無名関数を関数の引数に渡したり、戻り値として返す例だ。

% 引数
9> F = fun(A) -> A * A end.   
#Fun<erl_eval.6.80247286>
10> lists:map(F, [1, 2, 3, 4]).
[1,4,9,16]
% 戻り値
12> Plus = fun(X) -> (fun(Y) -> X + Y end) end.
#Fun<erl_eval.6.80247286>
13> PlusFive = Plus(5).
#Fun<erl_eval.6.80247286>
14> PlusFive(9).
14

リスト内包表記

リストから特定条件を満たす要素で構成された新しいリストを作るためのErlangの機能。
普通、リストから特定要素を持つ新しいリストを作るためには
新しい空のリストを宣言しておいて、ループと条件文を利用し、
条件にマッチした要素を空のリストに入れる処理が必要なので、
コードが長くて読みづらくなる。

しかし、リスト内包表記を使うと、リスト(例 : [ 1, 2, 3])の中で
新しいリストを作るための専用の表記ができるので、コードが短くて
読みやすい。

1> L = [1, 2, 3].
[1, 2, 3]
2> [X - 1 || X <- L].
[0, 1, 2].

後ろの部分、X <- LはリストLから要素Xを取り出すという意味で、
"||"の左側に要素Xで行う式を書く。

レコード

Cにおける構造体のようなもの。
Erlangでレコードの宣言方法は色々あるが、よく使われる方法は
拡張子がhrlのファイルにレコードを定義し、
そのhrlファイルをerlファイルで
インクルードする方法だ。

% person.hrl
-record(person, {
  name,
  age,
  tel = 000-0000-0000
}).
% test.erl
-module(test).
-export([duke/0]).
-include("person.hrl"). #インクルード

duke() ->
  #person{name=duke, age=34, tel="0800000-0000"}.

レコードの宣言は、まず、-recordキーワードを書いて、
1番目の引数にレコード名、次に要素名のタプルを指定する。
要素にはデフォルト値の指定ができる。

レコードの使用は

    #レコード名{要素1=値, ... , 要素x=値}

のようにする。

パターン照合

Erlang 基礎ポイント1 - DukeLabでちょっとだけ、触れたが、ここでもうちょっと説明しよう。
Erlangで、=は代入するのではなく、パターン照合するという。

以下の場合、Aに100を代入するのではなく、右側(100)の評価結果と左側のパターン(A)を照合するのだ。

 A = 100

上記の例だと、ぱっとイメージしにくいだろう。
パターン照合とイメージが似ているのは正規表現ではないかな。
正規表現を使うと、ある複雑な文字列からパターンにマッチする特定の部分を手軽に抽出することができる。
ただし、正規表現のルールが分かりにくい短所はある。

同じくErlangのパターン照合も正規表現のようなものだが、
文字列だけでなく、タプル、リスト、関数の引数など、何にでも使えると考えればいいだろう。

以下の例を見てみよう。

19> T = {{name, "duke"}, {age, 34}}.
{{name,"duke"},{age,34}}
20> {{_,_},{_,MyAge}} = T.    
{{name,"duke"},{age,34}}
21> MyAge.
34

Tにタプルが二つ({name, "duke"}と{age, 34})が入っているが、
二つ目のタプルから年齢(34)を取得したい場合、20>のように
パターン照合すればいい。20>の左側にあるパターンのうち、
_(アンダーバー)はダミー要素で何でもマッチする。
マッチするだけで変数に束縛したくない場合、_(アンダーバー)を使う。
パターンのうち、大文字で始まっているMyAgeが
二つめのタプルにある2番めの要素(34)に一致して
年齢(34)を取り出せたことが分かる。
パターン照合の基本が分かれば、後はマニュアルか
ググってパターン照合の例を参考すればいいだろう。

最後に関数のパターン照合に関する例を載せる。

% func_test.erl
-module(func_test).
-export([add/2]).
add(X,plus) -> X + X;
add(X,pow) -> X * X;
add(X,Y) -> X + Y + 1.

% 以下はREPL環境で実行したもの。
1> c(func_test).
{ok,func_test}
2> func_test:add(3, plus).
6
3> func_test:add(3, pow). 
9
4> func_test:add(3, 5).  
9
5> c(func_test).          
{ok,func_test}

ガード

ある関数を呼び出すと、呼び出される関数を探すため、
引数に指定した値の型と関数のシグネチャとのパターン照合を行う。
Javaオーバーロードと似ているものだと考えればよさそう。

追加的にメソッド内で引数の値の内容によって、違う動作をする必要がある時、
Javaではif文やポリモーフィズムを使うが、Erlangではガードを使えばいい

ここでは関数を中心にガードを使い方を説明するが、
case式やif式でも使用できる。

以下のソースを見てみよう。

% guard_module.erl
-module(guard_module).
-export([guard_test/1]).

guard_test(X) when X < 5, X > 1 -> X * X;
guard_test(X) when X >= 5; X < 10 -> X - 2;
guard_test(X) -> X - 2.

上記のソースを解析してみると、
呼び出された関数がguard_testで一番目の引数(X)に値が指定されていて、
Xが5未満かつ1より大きければ(コンマ[,]はandを意味)、X * Xを、
Xが5以上か10未満なら(セミコロン[;]はorを意味)、X - 2を、
それ以外の場合(つまり、elseなら)、X - 2
を返すという意味だ。

以下は上記の関数をREPL環境でテストしたものだ。

1> c(guard_module).
{ok,guard_module}
2> guard_module:guard_test(5).
3
3> guard_module:guard_test(1).
-1
4> guard_module:guard_test(6).
4
5> guard_module:guard_test(15).
13
6> 

ガードは条件文のようなものだと考えればいい。

ガードは便利そうだが、関数の宣言部が複雑になる恐れがあるので、
なるべくパターン照合だけで済ませた方がいいと思う。

今日はここまで。

EclipseのMavenプロジェクトにびっくりマークが出る時の対処方法

EclipseMavenプロジェクトのアイコンに

びっくりマークが出る時がある。

なんらかの理由でプロジェクトのビルドパスが

間違っているよう。

 

その時は、Package Explorerで該当プロジェクトを選択し、

右ボタンをクリック→Maven→Update Projectを選択し、

OKボタンを押せば、びっくりマークがなくなる。