[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

class << x

Greg McIntyre

11/30/2003 3:00:00 AM

[ruby-talk:86745] reminded me of something I was going to ask.

I know "class << x" does, but can somebody explain to me the rationale
behind the syntax? How should I "read" it? I currently read it as
"open x's class for modification". Is that right?

I was quite confused about it when I first learned Ruby.

class A
class << self # what does this mean? (says newbie Greg)
# ...
end
end

Even the more "direct" usage is confusing, IMHO:

class B
# ...
end

b = B.new

class << b # what does this mean? (says newbie Greg)
def f
# ...
end
end

What about this, as an alternative (for Ruby 2?):

class A
class A # or "class self"
# ...
end
end

class b.class
def f
# ...
end
end

--
Greg McIntyre ======[ greg@puyo.cjb.net ]===[ http://pu... ]===
13 Answers

Greg McIntyre

11/30/2003 3:02:00 AM

0

Greg McIntyre <greg@puyo.cjb.net> wrote:
> I was quite confused about it when I first learned Ruby.
^^^^^^^
"learnt", sorry.

--
Greg McIntyre ======[ greg@puyo.cjb.net ]===[ http://pu... ]===

Tim Bates

11/30/2003 3:12:00 AM

0

On Sun, Nov 30, 2003 at 12:07:08PM +0900, Greg McIntyre wrote:
> > I was quite confused about it when I first learned Ruby.
> ^^^^^^^
> "learnt", sorry.

Both are correct, depending on who you ask. ;)

Tim Bates
--
tim@bates.id.au

Mark J. Reed

11/30/2003 3:24:00 AM

0

On Sun, Nov 30, 2003 at 01:59:54PM +1100, Greg McIntyre wrote:
> I know "class << x" does, but can somebody explain to me the rationale
> behind the syntax?

First: classes in Ruby are objects, just like everything
else. In particular, they are objects of the class named Class
(which is an instance of itself!). There's nothing magical about
them; in particular, a class is a *value*. Now, the usual way of
creating a class ("class Name") happens to simultaneously create
a constant (in this case Name) referring to the created class,
but that's not the only way of creating a class. You can, in fact,
create anonymous classes, and one way of doing that is via "class
<< object".

What "class << object" does is create a new, unnamed class and make
that class the new class of "object", putting it in between the instance
and its original class. It does this transparently; for instance,
calling "class" on the object still reports the original class, because
the class method is written to skip over anonymous classes.

The upshot is that you can define methods on an object without defining
them for all objects of that class. For instance:

irb(main):001:0> greeting = "Hello"
=> "Hello"
irb(main):002:0> class << greeting
irb(main):003:1> def greet(x="World")
irb(main):004:2> puts "#{self}, #{x}!"
irb(main):005:2> end
irb(main):006:1> end
=> nil
irb(main):007:0> greeting.greet
Hello, World!
=> nil
irb(main):008:0> "Hello".greet
NoMethodError: undefined method `greet' for "Hello":String
from (irb):8

Note that the method is associated with the value, not the variable you
use to access it:

irb(main):009:0> yo=greeting
=> "Hello"
irb(main):010:0> yo.greet
Hello, World!
irb(main):011:0> greeting="Hi"
=> "Hi"
irb(main):012:0> greeting.greet
NoMethodError: undefined method `greet' for "Hi":String
from (irb):12

So, what happens when the object on the right of the "<<" is a class?
Exactly the same thing! It gives you the ability to define methods on
that class (which is, again, just another object) without having to
define them for all objects of its class (which is Class). If you
defined a method of Class it would be available on all classes in
Ruby; 'new' is such a method, for instance.

-Mark

Greg McIntyre

11/30/2003 3:55:00 AM

0

I didn't ask what it does. I understand perfectly what "class << x" does
and how it works and all about anonymous classes. What I asked was, why
is the syntax "class << x"? Is there a reason? Why "class << x"?

--
Greg McIntyre ======[ greg@puyo.cjb.net ]===[ http://pu... ]===

Mark J. Reed

11/30/2003 4:10:00 AM

0

On Sun, Nov 30, 2003 at 02:55:09PM +1100, Greg McIntyre wrote:
> I didn't ask what it does. I understand perfectly what "class << x" does
> and how it works and all about anonymous classes.

I apologize; I was only trying to help, not impugn your knowledge,
And the reading "open x's class for modification" didn't sound like
you understood it, since "class << x" *doesn't* modify x's class, but rather
creates a new subclass just for x.

> What I asked was, why is the syntax "class << x"? Is there a reason?
> Why "class << x"?

It's designed to suggest that something very similar to
"class X < Y" (which defines a new class X as a subclass of Y)
is going on. The main differences are:

1. the new class has no name (so there's nothing on the left of
the <<)

2. the object on the right is not used directly as the superclass,
even if it happens to be a class object; rather, its class
is used.

2. that object is modified such that it becomes an instance of
the new class (whereas class X < Y doesn't modify Y at all).

-Mark

Greg McIntyre

11/30/2003 4:37:00 AM

0

"Mark J. Reed" <markjreed@mail.com> wrote:
> On Sun, Nov 30, 2003 at 02:55:09PM +1100, Greg McIntyre wrote:
> > I didn't ask what it does. I understand perfectly what "class << x"
> > does and how it works and all about anonymous classes.
>
> I apologize; I was only trying to help, not impugn your knowledge,
> And the reading "open x's class for modification" didn't sound like
> you understood it, since "class << x" *doesn't* modify x's class, but
> rather creates a new subclass just for x.
>
> > What I asked was, why is the syntax "class << x"? Is there a reason?
> > Why "class << x"?
>
> It's designed to suggest that something very similar to
> "class X < Y" (which defines a new class X as a subclass of Y)
> is going on. The main differences are:
>
> 1. the new class has no name (so there's nothing on the left of
> the <<)
>
> 2. the object on the right is not used directly as the
> superclass,
> even if it happens to be a class object; rather, its class
> is used.
>
> 2. that object is modified such that it becomes an instance of
> the new class (whereas class X < Y doesn't modify Y at all).

I'm sorry, I was very curt. Thanks for spending time to answer me fully.
That's something I love about ruby-talk and I'd hate to be unthankful of
it.

In all the time I've used Ruby, I've never recognised the similarity
between "class X < Y" and "class << y". I suppose everybody else here
thinks it's obvious.

It does sort of kind of mean "open x's class", if you interpret x's
class as it's _current_ class (possibly "type") and not the class object
used to create x (which is the usual sense for "x's class"). I think in
the past I've let some non-lingual section of my brain take over
whenever I saw "class << x". :-) Everything goes fuzzy and I just kind
of ignore the syntax and see the semantics. But it'd be nice if I
understood it at a rational, logical level too. :-)

--
Greg McIntyre ======[ greg@puyo.cjb.net ]===[ http://pu... ]===

Gavin Sinclair

11/30/2003 6:25:00 AM

0

On Sunday, November 30, 2003, 2:57:07 PM, Greg wrote:

> I didn't ask what it does. I understand perfectly what "class << x" does
> and how it works and all about anonymous classes. What I asked was, why
> is the syntax "class << x"? Is there a reason? Why "class << x"?

When I was a newbie, I accepted

o = Object.new

class << o
...
end

perfectly well. I didn't have a way to "read" it, but I was happy
with the syntax. It took a bit of mental gymnastics to understand

class A
class << self
...
end
end

but I wouldn't sacrifice the unity of concept (a class is an object)
for anything.

To summarise: I've never been put out by the syntax that Ruby has to
offer in this regard, and see no need for an alternative.

The alternative you offer is invalid, because it treads on a valid
concept in Ruby: classes within classes.

class A
class A
puts self.to_s # "A::A"
end
end

And the other thing you offer I find confusing:

b = B.new
class b.class
def f
...
end
end

I expected this to add a method to B (the class, not the object), but
it was a syntax error. Why? b.class evaluates to B, and class B is
valid. Oh well. Anyway, I hope I've demonstrated why it doesn't
communicate with me what you want it to.

To summarise, again. The issues that you raise are certainly things
that need to be explained to newbies quite often. Normally, that
would reasonably be seen as a problem with the language. In this
case, however, I think the language has it right and everybody needs
to adjust their thinking.

Cheers,
Gavin



Joel VanderWerf

11/30/2003 8:03:00 AM

0


The 'class << x' notation has some weaknesses:

* It looks a bit like a heredoc, but there is no analogy.

* '<<' does not have any other role as an operator or special form
associated with singleton classes.

* '<<' suggests an append or shift operation, or perhaps a "much less
than" comparison, or even some kind of bracket ('<<x,y,z>>') notation.

* It looks too much like 'class Y < x' in which the new class Y is less
than x in the ancestral sense. However, the analogy is false--there is
no class below x.

* How do you read it? "class under x"? "class singleton of x"?

It has bothered me for the last 3 years, but I simply accept it as an
idiom and get on with life. We don't always have to construct meaning
for the symbols we push around.

Still, I'd feel better if there were some method on objects that
returned the singleton class and you could use that in a class
definition, something like this:

def singleton(x); class << x; self; end; end

x = [0,1,2,3]

# class singleton(x); end # parse error!

singleton(x).class_eval do
def last_elt; at(-1); end
end

p x.last_elt # ==> 3

But this is a poor workaround, since do..end and class..end have
different scoping rules.



Greg McIntyre

11/30/2003 9:02:00 AM

0

Gavin Sinclair <gsinclair@soyabean.com.au> wrote:
> The alternative you offer is invalid, because it treads on a valid
> concept in Ruby: classes within classes.

Oops! I think I was a bit tired when I wrote that! :-) Sorry.


> It took a bit of mental gymnastics to understand...
> class A
> class << self
> ...
> end
> end

[snip]

> I've never been put out by the syntax that Ruby has to
> offer in this regard, and see no need for an alternative.

Isn't that contradictory? -- It took mental gymnastics to understand,
but never put you out?

My limited intelligence prevents me coming up with good alternatives,
however I still think that the syntax "class << x" is a language wart.
Here are some more carefully considered (but probably flawed)
alternatives which look clearer to me:

0) Syntax "class << x" (for comparsion)

class A; end
class B; end
b = B.new

class << A # add singleton methods to A
def f; end
end

class << b # add singleton methods to b
def f; end
end

A.f
b.f

class A
class << self # add singleton methods to A
def x; end
end
end

A.x

1) Method Object#anonymous_class

class A; end
class B; end
b = B.new

A.class # => Class
A.anonymous_class # => #<Class:A>
b.class # => B
b.anonymous_class # =>

class A.anonymous_class # add singleton methods to A
def f; end
end

class b.anonymous_class # add singleton methods to b
def f; end
end

A.f
b.f

class A
class anonymous_class # add singleton methods to A
def x; end
end
end

A.x

(2) Keyword 'singleton'

Keyword/special method called 'singleton' which opens an object's
anonymous class for editing. Argument defaults to 'self'.

class A; end
class B; end
b = B.new

singleton A # add singleton methods to A
def f; end
end

singleton b # add singleton methods to b
def f; end
end

A.f
b.f

class A
singleton # add singleton methods to A
def x; end
end
end

A.x

(3) Method Object#singleton{|anonymous_class| ... }

Like the keyword, but as a method which takes a block which assigns
to 'self'.

class A; end
class B; end
b = B.new

A.singleton do |self|
self.to_s # => "#<Class:A>"
def f; end # defines self.f
end

b.singleton do |self|
self.to_s # => "#<Class:#<B:0x401cff20>>"
def f; end # defines self.f
end

A.f
b.f

class A
singleton do |self| # add singleton methods to A
def x; end # defines self.f
end
end

A.x

-------

I think I was trying to suggest alternative (1) but without enough
sleep to distinguish between an object's class and an object's
anonymous class, and without checking what I'd written properly.

--
Greg McIntyre ======[ greg@puyo.cjb.net ]===[ http://pu... ]===

Greg McIntyre

11/30/2003 9:05:00 AM

0

Oops, let me just untabify that for you...

<M-x> untabify

There. :-)


Gavin Sinclair <gsinclair@soyabean.com.au> wrote:
> The alternative you offer is invalid, because it treads on a valid
> concept in Ruby: classes within classes.

Oops! I think I was a bit tired when I wrote that! :-) Sorry.


> It took a bit of mental gymnastics to understand...
> class A
> class << self
> ...
> end
> end

[snip]

> I've never been put out by the syntax that Ruby has to
> offer in this regard, and see no need for an alternative.

Isn't that contradictory? -- It took mental gymnastics to understand,
but never put you out?

My limited intelligence prevents me coming up with good alternatives,
however I still think that the syntax "class << x" is a language wart.
Here are some more carefully considered (but probably flawed)
alternatives which look clearer to me:

0) Syntax "class << x" (for comparsion)

class A; end
class B; end
b = B.new

class << A # add singleton methods to A
def f; end
end

class << b # add singleton methods to b
def f; end
end

A.f
b.f

class A
class << self # add singleton methods to A
def x; end
end
end

A.x

1) Method Object#anonymous_class

class A; end
class B; end
b = B.new

A.class # => Class
A.anonymous_class # => #<Class:A>
b.class # => B
b.anonymous_class # =>

class A.anonymous_class # add singleton methods to A
def f; end
end

class b.anonymous_class # add singleton methods to b
def f; end
end

A.f
b.f

class A
class anonymous_class # add singleton methods to A
def x; end
end
end

A.x

(2) Keyword 'singleton'

Keyword/special method called 'singleton' which opens an object's
anonymous class for editing. Argument defaults to 'self'.

class A; end
class B; end
b = B.new

singleton A # add singleton methods to A
def f; end
end

singleton b # add singleton methods to b
def f; end
end

A.f
b.f

class A
singleton # add singleton methods to A
def x; end
end
end

A.x

(3) Method Object#singleton{|anonymous_class| ... }

Like the keyword, but as a method which takes a block which assigns
to 'self'.

class A; end
class B; end
b = B.new

A.singleton do |self|
self.to_s # => "#<Class:A>"
def f; end # defines self.f
end

b.singleton do |self|
self.to_s # => "#<Class:#<B:0x401cff20>>"
def f; end # defines self.f
end

A.f
b.f

class A
singleton do |self| # add singleton methods to A
def x; end # defines self.f
end
end

A.x

-------

I think I was trying to suggest alternative (1) but without enough
sleep to distinguish between an object's class and an object's
anonymous class, and without checking what I'd written properly.

--
Greg McIntyre ======[ greg@puyo.cjb.net ]===[ http://pu... ]===