きりかノート 3冊め

おあそびプログラミング

RubyCocoa プログラミングでバグを減らすアイディア

MiniKidsGames の Tat さんとのコメントのやりとりで思いついたのだけれど、「nil が来ないことを期待されているところで nil を渡されてしまうことによるクラッシュ」を減らすためのちょっとしたアイディアが浮かんだ。

通常、Cocoa のメソッドでパラメータに nil を渡してはいけないものに nil 渡すと NSInvalidArgumentError が発生する。なので、それでわかるのだけれど、ここでハマリがちなのが、Array -> NSArray や Hash -> NSDictionary への自動変換だ。ちょっと試してみると

 % irb -r osx/cocoa
irb> ary = [1, nil, 3]
=> [1, nil, 3]
irb> nsary = OSX::NSArray.arrayWithArray(ary)
2006-12-09 07:43:40.565 irb[13501] *** Uncaught exception: <NSInvalidArgumentExc
eption> *** -[NSCFArray addObject:]: attempt to insert nil
zsh: trace trap irb -r osx/cocoa

とまあこうなったりする。これはどこが問題かわかりにくいので、変換時 (framework/src/objc/ocdata_conv.m の中の処理) で明示的に例外を出すようにしたほうがいいんじゃないかと思うのだ。これで、配列にいれた要素が予期せず nil になっているときは Cocoa 側には渡せないってことになる。

悩むのは NSDictionary ではキー、値とも nil は禁止なのだけど、値には NSNull が利用できるってところだな。nil のとき、これを NSNull で置き換えてよいかなあ。

(以下 2006.12.09 追記)

[rubycocoa-devel:481] で提案とパッチ。個人的な見解としては例外にすること自体は全然問題はなくって、あとは例外のクラスが ArgumentError でいいかどうかってあたりが議論したいとこ。この例外が発生するのは、Ruby から Objective-C 側に渡すときだけだから ArgumentError であるってのはそんなにおかしくはないと思うのだけれど、もっと適したものがあるかもしれない。

今回の実装では、ハッシュの値は NSNull に変換するようにした。これでなにか問題になるようなら、-w や -d でメッセージを冗長にしたとき NSNull への変換に関するメッセージを出力するようにすればいいかなと考えている。