Smalltalk-72で学ぶOOPの原点:Rubyのinstance_eval相当の「's」

アラン・ケイの“オブジェクト指向”というアイデアをもとに(非同期処理などいろいろ足りていないながらも──)比較的忠実に実装された1970年代の非常に古いSmalltalk-72で遊んでみるシリーズです(なお最新のSmalltalkについては Pharo などでお楽しみください!)。他の記事はこちらから→Smalltalk-72で学ぶOOPの原点 Advent Calendar 2019 - Qiita


組み込みの構造化エディター(ソース概説))の続き)

'sでオブジェクトの中身を直接いじる

すでに何度か触れたり、エディターのソースにも出てきた'sは、それに続くメッセージとして送られる「括弧でくくられたコード(ある意味で“ブロック”)」をレシーバーのコンテキストで実行する振る舞いをさせるときに使う(ことになっている)記号です。

ただ、これもやはり既に述べたとおり、継承の無いSmalltalk-72ではObjectに代表される基底クラスに定義された“デフォルトの振る舞い”などというものは期待できないので、自作のクラス(に限らず、それが期待される全てのクラス)にはそうした振る舞いをさせたい旨の記述をいちいちしておく必要があります。

試しに、インスタンス変数ivを持つクラスfooについて、通常どおりiv ← <値>というメッセージを送るのとは別に、'sで直接値を変更することも可能なように定義してみましょう。

インスタンス変数はクラス名の後に(一時変数宣言と区別するために──):(コロン)で区切りを入れてから宣言します。アクセッサーのパターンマッチコード片は「ivというメッセージを受け取ったら(∢iv⇒()、続くメッセージがなら(∢←()、さらにそれに続くメッセージを評価してivに代入してからその値を返し(⇑:iv))、そうでなければ単純にivを返す(⇑iv))」と記述します。

一方、'sのパターンマッチコード片はALLDEFSに何度も現れる決まり文句ならぬ“お決まりのコード片”のとおり「∢'s⇒(⇑⦂ eval)」です。は続くメッセージとして与えられたトークン(配列ならトークン列)を評価せずにトークンのまま取り込むアクションで、したがって⇑⦂ evalは取り込んだ配列を自分のコンテキストで評価(eval)して返す()ことを意味します。

'sという一文字の記号は、ちょい直し版でのみ入力可能で、「KeyboardHelp」にあるとおり ctrl+shift+s か、あるいはブラウザなどの都合で同キーアサインが使用できない場合は「|」をタイプすることでも入力できます(ちょい直し版は、ドキュメント通りの ctrl+shift+s が機能するようにすると同時に、代替キーアサインの追加もしています)。

f:id:sumim:20191217224538p:plain
インスタンス変数「iv」を持ち、そのアクセッサーとは別に「's」に応答できるクラス「foo」の定義

xfooインスタンスを代入し、アクセッサーの動作を確認します。

f:id:sumim:20191217225859p:plain
クラス「foo」のインスタンス作成とアクセッサーの動作確認

この状態でインスタンス変数ivには3が代入されているわけですが、これを'sを使って直接4に書き換えてから、あらためてアクセスしてみましょう。

f:id:sumim:20191217230852p:plain
「's」を使って直接インスタンス変数を書き換える

'sが入力できないときの代替策

'sが入力できなくても、たとえばssなど適当なメッセージに応答して同じ振る舞いをするように記述すればよいわけですが、ただ、が入力できないと件のお決まりのコード片である「∢ss⇒(⇑⦂ eval)」が記述できずそこで困ってしまいます。改めてアクションの定義をALLDEFSで探すと次のように(プリミティブCODE 36を呼んでこそいますが──)「(:☞)と等価である」と分かります。

f:id:sumim:20191217231911p:plain
「⦂」アクションの定義

したがって、'sの代替をを使わずに書くと∢ss ⇒(⇑(:☞) eval)と書くことができ、既存のクラスにもaddtoアクションを使うか、editの「Add」等で追加できます。

f:id:sumim:20191217232642p:plain
「's」と「⦂」が入力できないときの回避策

それでも'sが入力できないと、そのうち不可能なこともなにかと出てきて不便なので、なんとか'sを入力できるようにした件の「ちょい直し版」を作ったというわけです。

ユーザー定義クラス・アクションの一覧「defs」と定義の出力「show」に続く)