Bug #12855
closed
Inconsistent keys identity in compare_by_identity Hash when using literals
Added by Eregon (Benoit Daloze) about 8 years ago.
Updated over 7 years ago.
Description
This seems a regression since 2.2.
I would guess it's due to some optimization for having a string literal between []=.
That optimization should not trigger for compare_by_identity hashes, so both cases below are consistent.
h = {}.compare_by_identity
h['pear'] = 1
h['pear'] = 2
p h.size # => 1
p h
h = {}.compare_by_identity
k1 = 'pear'
h[k1] = 1
k2 = 'pear'
h[k2] = 2
p h.size # => 2
p h
While this was a behavior change between 2.1 and 2.2, I'm not sure I would consider it a regression. It seems unlikely anyone who uses compare_by_identity hashes would also be using string literals and want string literals keys to have different values.
If we do decide to revert to 2.1 behavior for string literals, at the very least we should make sure that on ruby 2.1+:
h = {}.compare_by_identity
h['pear'.freeze] = 1
h['pear'.freeze] = 2
p h.size # => 1
# because 'pear'.freeze.equal?('pear'.freeze)
and on ruby 2.3+:
# frozen-string-literal: true
# or when using --enable-frozen-string-literal
h = {}.compare_by_identity
h['pear'] = 1
h['pear'] = 2
p h.size # => 1
# because 'pear'.equal?('pear')
Jeremy Evans wrote:
While this was a behavior change between 2.1 and 2.2, I'm not sure I would consider it a regression.
It seems unlikely anyone who uses compare_by_identity hashes would also be using string literals and want string literals keys to have different values.
The main reason I consider it a bug is that it contradicts the very basic intuition that replacing a literal with an expression producing it has identical behavior.
For example, "z = #{3*4}"
vs r = 12; "z = #{r}"
.
While of course a much smaller area of exposition,
I think there is no reason to introduce this change (and I'm fairly confident it was not intended).
- Status changed from Open to Assigned
- Assignee set to normalperson (Eric Wong)
- Related to Bug #9382: [patch] add opt_aref_str and opt_aset_str added
- Assignee changed from normalperson (Eric Wong) to tmm1 (Aman Karmani)
We looked at this issue at today's developer meeting. It seems over-optimization as Benoit originally guessed. Let me assign this to Aman.
Unintentional, yes, but maybe moot since frozen_string_literal
is going to be default in the future (maybe that case changed?)
Anyways, I hate this patch because it makes insns.def bigger,
and insns.def is already too big IMHO:
https://80x24.org/spew/20161222004752.4086-1-e@80x24.org/raw
Somebody else can commit; I hate it too much.
Eric Wong wrote:
Unintentional, yes, but maybe moot since frozen_string_literal
is going to be default in the future (maybe that case changed?)
Anyways, I hate this patch because it makes insns.def bigger,
and insns.def is already too big IMHO:
https://80x24.org/spew/20161222004752.4086-1-e@80x24.org/raw
Somebody else can commit; I hate it too much.
Thank you for the patch!
I would like to commit it then, unless there is an objection.
IMHO optimizations have to be correct, even in edge cases.
Such instructions are already a trade-off of duplication and complexity for speed improvement,
so this small change in size does not matter much to me.
Optimizations need to be totally transparent to the user to be called as such.
- Status changed from Assigned to Closed
Applied in changeset r57278.
fix optimization for hash aset/aref with fstring
Patch by Eric Wong [ruby-core:78797].
I don't like the idea of making insns.def any bigger to support
a corner case, and "test_hash_aref_fstring_identity" shows
how contrived this is.
[ruby-core:78783] [Bug #12855]
- Backport changed from 2.1: UNKNOWN, 2.2: UNKNOWN, 2.3: UNKNOWN to 2.1: UNKNOWN, 2.2: UNKNOWN, 2.3: UNKNOWN, 2.4: DONE
ruby_2_4 r57848 merged revision(s) 57278,57279.
- Backport changed from 2.1: UNKNOWN, 2.2: UNKNOWN, 2.3: UNKNOWN, 2.4: DONE to 2.1: UNKNOWN, 2.2: REQUIRED, 2.3: REQUIRED, 2.4: DONE
- Backport changed from 2.1: UNKNOWN, 2.2: REQUIRED, 2.3: REQUIRED, 2.4: DONE to 2.1: UNKNOWN, 2.2: DONE, 2.3: REQUIRED, 2.4: DONE
ruby_2_2 r58099 merged revision(s) 57278,57279.
- Backport changed from 2.1: UNKNOWN, 2.2: DONE, 2.3: REQUIRED, 2.4: DONE to 2.1: UNKNOWN, 2.2: DONE, 2.3: DONE, 2.4: DONE
ruby_2_3 r58166 merged revision(s) 57278,57279.
Also available in: Atom
PDF
Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0