[ANN] Article: Seeing Metaclasses Clearly

  • Thread starter why the lucky stiff
  • Start date
S

Sascha Ebach

why said:
I've written a very nuts+bolts article on metaclasses (aka virtual
classes or metaobjects), since they still lurk under a shroud of fear
and enigma.

<http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html>

I'm hoping this will help uncover the truth. If anything is unclear,
please report it. Shed a light.

Very nice and thanks,

would you mind using a print stylesheet so the article can be nicely
printed out?

Sascha Ebach
 
D

David A. Black

Hi --

I've written a very nuts+bolts article on metaclasses (aka virtual classes or
metaobjects), since they still lurk under a shroud of fear and enigma.

<http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html>

I'm hoping this will help uncover the truth. If anything is unclear, please
report it. Shed a light.

For some reason the first 1/8 inch or so on the left are cut off on my
browser. I don't know whether it's a CSS thing or a browser thing
(Netscape 6). So "methods" comes out as "thods", etc.

The tutorial itself looks good, though the terminology in this area
continues to be a problem. My understanding is that the most general
term is "singleton class", and that "metaclass" is a special term for
singleton class of a Class object. (See Pickaxe, 2nd ed., p. 382.)
So, for example, I would rename your Object#metaclass method
#singleton_class, since it applies to all objects (as per RCR 231).

Then there's "virtual class", which I think is the weakest and least
useful term, certainly at a general level. The Matz paraphrase on
p.382 suggests that virtual-ness is more a matter of implementation
than anything language-level, which is good. I haven't checked, but
I'm hoping the > 1.8 error messages will cease to refer to "virtual"
classes (e.g., when you try to get at the singleton class of a
Fixnum).


David
 
F

Florian Groß

why said:
<http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html>

I'm hoping this will help uncover the truth. If anything is unclear,
please report it. Shed a light.

Nice article, but I disagree in the point that @@vars are simpler than
class instance variables. Class instance variables have odd semantics in
the current Ruby which means that they will probably do some detail
different than you expect.

I've found that sticking to class instance variables (and thus keeping
things simple -- why do we need another type of variables again?) helps
in making code easier to understand.

Perhaps you should display both sides of this in the article.
 
G

Gavin Kistner

Nice article, but I disagree in the point that @@vars are simpler than
class instance variables. Class instance variables have odd semantics
in the current Ruby which means that they will probably do some detail
different than you expect.

But you have to do:

class Foo
@var1 = []
@var2 = {}
class << self
attr_accessor :var1, :var2
end
end

to get reasonable access to those class instance variables inside an
instance method, and even then you have to do self.class.var1


Once you 'get it' it's not TERRIBLY difficult, but I would say that the
above is more than enough justification for calling @@foo simpler.
Simpler, but also confusing in the inherited-class cases. (So confusing
that I still don't fully grok what specifically occurs that makes @@foo
unusable, and when it occurs. I'm still grasping at the fringes of the
tablecloth.)
 
R

Robert Klemme

Florian Groß said:
Nice article, but I disagree in the point that @@vars are simpler than
class instance variables. Class instance variables have odd semantics in
the current Ruby which means that they will probably do some detail
different than you expect.

I've found that sticking to class instance variables (and thus keeping
things simple -- why do we need another type of variables again?) helps
in making code easier to understand.
+1

Perhaps you should display both sides of this in the article.

Yeah, I missed that, too. In fact, the article seems to discourage class
instance variable usage...

Kind regards

robert
 
K

Karl von Laudermann

why said:
I've written a very nuts+bolts article on metaclasses (aka virtual
classes or metaobjects), since they still lurk under a shroud of fear
and enigma.

<http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html>

I'm hoping this will help uncover the truth. If anything is unclear,
please report it. Shed a light.

Noticed a small mistake; At one point, you refer to the at-sign (@) as
an ampersand. Other than that... the article went way over my head and
twisted my poor brain into knots. :-( I think I'll need to re-read
chapter 24 of Pickaxe 2 immediately before reading this article.
 
W

why the lucky stiff

Florian said:
Nice article, but I disagree in the point that @@vars are simpler than
class instance variables. Class instance variables have odd semantics in
the current Ruby which means that they will probably do some detail
different than you expect.

You're right. I'm oversimplifying this. I need to discuss the
metaclass/inheritance thing a bit more.

_why
 
C

Curt Hibbs

David said:
Hi --




For some reason the first 1/8 inch or so on the left are cut off on my
browser. I don't know whether it's a CSS thing or a browser thing
(Netscape 6). So "methods" comes out as "thods", etc.

Also, in Firefox 1.0 on Windows XP, when I try to print it, it only
prints the first page. If I use MS Internet Explorer, it prints just fine.

Curt
 
W

why the lucky stiff

David said:
The tutorial itself looks good, though the terminology in this area
continues to be a problem. My understanding is that the most general
term is "singleton class", and that "metaclass" is a special term for
singleton class of a Class object. (See Pickaxe, 2nd ed., p. 382.)
So, for example, I would rename your Object#metaclass method
#singleton_class, since it applies to all objects (as per RCR 231).

Sure, I'm aware that "virtual class" is the generic term, while Matz has
also used "singleton class" and "meta-object" to describe these classes
used in tandem with an RObject.

I only use the term "metaclass" because it is the term predominantly
used in the PickAxe II. While Dave does interchangibly use "virtual
class" and "singleton class", the only term he uses to generically refer
to the construct is "metaclass".

And I really need to be able to wrap these up in a single word, whilst
still jiving with the PickAxe.

_why
 
M

Mike Woodhouse

Karl said:
fear unclear,

Noticed a small mistake; At one point, you refer to the at-sign (@) as
an ampersand. Other than that... the article went way over my head and
twisted my poor brain into knots. :-( I think I'll need to re-read
chapter 24 of Pickaxe 2 immediately before reading this article.

Glad I'm not the only one who has to go back to the books! (I did spot
the "ampersand" thing, though).
 
M

mark sparshatt

why said:
I've written a very nuts+bolts article on metaclasses (aka virtual
classes or metaobjects), since they still lurk under a shroud of fear
and enigma.

<http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html>

I'm hoping this will help uncover the truth. If anything is unclear,
please report it. Shed a light.

One thing I found confusing was the comment for the class_def method
# Just defines a class method
def class_def name, &blk
class_eval { define_method name, &blk }
end


However it actually defines an instance method

require "metaid"

class MyClass
class_def "class_method" do puts "success" end
end

MyClass.class_method
#=> undefined method "class_method" for MyClass:Class

MyClass.new.class_method #=> success
 
J

Jeffrey Moss

_why,

Nice tutorial, I found I learned something from it. I know there is a
chapter in the pickaxe that attempts to explain this, but this seems to be
the best (only?) freely available explanation.

Being somewhat new to the concept of metaprogramming, I can tell you what is
particularly confusing is the use of class << self, how this is like the
root of all singleton behavior, how it differs from class a < b (perhaps
even display how it works inside the interpreter). I wasn't sure what the
difference between the < and the << operator was, so I had to go look it up.

Also the difference between class instance variables and class variables
could use some extra explaining, it seems you're just saying what to do and
what not to do, but not why you can't or shouldn't do it, and why a @@ class
variable is handy.

Thanks,

-Jeff

----- Original Message -----
From: "why the lucky stiff" <[email protected]>
To: "ruby-talk ML" <[email protected]>
Sent: Monday, April 18, 2005 12:50 AM
Subject: [ANN] Article: Seeing Metaclasses Clearly
 
J

Jeffrey Moss

That happens to me when I try and print my bank statements, its probably a
firefox bug.

-Jeff
 
L

Lionel Thiry

mark sparshatt a écrit :
One thing I found confusing was the comment for the class_def method



However it actually defines an instance method

require "metaid"

class MyClass
class_def "class_method" do puts "success" end
end

MyClass.class_method
#=> undefined method "class_method" for MyClass:Class

MyClass.new.class_method #=> success

The only I've found to make your sample code work is to refactor class_def this way:
def class_def name, &blk
meta_eval { define_method name, &blk }
end

I personnaly feel it weird I could not realise this whithout the help of the
metaclass manipulation methods _why has added.
 
L

Lionel Thiry

why the lucky stiff a écrit :
I've written a very nuts+bolts article on metaclasses (aka virtual
classes or metaobjects), since they still lurk under a shroud of fear
and enigma.

<http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html>

I'm hoping this will help uncover the truth. If anything is unclear,
please report it. Shed a light.

Sharkin',

_why

Errata

In the begining of the page:
"I’ve been keeping these methods in a file called metaid.rb and it’s a start
toward building a little library that can simplify use of metaclasses. Let’s
talk about metaclasses and I advise you to keep metaid.rb at your side. Let’s
talk about metaclasses and I advise you to keep metaid.rb at your side."

"Let’s talk about metaclasses and I advise you to keep metaid.rb at your side."
is said twice.
 
W

why the lucky stiff

Jeffrey said:
Being somewhat new to the concept of metaprogramming, I can tell you
what is particularly confusing is the use of class << self, how this
is like the root of all singleton behavior, how it differs from class
a < b (perhaps even display how it works inside the interpreter). I
wasn't sure what the difference between the < and the << operator was,
so I had to go look it up.

My article briefly discusses the singleton class notation (the << you
are referring to). This notation is very simple to understand once
you've gotten the hang of:

1. Objects are containers for instance variables.
2. Classes are containers for methods and instance variables.

There are more to objects and classes than this, but for the sake of
this discussion, it's useful to whittle it down to this.

a = Object.new
a.instance_variable_set( "@name", "Jeff" )

I've created a new object above, storage for instance variables. I've
added an instance variable to the object. In doing so, I called the
`instance_variable_set' method. This method isn't contained in the `a'
object. It's contained way up the inheritance tree, in the Object class.

Again: the instance variables are stored in the object. The methods are
stored in a class up the inheritance tree.

class << a
def name; @name; end
end

We're opening a metaclass here. What is a metaclass? It's method
storage for an object. An object can only store instance variables.
The `name' method has been added to the metaclass (the personal method
storage) for the object `a'.

The most needlessly confusing construct in Ruby is `class << self'.
You're simply accessing the method storage for whatever object is
currently `self'.

class Dragon
class << self; p self; end
end

Prints: #<Class:Dragon>

Okay, so we're in the metaclass for a class. But what is that?

It's method storage for class methods. Normal instance methods are
stored directly in the class. But class methods are stored in the
metaclass.

class Dragon
def self.me; p self; end # This method is stored in the metaclass
def me; p self; end # This method is stored in the class
end

Dragon.me #=> Dragon
Dragon.new.me #=> #<Dragon:0x80914e0>

Everyone who uses class methods uses metaclasses.

class << Dragon
def roar; "#<CLASS:ROAR>"; end
end
Dragon.roar #=> #<CLASS:ROAR>

d = Dragon.new
class << d
def roar; "#<OBJ:ROAR>"; end
end
d.roar #=> #<OBJ:ROAR>

I don't really get into this in the article, since I've opted to use the
`metaclass' method and `meta_eval' which are alternate forms of the above.

The < operator is a completely different operator, used strictly for
setting the superclass of a class.

But one handy thing about metaclass (which I believe qualifies them for
the meta- prefix) is that they follow the inheritance tree, simply
remaining one level removed.
=> #<Class:Object>

See, an object's metaclass' superclass is the same as the object's
superclass' metaclass.
Also the difference between class instance variables and class
variables could use some extra explaining, it seems you're just saying
what to do and what not to do, but not why you can't or shouldn't do
it, and why a @@ class variable is handy.

I'll address this once I'm sure I completely understand variable.c and
have played around with class variables in metaclasses a bit more.

_why
 
W

why the lucky stiff

Lionel said:
The only I've found to make your sample code work is to refactor
class_def this way:
def class_def name, &blk
meta_eval { define_method name, &blk }
end

That's the `meta_def' you've recreated above.

The `class_def' method is intended to be used to add instance methods
(like the `initialize' I'm adding in Dwemthy's Array):

class Dragon; end
Dragon.class_def :initialize do
@life = 11; @strength = 12
end
=> #<Dragon:0xb7d571e8 @strength=12, @life=11>

The `meta_def' can be used to add class methods, because of reasons
stated throughout the article and in my response to Jeff.

_why
 
F

Florian Groß

why said:
The `class_def' method is intended to be used to add instance methods
(like the `initialize' I'm adding in Dwemthy's Array):

class Dragon; end
Dragon.class_def :initialize do
@life = 11; @strength = 12
end

Oh, that's already done by Module#define_method then. Perhaps you can
just make that method public?
 
L

Lyndon Samson

From the article

"It's an important lesson: objects do not store methods, only classes can."

Might be nice to contrast this with prototype based languages like javascript.

Or ProtoRuby ;-)

class ProtoObj
def initialize
@methods = {}
end
def addMethod(name, &method)
@methods[name.id2name] = method
end
def method_missing(method, *args)
@methods[method.id2name].call(*args)
end
end

dog = ProtoObj.new
dog.addMethod:)bark) {
puts "Bark"
}
dog.bark
 

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

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top