







第19回
■
■SqueakではじめるSmalltalk入門 第19回
■
本連載では、名前は知っていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。今回は遅延初期化についてです。
前回、生成した直後のオブジェクトa BankAccountがメッセージ「deposit: 100」に正しく反応できないことに(いささかわざとらしく…)気が付き、そのとき表示されるノーティファイアが提供する情報から、数値の束縛が期待されるインスタンス変数balanceにnilが束縛されていたことが原因だということも分かりました。したがって、インスタンス変数balanceに数値を(アクセッサを介して)束縛しておくことで、消極的ではありますが、とりあえずこの問題は解決できそうです。
| account |
account _ BankAccount new.
account deposit: 100 "=> ノーティファイア "
↓
| account |
account _ BankAccount new.
account balance: 0 "インスタンス変数balanceに0を束縛"
account deposit: 100 "エラーは出ない"
^ account balance "=> 100 "
ただ、これではおもしろくないので、アクセッサにひと工夫することにより別の方向から、よりスマートに、この問題を解決する方法を模索してみることにします。今、BankAccount >> #balanceの定義は、
balance
^ balance
と、単純にインスタンス変数balanceを返すだけです。これを「もしbalanceがnilなら、balanceに0を束縛して、あらためてそれを返値とする」…というような遅延初期化を行なうコードに置き換えてしまえば、このメソッドを介してインスタンス変数balanceにアクセスする限り、nilが返ることはなくなります。では、実際にコードを書いてみましょう。
balance
^ balance ifNil: [balance _ 0]
1行目はメッセージパターン(パラメータがないので、メソッド名とも一致)なので変わりません。なお、ブラウザのコードペインでは、メソッド名が既存のものと同じメソッドの定義は、断りなく古いものと置き換わります。バージョンは管理されているので、ファイルの重ね書きのような気の使い方をする必要はありません。
メソッド本体は2行目です。まず、行頭の「^」は無視して考えましょう。改めて書き直すとこうなります。
balance ifNil: [balance _ 0]
初出の#ifNil:で腰が引けてしまうかたもあるかもしれませんが、この式は典型的なメッセージ式です。インスタンス変数balanceに束縛されているオブジェクトに「ifNil: …」というメッセージを送ることを表わします。ここで起動されるメソッド#ifNil:はレシーバがnilならパラメータとして添えられたブロック(手続きのオブジェクト)を評価してその結果を返し、そうでなければレシーバを式の返値とします。したがってこの場合、balanceにnil以外が束縛されていれば、balanceに束縛されているオブジェクトがこの式の返値になり、balanceにnilが束縛されている場合は、ブロックが評価されてその値がこの式全体の返値になります。
ブロックの内容である「balance _ 0」は、インスタンス変数balanceに0を束縛する代入式です。Smalltalkはメッセージ式ですべてを表現するのが原則ですが、代入式は例外でこのように書きます。ただ、Smalltalkにおいて代入の手続きは“式”なので返値があります。それは、変数に代入(束縛)しようとするオブジェクトで、くだんの代入式では「0」がこれにあたります。
改めてまとめると、この式は、インスタンス変数balanceにnil以外が束縛されているときはそのオブジェクトを、nilが束縛されているときはbalanceに改めて0を束縛し、同時に0を返す式…となります。さらに頭に「^」が付いていたので、この式の返値がそのままこの#balanceメソッド(と言っても、メソッドにはこの式しかないのですが…)の返値になります。
このようなBankAccount >> #balanceの改変により、以後生成するa BankAccountはもちろん、すでに存在するインスタンスについても、そのインスタンス変数balanceが未定義か否かに関わらず、メッセージ「deposit: 100」への応答は正常に行なわれるようになるでしょう。これにて一件落着ですね。
一般に遅延初期化という手法は、アクセス頻度の低いプロパティ(インスタンス変数)を多数抱えるオブジェクトで、生成時の初期化のコストを削減しパフォーマンスを稼ぐために用いられるのが普通です。しかし、Smalltalkのように動的な(つまりシステムを止めずに動かしながら改変を加えることが多い)システムでは、すでに運用中のオブジェクトに対し、インスタンス変数やアクセッサを比較的安全に追加できる…というメリットが加わります。
次回は最後のメソッド#withdraw:を追加して、このBankAccountを完成させます。
このページを編集 (4002 bytes)
 |
以下の 1 ページから参照されています。 |
This page has been visited 907 times.