I’m trying to implement a weak key hash to use for generic objects.
I’m more than happy to use Object#hash and Object#eql? as they come
with the distribution, but when I make the WeakRef, the hash values
don’t come out the same way:
irb(main):002:0> a = Object.new
=> #Object:0x402c9b44
irb(main):003:0> a.hash
=> 538332578
irb(main):004:0> a = WeakRef.new(a)
=> #Object:0x402c9b44
irb(main):005:0> a.hash
=> 538323898
I’m trying to implement a weak key hash to use for generic objects.
I’m more than happy to use Object#hash and Object#eql? as they come
with the distribution, but when I make the WeakRef, the hash values
don’t come out the same way:
irb(main):002:0> a = Object.new
=> #Object:0x402c9b44
irb(main):003:0> a.hash
=> 538332578
irb(main):004:0> a = WeakRef.new(a)
=> #Object:0x402c9b44
irb(main):005:0> a.hash
=> 538323898
Is this by design, or is this a bug somewhere?
I guess it’s by design. But you can fix this easily by sub classing
WeakRef
class WeakHashRef < WeakRef
def initialize(*args)
super
end
def hash
begin getobj.hash
rescue WeakRef::RefError
0
end
end
def eql?(ref)
begin getobj.id == ref.getobj.id
rescue WeakRef::RefError
false
end
end
end
Then you need to sub class Hash and override some methods if you want the
WeakHash to look like a normal hash from the outside.
As you can see, I’m not even adding methods, and it causes the weak
reference to not be recycled by the garbage collector. Somehow, I
don’t think this is intended behavior. I don’t know enough about Ruby
internals to say for sure (although I’m reading the code right now, so
I will soon enough).
Matz?
Cheerio,
Samuel
(Trying to figure this out, sure is fun)
Then you need to sub class Hash and override some methods if you want the
WeakHash to look like a normal hash from the outside.
Indeed, with the exception of the problem I posted about the class no
longer being a a weak reference, here’s that subclass. Works out
fairly well:
test.rb
require ‘weakref’
class WeakKey < WeakRef
def initialize(aRef)
super(aRef)
# We need to change #eql? on the incoming object because the
# method defined in object.c does not actualy check
# #object_id it actually compares the VALUE structs passed
# in. So when I override #object_id below, it doesn't completely
# take care of the problem.
class << aRef
def eql?(ref)
begin
self.object_id == ref.object_id
rescue WeakRef::RefError
false
end
end
end
end
We need to override this so that anything that asks for our ID
will actually receive the ID of the object we are pretending to be.
def object_id
begin getobj.object_id
rescue WeakRef::RefError
0
end
end
Object#id is deprecated, but people use it still. Let’s make sure
they get the proper ID when they do.
alias_method :id, :object_id
From Robert Klemme. This simply calls the hash function from the
actual object.
def hash
begin getobj.hash
rescue WeakRef::RefError
0
end
end
Also from Robert Klemme. Same idea as #hash.
def eql?(ref)
begin getobj.object_id == ref.object_id
rescue WeakRef::RefError
false
end
end
end
a = Object.new
b = WeakKey.new(a)
puts(a.eql?(b).to_s) # => true
puts(b.eql?(a).to_s) # => true
As you can see, I’m not even adding methods, and it causes the weak
reference to not be recycled by the garbage collector.
I had similar experiences about references not beeing cleared. Maybe
someone with more insight (Matz?) should comment on this. Maybe only an
instance’s type is checked against WeakRef and not if it’s a subtype of
that.
On Fri, 5 Dec 2003 13:57:04 +0900, Mark J. Reed wrote:
On Fri, Dec 05, 2003 at 01:45:36PM +0900, Austin Ziegler wrote:
hash = { :a => 3, :b => 2, :c => 1, :d => 0}
hash.update({ :a => 1, :b => 2, :c => 3 })
I know that, but in this case I have the keys and values in two arrays
and want to match them up by position. In other words, I want to do this:
In message “Re: WeakRef and Object#hash” on 03/12/08, “Robert Klemme” bob.news@gmx.net writes:
As you can see, I’m not even adding methods, and it causes the weak
reference to not be recycled by the garbage collector.
I had similar experiences about references not beeing cleared. Maybe
someone with more insight (Matz?) should comment on this. Maybe only an
instance’s type is checked against WeakRef and not if it’s a subtype of
that.
The weakly referenced object is also considered as referenced from C
stack region. It’s due to Ruby’s conservative nature of GC.
[Changed the subject to something more informative ]
hash = { :a => 3, :b => 2, :c => 1, :d => 0}
hash.update({ :a => 1, :b => 2, :c => 3 })
I know that, but in this case I have the keys and values in two arrays
and want to match them up by position. In other words, I want to do this:
keys.each_with_index do
k, i|
hash[k] = values[i]
end
The equivalent of Perl @hash{@keys} = @values.
Unfortunately, that won’t work in Ruby because arrays can be keys, whereas
in Perl, hash keys can only be scalars.
That would be handy, but I don’t think it’s possible to define such
a method in current Ruby. The parameters to = are flattened;
you wouldn’t be able to tell where the keys stopped and the values
started, unless you assumed that keys.length == values.length, which
is not always a valid assumption where I’ve seen the Perl idiom used.
“Yukihiro Matsumoto” matz@ruby-lang.org schrieb im Newsbeitrag
news:1070890833.524202.5797.nullmailer@picachu.netlab.jp…
Hi,
As you can see, I’m not even adding methods, and it causes the weak
reference to not be recycled by the garbage collector.
I had similar experiences about references not beeing cleared. Maybe
someone with more insight (Matz?) should comment on this. Maybe only
an
instance’s type is checked against WeakRef and not if it’s a subtype of
that.
The weakly referenced object is also considered as referenced from C
stack region. It’s due to Ruby’s conservative nature of GC.
Hm, not sure what exactly you mean. I was assuming, the line
wr = WeakRef.new Object.new
leads to exactly one ref (the weak ref to be precise) to the instance.
Anyway, can I circumvent this by doing:
def create; Object.new; end
wk = WeakRef.new create
?
Regards
robert
···
In message “Re: WeakRef and Object#hash” > on 03/12/08, “Robert Klemme” bob.news@gmx.net writes:
Now that is handy. I assume there’s a historical reason for the
name ‘zip’? Because I would never have thought it meant
“iterate in parallel with”.
It’s more that the result is ‘zipped’, as the teeth of a zipper become
interleaved when the zipper is zipped (one from the right, one from the
left, one from the right…).
matz is trying to say that it's hard to know if a variable will be gc'ed,
because internally ruby can have reference to the object that you are not
aware.
I was assuming, the line
wr = WeakRef.new Object.new
leads to exactly one ref (the weak ref to be precise) to the instance.
yes, it has only one ref. Now write it (like in the original example)
class WeakRef; end
wr = WeakRef.new Object.new
and if you are lucky the variable will not be gc'ed because internally
ruby has a reference to it.
matz is trying to say that it’s hard to know if a variable will be
gc’ed,
because internally ruby can have reference to the object that you are
not
aware.
Aha. But “WeakRef.new Object.new” is not supposed to generate any side
effects that create additional references to the newly created instance of
class Object, is it? At least not, if WeakRef#initialize is unmodified.
I was assuming, the line
wr = WeakRef.new Object.new
leads to exactly one ref (the weak ref to be precise) to the
instance.
yes, it has only one ref. Now write it (like in the original example)
class WeakRef; end
wr = WeakRef.new Object.new
and if you are lucky the variable will not be gc’ed because internally
ruby has a reference to it.
To prevent misunderstandings: I was talking about the Object instance, not
“wr”. Currently I can’t see how opening class WeakRef and closing it
without doing anything else affects the references to the newly created
Object instance. Could you please clarify this? Thanks a lot!
To prevent misunderstandings: I was talking about the Object instance, not
"wr". Currently I can't see how opening class WeakRef and closing it
without doing anything else affects the references to the newly created
Object instance. Could you please clarify this? Thanks a lot!
Object.new create a new reference : in reality this reference is one of
the reference internally created by ruby when it has called
class WeakRef; end
When the GC run it will mark indirectly this reference, because it still
have the struct which make reference to this object.