Smalltalk

プログラミング言語のひとつ

SmalltalkSimula LISPLOGO [2]
Smalltalk
Smalltalk
Smalltalkのロゴ
パラダイム オブジェクト指向プログラミングクラスベース ウィキデータを編集
登場時期
  • 1972年 (52年前) (1972) (開発開始)
  • 1980年 (44年前) (1980) (公開)
設計者 アラン・ケイ, ダン・インガルス, エイデル・ゴールドバーグ
開発者 アラン・ケイ, ダン・インガルス, エイデル・ゴールドバーグ, Ted Kaehler, Diana Merry, Scott Wallace, Peter Deutsch, ラリー・テスラー, パロアルト研究所
最新リリース VisualWorks 8.3.1 英語版/ 2018年5月 (6年前) (2018-05)
型付け 型なし[1], ダック・タイピング(オプショナルな静的型検査が可能な処理系も存在する)
主な処理系 VisualWorksSqueakPharo
影響を受けた言語 LISP、Simula 67、SimulalOGO ウィキデータを編集
影響を与えた言語 Actor英語版FlavorsObjective-CSelfRubyScala
拡張子 st ウィキデータを編集
テンプレートを表示

カテゴリ / テンプレート

Smalltalk で一語であり、「Small Talk」「SmallTalk」などは誤りである。

大規模な開発実績としてはCargill Lynx Project[3]があり、国産製品の開発実績としてはMCFrameがある。

概要

編集

開発の経緯

編集

PARC1970103Smalltalk-727680 Alto Alto Alto Smalltalk-801983[1] VisualWorks

Smalltalkの変遷

編集

※この節は[4][5]を元に執筆されている。

名称 備考
Smalltalk-71 最初にSmalltalkの名前を冠した言語だが、文法など一部仕様が定められただけで実装はされていない。
Smalltalk-72 メッセージングの機構により最初に動作したSmalltalk。初期のGUIはタートルグラフィックスで表現されたウインドウやメニューなど原始的な構成で、言語仕様的にもクラスが関数であったり、メソッド定義がリーダーマクロ(あるいは簡易パーサー記述)のようであったりと、現在のSmalltalkとは異なる点が多い。
Smalltalk-74 Smalltalk-72に対し、処理系の高速化、GUIの整備、オブジェクト指向仮想メモリ (OOZE) を導入したバージョン。
Smalltalk-76 現在のメッセージ式に近い文法(特にキーワードメッセージ式)を取り入れたSmalltalk。メタクラス、第一級オブジェクトとしてのブロックなどはまだない。
Smalltalk-78 Smalltalk-76を、可搬式の試作機「NoteTaker」で動作するよう8086向けにBitBlt等を再構築し、小さく整理したバージョン。
Smalltalk-80 現在に知られる仕様となったSmalltalk。
ObjectWorks Smalltalk-80を一般に普及させるために開発・販売されたSmalltalk。
VisualWorks ObjectWorksを引き継ぎ開発されたSmalltalk。Smalltak直系の子孫で現代に至るSmalltalkの中で本家と言える存在である。
Apple Smalltalk Smalltalk-80 v1(リリース前バージョン)を元に、XEROX社に許諾および指導を受けてAppleが開発したSmalltalk。同時期にDECテクトロニクスヒューレット・パッカードでも同様の試みがなされている。
Squeak Appleに移籍したアラン・ケイ、ダン・インガルスらによってApple Smalltalkを元に開発された。Smalltalkの設計者により開発されており、いわば分家と言える存在である。
Pharo Squeakから派生した実装。大胆で実験的な機能追加の試みが多いが、2017年現在精力的かつ活発に開発が進められているSmalltalk処理系のひとつ。

Smalltalk とオブジェクト指向

編集



Smalltalk C++ Smalltalk C++ 

Smalltalk の独自性

編集

Smalltalk C C++ Smalltalk Smalltalk 使

 VisualWorks  Squeak  Smalltalk  Smalltalk 

環境および処理系としてのSmalltalk

編集

Smalltalk 環境から見たSmalltalk 言語

編集

Smalltalk  Smalltalk  bash Smalltalk  Smalltalk 

()調#browse#inspect使do it(WindowsCtrl+D)

 Smalltalk 使 Smalltalk 

仮想機械方式

編集

仮想機械による実行

編集

Smalltalk Smalltalk 使() Smalltalk  Smalltalk Smalltalk 

 Smalltalk  Smalltalk [6] Smalltalk EULERp[7]

イメージファイル

編集

Smalltalk  Smalltalk Smalltalk Smalltalk Smalltalk 

仮想機械とブートストラップ

編集

Smalltalk の実行環境が全く存在しない初期の状況ではコンパイラーも仮想機械も Smalltalk で用意する事はできない。このため Smalltalk の初期段階ではALTOアセンブリ言語によりコンパイラーや仮想機械が実装されていた。[8]

実行時書き換え

編集

Smalltalk使Class BrowserSmalltalkSmalltalkC++PythonSmalltalkWindowWindowButtonWindowButtonWindowButton

環境の種類

編集

GUIツール

編集
 
Linux上で稼働するSmalltalk環境(VisualWorks)。 左上:Class Browser, 右上:Transcript, 左下:Workspace, 右中段:Debugger/Notifier, 中央下段:Inspector, 右下段:変数を表示したWorkspace

準標準的なGUIツール

編集

GUIを使わないような特殊なものを除き、大半のSmalltalk環境では次のようなGUIツールが用意されている。

  • Class Browser(System Browser)
  • Transcript
  • Workspace
  • Debugger/Notifier
  • Inspector

Smalltalkの開発ではこれらのツールを使って開発する事が半ば前提となっている。

Class Browser(System Browser)

編集

Smalltalk環境内に存在する全てのクラスを(存在する場合は名前空間も)表示/編集できるツールで、Smalltalk開発において中核となるツールである。

Transcript

編集

言うなれば出力しかできないコンソールといったツールで、プログラムの実行結果を簡易的に表示したいときに使われるツールである。Smalltalk環境内でTranscript変数に書き込まれたメッセージは、全てこのTranscriptに表示される。

Workspace

編集

言うなればコンソールの入力側とテキストエディターを組み合わせた様なツールである。一見すれば書いたコードを実行できるだけの簡易的なテキストエディターにしか見えないが、WorkspaceはWorkspace変数というWorkspace固有の変数を持っており、Workspace内で実行されたSmalltalkコードの実行結果を保持することができる。このため、長いコードを書くような用途では使わず、Smalltalk環境に対するパッケージの追加や、環境設定、ファイルの一時的な操作など一時的な操作を実行する場所として使われる。

Debugger/Notifier

編集

Inspector

編集

オブジェクトの内部構造を再帰的に表示するツールである。また、多くの場合オブジェクトの編集が可能でありWorkspaceと組み合わせてオブジェクトを組み立てていくことが可能である。例えば画面部品をWindowを表すオブジェクトに組み込み、クラス変数に格納するといった具合である。Inspectorに限らずSmalltalk環境全体に共通することであるが、オブジェクト内の変数を表示するときは内部構造そのままではなくオブジェクトの文字列表現で表示する。このため内部がHash map等複雑な構造になっている場合でもDictionary (#key -> 'value' )といった読み易い表示となる。

言語としてのSmalltalk

編集

言語としての設計思想

編集

 Smalltalk 

 Smalltalk 

SB5000[7]

The basic principle of recursive design is to make the parts have the same power as the whole.


 Smalltalk 





MetaclassMetaclass classMetaclass classMetaclass

ObjectProtoObjectUndefinedObjectnil

Smalltalk  Smalltalk 

Smalltalk  Smalltalk 

Smalltalk SmalltalkSmalltalk

言語仕様の種類

編集

Smalltalk  Smalltalk 

文法

編集

コメント

編集

"~"」のようにダブルクオーテーションでくくった文字列がコメントとして扱われる。

定数表現

編集

主な定数表現には次のようなものがある。

整数 3
整数(16進数) 16r3
小数 3.4
浮動小数点数 3.4e5
文字 $a
文字列 'abc'
シンボル #abc
記号を含むシンボル #'*abc'
配列(要素は定数限定) #( 'This' #is $a 10 )
バイト配列(要素は0〜255の定数限定) #[ 0 255 16r0 16r255 ]
ブロック(引き数なし) [ 3 + 4 ]
ブロック(引き数付き) [ :x | x + 1 ]

定数ではないが、よく用いられるオブジェクトの生成式には次のようなものがある。

分数 3 / 4
複素数 3 + 4i
座標 3 @ 4
共同体 'a' -> 0

言語機能の様に見えるが「/」や「@」などはただのセレクターであり、Smalltalk の使用者も同様の機能を作ることが出来る。

変数

編集

|:=_使
| a b |
a := 3.
b := 4.

擬変数

編集

 selfsuperniltruefalsethisContext 6self  super nil  true  false  UndefinedObjectTrueFalse thisContext 使

self  super self super 

メッセージ式

編集

Smalltalk では「メッセージ式」と呼ばれる書式でコードを記述する。メッセージ式は「レシーバー」に「メッセージ」を送ることを表すためのもので、そのまま

receiver message

[2]0 Smalltalk 
メッセージ式 セレクター 引数
receiver noArg noArg N/A
receiver oneArg: arg oneArg: arg
receiver firstArg: arg1 secondArg: arg2 firstArg:secondArg: arg1arg2

 firstArg:secondArg:  firstArg:  secondArg:便

01使
メッセージ式 セレクター 引数
3 + 4 + 4
#( 1 2 3 ), #( 4 5 ) , #( 4 5 )

3 + 43+ 4


メッセージ式 結合性を明示した等価の表現
3 + 4 * 5 min: 6 factorial ( ( 3 + 4 ) * 5 ) min: ( 6 factorial )

セミコロン「;」でメッセージ式を区切る事により、1個のレシーバーに対して複数のメッセージを送ることが出来る。これをカスケード式という。

| collection |

collection := OrderedCollection
	new
	add: 0;
	add: 1;
	add: 2;
	add: 3;
	add: 4;
	yourself.

カスケード式を用いて書いた上記の文は、カスケード式を用いない次の文と等価である。

| collection |

collection := OrderedCollection new.
collection add: 0.
collection add: 1.
collection add: 2.
collection add: 3.
collection add: 4.

制御構文

編集

^ 使
ブロック
編集

 Smalltalk 

value
[                  0               ] value.             "-> 0"
[ :value1         | value1          ] value: 1.          "-> 1"
[ :value1 :value2 | value1 + value2 ] value: 1 value: 1. "-> 2"

:value1 :value2|valuevalue4( #value:value:value:value: )5#valueWithArguments:使value#value#value:使

value使cullcullvalue
[ :value1 | value1 ] cull: 1 cull: 2. "-> 1"

cullはブロックによる分岐制御が主目的であるが、分岐の基準になったオブジェクトを参照する場合もあるようなセレクターで使われる。典型的な例は、オブジェクトがnilで無いときだけブロックを実行する#ifNotNil:である。

| block value1 value2 |

block := [ :value | value ].

value1 := 1.
value2 := 2.

value1 ifNotNil: [ 9 ]. "-> 9"
value1 ifNotNil: block. "-> 1"
value2 ifNotNil: block. "-> 2"
条件分岐
編集

条件分岐は #ifTrue:ifFalse: セレクターを用いたメッセージ式として、条件式の結果の真偽値へのメッセージ送信の形で次のように記述する。

3 < 4 ifTrue: [ 5 ] ifFalse: [ 6 ].

Smalltalk では nil がオブジェクトである。これを利用した nil 専用の条件式も存在する。

object := nil.
object ifNil: [ 5 ] ifNotNil: [ 6 ].
object ifNotNilDo: [ :value | value inspect. ].

条件分岐の制御において、他の言語でいうswitchに直接該当する文は存在しない。多態性を利用して分岐するか、次のように連想配列を利用して分岐するため不要である。

something: aNumber
	| switch |

	"速度が求められる場合は、初期化済みのDictionaryのオブジェクトをインスタンス変数やクラス変数にキャッシュする。"
	switch := Dictionary
		new
		at: 1 put: [ #a ];
		at: 2 put: [ #b ];
		at: 3 put: [ #c ];
		yourself.

	^ ( switch at: aNumber ifAbsent: [ #z ] ) value.

但し一部の処理系では、次のようなswitchに類似した書き方ができるものも存在する。

something: aNumber

	^ aNumber caseOf:
	{
		[ 1 ]->[ #a ].
		[ 2 ]->[ #b ].
		[ 3 ]->[ #c ].
	}.
反復
編集

反復制御においてfor に直接該当する文は存在しない。代わりに回数を指定した反復がある。回数を指定した反復は、整数型へのメッセージ送信の形で次の様に記述する。

 "100回の反復処理を実行する"
100 timesRepeat:
[
	"反復実行する処理"
].

現在の反復回数を参照しながら反復する事も出来る。

 "100回の反復処理を実行する"
1 to: 100 do:
[ :each |
	"eachは現在の反復回数"
].

for に該当する文は存在しないものの、while に該当する文は存在する。while に該当する反復は、ブロックに対するメッセージ送信の形で次の様に記述する。

[ true "真偽値を返す式" ] whileTrue:
[
	"反復実行する処理"
].

#whileTrue:  #whileFalse: 

 do-while do-while 
[
	"反復実行する処理"
	"このブロックの実行結果が真である間反復を繰り返す"
] whileTrue.

Smalltalk では条件なしの反復も存在する。無条件反復は、ブロックに対するメッセージ送信の形で次の様に記述する。

[
	"反復実行する処理"
] repeat.

Smalltalk  #ifTrue:ifFalse 
反復からの脱出
編集

C言語の breakPerllast に相当する反復脱出は thisContext に対し #return セレクターを使ったメッセージを送る。

[
	thisContext return. "反復を抜ける"
] repeat.

thisContext  #return:  #return:to:  return 
例外処理機構
編集

Smalltalk 
[
	[
		Exception signal: '処理失敗'. "例外発生"
	]
		ensure:
		[
			"例外の有無に関わらず実行したい処理"
		].
]
	on: Exception "補足する例外の種類"
	do:
	[ :exception |
		"例外を補足した際の処理"
	].

なお#ensure:は後述のブロックによる資源の開放があるため多用されることはない。

例外の制御はメッセージ送信毎に連結リストとして積み上げられたコンテキスト情報の末端のコンテキスト(メソッドスタック)を表す thisContext オブジェクトを操作し、コンテキストを巻き戻す事で実現されている。複数の例外は、#on:do:on:do・・とon:do:を繰り返し(処理系が定義している限りの数で)記述して補足する事もできるが、次の様に例外の型を,で並べて補足する事も出来る。

[
	Notification signal: '接続準備完了'. 
]
	on: Error, Notification
	do:
	[ :exception |
		"エラーと通知両方の例外を1度に補足"
	].

なお、Smalltalkでは正常な結果を返せない異常な状態と通知両方を合わせたものが例外である。例外は正常な戻り値を返せない異常な場合と割り込みの様に非同期な通知に利用される。特徴的な点として異常な場合と通知の場合では動作が異なる。異常な場合は他の言語の例外同様、補足しなければその時点で停止しDebugウィンドウに移行するが、通知の場合は補足しなければ例外発生地点から処理を継続する。

並列処理
編集

Smalltalkでは、標準で並列処理が存在する。並列処理は次の様に記述する。

| process semaphore |

semaphore := Semaphore new.
process :=
[
	Process yield. "他のProcessに切り替える切り替え点"
	"並列実行される子処理"

	semaphore signal. "親処理への終了通知"
] newProcess.

process resume.	"子処理の起動。Blockに対し#forkを送る場合はnewProcessとresumeは省略できる"
"並列実行される親処理"

semaphore wait. "子処理の終了待機"

Smalltalk()POSIXGNU Smalltalk[24]()使

クラスオブジェクトの登録

編集

Smalltalk は、クラスの定義をメッセージ式による実行環境へのクラスオブジェクトの登録として実現する。他の言語と異なりクラスオブジェクトの登録は単なる定義ではなく実行環境に対する操作である。1度クラスオブジェクトを登録してイメージファイルを保存すると、明示的にクラスオブジェクトを削除しないかぎりはクラスオブジェクトがイメージファイルに残り続ける。Smalltalk 環境に対するクラスオブジェクトの登録は次の様に記述する。

"DerivedクラスをSmalltalk環境に登録する例"
Object						"基底クラスオブジェクト"
	subclass:		        #Derived	"Objectクラスの派生として登録するクラスオブジェクト名の指定"
	instanceVariableNames:	'ia ib ic'	"インスタンス(実体)オブジェクトに所属する変数名(インスタンス変数)の指定(空白区切り)"
	classVariableNames:	    'ca cb cc'	"クラスオブジェクトと共有する変数名(クラス変数)の指定(空白区切り)"
	poolDictionaries:	    'pa pb pc'	"クラスに所属する変数(プール変数)を取り込む辞書の指定(空白区切り)"
	category:		        'example'.	"Smalltalk環境上でクラス名を表示する際にクラスが所属する分類の指定"

poolDictionaries  category C++ 

Smalltalk 使
#subclass:instanceVariableNames:classVariableNames:poolDictionaries:category:

 Smalltalk  Pharo 
#subclass:
#subclass:category:
#subclass:instanceVariableNames:
#subclass:instanceVariableNames:classVariableNames:poolDictionaries:category:
#subclass:uses: 
#subclass:uses:instanceVariableNames:classVariableNames:poolDictionaries:category:
#variableByteSubclass:instanceVariableNames:classVariableNames:poolDictionaries:category:
#variableByteSubclass:uses:ginstanceVariableNames:classVariableNames:poolDictionaries:category:
#variableSubclass:instanceVariableNames:classVariableNames:poolDictionaries:category:
#variableSubclass:uses:ginstanceVariableNames:classVariableNames:poolDictionaries:category:
#variableWordSubclass:instanceVariableNames:classVariableNames:poolDictionaries:category:
#variableWordSubclass:uses:ginstanceVariableNames:classVariableNames:poolDictionaries:category:
#weakSubclass:instanceVariableNames:classVariableNames:poolDictionaries:category:
#weakSubclass:uses:ginstanceVariableNames:classVariableNames:poolDictionaries:category:


クラスオブジェクトには、クラス変数とは別途、クラスオブジェクトが Class クラスから派生したインスタンスとして状態を持つためのインスタンス変数がある。このクラスオブジェクトのインスタンス変数はクラスオブジェクト内だけで共有され、インスタンスオブジェクトからは直接使用できない。

Smalltalk 環境に対するクラスオブジェクトのインスタンス変数の登録は次の様に記述する。

Derived class instanceVariableNames: 'ia ib ic'. "クラスオブジェクトのインスタンス変数名(空白区切り)"

クラスオブジェクトがもつインスタンス変数には変数を登録した基底クラスと派生クラスで別々の変数領域が確保されるという特筆すべき点がある。これを使用して下記の様にクラスに所属するオブジェクトだけを保持する変数としてつかったりする事ができる。

Object subclass: #Super.
Super class instanceVariableNames: 'objects'.

Super class methodsFor: 'accessing'
!
objects

    ^ objects ifNil: [ objects := OrderedCollection new ].
!!

Super class methodsFor: 'instance creation'
!
new
    | object |
    
    object := super new.
    self objects add: object.
    ^ object.
!!

Super subclass: #Derived. 

Derived new.
Derived objects size. "-> 1"
Super objects size. "-> 0"

メソッドの登録

編集

GUI

0min:
min: anOtherObject
	^ self < anOtherObject ifTrue: [ self ] ifFalse: [ anOtherObject ].

min: anOtherObjectmin:anOtherObject

 self  Smalltalk 

クラスオブジェクト

編集

Smalltalkは、多くの動的型付け言語やDelphiの様にクラスがオブジェクトである。このためSmalltalkではインスタンスオブジェクトと同様にクラスオブジェクトを変数に束縛してメッセージを送ることができる。

| object |

object := Something new.
object value. "インスタンスオブジェクトにvalueメッセージを送信"
object := Something.
object value. "クラスオブジェクトにvalueメッセージを送信"

クラスオブジェクトは、オブジェクトにclassメッセージを送ることでも取得できる。

' ' class. "-> ByteString"

復帰文とブロック

編集

Smalltalk のブロックは一種の制御構文であるという性質上、復帰文が他の言語と比べ極めて異質な振る舞いをする。

example
	| block |

	block := [ ^ 1 ].
	block value. "ブロックを実行"
	^ 0.

#example 使Smalltalk  0  Smalltalk  1Smalltalk block value.block ^ 1. example  example  block  1
callee: aBlock
	aBlock value.
	^ 2.
caller
	| block |

	block := [ ^ 1 ].
	self callee: block.
	^ 0.

 Smalltalk  example  block 1Smalltalk  Smalltalk #ifTrue:ifFalse: 使 #repeat 使
exampleBlock
	^ [ ^ 1 ].
callee: aBlock
	aBlock value.
	^ 2.
caller
	| block |

	block := self exampleBlock.
	self callee: block.
	^ 0.

ただし、上記の様にブロックを生成したコンテキストと、ブロックを評価する際のコンテキストが枝分かれする様な場合は復帰文を実行する事はできない。この場合は BlockContext が例外を出力し処理が停止してしまう。

メソッドに対する注釈

編集

(Pragma)使Smalltalk

Behaviorevaluate:SmalltalkWorkspace


< keyword1: arg1 ... keywordN: argN >

<>

Smalltalk使
コード 意味
<primitive: 1> 数値演算など原子的機能の呼び出し。引き数の値は呼び出す機能の番号。
<apicall: int 'GetLastError' () module: 'kernel32.dll'> FFIによる外部関数の呼び出し。先頭のapicallは呼び出し規約であり注釈の名前ではない。cdeclなどもある。

大域変数

編集

Smaltallkでは、Smalltalk環境全体で参照できる大域変数を作成する事が出来る。大域変数は同じく大域変数であるSmalltalk変数に格納されたSmalltalkImageのインスタンスオブジェクトにメッセージを送って作成する。また、大域変数の削除もSmalltalkImageのインスタンスオブジェクトに対するメッセージ送信となっている。

Smalltalk at: #GlobalVariable put: 100.
GlobalVariable. "->100"

globalVariable := 10.
Smalltalk at: #GlobalVariable. "->10"

Smalltalk removeAt: #GlobalVariable.
GlobalVariable. "->nil"

SmalltalkImageSmalltalkSmalltalk SmalltalkSmalltalkSmalltlakSmalltalkSmalltalk使

プール辞書

編集

プール辞書は、クラスの変数として連想配列または、他のクラスオブジェクトのクラス変数を取り込むという機能である。取り込む連想配列の要素やクラスオブジェクトのクラス変数はプール変数と呼ばれる。連想配列やクラスオブジェクトは大域変数でなくてはならない。

"プール辞書で使用する連想配列の登録"
Smalltalk at: #UserPoolA put: Dictionary new.
UserPoolA at: #ExamplePoolValueA put: 1.

"プール辞書で使用するクラスオブジェクトの登録"
Object
	subclass:		#UserPoolB
	instanceVariableNames:	''
	classVariableNames:	'ExamplePoolValueB'
	poolDictionaries:	''
	category:		'example'.

"UserPoolAとUserPoolBをプール変数として利用するクラスオブジェクト"
Object
	subclass:		#Someone
	instanceVariableNames:	''
	classVariableNames:	''
	poolDictionaries:	'UserPoolA UserPoolB'	"UserPoolAとUserPoolBを辞書に記述しプール変数を取り込む"
	category:		'example'.

Someone methodsFor: 'accessing'
!
valueA
	^ ExamplePoolValueA. "UserPoolAのExamplePoolValueAを参照"
!
valueB

	^ ExamplePoolValueB. "UserPoolBのExamplePoolValueBを参照"
!!

プール辞書には複数の連想配列やクラスオブジェクトを指定できるが、プール変数が重複した場合は、先に指定した連想配列やクラスオブジェクトのプール変数が使われる。

準標準的な文法

編集

非定数要素配列

編集

Pharo, GNU Smalltalkといった近代の環境では、定数以外に式の結果を指定可能な非定数要素の配列定数を使用できる。配列の要素は空白ではなく.で区切る。

array := { 1. 1 + 1 }. "1と2を要素に持つ配列を作る。"

継続

編集

継続渡し形式を支援する機能として継続があり、PharoやGNU Smalltalkで使用できる。もっぱら反復の中断や、メソッド内の処理を飛ばすために使われる。継続の使用は次の様に記述する。

result := Continuation currentDo:
[ :break |

 aCondition1 ifTrue: [ break value: 1 ]. "aCondition1がtrueなら以降の処理を中断しresultに1を代入する。"
 aCondition2 ifTrue: [ break value: 2 ]. "aCondition2がtrueなら以降の処理を中断しresultに2を代入する。"

 3 "aCondition1, aCondition2両方trueならresultに3を代入する。"
].

生成器

編集

遅延評価を支援する機能として生成器があり、PharoやGNU Smalltalkで使用できる。生成器はCoroutineにも利用できる。生成器の使用は次の様に記述する。

stream := Generator on:
[ :each |
	each yield: 1.
	each yield: 2. "stream nextを1回呼ぶまで実行しない。"
	each yield: 3. "stream nextを2回呼ぶまで実行しない。"
].

stream next. "-> 1"
stream next. "-> 2"
stream next. "-> 3"

生成器を使って処理を作ることは多くないが、配列などを使用する際、間接的に使用していることが多い。

| readStream grater2 total |

readStream := #( 1 2 3 4 5 ) readStream. "#readStreamにより#select:を遅延実行する生成器が作られる。"
grater2 := ( ( readStream select: [ :each | 1 < each ] ) collect: [ :each | each * 2 ] ) reject: [ :each | 8 > each ].
total := grater2 inject: 0 into: [ :value :each | value + total ]. "#inject:into:でeachに代入するとき初めて#select:と#collect:と#reject:が実行される。"

ファイル用構文

編集

Smalltalk  Smalltalk GUI Smalltalk  Smalltalk 
Object
	subclass:		#Example
	instanceVariableNames:	''
	classVariableNames:	''
	poolDictionaries:	''
	category:		'example'.

Example methodsFor: 'Instance Methods A' 
!
selectorA1
	"処理"
	^ 0.
!
selectorA2: anArgument
	"処理"
	^ 0.
!!

Example methodsFor: 'Instance Methods B'
!
selectorB1
	"処理"
	^ 0.
!
selectorB2: anArgument
	"処理"
	^ 0.
!!

Example class methodsFor: 'Class Methods' 
!
selector1
	"処理"
	^ 0.
!
selector2: anArgument
	"処理"
	^ 0.
!!

!使!  methodsFor: '' !  !!!

使
Example methodsFor: 'Instance Methods A' 
!
selector1
!!

'hello' displayNl.
'world' displayNl.

Example2 methodsFor: 'Instance Methods A' 
!
selector
!!

ファイル用構文で記述されたメソッドの登録は、可読性や記述性の面からメッセージ式からかけ離れた変則的な構文が使用される。しかし、この変則的な構文を用いなければメソッドを登録できないわけではなく、次のように通常のメッセージ式でメソッドを登録する事も出来る。

Example
	compile:
		'
		selectorC: anArgument
			^ 0.
		'
	classified: 'Instance Methods C'.

上記では、クラスオブジェクトExampleのプロトコルInstance Methods Cに対し、メソッドselectorCを登録している。

委譲と継承

編集

Smalltalk において、継承とは特殊な委譲に過ぎない。

Object
	subclass:		#Derived	"DerivedはObjectクラスから派生させる"
	instanceVariableNames:	''		"オブジェクトに所属する変数は定義しない"
	classVariableNames:	''		"クラスオブジェクトと共有する変数は定義しない"
	poolDictionaries:	''		"クラスに所属する変数は定義しない"
	category:		'example'.	"クラスの分類はexampleとする(今回の名前に意味はない)"

このため、例えば上記のクラスオブジェクトの生成では、Derived クラスオブジェクトの基底クラスオブジェクトとして Object を指定しているが、処理系によっては下記の様に #superclass: メッセージを送る事で、基底クラスに別のクラスオブジェクトを指定する事が出来る。

"superclass: NewBase. メッセージを送り基底クラスを NewBase に変更する事が出来る。"
Derived superclass: NewBase.

処理系により不可能な事もあるがクラスオブジェクトだけでなく、インスタンスオブジェクトから派生することも出来る。

"インスタンスオブジェクトの nil から派生した Derived クラスを Smalltalk 環境に登録する"
nil
	subclass:		#Derived
	instanceVariableNames:	''
	classVariableNames:	''
	poolDictionaries:	''
	category:		'example'.

なお通常、派生元の基本となるProtoObjectやObjectはnilから派生しており継承関係は再帰的に循環している。

メッセージ

編集

Smalltalk C++ 

 #hello 使Smalltalk  hello hello hello  doesNotUnderstand: 

 Smalltalk  doesNotUnderstand:  Smalltalk  Pharo  MessageCatcher [25]
message := MessageCatcher new show: 'text'. "「show: 'text'」がmessageに代入される。"
message sendTo: Transcript. "「Transcript show: 'text'」が実行される。"

また、セレクターとメソッドが独立していることを利用して一つのメソッドを複数のセレクターに結びつける事もできる。

"#onClick:を使ったメッセージをopen:メソッドに転送させる。"
FileEventHandler
	addSelector:	#onClick:
	withMethod:	FileEventHandler >> #open:.

メッセージにはセレクターと引き数が含まれている。このため受け取ったセレクターと引き数を編集する事も出来る。

message := MessageCatcher
	new
		bold: true
		text: 'example'.

message selector keywords keysAndValuesDo:
[ :key :each |
        Transcript
                show: each, ':=', ( message arguments at: key ) printString;
                cr.
].
"
以下が出力される。

bold:=true
text:=example
"

型付け

編集

Smalltalk: untyped[1]Smalltalk () Smalltalk Pharo  MessageCatcher GNU Smalltalknil使 Smalltalk 

メッセージと制御構文

編集

SmalltalkSmalltalkSmalltalk


| then else message condition |

then := [ 1 ].
else := [ 2 ].

message := MessageCatcher
	new
		ifTrue:  then
		ifFalse: else.

condition := 2 = 2.
^ message sendTo: condition.

これらの変数に分解された構文要素は、どのクラスのオブジェクトで無いといけないという制限はない。送られたメッセージを処理することさえ出来ればあらゆるオブジェクトに置き換える事が出来る。

特殊セレクター

編集

Smalltalk: special selector #ifTrue:ifFalse:ifTrue: [5] ifFalse: [6]ifTrue:ifFalse: truefalseBooleanMustBeBoolean使
3 < 4 ifTrue: [ 5 ] ifFalse: [ 6 ].

セレクターと名がつくが特殊セレクターは、特別扱いする条件が引数の状態を含んでおり、たとえ同じセレクターを使ったメッセージでも引数が条件に一致しなければ特別扱いしない。例えば下記のように引数に直接ブロックを指定していない場合では多くの処理系(VisualWorks, GNU Smalltalk等)は特別扱いせずメッセージ送信を実行する。

| then else |
then := [ 5 ].
else := [ 6 ].
true ifTrue: then ifFalse: else.

特殊セレクターはあくまで高速化の手段であるため種類は処理系によって異る。どの処理系が何を特殊セレクターとして扱うかは処理系ごとに提供される説明資料に記述されている。[26][27]

またPharoのように設定から特殊セレクターを通常のメッセージ送信に切り替えられる処理系も存在する。

クラスオブジェクトとMetaclass

編集

クラスオブジェクトもオブジェクトであるため、所属するクラスが存在している。クラスオブジェクトが所属するクラスはMetaclassというクラスのインスタンスオブジェクトである。

ByteString.                   "-> ByteString"
ByteString class.             "-> ByteString class"
ByteString class class.       "-> Metaclass"

Metaclassも当然ながらクラスに所属しており、再帰的にMetaclassに属するようになっている。

' ' class.                               "-> ByteString"
' ' class class.                         "-> ByteString class"
' ' class class class.                   "-> Metaclass"
' ' class class class class.             "-> Metaclass class"
' ' class class class class class.       "-> Metaclass"
' ' class class class class class class. "-> Metaclass class"

クラスオブジェクトが所属するMetaclassのインスタンスオブジェクトは特殊なオブジェクトであり、クラスの継承階層と同様に継承階層を持っている。

Collection  class superclass. "-> Object class"
Object      class superclass. "-> ProtoObject class"
ProtoObject class superclass. "-> Class"

クラスオブジェクトはMetaclassから生成された単なるオブジェクトで有ることから、Smalltalkが標準で提供するクラスオブジェクトとは異なる独自の構造をもったクラスオブジェクトを作ることができる。

例えば以下のようにメソッドの代わりにブロックを持つ無名クラスを作成することも出来る。

| class object |

"Metaclassからクラスオブジェクトを生成"
class :=
	Class 
		new
			superclass: Object;
			methodDictionary: MethodDictionary new.

"生成したクラスオブジェクトのセレクターにメソッドではなくブロックを紐付け"
class
	methodDictionary
		add:	#something1: -> [ :value | value ] block;
		add:	#something2 -> [ 2 ] block.

"生成したクラスオブジェクトをインスタンスオブジェクトの生成に使用"
object := class new.

Transcript
	show: ( object something1: 1 ) printString;
	nl.

"生成したクラスオブジェクトを基底クラスとして使用"
class
	subclass:		#Example
	instanceVariableNames:	''
	classVariableNames:	''
	poolDictionaries:	''
	category:		''.

定数とオブジェクト

編集

文法の節で述べた通りSmallatalkでは定数も全てオブジェクトである。どんな定数であれ#class#inspectといった基本的なセレクターを使ったメッセージを受け取ることが出来るため、基本的な操作であれば定数と他のオブジェクトを区別する必要はない。

| showClass |

showClass :=
[ :object |
	Transcript
		show: object class name;
		cr.
].

showClass
	value: Object new; "-> Object"
	value: Object;     "-> Object class"
	value: nil;        "-> UndefinedObject"
	value: 0;          "-> SmallInteger"
	value: 0.0;        "-> Float"
	value: 0.0e1;      "-> Float"
	value: $0;         "-> Character"
	value: '';         "-> ByteString"
	value: #a;         "-> ByteSymbol"
	value: #'a';       "-> ByteSymbol"
	value: #();        "-> Array"
	value: [].         "-> BlockClosure"

可変長オブジェクト

編集

Smalltalk は、任意の広さで確保した領域を持つ可変長オブジェクトを作ることが出来る。Smalltalkには配列を表わすためArray等が存在するが、これらのクラスオブジェクトは可変長オブジェクトを使って構築されている。可変長オブジェクトの領域は、オブジェクトの生成したときの一度だけしか広さを指定できない。また、クラスオブジェクトの登録時にvariable〜で始まるセレクターを使っている必要がある。

Object
	variableSubclass:	#ExampleArray
	instanceVariableNames:	''
	classVariableNames:	''
	poolDictionaries:	''
	category:		'example'.

| array |

array := ExampleArray new: 100.	"要素100個分の領域を確保した可変長オブジェクトを生成する。"
array at: 1 put: 0.		"1番目の要素に0を入れる。"
array at: 1.			"1番目の要素を取り出す。"

記憶領域の管理

編集

Smalltalk は、ハンドルとごみ回収機能(ガーベッジコレクター)の全面的な導入によりハンドルテーブルの書き換えを利用した特殊な制御を提供している。[28]

ハンドルテーブルの書き換え[29]

編集

ハンドルが参照している記憶領域上のテーブルを書き換えることによりSmalltalkは、あるオブジェクトを参照している全ハンドルの参照先を一気に変更することができる。ハンドルテーブルの書き換えには#become:を用いる。ただし、数字や文字列といった定数オブジェクトは置き換えることはできず、定数を置き換える際は定数を保持しているオブジェクトを置き換える必要がある。

| value1 value2 |

value1 := 'hello' asValue.
value2 := value1. "この時点ではvalue2はValueHolder('hello')"
value1 become: 'こんにちは' asValue. "この時点でvalue2はValueHolder('こんにちは')になる"

#become:を使っている良い例はクラスオブジェクトの再登録である。Smalltalkではクラスオブジェクトはインスタンスオブジェクトが生きている間でも再登録可能でなければならず、インスタンスオブジェクトを生きたままクラスオブジェクトを再登録するために使われている。

弱参照

編集

弱参照は参照カウント方式を使う言語でよくライブラリーとして実装されるがSmalltalkではハンドルの制御を用いた言語機能として用意されており相互参照しているが不要になっているオブジェクトを迅速に解放するために使われている。弱参照には#makeWeakを用い、#makeWeakを受け取ったオブジェクトは弱参照となる。

| holder object |
holder := ValueHolder new.
holder makeWeak. "holderが弱参照になる。"
object := Object new.
holder value: object.
ObjectMemory compact. "ごみ回収。この時点ではholder valueはnilではない。" 
object := nil.  
ObjectMemory compact. "ごみ回収。この時点でholder valueはnilとなる。"

カゲロウ(蜉蝣)

編集

(Ephemeron)Smalltalk#key#key#makeEphemeron
| association key |
key := Object new.
association :=
 Association
  key: key
  value: Object new.
association makeEphemeron. "associationがカゲロウになる。"
ObjectMemory compact. "ごみ回収。この時点ではassociation keyとassociation valueは共にnilではない。" 
key := nil.
ObjectMemory compact. "ごみ回収。この時点ではassociation keyとassociation valueは共にnilとなる。"

ここでは連想配列の要素としてよく使われるAssociationを例としているが、カゲロウが消滅する基準は最初のインスタンス変数でクラスに依存しないためどんなクラスでもカゲロウにすることができる。

Smalltalk の慣習

編集

大文字からはじめる識別子と小文字からはじめる識別子

編集
変数名
編集

1使 使
大域変数 大文字からはじめる
大域変数以外(局所変数等) 小文字からはじめる

クラス名が大文字から始まるのは、クラス名が大域変数だからである。

よく使われるクラス以外の大域変数:

  • Smalltalk
  • Processor
  • Transcript
セレクター
編集

セレクターを表す識別子については、基本的に1文字目に小文字を使うが、メソッドが存在するセレクターを避けたい場合は大文字を使う事が慣習になっている。 GNU SmalltakやVisualWorksで用意されている名前空間は、大文字のセレクターを使う典型的な例である。

Smalltalk SystemExceptions InvalidValue signalOn: 0. "「Smalltalk」以外は全てセレクター"

使.使使

オブジェクトの生成と初期化

編集

オブジェクトの生成には #new セレクターを使ったメッセージを使う。他の言語と違い、new は演算子ではない。

|object|

object := Example new. "Exampleクラスオブジェクトに「new」メッセージを送りオブジェクトを生成。"

Smalltalk  new new  new  #basicNew 使Behavior  new  basicNewBehavior

 new 使 new 使 new使instance creation
| number |

number := Number readFrom: '10'. "readFrom:がインスタンス・クリエイション".

Smalltalk では1個のセレクターに対し1個のオブジェクトから複数のメソッドを関連付けられない[注釈 3]ため 「new」メッセージの送信によりできる初期化は1個のオブジェクトにつき一通りの初期化だけである。このため複数のインスタンス・クリエイションを用意することで用途に応じた複数の初期化方法を提供しているのである。インスタンス・クリエイションは一般的なメソッドのひとつでしかない。このためインスタンス・クリエイション持つクラスオブジェクトはアブストラクト・ファクトリーとして機能する。

具体的には次のように使われる。

defaultDatabase
	"既定のデータベースのクラスオブジェクトを定義した派生クラスで再定義可能なメソッド。
	 オーバーライドされた際は、必ずしもクラスオブジェクトが返されるとは限らず、インスタンス
	 オブジェクトが返される場合もある。"
	^ PostgreSQL.
database
 "databaseへの接続を返すメソッド。
  defaultDatabaseにより返されたPostgreSQLに対し、インスタンス・クリエイションである
  #connect:セレクターを使ったメッセージが送られ、PostgreSQLのインスタンスオブジェクトが生成される。
  ただし、defaultDatabaseは、派生クラスによって再定義できるため、#connect:セレクターを使ったメッセージが
  必ずしもPostgreSQLクラスオブジェクトに送られるとは限らない。"
 ^ self defaultDatabase connect: self configuration.

また、Smalltalk はクラスメソッドを上書きできるため、インスタンス・クリエイションを次の様に実装する事で基本的な初期化処理を派生元のクラスに任せることができる。

x: aX y: aY
	^ self new
		x: aX;
		y: aY.

上記は、2次元座標用のクラスオブジェクトのインスタンスオブジェクトを初期化する派生元のクラスオブジェクトに実装されたインスタンス・クリエイションである。このクラスオブジェクトを継承した2次元座標用のクラスオブジェクトでは#x:y:セレクターを使ったメッセージに対応するメソッドを実装する必要はない。インスタンス・クリエイションを利用したパターンは Smalltalk では広く利用され、いたる所で見ることが出来る。

アクセッサー

編集

Smalltalk では、単一の値を出し入れするメッセージの事を特にアクセッサ―[注釈 4]と呼ぶ。引き数の有無により値の入出の方向を区別する。

例:

コード 意味
object value. オブジェクトから値を取得する
object value: 10. オブジェクトに値を渡す

Smalltalk においてアクセッサーはその他のメソッドと役割に違いはなく特別な意味を持たないが、プロトコルとして明示的に accessingアクセッシングとして登録される点が特徴的である。

Smalltalk においてアクセッサーはインスタンス変数の出し入れや、クラス変数の単純な出し入れに使用される事は多くない。Smalltalk においてアクセッサーは次の用途でよく使われる。

目的 詳細
インスタンス変数やクラス変数の初期化 インスタンス変数やクラス変数からの値の取得時にインスタンス変数やクラス変数が nil であればそれらの変数を初期化する。
使用するクラス・オブジェクトの抽象化 クラス・オブジェクトあるいはファクトリーオブジェクトを取得できるアクセッサ―を用意し、アクセッサ―を派生クラスでオーバーライドする事で派生クラスからオブジェクトの生成に使うクラス・オブジェクトを自由に切り替えられるようにする。
保管場所の抽象化 オブジェクトが、インスタンス・クラス・プールのどこで管理されているかを抽象化する意味がある。例えばクラス変数やプール辞書の操作では、クラス変数やプール辞書の操作目的であってもインスタンスオブジェクトのメソッドとしてアクセッサーを用意する。
インスタンス変数やクラス変数に対する委譲 インスタンス変数やクラス変数に対しメッセージを送るアクセッサ―を定義し、複数の箇所でインスタンス変数やクラス変数に対する同じメッセージ送信をしないようにする。これによりself object value value: 1.というような複雑なメッセージをself value: 1.というメッセージに単純化する。

定数

編集

定数は、単に定数を返すアクセッサ―で定義する。C言語の影響を受けた言語のように定数を#defineや変数で定義するという慣習はない。

附帯情報

編集

Smalltalk では、非常に利用頻度の低いインスタンス変数やクラス変数を管理する方法として附帯情報(: property)というパターンが使用される。附帯情報はインスタンス変数やクラス変数などの内部変数の代わりに連想配列によりオブジェクトを保持する仕組みである。

附帯情報の使用例:

Tag methodsFor: 'accessing'
!
id
	^ self valueOfProperty: #id.
!
id: aString
	self setProperty: #id toValue: aString.
!!

XMLHTMLHTML id onClick 使HTML使 onClickonMouseDownonMouseUp鹿 Smalltalk 使

 Self JavaScript  Smalltalk ()

 Self  JavaScript 使Smalltalk HTML使使使[30]

単純な例外処理

編集

Smalltalk 以外の言語において、配列の範囲外にある配列要素の操作や、値の代入されていない連想配列の操作は、次の例のように操作の前に一旦判定を行なって例外処理するか、例外機構を利用する方法が一般的である。

| key |
key := #phoneNumber.
( map contain: key ) ifTrue: [ ^ map at: key ] ifFalse: [ ^ nil ].

一方 Smalltalk では、配列の範囲外操作の様に単純で頻発するような処理では、次のように予めメッセージに例外処理をブロックとして渡してしまう方法が一般的である。

"#phoneNumber に対応する値が無ければ常に nil を返す。map 自身に #phoneNumber が追加される事はない。"
^ map at:#phoneNumber ifAbsent: [ ^ nil ].



Smalltalk 


| value |

value := map at:#phoneNumber ifAbsent: [ ^ self ].
Transcript
	show: value;
	cr.

ブロックによる資源の開放

編集

SmalltalkC#usingusingnew
"Pharo"
'example.txt' asFileReference writeStreamDo: "example.txtを開く"
[ :writeStream |

	writeStream nextPutAll: 'text'.

]. "example.txtを閉じる(例外発生時も閉じる)"
"GNU Smalltalk"
'example.txt' asFile withWriteStreamDo: "example.txtを開く"
[ :writeStream |

	writeStream nextPutAll: 'text'.

]. "example.txtを閉じる(例外発生時も閉じる)"

要素の列挙

編集

Smalltalk 使Smalltalk : enumerating使




#( 4 3 2 1 0 ) do:
[ :each |
	"配列の要素が1個ずつ each に代入され表示領域(Transcript)に表示される"
	Transcript
		show: each;
		cr.
].

実行結果:

4
3
2
1
0

数値に対する列挙メッセージの例:

( 0 to: 4 ) do:
[ :each |
	"配列の要素が1個ずつ each に代入され表示領域(Transcript)に表示される"
	Transcript
		show: each;
		cr.
].

実行結果:

0
1
2
3
4

使 #do:  #collect:  #select: #detect:ifNone:  #groupBy:having: SQLSmalltalk  foreach yeildLINQ Smalltalk 

オブジェクトの変換

編集

Smalltalkでは一般的にオブジェクトに#as〜というセレクターを使ったメッセージが送られた場合、オブジェクトを別のクラスのオブジェクトに変換する。例えば次の様な変換がある。

Stringの変換による具体例(変換結果は処理系依存):

'abcd' asSymbol.      "→Symbolクラスのオブジェクト"
'10' asInteger.       "→SignedIntegerクラスのオブジェクト"
'10:00' asTime.       "→Timeクラスのオブジェクト"

"以下は処理系によっては存在しない"
'/home' asPath.       "→AbsolutePathクラスのオブジェクト"
'http://example.com' asUrl. "→Urlクラスのオブジェクト"

オブジェクトを別のオブジェクトに変換するメソッドやメンバー関数が用意されている事は、Smalltalkに限らず他の言語でも一般的であり珍しい事ではない。Smalltalkの慣習として特徴的なところは、既存のクラスにこのオブジェクトの変換をユーザーやライブラリーの作者が自由に組み込んでいる所である。例えばSmalltalkの処理系であるPharoでは、初期状態で基本的なクラスであるStringに54個ものas〜で始まるメソッドが定義されている。この大量の変換メソッドは、メソッド追加した際すぐに影響を判断できるためメソッド追加に対し寛容的なSmalltalk独特の空気を象徴している。しかし、既存のクラスにメソッドを追加すればライブラリーを併合した際、意図しない衝突を生むため多用は避けるべきであるとの意見も存在する。[30]

オブジェクトの変換はただオブジェクトの内部表現の変換だけでなく情報の加工にも使われる。

オブジェクト変換による具体例:

#( 2 1 2 3 1 3 ) asSortedCollection asSet. "-> #( 1 2 3 )"

セレクターとオブジェクトを指定したイベント処理

編集

イベントハンドラーを定義する方法として、Smalltalkでは次のようにセレクターと、レシーバーとなるオブジェクトを指定する方法が一般的である。

| view controller |
view := Morph new.
controller := FileControlHandler withOwnerView: view.

"#click:イベントが発生すると、controllerに対し#open:を使ったメッセージを送る。"
view
	handler
		on:	#click:
		send:	#open:
		to:	controller.

同様にイベントハンドラーを指定する別の方法としては、ブロックを指定する方法が考えられる。しかし、イベントハンドラーにブロックを使う方法は、セレクターとオブジェクトを指定する方法のようにinspectだけでブロックを抱えたオブジェクトがどんな処理を実行するか判断できないうえ、ほとんどの環境はブロックの直列化に対応しておらず直列化もできなくなってしまうため、Smalltalkの文化においては避けるべきとされる。[30]

このセレクターとオブジェクトを指定したイベント処理の方法は、Objective-Cの文化にも引き継がれておりCocoa等のライブラリーにて頻繁に目にすることができる。

MVCとMVCから派生した設計方式

編集

Model View Controller(MVC)は Smalltalk から生まれた、制御(コントローラー)と情報(モデル)、そして情報の表現方法(ビュー)の3つを分離しクラスオブジェクトの再利用性を高め、実行時に情報と表現の組み合わせを変更できるようにした設計方針である。Smalltalk の世界でMVCは更に表現を担当するクラスに既定の制御を取り込む仕組みを持たせることで PluggableMVC へと発展した。

モデル支援機構

編集

Smalltalk はクラスライブラリーの基礎部分からMVCやMVCから派生した設計方式で使用されるモデルの構築を支援する仕組みを持っており、Smalltalk 以外の言語と比べモデルの構築が格段に楽になっている。次にモデルの動作を確認する最低限のコードを示す。

モデルの登録:

"単純なモデルのクラスオブジェクトを登録"
Object
	subclass:		#ValueHolderModel
	instanceVariableNames:	'value'
	classVariableNames:	''
	poolDictionaries:	''
	category:		'Models'.

ValueHolderModel class methodsFor: 'accessing'
!
defaultValue
	^ 0.
!!

ValueHolderModel methodsFor: 'accessing'
!
value
	value isNull: [ model := self class defaultValue. ].
	^ value.
!
value: aValue
	value := aValue.
	self changed: #value.
!!

モデルの監視側登録

"モデルを監視する単純なクラスオブジェクトを登録"
Object
	subclass:		#ValueHolderObserver
	instanceVariableNames:	'model getSelector'
	classVariableNames:	''
	poolDictionaries:	''
	category:		'Models'.

ValueHolderObserver class methodsFor: 'accessing'
!
defaultModel
	"model が nil の場合に使用する既定のモデルを返す"
	^ ValueHolderModel.
!!

ValueHolderObserver methodsFor: 'accessing'
!
value
	model ifNil: [ ^ nil ].
	"modelから指定のセレクターで値を取り出す"
	^ model perform: getSelector.
!
getState: aGetSelector
	"モデルから値を取り出す際のセレクターはシンボルにより外部から指定する"
	getSelector := aGetSelector.
!
model
	"現在監視対象となっているモデルを返す"
	model isNull:
	[
		model := self class defaultModel new.
		model addDependent: self.
        ].
	^ model.
!
model: aModel
	"現在監視対象となっているモデルを監視対象から除去し、
	 aModelに指定されたオブジェクトを監視対象として追加する。"
	self model removeDependent: self.
	model := aModel.
	self model addDependent: self.

	"また、通常は新しいモデルからValueHolderObserverにとっての初期値の読み取りを行う。
	 ここでは、初期値の読み取りの代わりにモデルが持つvalueオブジェクトの内容を表示Window(Transcript)に表示する。"
	Transcript
		show: self value asString;
		cr.
!!

ValueHolderObserver methodsFor: 'updating'
!
update: anAspect
	"モデルが存在しないときは更新しない"
	model ifNil: [ ^ nil ].

	"モデルが更新されると呼び出され、モデルが持つvalueオブジェクトの内容を表示Window(Transcript)に表示する。"
	getSelector = anAspect ifTrue:
	[
		Transcript
			show: self value asString;
			cr.
	].
!!

ValueHolderObserver class methodsFor: 'instance creation'
!
on: aModel getState: aGetSelector
	^ self
		getState:	aGetSelector;
		model:		aModel.
!!

動作の確認:

| model observer |

model := ValueHolderModel new.

"監視対象にmodelを指定してobserverを生成。
 on:getState:内にてmodel valueが返す値、0が表示Window(Transcript)に表示される。"
observer := ValueHolderObserver
 on:  model
 getState: #value.

"modelの値を更新。observerの#update:が実行されmodel valueが返す値、100が表示Window(Transcript)に表示される。"
model value: 100.

モデルの支援機構は全て Object クラスオブジェクトに実装されており、全てのオブジェクトはモデルとして動作する。つまりクラスオブジェクトもモデルとして使用できるようになっている。

Morphic方式

編集

PluggableMVC  Self 1 Morphic Self  Morphic  Smalltalk Squeak Smalltalk GUISelf  Morphic DOM JavaScript 

脚注

編集

注釈

編集
  1. ^ : Cincom
  2. ^ あるいは単に「セレクター」。
  3. ^ 他の言語でいうメソッドの多重定義はできない。
  4. ^ : accessor

出典

編集


(一)^ abhttp://web.cecs.pdx.edu/~harry/musings/SmalltalkOverview.html

(二)^     1988810346ISBN 4-89362-035-5 

(三)^ https://www.infoq.com/jp/news/2010/07/objects-smalltalk-erlang

(四)^ http://smalltalk.cincom.jp/main/about-us/smalltalks-past/

(五)^ http://www.smalltalk.org/smalltalk/history.html

(六)^ http://stephane.ducasse.free.fr/FreeBooks/BlueBook/Bluebook.pdf

(七)^ abhttp://worrydream.com/EarlyHistoryOfSmalltalk/

(八)^ Reviving Smalltalk-78

(九)^ abhttp://www.cincomsmalltalk.com/main/developer-community/trying-cincom-smalltalk/try-cincom-smalltalk/

(十)^ http://smalltalk.cincom.jp/tutorials/primers/Introduction/Namespace.ssp

(11)^ http://smalltalk.cincom.jp/tutorials/vw7.7/tutorial2/vwparcels2.ssp

(12)^ http://www.pharo-project.org/about

(13)^ http://strongtalk.org/

(14)^ http://pleiad.cl/research/software/gradualtalk

(15)^ http://amber-lang.net/

(16)^ http://www.object-arts.com/downloads/docs/index.html

(17)^ http://www.object-arts.com

(18)^ https://sites.google.com/site/jniport/documentation/jniport-for-visualworks

(19)^ http://missionsoft.com/

(20)^ http://www.refactory.com/tools/sharp-smalltalk

(21)^ Does IBM offer support for VisualAge Smalltalk?. 20181016

(22)^ http://www.objectconnect.com/stmtvc_info.htm

(23)^ SuperASCII 19911, p. 108-112.

(24)^ [1]

(25)^ Pharo source documentation (). magaloma.seasidehosting.st. 201893

(26)^ https://www.gnu.org/software/smalltalk/manual/gst.html#Performance

(27)^ ImplementationLimits7x.pdf(VisualWorks)

(28)^ https://www.gnu.org/software/smalltalk/manual/html_node/Special-objects.html#Special-objects

(29)^ https://www.gnu.org/software/smalltalk/manual-base/html_node/Object_002dbuilt-ins.html#Object_002dbuilt-ins

(30)^ abc Smalltalk  ISBN 978-4894717541

参考文献

編集
  • 「SuperASCII 1991年1月号」第2巻第1号、株式会社アスキー出版、1991年1月1日。 

関連項目

編集

外部リンク

編集