アラン・ケイの“オブジェクト指向”というアイデアをもとに(非同期処理などいろいろ足りていないながらも──)比較的忠実に実装された1970年代の非常に古いSmalltalk-72で遊んでみるシリーズです(なお最新のSmalltalkについては Pharo などでお楽しみください!)。他の記事はこちらから→Smalltalk-72で学ぶOOPの原点 Advent Calendar 2019 - Qiita
(サンプルコード「joe the box」(turtleにplace追加、squareとboxの定義)の続き)
「is
」メソッドの追加
今のままではjoe
やjill
、つまりbox
クラスのインスタンスたちは、メッセージ「is …
」に対してしかるべく振る舞えず、untyped
ということになってしまいます。なお、?
は「~」で入力できます。
これにきちんと答えられるようにbox
クラスにis
メソッドを追加しましょう。Smalltalk-72操作マニュアルの Page 22 には、学習目的でISIT
を使わないちょっと長めの素朴な記述が紹介されています
が、ここでは素直に既に解説済みのISIT
を使って簡単に済ませてしまいましょう。
「's
」メソッドの追加
これまた今のままでは、せっかく位置も変更できるように用意されたインスタンス変数x
やy
が使えません。「x
メソッド」「y
メソッド」といったアクセッサーを用意するのも手ですが、ここはもう少し柔軟に対応できる's
メソッドを定義することで対処します。
既にご紹介した's
メソッドのイディオム(⇑⦂ eval
、もしくは⇑(:☞) eval
)は、メッセージの続きのトークンもしくは配列を評価せずに取り込んで(⦂
、もしくは(:☞)
)からあらためて評価し(eval
)その結果を返す(⇑
)というものでした。
is
メソッド同様、addto
アクションを使ってbox
クラスに簡単に追加できます。
ただしこの定義の場合、ゲッターとして使うときは欲しい変数を指定するだけで済むのですが──
x
に別の値を代入しようとすると、そのための式を括弧でくくって与える必要が生じます。
ここは「joe's x ← 64
」などとスマートに書きたいところですが、⇑⦂ eval
のままでは「joe's x
」で式が完結し、その返り値である数値「127」に改めて「← 64
」が送られることになるため、結果、エラーが発生してしまいます(数値は← …
メッセージに応答できないため。仮に応答できても望んだ結果にはなりませんが…)。
そこで、あらためてSmalltalk-72操作マニュアルの Page 22 に紹介されている's
メソッドを見てみると──
取り込んだトークンをいったん一時変数「var
」に代入し(☞var←⦂.
)、続くメッセージが「←
」なら(∢ ←⇒(…)
)その後に続くメッセージを評価して取り込んでから「var
」に入った変数に代入して値をリターン(⇑var←:
)、そうでなければ改めて取り込んだトークンを評価(変数ならその値を得る)して結果をリターンする(⇑var eval
)という、ちょっと凝った処理をしています。この定義に差し替えて期待通り振る舞うか試してみましょう。
すでに「's
」メソッドを定義済みなので、与えたコード片を単純にコード末尾に追加するだけの「addto
」アクションは使えません。そこで「edit
」アクションでエディターを起動し、Replaceで「's
」メソッドを差し替えます。
Exitでエディターを抜けて元のREPLに戻れば、今度は「joe's x ← 64
」が期待通り動作するようになっているはずです。
こんな記述も可能になります。
「's
」はRubyのinstance_eval相当なのですが、とても自然に書き下せていますね。このように文法を気軽に拡張できることは、たいへん柔軟でパワフルである反面、なんとも怖ろしくもあります(そしてそれが次の世代のSmalltalk-76が同様の実装にならなかった理由のひとつであり、また、LISPの強い影響下にありながらRubyにマクロがない理由のひとつでもあるわけです)。
Smalltalk-72操作マニュアルには、この他にmove
メソッドの追加や、そのバリエーション、redraw
メソッドを使った別のbox
の実装なども紹介されているので是非試してみてください。