Ruby fields initialization - ruby

In this tiny class when the #sides=10 statement is executed?
How this statement is related to the initialize method?
class Poligon
attr_accessor :sides
#sides=10
end
I am mostly used to Java where it is common to have inline initialization for the attributes. I am now trying to understand the complete initialization procedure for Ruby but I was not able to find it.

Short answers:
The statemen #sides = 0 (which actually is an expression) is exectuted when the class expression in evaluated.
It is not related at all with the initialize method.
As you write it, the #sides variable is a class instance variable, i.e. an instance variable of the Poligon object (remember that in Ruby classes are objects of class Class). You must initialize instance variables inside a method definitions (perhaps inside the initialize method). Consider this example:
class Poligon
#class_sides = 'class instance variable'
def initialize
#instance_sides = 'instance variable'
end
end
Poligon.instance_variables
# => [:#class_sides]
Poligon.instance_variable_get(:#class_sides)
# => "class instance variable"
Poligon.new.instance_variables
# => [:#instance_sides]
Poligon.new.instance_variable_get(:#instance_sides)
# => "instance variable"
For more information about class instance variable and how they relate to class variables you can read this article by Martin Fowler.

You need to put this #sides=10 inside a method,with your current class definition.
class Poligon
attr_accessor :sides
def line
#sides=10
end
end
p = Poligon.new
p.line
puts p.sides
# >> 10

The initialize method is the constructor for the class. If you want, you can initialize your instance variables in the contructor:
class Poligon
attr_accessor :sides
def initialize(num_sides)
#sides = num_sides
end
end
But since #sides is declared as an attr_accessor, you can set/get it directly:
p = Poligon.new
p.sides = 10

Related

Why am I getting NoMethodError undefined method for nil::NilClass

['board'].each{|script| require_relative script}
class GameRunner
#board = Board.new
def initialize
end
def getBoard
#board
end
end
This piece of code generates an error when getBoard is called. But when I move the instantiation of #board to the initialize block there is no errors. Why?
Edit: An answer with a more clear explanation on what is going on: Ruby class instance variable vs. class variable
Here #board is an instance variable. Instance variables belong to an object (instance), hence why they are called instance variables.
You have two references to an instance variable named #board in your code. Now, ask yourself: which object do they belong to? In other words: what is self at the point where you reference the instance variable?
class GameRunner
# Here, `self` is `GameRunner`
#board = Board.new
def getBoard
# Here, `self` is an *instance* of `GameRunner`
#board
end
end
At the first reference to #board, self is the GameRunner class itself. Remember, class are objects just like any other object; they are instances of the Class class just like strings are instances of the String class, integers are instances of the Integer class, and game runners are instances of the GameRunner class.
You can easily see that the instance variable has been defined and initialized:
GameRunner.instance_variables
#=> [:#board]
GameRunner.instance_variable_get(:#board)
#=> #<Board:0x0000deadbeef1230>
At your second mention, however, self is an instance of GameRunner, and not the GameRunner class itself.
Or, to put it differently: you have two completely independent instance variables of two completely independent objects. The instance variables just happen to have the same name.
It's exactly the same as if you did:
game_runner1 = GameRunner.new
game_runner2 = GameRunner.new
The instance variables of game_runner1 and game_runner2 are private to each of those two objects. game_runner1 does not know anything about the instance variables of game_runner2 and vice versa. The same thing is true about game_runner1 and GameRunner.
Again, it is important to remember that classes are just objects like any other object.
It looks like what you actually want is to have both references refer to the same instance variable, namely an instance variable of an instance of GameRunner. You can achieve that by moving the assignment into an instance method, something like this:
class GameRunner
def initializeBoard
# Here, `self` is an *instance* of `GameRunner`
#board = Board.new
end
def getBoard
# Here, `self` is an *instance* of `GameRunner`
#board
end
end
However, this is somewhat annoying because you always have to remember to call initializeBoard before you can use the object, and you have to make sure that once you have called initializeBoard, you never call it again.
To make initialization tasks like this easier, Ruby has a convention: the default implementation of Class#new will call a method named initialize on the newly allocated object:
class Class
def new(...)
obj = allocate
obj.initialize(...)
obj
end
end
[This is not quite accurate because initialize is private by default, so it would be more like obj.__send__(:initialize, ...), but you get the idea.]
So, if we simply rename the initializeBoard method to initialize, that will ensure that our instance variable is always initialized by GameRunner::new:
class GameRunner
def initialize
# Here, `self` is an *instance* of `GameRunner`
#board = Board.new
end
def getBoard
# Here, `self` is an *instance* of `GameRunner`
#board
end
end
Note that your code violates multiple Ruby community coding standards:
Ruby uses 2 spaces for indentation, not 4.
There should be no empty line after class or before end
Method names use snake_case, not camelCase. IOW, your getter method should be called get_board.
… Except it shouldn't, because getters should simply be called noun, not get_noun, i.e. your getter method should be called simply board.
Lastly, trivial getters should not be defined by hand, but using the core Module#attr_reader method.
If we combine all of this, your class should look like this:
class GameRunner
attr_reader :board
def initialize
#board = Board.new
end
end
I, personally, prefer to avoid referring to instance variables directly as much as possible, and only use getters and setters. However, that is not a majority coding style, that is just my personal preference:
class GameRunner
attr_reader :board
private
def initialize
self.board = Board.new
end
attr_writer :board
end
Here #board is a class variable, not an instance variable.
What you probably mean is:
class GameRunner
# Anything declared here is assumed to be class-level
def initialize
# Anything inside an instance method is an instance variable
#board = Board.new
end
def getBoard
#board
end
end
Since classes are objects, the class can also have its own instance variables. Confusingly they also use the same # prefix.
It's worth noting that accessors like this are usually declared in Ruby as:
attr_reader :board
Which makes the method for you. The get prefix is almost always omitted because mutator methods (e.g. set) are the same but with the = suffix.

How to Initialize Class Arrays in Ruby

I want to create an empty array as a class instance variable in Ruby. However, my current method does not seem to work.
Here is my code:
class Something
#something = []
def dosomething
s = 5
#something << s
end
end
When I call the function, it gives me an undefined method traceback.
However, if I do something similar with class variables, i.e.:
class Something
##something = []
def dosomething
s = 5
##something << s
end
end
This works perfectly.
I know I can use the initialize method to actually create an empty list for #something, but is there another way of doing this without using the initialize method? And why does this work for class variables?
EDIT: Fixed typo
You need to use initialize as a constructor as below code and is there any reason why not to use initialize/constructor. And please fix a typo error in class definition Class Something to class Something no camel case or first letter capitalize while in class
class Something
def initialize
#something = Array.new
end
def dosomething
s = 5
#something << s
end
end
class variable ## are available to the whole class scope. so they are working in the code and if you want to use instance variable # you need to initialize it as above. The instance variable is share with instance/objects of a class
for more details visit the link Ruby initialize method
At first you have a typo. Change Classto class. Next I suggest to use the initialize method. While creating a new object this is the perfect place to initialize instance variables.
class Something
##my_class_variable = [1]
def initialize
#something = []
end
def dosomething
s = 5
#something << s
end
def self.get_my_class_variable
##my_class_variable
end
end
Your script will be read and executed from top to bottom and after this,
you can access the class Something. While the parser reads your script/class/module you can define class variables (##), execute mixins and extend the class with other modules. This is why you can define a class variable, but you can not define an instance variable. Because actually you have no instance object from your class. You only have a class object. In ruby everything is an object. And your class object has a defined class variable now:
Something.get_my_class_variable
# => [1]
Now you can create an instance from your class. With Something.new the initialize method will be invoked and your instance variable will be defined.
something = Something.new
something.dosomething
# => [5]
Later, if you are familar with this you can define getter and setter methods with attr_reader, attr_writer and attr_accessor for instance objects or cattr_reader, cattr_writer and cattr_accessor for class objects. For example:
class Something
attr_reader :my_something
def initialize
#my_something = []
end
def dosomething
s = 5
#my_something << s
end
end
something = Something.new
something.my_something
# => []
something.dosomething
# => [5]
something.my_something
# => [5]
Your problem in trying to access #something in your instance method is that, in the scope of instance methods, # variables refer to instance variables, and your #something is a class instance variable.
# variables are instance variables of the instance that is self when they are created. When #something was created, self was the class Something, not an instance of Something, which would be the case inside an instance method.
How then to access a class instance variable in an instance method? Like regular instance variables, this must be done via a method, as in attr_accessor. One way to do this is to use class << self to tell the Ruby interpreter that the enclosed code should be evaluated with the class (and not the instance) as self:
class C
#foo = 'hello'
class << self
attr_accessor :foo # this will be a class method
end
def test_foo # this is, of course, an instance method
puts self.class.foo # or puts C.foo
end
end
We can show that this works in irb:
2.3.0 :005 > C.foo
=> "hello"
2.3.0 :006 > C.new.test_foo
hello
You have correctly created a class instance variable, #something, and initialized it to an empty array. There are two ways for instances to obtain or change the value of that variable. One is to use the methods Object#instance_variable_get and Object#instance_variable_set (invoked on the class):
class Something
#something = []
def dosomething
s = 5
self.class.instance_variable_get(:#something) << s
end
end
sthg = Something.new
sthg.dosomething
Something.instance_variable_get(:#something)
#=> 5
The other way is to create an accessor for the variable. There are several ways to do that. My preference is the following:
Something.singleton_class.send(:attr_accessor, :something)
Something.something #=> [5]
In your dosomething method you would write:
self.class.something << s

Local variables in `class` definition scope versus `def` method scope

Here, I create a local variable in class scope:
class MyClass
x = 1
puts x
end
It prints 1 even if I don't create any instances of MyClass.
I want to use x in some method:
class MyClass
x = 1
def method
puts x
end
end
m = MyClass.new
m.method
And I can't. Why? I get that class definition creates a scope, but why is it not accessible in the method? Isn't scope of the method inside the scope of the class?
I can imagine that this is related to creation of a class. Since any class is an object of Class, maybe the scope of MyClass is the scope of some Class method, and the way of coupling methods of MyClass to that instance makes their scope completely different.
It also seems to me that I can't just create a scope with {} (like in C) or something like do..end. Am I correct?
Scope of a method is not inside the class. Each method has its own entirely new scope.
New scopes are created whenever you use the class, module, and def keywords. Using brackets, as in C, does not create a new scope, and in fact you cannot arbitrarily group lines of code using brackets. The brackets (or do...end) around a Ruby block create a block-level scope, where variables previously created in the surrounding scope are available, but variables created within the block scope do not escape into the surrounding scope afterward.
Instance methods share the scope of their instance variables with other instances methods. An instance variable defined in the scope of a class definition is available in class-level singleton methods, but not in instance methods of the class.
Illustration:
class Foo
x = 1 # available only here
#y = 2 # class-wide value
def self.class_x
#x # never set; nil value
end
def self.class_y
#y # class-wide value
end
def initialize(z)
x = 3 # available only here
#z = z # value for this instance only
end
def instance_x
#x # never set; nil
end
def instance_y
#y # never set; nil
end
def instance_z
#z # value for this instance only
end
end
Foo.class_x # => nil
Foo.class_y # => 2
Foo.new(0).instance_x # => nil
Foo.new(0).instance_y # => nil
foo3 = Foo.new(3)
foo4 = Foo.new(4)
foo3.instance_z # => 3
foo4.instance_z # => 4
You can access class-level instance variables from within instances using the class-level getter. Continuing the example above:
class Foo
def get_class_y
self.class.class_y
end
end
foo = Foo.new(0)
foo.get_class_y # => 2
There exists in Ruby the notion of a "class variable," which uses the ## sigil. In practice, there is almost never a reasonable use case for this language construct. Typically the goal can be better achieved using a class-level instance variable, as shown here.
Here, I create a local variable in class scope:
class MyClass
x = 1
puts x
end
It prints 1 even if I don't create any instances of MyClass.
Correct. The class definition body is executed when it is read. It's just code like any other code, there is nothing special about class definition bodies.
Ask yourself: how would methods like attr_reader/attr_writer/attr_accessor, alias_method, public/protected/private work otherwise? Heck, how would def work otherwise if it didn't get executed when the class is defined? (After all, def is just an expression like any other expression!)
That's why you can do stuff like this:
class FileReader
if operating_system == :windows
def blah; end
else
def blubb; end
end
end
I want to use x in some method:
class MyClass
x = 1
def method
puts x
end
end
m = MyClass.new
m.method
And I can't. Why? I get that class definition creates a scope, but why is it not accessible in the method? Isn't scope of the method inside the scope of the class?
No, it is not. There are 4 scopes in Ruby: script scope, module/class definition scope, method definition scope, and block/lambda scope. Only blocks/lambdas nest, all the others create new scopes.
I can imagine that this is related to creation of a class. Since any class is an object of Class, maybe the scope of MyClass is the scope of some Class method, and the way of coupling methods of MyClass to that instance makes their scope completely different.
Honestly, I don't fully understand what you are saying, but no, class definition scope is not method definition scope, class definition scope is class definition scope, and method definition scope is method definition scope.
It also seems to me that I can't just create a scope with {} (like in C) or something like do..end. Am I correct?
Like I said above: there are 4 scopes in Ruby. There is nothing like block scope in C. (The Ruby concept of "block" is something completely different than the C concept of "block.") The closest thing you can get is a JavaScript-inspired immediately-invoked lambda-literal, something like this:
foo = 1
-> {
bar = 2
foo + bar
}.()
# => 3
bar
# NameError
In general, that is not necessary in Ruby. In well-factored code, methods will be so small, that keeping track of local variables and their scopes and lifetimes is really not a big deal.
So just creating a class without any instances will lead to something
actually executing in runtime (even allocating may be)? That is very
not like C++. –
Check out this code:
Dog = Class.new do
attr_accessor :name
def initialize(name)
#name = name
end
end
If you execute that code, there won't be any output, but something still happened. For instance, a global variable named Dog was created, and it has a value. Here's the proof:
Dog = Class.new do
attr_accessor :name
def initialize(name)
#name = name
end
end
dog = Dog.new("Ralph")
puts dog.name
--output:--
Ralph
The assignment to the Dog constant above is equivalent to writing:
class Dog
...
...
end
And, in fact, ruby steps through each line inside the class definition and executes each line--unless the line of code is inside a def. The def is created but the code inside a def doesn't execute until the def is called.
A very common line you will see inside a class definition is:
attr_accessor :name
...which can be rewritten as:
attr_accessor(:name)
...which makes it obvious that it's a method call. Ruby executes that line--and calls the method--when you run a file containing the class definition. The attr_accessor method then dynamically creates and inserts a getter and a setter method into the class. At runtime. Yeah, this ain't C++ land anymore--welcome to NeverNever Land.
I get that class definition creates a scope, but why is it not
accessible in the method?
Because that is the way Matz decided things should be: a def creates a new scope, blocking visibility of variables outside the def. However, there are ways to open up the scope gates, so to speak: blocks can see the variables defined in the surrounding scope. Check out define_method():
class MyClass
x = 1
define_method(:do_stuff) do
puts x
end
end
m = MyClass.new
m.do_stuff
--output:--
1
The block is everything between do...end. In ruby, a block is a closure, which means that when a block is created, it captures the variables in the surrounding scope, and carries those variables with it until the the block is executed. A block is like an anonymous function, which gets passed to a method as an argument.
Note that if you use the Class.new trick, you can open two scope gates:
x = 1
MyClass = Class.new do
define_method(:do_stuff) do
puts x
end
end
m = MyClass.new
m.do_stuff
--output:--
1
Generally, ruby allows a programmer to do whatever they want, rules be damned.

Ruby newbie, what is the difference between #var and ##var in a class

as the title says,
what is the difference between #var and ##var in a class definition?
Also, what is the difference between self.mymethod and mymethod in defining a method?
##var is a class variable, it is shared between class and all instances of this class. You can access this variable from class methods and from instance methods.
class C
##a = 1
def self.m1 # define class method (this is similar to def C.m1, because self will evaluate to C in this context)
##a
end
def m2 # define instance method
##a
end
end
C.m1 # => 1
C.new.m2 # => 1
#var is a class instance variable. Normally you can get access to this instance variable from the class methods.
class C
#a = 1
def self.m1
#a
end
def m2
# no direct access to #a because in this context #a will refer to regular instance variable, not instance variable of an object that represent class C
end
end
C.m1 # => 1
These variables might be confusing and you should always know the context where you define instance variable #... - it might be defined in the instance of an object that represent a class or might be an instance of regular object.
self always refers to the current object.Check the following Eg:-
class Test
def test
puts "At the instance level, self is #{self}"
end
def self.test
puts "At the class level, self is #{self}"
end
end
Test.test
#=> At the class level, self is Test
Test.new.test
#=> At the instance level, self is #<Test:0x28190>
object variables are so named because they have scope within, and are associated
to, the current object.an object variable, is then accessible from any other method inside that object.
Class variables are particularly useful for storing information relevant to all objects
of a certain class.
In intuitive terms, instance vars are used to keep track of the state of each object. On the other hand, class variables are used to keep track of the state of all instances of the class. E.g. you might use ##count to keep track of the number of this class' objects that have been instantiated, like so:
class User
##count = 0
attr_reader :name
def initialize(name)
##count += 1
#name = name
end
end
User.count gives you the number of users that have been instantiated so far.
user = User.new('Peter') increases User.count by one and user.name returns Peter.

What can't I access class variable from object in ruby?

I wan't to set a class variable of a class from the outside(via attr_accessor), and then access it from inside one of its objects. I'm using ruby 1.9.2. This is my code:
class Service
def initialize(id)
#my_id = id
end
class << self
attr_accessor :shared_id
end
def system_id
#my_id + ##shared_id
end
end
If I set Service.shared_id = "A2", and then call Service.new("A").system_id, this doesn't return "AA2". It displays the following error:
uninitialized class variable ##shared_id in Service
The behaviour is like if I didn't set the Service.service_id. Can someone please explain why this happens?
attr_accessor creates methods to manipulate instance variables — it does not create instance or class variables. To create a class variable, you must set it to something:
##shared_id = something
There's no helper method to generate accessor for class variables, so you have to write them yourself.
However, class variables, because of their weird lookup rules, are rarely used — avoided, even. Instead, instance variables at class-level are used.
class Service
#shared_id = thing
class << self
attr_accessor :shared_id
end
def system_id
# use self.class.shared_id; you could add a shared_id helper to generate it, too.
end
end
How about cattr_accessor?
Remember that ##class_var is global for all classes.

Resources