Robert Klemme <shortcutter@googlemail.com> writes:
Hi, I have next script:
t.rb:
class TestStr < String
attr_accessor :dupstr
def initialize ( str ) @dupstr = str
super(str)
end
end
ts=TestStr.new("aaa")
puts ts.dupstr
h=Hash.new()
h[ts]=true
puts h.keys.first.class
puts h.keys.first
puts h.keys.first.dupstr
run it:
$ ruby t.rb
aaa
TestStr
aaa
nil
$
The question is - why there is 'nil' in the last line instead of "aaa" ?
Because Hash copies #dup an unfrozen String.
Why would that cause this effect though? The docs say "a String passed
as a key will be duplicated and frozen", but duplicating and freezing
a TestStr doesn't nullify dupstr:
Why would that cause this effect though? The docs say "a String passed
as a key will be duplicated and frozen", but duplicating and freezing
a TestStr doesn't nullify dupstr:
The answer lies in the rb_hash_aset() function I quoted. rb_str_new4()
begins like this:
VALUE
rb_str_new4(orig)
VALUE orig;
{
VALUE klass, str;
if (OBJ_FROZEN(orig)) return orig;
/* ... */
}
Like Robert showed, if it's already frozen then the key is untouched (no
dup+freeze).
The docs could be made clearer: An _unfrozen_ String passed as a key
will be duplicated and frozen.
BTW, why delegation is more primary than standard inheritance ?
Delegation carries a greater degree of decoupling and flexibility.
Sometimes it's useful to replace your car engine while you're cruising
down the highway. That's delegation.
With inheritance, the engine is welded onto the car body. You've
already tossed aside the possibility of hot-swapping. Perhaps that was
an arbitrary decision.
Delegation makes something new out of existing parts. Inheritance
grafts stuff onto existing parts.
Why would that cause this effect though? The docs say "a String passed
as a key will be duplicated and frozen", but duplicating and freezing
a TestStr doesn't nullify dupstr:
The answer lies in the rb_hash_aset() function I quoted. rb_str_new4()
begins like this:
VALUE
rb_str_new4(orig)
VALUE orig;
{
VALUE klass, str;
if (OBJ_FROZEN(orig)) return orig;
/* ... */
}
Like Robert showed, if it's already frozen then the key is untouched (no
dup+freeze).
The docs could be made clearer: An _unfrozen_ String passed as a key
will be duplicated and frozen.
That doesn't answer my question. I showed that dup+freeze did not
adversely affect TestStr (i.e. dupstr was still accessible), so
something else is going on.
The docs could be made clearer: An _unfrozen_ String passed as a key
will be duplicated and frozen.
That doesn't answer my question. I showed that dup+freeze did not
adversely affect TestStr (i.e. dupstr was still accessible), so
something else is going on.
You passed in a frozen String, so Hash#= did not touch it. So it was
not adversely affected.
Could you write an assertion which you think should succeed but doesn't?
The docs could be made clearer: An _unfrozen_ String passed as a key
will be duplicated and frozen.
That doesn't answer my question. I showed that dup+freeze did not
adversely affect TestStr (i.e. dupstr was still accessible), so
something else is going on.
You passed in a frozen String, so Hash#= did not touch it. So it was
not adversely affected.
No I didn't. In fact, I didn't even use Hash in the example. Maybe
you're referring to a different post. I'll repost below:
What the above demonstrates is that dup'ing and freezing a TestStr
does not nilify TestStr#dupstr, so the C code for Hash seems to be
doing more than just dup'ing and freezing. Does that make sense?
Could you write an assertion which you think should succeed but doesn't?
--
Posted via http://www.ruby-forum.com/\.
What the above demonstrates is that dup'ing and freezing a TestStr
does not nilify TestStr#dupstr, so the C code for Hash seems to be
doing more than just dup'ing and freezing. Does that make sense?
Yes, sorry, I misunderstood. I did re-read your post several times but
was still a little puzzled.
You are right that something appears to be amiss. rb_str_new4()
duplicates the String portion of the TestStr object, but does not copy
over the TestStr-specific data. A subclassed String is not duplicated;
the documentation is wrong.
I see the reason for it: the raw string data is being shared between the
object and its "dup". I guess sharing should only be done if it's a
real String and not a subclass thereof. This fixes the problem reported
in this thread.
What the above demonstrates is that dup'ing and freezing a TestStr
does not nilify TestStr#dupstr, so the C code for Hash seems to be
doing more than just dup'ing and freezing. Does that make sense?
Yes, sorry, I misunderstood. I did re-read your post several times but
was still a little puzzled.
You are right that something appears to be amiss. rb_str_new4()
duplicates the String portion of the TestStr object, but does not copy
over the TestStr-specific data. A subclassed String is not duplicated;
the documentation is wrong.
I see the reason for it: the raw string data is being shared between the
object and its "dup". I guess sharing should only be done if it's a
real String and not a subclass thereof. This fixes the problem reported
in this thread.
In message "Re: why Hash corrupts 'key' object ?" on Thu, 18 Dec 2008 05:07:16 +0900, Brian Adkins <lojicdotcom@gmail.com> writes:
Wow, complete with a patch! Have you passed this on to the appropriate
channel for possible inclusion ?
I committed the patch to the trunk. So it will be available somewhere
in 1.9 (1.9.1 or 1.9.2). I am not sure yet it goes into 1.8, since
it has small incompatibility.