Get object from its object-specific class?

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

On Sun, 11 Mar 2007, Thomas H. wrote:

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>

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

harp:~ > cat a.rb
require ‘rubygems’
require ‘prototype’

c = Object.prototype(Hash) do
def mult(x)
self[:a] * x
end

def initialize
self[:a] = 5
end
end

p c

harp:~ > ruby a.rb
{:a=>5}

-a

[email protected] wrote/schrieb
[email protected]:

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 schrieb:

On Sun, 11 Mar 2007, Thomas H. 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 :slight_smile:

Regards,
Pit

On Mar 11, 10:23 am, [email protected] wrote:

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.

On 3/13/07, Trans [email protected] 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.denhaven2.com/

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

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.denhaven2.com/

IPMS/USA Region 12 Coordinator
http://ipmsr12.denhaven2.com/

Visit the Project Mercury Wiki Site
http://www.mercuryspacecraft.com/

Trans schrieb:

I imagine ObjectSpace._id2ref and parsing inspect would work.

Too easy, Tom, much too easy :slight_smile: 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

On Mar 13, 11:38 am, Pit C. [email protected] wrote:

   return obj
   define_method("singleton_method_added") do |m|

sc = class << {:a => 5}; self; end
1000.times do instance_of_singleton_class_1(sc) end
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 C. 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

On Mar 13, 1:56 pm, “Rick DeNatale” [email protected] wrote:

static VALUE singleton_instance(VALUE obj)
rb_define_method(rb_cClass, “singleton_instance”, singleton_instance, 0);

end
end
10000.times do instance_of_singleton_class_1(sc) end
many interations as Trans did, 10000 vs. 1000, the primitive is on the
order of two orders of magnitude faster than either of the other
approaches.

Actually, you mean Pit. He did the benchmarks. This is definitely the
way to do it right though. I would submit this to ruby-core mailing
list and see how it takes over there.

T.

def instance_of_singleton_class_2(sc)

not only is this method faster but it works in a situation where the
ObjectSpace does not. Consider this rspec test pasted in from a personal
introspection lib. It will work with this method but not with the
ObjectSpace:

def singleton
class<<self;self;end
end

def singleton_ancestors
result = []
return result unless pointer = singleton_parent
result << self
begin
result << pointer
end while pointer = pointer.singleton_parent
result
end

it "should get singletons back in the correct order" do
  parent = ""
  a = parent.singleton
  b = a.singleton
  c = b.singleton
  d = c.singleton
  e = d.singleton
  f = e.singleton
  f.singleton_ancestors.should == [ f, e, d, c, b, a, parent ]
end

On 3/13/07, Trans [email protected] wrote:
Two approaches with a benchmark.

And as I surmised, there’s a really quick way to do this with a
relatively simple extension (at least for ruby1.8, I haven’t looked at
this on 1.9).

rick@frodo:/public/rubyscripts/getsinginst$ cat get_sing_inst.c
#include “ruby.h”

static VALUE singleton_instance(VALUE obj)
{
if (BUILTIN_TYPE(obj) == T_CLASS && FL_TEST(obj, FL_SINGLETON)) {
return rb_iv_get(obj, “attached”);
}
rb_raise(rb_eTypeError, “not a singleton class”);
}

void Init_get_sing_inst()
{
rb_define_method(rb_cClass, “singleton_instance”, singleton_instance,
0);

}

rick@frodo:/public/rubyscripts/getsinginst$ cat gsi.rb
require ‘get_sing_inst’

h = {:a => 1}
sc = class << h
def foo
end

self

end

p sc.singleton_instance
p sc.singleton_instance.object_id == h.object_id

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

require “benchmark”

Benchmark.bmbm do |bm|
bm.report “ObjectSpace” do
10000.times do instance_of_singleton_class_1(sc) end
end
bm.report “singleton_method_added” do
10000.times do instance_of_singleton_class_2(sc) end
end
bm.report “primitive” do
10000.times do sc.singleton_instance end
end
end

And now for the benchmark results, note that I’m doing 10 times as
many interations as Trans did, 10000 vs. 1000, the primitive is on the
order of two orders of magnitude faster than either of the other
approaches.

rick@frodo:/public/rubyscripts/getsinginst$ ruby gsi.rb
{:a=>1}
true
Rehearsal ----------------------------------------------------------
ObjectSpace 3.270000 0.100000 3.370000 ( 3.469175)
singleton_method_added 4.450000 0.110000 4.560000 ( 4.580452)
primitive 0.040000 0.000000 0.040000 ( 0.046098)
------------------------------------------------- total: 7.970000sec

                         user     system      total        real

ObjectSpace 2.300000 0.050000 2.350000 ( 2.352730)
singleton_method_added 4.430000 0.070000 4.500000 ( 4.510719)
primitive 0.040000 0.000000 0.040000 ( 0.037970)


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

No, this was deliberate. Maybe it was a mistake… My singleton_parent
retrieves attached, but I was saying Pit’s
instance_of_singleton_class_2 method works as a replacement for this
where as ObjectSpace does not. Here, I’ve refactored the
instance_of_singleton_class_2 into a singleton_parent method for you:

def singleton_parent
# instance_variable_get( ‘attached’ )
return nil unless is_a? Class
obj = nil
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

I think you forgot to define singleton_parent.

David

Hi –

On Fri, 21 Mar 2008, Rob Pitt wrote:

def singleton_ancestors
result = []
return result unless pointer = singleton_parent

I think you forgot to define singleton_parent.

David