自己ロゴ | |
| パラダイム | オブジェクト指向(プロトタイプベース) |
|---|---|
| 家族 | 雑談 |
| デザイン: | デビッド・ウンガー、ランドール・スミス |
| 開発者 | デビッド・ウンガー、ランドール・スミス、 スタンフォード大学、 サン・マイクロシステムズ |
| 初登場 | 1987年 |
| 安定リリース | マンダリン 2017.1 / 2017年5月24日 |
| タイピングの規律 | ダイナミック、強い |
| OS | クロスプラットフォーム: Unixライク、macOS、Windows |
| ライセンス | BSDのような |
| Webサイト | 自己言語 |
| 主な実装 | |
| 自己 | |
| 影響を受けた | |
| Smalltalk、APL [1] | |
| 影響を受けた | |
| NewtonScript、JavaScript、Io、Agora、Squeak、Lua、Factor、Rebol | |
Self は、プロトタイプの概念に基づいた、汎用性の高いオブジェクト指向プログラミング言語です。Self はSmalltalkの方言として始まり、動的型付けと、オブジェクトに対するプロトタイプベースのアプローチによるジャストインタイムコンパイル(JIT) を採用しています。1980 年代と 1990 年代に、言語設計の実験的なテストシステムとして初めて使用されました。2006 年、Self は、完全に Self で記述された Self 仮想マシンである Klein プロジェクトの一部としてまだ開発中でした。最新バージョンの 2017.1 は、2017 年 5 月にリリースされました。[2]
非常に高度なオブジェクト指向言語を最適化されたCの半分以下の速度で実行できるようにするには、いくつかのジャストインタイム コンパイル手法が Self 研究で開発され、改良されました。Selfの開発の多くはSun Microsystemsで行われ、そこで開発された手法は後にJavaのHotSpot 仮想マシンに導入されました。
ある時点で、SmalltalkのバージョンがSelfに実装されました。JITを使用できたため、これも非常に優れたパフォーマンスを発揮しました。[3]
歴史
Self は、1986 年にXerox PARCで働いていたDavid Ungarと Randall Smithによって主に設計されました。彼らの目的は、 Smalltalk -80 が研究所からリリースされ、業界で真剣に受け止められるようになった後、オブジェクト指向プログラミング言語研究の最先端を前進させることでした。彼らはスタンフォード大学に移り、言語の研究を続け、1987 年に最初の実用的な Self コンパイラを構築しました。その後、焦点は言語だけでなく、Self の完全なシステムを構築する作業に移りました。
最初の公開リリースは1990年で、翌年チームはサン・マイクロシステムズに移り、そこで言語の開発を続けた。その後もいくつかの新リリースが続いたが、1995年のバージョン4.0でほぼ休止状態となった。2006年にバージョン4.3がMac OS XとSolaris向けにリリースされた。2010年には、オリジナルチームの一部と独立したプログラマーで構成されるグループによって、新しいリリースのバージョン4.4 [4]がMac OS XとLinux向けに開発され、以降のすべてのバージョンも同様に開発されている。2014年1月にはフォローアップのバージョン4.5がリリースされ[5]、3年後のバージョン2017.1が2017年5月にリリースされた。
Morphicユーザーインターフェース構築環境は、もともとRandy SmithとJohn MaloneyによってSelfプログラミング言語用に開発されました。[6] Morphicは、 Squeak、JavaScript、Python、Objective-Cなどの他の著名なプログラミング言語にも移植されています。
Self は、そのコンセプトに基づいた多くの言語にも影響を与えました。最も有名なのは、おそらくApple Newton用のNewtonScriptと、すべての最新ブラウザで使用されているJavaScriptでしょう。その他の例としては、Io、 Lisaac 、Agora などがあります。1990 年に開発された IBM Tivoli Framework の分散オブジェクト システムは、最も低いレベルでは、Self に触発されたプロトタイプ ベースのオブジェクト システムでした。
プロトタイプベースのプログラミング言語
従来のクラスベースの OO 言語は、根深い二重性に基づいています。
- クラスはオブジェクトの基本的な特性と動作を定義します。
- オブジェクト インスタンスは、クラスの特定の表現です。
たとえば、クラスのオブジェクトに名前Vehicleがあり、車で職場まで行ったり、建設資材を配達するなど、さまざまなアクションを実行する機能があるとします。は、クラス の特定のオブジェクト (インスタンス) で、「Bob's car」という名前が付けられています。 理論的には、 にメッセージを送信して、建設資材を配達するように指示することができます。
Bob's carVehicleBob's car
この例は、このアプローチの問題点の 1 つを示しています。ボブの車はたまたまスポーツカーですが、建設資材を運搬したり配達したりすることはできません (意味のある意味で)。しかし、これは が持つようにモデル化されている機能です。 のサブクラス化を使用しての特殊化を作成するVehicleことで、より便利なモデルが作成されます。たとえば、と です。 クラスのオブジェクトだけが建設資材を配達するメカニズムを提供する必要があります。その種の作業には適さないスポーツカーは、を高速で運転するだけで済みます。ただし、このより深いモデルには、設計中にさらに多くの洞察が必要であり、問題が発生したときにのみ明らかになる洞察です。
VehicleSports CarFlatbed TruckFlatbed Truck
この問題は、プロトタイプの背後にある動機付け要因の 1 つです。遠い将来にオブジェクトとクラスのセットがどのような品質を持つかを確実に予測できない限り、クラス階層を適切に設計することはできません。多くの場合、プログラムには最終的に追加の動作が必要になり、システムの一部を再設計 (またはリファクタリング) して、オブジェクトを別の方法で分離する必要があります。[引用が必要] Smalltalkなどの初期の OO 言語の経験から、この種の問題が何度も発生することがわかりました。システムは、ある程度まで成長すると、その後非常に硬直的になり、プログラマーのコードの奥深くにある基本クラスが単純に「間違っている」ものになる傾向があります。元のクラスを簡単に変更する方法がなければ、深刻な問題が発生する可能性があります。[引用が必要]
Smalltalk などの動的言語では、クラスのよく知られたメソッドを介してこの種の変更が可能でした。つまり、クラスを変更すると、そのクラスに基づくオブジェクトの動作が変更されます。ただし、同じクラスに基づく他のオブジェクトがこの「間違った」動作を予期している可能性があるため、このような変更は非常に慎重に行う必要がありました。「間違った」動作は多くの場合、コンテキストに依存します。(これは、脆弱な基本クラスの問題の一形態です。) さらに、サブクラスをスーパークラスとは別にコンパイルできるC++などの言語では、スーパークラスを変更すると、プリコンパイルされたサブクラスのメソッドが実際に壊れる可能性があります。(これは、脆弱な基本クラスの問題の一形態であり、脆弱なバイナリ インターフェイスの問題の一形態でもあります。)
Self やその他のプロトタイプベースの言語では、クラスとオブジェクト インスタンス間の二重性は排除されます。
Self では、何らかの「クラス」に基づいたオブジェクトの「インスタンス」を持つ代わりに、既存のオブジェクトのコピーを作成し、それを変更します。Bob's car既存の「車両」オブジェクトのコピーを作成し、ドライブ ファストメソッドを追加して、それがたまたまポルシェ 911であるという事実をモデル化することで、これが作成されます。主にコピーを作成するために使用される基本オブジェクトは、プロトタイプと呼ばれます。この手法は、ダイナミズムを大幅に簡素化するとされています。既存のオブジェクト (またはオブジェクトのセット) が不適切なモデルであることが判明した場合、プログラマーは、正しい動作を持つ変更されたオブジェクトを作成し、代わりにそれを使用できます。既存のオブジェクトを使用するコードは変更されません。
説明
Self オブジェクトは「スロット」の集合です。スロットは値を返すアクセサ メソッドであり、スロット名の後にコロンを置くと値が設定されます。たとえば、「name」というスロットの場合、
私の 名前
名前の値を返し、
myPerson 名: 'foo'
設定します。
Self は Smalltalk と同様に、フロー制御やその他の機能にブロックを使用します。メソッドは、スロット (引数や一時的な値に使用) に加えてコードを含むオブジェクトであり、他のオブジェクト (たとえば数値) と同様に Self スロットに配置できます。どちらの場合も構文は同じです。
Self ではフィールドとメソッドの区別がなく、すべてがスロットであることに注意してください。Self では、メッセージを介してスロットにアクセスすることが構文の大部分を占めるため、多くのメッセージは「self」に送信され、「self」は省略できます (これが名前の由来です)。
基本的な構文
スロットにアクセスするための構文は Smalltalk の構文に似ています。3 種類のメッセージが利用可能です:
- 単項
receiver slot_name- バイナリ
receiver + argument- キーワード
receiver keyword: arg1 With: arg2
すべてのメッセージは結果を返すため、レシーバー (存在する場合) と引数は、それ自体が他のメッセージの結果になることがあります。メッセージの後にピリオドが続くと、Self は返された値を破棄します。例:
「Hello, World!」 を印刷します。
これは、「Hello, World!」プログラムの Self バージョンです。'構文はリテラル文字列オブジェクトを示します。その他のリテラルには、数値、ブロック、および一般的なオブジェクトが含まれます。
括弧を使用してグループ化を強制できます。明示的なグループ化がない場合、単項メッセージの優先順位が最も高く、次に二項メッセージ (左から右にグループ化)、キーワードの優先順位が最も低くなります。割り当てにキーワードを使用すると、式にキーワード メッセージも含まれる場合に余分な括弧が必要になるため、これを回避するには、Self でキーワード メッセージ セレクタの最初の部分が小文字で始まり、後続の部分が大文字で始まるようにする必要があります。
有効: ベース ボトム
と、 リガチャ ボトム + 高さの間
、および、 ベース トップ / スケール 係数。
明確に解析でき、次のものと同じ意味になります。
有効: ((ベース ボトム)
から((合字 ボトム) + 高さ)
まで、かつ: ((ベース トップ) / (スケール 係数)))まで。
Smalltalk-80 では、同じ式は次のように記述されます。
有効 範囲: 自己 ベース ボトム
、 自己 リガチャ ボトム + 自己 高さ
、および 自己 ベース トップ / 自己 スケール 係数。
base、、ligatureはのインスタンス変数ではなく、実際にはメソッドである
heightと仮定します。scaleself
新しいオブジェクトの作成
もう少し複雑な例を考えてみましょう。
labelWidget コピー ラベル: 'Hello, World!' 。
コピー メッセージを使用して "labelWidget" オブジェクトのコピーを作成し (今回はショートカットなし)、"Hello, World" を "label" というスロットに配置するメッセージを送信します。次に、これを使用して何かを実行します。
(デスクトップの アクティブウィンドウ)描画: ( labelWidget コピー ラベル: 'Hello, World!' ) 。
この場合(desktop activeWindow)、最初に が実行され、デスクトップ オブジェクトが認識しているウィンドウのリストからアクティブ ウィンドウが返されます。次に (内側から外側、左から右に読んでください)、先ほど調べたコードが labelWidget を返します。最後に、ウィジェットがアクティブ ウィンドウの描画スロットに送信されます。
委任
理論上、すべての Self オブジェクトはスタンドアロン エンティティです。Self にはクラスもメタクラスもありません。特定のオブジェクトを変更しても他のオブジェクトには影響しませんが、影響することが望ましい場合もあります。通常、オブジェクトはローカル スロットに対応するメッセージのみを理解できますが、親オブジェクトを示す 1 つ以上のスロットを持つことで、オブジェクトは自身が理解できないメッセージを親オブジェクトに委任できます。アスタリスクをサフィックスとして追加することで、どのスロットも親ポインターにすることができます。このようにして、Self はクラス ベースの言語で継承を使用するような役割を処理します。委任は、名前空間やレキシカル スコープなどの機能を実装するためにも使用できます。
たとえば、単純な簿記アプリケーションで使用される「銀行口座」というオブジェクトが定義されているとします。通常、このオブジェクトは、内部のメソッド (おそらく「入金」や「引き出し」) と、それらに必要なデータ スロットを使用して作成されます。これはプロトタイプであり、完全に機能する銀行口座でもあるため、使用方法だけが特別です。
特性
「ボブのアカウント」のこのオブジェクトのクローンを作成すると、プロトタイプとまったく同じ新しいオブジェクトが作成されます。この場合、メソッドとデータを含むスロットをコピーしました。ただし、より一般的な解決策は、通常クラスに関連付けられる項目を含む 特性オブジェクトと呼ばれるより単純なオブジェクトを最初に作成することです。
この例では、「銀行口座」オブジェクトには入金と引き出しのメソッドはありませんが、親としてそれらのメソッドを持つオブジェクトがあります。このようにして、銀行口座オブジェクトのコピーを多数作成できますが、ルート オブジェクトのスロットを変更することで、それらすべての動作を変更できます。
これは従来のクラスとどう違うのでしょうか? 次の意味を考えてみましょう:
myObject の 親: someOtherObject 。
この抜粋では、'parent*' スロットに関連付けられた値を変更することで、実行時に myObject の「クラス」を変更します (アスタリスクはスロット名の一部ですが、対応するメッセージではありません)。継承やレキシカル スコープとは異なり、デリゲート オブジェクトは実行時に変更できます。
スロットの追加
Self 内のオブジェクトは、追加のスロットを含むように変更できます。これは、グラフィカル プログラミング環境を使用するか、プリミティブ '_AddSlots:' を使用して行うことができます。プリミティブの構文は通常のキーワード メッセージと同じですが、名前はアンダースコア文字で始まります。_AddSlots プリミティブは、初期の実装から残っているため、使用しないでください。ただし、コードが短くなるため、以下の例で示します。
以前の例では、自動車とトラックの動作を区別できるように、Vehicle という単純なクラスをリファクタリングしました。Self では、次のようにしてこれを実現します。
_ AddSlots: ( | 車両 <- ( |親* = 特性 のクローン可能| ) | ) .
'_AddSlots:' プリミティブのレシーバーは示されていないため、"self" になります。プロンプトで入力された式の場合、これは "lobby" と呼ばれるオブジェクトです。'_AddSlots:' の引数は、スロットがレシーバーにコピーされるオブジェクトです。この場合、これは 1 つのスロットだけを持つリテラル オブジェクトです。スロットの名前は 'vehicle' で、その値は別のリテラル オブジェクトです。"<-" 表記は、最初のスロットの値を変更するために使用できる 'vehicle:' と呼ばれる 2 番目のスロットを意味します。
「=」は定数スロットを示すため、対応する「parent:」はありません。「vehicle」の初期値であるリテラル オブジェクトには、クローン作成に関連するメッセージを理解できるように 1 つのスロットが含まれています。(| |) または単に () として示される完全に空のオブジェクトは、メッセージをまったく受信できません。
車両 _AddSlots : ( | name <- '自動車' | ) .
ここで、レシーバーは以前のオブジェクトであり、これには「parent*」に加えて「name」および「name:」スロットが含まれます。
_ AddSlots: ( | sportsCar <- 車両の コピー | ) .
sportsCar _ AddSlots: ( | driveToWork = ( ''いくつかの コード、 これは メソッドです' ' ) | ) .
以前は「vehicle」と「sportsCar」はまったく同じでしたが、後者には元のものにはないメソッドを持つ新しいスロットが含まれるようになりました。メソッドは定数スロットにのみ含めることができます。
_ AddSlots: ( | porsche911 <- sportsCar copy | ) .
porsche911 name: 'Bobs Porsche' .
新しいオブジェクト「porsche911」は「sportsCar」とまったく同じように始まりましたが、最後のメッセージによって「name」スロットの値が変更されました。どちらかの値が異なっていても、両方ともまったく同じスロットを持っていることに注意してください。
環境
Self の特徴の 1 つは、以前の Smalltalk システムで使用されていたのと同じ種類の仮想マシンシステムに基づいていることです。つまり、プログラムはCなどの言語のようにスタンドアロンのエンティティではなく、実行するためにメモリ環境全体を必要とします。このため、アプリケーションはスナップショットまたはイメージと呼ばれる保存されたメモリのチャンクで出荷される必要があります。このアプローチの欠点の 1 つは、イメージが大きく扱いにくい場合があることです。ただし、実行時の状態を検査および変更するのが簡単なため、イメージのデバッグは従来のプログラムのデバッグよりも簡単な場合がよくあります (ソースベースの開発とイメージベースの開発の違いは、クラスベースのプログラミングとプロトタイプのオブジェクト指向プログラミングの違いに似ています)。
さらに、この環境は、システム内のオブジェクトの急速かつ継続的な変更に合わせて調整されています。「クラス」設計のリファクタリングは、既存の祖先からメソッドを新しいものにドラッグするのと同じくらい簡単です。テスト メソッドなどの単純なタスクは、コピーを作成し、メソッドをコピーにドラッグして変更することで処理できます。従来のシステムとは異なり、変更されたオブジェクトにのみ新しいコードがあり、テストのために再構築する必要はありません。メソッドが機能する場合は、祖先にドラッグするだけで済みます。
パフォーマンス
セルフVMは、いくつかのベンチマークで最適化されたCの約半分の速度を達成しました。[7]
これは、高水準言語をこれほど優れたパフォーマンスで実行できるようにするために Self 研究で開発され、改良された ジャストインタイム コンパイル技術によって実現されました。
ガベージコレクション
Self のガベージ コレクターは、オブジェクトを経過時間によって分離する世代別ガベージ コレクションを使用します。メモリ管理システムを使用してページ書き込みを記録することで、書き込みバリアを維持できます。この手法は優れたパフォーマンスを提供しますが、しばらく実行すると完全なガベージ コレクションが発生し、かなりの時間がかかります。[あいまい]
最適化
ランタイムシステムは、呼び出し構造を選択的にフラット化します。これにより、それ自体は適度なスピードアップが得られますが、型情報の広範なキャッシュと、異なる呼び出し元タイプに対する複数のコードバージョンが可能になります。これにより、多くのメソッド検索を行う必要がなくなり、条件分岐ステートメントとハードコードされた呼び出しを挿入できるようになります。これにより、言語レベルでの一般性を失うことなく、完全にガベージコレクションされたシステムで、Cのようなパフォーマンスが得られることがよくあります。[8]
参照
参考文献
- ^ Ungar, David; Smith, Randall B. (2007). 「Self」。プログラミング言語の歴史に関する第3回ACM SIGPLAN会議の議事録。doi : 10.1145 / 1238844.1238853。ISBN 9781595937667. S2CID 220937663。
- ^ “Self "Mandarin" 2017.1”. 2017年5月24日. 2017年5月24日時点のオリジナルよりアーカイブ。 2017年5月24日閲覧。
- ^ Wolczko, Mario (1996)。selfには以下が含まれます: Smalltalk。プロトタイプベース言語に関するワークショップ、ECOOP '96。リンツ、オーストリア。
- ^ “Self 4.4 リリース”. 2010年7月16日. 2017年12月5日時点のオリジナルよりアーカイブ。 2017年5月24日閲覧。
- ^ “Self Mallard (4.5.0) リリース”. 2014年1月12日. 2017年12月6日時点のオリジナルよりアーカイブ。 2017年5月24日閲覧。
- ^ マロニー、ジョン H.、スミス、ランドール B. (1995)。「モーフィック ユーザー インターフェイス構築環境における直接性とライブ性」。ユーザーインターフェイスとソフトウェア テクノロジーに関する第 8 回 ACM シンポジウムの議事録。pp. 21–28。doi :10.1145/ 215585.215636。ISBN 089791709X. S2CID 14479674 . 2020年3月24日閲覧。
- ^ Agesen, Ole (1997 年 3 月)。「Java Just-In-Time Translator である Pep の設計と実装」。オブジェクト システムの理論と実践。3 (2): 127–155。doi : 10.1002 /(SICI)1096-9942(1997) 3 :2<127::AID-TAPO4>3.0.CO;2-S。2006 年 11 月 24 日時点のオリジナルからアーカイブ。
- ^ Chambers, Craig (1992 年 3 月 13 日)。オブジェクト指向プログラミング言語の最適化コンパイラである SELF コンパイラの設計と実装(PDF) (博士論文)。スタンフォード大学。
さらに読む
- 自己に関する論文を発表
- Chambers, C. (1992)、「オブジェクト指向プログラミング言語の最適化コンパイラであるセルフコンパイラの設計と実装」、スタンフォード大学、CiteSeerX 10.1.1.30.1652
- 4 回の連載記事「環境とプログラミング言語 Self」
外部リンク
- 公式サイト
- GitHub上の自分自身
- Sun Microsystems の以前の自己ホームページ
