% google-count edit-compile-{run,test,link} 1980 edit-compile-run 1190 edit-compile-test 1600 edit-compile-link
スクリプト言語の利点としてコンパイル不要というのがあげられることがある。 これは turn around time の短縮を極限まで進めたものだと考えられなくもない。
とすれば、静的にコードを生成するツールはその利点を殺すものなのかも知れない。
いや、これは極限ではないかも?
edit-compile-test cycle のうち、compile が除かれて edit-test になっているわけだから、 edit と test を融合すればさらに短縮できるかも?
たとえば、save すると自動的に unit test が起動するというのはどうだろう?
そういえば、Eclipse のように save すると自動的に compile するってのも turn around time を減らすという意味ではよく似ている。
time ではなく、必要な手動操作の量かも知れない。
あるいは、手動で save しなくても?
プログラムを生成するプログラムを作るのは 箸でフォークを摘んで飯を食うようなものだという例えを思いつく。
... 間接性の増加による不便さは表現しているが、 その間接性がもたらす強力さを表現できてないか。
WYSIWYG なプログラミング言語というのはあり得るだろうか?
つまり、プログラムが実現するものをプログラミング時に見ることは可能だろうか?
まぁ、プログラムの強力さは間接性によるわけで、 すべてをそうするのが不可能なのは自明な気はする。 では、可能な部分にはどんなものが存在するだろうか?
WYSIWYG といっても実現するものすべてが見えなくてもいいかもしれない。
たとえば、WYSIWYG な HTML エディタならグラフィカルなブラウザでの表示という 実現を見えるようにしてくれるけれども、 w3m における表示という実現を見えるようにはしてくれない(と思う)。 (音声ブラウザみたいなののほうが例として適切か?)
そんな感じで、実現するものの一部を見えるようにするというのはどうだろうか。
プログラムを入力から出力への関数だと思えば、 関数を直接見えるようにするのは (グラフで表現できるようなケースを除けば) 難しいが、 いくつかの入力を選んでそれらに対する出力を常に表示しておくことはそれほど難しくないかも知れない。 unit test をのべつまくなしに動かすというのはこれのひとつのやりかたかもしれない。
12-02 あたりの「バカが征く」:
> 自分の場合、C-x C-sが手くせになってますから、セーブのたびにユニット・ > テストが走るのはあんまし・・・
まぁ、あれは原理的な話としてであって、現実にやるにはいろいろ細工がいるかも知れません。
たとえば、速度が問題になるなら、 テスト毎にどこが実行されるかの記録 (カバレッジとか、プロファイルくらいでもいいかも) を取っておいて、行った変更が影響する可能性があるものだけを実行するとか。
計算機の速度向上がテスト量の増加に勝てるならそんな細工はそのうちいらなくなっちゃうかもしれませんが。
でも、unit test がのべつまくなしに動いても、 WYSIWYG という感じにならない気がする。
考えてみると普通の(アプリケーションの)ユーザは unit test を 動かしたりはしないわけで、 とするとそんなものを表示したとしても WYSIWYG にはならないか。
WYSIWYG というからには、 実際にユーザが使用している状況に近い状況において プログラミングするようなものなはずで、さて、どんなものがあり得るかな。
いや、アプリケーションでなく、ライブラリだとしたらどうだろう?
ライブラリをプログラミングしているときに、unit test を起動するのは、 そのライブラリのユーザであるところのアプリケーションの動作を近似しているといえる?
他のプログラムを exec するだけのシェルスクリプトを生成するコマンドを書いてみる。
まぁ、普通は symbolic link で済むのだが、「他のプログラム」がスクリプトで、 dirname $0 などとやってると動かなかったりするし。
なお、pathname.rb の習作という意味合いもあったのだが、 とくに思うところもなく終ってしまった。
fseek が lseek を呼ばない条件を調べる。
ふと思い立って helium への cvs access を ssh 経由にする。
昔作った cvs-rsh-pserver を引っ張りだしたら、 古い .cvspass の形式しか扱ってなくて修正が必要だった。
東京
とある人に似ていると今日だけで 4回(だったと思う)も(それぞれ別のひとから)言われてしまったのはどういうことなのだろう。
そのとある人に意見を求めたところ、人間の識別能力が低い人が多いのではないかとのことであった。
自分自身他人の顔を覚えられないので納得できるものがある。
今日 pathname.rb を使って気がついたこと:
最近、必要性が薄くても pathname.rb を使うようにしているのだが、 Pathname.new と書く数が意外に少ないことに気がついた。 ひとつのスクリプトで、 argv = ARGV.map {|f| Pathname.new(f) } と一回だけ書いて それ以外では書かないケースが多い。
さて、Pathname#find についてはそういう欲求を感じたのは初めてなので、 現時点ではメモしておく以上の話ではない。 実際に実装するかどうかまじめに考えるのは何回か欲しくなった後でいい。
酒
次に、Pathname#extname であるが、 これはすでに何回か考えたことがあるので、もう少し深い考察をすべきである。
以前考えたのは、"." 込みのを返すのは冗長ではあるが、 ソースコードを一見して分かるようにする効果があるということである。 つまり、例えばソースコード内に "java" と書いてあるのに比べ、 ".java" と書いてあると、 そのリテラルが拡張子を表現していることが即座に見て取れるため、 x.extname == ".java" というようにアプリケーション内で比較を行う場合、 アプリケーションのソースコードに「一見して分かる」要素を増加させ、 ソースコードのドキュメント化を促進する効果がある。
というわけで、"." は冗長であってコードを長くする悪い効果もあるが、 ソースコードのドキュメント化を促す良い効果もある。
というわけで、"." を含まないメソッドを要求するケースがいくつか存在するというだけでは、 即座に(Pathname.new("x.java").ext == "java" というような) "." を含まないものを返すメソッドを付け加える根拠としては十分ではない。 もし単純にそういうのを付け加えたとすると、 プログラマはプログラムを短くするのとドキュメント化の二つの効果のどちらかを排他的に選ばなければならない。
というわけで、これまた即座にメソッド追加で対処する対象ではなく、 さらなる考察を要求する話である。
うぅむ。こんなのあたりまえではないか。 酒が入っているせいかなんか意味もなく長いな。 もっと短く表現できていいはずだが。 あるいは、酔っていなければもっと短い表現で済ますであろうと推測できるというべきか。
酔っていると自覚している状況でネットワークトラブルを確認した場合、 どのように対処すべきか?
とくになにもせずに眠りこんでしばらくして起きたらトラブルは消えていた。
五月雨を動かしていると、たまに core を吐く。 昨日も吐いていたことに気がついた。
core を吐くたびにいろいろと記録しているのだが、 それなりにたまったので backtrace の頭をまとめて眺めてみよう。
% head bugs/*/backtrace ==> bugs/20031109-132138/backtrace <== Core was generated by `ruby ./main.rb -v'. Program terminated with signal 11, Segmentation fault. #0 0x08057286 in rb_eval (self=1078927176, n=0x402fab94) at ruby.h:634 634 return RBASIC(obj)->klass; #0 0x08057286 in rb_eval (self=1078927176, n=0x402fab94) at ruby.h:634 #1 0x080570b6 in rb_eval (self=1078927176, n=0x402fab44) at eval.c:3024 #2 0x08059f03 in rb_yield_0 (val=1086760044, self=1078927176, klass=0, flags=0, avalue=2) at eval.c:4233 #3 0x0805a148 in rb_yield_values (n=2) at eval.c:4310 #4 0x0806cf44 in delete_if_i (key=1075628196, value=10) at hash.c:467 #5 0x0806c80f in rb_hash_foreach_iter (key=1075628196, value=10, arg=0xbffdfbcc) at hash.c:133 ==> bugs/20031110-030509/backtrace <== Core was generated by `ruby ./main.rb -v'. Program terminated with signal 11, Segmentation fault. #0 0x08057286 in rb_eval (self=1079273516, n=0x402fab94) at ruby.h:634 634 return RBASIC(obj)->klass; #0 0x08057286 in rb_eval (self=1079273516, n=0x402fab94) at ruby.h:634 #1 0x080570b6 in rb_eval (self=1079273516, n=0x402fab44) at eval.c:3024 #2 0x08059f03 in rb_yield_0 (val=1078872516, self=1079273516, klass=0, flags=0, avalue=2) at eval.c:4233 #3 0x0805a148 in rb_yield_values (n=2) at eval.c:4310 #4 0x0806cf44 in delete_if_i (key=1075628196, value=10) at hash.c:467 #5 0x0806c80f in rb_hash_foreach_iter (key=1075628196, value=10, arg=0xbffdfbcc) at hash.c:133 ==> bugs/20031118-145233/backtrace <== Core was generated by `ruby ./main.rb -v'. Program terminated with signal 11, Segmentation fault. #0 0x080986db in rb_reg_prepare_re (re=1079819936) at re.c:701 701 RREGEXP(re)->ptr->fastmap_accurate = 0; #0 0x080986db in rb_reg_prepare_re (re=1079819936) at re.c:701 #1 0x080987f1 in rb_reg_search (re=1079819936, str=1079900856, pos=0, reverse=0) at re.c:751 #2 0x08099293 in rb_reg_match (re=1079819936, str=1079900856) at re.c:1196 #3 0x08055c06 in rb_eval (self=1079833976, n=0x4029da28) at eval.c:2530 #4 0x08055dde in rb_eval (self=1079833976, n=0x4029cfb0) at eval.c:2593 #5 0x0805c159 in rb_call0 (klass=1076077548, recv=1079833976, id=17585, oid=17585, argc=0, argv=0x0, body=0x4029cfb0, ==> bugs/20031125-113636/backtrace <== Core was generated by `ruby ./main.rb -v'. Program terminated with signal 11, Segmentation fault. #0 0x080572d6 in rb_eval (self=1078763836, n=0x403eee5c) at ruby.h:634 634 return RBASIC(obj)->klass; #0 0x080572d6 in rb_eval (self=1078763836, n=0x403eee5c) at ruby.h:634 #1 0x08057106 in rb_eval (self=1078763836, n=0x403eed80) at eval.c:3047 #2 0x08059f73 in rb_yield_0 (val=1086266664, self=1078763836, klass=0, flags=0, avalue=2) at eval.c:4260 #3 0x0805a1b8 in rb_yield_values (n=2) at eval.c:4337 #4 0x0806d174 in delete_if_i (key=1075628196, value=10) at hash.c:467 #5 0x0806ca3f in rb_hash_foreach_iter (key=1075628196, value=10, arg=0xbffe008c) at hash.c:133 ==> bugs/20031129-133739/backtrace <== Core was generated by `ruby ./main.rb -v'. Program terminated with signal 11, Segmentation fault. #0 0x080986fb in rb_reg_prepare_re (re=1078602256) at re.c:701 701 RREGEXP(re)->ptr->fastmap_accurate = 0; #0 0x080986fb in rb_reg_prepare_re (re=1078602256) at re.c:701 #1 0x08098811 in rb_reg_search (re=1078602256, str=1078314676, pos=0, reverse=0) at re.c:751 #2 0x080992b3 in rb_reg_match (re=1078602256, str=1078314676) at re.c:1196 #3 0x08055bd6 in rb_eval (self=1076927096, n=0x40373824) at eval.c:2537 #4 0x08055dae in rb_eval (self=1076927096, n=0x40373694) at eval.c:2600 ==> bugs/20031208-195453/backtrace <== Core was generated by `ruby ./main.rb -v'. Program terminated with signal 11, Segmentation fault. #0 0x08057286 in rb_eval (self=1078745436, n=0x403edc64) at ruby.h:634 634 return RBASIC(obj)->klass; #0 0x08057286 in rb_eval (self=1078745436, n=0x403edc64) at ruby.h:634 #1 0x080570b8 in rb_eval (self=1078745436, n=0x403edc14) at eval.c:3047 #2 0x08059f53 in rb_yield_0 (val=1085592912, self=1078745436, klass=0, flags=0, avalue=2) at eval.c:4270 #3 0x0805a198 in rb_yield_values (n=2) at eval.c:4347 #4 0x0806d234 in delete_if_i (key=1075628156, value=16) at hash.c:467 #5 0x0806caff in rb_hash_foreach_iter (key=1075628156, value=16, arg=0xbffdb3ec) at hash.c:133 ==> bugs/20031213-202323/backtrace <== Core was generated by `ruby ./main.rb -v'. Program terminated with signal 11, Segmentation fault. #0 0x08057286 in rb_eval (self=1078705256, n=0x403e760c) at ruby.h:634 634 return RBASIC(obj)->klass; #0 0x08057286 in rb_eval (self=1078705256, n=0x403e760c) at ruby.h:634 #1 0x080570b8 in rb_eval (self=1078705256, n=0x403e75bc) at eval.c:3076 #2 0x08059f53 in rb_yield_0 (val=1080042436, self=1078705256, klass=0, flags=0, avalue=2) at eval.c:4299 #3 0x0805a198 in rb_yield_values (n=2) at eval.c:4376 #4 0x0806d224 in delete_if_i (key=1075628156, value=10) at hash.c:467 #5 0x0806caef in rb_hash_foreach_iter (key=1075628156, value=10, arg=0xbffdb3cc) at hash.c:133 ==> bugs/20031217-130942/backtrace <== Core was generated by `ruby ./main.rb -v'. Program terminated with signal 11, Segmentation fault. #0 0x08057326 in rb_eval (self=1078816076, n=0x403e7724) at ruby.h:634 634 return RBASIC(obj)->klass; #0 0x08057326 in rb_eval (self=1078816076, n=0x403e7724) at ruby.h:634 #1 0x08057158 in rb_eval (self=1078816076, n=0x403e76d4) at eval.c:3076 #2 0x08059ff3 in rb_yield_0 (val=1087022696, self=1078816076, klass=0, flags=0, avalue=2) at eval.c:4299 #3 0x0805a238 in rb_yield_values (n=2) at eval.c:4376 #4 0x0806d2f4 in delete_if_i (key=1075628156, value=16) at hash.c:467 #5 0x0806cbbf in rb_hash_foreach_iter (key=1075628156, value=16, arg=0xbffdb3ec) at hash.c:133
数えてみると、delete_if が 6回、 rb_reg_match が 2回である。
delete_if は [ruby-dev:21899] ですでに書いたが、 rb_reg_match もそのうちどうにかして再現させないとな。
プログラムを書いていて、なんかクラスが必要になったとしよう。 実装も頭に思い浮かび、べつに問題なさそうだとしよう。 しかし、適切な名前を思いつかない場合どうしたらいいか?
-> そのプログラムを捨てる
「よくわかるリファラースパム」の話を読... む前に 「よくわかる現代魔法」を読む。
作品としては好みに合う。
べつに魔法を使うときに素数を遅延評価で求めるところに萌えたわけではない。 ましてやその Haskell コードが出ていることにひかれたわけでもない。
% google-count {アホ,あほ,バカ,ばか}毛 3230 アホ毛 754 あほ毛 90 バカ毛 22 ばか毛
アクセス可能な時計がふたつある。 ひとつは、VMware 内で動いている Linux の時計。 もうひとつは、ISDN ルータの時計。
両方の時刻を正しくセットしてもしばらくするとずれていることから、 このふたつの中には信用できない時計が少なくともひとつ (最大ふたつ) 存在する。
さて、どちらが (もしくは両方が) どのように信用できないかを調べるには、 どんな観測をすれば良いか?
VMware に host OS の時刻を尋ねるコマンドをでっちあげ、 観測可能な時計をひとつ増やす。
時計の進みかたを 1日ぶん測定するには 1日かかる。 どんなに高速な計算機を使ってもこれは変わらない。
% cat t.c #include <stdio.h> int main() { while (1) { int c = getc(stdin); printf("char=%d eof=%d\n", c, feof(stdin)); } return 0; } % gcc t.c % ./a.out abc char=97 eof=0 char=98 eof=0 char=99 eof=0 char=10 eof=0 <^D>char=-1 eof=1 def char=100 eof=1 char=101 eof=1 char=102 eof=1 char=10 eof=1
そーか。feof が真でも getc は動くか。
[latest]