# "Seeing Metaclasses Clearly"

**URL:** <https://www.ruby-forum.com/t/seeing-metaclasses-clearly/60464>\
**Category:** Ruby\
**Created:** [May 14, 2006, 8:29am UTC](https://www.ruby-forum.com/t/seeing-metaclasses-clearly/60464 "2006-05-14T08:29:17Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![pergesu](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/22d042/32.png) [@pergesu](https://www.ruby-forum.com/u/pergesu)\
**Post date:** [May 14, 2006, 8:29am UTC](https://www.ruby-forum.com/t/seeing-metaclasses-clearly/60464/1 "2006-05-14T08:29:17Z")

</div>

I saw a link for why’s article “Seeing Metaclasses Clearly” [1]  
earlier this week. Been looking at it, and honestly I can’t say it’s  
making things more clear for me. The final example is:

class MailTruck  
def self.company( name )  
meta\_def :company do; name; end  
end  
end

class HappyTruck \< MailTruck  
company “Happy’s – We Bring the Mail, and That’s It!”  
end

I simply don’t see how that’s different from

class MailTruck  
def self.company(name)  
instance\_eval do  
define\_method(name) { name }  
end  
end  
end

except for, um, my code doesn’t work - wrong number of arguments (0 for  
1)

I also don’t understand why this doesn’t work, I thought it was the  
same thing as the first example, just without the helper methods that  
why wrote:

class Truck  
def self.company(name)  
class \<\< self  
instance\_eval do  
define\_method(name) { name }  
end  
end  
end  
end

Now after reading this I don’t even have a clue how/why all the evals  
are supposed to be used. Thought I had it down, but I’m just way more  
confused after this article. I know there’s already a post on the  
various evals, but can someone explain what’s going on in this  
metclass article? Clearly, please.

Pat

[1] [http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html](http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html)

---

<div class="post-metadata">

**Author:** ![pergesu](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/22d042/32.png) [@pergesu](https://www.ruby-forum.com/u/pergesu)\
**Post date:** [May 14, 2006, 8:32am UTC](https://www.ruby-forum.com/t/seeing-metaclasses-clearly/60464/2 "2006-05-14T08:32:23Z")

</div>

> ```
> end
> 
> ```
> 
> end  
> end

I forgot to give the error message when I inherit from this Truck  
class and call company: ArgumentError: empty symbol string

---

<div class="post-metadata">

**Author:** ![pergesu](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/22d042/32.png) [@pergesu](https://www.ruby-forum.com/u/pergesu)\
**Post date:** [May 14, 2006, 9:11am UTC](https://www.ruby-forum.com/t/seeing-metaclasses-clearly/60464/3 "2006-05-14T09:11:46Z")

</div>

Hi –

On Sun, 14 May 2006, Pat M. wrote:

> class HappyTruck \< MailTruck  
> end  
> end
> 
> except for, um, my code doesn’t work - wrong number of arguments (0 for 1)

The problem is that you’re defining an _instance_ method of MailTruck,  
called “company”. Meanwhile, the class method company is still the  
above method. So when you call HappyTruck.company, it’s running the  
method that expects the (name) argument.

You’d need to do:

def self.company(name)  
metaclass.instance\_eval do # or class\_eval  
define\_method(name) { name }  
end  
end

(Note: I use this “metaclass” method under protest 🙂 I believe it  
should be called singleton\_class; see  
[http://www.rcrchive.net/rcr/show/231.](http://www.rcrchive.net/rcr/show/231.))

I think part of the confusion may be that the same name (“company”) is  
being used for both the method that creates a new method, and for that  
new method itself. The idea is that the parent class has a method,  
company, and every time a child class calls that method, the child  
class gets a _new_ method called company, which reports back the  
argument to the original method. I think the collapse of levels in  
your code might stem from this collapsing of names.

Here’s a rewrite of the example, using differentiated names. See if  
this helps:

class MailTruck  
def self.set\_slogan( our\_slogan )  
meta\_def :slogan do; our\_slogan; end  
end  
end

class HappyTruck \< MailTruck  
set\_slogan “Happy’s – We Bring the Mail, and That’s It!”  
end

p HappyTruck.slogan

(It would be more “Rubyish” to use slogan= rather than set\_slogan, but  
anyway, I just wanted to change it by one increment.)

In this rewrite, set\_slogan is the equivalent of the parent “company”  
method, and slogan is equivalent of the child “company” method that  
the parent method is able to create for each subclass.

David

---

<div class="post-metadata">

**Author:** ![pergesu](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/22d042/32.png) [@pergesu](https://www.ruby-forum.com/u/pergesu)\
**Post date:** [May 14, 2006, 9:39am UTC](https://www.ruby-forum.com/t/seeing-metaclasses-clearly/60464/4 "2006-05-14T09:39:04Z")

</div>

On Sun, 2006-05-14 at 15:28 +0900, Pat M. wrote:

> class HappyTruck \< MailTruck  
> end  
> end

I’m sure this is probably a typo, but the above code isn’t doing exactly  
what it’s supposed to:

class HappyTruck \< MailTruck  
company “Happy’s – We Bring the Mail, and That’s It!”  
end

puts HappyTruck.instance\_methods

# dup

# hash

# private\_methods

# […]

# Happy’s – We Bring the Mail, and That’s It!

# […]

puts HappyTruck.new.send(“Happy’s – We Bring the Mail, and That’s It!”)

# Happy’s – We Bring the Mail, and That’s It!

I.e. you’re making an instance method named for the argument passed into  
the class-level ‘company’. ruby is pretty relaxed about that, but  
obviously it can’t be called without using send.

Switching to ‘define\_method(:company) { name }’ made it work as (I  
think) \_why intended.

---

<div class="post-metadata">

**Author:** ![pergesu](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/22d042/32.png) [@pergesu](https://www.ruby-forum.com/u/pergesu)\
**Post date:** [May 14, 2006, 12:53pm UTC](https://www.ruby-forum.com/t/seeing-metaclasses-clearly/60464/5 "2006-05-14T12:53:05Z")

</div>

On 5/14/06, Ross B. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> I.e. you’re making an instance method named for the argument passed into  
> the class-level ‘company’. ruby is pretty relaxed about that, but  
> obviously it can’t be called without using send.

Well that was kind of a stupid mistake on my part.

> Switching to ‘define\_method(:company) { name }’ made it work as (I  
> think) \_why intended.

Actually, it doesn’t. Your code lets me do  
HappyTruck.new.company

but why’s code doesn’t. His code does  
HappyTruck.company

Which struck me as kind of useless, to be honest. If you’re going to  
make it a class-level method, why do all the metaclass stuff? What’s  
wrong with:

class HappyTruck \< MailTruck  
def self.company; “Happy Truck Company”; end  
end

That is a much more direct way to achieve the same result, at least as  
far as I can tell. Okay actually even if I did it your way it seems  
like it would make a lot more sense to just do

class HappyTruck \< MailTruck  
def company; “Happy Truck Company”; end  
end

I’m REALLY not understanding this stuff now :\

Pat

---

<div class="post-metadata">

**Author:** ![pergesu](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/22d042/32.png) [@pergesu](https://www.ruby-forum.com/u/pergesu)\
**Post date:** [May 14, 2006, 9:48am UTC](https://www.ruby-forum.com/t/seeing-metaclasses-clearly/60464/6 "2006-05-14T09:48:10Z")

</div>

Hi –

On Sun, 14 May 2006, removed\_email\_address@domain.invalid wrote:

> You’d need to do:
> 
> def self.company(name)  
> metaclass.instance\_eval do # or class\_eval  
> define\_method(name) { name }  
> end  
> end

Whoops, as Ross pointed out, it should be define\_method(:company), not  
define\_method(name). (And it was, in the version I tested. Honest!  
🙂

David

---

<div class="post-metadata">

**Author:** ![pergesu](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/22d042/32.png) [@pergesu](https://www.ruby-forum.com/u/pergesu)\
**Post date:** [May 14, 2006, 4:01pm UTC](https://www.ruby-forum.com/t/seeing-metaclasses-clearly/60464/7 "2006-05-14T16:01:37Z")

</div>

On Sun, May 14, 2006 at 07:52:08PM +0900, Pat M. wrote:  
[…]  
} Actually, it doesn’t. Your code lets me do  
} HappyTruck.new.company  
}  
} but why’s code doesn’t. His code does  
} HappyTruck.company  
}  
} Which struck me as kind of useless, to be honest. If you’re going to  
} make it a class-level method, why do all the metaclass stuff? What’s  
} wrong with:  
}  
} class HappyTruck \< MailTruck  
} def self.company; “Happy Truck Company”; end  
} end  
[…]  
} I’m REALLY not understanding this stuff now :\

For purposes of exposition, \_why was using a simple example. A bit  
further  
down the post he uses a more complex example involving Creatures. I’ll  
rewrite his example a little more simply, without his meta\_def and such  
(which I find somewhat confusing, honestly), and with some stylistic  
changes I prefer:

class Creature  
class \<\< self  
attr\_reader :traits

```
def traits(*args)
  @traits ||= {}
  return @traits if args.empty?
  attr_accessor *args
  args.each { |trait|
    #need to use send because define_method is private
    self.class.send(:define_method, trait) { |val|
      @traits[trait] = val
    }
  }
end

def set_traits_defaults(obj)
  @traits.each { |k,v|
    obj.send(:instance_variable_set, "@#{k}", v)
  }
end

```

end

def initialize  
self.class.set\_traits\_defaults(self)  
end

end

class WhimperingWhuffle \< Creature  
traits :fear\_level, :whimpering\_volume  
fear\_level 2  
whimpering\_volume 8  
end

class SarcasticSnark \< Creature  
traits :snarkiness\_level, :toxicity  
snarkiness\_level 7  
toxicity 200  
end

First off, what is the goal of this code? We want to be able to create  
Creature subclasses that have creature traits with default values. For  
our  
WhimperingWhuffle, new instances are created with a fear\_level of 2 and  
a  
whimpering\_volume of 8.

In the WhimperingWhuffle class definition, the traits line calls the  
method  
we defined on the Creature class. The Creature.traits method initializes  
the @traits instance variable, but the instance in question is the  
WhimperingWhuffle class object, i.e. an instance of Class. The @traits  
instance variable can be thought of as metadata for the  
WhimperingWhuffle  
class. The Creature.traits method also call attr\_accessor, but this is  
again called on the WhimperingWhuffle class rather than the Creature  
class.  
When we instantiate (e.g. foo = WhimperingWhuffle.new), the initialize  
method gets called. The initialize method sets the associated instance  
variables to the defaults in the traits metadata.

Now consider the following version, which is a bit kinky but doesn’t  
require the repetition inherent in declaring the traits then setting  
their  
default values:

class Creature  
class \<\< self  
attr\_reader :traits

```
def method_missing(method_name, *args)
  if /[=?]/ !~ method_name.to_s && args.length == 1
    @traits ||= {}
    attr_accessor method_name
    @traits[method_name] = args[0]
  else
    super method_name, *args
  end
end

def set_traits_defaults(obj)
  @traits.each { |k,v|
    obj.send(:instance_variable_set, "@#{k}", v)
  }
end

```

end

def initialize  
self.class.set\_traits\_defaults(self)  
end

end

class WhimperingWhuffle \< Creature  
fear\_level 2  
whimpering\_volume 8  
end

class SarcasticSnark \< Creature  
snarkiness\_level 7  
toxicity 200  
end

We have the same sort of metaprogramming going on, but it’s a bit  
simpler.  
We simply assume that any statements (that do not have a ? or = in them  
and  
are called with a single argument) that are otherwise unrecognized are  
trait declarations, with a default value. The code is much the same as  
before, except we don’t have to create class methods for the traits.

Does this help your understanding?

} Pat  
–Greg

---

<div class="post-metadata">

**Author:** ![pergesu](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/22d042/32.png) [@pergesu](https://www.ruby-forum.com/u/pergesu)\
**Post date:** [May 14, 2006, 5:01pm UTC](https://www.ruby-forum.com/t/seeing-metaclasses-clearly/60464/8 "2006-05-14T17:01:07Z")

</div>

Gregory S. wrote:

> I’ll  
> rewrite his example a little more simply, without his meta\_def and such  
> (which I find somewhat confusing, honestly), and with some stylistic  
> changes I prefer:

Not sure if this helped Pat, but it sure helped me. I too find \_why’s  
meta\_def stuff confusing.

Also, your method\_missing approach helped me see the whole idea behind  
the traits thing clearer (probably because there is less code that way).  
That was always a bit elusive to me before.
