クロージャ、クロージャ

日これ より。Gaucheクロージャでオブジェクトを作って遊んでおられるのを見かけたので、ClosureComplierクロージャを使えるようにした Squeak システムの Smalltalk にて(ほぼ)同じものを書いて私も遊んでみました。

openAccount
openAccount _ [: balance | [: selector : amount | selector caseOf: { [#withdraw] -> [ balance >= amount ifTrue: [balance _ balance - amount] ifFalse: [self notify: 'insufficient funds']. balance]. [#deposit] -> [ balance _ balance + amount. balance]} otherwise: [ self notify: 'no such selector : ', selector printString. balance]]]. Smalltalk at: #myAcc put: (openAccount value: 1000)
myAcc value: #withdraw value: 300    " => 700 "
myAcc value: #deposit value: 200     " => 900 "
myAcc value: #withdraw value: 1000   " => insufficient funds "
myAcc value: #account value: 0       " => no such method : #account "

こうやって(ブロック)クロージャでオブジェクトを容易に作成可能なことを目の当たりにすると、クラスって何? とか、Smalltalk における“スタイルの結晶化*1”もまだまだだな… and/or Smalltalk の目指しているところの“スタイル”って何? 的なところに思いを馳せることができたりして、おもしろいですよね。

SqueakSmalltalk によるオブジェクト版

ちなみにクラスを使って書くと、スクリプトはこんな感じで、

myAcc
myAcc _ Account openWith: 1000. Smalltalk at: #myAcc put: myAcc
myAcc withdraw: 300    " => 700 "
myAcc deposit: 200     " => 900 "
myAcc withdraw: 1000   " => insufficient funds "
myAcc account          " => MessageNotUnderstood: Account>>account "

定義は(セッターで balance を返してしまっているなど、Smalltalk の流儀からはハズれてしまっていますが、あくまでオリジナルの仕様に忠実に…ということだと)こんな感じになりましょうか。Squeak システムへコピペして fileIn selection (alt-/cmd- shift-g) できます。

Object subclass: #Account
   instanceVariableNames: 'balance '
   classVariableNames: ''
   poolDictionaries: ''
   category: 'Category-Account'!

!Account methodsFor: 'accounting'!
deposit: amount
   balance _ balance + amount.
   ^ balance! !

!Account methodsFor: 'accounting'!
withdraw: amount
   balance >= amount
   	ifTrue: [balance _ balance - amount]
   	ifFalse: [self notify: 'insufficient funds'].
   ^ balance! !

!Account methodsFor: 'private'!
setBalance: amount
   balance _ amount! !

!Account class methodsFor: 'instance creation'!
openWith: amount
   ^ self new setBalance: amount! !


SELF で同じものを書いてみるのも、また、いろいろと考えるところが出てきそうで楽しそうですね。

SELF によるオブジェクト版

ということで、さくっと SELF でも書いてみました。

globals _AddSlots: (| account = (). myAcc |)
account _Define:
   (| balance <- 0.
      withdraw: amount = (
         balance >= amount
            ifTrue: [balance: balance - amount]
            False: ['insufficient funds' printLine].
         balance).
      deposit: amount = (
         balance: balance + amount.
         balance).
   |).
myAcc: (account _Clone balance: 1000)
myAcc withdraw: 300    " => 700 "
myAcc deposit: 200     " => 900 "
myAcc withdraw: 1000   " => insufficient funds "
myAcc account          " => No 'account' slot found in an object. "


*1:「スタイルの結晶化」  Programming languages can be categorized in a number of ways: imperative, applicative, logic-based, problem-oriented, etc. But they all seem to be either an "agglutination of features" or a "crystallization of style." COBOL, PL/1, Ada, etc., belong to the first kind; LISP, APL-- and Smalltalk--are the second kind. The Early History of Smalltalk より