Singleton method on object via define_method?

In article <Pine.LNX.4.44.0409130856080.26699-100000@wobblini>,

···

David A. Black <dblack@wobblini.net> wrote:

Hi --

On Mon, 13 Sep 2004, Robert Klemme wrote:

Originally I was going to argue that "virtual" is inappropriate because it
was deceiving. While thinking about this issue it occurred to me that
"singleton classes" aka "virtual classes" share a property with C++'s
"virtual classes": you cannot instantiate objects from them.

Actually if C++ has virtual classes, I think that's all the more
reason for Ruby not to call them that. Any such point of contact
inevitably leads to misunderstanding and/or expectation (i.e., that
Ruby will be like the other language).

I agree. There are already too many overloaded terms - isn't that why we
were trying to get away from using 'singleton' class?

Now I don't remember, but what was the problem with calling them
metaclasses?

Phil

"David A. Black" <dblack@wobblini.net> schrieb im Newsbeitrag
news:Pine.LNX.4.44.0409130856080.26699-100000@wobblini...

Hi --

> Originally I was going to argue that "virtual" is inappropriate

because it

> was deceiving. While thinking about this issue it occurred to me that
> "singleton classes" aka "virtual classes" share a property with C++'s
> "virtual classes": you cannot instantiate objects from them.

Actually if C++ has virtual classes, I think that's all the more
reason for Ruby not to call them that. Any such point of contact
inevitably leads to misunderstanding and/or expectation (i.e., that
Ruby will be like the other language).

> OTOH, you can have exactly one instance of this class, but this

instance

> preceedes the class (i.e. first the instance is created and then -

maybe -

> the class). Strictly speaking, the instance is the factory for the
> class - not the other way round as it is normally.
>
> <philosophical>I depends on everyones notion of "class" whether he or

she

> thinks this no longer makes it a class. Although in that case I'd be
> interested to learn a more appropriate name for this
> thing.</philosophical>
>
> > [I wrote:]
> >
> > the whole per-object
> > behavior model of Ruby is based on the idea that every object has

both

> > a class of origin and a class of its own where the definitions
> > exclusive to that object reside. This isn't abnormal, nor an
> > aberration; it's the way the whole thing works.
>
> Well, it's normal in Ruby. But generally speaking the naive OO expert
> would expect either not to have singleton/virtual classes (SVC :-))

*or*

> have Object#class return the singleton class - if that would exist.

Note,

> I'm not advocating to change this in any way - in fact it's good the

way

> it is. I just try to uncover why SVC often create confusion.

"Naive OO expert" -- interesting :slight_smile:

Isn't it? :slight_smile:

"Normal in Ruby" is good enough
for me, since we're talking about Ruby. Otherwise it becomes an
argument that there's an immutable/official OO model that languages
must not deviate from. (I know you don't really think this -- I'm
just extrapolating from what you're saying.)

Well, yes, the extrapolation was correct. Although I couldn't agree more,
that there is no such thing as a commonly agreed model of OO, I'd say
singleton classes the way they are in Ruby are not part of it. :slight_smile:

> The schizophrenic thing about SVC is, that instances change their

class at

> most once without showing it to the outside world (i.e. #class still
> returns the original class).

I think we're looking at this backwards in this discussion. We're
looking at it as: Objects have this weird class-like thing, so what
is it? I think it's better to look at it from the other end, like
this: Objects in Ruby can have methods added to them on a per-object
basis. That's a fundamental principle of Ruby (whether it is true of
other OO languages or not). The way Matz has chosen to implement this
is by associating a second, dedicated class with each object. That's
what this class actually *is* -- it's the fulfillment of that design,
not something growing off the design that has to be explained
separately.

While that's certainly true, we're (I am) here trying to grasp the nature
of these things to come up with a more appropriate name. At least that's
my understanding of the thread.

The details then fall into place. The fact that the class doesn't
exist until it's needn't does not have to mean that there's anything
virtual about it

.... but it might be a good reason to call it "virtual": it simply doesn't
exist the whole time. :slight_smile: OTOH, you can't tell from the outside - it's
there when you need it - lazyly initialized... ("lazy_class"? Oh no...)

-- it's just a matter of efficiency, and it's
transparent. And it's a perfectly real class, because it fits the
definition of what a class can be in Ruby.

.... apart from the instance creation.

Hmmm... "dedicated_class"... hmmm... :slight_smile:

How about "instance_class"?

Hmm...

    robert

···

On Mon, 13 Sep 2004, Robert Klemme wrote:

Randy W. Sims ha scritto:

Sounds sort of like a traits[1] or what Perl 6 refers to as roles[2][3]. But, then this is deeper Ruby than I'm familiar with.

I think traits mostly are what we call modules

Cause it is so meta-meaningless !?

What about something most meaningful, like per_instance_class or
per_object_class. Albeit virtual_class doesn't bother me as much. I don't C.

···

On Monday 13 September 2004 09:24 pm, Phil Tomson wrote:

In article <Pine.LNX.4.44.0409130856080.26699-100000@wobblini>,

David A. Black <dblack@wobblini.net> wrote:
>Hi --
>
>On Mon, 13 Sep 2004, Robert Klemme wrote:
>> Originally I was going to argue that "virtual" is inappropriate because
>> it was deceiving. While thinking about this issue it occurred to me
>> that "singleton classes" aka "virtual classes" share a property with
>> C++'s "virtual classes": you cannot instantiate objects from them.
>
>Actually if C++ has virtual classes, I think that's all the more
>reason for Ruby not to call them that. Any such point of contact
>inevitably leads to misunderstanding and/or expectation (i.e., that
>Ruby will be like the other language).

I agree. There are already too many overloaded terms - isn't that why we
were trying to get away from using 'singleton' class?

Now I don't remember, but what was the problem with calling them
metaclasses?

--
( o _ カラチ
// trans.
/ \ transami@runbox.com

I don't give a damn for a man that can only spell a word one way.
-Mark Twain

There's at least one case where you can know if the singleton class has
been created or not (singletons of singletons). And you can always know
if you're using evil.rb, of course :slight_smile:

···

On Tue, Sep 14, 2004 at 05:34:54PM +0900, Robert Klemme wrote:

.... but it might be a good reason to call it "virtual": it simply doesn't
exist the whole time. :slight_smile: OTOH, you can't tell from the outside - it's
there when you need it - lazyly initialized... ("lazy_class"? Oh no...)

--
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Phil Tomson ha scritto:

I agree. There are already too many overloaded terms - isn't that why we were trying to get away from using 'singleton' class?

Now I don't remember, but what was the problem with calling them metaclasses?

metaclass already is used in other contexts in other languages, where it stands for the (redefineable) class of a class. In ruby we usually just override #new, in other languages they define their own class hierarchy, so this has the same problem that virtual.

Hi --

> [I wrote:]
>
> I think we're looking at this backwards in this discussion. We're
> looking at it as: Objects have this weird class-like thing, so what
> is it? I think it's better to look at it from the other end, like
> this: Objects in Ruby can have methods added to them on a per-object
> basis. That's a fundamental principle of Ruby (whether it is true of
> other OO languages or not). The way Matz has chosen to implement this
> is by associating a second, dedicated class with each object. That's
> what this class actually *is* -- it's the fulfillment of that design,
> not something growing off the design that has to be explained
> separately.

While that's certainly true, we're (I am) here trying to grasp the nature
of these things to come up with a more appropriate name. At least that's
my understanding of the thread.

I agree, but I think the nature of singleton (or whatever) classes is
that they serve to manifest an important design feature of Ruby.
That being their nature, questions like whether they are identical to
other classes, etc., are secondary, not primary.

> -- it's just a matter of efficiency, and it's
> transparent. And it's a perfectly real class, because it fits the
> definition of what a class can be in Ruby.

.... apart from the instance creation.

But that's the point: "being a class" in Ruby does not actually always
mean being instantiable. We know this, because there are classes that
aren't. To argue it the other way would be like saying: there are
variables that begin with "@", so variables in Ruby begin with "@";
therefore, "var" can't be a variable. (Don't worry -- I'm completely
aware of what can be said both for and against this analogy :slight_smile: But
I still think it's good to let the language talk to us, rather than
the other way around.)

> Hmmm... "dedicated_class"... hmmm... :slight_smile:

How about "instance_class"?

Interesting... though kind of weird that an object would be an
instance of something other than its instance_class :slight_smile:

David

···

On Tue, 14 Sep 2004, Robert Klemme wrote:

--
David A. Black
dblack@wobblini.net

gabriele renzi wrote:

Randy W. Sims ha scritto:

Sounds sort of like a traits[1] or what Perl 6 refers to as roles[2][3]. But, then this is deeper Ruby than I'm familiar with.

I think traits mostly are what we call modules

I'm still learning Ruby, but aren't modules pretty much static? I think of traits as a set of behaviors that an object can take on at any point in it's lifetime. These behaviors are specific to that instance. They are transient behaviors that can be taken on and latter shed off. You would test for the presence of a trait before using it (much like testing is_a?). etc.

Randy.

"Mauricio Fernández" <batsman.geo@yahoo.com> schrieb im Newsbeitrag
news:20040914095258.GA6742@student.ei.uni-stuttgart.de...

> .... but it might be a good reason to call it "virtual": it simply

doesn't

> exist the whole time. :slight_smile: OTOH, you can't tell from the outside -

it's

> there when you need it - lazyly initialized... ("lazy_class"? Oh

no...)

There's at least one case where you can know if the singleton class has
been created or not (singletons of singletons).

How come? What's special about singletons here?

And you can always know
if you're using evil.rb, of course :slight_smile:

How exactly would you want to do it? I don't see how eval helps here.

The only way I can imagine is indirect: via instance_methods. But that
test can only assure, that the singleton class is created, you can't be
sure as long as the difference is empty:

s=""

=> ""

class << s ; def length() 1 end; end

=> nil

s.methods - s.class.instance_methods

=>

class << s ; def foo;"foo"; end; end

=> nil

s.methods - s.class.instance_methods

=> ["foo"]

Regards

    robert

···

On Tue, Sep 14, 2004 at 05:34:54PM +0900, Robert Klemme wrote:

Hi --

> .... but it might be a good reason to call it "virtual": it simply doesn't
> exist the whole time. :slight_smile: OTOH, you can't tell from the outside - it's
> there when you need it - lazyly initialized... ("lazy_class"? Oh no...)

There's at least one case where you can know if the singleton class has
been created or not (singletons of singletons).

Can you elaborate and/or give an example of what you mean?

And you can always know if you're using evil.rb, of course :slight_smile:

Still holding out for a name change :slight_smile:

David

···

On Tue, 14 Sep 2004, Mauricio Fernández wrote:

On Tue, Sep 14, 2004 at 05:34:54PM +0900, Robert Klemme wrote:

--
David A. Black
dblack@wobblini.net

In article <4145CFE2.7070404@thepierianspring.org>,

gabriele renzi wrote:

Randy W. Sims ha scritto:

Sounds sort of like a traits[1] or what Perl 6 refers to as
roles[2][3]. But, then this is deeper Ruby than I'm familiar with.

I think traits mostly are what we call modules

I'm still learning Ruby, but aren't modules pretty much static? I think
of traits as a set of behaviors that an object can take on at any point
in it's lifetime. These behaviors are specific to that instance. They
are transient behaviors that can be taken on and latter shed off. You
would test for the presence of a trait before using it (much like
testing is_a?). etc.

You can always add more methods to a module as well as remove methods from
a module:

irb(main):001:0> module Foo
irb(main):002:1> def a
irb(main):003:2> "a"
irb(main):004:2> end
irb(main):005:1> def b
irb(main):006:2> "b"
irb(main):007:2> end
irb(main):008:1> end
=> nil
irb(main):009:0> class Bar
irb(main):010:1> include Foo
irb(main):011:1> end
=> Bar
irb(main):012:0> b = Bar.new
=> #<Bar:0x400c3418>
irb(main):013:0> b.a
=> "a"
irb(main):014:0> b.b
=> "b"
irb(main):015:0> module Foo
irb(main):016:1> undef b
irb(main):017:1> end
irb(main):018:0> b.b
NoMethodError: undefined method `b' for #<Bar:0x400c3418>
  from (irb):18
irb(main):019:0>
irb(main):019:0> module Foo
irb(main):020:1> def c
irb(main):021:2> "c"
irb(main):022:2> end
irb(main):023:1> end
=> nil
irb(main):024:0> b.c
=> "c"

However, with traits & roles (and I'm certainly no expert) wouldn't it be
better to have different modules that get mixed-in and 'unmixed'.

So you might have:

  class Baz
  end

  baz = Baz.new
  baz.extend Foo #baz now has Foo 'traits'

....and later you might want to do:
  baz.unextend Foo #remove the Foo 'traits' from baz

....later on you could add another set of traits to baz:
  baz.extend OtherTraits

Of course there is no 'unextend', but there are probably ways to
implement this. For example, you could get a list of all of the methods
of Foo and undef them in the baz object (couldn't you?)

Phil

···

Randy W. Sims <ml-ruby@thepierianspring.org> wrote:

> There's at least one case where you can know if the singleton class has
> been created or not (singletons of singletons).

How come? What's special about singletons here?

o = Object.new

=> #<Object:0x401fdd20>

class << o; class << self; def foo; "foo" end end end

=> nil

class << o; class << self; foo end end

=> "foo"

class << o; class << self; class << self; end end end

=> nil

class << o; class << self; foo end end

NameError: undefined local variable or method `foo' for #<Class:#<Class:#<Object:0x401fdd20>>>
        from (irb):5

> And you can always know
> if you're using evil.rb, of course :slight_smile:

How exactly would you want to do it? I don't see how eval helps here.

eval is evil, but I really meant evil.rb :slight_smile:

require 'evil'

=> true

o = Object.new

=> #<Object:0x4032e35c>

o.internal.klass.to_i

=> 1075690784

class << o; end

=> nil

o.internal.klass.to_i

=> 1076982108

class << o; def foo; end end

=> nil

ObjectSpace._id2ref(o.internal.klass.to_i/2).instance_methods.include? "foo"

=> true

klass = ObjectSpace._id2ref(o.internal.klass.to_i/2)

=> #<Class:#<Object:0x4032e35c>>

class << o; self end

=> #<Class:#<Object:0x4032e35c>>

hence

def has_singleton?(obj); obj.class.id * 2 != obj.internal.klass.to_i end

=> nil

o = ""

=> ""

has_singleton? o

=> false

class << o; end

=> nil

has_singleton? o

=> true

···

On Tue, Sep 14, 2004 at 07:39:57PM +0900, Robert Klemme wrote:

--
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

See my other response to Robert's post.
The reason is in rb_make_metaclass:

     if (BUILTIN_TYPE(obj) == T_CLASS && FL_TEST(obj, FL_SINGLETON)) {
         RBASIC(klass)->klass = klass;
         RCLASS(klass)->super = RBASIC(rb_class_real(RCLASS(obj)->super))->klass;
     }

···

On Tue, Sep 14, 2004 at 07:43:06PM +0900, David A. Black wrote:

Hi --

On Tue, 14 Sep 2004, Mauricio Fernández wrote:

> On Tue, Sep 14, 2004 at 05:34:54PM +0900, Robert Klemme wrote:
> > .... but it might be a good reason to call it "virtual": it simply doesn't
> > exist the whole time. :slight_smile: OTOH, you can't tell from the outside - it's
> > there when you need it - lazyly initialized... ("lazy_class"? Oh no...)
>
> There's at least one case where you can know if the singleton class has
> been created or not (singletons of singletons).

Can you elaborate and/or give an example of what you mean?

--
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Phil wrote:

So you might have:

  class Baz
  end

  baz = Baz.new
  baz.extend Foo #baz now has Foo 'traits'

....and later you might want to do:
  baz.unextend Foo #remove the Foo 'traits' from baz

....later on you could add another set of traits to baz:
  baz.extend OtherTraits

Of course there is no 'unextend', but there are probably ways to
implement this. For example, you could get a list of all of the methods
of Foo and undef them in the baz object (couldn't you?)

I'd expect a proper implementation of 'unextend' to just "peel away a
layer of methods", not actually remove them. So...

  module Foo1
    def foo; "foo1"; end
  end

  module Foo2
    def foo; "foo2"; end
  end

  class X
  end

  x = X.new

  x.foo # error

  x.extend Foo1
  x.foo # "foo1"

  x.extend Foo2
  x.foo # "foo2"

  x.unextend Foo2
  x.foo # "foo1"

Gavin

ptkwt@aracnet.com (Phil Tomson) wrote in message news:<ci4p8602fvt@enews4.newsguy.com>...

In article <4145CFE2.7070404@thepierianspring.org>,
>gabriele renzi wrote:
>> Randy W. Sims ha scritto:
>>
>>> Sounds sort of like a traits[1] or what Perl 6 refers to as
>>> roles[2][3]. But, then this is deeper Ruby than I'm familiar with.
>>
>>
>> I think traits mostly are what we call modules

Take a look at this blog/article from David Naseby where he implements
traits in Ruby:

http://homepages.ihug.com.au/~naseby/33.html

Regards,

Dan

···

Randy W. Sims <ml-ruby@thepierianspring.org> wrote:

"Mauricio Fernández" <batsman.geo@yahoo.com> schrieb im Newsbeitrag
news:20040914113158.GA12061@student.ei.uni-stuttgart.de...

> > There's at least one case where you can know if the singleton class

has

> > been created or not (singletons of singletons).
>
> How come? What's special about singletons here?

>> o = Object.new
=> #<Object:0x401fdd20>
>> class << o; class << self; def foo; "foo" end end end
=> nil
>> class << o; class << self; foo end end
=> "foo"
>> class << o; class << self; class << self; end end end
=> nil
>> class << o; class << self; foo end end
NameError: undefined local variable or method `foo' for

#<Class:#<Class:#<Object:0x401fdd20>>>

        from (irb):5

Hm, but what about:

o = Object.new

=> #<Object:0x10184d40>

class << o; class << self; def to_s ; "foo" end end end

=> nil

class << o; class << self;to_s end end

=> "foo"

class << o; class << self; class << self; end end end

=> nil

class << o; class << self; to_s end end

=> "#<Class:foo>"

> > And you can always know
> > if you're using evil.rb, of course :slight_smile:
>
> How exactly would you want to do it? I don't see how eval helps here.

eval is evil, but I really meant evil.rb :slight_smile:

Oops. I wasn't aware of evil.rb and assumed an evil pun. :slight_smile: Shame on
me...

>> require 'evil'
=> true
>> o = Object.new
=> #<Object:0x4032e35c>
>> o.internal.klass.to_i
=> 1075690784
>> class << o; end
=> nil
>> o.internal.klass.to_i
=> 1076982108
>> class << o; def foo; end end
=> nil
>>

ObjectSpace._id2ref(o.internal.klass.to_i/2).instance_methods.include?
"foo"

=> true
>> klass = ObjectSpace._id2ref(o.internal.klass.to_i/2)
=> #<Class:#<Object:0x4032e35c>>
>> class << o; self end
=> #<Class:#<Object:0x4032e35c>>

hence

>> def has_singleton?(obj); obj.class.id * 2 != obj.internal.klass.to_i

end

=> nil
>> o = ""
=> ""
>> has_singleton? o
=> false
>> class << o; end
=> nil
>> has_singleton? o
=> true

Hm, well ok. But is there an equivalent without evil.rb, i.e. with
"normal" Ruby code? I know that you can access all kinds of internals if
you write an extension, but AFAIK you can't know whether there is a
singleton class or not. Please correct me if I'm wrong here...

Kind regards

    robert

···

On Tue, Sep 14, 2004 at 07:39:57PM +0900, Robert Klemme wrote:

In article <4581.218.214.1.200.1095117526.squirrel@webmail.imagineis.com>,

···

Gavin Sinclair <gsinclair@soyabean.com.au> wrote:

Phil wrote:

So you might have:

  class Baz
  end

  baz = Baz.new
  baz.extend Foo #baz now has Foo 'traits'

....and later you might want to do:
  baz.unextend Foo #remove the Foo 'traits' from baz

....later on you could add another set of traits to baz:
  baz.extend OtherTraits

Of course there is no 'unextend', but there are probably ways to
implement this. For example, you could get a list of all of the methods
of Foo and undef them in the baz object (couldn't you?)

I'd expect a proper implementation of 'unextend' to just "peel away a
layer of methods", not actually remove them. So...

module Foo1
   def foo; "foo1"; end
end

module Foo2
   def foo; "foo2"; end
end

class X
end

x = X.new

x.foo # error

x.extend Foo1
x.foo # "foo1"

x.extend Foo2
x.foo # "foo2"

x.unextend Foo2
x.foo # "foo1"

Yes, you're right. This would be better behavior. Any idea how something
like that could be implemented?

Phil

>> o = Object.new
=> #<Object:0x10184d40>
>> class << o; class << self; def to_s ; "foo" end end end
=> nil
>> class << o; class << self;to_s end end
=> "foo"
>> class << o; class << self; class << self; end end end
=> nil
>> class << o; class << self; to_s end end
=> "#<Class:foo>"

It's using Module#to_s because the klass of the singleton class is
no longer itself... Module#to_s ends up calling
class << o; self.to_s end
which you defined before.

Hm, well ok. But is there an equivalent without evil.rb, i.e. with
"normal" Ruby code? I know that you can access all kinds of internals if
you write an extension, but AFAIK you can't know whether there is a
singleton class or not.

(I assume your last sentence if missing "... without an extension".)

The case above (singletons of singletons) is the only one I can think
of right now where you can always know if the singleton has been created
or not.

···

On Wed, Sep 15, 2004 at 05:09:52PM +0900, Robert Klemme wrote:

--
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Phil wrote:

module Foo1
   def foo; "foo1"; end
end

module Foo2
   def foo; "foo2"; end
end

class X
end

x = X.new

x.foo # error

x.extend Foo1
x.foo # "foo1"

x.extend Foo2
x.foo # "foo2"

x.unextend Foo2
x.foo # "foo1"

Yes, you're right. This would be better behavior. Any idea how
something like that could be implemented?

Yep: in the Ruby core! :slight_smile:

Only pure-Ruby solution I can think of is to remember the modules that
have been mixed in, and selectively reapply earlier ones when 'unextend'
is called. Pretty fugly.

Gavin

"Mauricio Fernández" <batsman.geo@yahoo.com> schrieb im Newsbeitrag
news:20040915112257.GA14360@student.ei.uni-stuttgart.de...

> >> o = Object.new
> => #<Object:0x10184d40>
> >> class << o; class << self; def to_s ; "foo" end end end
> => nil
> >> class << o; class << self;to_s end end
> => "foo"
> >> class << o; class << self; class << self; end end end
> => nil
> >> class << o; class << self; to_s end end
> => "#<Class:foo>"

It's using Module#to_s because the klass of the singleton class is
no longer itself... Module#to_s ends up calling
class << o; self.to_s end
which you defined before.

Well yes, but the fact remains that there is a singleton we don't know of,
do we? Probably I don't see clearly your point so I'd appreciate it if
you'd elaborate it.

> Hm, well ok. But is there an equivalent without evil.rb, i.e. with
> "normal" Ruby code? I know that you can access all kinds of internals

if

> you write an extension, but AFAIK you can't know whether there is a
> singleton class or not.

(I assume your last sentence if missing "... without an extension".)

You can safely assume this without altering the indended semantics of the
sentence. :slight_smile:

The case above (singletons of singletons) is the only one I can think
of right now where you can always know if the singleton has been created
or not.

see above.

Kind regards

    robert

···

On Wed, Sep 15, 2004 at 05:09:52PM +0900, Robert Klemme wrote: