Infinite number of singleton_classes

Hi,

···

In message "Re: Bug printing classes - Re: infinite number of singleton_classes" on Mon, 16 May 2005 14:37:03 +0900, "Nakada, Nobuyoshi" <nobuyoshi.nakada@ge.com> writes:

David A. Black wrote:

I'd rather just see the #inspect bug fixed :slight_smile:

I rather guess singleton class would not be allowed to copy, from its
definition.

Agreed. Can you commit the patch?

              matz.

David A. Black schrieb:

:

Having a subclass able to call its superclass's singleton (class)
methods is, as far as I know, the only case where one object can call
another's singleton methods. This arrangement seems to disappear in
the case of singleton classes of singleton classes... but at least it
disappears consistently (i.e., even in the case of "Klass" above).

It also works if the subclass is an ordinary singleton class of an
instance of the superclass.

Or something. In practical terms there's probably not much mileage to
be had out of these.

True - but when there is very little mileage why not simply disallow them in
the first place.

As a side note the class Klass lends itself naturally as the mother of all
singleton classes - i.e. "pouch == Klass" - a problem with this idea is that
we currently have Class < Module < Object.

/Christoph

David A. Black a écrit :

You have skipped this part of my post in your answer:
----8<----
And, please note this: I agree with you. There is nothing wrong or
harmfull in
the current behavior, while looking from the point of view of a ruby
user. But I
think it may be different from the point of view of a language
designer and I
like to take count of it.
----8<----

I didn't have anything to add to it, so I didn't quote it back.
Otherwise we get into infinite recursion :slight_smile:

The feature is currently avaible, but unless Matz state otherwise, it
is an
accident, it shouldn't have never happened. Why? Because it may
disapear in any
future version of ruby. Who said it? Matz himself. It then should be
accessible
only via special module like evil.rb if one really want the feature.

If it disappears, it can't be accessible from any module, at least not
in exactly that form.

I should have added "Until it disapears (if it disapears), it should be
accessible only via...". Sorry.

On the other hand, if it was said that ruby won't never change about
singleton
methods hold in singleton classes, I wouldn't care at all about this.

There's a bit of a paradox there. If Ruby shouldn't contain anything
that might be absent in a future Ruby, then Ruby today must be exactly
what Ruby in the future will be.... If singleton classes disappear,
lots of things will change, possibly including:

   class << obj # this form of the class keyword
     X = 1 # constants -- where would this go?
     def self.x # class methods on the singleton class
     end
   end

as well as just the fact that you can call Class's instance methods,
in general, on singleton classes.

So if you apply the rule: it should never have happened because it
may disappear in a future version of Ruby, then all of this should
never have happened and should disappear. But so should lots of other
things, because Matz is planning lots of changes. So that means Ruby
should be turned into future Ruby *now*. But that takes time :slight_smile:

My "why?" argument was insuficiant, I admit it. Sorry.

Future version of ruby will change... but the ruby way/feeling will not. This is
the garantee Matz has given us for ruby2, AFAIK. And IMO I think the presence or
the absence of that feature matters a lot for defining that ruby way.

For example, the fact that
----8<----
class << obj
  X = 1
  def self.x
  end
end
----8<----
could disapear implies a lot on the ruby way.

···

On Mon, 16 May 2005, Lionel Thiry wrote:

--
Lionel Thiry

Personal website: http://users.skynet.be/lthiry/

Ara.T.Howard@noaa.gov schrieb:

misunderstood something once again?

well - sorta :wink:

i only meant to say that the behaviour is consistent and, although there is no
regular ruby idiom that makes use of it now, there may well be in the future.

Actually the behavior is not consistent - assuming the definition

···

----
public # create meta objects
def m(height =1)
    height.zero? ? self : class << self; self end.m(height -1)
end
----

and the natural inheritance assumption, that the class relation

X < Y # true, implies
X.m < Y.m # true
---
you would expect the following method lookup path for a
singleton class of "height" 5
---
class A; end
class B < A; end
b = B.new

b.m(5) <- B.m(4) < A.m(4) < Object.m(4) <
Class.m(3) < Module.m(3) < Object.m(3) <
Class.m(2) < Module.m(2) < Object.m(2) <
Class.m < Module.m < Object.m <
Class < Module < Object < Kernel
---

From a practical point of view this would be rather silly, so Matz bend
the rules, and "benevolently ruled" the following to be true
---
b.m(5) < Class.m < Module.m < Object.m <
              Class < Module < Object < Kernel
---

I personally still prefer honest exception raising over a trickery like this.

/Christoh

Hi --

David A. Black schrieb:

:

Having a subclass able to call its superclass's singleton (class)
methods is, as far as I know, the only case where one object can call
another's singleton methods. This arrangement seems to disappear in
the case of singleton classes of singleton classes... but at least it
disappears consistently (i.e., even in the case of "Klass" above).

It also works if the subclass is an ordinary singleton class of an
instance of the superclass.

Or something. In practical terms there's probably not much mileage to
be had out of these.

True - but when there is very little mileage why not simply disallow them in
the first place.

I'm just not ready for:

   class << obj; def self.x; end; end

to throw an error. It just seems like taking away too much
class-ness -- though obviously if the class interface to object
singleton behavior disappears entirely, that won't be an issue.

As a side note the class Klass lends itself naturally as the mother of all
singleton classes - i.e. "pouch == Klass" - a problem with this idea is that
we currently have Class < Module < Object.

I'm not sure what you mean. If every object's "pouch" is Klass, it
will get very crowded.... But I think I'm misunderstanding.

David

···

On Mon, 16 May 2005, Christoph wrote:

--
David A. Black
dblack@wobblini.net

Christoph a écrit :

Ara.T.Howard@noaa.gov schrieb:
Actually the behavior is not consistent - assuming the definition
----
public # create meta objects
def m(height =1)
   height.zero? ? self : class << self; self end.m(height -1)
end
----

and the natural inheritance assumption, that the class relation

X < Y # true, implies
X.m < Y.m # true
---
you would expect the following method lookup path for a
singleton class of "height" 5
---
class A; end
class B < A; end
b = B.new

b.m(5) <- B.m(4) < A.m(4) < Object.m(4) <
Class.m(3) < Module.m(3) < Object.m(3) <
Class.m(2) < Module.m(2) < Object.m(2) <
Class.m < Module.m < Object.m <
Class < Module < Object < Kernel
---

From a practical point of view this would be rather silly, so Matz bend
the rules, and "benevolently ruled" the following to be true
---
b.m(5) < Class.m < Module.m < Object.m <
             Class < Module < Object < Kernel
---

I personally still prefer honest exception raising over a trickery like
this.

What an impressive demonstration.

Let me add more precision to your affirmation:
b.m(5) < B.m(4) # => nil
B.m(4) < A.m(4) # => nil
A.m(4) < Object.m(4) # => nil
Object.m(4) < Class.m(3) # => nil
Class.m(3) < Module.m(3) # => nil
Module.m(3) < Object.m(3) # => nil
Object.m(3) < Class.m(2) # => nil
Class.m(2) < Module.m(2) # => nil
Module.m(2) < Object.m(2) # => nil
Object.m(2) < Class.m # => true
Class.m < Module.m # => true
Module.m < Object.m # => true
Object.m < Class # => true
Class < Module # => true
Module < Object # => true
Object < Kernel # => true

Then, we have to choose between two things: limit the "height" of singleton
class, or correct that inheritence model. I'd be for the first one.

···

--
Lionel Thiry

Personal website: http://users.skynet.be/lthiry/

here we depart. i don't assume this because X's singleton class is just that
: a singleton (eg. one) class with no relation to that of Y's. i think of as
in

   class Clothes
   end

   class Shirts < Clothes
   end

   class Pants < Clothes
   end

   class TShirts < Shirts
   end

now, obviously, we have something of a hierarchy described in 'is-a' terms:
TShirt 'is-a' Shirt, etc.

now we thow in a __separate__ hierarchy : Pockets. so

   class Pocket
   end

Pockets, obviously, being where classes store their personal (singleton)
stuff. :wink:

now we have

   class Clothes
     class Pocket < ::Pocket
     end
   end

   class Shirts
     class Pocket < ::Pocket
     end
   end

now this is a 'has-a' relationship: a Pants 'has-a' Pocket class
(Pants::Pocket) and Shirt 'has-a' Pocket class (Shirt::Pocket). there __is__
a subtle 'is-a' relationshiop between pocket classes : a Shirt::Pocket 'is-a'
::Pocket and a Pant::Pocket 'is-a' Pocket. however we do not (necessarily)
have : Shirt::Pocket 'is-a' Pants::Pocket.

in this case the Pocket class(es) are singleton classes. all classes have one
that descends from a parent singleton class(es). this is a hierarchy that is
related to, but separate and parallel from, the hierachy of any classes which
may themselves have some arbitrary inheritence relationship.

so, for me, it is consistent.

consider the more generic case and it makes much more sense

   a =

   class << a
     def foo; 42; end
   end

   a2 =

   class << a2
     def bar; 'forty-two'; end
   end

surely the search path for

   a.bar

should not look into a2's singleton class for it and, conversely,

   a2.foo

should not look into a's singleton class. both methods should raise a
NoMethodError. why? because there exists no relationship between the
singleton classes of two instances of a class. in this case the instances are
of class Array, but remember that ruby classes are just instances of class
Class so the same holds true.

so the only reason that

   class C; end
   class B < C; end

   class << C
     def foo; 42; end
   end
   class << B
     def bar; 'forty-two'; end
   end

permits

   B.foo

is __not__ because B.singleton_class < C.singleton_class. rather it is
because the search path for a method is, naturally, up the ancestor list
hierarchy and, at each step along the way, each class additionally looks
'sideways' into it's singleton_class (it's pocket) but not into the
singleton_class of any other classes since, by definition, those classes
belong only to the object that created them - it would be like looking into
someone else's pockets :wink:

cheers.

-a

···

On Tue, 17 May 2005, Christoph wrote:

Ara.T.Howard@noaa.gov schrieb:

misunderstood something once again?

well - sorta :wink:

i only meant to say that the behaviour is consistent and, although
there is no
regular ruby idiom that makes use of it now, there may well be in the
future.

Actually the behavior is not consistent - assuming the definition
----
public # create meta objects
def m(height =1)
   height.zero? ? self : class << self; self end.m(height -1)
end
----

and the natural inheritance assumption, that the class relation

X < Y # true, implies
X.m < Y.m # true

--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
renunciation is not getting rid of the things of this world, but accepting
that they pass away. --aitken roshi

===============================================================================

David A. Black schrieb:

I'm just not ready for:

  class << obj; def self.x; end; end

to throw an error. It just seems like taking away too much
class-ness -- though obviously if the class interface to object
singleton behavior disappears entirely, that won't be an issue.

I was kind of proposing to throw an error at the next level

class << obj; class << self def self.x; end; end; end

Disallowing the formation of the "singleton singleton class" of
any type of class including "singleton classes" - this would
effectively kill Ara's usage example

As a side note the class Klass lends itself naturally as the mother of all
singleton classes - i.e. "pouch == Klass" - a problem with this idea is that
we currently have Class < Module < Object.

I'm not sure what you mean. If every object's "pouch" is Klass, it
will get very crowded.... But I think I'm misunderstanding.

Singleton classes could be instances of Klass, essentially Klass would be a subclass
and "singleton class" of Class at the same time. This is similar (kind of the higher order
version of) of Matju's proposed identification.
class << Object; self end == Class

/Christoph

Ara.T.Howard@noaa.gov schrieb:

misunderstood something once again?

well - sorta :wink:

i only meant to say that the behaviour is consistent and, although
there is no
regular ruby idiom that makes use of it now, there may well be in the
future.

Actually the behavior is not consistent - assuming the definition
----
public # create meta objects
def m(height =1)
   height.zero? ? self : class << self; self end.m(height -1)
end
----

and the natural inheritance assumption, that the class relation

X < Y # true, implies
X.m < Y.m # true

here we depart. i don't assume this because X's singleton class is just that
: a singleton (eg. one) class with no relation to that of Y's. i think of as
in

  class Clothes
  end

  class Shirts < Clothes
  end

  class Pants < Clothes
  end

  class TShirts < Shirts
  end

now, obviously, we have something of a hierarchy described in 'is-a' terms:
TShirt 'is-a' Shirt, etc.

now we thow in a __separate__ hierarchy : Pockets. so

  class Pocket
  end

Pockets, obviously, being where classes store their personal (singleton)
stuff. :wink:

now we have

  class Clothes
    class Pocket < ::Pocket
    end
  end

  class Shirts
    class Pocket < ::Pocket
    end
  end

now this is a 'has-a' relationship: a Pants 'has-a' Pocket class
(Pants::Pocket) and Shirt 'has-a' Pocket class (Shirt::Pocket). there __is__
a subtle 'is-a' relationshiop between pocket classes : a Shirt::Pocket 'is-a'
::Pocket and a Pant::Pocket 'is-a' Pocket. however we do not (necessarily)
have : Shirt::Pocket 'is-a' Pants::Pocket.

No, that would imply Shirt::Pocket < Pants::Pocket. However, I
think it is profoundly faulty to imply there is not a significant
relationship between the two. Both children should share the traits
of their parent but not those of their siblings.

in this case the Pocket class(es) are singleton classes. all classes have one
that descends from a parent singleton class(es). this is a hierarchy that is
related to, but separate and parallel from, the hierachy of any classes which
may themselves have some arbitrary inheritence relationship.

so, for me, it is consistent.

consider the more generic case and it makes much more sense

  a =

  class << a
    def foo; 42; end
  end

  a2 =

  class << a2
    def bar; 'forty-two'; end
  end

surely the search path for

  a.bar

should not look into a2's singleton class for it and, conversely,

  a2.foo

should not look into a's singleton class. both methods should raise a
NoMethodError. why? because there exists no relationship between the
singleton classes of two instances of a class. in this case the instances are
of class Array, but remember that ruby classes are just instances of class
Class so the same holds true.

Your analysis is correct but the analogy is not quite, er
analogous. To make it similar, each singleton (or pouch)
would be a subclass of Pocket here. Therefore, while the
methods defined in each of them have no relevance to the
other (siblings' traits are not inherited), they _should_
share the methods from any common ancestors.

So, if child_one.pouch and child_two.pouch are subclasses
of parent.pouch, they should both share any methods in
parent.pouch but not (necessarily) eachother.

so the only reason that

  class C; end
  class B < C; end

  class << C
    def foo; 42; end
  end
  class << B
    def bar; 'forty-two'; end
  end

permits

  B.foo

is __not__ because B.singleton_class < C.singleton_class. rather it is
because the search path for a method is, naturally, up the ancestor list
hierarchy and, at each step along the way, each class additionally looks
'sideways' into it's singleton_class (it's pocket) but not into the
singleton_class of any other classes since, by definition, those classes
belong only to the object that created them - it would be like looking into
someone else's pockets :wink:

This is certainly true.

cheers.

-a

E

···

Le 16/5/2005, "Ara.T.Howard@noaa.gov" <Ara.T.Howard@noaa.gov> a écrit:

On Tue, 17 May 2005, Christoph wrote:

--
template<typename duck>
void quack(duck& d) { d.quack(); }

Ara.T.Howard@noaa.gov a écrit :

···

On Tue, 17 May 2005, Christoph wrote:

Ara.T.Howard@noaa.gov schrieb:

misunderstood something once again?

well - sorta :wink:

i only meant to say that the behaviour is consistent and, although
there is no
regular ruby idiom that makes use of it now, there may well be in the
future.

Actually the behavior is not consistent - assuming the definition
----
public # create meta objects
def m(height =1)
   height.zero? ? self : class << self; self end.m(height -1)
end
----

and the natural inheritance assumption, that the class relation

X < Y # true, implies
X.m < Y.m # true

here we depart. i don't assume this because X's singleton class is just
that
: a singleton (eg. one) class with no relation to that of Y's.

[snip]

so the only reason that

  class C; end
  class B < C; end

  class << C
    def foo; 42; end
  end
  class << B
    def bar; 'forty-two'; end
  end

permits

  B.foo

is __not__ because B.singleton_class < C.singleton_class. rather it is
because the search path for a method is, naturally, up the ancestor list
hierarchy and, at each step along the way, each class additionally looks
'sideways' into it's singleton_class (it's pocket) but not into the
singleton_class of any other classes since, by definition, those classes
belong only to the object that created them - it would be like looking into
someone else's pockets :wink:

http://www.ruby-talk.org/cgi-bin/scat.rb/ruby/ruby-talk/140562

If you really want ruby2 works the way you described it, I advice you to
urgently post an RCR for it.

--
Lionel Thiry

Personal website: http://users.skynet.be/lthiry/

Hi --

David A. Black schrieb:

I'm just not ready for:

  class << obj; def self.x; end; end

to throw an error. It just seems like taking away too much
class-ness -- though obviously if the class interface to object
singleton behavior disappears entirely, that won't be an issue.

I was kind of proposing to throw an error at the next level

class << obj; class << self def self.x; end; end; end

Disallowing the formation of the "singleton singleton class" of
any type of class including "singleton classes" - this would
effectively kill Ara's usage example

You're three-deep here, though. I thought you meant to disallow
two-deep (singleton class of a singleton class). (In my example I'm
assuming that "def self.x" puts x into the singleton class of self,
which is itself the singleton class of obj.)

As a side note the class Klass lends itself naturally as the mother of all
singleton classes - i.e. "pouch == Klass" - a problem with this idea is that
we currently have Class < Module < Object.

I'm not sure what you mean. If every object's "pouch" is Klass, it
will get very crowded.... But I think I'm misunderstanding.

Singleton classes could be instances of Klass, essentially Klass would be a subclass
and "singleton class" of Class at the same time. This is similar (kind of the higher order
version of) of Matju's proposed identification.

class << Object; self end == Class

It then becomes a little confusing to call them "classes", since
they're instances of something other than Class. And it raises the
whole subclassing Class problem....

David

···

On Mon, 16 May 2005, Christoph wrote:

--
David A. Black
dblack@wobblini.net

  class Clothes
    class Pocket < ::Pocket
    end
  end

  class Shirts
    class Pocket < ::Pocket
    end
  end

now this is a 'has-a' relationship: a Pants 'has-a' Pocket class
(Pants::Pocket) and Shirt 'has-a' Pocket class (Shirt::Pocket). there __is_=

_

a subtle 'is-a' relationshiop between pocket classes : a Shirt::Pocket 'is-a=

'

::Pocket and a Pant::Pocket 'is-a' Pocket. however we do not (necessarily)
have : Shirt::Pocket 'is-a' Pants::Pocket.

No, that would imply Shirt::Pocket < Pants::Pocket.

how do you figure:

     harp:~ > cat a.rb
     class Pocket; end
     class Clothes; class Pocket < ::Pocket; end; end
     class Shirts; class Pocket < ::Pocket; end; end

     p Clothes::Pocket.ancestors
     p Shirts::Pocket.ancestors

     harp:~ > ruby a.rb
     [Clothes::Pocket, Pocket, Object, Kernel]
     [Shirts::Pocket, Pocket, Object, Kernel]

??

However, I think it is > profoundly faulty to imply there is not a
significant relationship between the two. Both children should share the traits of their parent but not those
of their siblings.

but this is exactly the case? in the above both pocket classes share the
traits of their common parent, Pocket, and neither one shares that of their
siblings. this is precisely the case of singleton classes - they all descend
from [Class, Module, Object, Kernel] (the parent classes) and share those
traits - such as the ability to do 'self.attr :foobar'. i think the mistake
people are making is thinking that by doing

   foo = Foo::new

   singleton_class = class << foo; self; end

is in thinking that singleton_class 'isa' foo. that is simply not the case.
rather 'singleton_class' is owned by foo. in otherwords foo 'has-a'
singleton_class and their is no parent child relationship between the two.

i think if the syntax were more like

   class Foo
     singleton_class = generate_a_singleton_class
     singleton_class.attr :bar
   end

vs.

   class Foo
     class << self
       attr :bar
     end
   end

this might be more clear. visually the '<<' syntax is similar to '<' in 'A <
B' but it doesn't do anything similar - it only generates a special object
owned by the object calling the '<<' operator.

Your analysis is correct but the analogy is not quite, er
analogous. To make it similar, each singleton (or pouch)
would be a subclass of Pocket here. Therefore, while the
methods defined in each of them have no relevance to the
other (siblings' traits are not inherited), they _should_
share the methods from any common ancestors.

they do. both singletons share the common attributes of their parents:

   [Class, Module, Object, Kernel]

again the issue is that

   class C
     class << self
       this_is_a_child_of_Class_not_a_child_of_C = self
     end
   end

so you are right and the analogy is too - all singleton classes share all the
traits of their common ancestors. it's just that those ancestors don't seem
to be who people think they are :wink:

So, if child_one.pouch and child_two.pouch are subclasses of parent.pouch,
they should both share any methods in parent.pouch but not (necessarily)
eachother.

you'd be right if that were the relationship between parent/child classes and
their respective singleton classes - but with singleton_classes child_one.pouch
is a subclass of Pouch and child_two.pouch is a subclass of Pouch and child_one
and child_two are both children of Parent. check this out closely and you'll
see it for yourself:

   harp:~ > cat a.rb
   class Class
     def pouch; class << self; self; end; end
   end
   class Parent
     p ancestors
     p pouch.ancestors
   end
   class ChildOne < Parent
     p ancestors
     p pouch.ancestors
   end
   class ChildTwo < Parent
     p ancestors
     p pouch.ancestors
   end

   harp:~ > ruby a.rb

   [Parent, Object, Kernel]
   [Class, Module, Object, Kernel]

   [ChildOne, Parent, Object, Kernel]
   [Class, Module, Object, Kernel]

   [ChildTwo, Parent, Object, Kernel]
   [Class, Module, Object, Kernel]

so the only common ancestors between all the pouches of the above clases are
[Class, Module, Object, Kernel] and they definitely do inherit all the methods
from those ancestors.

note that there is relationship __added__ to the pouches by being pouches of
parent/child classes : all pouches descend from the same Pouch class as in my
Pocket example above.

for some reason i get the feeling we might be saying the same thing an i'm just
saying it badly?

cheers.

-a

···

On Tue, 17 May 2005, ES wrote:
--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
renunciation is not getting rid of the things of this world, but accepting
that they pass away. --aitken roshi

===============================================================================

http://www.ruby-talk.org/cgi-bin/scat.rb/ruby/ruby-talk/140562

yes i saw that.

If you really want ruby2 works the way you described it, I advice you to
urgently post an RCR for it.

no. the new behaviour is fine - i was simply describing how it is now and how
that relates to the 'infinite levels' issue in that i think it's strange -
but consistent. believe me - you've no idea how much easier my trait lib
would have been to write if

   child.singleton_class < parent.singleton_class

as it were i had to do this

   class << self
     # determine our 'singleton_super' so we can use it's ancestors
   end

and this is precisely because parent/child meta classes do not fit into the
same kind of hierarchy as their respective classes. so i will love the new
behaviour.

i'm going to quit on this now because i feel like i've only confused things.
sorry if i have.

cheers.

-a

···

On Tue, 17 May 2005, Lionel Thiry wrote:
--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
renunciation is not getting rid of the things of this world, but accepting
that they pass away. --aitken roshi

===============================================================================

David A. Black schrieb:

You're three-deep here, though. I thought you meant to disallow
two-deep (singleton class of a singleton class). (In my example I'm
assuming that "def self.x" puts x into the singleton class of self,
which is itself the singleton class of obj.)

Sorry for being my confusing self::slight_smile:

It then becomes a little confusing to call them "classes", since
they're instances of something other than Class. And it raises the
whole subclassing Class problem....

Well that's the whole point they (singleton classes) are classes
but they are also very special kind of classes. For normal objects
you would xpress this kind of relation ship by sub classing.
For example, similar to

···

---
class Rodent; end
class Mouse < Rodent; end
jerry.instance_of?(Mouse) # true
jerry.instance_of?(Rodent) # false
jerry.kind_of?(Rodent) # true
---

it would be

---
class Klass < Class; end # we also have Klass == class << Class; self end

Jerry = class << self; self end
Jerry.instance_of?(Klass) # true
Jerry.instance_of?(Class) # false
Jerry.kind_of?(Class) # true
----

The sub classing problem isn't all that bad because you could allow
sub classing Class exactly once (during the boot up of the object model).
Being a subclass and singleton of a class at the same time may sound
a bit confusing. On the hand, it also would emphasize the central role
of Object, Class (and possibly Klass) and the normal user would never
notice the difference.

/Christoph

  class Clothes
    class Pocket < ::Pocket
    end
  end

  class Shirts
    class Pocket < ::Pocket
    end
  end

now this is a 'has-a' relationship: a Pants 'has-a' Pocket class
(Pants::Pocket) and Shirt 'has-a' Pocket class (Shirt::Pocket). there __is_=

_

a subtle 'is-a' relationshiop between pocket classes : a Shirt::Pocket 'is-a=

'

::Pocket and a Pant::Pocket 'is-a' Pocket. however we do not (necessarily)
have : Shirt::Pocket 'is-a' Pants::Pocket.

No, that would imply Shirt::Pocket < Pants::Pocket.

how do you figure:

    harp:~ > cat a.rb
    class Pocket; end
    class Clothes; class Pocket < ::Pocket; end; end
    class Shirts; class Pocket < ::Pocket; end; end

    p Clothes::Pocket.ancestors
    p Shirts::Pocket.ancestors

    harp:~ > ruby a.rb
    [Clothes::Pocket, Pocket, Object, Kernel]
    [Shirts::Pocket, Pocket, Object, Kernel]

??

Er, I think I was too curt. I meant to say, "No, we do not necessarily
have Shirt::Pocket is-a Pants::Pocket, _that_ would imply Shirt::Pocket
< Pants::Pocket. However..." I was agreeing with you on that point but
disagreeing later :slight_smile:

However, I think it is > profoundly faulty to imply there is not a
significant relationship between the two.
Both children should share the traits of their parent but not those
of their siblings.

but this is exactly the case? in the above both pocket classes share the
traits of their common parent, Pocket, --

Yes, I was merely pointing out that I thought you were perhaps not
describing the relationship of the siblings accurately.

-- and neither one shares that of their
siblings. this is precisely the case of singleton classes - they all descend
from [Class, Module, Object, Kernel] (the parent classes) and share those
traits - such as the ability to do 'self.attr :foobar'. i think the mistake
people are making is thinking that by doing

  foo = Foo::new

  singleton_class = class << foo; self; end

is in thinking that singleton_class 'isa' foo. that is simply not the case.
rather 'singleton_class' is owned by foo. in otherwords foo 'has-a'
singleton_class and their is no parent child relationship between the two.

Hm, that is a good point, and may well be a common confusion.

i think if the syntax were more like

  class Foo
    singleton_class = generate_a_singleton_class
    singleton_class.attr :bar
  end

vs.

  class Foo
    class << self
      attr :bar
    end
  end

this might be more clear. visually the '<<' syntax is similar to '<' in 'A <
B' but it doesn't do anything similar - it only generates a special object
owned by the object calling the '<<' operator.

Your analysis is correct but the analogy is not quite, er
analogous. To make it similar, each singleton (or pouch)
would be a subclass of Pocket here. Therefore, while the
methods defined in each of them have no relevance to the
other (siblings' traits are not inherited), they _should_
share the methods from any common ancestors.

they do. both singletons share the common attributes of their parents:

  [Class, Module, Object, Kernel]

again the issue is that

  class C
    class << self
      this_is_a_child_of_Class_not_a_child_of_C = self
    end
  end

so you are right and the analogy is too - all singleton classes share all the
traits of their common ancestors. it's just that those ancestors don't seem
to be who people think they are :wink:

So, if child_one.pouch and child_two.pouch are subclasses of parent.pouch,
they should both share any methods in parent.pouch but not (necessarily)
eachother.

you'd be right if that were the relationship between parent/child classes and
their respective singleton classes - but with singleton_classes child_one.pouch
is a subclass of Pouch and child_two.pouch is a subclass of Pouch and child_one
and child_two are both children of Parent. check this out closely and you'll
see it for yourself:

Agreed! Words fail me again; the 'are' should have been 'were' to
signal a hypothetical.

  harp:~ > cat a.rb
  class Class
    def pouch; class << self; self; end; end
  end
  class Parent
    p ancestors
    p pouch.ancestors
  end
  class ChildOne < Parent
    p ancestors
    p pouch.ancestors
  end
  class ChildTwo < Parent
    p ancestors
    p pouch.ancestors
  end

  harp:~ > ruby a.rb

  [Parent, Object, Kernel]
  [Class, Module, Object, Kernel]

  [ChildOne, Parent, Object, Kernel]
  [Class, Module, Object, Kernel]

  [ChildTwo, Parent, Object, Kernel]
  [Class, Module, Object, Kernel]

so the only common ancestors between all the pouches of the above clases are
[Class, Module, Object, Kernel] and they definitely do inherit all the methods
from those ancestors.

note that there is relationship __added__ to the pouches by being pouches of
parent/child classes : all pouches descend from the same Pouch class as in my
Pocket example above.

for some reason i get the feeling we might be saying the same thing an i'm just
saying it badly?

I are both think we uncommunicating miswell.

Yes, I generally agree with what you are saying, definitely. My
objection was merely to you (to me) not describing the 'common
lineage' of the two singletons/pouches correctly, rather than
the entire explanation. I was not clear about this, sorry.

cheers.

-a

E

···

Le 16/5/2005, "Ara.T.Howard@noaa.gov" <Ara.T.Howard@noaa.gov> a écrit:

On Tue, 17 May 2005, ES wrote:

--
template<typename duck>
void quack(duck& d) { d.quack(); }

Ara.T.Howard@noaa.gov schrieb:

no. the new behaviour is fine - i was simply describing how it is now and how
that relates to the 'infinite levels' issue in that i think it's strange -
but consistent. believe me - you've no idea how much easier my trait lib
would have been to write if

  child.singleton_class < parent.singleton_class

Well it would be nice if this were true, but it's not - "higher order" singleton class
behavior changed quite a bit in the past and it so again from 1.82 to todays cvs.
Lionel point was because Ruby does not seem to have a consistent treatment
(consitency is always relative to the reades eyes) of these "higher order" singleton
classes, they should be forbidden in the first place. I ran the following script
with a standard 1.82, todays cvs.

···

----
puts RUBY_VERSION
public # create meta objects

def m(height =1)
   height.zero? ? self : class << self; self end.m(height -1)
end

base = [Object,Module, Class]
require 'enumerator'

(0..11).each_cons(2) do |a,b|
  d0,r0 = a.divmod(3)
  d1,r1 = b.divmod(3)
  rel = base[r0].m(d0) > base[r1].m(d1)
  puts "#{base[r0]}.m(#{d0}) > #{base[r1]}.m(#{d1}) # #{rel}"
end

class A; end
class B < A; end

def q(s)
  puts s << " # #{eval(s)}"
end

puts "\n###","\n"
q "B.new.m(5) < B.m(4)"
q "B.m(4) < A.m(4)"
q "A.m(4) < Object.m(4)"

puts "\n### print superclass chain","\n"
class Class
  alias succ superclass
end

(1..8).each do |i|
  puts ((B.new.m(i)..Object).to_a.join(" : "))
end
---

These were the two outputs

---
1.9.0
Object.m(0) > Module.m(0) # true
Module.m(0) > Class.m(0) # true
Class.m(0) > Object.m(1) # true
Object.m(1) > Module.m(1) # true
Module.m(1) > Class.m(1) # true
Class.m(1) > Object.m(2) # false
Object.m(2) > Module.m(2) # false
Module.m(2) > Class.m(2) # false
Class.m(2) > Object.m(3) # true
Object.m(3) > Module.m(3) # false
Module.m(3) > Class.m(3) # false

###

B.new.m(5) < B.m(4) # true
B.m(4) < A.m(4) # false
A.m(4) < Object.m(4) # false
### print superclass chain

#<Class:#<B:0x101030a0>> : B : A : Object
Class : Module : Object
#<Class:Class> : #<Class:Module> : #<Class:Object> : Class : Module : Object
Class : Module : Object
#<Class:Class> : #<Class:Module> : #<Class:Object> : Class : Module : Object
Class : Module : Object
#<Class:Class> : #<Class:Module> : #<Class:Object> : Class : Module : Object
Class : Module : Object
---
and
---
1.8.2
Object.m(0) > Module.m(0) # true
Module.m(0) > Class.m(0) # true
Class.m(0) > Object.m(1) # true
Object.m(1) > Module.m(1) #
Module.m(1) > Class.m(1) # true
Class.m(1) > Object.m(2) # true
Object.m(2) > Module.m(2) #
Module.m(2) > Class.m(2) #
Class.m(2) > Object.m(3) #
Object.m(3) > Module.m(3) #
Module.m(3) > Class.m(3) #

###

B.new.m(5) < B.m(4) #
B.m(4) < A.m(4) #
A.m(4) < Object.m(4) #
### print superclass chain

#<Class:#<B:0x2793bc8>> : B : A : Object
#<Class:#<Class:#<B:0x2793a60>>> : #<Class:B> : #<Class:A> : #<Class:Object> : Class : Module : Object
#<Class:#<Class:#<Class:#<B:0x2793820>>>> : #<Class:Class> : #<Class:Module> : #<Class:Object> : Class : Module : Object
#<Class:#<Class:#<Class:#<Class:#<B:0x2793598>>>>> : #<Class:Class> : #<Class:Module> : #<Class:Object> : Class : Module : Object
#<Class:#<Class:#<Class:#<Class:#<Class:#<B:0x27932c8>>>>>> : #<Class:Class> : #<Class:Module> : #<Class:Object> : Class : Module : Object
#<Class:#<Class:#<Class:#<Class:#<Class:#<Class:#<B:0x2792fb0>>>>>>> : #<Class:Class> : #<Class:Module> : #<Class:Object> : Class : Module : Object
#<Class:#<Class:#<Class:#<Class:#<Class:#<Class:#<Class:#<B:0x2792c50>>>>>>>> : #<Class:Class> : #<Class:Module> : #<Class:Object> : Class : Module : Object
#<Class:#<Class:#<Class:#<Class:#<Class:#<Class:#<Class:#<Class:#<B:0x27928a8>>>>>>>>> : #<Class:Class> : #<Class:Module> : #<Class:Object> : Class : Module : Object
---

as it were i had to do this

  class << self
    # determine our 'singleton_super' so we can use it's ancestors
  end

and this is precisely because parent/child meta classes do not fit into the
same kind of hierarchy as their respective classes. so i will love the new
behaviour.

i'm going to quit on this now because i feel like i've only confused things.
sorry if i have.

I promise I will quit this too, well after this post:-)

/Christoph

Er, I think I was too curt. I meant to say, "No, we do not necessarily have
Shirt::Pocket is-a Pants::Pocket, _that_ would imply Shirt::Pocket <
Pants::Pocket. However..." I was agreeing with you on that point but
disagreeing later :slight_smile:

ah - i'm on board now.

is in thinking that singleton_class 'isa' foo. that is simply not the case.
rather 'singleton_class' is owned by foo. in otherwords foo 'has-a'
singleton_class and their is no parent child relationship between the two.

Hm, that is a good point, and may well be a common confusion.

it confused me! :wink:

Agreed! Words fail me again; the 'are' should have been 'were' to signal a
hypothetical.

o.k. - we're on a roll!

I are both think we uncommunicating miswell.

who? what? where?

Yes, I generally agree with what you are saying, definitely. My objection
was merely to you (to me) not describing the 'common lineage' of the two
singletons/pouches correctly, rather than the entire explanation. I was not
clear about this, sorry.

no problem. i had to really struggle to figure all this out for my traits.rb
lib and am still looking for any opportunity to refine my understanding -
which was the entire motivation for the long post : i'm trying to make
__sure__ i know what i think i know.

ciao.

-a

···

On Tue, 17 May 2005, ES wrote:
--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
renunciation is not getting rid of the things of this world, but accepting
that they pass away. --aitken roshi

===============================================================================