Project

General

Profile

Actions

Bug #18671

closed

ruby2_keywords_hash not #equal? to itself with __send__

Added by Eregon (Benoit Daloze) about 2 years ago. Updated about 2 years ago.

Status:
Rejected
Assignee:
-
Target version:
-
ruby -v:
ruby 3.0.3p157 (2021-11-24 revision 3fb7d2cadc) [x86_64-linux]
[ruby-core:108123]

Description

h = {a: 1}
h = Hash.ruby2_keywords_hash(h)
args = [h]

p h.equal?(h) # => true
p h.__send__(:equal?, *args) # => false

Updated by jeremyevans0 (Jeremy Evans) about 2 years ago

  • Status changed from Open to Rejected

This is expected. When you use *args, it passes the flagged hash as keywords (new hash), it doesn't pass it through directly. This has nothing to do with __send__, you get the same false result using p h.equal?(*args).

Updated by Eregon (Benoit Daloze) about 2 years ago

Indeed:

h = {a: 1}
h = Hash.ruby2_keywords_hash(h)
args = [h]

p h.equal?(h) # => true
p h.equal?(*args) # => false
p h.equal?(*args, **{}) # => true

What was very confusing is in ruby/spec, I had code like:

after_usage.should_not.equal?(marked)

to check whether a copy was made for #18625.
And this didn't fail, even though after_usage and marked are the same object.
The reason is this behavior, and MSpec internally dispatching through __send__.
I worked around it by calling equal? more directly and avoiding __send__ for the case of equal? but obviously it's kind of a hack.

What this means is ruby2_keywords delegation doesn't preserve identity of the last argument if it is a marked Hash.
And an unintentionally marked Hash does not seem so unlikely to happen with #18625.

I updated the description of #18625 to this, there is no copy currently on master for that case (I misunderstood that originally due to this issue):

after_usage.equal?(marked) # => true, BUG, should be false
Actions

Also available in: Atom PDF

Like0
Like0Like0