2011-12-06
ネタにマジレスした@bleisお兄ちゃんへ
というタイトルのメッセージを妹に見え妹のように振舞う何かから頂きましたが、残念ながら私はbleisさんではないので、取りあえず受信したということだけ報告しておきます。
bjam AdC jp 2011 7日目
いつもどおり進みます。
参照:2006-02-05 - Cry’s Diary
testingモジュール
testingモジュールはテスト機能を提供するモジュールです。
一般に使用するruleは以下の6つだと思います。unit-test ruleは歴史的理由であるみたいな曖昧なことが書いてあるのでここでは解説しません。
rule compile ( sources + : requirements * : target-name ? ) rule compile-fail ( sources + : requirements * : target-name ? ) rule link ( sources + : requirements * : target-name ? ) rule link-fail ( sources + : requirements * : target-name ? ) rule run ( sources + : args * : input-files * : requirements * : target-name ? : default-build * ) rule run-fail ( sources + : args * : input-files * : requirements * : target-name ? : default-build * )
-failと付いているruleは失敗したら成功を意味するテストです。ill-formedなコードが正しくコンパイルエラーになるかの確認や、実行時に正しく落ちるかの確認などに使います。
これらruleに共通して現れるsourcesとrequirementsはexe ruleなどのそれと同じです。
前回のaliasモジュールに関連して、今回はtarget-nameが重要な意味を持ちます。読んで字の如くターゲット名です。bjamのコマンドライン引数に渡すあれです。省略できるけど省略するとexplicit ruleとかに投げれなくなるので何か設定しとくといいです。
compileとlinkは同じ引数を受け取りますが、rule名の通りコンパイルが通るかリンクが通るかをテストします。
runは実行するための引数や標準入力に渡すファイルなどを設定できます。
bjam checkを豪華に
豪華かどうかは知らないです。classとか使うともっとスマートになりますがめんどいのでガッと書きます。
import testing ;
project /somelib ;
rule named-compile ( name : sources + : requirements * )
{
compile $(sources) : $(requirements) : $(name) ;
explicit $(name) ;
}
rule named-compile-fail ( name : sources + : requirements * )
{
compile-fail $(sources) : $(requirements) : $(name) ;
explicit $(name) ;
}
rule named-link ( name : sources + : requirements * )
{
link $(sources) : $(requirements) : $(name) ;
explicit $(name) ;
}
rule named-link-fail ( name : sources + : requirements * )
{
link-fail $(sources) : $(requirements) : $(name) ;
explicit $(name) ;
}
rule named-run ( name : sources + : requirements * )
{
run $(sources) : : : $(requirements) : $(name) ;
explicit $(name) ;
}
rule named-run-fail ( name : sources + : requirements * )
{
run-fail $(sources) : : : $(requirements) : $(name) ;
explicit $(name) ;
}
rule test ( rule : successes * : fails * )
{
for local s in $(successes) { named-$(rule) $(s) : $(s).cpp ; }
for local f in $(fails) { named-$(rule)-fail $(s) : $(s).cpp ; }
}
local all-tests = [ glob */*.cpp ] ;
local compile-tests = [ MATCH (.*/compile[0-9]*).cpp : $(all-tests) ] ;
local compile-fail-tests = [ MATCH (.*/compile[0-9]*-fail).cpp : $(all-tests) ] ;
local link-tests = [ MATCH (.*/link[0-9]*).cpp : $(all-tests) ] ;
local link-fail-tests = [ MATCH (.*/link[0-9]*-fail).cpp : $(all-tests) ] ;
local run-tests = [ MATCH (.*/run[0-9]*).cpp : $(all-tests) ] ;
local run-fail-tests = [ MATCH (.*/run[0-9]*-fail).cpp : $(all-tests) ] ;
test compile : $(compile-tests) : $(compile-fail-tests) ;
test link : $(link-tests) : $(link-fail-tests) ;
test run : $(run-tests) : $(run-fail-tests) ;
explicit check ;
alias check
: $(compile-tests) $(compiile-fail-tests )
$(link-tests) $(link-fail-tests)
$(run-tests) $(run-fail-tests)
;
まぁ読んだらわかりますね。わからなかったらコメントとか@とかください。以上。
所謂オブジェクト指向言語はオブジェクト指向してないんじゃないかというなにか
※ネタです。マジレスしない様に
※重ねて言いますがネタです。
※なんどもいい(ry
まずは 小人閑居して: 「ぐへへお姉ちゃんパンツ何色」から始めるクラス解説 を読んでください。
この説明でオブジェクト指向わかった!ってなったらそれどうなんだろうと思ってしまったわけです。で、オブジェクト指向プログラミング - Wikipedia読んでみると、
相互にメッセージ (message) を送りあうオブジェクト (object) の集まりとしてプログラムを構成する技法である。
ほう、メッセージとな。さて、先の説明にメッセージがあったか?となるわけです。
オブジェクトとはなにか
多くのOOPをサポートしていると謳っている言語はこのメッセージの送受信(Message Passing, MP)をメンバ呼び出しという形に置き換えて、概念的にはメッセージを送り合って通信しているように見せかけていると言えます。だってコンパイルすると全部線形命令列に置き換わるし。
さて、これはオブジェクト指向なのでしょうか。よくオブジェクト指向の説明に用いられる物と物の関係とか人と人の関係などをとってみても合致していないように見えます。
考えてみてください。ある物Aが別の物Bに対して作用(メッセージを送出)するとします。そのとき物AはBに対して作用はしますが、Bの中身に対して侵入的操作は行ないません。なにかBの内部状態が変化するとしたらそれはB自信が変化を加えます。さらに、現在Aが動いてるとしたらBが止まっているなどということはありません。好き勝手なにかやってるはずです。つまりAとBは独立に動いているはずです。
わかりづらかった場合は人間を例に取りましょう。誰かが何かを処理している過程であなたは心臓を停止して呼吸を停止して話しかけられるまで停止していますか?なにか自分の好きなことをしているはずです。その時だけ他人の心臓を借りて生きているわけがありません。
何がいいたいかというと、オブジェクトは独立したプロセスで好き勝手やってるというのが本来あるべき姿じゃないかと考えるわけです。
お姉ちゃんは答えなくてもいいはず
もうひとつ。主にC++のようにコンパイル時に該当するメンバがなかった場合にエラーになる系の言語についてです。
このエラーになるということが何を意味しているかを考えます。
- しゃべろうと思った相手はそのメッセージを受け取らなければならない
- メッセージを受け取ったことに対して何かしら反応を起こさないといけない
という制約が発生します。
これはお姉ちゃんの例に当てはめると、
ある人が「ぐへへお姉ちゃんパンツ何色」と質問する、と同時に暗黙の脅迫である「話聞けや」と「答えろや」が含まれる
と言うことになります。
答えたくなくて無視したい場合でもcaller側から脅迫されているので答える他ありません。答えたくないがために「はいてません」などと言ってしまうと更なる危険が待っていることでしょう。
この人権を無視したやりとりを紳士である皆さんは黙認できますか????たとえお姉ちゃんが警察を呼んだ(throw)としてもその瞬間ある人はcatchしてどこかに連れ去ってしまうでしょう。
真のメッセージパッシングによるOOPは無視できる
お姉ちゃんの人権を守るためにも正しいOOPを考える必要があります。現在問題に挙がっていることは
- 独立したプロセスでオブジェクトが動いて欲しい
- プロセス間でメッセージのやりとりをする必要がある
- メッセージを選択して受取りたい(無視できたい
ぐらいでしょうか。
これを解決するのが Erlang です。Erlangは並列指向として知られていて、オブジェクト指向に関する文言は1言も見つかりません。しかし最もOOPを再現できるのがErlangなのではないかと考えます。
Erlangは平行指向プログラミングという名からも想像できる通り、平行並列な記述を得意とする言語です。言語の設計はActorモデルをベースとしています。
新たなプロセスを作るのはspawnを使い、メッセージの送信には ! を使います。メッセージの受信にはreceiveを使い、receiveで受信するメッセージはパターンマッチにより取捨選択できます。
ちょっと適当なのを書いてみましょう。
-module(pants). -export([main/0]). main() -> Oneechan = spawn(fun() -> oneechan(shimapan) end), Boyfriend = spawn(fun() -> boyfriend(Oneechan) end), Aruhito = spawn(fun() -> aruhito(Oneechan) end), Oneechan ! {boyfriend, Boyfriend}. oneechan(Color) -> Boyfriend = receive {boyfriend, B} -> B end, oneechan(Color, Boyfriend). oneechan(Color, Boyfriend) -> receive {guhehe_oneechan_pants_naniiro, Boyfriend} -> Boyfriend ! {pants, Color} end, oneechan(Color, Boyfriend). boyfriend(Girlfriend) -> Girlfriend ! {guhehe_oneechan_pants_naniiro, self()}, Color = receive {pants, C} -> C end, io:format("Boyfriend: ~w~n", [Color]). aruhito(Oneechan) -> Oneechan ! {guhehe_oneechan_pants_naniiro, self()}, Color = receive {pants, C} -> C end, io:format("Aruhito: ~w~n", [Color]).
これを実行してみましょう。
$ erl Erlang R13B03 (erts-5.7.4) [source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.7.4 (abort with ^G) 1> c(pants). ./pants.erl:7: Warning: variable 'Aruhito' is unused {ok,pants} 2> pants:main(). Boyfriend: shimapan {boyfriend,<0.43.0>} 3> q(). ok 4>
素晴らしい!boyfriendのみパンツの色を聞くことに成功しました!ある人ざまぁwwwww
まとめ
Erlang使いましょう。 (<-力尽きた
