https://redmine.ruby-lang.org/https://redmine.ruby-lang.org/favicon.ico?17097754782011-01-26T16:52:06ZRuby Issue Tracking SystemRuby master - Bug #4323: Proc#hash is Ill-Behavedhttps://redmine.ruby-lang.org/issues/4323?journal_id=155232011-01-26T16:52:06Zheadius (Charles Nutter)headius@headius.com
<ul></ul><p>=begin<br>
I'm not so sure I'd expect Proc#hash to be equal in these cases. Of course, I don't feel like Procs that simply have the same code and closure should be expected to be eql? either.</p>
<p>Each proc has its own scope and its own reference to closed-over containing scope. They can be used independently and have independent state of their own. Should they be eql? and have identical hash values?</p>
<p>What constitutes equivalent procs? Just the code it contains? That's obviously not enough, since they'll have access to different closed-over state. The code it contains and the lexical scope in which it is instantiated? That's not consistently supported either, for whatever reason:</p>
<p>~/projects/jruby ➔ ruby1.9 -e "x = ->{def foo; end}; y = ->{def foo; end}; p x.eql? y"<br>
false</p>
<p>~/projects/jruby ➔ ruby1.9 -e "x = ->{:foo}; y = ->{:foo}; p x.eql? y"<br>
true</p>
<p>~/projects/jruby ➔ ruby1.9 -e "x = ->{'foo'}; y = ->{'foo'}; p x.eql? y"<br>
false</p>
<p>~/projects/jruby ➔ ruby1.9 -e "x = ->{if true; false; end}; y = ->{if true; false; end}; p x.eql? y"<br>
true</p>
<p>~/projects/jruby ➔ ruby1.9 -e "x = ->{->{}}; y = ->{->{}}; p x.eql? y"<br>
false</p>
<p>~/projects/jruby ➔ ruby1.9 -e "x = ->{5}; y = ->{5}; p x.eql? y"<br>
true</p>
<p>~/projects/jruby ➔ ruby1.9 -e "x = ->{5.0}; y = ->{5.0}; p x.eql? y"<br>
false</p>
<p>~/projects/jruby ➔ ruby1.9 -e "x = ->{[]}; y = ->{[]}; p x.eql? y"<br>
true</p>
<p>~/projects/jruby ➔ ruby1.9 -e "x = ->{[5.0]}; y = ->{[5.0]}; p x.eql? y"<br>
false</p>
<p>~/projects/jruby ➔ ruby1.9 -e "x = proc {}; y = lambda {}; p x.eql? y"<br>
true</p>
<p>I only searched for a few minutes and came up with all these inconsistencies in 1.9's Proc#eql?. Obviously the containing scope and the code within the proc are not enough to determine eql?, and simple cases like ->{'foo'}, which should be easy to call "equivalent", make me believe it's not a good idea to trust Proc#eql? in any case anyway. And if you can't trust eql? I'm not sure how useful it is to trust hash.</p>
<p>Maybe someone more familiar with MRI can explain what criteria should be used to determine equivalence of two procs? I can't figure it out from the above examples.</p>
<p>There may also be evidence here that this is a very implementation-specific detail. In JRuby, when a given Proc has been JIT-compiled, should it still be eql? the same proc that has not been compiled? In the case of precompiling a Proc, so that the original AST no longer exists at runtime, what would be use to determine the proc is equivalent to some other proc?<br>
=end</p> Ruby master - Bug #4323: Proc#hash is Ill-Behavedhttps://redmine.ruby-lang.org/issues/4323?journal_id=155242011-01-26T16:56:42Zheadius (Charles Nutter)headius@headius.com
<ul></ul><p>=begin<br>
I believe your example case, run in IRB, is also flawed. Witness:</p>
<p>~/projects/jruby ➔ irb1.9</p>
<blockquote>
<blockquote>
<p>->{}<br>
=> #<Proc:0x00000100aba6c0@(irb):1 (lambda)><br>
->{}<br>
=> #<Proc:0x00000100ab8cf8@(irb):2 (lambda)><br>
->{}<br>
=> #<Proc:0x00000100ab64a8@(irb):3 (lambda)></p>
</blockquote>
</blockquote>
<p>Oh ho you say, but that doesn't mean they should not be equivalent. Au contraire:</p>
<blockquote>
<blockquote>
<p>a = []<br>
=> []<br>
a << ->{}<br>
=> [#<Proc:0x00000100afee60@(irb):2 (lambda)>]<br>
a << ->{}<br>
=> [#<Proc:0x00000100afee60@(irb):2 (lambda)>, #<Proc:0x00000100afb170@(irb):3 (lambda)>]<br>
a[0].eql?(a[1])<br>
=> false</p>
</blockquote>
</blockquote>
<p>IRB is a bad place to demonstrate such things because the bindings are changing around all the time. Your examples do show different hash values (and your expected eql? results) within a script, however.<br>
=end</p> Ruby master - Bug #4323: Proc#hash is Ill-Behavedhttps://redmine.ruby-lang.org/issues/4323?journal_id=155282011-01-26T18:35:43Zrunpaint (Run Paint Run Run)runrun@runpaint.org
<ul><li><strong>File</strong> <a href="/attachments/1439">proc-hash.patch</a> <a class="icon-only icon-download" title="Download" href="/attachments/download/1439/proc-hash.patch">proc-hash.patch</a> added</li></ul><p>=begin</p>
<blockquote>
<p>I'm not so sure I'd expect Proc#hash to be equal in these cases. Of course, I don't feel like<br>
Procs that simply have the same code and closure should be expected to be eql? either.</p>
</blockquote>
<p>Perhaps, but the Rdoc is clear that the current behaviour of #eql? is intended, and that of #hash is wrong. If you want the spec changed, thus breaking backward compatibility, that's another discussion.</p>
<p>I've attached my best effort at a fix. It doesn't work for Method#to_proc cases because #eql? doesn't, either. With the patch applied:</p>
<pre><code> run@desktop:~/mir/ruby$ → ./ruby --disable-gems -e 'r=/#{1+2}/; p ->{:FOO; r}.hash; p ->{:FOO; r}.hash'
661952060
661952060
run@desktop:~/mir/ruby$ → ./ruby --disable-gems -e 'r=/#{1+2}/; p ->{:FOO; r}.hash; p ->{:FOO; r; 22}.hash'
-522099608
77097371
</code></pre>
<p>=end</p> Ruby master - Bug #4323: Proc#hash is Ill-Behavedhttps://redmine.ruby-lang.org/issues/4323?journal_id=183862011-06-26T17:19:22Znaruse (Yui NARUSE)naruse@airemix.jp
<ul><li><strong>Status</strong> changed from <i>Open</i> to <i>Assigned</i></li><li><strong>Assignee</strong> set to <i>matz (Yukihiro Matsumoto)</i></li></ul> Ruby master - Bug #4323: Proc#hash is Ill-Behavedhttps://redmine.ruby-lang.org/issues/4323?journal_id=280302012-07-14T14:36:37Zko1 (Koichi Sasada)
<ul><li><strong>Status</strong> changed from <i>Assigned</i> to <i>Closed</i></li></ul><p>See <a href="http://bugs.ruby-lang.org/issues/4559" class="external">http://bugs.ruby-lang.org/issues/4559</a></p>