class << x

G

Greg McIntyre

[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
 
G

Greg McIntyre

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"?
 
G

Greg McIntyre

Mark J. Reed said:
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.


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. :)
 
G

Gavin Sinclair

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
 
J

Joel VanderWerf

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.
 
G

Greg McIntyre

Gavin Sinclair said:
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
 
G

Greg McIntyre

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

<M-x> untabify

There. :)


Gavin Sinclair said:
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
 
G

Gavin Sinclair

The 'class << x' notation has some weaknesses:
* It looks a bit like a heredoc, but there is no analogy.

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

No, but one's enough. How many operators associated with singleton
classes do you want?
* '<<' suggests an append or shift operation, or perhaps a "much less
than" comparison, or even some kind of bracket ('<<x,y,z>>') notation.

This is where the analogy holds reasonalby well for me. I see it as
some class derived from 'x'.
* 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.

I'm not sure about that. Isn't there an anonymous class that's
roughly interpreted as "the singleton class of x"?
* How do you read it? "class under x"? "class singleton of x"?

"Class under x" is good enough for me. However, I don't tend to read
it as anything, rather "class << x" appears as a single token in my
mind :)
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.

That's the key, really. Before Ruby, I'd never heard of singleton
methods on an object. If the concept is unfamiliar, as I suspect it
is to many people, then it's asking a bit much for the symbol to
communicate the meaning. That's why I hold that it's just something
people have to learn about Ruby, and that's all there is to it.
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

In extensions.rubyforge.org, I included Object#singleton_class, with
the documentation:

Returns the singleton class associated with this object. How useful
this is I don’t know, but it’s an idiom that has appeared on
ruby-talk several times.

:)
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.

It's also poor because it mandates the use of eval, IMO.

Thanks for the interesting tour!

Gavin
 
A

Asfand Yar Qazi

Greg said:
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.

I learnt from it. So it was good!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,141
Messages
2,570,815
Members
47,361
Latest member
RogerDuabe

Latest Threads

Top