こんにちは、今日は Smalltalk 忘年会です。みなさん、忘れないように気をつけましょう!
わたくし、現在は Smalltalk 処理系で ALLSTOCKER というサービスを運用開発しているSORABITO株式会社に務めていまして、プロダクション環境で Smalltalk を運用することでさまざまなことを学んできました。今年のアドベントカレンダーではそれを少し意識して実務で役立ちそうな記事をふたつほど書きました。今回も Smalltalk をプロダクションとして使うときに有効な技を紹介できればと思ったのですが、ちょっと個人的な都合で時間がありません。
ですが、せっかくなので Smalltalk ならではというネタでも書いてみようと思いました。そこで思いついたのが Object>>#becomeForward:
でしたので、今日はそれについて書いてみます。
今日の記事にはきちんとオチがありますので、ぜひ最後までご覧下さいまし。
インスタンスはクラスに属する
よくオブジェクト指向を説明するときに「インスタンスはクラスに属していて、途中で他のクラスになることはない」といった説明が用いられることがあります1。
まあ、当たり前ですよね。イヌがいきなりニャーニャー鳴いたらおかしいわけです。
Smalltalk ではそうとは限らない
その概念をぶち壊すこととができるのが Object>>#becomeForward:
です。
インスタンスを他のクラスに属させるような変更をさせ、振る舞いを変えます。
簡単にコードで説明してみましょうか。
普通にオブジェクトをインスタンス化して代入
Array をインスタンス化して変数に代入、その変数に OrderedCollection を代入してみます。
その前後で Object>>#identityHash
を比較してみることで同一のインスタンスではないことを確認します。
| a |
a := #().
Transcript cr; show: a identityHash.
a := OrderedCollection new.
Transcript cr; show: a identityHash.
a inspect.
当然と言えば当然ですが、 Array と OrderedCollection はインスタンス化されていますから、 Transcript には異なる値がでます。
いま、実行してみたらこんな感じでした。
1066388736
972583936
言うまでもないかもしれないですが、 a inspect.
では空の OrderedCollection を見ることができます。
Object>>#becomeForward:
ところが、同じインスタンスであるにも関わらず属するクラスを変える事が Smalltalk ではできます。
それを可能にするのが Object>>#becomeForward:
です。
上と同じようなことを今度は Object>>#becomeForward:
を使って書いてみます。
| a |
a := #().
Transcript cr; show: a identityHash.
a becomeForward: OrderedCollection new.
Transcript cr; show: a identityHash.
a inspect.
a inspect.
では、同じく空の OrderedCollection を見ることができます。ここで Transcript に表示される値をみてみましょう。
454936320
454936320
なんと!
同じインスタンスであるにも関わらず、振る舞いを Array から OrderedCollection にしてしまえることが分かります。
どんな時に使うの?
この Object>>#becomeForward:
ですが、どんなときに便利かというと、わりと入り組んだ感じに変数を使ってしまっているところで、インスタンスの機能に不具合が発生したときに、代替となるクラスに属させることでフォールバックさせる、といった用途に便利です。
危険なんじゃないの?
何も考えずに使うと危険です。
Pharo 環境などがあれば、以下のようなコードを実行してみましょう。
実行前にはイメージをセーブしてください!!!
| a |
a := true.
a becomeForward: false.
ね。
ということで、ちゃんとオチがある話でした。
お後がよろしいようで。
ではまた。