著作一覧 |
次のようなコードがあって、一体なんだ? という話。
obj.foobar? !!baz
で、!!という演算子があるかと思ってGoogleで検索したら、いきなり「!! に一致する情報は見つかりませんでした。」と言われる、即座に。
おれの予想。
きっと、obj#foobar?の実装が腐っていて、苦肉の策ではなかろうか?
たとえば、次のようになっている。Javaプログラマとかだとやってもそれほどおかしかない。
def foobar?(o) o == true end
もし、引数がTrueClassのインスタンスかどうかを判定する目的のメソッドであれば、もちろん正しい実装ではある。
でも、真かどうかを判定しているなら、だめだね。
正しく実装すると
def foobar?(o) o != nil || o != false end
でも、ちょっと冗長だ。単純に、
def foobar?(o) o end
でいいじゃん。でも、いずれにしても、== true
とか書いてあるから、!!(否定によってfalseとなり、それを否定することでtrueとなる)としてTrueClassのインスタンスに変換してから引数としてるんじゃないかな。
いずれにしてもだけど、trueという特殊変数は戻り値、メソッドの引数とかにしか利用しないほうが良い。条件式に記述していたら、たいていは潜在的なバグだと言っても良さそうだ。もちろん == falseというのも、nilを考慮していないからだめだけど。
で、そういう怪しい可能性があるメソッドの引数なので、!!二重否定してTrueClassのインスタンス(あるいはFalseClassのインスタンス)に変換してんじゃないかなぁ、
似たようなのに、COMのC++コンポーネントがVBから正しく呼べないTRUE問題ってのもあったな。
HRESULT STDCALL FooBar(LONG baz) { if (baz == TRUE) ... return S_OK; }
となっているのを、
Set obj = CreateObject("FooBar") obj.FooBar True
とか呼び出すケース。VBのBooleanはVARIANT_BOOL(short)で、TrueはVARIANT_TRUE(-1)だということを、C++小僧が知らないという話。
結局、ベストプラクティスとして、偽(0)かどうかで判定するというのが正解だろう。
HRESULT STDCALL FooBar(LONG baz) { if (baz) ... return S_OK; }
しかも、この方が==演算子とか書かなくて済むだけ簡潔だ。
ジェズイットを見習え |
foobar?の実相としては、条件演算子が使えるなら、o ? true : falseが一番楽じゃないですかね。<br>また、仮説としては、foobar?の結果がfalseとnilで違うとか、0も偽になっちゃうとか。
条件演算子は楽ですね。でも、true、falseって使わなくてもいいんじゃない? ってのが趣旨だから、単に「o」ってのがこの場合はいいと思うんだけど。0が偽になってたら、!!ってやってもtrueだからちょっと違うような。<br>というか、真偽値と == でtrue/falseを比較するって、どのあたりの言語の習慣なのかなぁ。Cじゃないし、Javaでもないし、不思議なんだよね。