2008年1月17日木曜日

Smalltalk入門.オブジェクト指向の始祖だよね.

久しぶりの更新.卒論がねぇ・・・.(いいわけにつき,以下略.

今回は,Smalltalkの入門について.Simulaはどうしたといわれそうなタイトルだな.まあ,僕の中ではSmalltalkが始祖なんだって.

なんで,Smalltalkって思う人もいるかもしれないんだけど,オブジェクト指向について考えててぶつかったからなんだよね.(「オブジェクト指向における再利用のためのデザインパターン」を読んでるせいもある.)オブジェクト指向の始祖であるSmalltalkのオブジェクト指向ってのが,いま主流のC++とかJavaとかのクラスベースオブジェクト指向とJavaScriptとかSelfとかのプロトタイプベースオブジェクト指向のどちらとも違うってところでね.だけど,どこが違うとかの情報がなくて,どう違うのかがいまいちピンとこないから,実際に書いてみればわかるはずだってことで,Smalltalk入門ってなわけだ♪

処理系は,MacPortsで,GNU Smalltalkをインストール.(MacPortsを$ sudo port selfupdateしてからインストールしよう.なんか,アップデート前はIntel Macに対応してないとかで,インストールできなかった・・・.)
$ sudo port -c install gst


とりあえず,起動,Hello, world!,終了をやってみた.
$ gst
GNU Smalltalk ready

st> 'Hello, world!' printNl(「Hello, world!」文字列オブジェクトにprintNlメッセージを送信する.)
'Hello, world!'(表示結果.)
'Hello, world!'(評価結果の戻り値.)
st> ObjectMemory quit(終了方法.)
$


Hello, world!は,ほとんど普通の言語と同じだねぇ・・・.普通の言語は述語,主語の順だけど,Smalltalkは主語,述語の順ってかんじだね.

さてと,つぎはお約束の階乗計算プログラム♪っていつもなら軽いノリで書くんだけど,Smalltalkのプログラミングはかなり苦戦した〜.その苦戦したソースをどうぞw
Integer extend [
factorial [
self = 0 ifTrue: [ ^1 ].
self > 0 ifTrue: [ ^(self - 1) factorial * self ].
]
]

10 factorial printNl.


これは,既存のIntegerクラスを拡張して,factorialメソッドを追加する(実際は,factorialメソッドが存在するのでオーバライドになる.)という意味.末尾の10 factorial printNlでメッセージ送信をしてて,10っていうIntegerインスタンスへfactorialメッセージを送信し,その結果にprintNlメッセージを送信しているってかんじ.10は,factorialメソッドでいうところのselfになって,再帰されるようなね,そんな感じだと思う・・・たぶん・・・.

実行結果は当然普通だ.
$ gst factorial.st
3628800
$


Smalltalkって言語と環境ってこともあるせいか,処理系によって方言がある模様.ってかそもそも,Smalltalkのシステムブラウザから追加するもんだから,GNU Smalltalkは独自の記述に近いのね・・・.悩ましいなぁ.それに,GNU Smalltalkで解説してるとこってほとんどないんだね.やっぱり,Squeakが多いみたい.まだまだわからないことだらけだなぁ・・・.

FizzBuzzもやってみたけど,ひどいな・・・.
| fizzbuzz |
fizzbuzz := [
(1 to: 100) do: [ :n |
n \\ 3 = 0 ifTrue: [
n \\ 5 = 0 ifTrue: [
'FizzBuzz' printNl.
] ifFalse: [
'Fizz' printNl.
].
] ifFalse: [
n \\ 5 = 0 ifTrue: [
'Buzz' printNl.
] ifFalse: [
n printNl.
].
].
].
].

fizzbuzz value.


無理矢理4つに分岐させるようなコードを書いたかんじ.Smalltalkerはこれをどうやって書くんだろう.まだまだ理解不足だね.

うむぅ.不出来すぎるんで,Squeak本読んで出直してこよう・・・.Smalltalkの考え方についていけてない.必要なのは,オブジェクト脳っていうよりSmalltalk脳?

参考文献:
GNU Smalltalk User's Guide
Smalltalkイディオム

7 件のコメント:

sumim さんのコメント...

お邪魔します。いろいろと方法はありそうですが、こんなのはいかがでしょう。(インデントは全角スペースなので置き換えてください)

Integer extend [
 asFizzBuzz [
  | stream |
  stream := String new writeStream.
  self \\ 3 = 0 ifTrue: [stream nextPutAll: 'Fizz'].
  self \\ 5 = 0 ifTrue: [stream nextPutAll: 'Buzz'].
  ^stream isEmpty
   ifTrue: [self printString]
   ifFalse: [stream contents]
 ]
]

1 to: 100 do: [:n | n asFizzBuzz printNl]

Takuya Tsuchida さんのコメント...

おおぉ,すばらしい.

FizzBuzzの結果を文字列として返すメソッドasFizzBuzzをIntegerに追加して,1から100までの結果を出力.

asFizzBuzzは,文字列ストリームに3で割り切れるなら'Fizz',5で割り切れるなら'Buzz'を追加して,文字列ストリームが空だったら,自分自身を返し,文字列ストリームが空じゃなかったら文字列ストリームの中身を返す.

という感じでしょうか.'FizzBuzz'という文字列がプログラム中に現れないのがすごい.とかなんとか思っていたら,suminさんのsumim’s smalltalking-tosのFizzBuzz関連のエントリを見てさらにびっくり.いやぁ,まだ僕の力では理解できそうにありません.

sumim さんのコメント...

FizzBuzz の一般化とかの記事ですかね。あれはマニアックに過ぎるのでスルーしていいと思います(^_^;)。

ただ FizzBuzz 自体は意外と奥が深いので、それぞれの言語(この場合 Smalltalk)の特徴をいかした書き方を、頭を柔らかくしていろいろと考えて、じっさい動作するか試してみるのも面白いし、勉強になると思います。

Takuya Tsuchida さんのコメント...

たしかにマニアックなかんじですねwでも,そこに惹かれてしまいます.

コードを短くっていう方向だけじゃなく,あえてトリッキーに書くというのは面白そうですね.sumimさんからコメントにいただいたプログラムのように,Smalltalkらしい読みやすい書きかたというのも重要ですね.

それにしても,Smalltalkはこれほど興味深いのに,日本ではあまり情報がないような気がしますね.僕のまわりでもSmalltalkを知っている人はいますが,書いたことがあるという人はいないみたいです.僕としては,Prologに出会ったとき以来のエキサイティングな言語なんですけどねぇ.

Takuya Tsuchida さんのコメント...

すみません.最初のコメントで「suminさん」とかいてますね.失礼しました.「sumimさん」ですよね.

sumim さんのコメント...

いえいえ。名前の件はお気になさらずに。

私も Smalltalk の情報の少なさ、特にネットでの露出の少なさは以前から気になっているところです。

そんなわけで、TSUCHIDA さんもよければ是非、GNU Smalltalk での試行錯誤の過程と成果をどんどんブログにエントリーしてください!

Takuya Tsuchida さんのコメント...

そうですね.GNU Smalltalkでやってみた成果をできる限り公開していければなぁと思います.

Smalltalkの情報が少しでも増えれば,興味を持つ人も増えてくれるはずですしね♪