> 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.
> 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.
> 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).
> 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.
> 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.)
> 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.
> 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.
Florian Groß wrote: > 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.
>> 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.
>> 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.
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.
David A. Black wrote: > 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.
Karl von Laudermann wrote: > why the lucky stiff wrote: > > I've written a very nuts+bolts article on metaclasses (aka virtual > > classes or metaobjects), since they still lurk under a shroud of fear
> > 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.
Glad I'm not the only one who has to go back to the books! (I did spot the "ampersand" thing, though).
> 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.
> > 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.
+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...
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.
----- Original Message ----- From: "why the lucky stiff" <ruby-t...@whytheluckystiff.net> To: "ruby-talk ML" <ruby-t...@ruby-lang.org> Sent: Monday, April 18, 2005 12:50 AM Subject: [ANN] Article: Seeing Metaclasses Clearly
> 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.
>> 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.
>> 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
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.
> 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.
> 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.
Jeffrey Moss wrote: > 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
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.
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.
Lionel Thiry wrote: > 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
>> d = Dragon.new => #<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.
"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"
> David A. Black wrote: >> 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.
I read the Pickaxe differently, especially the box on p. 382. It paraphrases Matz as having said: "You can call it _metaclass_ but, unlike Smalltalk, it's not a class of a class; it's a singleton class of a class."
I don't think there's any case where Dave refers to a singleton class as a metaclass, except where the object is a Class, but I could be wrong about that... ?
Anyway, when RCR 231 gets addressed, we'll find out for sure :-)
(I think I misread the p. 382 thing about "virtual". It does actually sound like Matz is accepting it as a synonym for "singleton", though I avoid it because I don't see anything "virtual" about singleton classes. They're objects.)
[
multipart_mixed_part < 1K ] This message is in MIME format. The first part should be readable text, while the remaining parts are likely unreadable without MIME-aware tools.
On Mon, 18 Apr 2005, Gavin Kistner wrote: > On Apr 18, 2005, at 6:33 AM, Florian Groß wrote: >> 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.
Also, they're different. In 2.0, it sounds like they will be more similar to each other, because class vars will be truly scoped per class. I'm not in favor of that. Class variables, in my view, are responsible already for a huge amount of misunderstanding of *instance* variables (because the @/@@ thing always makes people think there must be some connection or similarity between the two entities, and then they get confused when there isn't).
I'm not sure what the best thing would be. I tend to root for the removal of class variables entirely. I might even be able to tolerate #class_attr_* methods, which actually make no sense (since there's really no more reason to create special methods, in that area, for Class objects than any other object) but might keep things smoother.
> On Mon, 18 Apr 2005, why the lucky stiff wrote: > > 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".
On Monday 18 April 2005 03:55 pm, David A. Black wrote:
> I read the Pickaxe differently, especially the box on p. 382. It > paraphrases Matz as having said: "You can call it _metaclass_ but, > unlike Smalltalk, it's not a class of a class; it's a singleton class > of a class."
I don't have the pickaxe with me (its at work), but let me quote from "Putting Metaclasses to Work" by Ira R. Forman and Scott H. Danforth. The quote is longish, but useful in understanding metaclasses. From the Preface:
> "If one thinks of objects as cookies, then classes are analogous to cookie > cutters. Cookie cutters are teamplates that are used to make and determine > the properties of cookies; classes make and determine the properties of > objects. But ow are cookie cutters themselvfes made? Let us ssay that they > are pressed from sheet metal using a cookie cutter press (a piece of heavy > machinery). So, if a cookie cutter press is ed to make cookie cutters, what > is used to make classes? The answer is a metaclass."
So, the instances of a metaclass are classes. Ruby happens to implement metaclasses as singleton classes (or virtual classes, whatever). So the singleton class of a class is a metaclass, but the singleton class of something that is not a class, would not be a meta class.
I would modify Why's metaid library thusly:
class Object def singletonclass class << self self end end end class Class def metaclass singletonclass end end
NoMethodError: undefined method `metaclass' for #<Object:0x40253228> from (irb):4
>> o.singletonclass
=> #<Class:#<Object:0x40253228>>
>> Object.metaclass == Object.singletonclass
=> true
> (I think I misread the p. 382 thing about "virtual". It does actually > sound like Matz is accepting it as a synonym for "singleton", though I > avoid it because I don't see anything "virtual" about singleton > classes. They're objects.)
I think the "virtual" is a modifier of "class", not "object". A virtual class is something that is like a class in someways (it holds instance methods), but unlike a class in other ways (can't create new instances of it).
-- -- Jim Weirich j...@weirichhouse.org http://onestepback.org ----------------------------------------------------------------- "Beware of bugs in the above code; I have only proved it correct, not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
> So, the instances of a metaclass are classes. Ruby happens to implement > metaclasses as singleton classes (or virtual classes, whatever). So the > singleton class of a class is a metaclass, but the singleton class of > something that is not a class, would not be a meta class.
> I would modify Why's metaid library thusly:
> class Object > def singletonclass > class << self > self > end > end > end > class Class > def metaclass > singletonclass > end > end
+1 - in fact, I think that should go into the FAQ, under "What is the difference between a singleton class and a metaclass?"