Perl スクリプトに assertion code を埋め込む実験中 ― 2006年12月05日 21時56分09秒
この記事の続きというか後日談というか。現在製作中の若干大きめのプロジェクトにおいて、自作の assertion code がそれなりに役立っているので、一応現状使っているものとほぼ等価のコードを示しておこうと思う。
sub assert (&) { return unless $debug_mode; shift->() and return; # assertion 失敗時の処理 my (undef, $filename, $line) = caller; my $main_file = main::__FILE__; print STDERR <<ENDLINE; $main_file: Assertion faild at $filename line $line ** Call stack ** ENDLINE my $i = 0; while (my ($pkg, $file, $l, $sub, undef, undef, $evaltxt, $is_req) = caller $i++){ $is_req = $is_req ? 'YES' : 'NO'; print <<ENDLINE; -- stack frame #$i: at $file (package $pkg) line $l -- ENDLINE print $file eq '(eval)' ? <<ENDEVALBLOCK : $sub eq '(eval)' ? <<ENDEVALTEXT : <<ENDSUB; type : eval block is require : $is_req ENDEVALBLOCK type : eval text is require : $is_req eval text : $evaltxt ENDEVALTEXT type : subroutine subroutine : $sub ENDSUB } die "\n"; }
使い方としては、例えばこんな感じ。
$debug_mode = 1; # 本来このインターフェースはもうちょっと別の形で用意されるべき # 最大値を求める sub maxNumber { my $max = shift or return; for my $number (@_){ assert { $number eq $number + 0 }; # 数値以外の値は渡されないはず $max = $number if $max < $number; } $max } my $num1 = maxNumber -2, -70, 6, 4.3; print "num1: $num1\n"; my $num2 = maxNumber 37, -256, 1.25e+17, 'infinity'; # assertion faild!! print "num2: $num2\n";
実用的かどうかはまだ検討中。プロジェクトではまだ小さいデータでしか試せてないのよ。もしかしたら実用には耐え難いほどに処理を重くしてしまうかもしれない (しょっちゅう無名関数を生成するし、少なくともデバッグモードか否かの判定は行われるからね)。
ただ、おいらの場合、大き目のプログラムを作る場合において、部品となる部分のプログラムを作って動作を確認しながら、それらを繋ぎ合わせて大きくする、という手順は踏まずに、大まかに設計した枠組みに沿って全体をどかっと書き始め、問題点をフィードバックしつつ実装し、ある程度出来上がったところで試しに走らせてバグ潰しをする、というやり方で作ってしまうことが多いので、assertion code を埋め込む仕組みがあるのと無いのとではバグ潰しのはかどり具合が全然違ってきてしまう。そういう意味では今のところ、かなり重宝していたりします (それだけバグが多いということですが。。。T-T/)。
union って、そーいやあんま使ったことなかったなぁ ― 2006年12月05日 23時34分13秒
プログラミング言語C 第2版 (訳書訂正版) ANSI規格準拠
(B.W.カーニハン / D.M.リッチー / 石田晴久 訳 / 共立出版)
C では union を reinterpret_cast
代わりに使えるよ、というお話。へぇぇ。
個人的には、union 使うと実数値の実装が見えておもろいなぁとか思った。そんだけなので tb はなし。w
しかし K&R おさらいしてみたら、malloc
するときの境界の整合のために union を使う例が示されてた。そうか union ってこういう風に使うものだったっけか。(なにをいまさら)
最近のコメント