OKLab
Smalltalk入門
目次
- はじめに
- 動作環境
- 対象者
- Smalltalkとは?
- 環境構築
- 最終目的
- 環境設定
- コメント
- コーディング規約
- 基本構造
- ハローワールド
- データ形式
- 演算子
- 配列
- I/O
- 制御構造
- API
- クラス
- クラスの初期化と開放
- インスタンス変数・インスタンスメソッド
- クラス変数・クラスメソッド
- アクセス制御( Access Privilege )
- 継承(Inheritance)
- ポリモーフィズム(Polymorphism)
- クラスオブジェクト
- オーバーライド(Override)
- オーバーロード(Overload)
- インタフェース
- セレクタ
- カテゴリ
- その他
- デバック
- 最後に
- 参考資料
はじめに
動作環境
対象者
Smalltalkとは?
環境構築
tar -zxvf smalltalk-2.1.8 # cd smalltalk-2.1.8 # ./configure --disable-gtk # make # make install
今回は、コンパイル時にエラーがgtkがらみで発生したので--disable-gtkというオプションをつけてコンパイルを通しました。
最終目的
Smalltalk版2c(バイナリクロック)の作成をします。オブジェクト指向の源流を学びます。
環境設定
GNU Smalltalkはimage pathとkernel pathを環境変数で定義できます。
環境変数SMALLTALK_IMAGEが定義されていないと、デフォルトでは/usr/local/share/gnu-smalltalkを確認します。
環境変数SMALLTALK_KERNELが定義されていないと、デフォルトでは/usr/local/share/gnu-smalltalk/kernelを確認します。
[s-okita@localhost s-okita]$ gst -v GNU Smalltalk version 2.1.8 Copyright 2003 Free Software Foundation, Inc. Written by Steve Byrne (sbb@gnu.org) and Paolo Bonzini (bonzini@gnu.org) GNU Smalltalk comes with NO WARRANTY, to the extent permitted by law. You may redistribute copies of GNU Smalltalk under the terms of the GNU General Public License. For more information, see the file named COPYING. Using default kernel path: /usr/local/share/smalltalk/kernel Using default image path: /usr/local/share/smalltalk
コメント
コーディング規約
基本構造
ハローワールド
[s-okita@localhost s-okita]$ gst GNU Smalltalk ready
st> 'hello world' printNl ! 'hello world' 'hello world' st>
GNU Smalltalkをインストールするとgstコマンドが使えるので、実行するとst>というプロンプトが表示されます。上記コマンドを入力するとHELLOWORLDが表示されます。このst>プロンプトは^D(control-D)で終了できます。
gstコマンドに-qオプションをつけると、print実行情報が表示されなくなるので1行のみ'hello world'と表示されます。
この例では、Stringオブジェクトの'hello world'を作成し、printNlというというメッセージでオブジェクトに送信( ! )しています。
インタプリタモードではなく、ファイルにSmalltalkのソースコードを記述しても実行できます。
[s-okita@localhost st]$ cat hello_Smalltalk.st 'hello world' printNl ! [s-okita@localhost st]$ gst hello_Smalltalk.st 'hello world'
データ形式
SmalltalkがJavaやC++と決定的に違うのは、インタプリタ言語であるということです。Perlなどのインタプリタ言語が型を意識せずに演算等が可能なようにこの言語もある程度型を意識せずに作成できます。これは、実行時に動的に処理するためには非常に強力な機能です。しかしパフォーマンスがコンパイラ言語や静的に型を持つ言語より劣るという諸刃の剣でもあります。
現在、型を意識せずに且つある程度のパフォーマンスを発揮できる言語としては、Objective-Cなどがあげられます。
今後のサンプルでは、Java, C/C++などに対して、型が存在していないことを意識して取り組んでみてください。
演算子
[s-okita@localhost s-okita]$ gst GNU Smalltalk ready st> ( ( 5 + 5 ) * 2 ) + ( 9 / 3 ) printNl ! 3 23
配列
Smalltalkでは、代入の演算子に=ではなく:=を使います。(Oracle PL/SQLも同様に:=を使ってました)
st> [s-okita@localhost s-okita]$ gst GNU Smalltalk ready オブジェクトをインタプリタ上で保持するための領域確保します st> Smalltalk at: #x put: 0 ! 0 変数xに配列を割り当てます st> x := Array new: 20 ! Array new: 20 "<0x42174178>" 一番目のデータを表示しようとしているが何もないのでnilが表示されます st> (x at: 1) printNl ! nil nil 一番目にデータを格納します st> x at: 1 put: 99 ! 99 もう一度取り出してみます st> (x at: 1) printNl ! 99 99
I/O
制御構造
分岐
他の言語とは非常に異なった書き方をします。
[s-okita@localhost st]$ cat if.st
Object subclass: #ConditionTest
instanceVariableNames:
'count age name'
classVariableNames: ''
poolDictionaries: ''
category: nil
!
!ConditionTest class methodsFor: ''!
new
|r|
r := super new.
r init.
^r
!!
!ConditionTest methodsFor: 'ini'!
init
count := 10.
age := 30.
name := 'helloman'.
!!
!ConditionTest methodsFor: ' if test '!
checkTest
count := count + 1.
!!
!ConditionTest methodsFor: 'print'!
printOn: stream
( count == 10 )
ifTrue: [ 'count is 10' printNl ].
( age == 29 )
ifFalse: [ age printNl ].
( name == 'helloman' )
ifTrue: [ 'count is 10' printNl ].
!!
Smalltalk at: #a put: (ConditionTest new)!
a printNl!
[s-okita@localhost st]$ gst if.st
'count is 10'
30
反復
[s-okita@localhost st]$ cat loop.st
Object subclass: #LoopTest
instanceVariableNames: 'count'
classVariableNames: ''
poolDictionaries: ''
category: nil
!!
!LoopTest class methodsFor: ''!
new
|this|
this := super new.
this init.
^this
!!
!LoopTest methodsFor: ''!
init
count := 0.
!!
!LoopTest methodsFor: ''!
counter
count printNl.
1 to: 5 do:
[:x |
count := count + x.
count printNl.
]
!!
[ LoopTest printNl ] !
[ LoopTest counter ] !
Smalltalk at: #id put: (LoopTest new)!
id counter!
[s-okita@localhost st]$ gst loop.st
0
1
3
6
10
15
API
クラス
[s-okita@localhost objc]$ gst GNU Smalltalk ready スナップショットの保存 st> ObjectMemory snapshot: 'class_sample.im' ! "Global garbage collection... done" ObjectMemory アカウントクラスの作成 st> Object subclass: #Account st> instanceVariableNames: 'balance' st> classVariableNames: '' st> poolDictionaries: '' st> category: nil ! Account comment:でコメントをつけられます。 st> Account comment: 'Account class inheritance Object Class.' !Account コメントの表示 st> (Account comment) printNl !'Account class inheritance Object Class.''Account class inheritance Object Class.' Stringクラス、Integerクラス、Objectクラス、Classクラスのコメントを表示してみます。 既存のクラスのコメントを確認することで概要がわかります。Java/C++にはない機能です。 st> (String comment) printNl !'My instances represent ASCII string data types. Being a very commoncase, they are particularly optimized.''My instances represent ASCII string data types. Being a very commoncase, they are particularly optimized.' st> (Object comment) printNl !'I am the root of the Smalltalk class system.All classes in the system are subclasses of me.''I am the root of the Smalltalk class system.All classes in the system are subclasses of me.' st> (Class comment) printNl !'I am THE class object. My instances are the classes of the system.I provide information commonly attributed to classes: namely, theclass name, class comment (you wouldn''t be reading this if itweren''t for me), a list of the instance variables of the class, andthe class category.''I am THE class object. My instances are the classes of the system.I provide information commonly attributed to classes: namely, theclass name, class comment (you wouldn't be reading this if itweren't for me), a list of the instance variables of the class, andthe class category.'
クラスの初期化と開放
インスタンス生成用のメソッドを作成します。Javaでいうコンストラクタです。
st> !Account class methodsFor: 'instance creation' !Account class newメッセージの動作を定義します。!!で終了です。問題がなければ何も表示されません。問題があるとエラーメッセージが表示されます。st> newst> |r| ローカル変数rの定義st> r := super new. Objectクラスを初期化(new)してr変数に格納st> r init. Accountクラスのinitメソッド呼び出しst> ^r return what r is attached to.st> !! インスタンス化してみます。 st> Account new !Object: Account new "<0x42167d50>" error: did not understand #initAccount(Object)>>#doesNotUnderstand:Account class>>#newUndefinedObject>>#executeStatementsnil initメソッドがAccountクラスにないためエラーになります。そこでinitメソッドを作成します。 st> !Account methodsFor: 'instance initialization'!Accountst> initst> balance := 0st> !! 再度、インスタンス化します。今回は正常にインスタンス化できました。 st> Account new !Account new "<0x42169528>" メモリを確保します。 st> ObjectMemory snapshot: 'class_test.im' !"Global garbage collection... done"ObjectMemory Smalltak a変数にAccountオブジェクトを格納します。st> Smalltalk at: #a put: (Account new) !Account new "<0x421403f8>" a変数をprintNlメソッドで確認してみます。'an Account'と表示されAccountオブジェクトが参照されていることがわかります st> a printNl !an AccountAccount new "<0x421403f8>"
インスタンス変数・インスタンスメソッド
クラス変数・クラスメソッド
- instanceVariableNames:を利用してインスタンス変数を作成します。Smalltalkは型を必要としません。
- methodFor:を利用してインスタンスメソッドを作成します。
- classVariableNames:を利用してクラス変数を作成します。
- class methodFor:を利用してクラスメソッドを作成します。
[s-okita@localhost st]$ cat instance_method.st
ObjectMemory snapshot: 'instance_method.im' !
Object subclass: #Human
instanceVariableNames:
'age'
classVariableNames:
'think'
poolDictionaries: ''
category: nil
!
Human comment: 'Pearent(Base) Class' !
!Human class methodsFor: 'instance creation' !
new
|r|
r := super new.
r init.
^r
!!
!Human methodsFor: 'initializer' !
init
age := 0.
!!
!Human methodsFor: 'old'!
addAge: val1
age := age + val1
!!
!Human methodsFor: 'view'!
printOn: stream
age printOn: stream.
!!
Smalltalk at: #a put: (Human new) !
a addAge: 25!
a printNl !
[s-okita@localhost st]$ gst instance_method.st
"Global garbage collection... done"
25
アクセス制御( Access Privilege )
継承(Inheritance)
[s-okita@localhost st]$ cat instance_method.st
ObjectMemory snapshot: 'instance_method.im' !
Object subclass: #Human
instanceVariableNames:
'age'
classVariableNames:
'think'
poolDictionaries: ''
category: nil
!
Human comment: 'Pearent(Base) Class' !
!Human class methodsFor: 'instance creation' !
new
|r|
r := super new.
r init.
^r
!!
!Human methodsFor: 'initializer' !
init
age := 0.
!!
!Human methodsFor: 'old'!
addAge: val1
age := age + val1
!!
!Human methodsFor: 'view'!
printOn: stream
age printOn: stream.
!!
Smalltalk at: #a put: (Human new) !
a addAge: 25!
a printNl !
Human subclass: #Japanese
instanceVariableNames: 'grace'
classVariableNames: ''
poolDictionaries: ''
category: nil
!
Japanese comment: 'Japanese has graceful hearts.' !
!Japanese methodsFor: 'initializer'!
init
grace := true.
^super init
!!
!Japanese methodsFor: 'instance method definition'!
printOn: stream
grace printOn: stream
!!
Smalltalk at: #b put: (Japanese new) !
b printNl!
[s-okita@localhost st]$ gst -q instance_method.st
"Global garbage collection... done"
25
true
ポリモーフィズム(Polymorphism)
クラスオブジェクト
オーバーライド(Override)
オーバーロード(Overload)
インタフェース
セレクタ
カテゴリ
その他
snapshot(現状の保存)の方法。 GNU Smalltalk User's Guideでは、Smalltalk snapshot:となっているがドキュメントが古いようです。
[s-okita@localhost s-okita]$ gst GNU Smalltalk ready st> ObjectMemory snapshot: 'test_hoge.im' ! "Global garbage collection... done" ObjectMemory
デバック
最後に

