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