Created
December 5, 2012 15:53
-
-
Save rsliter/4216800 to your computer and use it in GitHub Desktop.
Eigenclasses in Ruby
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# The design pattern to create singleton CLASSES is pretty familiar-- it restricts the instantiation of a | |
# class to a single object. Eigenclasses in Ruby, however, allow you to restrict methods to a particular | |
# instance of a class. Eigenclasses also allow for restricted class methods. | |
# | |
# Hence, eigenclasses contain an object's singleton METHODS. | |
class Lupus | |
def is_a_wolf? | |
true | |
end | |
end | |
class Familiaris < Lupus | |
def bark | |
"Woof!" | |
end | |
end | |
# DEFINING THE EIGENCLASS | |
# | |
# Consider the biological classification for a dog (http://en.wikipedia.org/wiki/Dog). | |
# It has a species designation of "lupus" and a subspecies of "familiaris." All dogs share this. | |
rover = Familiaris.new | |
# Now I have an instance of Familiaris, named "rover." He has a trick that not many other dogs can do: | |
def rover.roll_over_three_times | |
"Rolling over three times" | |
end | |
rover.roll_over_three_times | |
# => "Rolling over three times" | |
old_dog = Familiaris.new | |
old_dog.roll_over_three_times | |
# => raises a NoMethodError -- you can't teach an old dog new tricks! | |
# Above, we defined a method directly on an instance of the Familiaris class (rover). | |
# The better way to define a singleton method is by opening up the eigenclass using the "<<" syntax: | |
class << old_dog | |
def new_trick | |
"New trick!" | |
end | |
end | |
old_dog.new_trick | |
# => "New trick!" | |
rover.new_trick | |
# => raises a NoMethodError | |
# METHOD LOOKUP | |
# | |
# If an object has an eigenclass, Ruby first looks in its eigenclass when a method is called. | |
# If the method is not in the eigenclass, Ruby goes further up the object chain to the eigenclass's superclass, | |
# which is the object's class. After that, the normal method lookup chain continues, all the way up to object. | |
# If there is no eigenclass, the method lookup will go straight to the object's class. | |
rover.bark | |
# Lookup chain: rover -> eigenclass -> Familiaris | |
rover.is_a_wolf? | |
# Lookup chain: rover -> Familiaris -> Lupus | |
rover.to_s | |
# Lookup chain: rover -> Familiaris -> Lupus -> Object | |
# EIGENCLASS CLASS METHODS | |
# | |
# Along with creation of singleton object methods, eigenclasses, because they are classes, can also have class | |
# methods. Recall that Familiaris is a subclass of Lupus: | |
class Lupus | |
class << self | |
def howl | |
"AOOOOOOOOOOOOOO" | |
end | |
end | |
end | |
Familiaris.howl | |
# => "AOOOOOOOOOOOOOO" | |
# The method lookup for this is kind of wonky: Familiaris checks its eigenclass; not finding the method | |
# definition, the its superclass (the eigenclass of Familiaris' superclass) is then checked for the method | |
# definition. | |
# Lookup chain: Familiaris -> eigenclass -> eigenclass of Lupus | |
# REFERENCES | |
# | |
# http://madebydna.com/all/code/2011/06/24/eigenclasses-demystified.html | |
# http://pragprog.com/downloads/1155010/dca2a145e604baeb |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment