disclaimer: Code taken from the ruby koans
This is from a discussion of constants scoping within classes. Here is the defintion of a couple few classes:
class Animal
LEGS = 4
def legs_in_animal
LEGS
end
end
class MyAnimals
LEGS = 2
class Bird < Animal
def legs_in_bird
LEGS
end
end
end
At this point doing MyAnimals::Bird.new.legs_in_bird
results in 2 and I understand why--search lexical space for the constant before the inheritance heirarchy.
Then this class is defined:
class MyAnimals::Oyster < Animal
def legs_in_oyster
LEGS
end
end
The tutorial says that now calling MyAnimals::Oyster.new.legs_in_oyster
results in 4 and I can't figure it out. It appears to me that Oyster is a nested class in MyAnimals and as such I expected it to behave the same ways as the Birds class did above. I'm missing some key information about what declaring the class Oyster with explicit scoping means.
can anyone explain this to me? I've found hundreds of ruby class tutorials via Google but none of them address this situation.
thank you in advance...
If you define the Oyster INSIDE the MyAnimals class definition, then you get the answer that legs_in_oyster is 2.
If you define the Oyster separately--that is, you define it after LEGS = 2 has passed out of scope, you get the response of 4.
This suggests to me that the nested class is behaving differently than a namespace does, perhaps more like a closure.
---EDIT---
According to "The Ruby Programming Language", constants are looked up in the Lexical Scope of the place where they are used first, and in the inheritance hierarchy second. So what is the lexical scope of something that inherits Animal? Animal itself, right? The MyAnimals class redefines LEGS, so anything that uses LEGS, and is defined inside MyAnimals, will look for LEGS inside MyAnimals first.
I think this example explains it best. Ruby searches for the constant definition in this order:
Any outer scopes (repeat until top level is reached)Any outer scopes (up to but not including the top levelEDIT
Thanks to Mark Amery for pointing out this error. The top-level is only reached in the case where there are no enclosing scopes and/or superclasses. The linked example actually makes this clear, sadly I read it wrong.
An example for this case: