# Hash#compare_by_identity makes string unusable as key

e\$B1sF#\$H?=\$7\$^\$9!#e(B

Hash#compare_by_identity e\$B\$r@_Dj\$9\$k\$H!"%-!<\$,J8;zNs\$N>l9g\$Ke(B
e\$BCM\$,<h\$j=P\$;\$J\$/\$J\$j\$^\$9!#\$3\$l\$O;EMM\$G\$7\$g\$&\$+!#e(B

\$ ./ruby -ve ’
a = “foo”
h = { a => “bar” }
h.compare_by_identity
p h[a] #=> nil

ruby 1.9.0 (2008-02-05 revision 15377) [i686-linux]
nil

Hash#[]= e\$B\$,!"%-!<\$,J8;zNs\$N>l9g\$@\$1e(B dup e\$B\$7\$Fe(B freeze
e\$B\$7\$F\$+\$ie(B
e\$BJ]B8\$9\$k\$N\$,860x\$N\$h\$&\$G\$9!#e(B

e\$B:#F|\$^\$G\$3\$N%a%=%C%I\$rCN\$i\$J\$+\$C\$?\$s\$G\$9\$,!"\$3\$N%a%=%C%I\$Ne(B
e\$BL\E*\$O2?\$J\$s\$G\$7\$g\$&\$+!#9bB.2=!)e(B
e\$B%a%=%C%IL>\$,%O%C%7%e\$H2?\$+\$rHf3S\$9\$k\$_\$?\$\$\$@\$H\$+!“85\$KLa\$9e(B
e\$BJ}K!\$,\$J\$/\$F\$\$\$\$\$N\$+\$H\$+!”\$\$\$m\$\$\$m5\$\$K\$J\$k46\$8\$G\$9!#e(B

e\$B\$J\$+\$@\$G\$9!#e(B

At Tue, 5 Feb 2008 22:19:29 +0900,
Yusuke ENDOH wrote in [ruby-dev:33604]:

Hash#[]= e\$B\$,!"%-!<\$,J8;zNs\$N>l9g\$@\$1e(B dup e\$B\$7\$Fe(B freeze e\$B\$7\$F\$+\$ie(B
e\$BJ]B8\$9\$k\$N\$,860x\$N\$h\$&\$G\$9!#e(B

e\$BC;\$\$J8;zNs0J30\$G\$O!"e(Bfreezee\$B\$5\$l\$?\$b\$N\$,;2>H\$G\$-\$k\$N\$G\$=\$l\$r;H\$(\$Pe(B
e\$BBg>fIW\$@\$H;W\$\$\$^\$9\$,!"Kd\$a9~\$^\$l\$F\$\$\$k\$ODL>o\$NHf3S\$r\$9\$k\$7\$+\$J\$\$e(B
e\$B\$+\$b!#e(B

e\$B:#F|\$^\$G\$3\$N%a%=%C%I\$rCN\$i\$J\$+\$C\$?\$s\$G\$9\$,!"\$3\$N%a%=%C%I\$Ne(B
e\$BL\E*\$O2?\$J\$s\$G\$7\$g\$&\$+!#9bB.2=!)e(B

e\$B\$?\$7\$+!"e(BRails(e\$B\$H\$\$\$&\$+e(BActiveSupport?)e\$B\$+\$i<h\$j9~\$^\$l\$?5!G=\$N\$O\$:e(B
e\$B\$G\$9!#e(B

e\$B%a%=%C%IL>\$,%O%C%7%e\$H2?\$+\$rHf3S\$9\$k\$_\$?\$\$\$@\$H\$+!“85\$KLa\$9e(B
e\$BJ}K!\$,\$J\$/\$F\$\$\$\$\$N\$+\$H\$+!”\$\$\$m\$\$\$m5\$\$K\$J\$k46\$8\$G\$9!#e(B

e\$BLa\$9\$K\$O!">WFM\$r\$I\$&\$9\$k\$+9M\$(\$J\$\$\$H\$\$\$1\$J\$\$\$H;W\$\$\$^\$9!#e(B

# Index: hash.c

— hash.c (revision 15384)
+++ hash.c (working copy)
@@ -1683,7 +1683,28 @@ rb_hash_flatten(int argc, VALUE *argv, V
}

+int rb_strcmp_by_identity(VALUE, VALUE);
+int rb_strhash_by_identity(VALUE);
+
+static int
+strcmp_by_identity(st_data_t x, st_data_t y)
+{

• if (TYPE(x) == T_STRING && TYPE(y) == T_STRING) {
• return rb_strcmp_by_identity((VALUE)x, (VALUE)y);
• }
• return x != y;
+}

+static int
+strhash_by_identity(st_data_t x)
+{

• if (TYPE(x) == T_STRING) {
• return rb_strhash_by_identity((VALUE)x);
• }
• return (int)x;
+}

static const struct st_hash_type identhash = {

• st_numcmp,
• st_numhash,
• strcmp_by_identity,
• strhash_by_identity,
};

# Index: string.c

— string.c (revision 15384)
+++ string.c (working copy)
@@ -1601,4 +1601,34 @@ rb_str_eql(VALUE str1, VALUE str2)
}

+int
+rb_strcmp_by_identity(VALUE x, VALUE y)
+{

• if ((RBASIC(x)->flags ^ RBASIC(y)->flags) & STR_NOEMBED) {
• return Qfalse;
• }
• if (RBASIC(x)->flags & STR_NOEMBED) {
• return !rb_str_eql(x, y);
• }
• if (RBASIC(x)->flags & ELTS_SHARED) {
• x = RSTRING(x)->as.heap.aux.shared;
• }
• if (RBASIC(y)->flags & ELTS_SHARED) {
• y = RSTRING(y)->as.heap.aux.shared;
• }
• return x != y;
+}

+int
+rb_strhash_by_identity(VALUE x)
+{

• if (RBASIC(x)->flags & STR_NOEMBED) {
• return rb_str_hash(x);
• }
• if (RBASIC(x)->flags & ELTS_SHARED) {
• x = RSTRING(x)->as.heap.aux.shared;
• }
• return (int)x;
+}

/*

• call-seq:

e\$B\$^\$D\$b\$He(B e\$B\$f\$-\$R\$m\$G\$9e(B

e\$BCY\$/\$J\$j\$^\$7\$?!#e(B

In message “Re: [ruby-dev:33604] Hash#compare_by_identity makes string
unusable as key”
on Tue, 5 Feb 2008 22:19:29 +0900, “Yusuke ENDOH” [email protected]
writes:

|Hash#compare_by_identity e\$B\$r@_Dj\$9\$k\$H!"%-!<\$,J8;zNs\$N>l9g\$Ke(B
|e\$BCM\$,<h\$j=P\$;\$J\$/\$J\$j\$^\$9!#\$3\$l\$O;EMM\$G\$7\$g\$&\$+!#e(B

e\$B;EMM\$G\$9!#e(Bcompare_by_identitye\$B\$O6u\$C\$]\$N\$H\$-\$K@_Dj\$7\$F\$/\$@\$5e(B
e\$B\$\$!#\$?\$@\$7!“;XE&\$5\$l\$?E@\$K%P%0\$O\$”\$C\$Fe(B

|Hash#[]= e\$B\$,!"%-!<\$,J8;zNs\$N>l9g\$@\$1e(B dup e\$B\$7\$Fe(B freeze e\$B\$7\$F\$+\$ie(B
|e\$BJ]B8\$9\$k\$N\$,860x\$N\$h\$&\$G\$9!#e(B

e\$B\$H\$\$\$&F0:n\$,0z\$-5/\$3\$9LdBj\$O;D\$C\$F\$^\$9!#\$=\$l\$OD>\$7\$^\$9!#e(B

e\$B\$b\$C\$H\$b!“e(Bcompare_by_identitye\$B\$=\$N\$b\$N\$,0-\$H\$\$\$&OC\$O\$”\$k\$N\$Ge(B
e\$B\$9\$,!"\$&!<\$`!#e(B