Constructors in Ruby
In Ruby, a particular instance method called initialize serves as the constructor. When an object is formed, it is automatically called to set up its initial state. In Ruby, the concept of a “constructor” is implemented through a special instance method called initialize
. When you create a new object of a class using ClassName.new
, Ruby automatically calls the initialize
method on that newly created object.
Key Characteristics of Constructors (initialize)
Automatic Invocation: Usually, when the class method new is run, memory is allocated for a new
object instance, and the initialize
function is automatically called right away.
Argument Passing: Any arguments submitted to the initialize
method are passed straight from the Class.new
method.
Object Creation Flow: Calling allocate
to create the uninitialized object and then calling initialize
to specify its state are the two phases that the default new
method usually handles in the object creation process.
State Management: Initialize
main function is to assign parameters local variables inside the method to instance variables, which are variables that start with @
. When the method is finished running, local variables defined within initialize
are removed, while instance variables remain for the duration of the object.
Return Value Ignored: The object produced by allocation
is returned by the new
method, which always ignores the initialize
return value.
Visibility: It is inherently private to use the initialize
method. To reinitialize the state of an object, you cannot use initialize
manually from outside the class.
Code Examples Demonstrating
Example 1: Basic Initialization
There can only be one constructor per class, and that is the initialize
method. Using this technique, arguments are assigned to instance variables:
class Customer
attr_reader :name # Automatically creates a `name` getter method
def initialize(name)
@name = name.capitalize
end
end
sarah = Customer.new('sarah')
puts sarah.name #=> "Sarah"
Output
Sarah
Calling Customer.new('sarah')
in this example implicitly calls initialize('sarah')
. Following its passing as the local variable name, the value'sarah
‘ is placed in the instance variable @name
.
Example 2: Distinguishing Instance Variables from Local Variables
When leaving the constructor, local variables defined in initialize
are destroyed, whereas instance variables (preceded by @
) are available across instance methods.
class Person
def initialize(name, age)
# The age is now stored in an instance variable, @age
@name = name
@age = age
end
def some_method
puts "My name is #{@name}."
end
def another_method
# This now works because @age is an instance variable
puts "My age is #{@age}."
end
end
mhmd = Person.new("Mark", 23)
mhmd.some_method
mhmd.another_method
Output
My name is Mark.
My age is 23.
Example 3: Constructor Chaining via Inheritance ()
The initialize method is inherited when creating a subclass. A subclass should typically call super
if it defines its own initialize
in order to guarantee that the parent class (superclass) is initialized appropriately. The super
keyword invokes a method in the superclass with the same name (in this case, initialize
).
When a basic 2D point is the ancestor of a 3D point:
class Point
# Provides read access to @x and @y
attr_reader :x, :y
def initialize(x, y)
@x, @y = x, y
end
end
class Point3D < Point
# Provides read access to @z
attr_reader :z
def initialize(x, y, z)
# Pass our first two arguments (x, y) along to the superclass initialize method
super(x, y)
# Deal with the third argument ourselves
@z = z
end
end
# Create a new instance of Point3D
p3d = Point3D.new(1, 2, 3)
# Access and print the values of the instance variables
puts "X-coordinate: #{p3d.x}"
puts "Y-coordinate: #{p3d.y}"
puts "Z-coordinate: #{p3d.z}"
Output
X-coordinate: 1
Y-coordinate: 2
Z-coordinate: 3
In this example, Point3D
relies on the parent’s initialize
method to create and set @x
and @y
by calling super(x,y)
. This chaining ensures that instance variables defined in the parent class are properly brought into existence for the subclass instance.
You can also read Method Parameters In Ruby: Defaults, Blocks And Flexibility