Object#to_bool
「Why Every Ruby Developer Should Learn Smalltalk(なぜ全てのRuby開発者がSmalltalkを学ぶべきなのか)」っていう文章がtwitterで流れてきたので読んでみた。概ね同意。みんなSmalltalkを学ぶべき。
で、その中にこんな一文があった。
みんなよくRubyでは0や空配列が真と見なされることに文句を言う。
if [] puts 'true' else puts 'false' end
そもそも空配列や0が偽と見なされる方が変じゃないのかとか、この動作が簡単に変えられたらメンテで死ぬとか色々と思うことはあるけど、例えばcase/whenでの比較は===メソッドを再定義することで変えられるので、if/unlessにも動作を変える手段があってもいいんじゃないか。
ということでやってみた。if/unlessは条件のto_boolを呼び出してから分岐する。
parse.yの一部。
| k_if expr_value then compstmt if_tail k_end { /*%%%*/ $$ = NEW_IF(NEW_CALL(cond($2), rb_intern("to_bool"), 0), $4, $5); fixpos($$, $2); /*% $$ = dispatch3(if, $2, $4, escape_Qundef($5)); %*/ }
prelude.rb
class Object def to_bool self end end
試してみる。
class Array def to_bool not empty? end end print '[] is ' if [] puts :true else puts :false end print '[1] is ' if [1] puts :true else puts :false end class Integer def to_bool 0 != self end end puts "0 is #{0 ? :true : :false}" puts "1 is #{1 ? :true : :false}"
実行。
$ ./ruby -Ilib -I. sample.rb [] is false [1] is true 0 is false 1 is true
実装はともかく、動作としてはこれはこれでありかも。
ちなみにこんなこともできる。
class TrueClass def to_bool false end end class FalseClass def to_bool true end end puts 'true?' if true puts 'false?' if false
実行。
$ ./ruby -Ilib -I. sample.rb false?
いい具合にカオス。