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.
Related
I was playing around with class variables, and I knew that I could override a class variable in a subclass but I didn't realize where I call a class method matters. For example;
class Vehicle
##wheels = 4
def self.wheels
##wheels
end
end
puts Vehicle.wheels #4
puts Vehicle.wheels #4
puts Vehicle.wheels #4
class Motorcycle < Vehicle
##wheels = 2
end
The puts statement outputs 4, that all makes sense to me because I figured that you ##wheels is not overridden until an object is instantiated from the Motorcycle class. So then I did this:
class Vehicle
##wheels = 4
def self.wheels
##wheels
end
end
class Motorcycle < Vehicle
##wheels = 2
end
puts Vehicle.wheels #2
puts Vehicle.wheels #2
puts Vehicle.wheels #2
Now once I move those three lines to after the class Motorcycle they output 2... even though a Motorcycle object hasn't been instantiated. This confuses me. In detail what is happening here? Is it because class variables are loaded when we try to access it? How is this possible?
First of all, instantiation has nothing to do with it; this is a class variable, not an instance variable. Your code never instantiates anything; nor, as written, does it need to. We're just talking about some classes. But classes are first-class objects in Ruby, so that's fine.
Second, order does matter, because in Ruby all statements are executable. When you say
class Motorcycle < Vehicle
##wheels = 2
end
...all of that code executes right now, at the moment you say it — the moment when it is encountered as Ruby walks down the page obeying instructions. That code is not a mere template to be obeyed at some future time; it says: "create a Motorcycle class and set its class variable wheels to 2, now."
Third, you're not "overriding" anything. In the class Motorcycle, ##wheels is the very same class variable ##wheels that you defined for Vehicle earlier. It is not some other variable that "overrides" it. This is a single value that works like a kind of namespaced global, reachable from the class, any subclasses, and any instances thereof.
For more information, see (e.g.):
How do I override a variable in a Ruby subclass without affecting the superclass?
Ruby class instance variable vs. class variable
https://www.ruby-lang.org/en/documentation/faq/8/
If you want something you can override, what you're looking for is probably more like an instance variable in a class context, often called a "class instance variable" — e.g. like this:
class Vehicle
#wheels = 4
class << self
attr_reader :wheels
end
end
class Motorcycle < Vehicle
#wheels = 2
end
puts Vehicle.wheels # 4
puts Motorcycle.wheels # 2
All occurances of ##wheels refer to the exactly same variable. First you set it to 4, then you set it to 2. Why does it surprise you, that it has the value 2? Use #wheels instead (as matt) suggested, if you want to have a separate variable for both.
Having said this (and this is the only reason I'm writing this answer, because matt has already covered everything else in his answer), your usage of this "variable" suggests that is is supposed to be an invariable property of the respective class. That is, every motorcycle is supposed to have 2 wheels. In this case, it would perhaps make more sense to make it a constant of its class:
class Motorcycle < Vehicle
WHEELS = 2
end
class Unicycle < Vehicle
WHEELS = 1
end
and use it as
puts Motorcycle::WHEELS
If you have a variable v, where you only know that it is some subclasss of Vehicle, you can write
puts v.class::WHEELS
Whether you also define WHEELS in the class Vehicle itself, its a design question. If you intend to treat Vehicle as abstract class, it does not make sense to define a fixed number of wheels in it. For orthogonality, you could catch this case by doing a
class Vehicle
WHEELS = nil
end
if you want to, or just don't define it and rely on the fact that your code will raise an exception, if you try to access the wheels of something which is "just a plain vehicle".
If you do want to instantiate a Vehicle, of course it may make sense to set the constants there to, i.e., 4.
However, in this case I would consider allowing individual instances having a different number of wheels. The Reliant Robin was a car with 3 wheels, and trucks have sometimes 6 or 8 wheels. For maximum generality, I would therefore make the number of wheels an instance variable, and of course you can provide a default value:
class Vehicle
attr_reader :wheels
def initialize(wheels=4)
#wheels=wheels
end
end
class Motorcycle < Vehicle
attr_reader :wheels
def initialize(wheels=2)
super(wheels)
end
end
m = Motorcycle.new
puts m.wheels
I need to make the following code functional by building a "Car" class. I feel I must be overlooking something simple. any help would be appreciated. The # indicates the expected output
# Make the following code functional by building a Car class
c = Car.new("blue")
puts c.color # blue
puts c.repaint_count # 0
c.paint("red")
c.paint("green")
puts c.repaint_count # 2
puts c.color # green
here is what I have done:
class Car
##repaint_count = 0
def initialize(color)
#color = color
end
def self.paint(color)
#color = color
##repaint_color += 1
end
def self.color
#color
end
end
I guess I am being thrown by the c.color / c.paint: should I be defining these methods and setting them equal to class or something else ? I think I am missing something about classes and inheritance.
I guess I am being thrown by the c.color / c.paint: should I be
defining these methods and setting them equal to class or something
else ? I think I am missing something about classes and inheritance.
I think in fact you are over-complicating it by worrying about these things at this stage. The question is not about inheritance. Although in some ways it is poorly specified in that it is possible to mis-interpret the question text and assign some properties to the class other than the instance.
So first things, you have got that the question expects you to implement a Car class, and that there is internal state to track for the current color and the number of times it has changed. You have partly mis-understood the repaint count and made it a class variable. It needs to be an instance variable - it is intended to be the number of times a specific car has been re-painted, not the number of times any car has been re-painted. Although the example numbers would be the same, the difference is that the question asks for c.repaint_count not Car.repaint_count, and c is an instance of Car, hence you want to store the count as an instance variable - set it to 0 in the constructor.
Similar confusion in your accessor code. Ruby's use of self is a little confusing - it changes meaning on context in the code. If you changed your def self.paint to just def paint and similarly for color then with the change from last paragraph, you are pretty much done.
One last thing, you need to implement repaint_count accessor similar to how you have done with color (and again, without the self. which would make it a class method)
You seem to be confusing classes and instances. c is an instance of Car, and is not the class Car itself. Unless you want to count the total repaint_count throughout the Car class, you should not use a class variable ##repaint_count, but should use an instance variable. Your paint method is a class method, and is not well defined. In addition the definition body looks like you randomly put something.
class Car
attr_reader :color, :repaint_count
def initialize color
#color = color
#repaint_count = 0
end
def paint color
#color = color
#repaint_count += 1
end
end
Well, this looks like a homework question, which I'm not going to write for you. However I'll give you some pointers.
You create/ open up a class like this.
class Foo
end
When you open up a class like this you can set it up to accept arguments immediately, like so:
class Foo
attr_accessor :bar, :bar_counter
def initialize(arg_1)
#bar = arg_1
#bar_counter = 0
end
# And add methods with any name like so.
def increase_bar
#bar_counter += 1
end
def change_bar(arg)
#bar = arg
end
end
This will explain the differences between attr_accessor, attr_reader, attr_writer https://stackoverflow.com/a/4371458/2167965
People have various opinions on Codecademy, but in my opinion it's perfect for teaching basic syntax like this. There's also Ruby Koans, and Ruby Test First.
My recommendations would be to start with codecademy to learn the syntax, and move to Test First to flesh out those concepts.
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.
(working in Ruby)
First off, I apologize in advance. I'm not a programmer by training, I've simply come to it by dint of convenience and a changing world. What I needed to do involved programming, and I got tired of waiting around for others to do my programming for me. As such, I've missed some basic concepts along the way, and when I ask these questions I sometimes make a fool of myself by consequence.
Let's say I want to define a species/job relationship in classes. I want to define a superclass "BlackAnt" and have subclasses "Worker" "Fighter" and "Queen"
To me, intuitively, this looks something like this:
class BlackAnt
#legs = 6
end
class Worker < BlackAnt
#jaws = 'small'
end
but if I then try
ant1 = Worker.new
puts ant1.legs
I get an error. If I amend class BlackAnt to:
class BlackAnt
attr_accessor :legs
#legs = 6
end
ant1.legs returns 'nil'
I've tried the method outlined here: http://railstips.org/blog/archives/2006/11/18/class-and-instance-variables-in-ruby/
and this allows Worker.legs to return '6', but... alas:
ant1 = Worker.new
Worker.legs => '6'
ant1.legs => 'nil'
At a guess, the values of those parent variables are not being initialized each time a new child is spawned.
I feel I'm being silly about this somehow, and the reply is no doubt going to make me curse the day I discovered caffeine-driven all-nighters. What I need to do is arrange things so that I can create objects like so:
ant1 = Worker.new
ant2 = Queen.new
ant3 = Fighter.new
and have them each acquire the appropriate quantity of legs, along with whatever special characteristics were assigned in the child class. The worker/queen/fighter classifications will be bound by namespaces such that the actual calls will be:
ant1 = AntBlack::Worker.new
ant2 = AntRed::Worker.new
ant3 = AntRed::Queen.new
etc.
I'd like to then be able to check the quantity of legs of an individual ant using:
ant1.legs #=> 6
I may be going around my elbow to get to my thumb. If so, feel free to offer alternate suggestions for ways to achieve the same result, I will greatly appreciate the insights.
///updated re:response///
class AntRed
attr_accessor :legs
def initialize
#legs = 6
end
end
class Worker < AntRed
#strength = 1
end
result:
irb(main):009:0> ant1 = Worker.new
#=> #<Worker:0x87616ac #strength=1>
irb(main):010:0> ant1.legs
#=> nil
Define your BlackAnt class as follows:
class BlackAnt
attr_accessor :legs
def initialize
#legs = 6
end
end
And your Worker class as follows:
class Worker < BlackAnt
attr_accessor :strength
def initialize
super
#strength = 1
end
end
The way you currently define the BlackAnt class, you are storing legs as a class level instance variable.
At a guess, the values of those parent variables are not being
initialized each time a new child is spawned.
In Ruby instance variables belong to a single object. Look at point 7) in my answer starting
To address your "If true that they are variables"
in Why are symbols in Ruby not thought of as a type of variable?
I don't understand why you get irb(main):010:0> ant1.legs #=> nil. For me it works (at least as script).
class AntRed
attr_accessor :legs
def initialize
#legs = 6
end
end
class Worker < AntRed
end
ant1 = Worker.new
print 'ant1.legs : '; puts ant1.legs
Execution :
$ ruby -w test.rb
ant1.legs : 6
you mean you want a class's instance varieble which has been initialed!
so you can do it like this:
class BlackAnt
attr_accessor :legs
#legs = 6
def initialize
#legs = self.class.instance_variable_get(:#legs)
end
end
newObj = BlackAnt.new
newObj.legs
If you look around you'll find some comparisons of class variables to class instance variables, and the best I ever hear of class variables are "that might be what you want", but I've never heard anybody say that is what they want, or when the situation of sharing a variable across an entire inheritance tree might be more useful.
So in practice, when is a class variable a better choice than a class instance variable?
Another example(you want unique name for every object)
class Foobar
##uniqueId = 0
def initialize
##uniqueId += 1
end
def unique_name
"Foobar_" + ##uniqueId.to_s
end
end
a = Foobar.new
puts a.unique_name
a = Foobar.new
puts a.unique_name
This will output
Foobar_1
Foobar_2
Edit: Singleton pattern is also good example for static variables link
The easiest example would be that you use class variable to store some overview states of that class or shared states of all instances.
class Foobar
##total = 0
def initialize
##total += 1
end
class << self
def all
##total
end
end
end
5.times { Foobar.new }
Foobar.all #=> 5
So here ##total will show you how many instances have been created as a sum.
Rails' ActiveRecord#FinderMethods#all simply returns the array's size. But if all your instances of a class are not wrapped in a array, using class variable to return "all" is also a solution.