I wanted to clarify some things off of this original post. The answer suggested that Ruby searches for the constant definition in this order:
The enclosing scope
Any outer scopes (repeat until top level is reached)
Included modules
Superclass(es)
Object
Kernel
So to clarify, at which step (1-6) is the value for the constant LEGS found for legs_in_oyster? Is it from the Superclass Animal? Is the scope of class MyAnimals ignored because it is not considered an enclosing scope? Is this due to the explicit MyAnimals::Oyster class definition?
Thanks! Just trying to understand. Here is the code:
class Animal
LEGS = 4
def legs_in_animal
LEGS
end
class NestedAnimal
def legs_in_nested_animal
LEGS
end
end
end
def test_nested_classes_inherit_constants_from_enclosing_classes
assert_equal 4, Animal::NestedAnimal.new.legs_in_nested_animal
end
# ------------------------------------------------------------------
class MyAnimals
LEGS = 2
class Bird < Animal
def legs_in_bird
LEGS
end
end
end
def test_who_wins_with_both_nested_and_inherited_constants
assert_equal 2, MyAnimals::Bird.new.legs_in_bird
end
# QUESTION: Which has precedence: The constant in the lexical scope,
# or the constant from the inheritance heirarachy?
# ------------------------------------------------------------------
class MyAnimals::Oyster < Animal
def legs_in_oyster
LEGS
end
end
def test_who_wins_with_explicit_scoping_on_class_definition
assert_equal 4, MyAnimals::Oyster.new.legs_in_oyster
end
# QUESTION: Now Which has precedence: The constant in the lexical
# scope, or the constant from the inheritance heirarachy? Why is it
# different than the previous answer?
end
I was just pondering the very same question from the very same koan. I am no expert at scoping, but the following simple explanation made a lot of sense to me, and maybe it will help you as well.
When you define MyAnimals::Oyster you are still in the global scope, so ruby has no knowledge of the LEGS value set to 2 in MyAnimals because you never actually are in the scope of MyAnimals (a little counterintuitive).
However, things would be different if you were to define Oyster this way:
class MyAnimals
class Oyster < Animal
def legs_in_oyster
LEGS # => 2
end
end
end
The difference is that in the code above, by the time you define Oyster, you have dropped into the scope of MyAnimals, so ruby knows that LEGS refers to MyAnimals::LEGS (2) and not Animal::LEGS (4).
FYI, I got this insight from the following URL (referenced in the question you linked to):
https://groups.google.com/forum/#!topic/comp.lang.ruby/t5rtDNol3P8
Related
I'm a bit surprise about this behavior:
puts RUBY_VERSION # 2.4.1
class A
class << A
def my_method
puts self
end
end
end
class B < A ; end
puts A.singleton_methods.inspect # [:my_method]
puts B.singleton_methods.inspect # [:my_method]
puts B.my_method # B
puts A.my_method # A
In metaprogramming Ruby 2 (amazing book BTW), Paolo Perrota says:
Also, singleton classes have only a single
instance (that’s where their name comes from), and they can’t be inherited
But we can see that the class method in the snipet has been inherited by B from A. So, can anyone explain me how that works?
Does this behavior means that classes are instances of singleton classes?
(I honestly wrote this before reding the part of the book which explain the mechanism of inheritance of class methods. But now that I understand it I still think is an interesting topic)
Why class methods are inherited?
Each class has singleton class,
When there is an inheritance hierachy, the singleton classes inheritance chain mirror the one of
the 'normal' clases.
In the Ruby method lookup process, the interpreter
goes through the inheritance chain of the singleton classes.
puts RUBY_VERSION # 2.4.1
class A
class << A
def my_method
puts self
end
end
end
class B < A ; end
puts A.singleton_class == B.singleton_class.superclass # true
puts A == B.superclass # true
So in the method lookup process the interpreter goes up to the singleton class of B, looks for the method my_method doesn't find it there, and goes up to the of the singleton class of A and there it finds the method and execute it.
But we should admit then, that having two inheritance chains of classes, they are in a sort in competition, in the sense that one of the two chains must be traversed first. But which one?, the one of the normal clases or the one of the singleton classes?
Well, if you know better please tell me, but code seems to talk:
puts RUBY_VERSION # 2.4.1
class Class
def my_method
puts "Those who seek for gold dig up much earth and find a little."
end
end
A = Class.new do
class << self
def my_method
puts self
end
end
end
class B < A ; end
Class.new.my_method # Those who seek for gold dig up much earth and find a little.
A.my_method # A
If the 'normal' chain of inheritance would have taken precedence over the chain of inheritance of the singleton classes, the result of A.my_method would have been the same of Class.new.my_method since the class of A is Class. We could see it more clearly if we remove the singleton method of A:
puts RUBY_VERSION # 2.4.1
class Class
def my_method
puts "Those who seek for gold dig up much earth and find a little."
end
end
A = Class.new do
# class << self
# def my_method
# puts self
# end
# end
end
class B < A ; end
Class.new.my_method # Those who seek for gold dig up much earth and find a little.
A.my_method # Those who seek for gold dig up much earth and find a little.
Those this behavior means that classes are instances of singleton classes?
I would really like to have an answer to this question. But I'm not so sure about it. Would not that mean that for example A is both an instance of Class and it's own singleton class? Double inheritance!?
If you know better, please share your knowledge. This is a very interesting topic :)
How can I write a ruby module that imposes some conditions on classes in which it is included, which must be met the end of currently opened class definition?
To be concrete, suppose the condition is "a class variable ##foo should be defined to be >0 "
I'd like to write a module that looks something like this:
module NeedPositiveFoo
module ClassMethods
def validate_positive_foo
raise unless defined?(##foo) && ##foo > 0
end
end
def included(other)
other.extend(ClassMethods)
end
end
Then this class definition would be valid:
class ValidClass
include NeedPositiveFoo
##foo = 3
end
But these class definitions would raise after their closing end's:
class InvalidClass1
include NeedPositiveFoo
# ##foo is not defined
end
class InvalidClass2
include NeedPositiveFoo
##foo = -2
end
While the answer by Uri Agassi perfectly works when you are allowed to put includes in the very end of class definition, the code below will work despite where include was placed.
def included(other)
TracePoint.new(:end) do |tp|
if tp.self == other
tp.disable
raise unless defined?(other.class_variable_get(:##foo)) # checks
end
end.enable
other.extend(ClassMethods)
end
TracePoint documentation.
You can't hook the end of a class definition, because there isn't one - a class can be declared in different files, at different times, and in different libraries even.
What you can do, is check the condition when the module is included, and declare the inclusion at the end of your definition:
module NeedPositiveFoo
def included(other)
raise unless defined?(##foo) && ##foo > 0
end
end
class ValidClass
##foo = 3
include NeedPositiveFoo
end
class InvalidClass1
# ##foo is not defined
include NeedPositiveFoo
end
class InvalidClass2
##foo = -2
include NeedPositiveFoo
end
class InvalidClass3
include NeedPositiveFoo
##foo = 4 # declared after inclusion - not a valid state...
end
When asking questions like this, it is often useful to see how the Ruby core library does it. There are two well-known mixins in the Ruby core library which place certain conditions on the classes they are being mixed into:
Enumerable requires that the class have an each method that can be called with zero arguments and takes a block, to which it yields all the elements of the collection successively.
Comparable requires that the class have a <=> method that can be called with a single argument and responds with either -1, 0, or 1, depending on whether the argument is considered to be greater than, equal, or less than the receiver.
In both of these cases, the requirements are simply stated in the documentation, not in code. It is up to the class author to make sure they are met.
In fact, in the Enumerable case, the requirements are not really stated at all, it is just assumed that any competent Ruby programmer knows them.
I would follow this style set out by the authors of the core library, since it is what Rubyists are used to.
This question already has answers here:
What is attr_accessor in Ruby?
(20 answers)
Closed 8 years ago.
Before I expand my question, let me state that I have read the answers to the questions here, here and here. So requesting you to not mark my question as duplicate as those answers didn't make me understand the purpose of attr_accessor. My question is more to do with the logic and not the syntax.
I've created two sets of code below. The sets are identical to each other except that one set simply doesn't have the attr_accessor line. When I ran both sets, they both gave me the same output. So, logically speaking, what difference does the attr_accessor line make, when both sets of code gave me the same intended output?
Code Set 1:
class Animal
def initialize(name)
#name = name
end
end
class Cat < Animal
def talk
"Meaow!"
end
end
class Dog < Animal
def talk
"Woof!"
end
end
animals = [Cat.new("Flossie"), Dog.new("Clive"), Cat.new("Max")]
animals.each do |animal|
puts animal.talk
end
#Output:
#Meaow!
#Woof!
#Meaow!
Code Set 2:
class Animal
attr_accessor :name #this line is the only difference between the two code sets.
def initialize(name)
#name = name
end
end
class Cat < Animal
def talk
"Meaow!"
end
end
class Dog < Animal
def talk
"Woof!"
end
end
animals = [Cat.new("Flossie"), Dog.new("Clive"), Cat.new("Max")]
animals.each do |animal|
puts animal.talk
end
#Output:
#Meaow!
#Woof!
#Meaow!
Both sets of code call the Animal class to create new instances of animal objects WITH names. I stress on "...WITH names." because the attr_accessor (in the 2nd set) is defining the :name attribute. But in the 1st code set, I have deleted the attr_accessor but still managed to create object instances with the name attribute.
attr_accessor :attribute_name is shorthand for:
def attribute_name
#attribute_name
end
def attribute_name=(value)
#attribute_name = value
end
and it's for setting instance variable. In your code snipped, you set instance variable directly in initialize method, so you don't need attr_accessor.
Instance variables can always be read/written inside instance methods, which your code demonstrates. attr_accessor makes instance variables readable/writable outside the class (by defining accessor methods). By adding it to your second example, you allow the following:
cat = Cat.new("Garfield")
puts cat.name
cat.name = "Maru"
which would raise NoMethodError in your first example.
I've had a chance to look around in StackOverflow and found this same question which I was trying to better understand from Ruby Koans (Ruby Koans: explicit scoping on a class definition part 2).
class MyAnimals
LEGS = 2
class Bird < Animal
def legs_in_bird
LEGS
end
end
end
def test_who_wins_with_both_nested_and_inherited_constants
assert_equal 2, MyAnimals::Bird.new.legs_in_bird
end
# QUESTION: Which has precedence: The constant in the lexical scope,
# or the constant from the inheritance heirarachy?
# ------------------------------------------------------------------
class MyAnimals::Oyster < Animal
def legs_in_oyster
LEGS
end
end
def test_who_wins_with_explicit_scoping_on_class_definition
assert_equal 4, MyAnimals::Oyster.new.legs_in_oyster
end
# QUESTION: Now Which has precedence: The constant in the lexical
# scope, or the constant from the inheritance heirarachy? Why is it
# different than the previous answer?
Based on the explanation in the link, it seems like the main confusion others (including myself) had was because of the class definition:
class MyAnimals::Oyster < Animal
# stuff goes in here
end
My original thought was that MyAnimals::Oyster means that the Oyster class was defined within MyAnimals. In other words, I thought the above code was analogous to the following code:
class MyAnimals
class Oyster < Animal
# stuff goes in here
end
end
To test my thought, I did the following in IRB:
class MyAnimals
LEGS = 2
class Bird < Animal
def legs_in_bird
LEGS
end
end
end
class MyAnimals::Oyster # You should notice that I'm not inheriting from Animal anymore
def legs_in_oyster
LEGS
end
end
If my reasoning is correct, then I would expect that the below code returns 2
MyAnimals::Oyster.new.legs_in_oyster # => NameError: uninitialized constant MyAnimals::Oyster::LEGS
Since this doesn't return 2, can someone explain to me why it doesn't return 2?
EDIT:
I neglected to add the Animal class; here it is:
class Animal
LEGS = 4
def legs_in_animal
LEGS
end
class NestedAnimal
def legs_in_nested_animal
LEGS
end
end
end
Go back to the order in which Ruby searches for the value. Step 1 is 'the enclosing scope'. When you define a nested class like this
class Animal
class Bird
end
end
'Bird' is enclosed in the 'Animal' scope.
When you do it like this
class Animal
end
class Animal::Bird
end
Although you've defined 'Bird' as nested within 'Animal', at the time you defined 'Bird', the enclosing scope was the global scope. Go back to IRB and define LEGS = 0 (in the global scope) and try your Oyster again.
In strictly lexically/statically scoped languages like C++ or Java, identifiers are resolved by simply checking the current scope, ascending one scope higher and repeating until the base most scope is reached. For example: if your example were C++, LEGS would be searched for first in the calling class Bird/Oyster, then Animal, then My Animal.
Ruby has a kind of dynamic scoping. Each object, even if it resides in the same 'place' can have its own scope lookup order depending on how it was defined or create at runtime. You can think of each method as having a stack of scopes to search, and how it was defined pushes new scopes onto that stack.
Because of the way Bird is defined it gets (BaseScope is not its real name, you did not provide enough code to provide this) BaseScope::MyAnimals::Bird, BaseScope::MyAnimals::Animal, BaseScope::MyAnimals and BaseScope to search through for resolving names.
While The first Oyster only gets BaseScope::MyAnimals::Oyster, BaseScope::MyAnimals::Animal and BaseScope.
The Oyster without inheritance gets even less, just BaseScope::MyAnimals::Oyster and BaseScope.
Each use of the class keyword and inheritance in this example pushes another scope to check onto the stack of scopes for its contents to search. So using class MyAnimals::Oyster only pushed one entry onto this stack.
Edit
For simplicity I left out the method legs_in_oyster. It is a scope that could be searched. It's trivial definition is self explanatory and including it would add much useless text to this answer.
I also left out the global scope for simplicity. I know Koans has at least one scope at or between BaseScope and the global scope.
I'm trying to understand inheritance:
class Car
##wheels = 4
def wheel
##wheels
end
end
class StretchLimo < Car
##wheels = 6
def whee
##wheels
end
def turn_on_television
end
end
I instantiate some objects like so:
moe = Car.new
larry = StretchLimo.new
When I do moe.wheel, I get 6, when I'm expecting 4.
The Ruby tutorial I'm following says it's supposed to be 4. Larry.whee should obviously return 6.
By the way, the "wheel" and "whee" functions I added so I could see the values. Can anyone explain what's wrong here?
Class variables in Ruby are strange and confusing.
An idiomatic way to implement what you want is this:
class Car
def wheels
4
end
end
class StretchLimo < Car
def wheels
6
end
end
Car.new.wheels #=> 4
StretchLimo.new.wheels #=> 6
Whats happening is that class variables are shared between all instances of a class. Because StrechLimo is a subclass of Car instances of StrechLimo also see this variable.
## is a class variable so it is shared across all objects instantiated from a given class and all derived class. Because Ruby is interpreted, until you instantiate a StretchLimo object, it should not look at any of the StretchLimo code, so if you did the following:
moe = Car.new
moe.wheel # should give 4
larry = StretchLimo.new
moe.wheel # should give 6
Because when the StretchLimo gets interpreted it updates the ##wheels class variable to be 6. On the other hand, if you declared "wheels" with only one "#" (#wheels), it would be an instance variable specific to the object itself, and you would get your preferred behavior.