やはりEnumerable#empty?は、汚染無しで可能でした

Enumerable#empty?は、汚染なしに可能かの続き。
Twitterでn0kadaさんから、もっとエレガントな書き方があると教えてもらいました。
(ありがとうございます!>n0kadaさん)

Owner@fam ~ $ /usr/local/ruby-1.8.1/bin/ruby -ve '
p [].any?{true} # => false
p [1].any?{true} # => true
'
ruby 1.8.1 (2003-12-25) [i386-cygwin]
false
true
Owner@fam ~ $ /usr/local/ruby-1.9.0-2/bin/ruby -ve '
p [].any?{true} # => false
p [1].any?{true} # => true
'
ruby 1.9.0 (2008-06-20 revision 17482) [i386-cygwin]
false
true

1.8系以降なら使えるEnumerable#any?を使うという方法。

あれだけ汚いコードを書いていたのがバカらしくなってきてしまいます。

せっかくなので、なんとなく1.4系で動くか試したところ、1.4系にはany?はない模様。

C:\develop\Language\ruby-1.4>ruby -ve 'p [].any?{true}'
ruby 1.4.6 (2000-08-16) [i386-mswin32]
C:\DOCUME~1\Owner\LOCALS~1\Temp/rba03860:1: undefined method `any?' for []:Array (NameError)

ま、今時1.4系を実用として使っている人は居ないと思うので、今となってはどうでもいい情報ですね。

で、実験的にコレをCにして、現在のtruncである#17885に対するパッチ作成。

--- enum.c (revision 17885)
+++ enum.c (working copy)
@@ -981,6 +981,37 @@
 }
 
 static VALUE
+enum_empty_func(VALUE result, VALUE *memo)
+{
+    *memo = Qtrue;
+    rb_iter_break();
+    return Qnil; // never reach
+}
+
+DEFINE_ENUMFUNCS(empty)
+
+/*
+ *  call-seq:
+ *     enum.empty?   => true or false
+ *
+ *  Passes each element of the collection to the given block. The method
+ *  returns <code>true</code> if the collection members by any value 
+ *  is a one or more.
+ *
+ *     [].empty?                                         #=> true
+ *     [1].empty?                                        #=> false
+ *     [nil, nil].empty?                                 #=> false
+ */
+static VALUE
+enum_empty(VALUE obj)
+{
+    VALUE result = Qfalse;
+
+    rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? empty_iter_i : empty_i, (VALUE)&result);
+    return result;
+}
+
+static VALUE
 min_i(VALUE i, VALUE *memo, int argc, VALUE *argv)
 {
     VALUE cmp;
@@ -1830,6 +1861,7 @@
     rb_define_method(rb_mEnumerable, "any?", enum_any, 0);
     rb_define_method(rb_mEnumerable, "one?", enum_one, 0);
     rb_define_method(rb_mEnumerable, "none?", enum_none, 0);
+    rb_define_method(rb_mEnumerable, "empty?", enum_empty, 0);
     rb_define_method(rb_mEnumerable, "min", enum_min, 0);
     rb_define_method(rb_mEnumerable, "max", enum_max, 0);
     rb_define_method(rb_mEnumerable, "minmax", enum_minmax, 0);

で、こいつをコンパイルして実行。

Owner@fam /usr/local/src/ruby/ruby-trunk/ruby $ ./ruby -ve 'p [].empty?; p [nil].empty?'
ruby 1.9.0 (2008-07-16 revision 17885) [i386-cygwin]
true
false

でも、「それって意味あるの?」と言われると、思考実験の産物なので実用からの要求じゃないってところで、苦しいですね。
ついでに名前もコレでいいのか悩んでしまうところ。(nilの扱いとの関連で)
まぁ、このまま寝かせておきますか。

22:20追記
diffの引数が逆だったので修正しました。