The following is the culmination of a discussion on ruby-talk from a
few days ago.

Someone asked if there was a way to find the instance of a singleton
class if you only had the class.  After positing a solution using
ObjectSpace.each_object, I then wrote a small extension to get it via
the hidden __attached__ instance variable.

I was then asked to submit it to ruby-core, although I'm not sure
whether it's a problem which needs to be addressed in the core.

But just in case here's the discussion.  If there's interest, I could
come up with a patch for 1.8.5, 1.8.6, and maybe 1.9.

On 3/13/07, Trans <transfire / gmail.com> wrote:
>
>
> On Mar 13, 1:56 pm, "Rick DeNatale" <rick.denat... / gmail.com> wrote:
> > On 3/13/07, Trans <transf... / gmail.com> 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.
>
> 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.
>
>
>


-- 
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/