プログラミング言語Selfのチュートリアルへようこそ。Selfは革新的なプロトタイプベースのオブジェクト指向言語で、柔軟性と効率性に優れています。このガイドでは、基本構文から始め、関数、データ構造、オブジェクト指向までを詳細に解説します。Selfの理解を深め、新しいプログラミングの世界への扉を開くためのステップとなるでしょう。
Selfは、革新的で柔軟性に富んだプロトタイプベースのオブジェクト指向プログラミング言語です。この言語は、1980年代初頭にスタンフォード大学とゼロックスパロアルト研究所の共同プロジェクトで生まれ、オブジェクト指向プログラミングの新しい次元を切り開きました。
Selfは、他のプログラミング言語とは異なり、クラスによるオブジェクト生成ではなく、プロトタイプを基に新しいオブジェクトを生成するプロトタイプベースの手法を採用しています。これにより、柔軟性と拡張性が向上し、開発者はより自由な形でオブジェクトを操ることができます。
Selfを学ぶことは、オブジェクト指向プログラミングにおける新しいアプローチを理解し、柔軟なコーディングスタイルを習得する素晴らしい機会です。また、Selfの持つ効率的な実行性能は、高度なプログラムの開発においても優れたパフォーマンスを提供します。この言語を学ぶことで、革新的なプログラミングスキルを身につけ、未来の挑戦に備えることができます。自己表現型の言語であるSelfに触れ、新しい次元のプログラミングの扉を開いてみましょう。
Selfは対話型なので、簡単なHello Worldプログラムも対話的に実行できます。以下は、SelfでHello Worldを表示する例です。
 
"Hello, Worldプログラム"
('Hello, World!') displayNl.
このプログラムは文字列'Hello, World!'を表示します。displayNlは改行付きで文字列を表示するメソッドです。Selfでは対話的にコードを実行することができるので、このコードをSelfの対話環境に入力して実行すると、"Hello, World!"が表示されます。
オブジェクトの作成とメッセージの送信:
// オブジェクトの作成
obj := ( | x = 10.  y = 20. | ).
// メッセージの送信
obj x.  // 結果は 10
プロトタイプベースのオブジェクト指向性:
// プロトタイプの作成
prototype := ( | x = 0.  increment = ( | self x: (self x + 1). | ). | ).
// オブジェクトの作成（プロトタイプのコピー）
obj1 := prototype copy.
obj2 := prototype copy.
// メッセージの送信
obj1 increment.
obj2 increment.
obj1 x.  // 結果は 1
obj2 x.  // 結果は 1
自己反映（self-reflection）:
// オブジェクトの作成
obj := ( | x = 10.  y = 20. | ).
// 自己反映によるメッセージの送信
obj ("x:" bind: ( | :newVal | obj x: newVal + 5. )) applyWith: 15.
obj x.  // 結果は 20
メソッドの定義
メソッドはdefine:キーワードを使用して定義されます。例えば：   この例では、objオブジェクトに myMethod というメソッドを定義しています。
obj define: myMethod [ "メソッドの本体" ].
メッセージの送信
メソッドはメッセージとしてオブジェクトに送信されます。メッセージはスペースで区切られたメソッド名と引数のリストで構成されます。
obj myMethod: 10.
この例では、objオブジェクトに対して myMethod: メソッドに引数 10 を送信しています。
条件分岐
条件分岐は ifTrue:ifFalse: メッセージを使用して行います。
condition ifTrue: [ "真の場合の処理" ] ifFalse: [ "偽の場合の処理" ].
繰り返し
ループは whileTrue: メッセージを使用して行います。
[ condition ] whileTrue: [ "ループ内の処理" ].
変数への代入
変数への代入は := を使用します。
x := 10.
これは非常に基本的な例であり、Selfの特徴や構文を十分に紹介するものではありません。Selfを学ぶには、公式のドキュメントや論文、関連するリソースを参照することが重要です。
Selfは、他の一般的なプログラミング言語とは異なる独自の特徴を持っており、従来の制御構造（条件分岐やループ）の形式も一部異なります。以下に、Selfでの基本的な制御構造について簡単に説明します。
Selfでは、条件分岐はifTrue:ifFalse:メッセージを使用して行います。以下は、簡単な条件分岐の例です。
| condition result |
condition := true.
result := condition ifTrue: [ "条件が真の場合の処理" ] ifFalse: [ "条件が偽の場合の処理" ].
ifTrue: ブロックは条件が真の場合に実行され、ifFalse: ブロックは条件が偽の場合に実行されます。
Selfでは、繰り返しはwhileTrue:メッセージを使用して行います。以下は、簡単なループの例です。
| counter |
counter := 1.
[ counter <= 5 ] whileTrue: [
    "ループ内の処理"
    counter := counter + 1.
].
この例では、whileTrue: メッセージが条件が真の間ループを続けます。
Selfの特徴的な点は、条件分岐やループがメッセージとして表現され、オブジェクト指向プログラミングの概念に基づいていることです。上記の例は非常に基本的なものであり、Selfが提供する他の機能や高度な制御構造を理解するには、より詳細なドキュメントや学習リソースを参照することが重要です。
Selfにおいて、配列は "ベクター"（Vector）と呼ばれ、順序を持つ複数の要素を格納するために使用されます。ベクターは、可変サイズであり、同じベクター内で異なる型の要素を混在させることができます。以下は、Selfでのベクターの基本的な使い方の例です。
 
| myVector |
myVector := ( | 'apple'. 10. true. | ).
"ベクターの要素へのアクセス"
(myVector at: 1) displayNl.  "apple"
(myVector at: 2) displayNl.  "10"
(myVector at: 3) displayNl.  "true"
"ベクターのサイズの取得"
(myVector size) displayNl.  "3"
"ベクターの要素の変更"
myVector at: 1 put: 'orange'.
(myVector at: 1) displayNl.  "orange"
この例では、myVectorというベクターを定義しています。このベクターには文字列、整数、真偽値の要素が格納されています。ベクターの要素へのアクセスには at: メソッドが使用され、ベクターのサイズを取得するには size メソッドが使用されます。また、要素を変更するには at:put: メソッドが使用されます。
ベクターは可変サイズであり、要素の追加や削除が可能です。以下は、ベクターに要素を追加する例です。
 
| fruits |
fruits := ( | 'apple'. 'orange'. 'banana'. | ).
"新しい要素を追加"
fruits addLast: 'grape'.
"変更を表示"
fruits displayNl.  "( 'apple' 'orange' 'banana' 'grape' )"
この例では、addLast: メソッドを使用して、ベクターに新しい要素 'grape' を追加しています。displayNl メソッドを使用して変更後のベクターを表示しています。
Selfでは、メソッド（method）はオブジェクトに対する振る舞いを定義する主要な手段です。メソッドはオブジェクトにメッセージが送信されたときに実行され、オブジェクトの状態を変更するか、結果を返します。以下に、Selfでメソッドを定義する基本的な構文を示します。
メソッドは、オブジェクトに対して|（パイプ）で始まり、.（ピリオド）で終わります。メソッドの中では、selfキーワードを使用してオブジェクト自体を参照します。また、引数はメソッド名の後にコロンを続けて指定されます。
例えば、以下は簡単なメソッドの例です。
| Point |
Point := ( | x. y. | ).
Point define: setX: [ :newX | x := newX. ].
Point define: setY: [ :newY | y := newY. ].
Point define: getX [ ^x. ].
Point define: getY [ ^y. ].
| p |
p := Point copy.
p setX: 10.
p setY: 20.
"メソッドの呼び出しと結果の表示"
(p getX) displayNl.
(p getY) displayNl.
 
この例では、Pointというオブジェクトを定義し、そのオブジェクトに対してsetX:, setY:, getX, getYという4つのメソッドを定義しています。これらのメソッドは、それぞれx座標とy座標の設定と取得を行います。
なお、Selfではメソッドの実行はメッセージの送信を通じて行われるため、実際にはメッセージがオブジェクトに送信されることによってメソッドが呼び出されます。上記の例では、setX:やgetXといったメッセージがオブジェクトに送信され、それに対応するメソッドが実行されています。
Selfでは再帰をサポートしており、再帰的な関数やメソッドを記述することができます。以下に、Selfでの再帰の例を示します。この例では、階乗を計算する再帰的なメソッドを定義しています。
 
"階乗を計算する再帰的なメソッド"
| Factorial |
Factorial := ( | factorial. | ).
Factorial define: compute: [ :n |
    n <= 1 ifTrue: [ ^1. ] ifFalse: [ ^n * (self compute: (n - 1)). ].
].
| result |
result := (Factorial copy) compute: 5.
result displayNl.
この例では、Factorialというオブジェクトを定義し、その中にcompute:という再帰的なメソッドを作成しています。このメソッドは引数 n が 1 以下の場合には 1 を返し、それ以外の場合には n と (self compute: (n - 1)) の積を返します。このようにして、階乗を再帰的に計算しています。
例の最後で、compute:メソッドを呼び出して 5 の階乗を計算し、その結果を表示しています。この例は再帰の基本的な構造を示しており、Selfで再帰を利用する際の一般的なアプローチを理解するのに役立ちます。
Selfはプロトタイプベースのオブジェクト指向プログラミングを採用しており、クラスとは異なる形で継承が実現されています。プロトタイプベースのオブジェクト指向プログラミングでは、オブジェクトが別のオブジェクトをプロトタイプとして利用し、そのプロトタイプの振る舞いを共有します。
以下は、Selfでの継承の簡単な例です。
| Shape Square |
Shape := ( | x. y. | ).
Shape define: moveTo: [ :newX :newY |
    x := newX.
    y := newY.
].
Square := (Shape copy) clone.
Square define: setSide: [ :side |
    "Squareオブジェクトの新しいメソッド"
    self moveTo: (self getX) : (self getY). "親のメソッドを呼び出す"
    x := x + side. "新しい機能を追加"
].
| square |
square := Square copy.
square setSide: 5.
(square getX) displayNl. "Squareオブジェクトは親のメソッドを利用"
 
この例では、Shapeというプロトタイプオブジェクトを定義し、SquareというオブジェクトがShapeをクローンして作成されています。Squareオブジェクトは新しいメソッドsetSide:を定義していますが、同時に親オブジェクトであるShapeのメソッドmoveTo:も呼び出しています。
Selfでは、継承がプロトタイプをコピーし、新しいメソッドを追加することで実現されます。このプロトタイプベースのアプローチにより、動的で柔軟なオブジェクトの構築が可能になります。
{{コラム|SelfはSmalltalkの方言？|2=Selfは、Smalltalkと関連しているものの、厳密にはSmalltalkの方言ではありません。Selfは、Smalltalkに基づいており、Smalltalkの影響を受けながらも、独自のアイデアや概念を組み込んだ新しいオブジェクト指向プログラミング言語です。
Selfは、Smalltalkよりもプロトタイプベースのオブジェクト指向プログラミングに焦点を当てています。プロトタイプベースのオブジェクト指向プログラミングでは、新しいオブジェクトを既存のオブジェクトから複製して作成することが一般的です。一方で、Smalltalkはクラスベースのオブジェクト指向プログラミングを採用しています。
Selfは、Stanford大学での研究プロジェクトにおいて、Smalltalk-80から派生して開発されました。そのため、Smalltalkの基本的なアイデアや概念に影響を受けていますが、言語仕様や構文は異なります。特に、Selfではクラスやメタクラスの概念がなく、プロトタイプが中心となっています。