[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

get object from its object-specific class?

Thomas Hafner

3/10/2007 11:46:00 PM

Hello,

is there a way to get an object, if only its object-specific class is
given? For instance, given

c = class << Hash[:a, 5]
def mult(x)
self[:a] * x
end
self
end

can I retrieve the hash object via evaluation of c?

Regards
Thomas
26 Answers

Ara.T.Howard

3/11/2007 2:24:00 PM

0

Thomas Hafner

3/11/2007 4:20:00 PM

0

ara.t.howard@noaa.gov wrote/schrieb <Pine.LNX.4.62.0703110817390.31042@harp.ngdc.noaa.gov>:

> p c.instance_eval{ self }

Thanks a lot.

> if you are doing much of this sort of thing check out the prototype lib

I'll have a look, thanks.

Regards
Thomas

Trans

3/13/2007 11:07:00 AM

0



On Mar 11, 10:23 am, ara.t.how...@noaa.gov wrote:
> On Sun, 11 Mar 2007, Thomas Hafner wrote:
> > Hello,
>
> > is there a way to get an object, if only its object-specific class is
> > given? For instance, given
>
> > c = class << Hash[:a, 5]
> > def mult(x)
> > self[:a] * x
> > end
> > self
> > end
>
> > can I retrieve the hash object via evaluation of c?
>
> harp:~ > cat a.rb
> c = class << Hash[:a, 5]
> def mult(x)
> self[:a] * x
> end
> self
> end
>
> p c.instance_eval{ self }
>
> harp:~ > ruby a.rb
> #<Class:#<Hash:0xb75cfd18>>

I thought we wanted the result to be #<Hash:0xb75cfd18>?

T.


Pit Capitain

3/13/2007 1:50:00 PM

0

Trans schrieb:
>> On Sun, 11 Mar 2007, Thomas Hafner wrote:
>>> is there a way to get an object, if only its object-specific class is
>>> given?
>
> I thought we wanted the result to be #<Hash:0xb75cfd18>?

Tom, I thought so, too, but I didn't want to show my solution before
there's a demand for it :-)

Regards,
Pit

Rick DeNatale

3/13/2007 2:55:00 PM

0

On 3/13/07, Trans <transfire@gmail.com> wrote:
> hought we wanted the result to be #<Hash:0xb75cfd18>?

rick@frodo:/public/rubyscripts$ ruby object_from_sc.rb
#<Class:#<Hash:0xb7df1774>>
{:a=>5}
oXb7df1774

And here's how:

rick@frodo:/public/rubyscripts$ cat object_from_sc.rb
# this method returns an integer value of the address of an object
with a standard
# object id.
# Note that internally Ruby FixedNums are stored as a value which is
the integer value
# shifted left one bit with a 1 bit ored into the LSB.
# For most objects the object_id is just the address with the LSB set.
This method
# undoes this magic to reveal the actual address.
def hex_oid(obj)
"oX#{(obj.object_id*2 & 0xffffffff).to_s(16)}"
end

c2 = class << {:a => 5}
def mult(x)
self[:a] * x
end
self
end

p c2

ObjectSpace.each_object(c2) {|o| p o; puts hex_oid(o)}

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denh...

Rick DeNatale

3/13/2007 3:17:00 PM

0

By the way.

I was a little concerned that having just a reference to a singleton
class without a reference to its single instance might not protect
that instance from being GCed.

I took a quick look through the ruby1.8 source and it looks like
singleton class objects have a hidden instance variable named
__attached__ which refers to the instance. This is what it uses to
compute it's string representation for example.

I don't think that theres any way to get at that through Ruby however,
for example instance_variable_get(:"__attached__") complains that
__attached__ is not a legal instance variable name.

So I guess you could write a C extension which accessed that hidden
variable, but in pure Ruby scanning using ObjectSpace.each_object
works albeit potentially less efficiently.

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denh...

IPMS/USA Region 12 Coordinator
http://ipmsr12.denh...

Visit the Project Mercury Wiki Site
http://www.mercuryspace...

Pit Capitain

3/13/2007 3:39:00 PM

0

Rick DeNatale schrieb:
> ObjectSpace.each_object(c2) {|o| p o}

Yeah Rick, this is what I came up with at first, too. But I didn't like
that it examines each Ruby object. Here's another solution, much
uglier but also faster:

def instance_of_singleton_class_1(sc)
ObjectSpace.each_object(sc) do |obj|
return obj
end
end

def instance_of_singleton_class_2(sc)
obj = nil
sc.class_eval do
if instance_methods(false).include?("singleton_method_added")
org = instance_method("singleton_method_added")
remove_method("singleton_method_added")
end
define_method("singleton_method_added") do |m|
obj = self
end
remove_method("singleton_method_added")
define_method("singleton_method_added", org) if org
end
obj
end

Test that they both work the same:

sc = class << {:a => 5}; self; end

p instance_of_singleton_class_1(sc) # => {:a=>5}
p instance_of_singleton_class_2(sc) # => {:a=>5}

And the benchmark:

require "benchmark"

Benchmark.bmbm do |bm|
bm.report "ObjectSpace" do
1000.times do instance_of_singleton_class_1(sc) end
end
bm.report "singleton_method_added" do
1000.times do instance_of_singleton_class_2(sc) end
end
end

yields:

Rehearsal ----------------------------------------------------------
ObjectSpace 3.109000 0.000000 3.109000 ( 3.188000)
singleton_method_added 0.266000 0.000000 0.266000 ( 0.265000)
------------------------------------------------- total: 3.375000sec

user system total real
ObjectSpace 3.016000 0.000000 3.016000 ( 3.032000)
singleton_method_added 0.266000 0.000000 0.266000 ( 0.266000)

Regards,
Pit

Trans

3/13/2007 4:13:00 PM

0

On Mar 13, 11:38 am, Pit Capitain <p...@capitain.de> wrote:
> Rick DeNatale schrieb:
>
> > ObjectSpace.each_object(c2) {|o| p o}
>
> Yeah Rick, this is what I came up with at first, too. But I didn't like
> that it examines each Ruby object. Here's another solution, much
> uglier but also faster:
>
> def instance_of_singleton_class_1(sc)
> ObjectSpace.each_object(sc) do |obj|
> return obj
> end
> end
>
> def instance_of_singleton_class_2(sc)
> obj = nil
> sc.class_eval do
> if instance_methods(false).include?("singleton_method_added")
> org = instance_method("singleton_method_added")
> remove_method("singleton_method_added")
> end
> define_method("singleton_method_added") do |m|
> obj = self
> end
> remove_method("singleton_method_added")
> define_method("singleton_method_added", org) if org
> end
> obj
> end
>
> Test that they both work the same:
>
> sc = class << {:a => 5}; self; end
>
> p instance_of_singleton_class_1(sc) # => {:a=>5}
> p instance_of_singleton_class_2(sc) # => {:a=>5}
>
> And the benchmark:
>
> require "benchmark"
>
> Benchmark.bmbm do |bm|
> bm.report "ObjectSpace" do
> 1000.times do instance_of_singleton_class_1(sc) end
> end
> bm.report "singleton_method_added" do
> 1000.times do instance_of_singleton_class_2(sc) end
> end
> end
>
> yields:
>
> Rehearsal ----------------------------------------------------------
> ObjectSpace 3.109000 0.000000 3.109000 ( 3.188000)
> singleton_method_added 0.266000 0.000000 0.266000 ( 0.265000)
> ------------------------------------------------- total: 3.375000sec
>
> user system total real
> ObjectSpace 3.016000 0.000000 3.016000 ( 3.032000)
> singleton_method_added 0.266000 0.000000 0.266000 ( 0.266000)


I imagine ObjectSpace._id2ref and parsing inspect would work.

T.


Pit Capitain

3/13/2007 4:47:00 PM

0

Trans schrieb:
> I imagine ObjectSpace._id2ref and parsing inspect would work.

Too easy, Tom, much too easy :-) Yes, this should work, too, of course.
The only gotchas are that you should make sure that the original #to_s
method is used, and you'd have to add a special case for singleton
classes of modules:

p class << Module; self; end # => #<Class:Module>

Regards,
Pit

Pit Capitain

3/13/2007 5:01:00 PM

0

Pit Capitain schrieb:
> The only gotchas are that you should make sure that the original #to_s
> method is used, and you'd have to add a special case for singleton
> classes of modules:
>
> p class << Module; self; end # => #<Class:Module>

Tom, sorry for the noise, but you can create pathological situations
where you can't get at the module via its name:

obj = M = Module.new
obj.to_s

Object.class_eval do
remove_const "M"
end

p class << obj; self; end # => #<Class:M>
p Object.const_get("M") rescue p $! # => #<NameError: M>

Maybe someone doing this deserves some troubles...

Regards,
Pit