Enumerable#empty?は、汚染なしに可能か

Enumerableに対して、変数領域を汚さずに empty? みたいなメソッドが出来ないか考えてみた。
つまり、Enumerableなインスタンスeに対して、

i = 0
e.each{i+=1}

して、このiが1以上であればfalse。0であればtrueを戻すメソッドと同じ動きをする処理。

つまるはinstance_evalを使えばいいのだが、

Owner@fam /usr/local $ ruby-1.8.7-p22/bin/ruby -ve 'p [1].instance_eval{x=true;each{x=false;break};x};p local_variables'
ruby 1.8.7 (2008-06-20 patchlevel 22) [i386-cygwin]
false
[]

所謂一つのクロージャを使うので、

Owner@fam /usr/local $ ruby-1.8.7-p22/bin/ruby -ve 'x=1;[1].instance_eval{x=true;each{x=false;break};x};p x'
ruby 1.8.7 (2008-06-20 patchlevel 22) [i386-cygwin]
false

同じ名前の変数があると汚染してしまう。
1.9系なら、クロージャの引数を使って

Owner@fam /usr/local $ ruby-1.9.0-2/bin/ruby -ve 'x=1;[1].instance_eval{|x|x=true;each{x=false;break};x};p x'
ruby 1.9.0 (2008-06-20 revision 17482) [i386-cygwin]
-e:1: warning: shadowing outer local variable - x
1

とすれば、warningは出るものの、元の値を保護することは可能だ。
でもソレってなんだかなぁ…。
# いや、思いっきり使い方間違ってますよね。

ではローカルな変数領域を汚さずにジャンプするような構文といえば例外があるわけで、こっちを使ってみるとどうなるだろう。

Owner@fam /usr/local $ ruby-1.9.0-2/bin/ruby -ve 'p [1].instance_eval{begin;each{raise};true;rescue;false;end}'
ruby 1.9.0 (2008-06-20 revision 17482) [i386-cygwin]
false

意図通りに動いているけど、これはひどい。キタナイ。
でも、一応$!は汚してない…よね。

Owner@fam /usr/local $ ruby-1.9.0-2/bin/ruby -ve '
begin
  raise
rescue
  p $! # => ?
end
p $! # => ?
[1].instance_eval{
  begin
    each{
      raise
    }
    true
  rescue
    false
  end
}
p $! # => ?'
ruby 1.9.0 (2008-06-20 revision 17482) [i386-cygwin]
RuntimeError
nil
nil
Owner@fam /usr/local $ ruby-1.8.7-p22/bin/ruby -ve '
begin
  raise
rescue
  p $! # => ?
end
p $! # => ?
[1].instance_eval{
  begin
    each{
      raise
    }
    true
  rescue
    false
  end
}
p $! # => ?'
ruby 1.8.7 (2008-06-20 patchlevel 22) [i386-cygwin]
RuntimeError
nil
nil

あれ?
$!ってrescueの中でしか有効じゃないのかな。スコープはどうだったっけ。
と、それは別件と言うことで、ココでは忘れよう。

で、美しく行くには、やはりEnumerable#empty? というのを実装してしまえばいいといえばいいのだけど。

Owner@fam /usr/local $ ruby-1.9.0-2/bin/ruby -ve '
module Enumerable
  if !method_defined?(:empty?)
    def empty?()
      empty = true
      each{
        empty=false
        break
      }
      empty
    end
  end
end
p [1].empty? # => false
p [].empty? # => true
'
ruby 1.9.0 (2008-06-20 revision 17482) [i386-cygwin]
false
true

しかし、ユーザがこちらの意図するのと違うempty?を実装していたらどうしよう。
いや、そりゃどうしようもないかな。

こうなったら、Cで実装して提案してしまうというのも一つの手だろうか。
言語系の中に取り込まれれば、ユーザに悪影響を及ぼさないわけだし。
# って、目的変わっちゃってますね。反省。
いやまぁ、結局は過去バージョンの問題が出るから、同じ事ですね。

ん〜む。