Smalltalk-72で学ぶOOPの原点:あらためて「Hello, World!」と文字列操作
アラン・ケイの“オブジェクト指向”というアイデアをもとに(非同期処理などいろいろ足りていないながらも──)比較的忠実に実装された1970年代の非常に古いSmalltalk-72で遊んでみるシリーズです(なお最新のSmalltalkについては Pharo などでお楽しみください!)。他の記事はこちらから→Smalltalk-72で学ぶOOPの原点 Advent Calendar 2019 - Qiita
(文字列操作…の前にクラス定義についてからの続き)
文字列の表示
文字列クラスstring
の定義を再掲します。
このprint
の定義を読むと文字列を表示する方法は(REPLで、文字列に限らず、直前に評価した結果を自動的に出力する振る舞いを除けば──)2つあることがわかります。
ひとつは、文字列に対してprint
メッセージを送ることで、もうひとつはそのprint
を受け取ったときの振る舞いに書かれているようにdisp
というオブジェクトに対して← <文字列>
というメッセージを送る方法です。やはりコードを読むことで分かるように、両者は同じではなく、前者は文字列の前後を'
(クオート)で括って出力します。
なお、残念ながら「!」(エクスクラメーションマーク)はそのままキーをタイプしても⇑
(リターン)が表示されるだけで入力できないので、とりあえず前者の方法では今は諦めます。後者の方法では、文字列の代わりに数値を送ることで文字を出力できるようなので、「!」のグリフが割り当てられている17
を送ることで対応しています。
参考まで、0から127までのコードの文字には次のようなグリフが割り当てられているようです。
上で使ったdisp ← <文字列>
やdisp ← <文字コード>
で文字列や文字が出力できる他に、print
のコードを読んでいて気がつくのは、文字列に[<開始位置> to <終了位置>]
を送ることでRubyのように部分文字列を取り出せる機能があることや、さらにfind first <文字コード>
を送ってコードで指定した文字の位置を知ることが出来る機能があること、そして、これらの定義がstring
には見当たらないことです。
どうやらクラス変数substr
がこの謎の鍵を握っているようですがこれについてはまた改めて。
文字列の結合
今のSmalltalkでは文字列や配列の結合は,
(カンマ)を使いますが、Smalltalk-72ではRubyなどと同様に+
を使うようです。もちろんこれは演算子ではなく、+ <結合したい文字列>
というメッセージです。
ただ、下に再掲したvector
の定義を見ると分かるように、配列には+
による結合は定義されていないので、このメッセージが使えるのは文字列だけであることがわかります。
ちなみに配列の操作にはvecmod
という専用のアクションが用意されています。これについてもまた別の機会に。
(継承が…ない!(クラス変数の利用)に続く)
Smalltalk-72で学ぶOOPの原点:文字列操作…の前にクラス定義について
アラン・ケイの“オブジェクト指向”というアイデアをもとに(非同期処理などいろいろ足りていないながらも──)比較的忠実に実装された1970年代の非常に古いSmalltalk-72で遊んでみるシリーズです(なお最新のSmalltalkについては Pharo などでお楽しみください!)。他の記事はこちらから→Smalltalk-72で学ぶOOPの原点 Advent Calendar 2019 - Qiita
(条件分岐以外の制御構造からの続き)
文字列クラス
今さらですが、新しい言語に挑戦するときに定番の「Hello, World!」がまだでした。
では早速Smalltalk-72で「Hello, World!」を…に対して皆さんが即座に無意識のうちに「文字列を出力するには文字列オブジェクトにどんなメッセージを送れば良いのだろうか…」と考えを巡らしていたなら、それはもう、メッセージングのオブジェクト指向への扉は開かれていると考えてよいのではないでしょうか。もしそうなら素晴らしいことですね!
それはさておき、どんなメッセージを送ればよいかについては例によって定義を読むのが早そうです。まずは文字列リテラルにis?
メッセージを送って、クラス名を尋ねてみましょう。?
の入力は?
そのままではなく~
(チルダ)を使ってください。
これはオーソドックスにstring
であるとのことですので、ALLDEFS(ブートストラップコード)からto string …
という記述を探して見てみましょう。
黄色くマークしたプリミティブ(始原関数)CODE 3
のおおよその内容は、薄い赤でマークしたコメント部分(文字列リテラルを代用)に擬似コードで書かれています。
クラス定義の要素
Smalltalk-72のやたら絵文字やら記号の多い癖のあるコードにもだいぶ目も慣れてきたと思うので、ここでちょっと脱線してクラス定義の式の構成について触れておきましょう。直近で取り上げたif
やfor
アクションの定義と同様に、クラスの定義にはto
アクションにメッセージを送る式で記述します。
実はクラスとアクションは本質的には同じもので、両者の違いは手続きの中でisnew
アクションをコールしているかどうかという点だけです。したがって、クラス定義式の最少構成は(仮にクラス名をfoo
とした場合)次のような式になります。
to foo (isnew)
クラスやアクションを定義する際に()
内に記述された手続き(これぞ当初の「メソッド」)は、クラスやアクションそれ自身や、クラスの場合はそのインスタンスがアクティベート(メッセージのトークンからの実体化)されたときにコールされるようです。
ここまで出てきたif
やfor
などのアクション、vector
やstring
などのクラスの定義がそうなっているように、()
内の処理、つまりメソッドは、メッセージのパターンマッチ式(∢<マッチさせたいトークン>
)に続く条件分岐処理(⇒(非偽時処理>) <偽時処理>
)の偽時処理にまた新たなパターンマッチをネストする構成になっています。つまり、今のSmalltalkを含め他の多くのOOPLがそうであるように、メンバー関数(便宜的に「メソッド」と呼ばれている──)がメッセージに対応させて個別に定義されているわけではない、ということはすでに述べたとおりです。
あいにくisnew
アクションの定義はALLDEFSにもプリミティブCODE 5
としか示されておらず、擬似コードもないのでその処理内容は想像するしかありませんが、おそらく、☞x ← foo.
などとクラスとして(つまりは、インスタンスを生成するアクションとして)コールされた場合はisnew
は新しいインスタンスを返し(したがって、続けて条件分岐処理⇒()
を書くと、多くの場合、非偽時処理として括弧内に記述された初期化の手続きが実行される──)、そうでなければfalse
を返す仕様になっているのだと考えられます。
変数の宣言
to <クラス名>
の後は、メソッド中で使われる一時変数の宣言が続き、必要なら:
(コロン)を挟んでインスタンス変数の宣言、さらに必要ならもう一つ:
を挟んでクラス変数の宣言を挿入することができます。
ここでちょっと注意したいのは、「Open the ST-72 Manual」ボタンでダウンロードして読むことができる「Smalltalk-72 Reference Manual」(1976年刊)には、この一時変数、インスタンス変数、クラス変数の区切りに|
(バーティカルバー、パイプ文字)を使うように記述されていることです。
これは、1974年に使われていたことが冒頭に記されているALLDEEFS(ブートストラップコード)、および、このエミュレーターで動いているメモリダンプベースの実装と、件の1976年刊のリファレンスマニュアルが対象にしているSmalltalk-72処理系実装との間には明らかな齟齬があることを示しています。したがって、マウスのクリックがフックできなかったり、ファイルの入出力に対応していないなどのエミュレーターそれ自体の不備や制限に加え、処理系がマニュアルのそれより古いことによりうまく動かないコードがあったり、動くとしてもある程度の読み換えが必要である可能性を念頭に置かなければならないことを意味します。
なお、クラス変数がクラスおよびそのインスタンス群から値を参照したり代入したりできる共有変数なのは今のSmalltalkやRubyなどと一緒です。この次の世代のSmalltalk-76から、SIMULA 67スタイルのクラス(つまり、メンバー関数の動的コールをメッセージと称する「省コスト化」を伴って──)が採用されて以降は、同時に導入された継承機構との兼ね合いでトラブルメーカーとなるわけですが、これはそのそしりを受ける前の話ということになります。
string
クラスにはsubstr
というクラス変数が定義されていますが、その使い方が継承機構に絡めて興味深いので、これについては追々ご紹介しようと思います。
Smalltalk-72で学ぶOOPの原点:条件分岐以外の制御構造
アラン・ケイの“オブジェクト指向”というアイデアをもとに(非同期処理などいろいろ足りていないながらも──)比較的忠実に実装された1970年代の非常に古いSmalltalk-72で遊んでみるシリーズです(なお最新のSmalltalkについては Pharo などでお楽しみください!)。他の記事はこちらから→Smalltalk-72で学ぶOOPの原点 Advent Calendar 2019 - Qiita
(条件分岐式についてもう少しからの続き)
Smalltalk-72のforループ
いわゆるforループは for <変数名> ← <開始値> to <終了値> by <差分> do (<処理>)
のように書きますが、条件分岐が 'if' アクション(オブジェクト)へのメッセージ送信で実現されているのと同様に、もちろん for
アクションへのそれで実現されています。
例によって完全な仕様は ALLDEFS(ブートストラップコード)で for
アクションの定義を読むのが手っ取り早いです。
for
アクションの定義(to for …
)token
step
stop
var
start
exp
という一時変数の宣言- まず、メッセージの最初のトークンを評価せずにそのまま
var
に取り込む(:☞var.
) - 続くメッセージで
←
がマッチしたら、メッセージの続きを式として評価してstart
に取り込む(∢← ⇒ (:start.)
) - そうでなければ、
start
の値は 1 に(☞start ← 1
) - 続くメッセージで
to
がマッチしたら、メッセージの続きを式として評価してstop
に取り込む(∢to ⇒ (:stop.)
) - そうでなければ、
stop
の値はstart
と同じ値に(☞stop ← start.
) - 続くメッセージで
by
がマッチしたら、メッセージの続きを式として評価してstep
に取り込む(∢by ⇒ (:step.)
) - そうでなければ、
step
の値は 1 に(☞step ← 1.
) - 続くメッセージで
do
がマッチしたら、その参照をexp
に取り込みプリミティブCODE 24
をコール(∢do ⇒ (:#exp. CODE 24)
)
差分はもちろん、初期値も終了値すらも省略可能である仕組みがよく分かって面白いですね。なお、プリミティブ CODE 24
は、一時変数を取り込んで実質的なforループ処理を実行します。コメントにもあるように後述のdone
(中断して抜ける)やagain
(中断して次の回の処理を実行)も使えます。
その他のループ
forループの他にも、単純なループのrepeat
(停止するときは esc
キーを押す)や
今のSmalltalkのtimesRepeat:
、Rubyのtimes
にあたるdo
もあります。ただし、今のSmalltalkやRubyが整数にメッセージを送る(体になっている──)のに対し、Smalltalk-72ではdo
自身がループ回数を表す整数を含めたメッセージの受け手になっていて、結果、記述順が異なるので要注意です。
done
とagain
done
はループを中断して抜けるアクションです。with <値>
で、ループを抜けたときの返値を指定することもできます。
again
はRubyでいうところの(redo
ではなく)next
の役割を持つアクションのようです。
(文字列操作…の前にクラス定義についてに続く)
Smalltalk-72で学ぶOOPの原点:条件分岐式についてもう少し
アラン・ケイの“オブジェクト指向”というアイデアをもとに(非同期処理などいろいろ足りていないながらも──)比較的忠実に実装された1970年代の非常に古いSmalltalk-72で遊んでみるシリーズです(なお最新のSmalltalkについては Pharo などでお楽しみください!)。他の記事はこちらから→Smalltalk-72で学ぶOOPの原点 Advent Calendar 2019 - Qiita
(配列要素の参照と要素の代入の実装からの続き)
Smalltalk-72の条件分岐式
第三世代目のSmalltalkであるSmalltalk-80以降(今のSmalltalkを含め)では、条件分岐もメッセージ式で表現することが比較的よく知られています。次の式は、今のSmalltalkで、「3 < 4 ならば 5 を、そうでなければ 6 を返す」という式です。
3 < 4 ifTrue: [5] ifFalse: [6]
3
に < 4
というメッセージを送った結果の true
に対して ifTrue: [5] ifFalse: [6]
というメッセージが送られる(と解釈する)ことで条件分岐を表現しています。
一方で、Smalltalk-72は制御構造としての条件分岐式 ⇒()
を用意しています。通常のメッセージと同様にトークンに分解されメッセージの一部となりますが、レシーバーが解釈する前に処理系によっていわば予約語として特別扱いされ処理されます。
3 < 4 ⇒ (5) 6
ALGOLライクなif-then-elseの実装
Smalltalk-72の条件分岐式に関連して、ブートストラップコードであるALLDEFSを読んでいるとこんな定義が登場します。
コメントにもあるようにこれはALGOLライクな、つまり、通常の言語の条件分岐式とよく似た記法を、その意味するところは冒頭の if
というアクション(オブジェクト)に対して、偽・非偽値(を返す式)、then
、非偽時の処理、else
、偽時の処理 といったもろもろの必要な情報をすべてメッセージとして送りつけることにより記述可能にするという実に驚きのアプローチです。
定義を細かく見てみましょう。
to
は「クラス」もしくはインスタンス生成能を持たないクラスである「アクション」を定義するためのオブジェクト(これ自体もアクション)です。ここでは if
というアクションを定義していて、続く exp
はこのアクション内で用いられる一時変数の宣言です。その先に続く括弧内のがメソッド(つまり、if
に送られてきたメッセージにどう対処するかを記述したコード)で次のような手続きが記述されています。
- メッセージの冒頭からのトークン列を式とみなして評価し結果を
exp
に代入し、その値がもし非偽ならば…(:exp⇒(
)★ - 続くトークンが
then
にマッチしたらあらためて続くトークン列を式として評価して結果をexp
に代入(∢then⇒(:exp.
)☆ - 続くトークンが
else
にマッチしたら続きからトークンをひとつ、評価せずに消費(:☞.
)。マッチしてもしなくてもexp
を返す。(つまり、else節は省略可) - ☆でなければ
then
が無い旨をエラー。(error ☞(no then)
) - ★でなければ、続くトークンが
then
にマッチしたら続きからトークンをひとつ、評価せずに消費(∢then⇒(:☞.
)。▲ - 続くトークンが
else
にマッチしたら続くトークン列を式として評価して結果をexp
に代入して返す(∢else⇒(:exp)
)。△ - △でなければ
false
を返す。 - ▲でなければ、
then
が無い旨をエラー(error ☞(no then)
)。
ためしに if 3 < 4 then 5 else 6
を評価してみましょう。
たしかに動きますね。ただし、この定義だと偽値時に実行されない then節、あるいは、非偽値時に実行されない else節が式の場合、括弧でくくらないとうまく処理できなさそうです。実際に試すとたしかにエラーになります。
then節、else節にリテラルをひとつだけ書くのでなければ括弧でくくる運用が必要そうです。
ちなみに、トークンを評価せずに取り込む :☞
は初出ですが、ALLDEFSの :
アクションの定義( to : …
)に擬似コードがありますので参照してください。
Smalltalk-72の条件分岐式の落とし穴
<偽値・非偽値> ⇒( <非偽時処理> ) <偽時処理>
のうち、括弧でくくられる非偽時処理だけでなく、偽時処理にも複数の式を書くことが出来ます。従って、条件分岐の後にもコードを続けるときには、この条件式全体を括弧でくくらないと、期待した動作にはならないので要注意です。
3 < 4 ⇒(5 print) 6 print. 7 print. '=> 7 は出力されない(偽時処理に含まれるため)'
(3 < 4 ⇒(5 print) 6 print.) 7 print. '=> 7 も出力される' (3 > 4 ⇒(5 print) 6 print.) 7 print. '=> 7 も出力される'
(条件分岐以外の制御構造に続く)
Smalltalk-72で学ぶOOPの原点:配列要素の参照と要素の代入の実装
アラン・ケイの“オブジェクト指向”というアイデアをもとに(非同期処理などいろいろ足りていないながらも──)比較的忠実に実装された1970年代の非常に古いSmalltalk-72で遊んでみるシリーズです(なお最新のSmalltalkについては Pharo などでお楽しみください!)。他の記事はこちらから→Smalltalk-72で学ぶOOPの原点 Advent Calendar 2019 - Qiita
(配列要素の参照と要素の代入からの続き)
ALLDEFSであらかじめ用意されたクラスの定義を調べる
では配列要素の参照と要素の代入を例に、Smalltalk-72において、(今のSmalltalkを含む)その後のOOPLで一般的になった「メッセージの一部(セレクタ-)と同じ名前のメンバー関数を動的にコール(…することを「メッセージング」と称する)」とは違ったどんなアプローチで実装されているかを見てみましょう。
「ALTO Smalltalk-72」ウインドウの右側に並んでいるボタンの中にある「ALLDEFS」を押すと、Smalltalk-72が起動時に読み込むブートストラップコードを読むことができます。
低レベルのクラスのコードはプリミティブ(処理系組み込みの始原関数)のコールの実装だけの場合もありますが、その場合でも直後のコメントとして擬似コードが添えられているのでどんな処理をしているのか程度の雰囲気はわかります。
配列のクラスを調べて実装を探す
オブジェクトのクラスは is? というメッセージを送ることで調べることができます。「?」は「?」キーそのままではなく、 KeyboradHelp にあるように「~」(チルダ)をタイプする必要があるので注意してください。do-it (「\」キー。グリフは「!」)で評価すると vector であることがわかります。
vector クラスは ALLDEFS では「to vector …」で始まる式で定義されています。起動フェーズごとに2回定義されていますが、2回目の定義を見てみましょう。
クラス定義式についての細かなことの説明がまだですが、変数の宣言を終えたあと「 (CODE 3 … 」とあるので、まず、プリミティブ CODE 3 を呼ぶ手続きになっていることはだいたいわかるかと思います。この CODE 3 のおおよその内容は他のプリミティブと同様に直後のコメント(「'」(シングルクオート)で括られている部分。実際は文字列リテラル。つまり文字列をコメント代わりにする運用らしい)に擬似コードで示されています(図の赤い部分)。この中の黄色で囲った部分が今知りたい配列要素の参照と要素代入の実装を端的に表した擬似コードです。
目玉マーク(∢)と条件分岐(⇒())、そして、評価して取り込み(:)
目が慣れないと何が書いてあるのかさっぱりですが、メッセージとして送られたトークン列を見るパターンマッチ式である「∢<マッチさせるトークン>」と、条件分岐「<偽・非偽値>⇒(<非偽時処理>)<偽時処理>」、メッセージの部分を構成する式を評価して値を取り込む「:<取り込む先の変数>」、そして今のSmalltalkと同様に値を返すリターン(ただしグリフは「↑」や「^」ではなく「⇑」)が分かれば、おおよそこの擬似コードが伝えたいことはくみ取れるかと思います。
つまり、読み下すとこんな感じになります。
- 送られてきたメッセージの冒頭で [ がマッチしたら…( ∢[⇒(… )
- 続くメッセージ中の式を評価して結果を一時変数 x に取り込み…( :x. )
- 括弧を閉じるのに使われるはずのトークン ] を消費( ∢] )。
- 残りのメッセージ冒頭で←がマッチしたら…( ∢←⇒(… )★
- 続くメッセージ中の式を評価して結果を一時変数 y に取り込み… ( :y. )
- y を返す( ⇑y )…のと並行して配列の x 番目の要素を y で置き換える。
- ★でなければ、配列の x 番目の要素を返す。
[ ] や [ ]← といった名前のメソッドが定義されていてそれを呼ぶ、Smalltalk-76やRubyのアプローチとはずいぶん違った実装になっていることを(まあ、これはあくまで擬似コードなので実際はもう少し複雑なことをやっていますが雰囲気だけでも)感じ取っていただけますでしょうか?
メッセージを受け取ったオブジェクトがそれを読み解いてゆく様子が(独立した関数などでない、文字通りの──)“メソッド”として、BNF法で文法を記述するように、あるいは、Lispのリーダーマクロに近い感覚で記述されていて面白いですね。同時に、(メッセージングの──)OOPLといっても、“メソッド”と称したメンバー関数の動的呼び出しで実装するだけが唯一のやり方ではないのだよ!ということがよく分かります。
(条件分岐式についてもう少しに続く)
Smalltalk-72で学ぶOOPの原点:配列要素の参照と要素の代入
アラン・ケイの“オブジェクト指向”というアイデアをもとに(非同期処理などいろいろ足りていないながらも──)比較的忠実に実装された1970年代の非常に古いSmalltalk-72で遊んでみるシリーズです(なお最新のSmalltalkについては Pharo などでお楽しみください!)。他の記事はこちらから→Smalltalk-72で学ぶOOPの原点 Advent Calendar 2019 - Qiita
(LivelyWeb版Smalltalk-72についてからの続き)
配列オブジェクトの生成
Smalltalk-72にも今のSmalltalkや他の一般的な言語同様に動的な配列生成式が書けますが、要素がすべてリテラルならリテラル配列式で生成するのが簡単です。今のSmalltalkは #(1 2 3 4) のように括弧の前に「#」を使いますが、Smalltalk-72 では「☞」(右方向指さしマーク)を代わりに用います。入力はKeyboardHelpにもあるように「"(ダブルクオーテーション)」です。評価の際に do-it (グリフは「!」、キーは「\」)の入力をお忘れなく。
今のSmalltalkと同様に、リテラル配列式の場合、変数による参照も含めて式による要素の動的生成はサポートしていない(もっとも、最近のSmalltalkは擬変数「true」「false」「nil」については便宜上例外的にリテラル扱いにしていますが──)ので、要素を生成する式のようなつもりで計算式を混ぜても、式のトークンが要素になるだけなので注意してください。
もし、式を用いて要素を動的に生成したい場合は、今のSmalltalkと同じように { } でくくる、配列の動的生成式を使います。ただし、今のSmalltalkは式の区切り(つまり要素ごと)に、式の区切りである「.」(ピリオド)を、一般的な言語では「,」(カンマ)が必須なのに対し、Smalltalk-72ではこうした式の区切りは無用です。
面白いのは式(要素)の区切りが“不要”(あってもなくてもよい)なのではなく“無用”(あってはいけない)である点です。どこが式(要素)の区切りになるかは、要素を生成する各メッセージ式のレシーバー(メッセージの受け手であるオブジェクト)により動的に判断されます。うっかりいつもの習慣でピリオドやカンマなどを入れてしまうとエラーになるので注意してください。
なお、エラーが出たときにポップアップするサブウインドウ(REPL)は done と入力して評価(「\」をタイプ)すると消すことができ、元のウインドウに復帰できます。
追記:要素を区切りを明示的にするには、{1 (2+3) 4}
のように要素を生成する式ごとに()
で括ってやればよいようです。
変数への代入
変数への代入は、今のSmalltalkやRubyなどのシンボルに似た扱いのアトムへの「← 値」というメッセージ送信で行われます。アトムの生成も配列のリテラル式同様「☞」を使って表現します。代入記号としての「←」はSmalltalk-80やSqueakの初期バージョンと同様に「_」で入力できます。
なお、この図の最初の式のようにREPLで評価する式の最後にピリオドを追加しておけば、評価時に最後の式の値の出力をいちいちしなように抑制することも可能です。ちなみに、次の世代のSmalltalk-76の doIt(今のSmalltalkの print it に相当)もこれと同じ運用になっていましたが、Smalltalk-80以降の今のSmalltalkでは末尾のピリオドの有無にかかわらず最後の式の結果が戻り値(print it なら出力値)になるように変更されています。
配列要素の参照
配列の要素の参照は arr[3] のように記述します。
省コスト版のメッセージング機構を採用した次の世代のSmalltalk-76の arr ◦ 3 や、今のSmalltalkの arr at: 3 とはずいぶんと様子が違って、一般の言語に近い表現になっているのが面白いですね。
配列要素の代入
配列の要素の代入は arr[3] ← 4.56 のように記述します。
こちらも次世代のSmalltalk-76の arr ◦ 3 ← 4.56 や、今のSmalltalkの arr at: 3 put: 4.56 とは違いますね。Rubyの arr[2] = 4.56 とは見た目は似ていますが、しかし、Smalltalk-76では ◦← 、今のSmalltalkでは at:put: 、そしてRubyでは []= というメソッド(ある種の関数)を定義してそれを使っているのに対し、Smalltalk-72では別のアプローチをとっています。
(配列要素の参照と要素の代入の実装へ続く)
Smalltalk-72で学ぶOOPの原点:LivelyWeb版Smalltalk-72について
アラン・ケイの“オブジェクト指向”というアイデアをもとに(非同期処理などいろいろ足りていないながらも──)比較的忠実に実装された1970年代の非常に古いSmalltalk-72で遊んでみるシリーズです(なお最新のSmalltalkについては Pharo などでお楽しみください!)。他の記事はこちらから→Smalltalk-72で学ぶOOPの原点 Advent Calendar 2019 - Qiita
(はじめにからの続き)
ダン・インガルス自らの手による今も使用可能なSmalltalk-72処理系
Lively(あるいはLively Kernel、LivelyWeb)は、XEROX PARC(パロアルト研究所)でSmalltalk-72をはじめとするSmalltalkの古典的実装や移籍後のAppleでSqueakの開発を手がけたダン・インガルスが考案した動的なWebアプリ開発用のフレームワーク&インタラクティブなコラボ開発環境です。Scratchの作者としても知られるジョン・マロニーが、その昔、SELFやSqueak Smalltalkで、従来のMVCに変わる新しい、そしてオブジェクトがもっと活き活きとしたGUIフレームワークとして考案した「Morphic」やそれで構築した環境を、素のWebブラウザ上で動くようにJavaScriptで書き直したようなものだとも言えます。
1970年代の前半、アラン・ケイらの実証実験のため週1回、彼らが持ち込んだパーソナルコンピューター試作機「Alto」を使ってSmalltalk学習をしていた生徒達は、その日の成果をメモリダンプファイルとして保存し、翌週それを再び読み込ませることでまったく同じ状態で作業を再開していたそうです。そのメモリダンプをLively上に構築されたAlto/Novaエミュレーター(Altoは他社製ミニコン「Nova」の互換機+動的な命令セット拡張可能なマシンとして作られました)に読み込ませて動かすことでSmalltalk-72処理系を当時のまま機能させるしくみになっているのがLivelyWeb版のSmalltalk-72です。
- https://lively-web.org/users/Dan/ALTO-Smalltalk-72.html (アクセスできないときは、次の勝手バックアップを使用してください)
- https://lively-web.org/users/sumim/ALTO-Smalltalk-72.tweak2.html
上記リンクにアクセスすると、本稿執筆時点では次図のような画面が表示されます(ただし、LivelyWebは環境の状態をユーザーが自由に変更したり保存したりできるので、アクセスするタイミングによってはこれとは違った状態になっている可能性もあります)。
はじめてのSmalltalk-72
試しにこのSmalltalk-72環境で簡単な式を実行してみましょう。Smalltalk-72にはまだ、後のSmalltalk-76や-80以降のSmalltalk処理系に特徴的なワークスペース(Pharoではプレイグラウンド)に代表されるモードレスなエディタや、そこに入力されたテキストの一部を選択してポップアップメニューから「print it」を選ぶことで自在に式を評価して結果が得られるような先進的な機構は備わっていなかったので、一周回って(?)、通常の言語処理系と似た感覚でREPL(入力・評価・出力のループ。対話型評価機構を指す)が使えます。
操作にあたってまず最初に知っておく必要があるのは、右上の About Smalltalk-72 にも書かれているように、入力したメッセージ式を評価するには do-it と呼ばれる文字を入力しなければならず、それはバックスラッシュ「\」(日本語キーボードでは円マーク「¥」)に割り当てられていることと、右下の Keyboard Help にあるように、この do-it(グリフは「!」)の他にもいくつかのアイコンライクなグリフを持つ特殊な文字の入力ができるようにしておくことです(ただし、未実装だったり、Webブラウザにキーイベントを奪われてしまう関係で、残念ながらその多くは入力できません)。
起動後から特に「About Smalltalk-72」もしくは「KeyboardHelp」といったウインドウのように見えるオブジェクトを操作したり、新しいウインドウを開いたりしていなければそのまま(もし操作してしまっていたら、改めて「ALTO Smalltalk-72」ウインドウ内をクリックしてフォーカスを戻してから)「3 + 4」とタイプして、最後に「\」(日本語キーボードでは「¥」)キーを打ってみてください。
正常に動作していれば行を改めて「7」が表示されるはずです。ちなみに、Altoを模したアイコン(実際には文字)がREPLのプロンプト記号として使われています。
もしどうしても入力ができなかったり「\」キーを押下後エラーのような表示になる場合は、使用中のWebブラウザとのLivelyWebとの相性が悪かったり未対応であったりする可能性があるので、別のWebブラウザで(必要ならインストールしてから)もう一度試してみてください。個人的には Chrome が比較的使い勝手がよさそうに思います。
(配列要素の参照と要素の代入に続く)