Self

歴史

1986年、パロアルト研究所で働いていたDavid UngarとRandall SmithがSelfを設計した。Smalltalk-80が一般にリリースされて産業界から真剣に受け止められ始めていることから、オブジェクト指向プログラミング言語の研究をさらに進めることを目的として行われた。彼らはスタンフォード大学に移り、Selfの作業を進め、1987年に最初のコンパイラを完成させた。そして、言語だけではなくSelfのシステム全体を構築することに注力することになった。
一般への最初のリリースは1990年であり、翌年には彼らチームはサン・マイクロシステムズに移り、さらに Selfに関する作業を続けた。その後、何回かのリリースが行われ、1995年のバージョン 4.0リリースで長い活動休止状態に入った。最近のバージョン 4.2は2004年にリリースされ、Mac OS XとSolaris上で動作した。
Selfはいくつかの言語に概念的な影響を与えた。特筆すべきものとしては、アップル・ニュートンのNewtonScriptと、動的ウェブページ構築に使われるJavaScriptがある。他に、Io言語、Cel言語、Agoraなどがある。

言語としての記述

Self のオブジェクトは「スロット」の集まりである。スロットとは、値を返すメッセージであり、スロット名の後にコロンをつければ値をセットするメッセージになる。例えば、"name" というスロットがあるとする。
   myPerson name
これは name の値を返す。
   myPerson name:'gizifa'
これは値をセットする。
Self は Smalltalk と同様「ブロック」を使って処理の流れを制御する。メッセージを受け取るメソッドはスロット群以外にコードを持つオブジェクトであり、任意のスロットの値としてメソッドを格納できる。メソッドの持つスロットは引数や一時変数として使われる。いずれの場合も文法的には同じである。
Self ではフィールドとメソッドに区別はなく、どちらもスロットである。メッセージによるスロットアクセスで Self の文法の大部分が説明されるため、自分自身（self）へのメッセージも多い。そのため "self" は省略できる（また、これが言語名の由来）。

新しいオブジェクトの生成

もう少し複雑な例として次の記述を示す:
   labelWidget copy label: 'Hello, World!'.
"labelWidget" オブジェクトへの copy メッセージでコピーを作り、そのコピーの "label" スロットに "Hello, World" メッセージを格納すべくメッセージを送っている。これを使ってみると次のようになる。
   (desktop activeWindow) draw: (labelWidget copy label: 'Hello, World!').
この場合、(desktop activeWindow) が最初に評価され、desktop オブジェクトが知っているウィンドウのリストからアクティブウィンドウを表すオブジェクトが返される。次に（内側から外側へ、左から右へという順で）前掲のコードが評価され labelWidget が返される。最後にそのウィジェットがアクティブウィンドウの draw スロットに送られる。

継承/委譲

理論上、全ての Self オブジェクトはスタンドアロンな実体である。Self にはクラスもメタクラスもない。あるオブジェクトを変更しても他には影響がないが、影響があったほうがよい場合もある。通常、オブジェクトは自身のローカルなスロットへのメッセージしか認識しないが、「親」オブジェクトを指定するスロットを持つことによって、そのオブジェクト自身が解釈できないメッセージを親オブジェクトに委譲することができる。スロット名の後ろにアスタリスクがあるものは親へのポインタとなる。このような手法で、クラスベースの言語で継承機能が担っていることを実現する。委譲によって名前空間やスコープといった機能も実装できる。

特徴

例えば、「銀行口座」というオブジェクトを定義し、口座の残高を管理するとしよう。一般にこのようなオブジェクトには「入金」と「出金」のメソッドが作られ、それに必要なデータスロットも作られる。これはプロトタイプであるが、そのまま汎用の口座を表すオブジェクトとしても使える。
このオブジェクトのクローン「ボブの口座」を作ることで、上記オブジェクトがプロトタイプとして使われたことになる。このとき、そのオブジェクトが持つ全てのメソッドやデータがスロットとしてコピーされる。しかし、より典型的な手法は、もっと単純な traits object（特徴オブジェクト）と呼ばれるオブジェクトをつくり、そこにクラスに関連するものを含める。
この例では、「銀行口座」オブジェクトに入金や出金メソッドを備えさせるのではなく、その親オブジェクトに持たせる。このようにすると、多数の銀行口座オブジェクトのコピーを作っても、親オブジェクトの修正によって全銀行口座オブジェクトの動作を更新できる。
これはいわゆるクラスと何が違うのだろうか？ 次の意味を考えてみよう:
   myObject parent: someOtherObject.
これは、'parent*' スロットに適当なオブジェクトを代入することで myObject の「クラス」を実行時に動的に変更できることを意味する（アスタリスクはスロット名の一部だが、メッセージには表記されない）。継承やスコープとは違い、委譲オブジェクトは実行時に変更可能である。

スロット追加

Self のオブジェクトにはスロットを追加可能である。グラフィカルなプログラミング環境でもできるし、'_AddSlots:' プリミティブでも可能である。プリミティブは通常のキーワードメッセージと同様の構文だが、その名前は常にアンダースコアで始まる。＿AddSlots プリミティブ自身は古い実装の名残りであるため、使うべきでないとされている。しかし、これを使うとコードを短縮できるため、以下ではあえて解説する。
Vehicle という単純なクラスのリファクタリングで乗用車とトラックで振る舞いを変えることを上の例で示した。Self ではこれを次のように実現できる:
   _AddSlots: (| vehicle <- (|parent* = traits clonable|) |).
'_AddSlots' プリミティブの受信者オブジェクトが明示されていないので、これは "self" に対するものである。これを対話型のプロンプトで入力すると、"self" オブジェクトに相当するのは "lobby" と呼ばれるオブジェクトである。'_AddSlots' の引数はオブジェクトであり、そのスロットが受信者オブジェクトにコピーされる。この例では、それは1つのスロットだけを持つリテラルオブジェクトである。スロット名は 'vehicle' で、その値が別のリテラルオブジェクトとなっている。"<-" という記号は、第一のスロットの値を変更するのに使われる 'vehicle:' という第二のスロットを暗に示している。
"=" は定数スロットを意味するので、'parent*' には対応する 'parent:' が無い。このリテラルオブジェクトは 'vehicle' の初期値であり、クローン作成に関するメッセージを理解できるスロットを1つもっている。完全に空のオブジェクトは、(| |) あるいは単に () で示され、メッセージを全く受け付けられない。
    vehicle _AddSlots: (| name <- 'automobile'|).
これも、前と同じオブジェクトが受信者であり、'parent*' に加えて新たに 'name' と 'name:' スロットが追加されている。
   _AddSlots: (| sportsCar <- vehicle copy |).
   sportsCar _AddSlots: (| driveToWork = (何かのコード、これがメソッドになる) |).
以前の 'vehicle' と 'sportsCar' はほとんど同じだが、ここでは後者にオリジナルが持っていなかったメソッドを伴うスロットが含まれている。メソッドを持つことができるスロットは定数スロットだけである。
   _AddSlots: (| porsche911 <- sportsCar copy |).
   porsche911 name:'Bobs Porsche'.
新たなオブジェクト 'porsche911' は 'sportsCar' とほぼ同じだが、最後のメッセージでその 'name' スロットの値が変更されている。これらはスロットの値は異なるものの、持っているスロットは同じであることに注意されたい。

環境

Self の特徴の1つとして、Smalltalk システムが使っていた仮想機械と同様の仕組みに基づいている点が挙げられる。つまり、Self のプログラムはC言語などとは異なり、それ単独では機能しない。常に実行環境が必要となる。しかし、このようになっているため、Self 環境は強力なデバッグツールを提供できる。プログラムを任意の時点で停止させ、コードや値を変更し、実行を再開させるといったことが可能である。
さらに、Self 環境はオブジェクトを素早くかつ継続的に変更することを考慮している。「クラス」設計のリファクタリングは、単に既存のメソッドを新しいオブジェクトに引っ張ってくればよいだけである。メソッドの評価のような単純な作業は、コピーを作って、メソッドをコピーに引っ張ってきて、そこで修正すればよい。他のシステムとは異なり、その新たなオブジェクトだけが新しいコードを持っており、テストするにも他に影響が発生しない。そのメソッドがうまく動いたら、それを元のオブジェクトに戻せばよい。

性能

Self の VM（仮想機械）は C言語と比較して（一部のベンチマークで）約半分程度の性能を達成している。
これはジャストインタイムコンパイル(JIT)方式によるもので、特に研究が進んでいる部分である。特に、起動当初はインタプリタとして実行し、よく送信されるメッセージや繰り返し実行されるコードの検出（プロファイリング）を行い、そのようなコードのみをコンパイルするadaptive compilationという技術は最初Selfの処理系で実装され、後にJavaのHotSpotで採用された。

ガベージコレクション

Self のガベージコレクションは世代型であり、オブジェクトを世代で管理する。メモリ管理システムを使ってページへの書き込みを記録し、ライトバリアを保つ。この手法は性能がよいが、ある期間実行を行っていると全体ガベージコレクションが発生し、無視できない時間を取られてしまう。

最適化

実行時環境は選択的に呼び出し構造を平坦化することで性能向上を図っている。そのためには、型情報や異なる型に応じた複数の実行コードをキャッシュしておく必要があるが、時間の掛かるメソッド探索の回数を減らしたり、メソッド探索を条件分岐やハードコードされた呼出しで置き換えたりすることができる。これにより言語としての一般性を保ち、ガベージコレクションを備えつつ、C言語に近い性能が達成されているのである。