Smalltalk-72で遊ぶOOPの原点:簡易スケジューラーを作る

アラン・ケイの“メッセージングによるプログラミング”という着想に基づき(非同期処理などいろいろ足りていないながらも──)比較的忠実に実装された1970年代の非常に古いSmalltalk-72に実際に触れてみるシリーズ 第2弾です(なお最新のSmalltalkについては Pharo などでお楽しみください!)。

今回は謎言語「Smalltalk-71」で書かれたスペースウォー・ゲームSmalltalk-72に移植して動かすことを目指します。前回(2019年)を含む他の記事はこちらから→Smalltalk-72で遊ぶOOPの原点 | Advent Calendar 2023 - Qiita


obset を活用して簡易スケジューラー spacewar を定義

前回の動作チェックで使った repeat の代わりに、新たに spacewar アクションを定義し、これにその役割を担わせることにしましょう。

こんな仕組みと動きを想定します。

  1. objects というセットもどき(obset)をクラス変数として持ち、
  2. spacewar schedule obj で宇宙船や、将来は魚雷などのオブジェクトを objects に追加
  3. spacewar delete obj で指定したオブジェクト、spacewar delete all で全てのオブジェクトのスケジュールを放棄
  4. spacewar runobjects 内のオブジェクトに順に制御を渡す

クラス変数 objects に代入される obset は、ALLDEFS(ブートストラップ)で定義されている、要素をユニークなもののみに保つセットの性質も有するシンプルな動的配列オブジェクトです。

☞set ← obset.インスタンスを生成し、set ← elem とすることで、elem がはじめてなら追加、すでに追加済みなら無視します。

obset は、この elem のユニーク性を維持する ← elem だけでなく、無条件で追加する add elem もあるので、こちらを使えば要素の重複を許す通常の動的配列としても使えます。

ただし、動的“配列”とはいうものの、インデックスでのアクセスなど配列の基本的な機能はいっさい用意されていないので、そういう用途には vec で内部表現のベクター vectorインスタンスを引っ張り出して使うという割り切った仕様になっています。

前述のとおり、ALLDEFSウインドウ、もしくは show obset でその定義を見ることができます。

後の Smalltalk-80 で導入される do:Rubyeach に相当する map も素朴な実装ながら備えられています。

www.evernote.com

ところで、組み込みの配列 vector にも map はあるにはあるのですが、この obsetmap とは違って、各要素に map の引数となる配列内に収めたシンボルをメッセージとして送るだけという別の仕様になっています。こちらは、Smalltalkdo:Rubyeach でブロックの代わりにシンボルを与えたときの使い方に似ています。同じ map でもぶれがある雑さがいいですね^^;

spacewarアクションはこんなふうに定義してみました。

to spacewar x y z : : objects (
    (null objects ? ("objects _ obset))
    %schedule ? (objects _ :#)
    %delete ? (%all ? ("objects _ nil) objects delete :#)
    %run ? (repeat (objects map "("x _ vec[i]. x)))
)

disp clear
"s1 _ spaceship 'Jimmy' 5 30 false.
"s2 _ spaceship 'Beth' `5 `20 false.
spacewar schedule s1. spacewar schedule s2.
spacewar run

前回同様に2艇の宇宙船 s1 s2 を定義して schedule 後、run してみましょう。

escキーで停止できます。

組み込みコレクションにeach変数が使える「do」を新たに追加する へ続く )