vieweditattachhistorytopchangessearchhelp

第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)


Congratulations! 以下の 1 ページから参照されています。

This page has been visited 903 times.