NScripterにおけるパッケージ化

絶対値を返す命令を作ってみる。

#define部
numalias abs_num,100
numalias abs_result,101
defsub abs

#ルーチン部
 *abs
getparam i%abs_result,%abs_num ; 引数を取る。
if %abs_num < 0 mul %abs_num,-1 ; マイナスならばマイナス1をかける。
mov %%abs_result,%abs_num ; 結果を回答変数に代入
return

たとえば、

abs %0,%1

とするならば、%0に%1の内容の絶対値が入る。
サンプルスクリプトはこんな感じで。

*start
rnd2 %1,-100,100 ; -100から100までの乱数を発生させる。
%1=%1
abs %0,%1
%1の絶対値=%0
click
end

ここで使われているテクニックは

  • 使用される変数を全てnumaliasで規定することで、何番を使うかを柔軟に変更できる。
  • numaliasに_(アンダーバー)を使って識別接頭辞をつけることで、numalias自身の重複を防ぐ。
  • defsub命令により命令化する。
  • getparam命令により引数を取れるようにする。

などである。
ダイクストラによれば、サブルーチンや関数は全て返り値を返すべきなのだが、NScripterにはそうでない命令もあるので、それにこだわる必要はないと思う。
ある設定をする命令があるならば、その命令によって設定された数値を取得する別の命令を作るのがNScripterの流儀だろう。画面を800*600にする;mode800に対する、getwindowsize命令などその一例である。
今回は数学関数であり、返り値を戻してナンボだったので、第一引数に与えた変数に結果を返すことにした。第一引数に結果を返す仕様は、他のcosなどを始めとする既定の数学関数と仕様を合わせた結果である。こういう法則性に留意するのも、理解を助けバグのないプログラムを作る基礎となる事項だ。
追記。同じ変数を使って、もう一つのabsを作ってみた。

defsub abs2
 *abs2
getparam i%abs_result
if %%abs_result < 0 mul %%abs_result,-1
return

引数に与えた変数を絶対値に変換してしまうものだ。元の数値を使う必要がない場合はこちらを使った方が恐らくは早いだろう。
結論として、このルーチンを使った場合、

  • abs_で始まるnumaliasの変数は使わない

ことを守る限り、abs(とabs2)命令はどんな場合でも誤作動しないことがわかるだろう。(もしそれで誤作動するのであれば、それはNScripter自身のバグであるからして、その場合は速やかに高橋直樹氏に連絡すること。多分せねばならん状況はないと思うが)
中でどんな処理をしているか気にせず、ただ引数の与え方と結果の取得の仕方(あわせてインターフェイスと呼ぶ)を規定し、それを崩さなければ、それは「パッケージ化されている」と表現し、安定の第一歩となる。
アインシュタインだか誰だかはこんなことを言っていたように思う。

物事はそれ以上分割できないくらいに単純化してから考えろ

正しい動作をする部品を組み合わせてできた物が、正しい道具でないはずがないのだ。
もしそうなら、それは組み立てた奴が馬鹿なだけだ。