null 安全が叫ばれるのを横目に nil の賢さを競う


はじめに

近頃、null 安全とやらが流行しているようです。なんでも、null って危ないものだと思われているようです。そんな null について以前 nilは悪か?なるポエムを書きましたが、多勢に無勢、もう心が折れてしまいそうです。
こうなったらもう Smalltalk の世界にヒキコモるしかありません。そこで、Smalltalk の代表的な処理系で nil の賢さについて比較してみました。

比較する処理系

とりあえず、今元気がいい処理系として Pharo 5 と次バージョンとなるべく開発中の Pharo 6、総本山といっていい Squeak 5.1、PARC直系正統派の VisualWorks 7.10.1、そして GNU Smalltalk 3.2.5 を比較してみました。

nilのクラスが定義しているメソッド数

nilがどんなに賢いか。プログラマとしてはコードがオブジェクトを賢くすると思いたい。つまり、メソッドがいっぱい定義されていれば賢いだろうということで、nilのクラスである UndefinedObject が定義しているメソッドの数を比較してみました。次のコードで確認できます。

nil class selectors size

結果は以下の通りです。

処理系 メソッド数
Pharo5 62
Pharo6 57
GNU Smalltak 3.2.5 44
Squeak5.1 40
VisualWorks 7.10.1 38

Pharo たん、賢い!
新旧Pharoのワンツーフィニッシュです。

nilが応答できるメッセージセレクタの数

UndefinedObjectで定義されていなくてもいいじゃないか、Objectとかから継承されていてもいいじゃないか、応答できればいいんだい!というわけで、継承した分もあわせてセレクタ数を数えてみました。

 nil class allSelectors size

結果は

処理系 応答可能セレクタ数
Squeak5.1 511
Pharo6 476
Pharo5 468
VisualWorks 7.10.1 278
GNU Smalltak 3.2.5 157

さすが、Objectの分厚さでいえば Squeak ですね!
9bitの符号なし整数の最大値をマークしました。
Pharoも6が5を抜きました。
そして清く正しい GNU Smalltalk はやはり清く正しかった。

コードの中で nil 判定をしている密度

null 安全どーたらでは、nil 判定はバグの元だそうです。よくわからんけど。
というわけで、標準ライブラリ中の1メソッド当たりの nil 判定の個数を計算して、どの処理系が一番 nil 判定が多いかを見てみましょう。

コードは

 (#isNil senders size + 
  #notNil senders size + 
  #ifNil: senders size + 
  #ifNotNil: senders size + 
  #ifNil:ifNotNil: senders size + 
  #ifNotNil:ifNil: senders size) / 
(Object allSubclasses inject: 0 into: [ :sum :each | sum + each selectors size ]) asFloat

ただし、Squeak と VisualWorks と GNU Smalltalk には Symbol>>senders が定義されてないようなので、それぞれ Symbol に定義してみました。

Squeak5.1
senders
    ^ self systemNavigation allCallsOn: self
VisualWorks7.10.1
senders
    | collector |
    collector := MethodCollector new.
    ^ collector select: (collector referencesTo: self)

GNU Smalltalk は…ごめんなさい、どうしたもんか皆目見当もつきませんでしたわい…orz

さて、結果は…

処理系 nil判定密度
Squeak5.1 0.152
Pharo5 0.107
Pharo6 0.105
VisualWorks 7.10.1 0.088
GNU Smalltak 3.2.5 -

一番 nil 判定を頻繁にやっているのは Squeak 5.1 でした。VisualWorks、nil判定少ないですね。まあいずれにせよ、Smalltalk を書いたらこんぐらいの頻度で nil のことを気にしてみましょうね、ってことなのかな。よくわからないけど。まあ10個メソッドを書いて1回思い出すぐらいならオレにもできそうなので安心しました。

おわりに

どの Smalltalk の nil が賢いか比べるつもりでしたが、どうもあまり大差ないというのが率直な感想です。
差が目立ったのは allSelectors でしたが、これは nil どうこうというよりも、Squeak の Object が肥大化していて、Squeak から派生した Pharo もやっぱり Object がメタボっている、という解釈が一番ピンとくるかなあという感じで、nil の賢さとはちょっと違うような気がします。

というわけで、結論は、
Smalltalkの nil はみんな賢いから、どんどん使おう!
ということで、めでたしめでたし。

追記 (2016/12/19)

Юрий Мироненко さんによる 素敵な nil への対処法。
Protego - smart way to manage nil in business calculation