I think I'm going a bit crazy when trying to understand instance variables in Ruby. My only aim here is to make sure that every object created for a given class has a variable with a predetermined value without writing an initialize
method for that class. Something like:
class Test
@my = []
attr_accessor :my
end
t = Test.new
t.my # I want [] but this shows nil
Is it possible to achieve this without touching initialize
? Thanks.
EDIT: To clarify, I'm writing some piece of code which will be executed similar to attr_accessor
in the sense that it'll add an instance variable to the class in which it is executed. If I write my own initialize
, I will end up clobbering the one written by the user.
The ruby instance variables do not need a declaration. This implies a flexible object structure. Every instance variable is dynamically appended to an object when it is first referenced. An instance variable belongs to the object itself (each object has its own instance variable of that particular class)
Normally, you would put code to initialize an instance variable in a constructor. There are two alternatives to using a constructor to initialize instance variables: initializer blocks and final methods. The Java compiler copies initializer blocks into every constructor.
In the Ruby programming language, an instance variable is a type of variable which starts with an @ symbol. Example: @fruit. An instance variable is used as part of Object-Oriented Programming (OOP) to give objects their own private space to store data.
The initialize method is useful when we want to initialize some class variables at the time of object creation. The initialize method is part of the object-creation process in Ruby and it allows us to set the initial values for an object.
What you are doing is defining an instance variable on the class level (Since classes are instances of the Class class, this works just fine).
And no, there is no way around initialize.
Edit: You have a little misconception in your edit. attr_accessor
doesn't add an instance variable to the class. What it does, literally, is this (using your example of my
):
def my; @my; end
def my=(value); @my = value; end
It doesn't actively create/initialize any instance variable, it just defines two methods. And you could very well write your own class method that does similar things, by using define_method
.
Edit 2:
To further illustrate how one would write such a method:
class Module
def array_attr_accessor(name)
define_method(name) do
if instance_variable_defined?("@#{name}")
instance_variable_get("@#{name}")
else
instance_variable_set("@#{name}", [])
end
end
define_method("#{name}=") do |val|
instance_variable_set("@#{name}", val)
end
end
end
class Test
array_attr_accessor :my
end
t = Test.new
t.my # => []
t.my = [1,2,3]
t.my # => [1, 2, 3]
# as instance variable without initialize
class Test1
def my; @my ||= [] end
attr_writer :my
end
t = Test1.new
t.my
# as class instance variable
class Test2
@my = []
class << self; attr_accessor :my end
end
Test2.my
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With