Does ruby call initialize method automatically?
No, Ruby does not call initialize
automatically.
The default implementation of Class#new
looks a bit like this:
class Class
def new(*args, &block)
obj = allocate
obj.initialize(*args, &block)
obj
end
end
[Actually, initialize
is private
by default so you need to use obj.send(:initialize, *args, &block)
.]
So, the default implementation of Class#new
does call initialize
, but it would be perfectly possible (albeit extremely stupid) to override or overwrite it with an implementation that does not.
So, it's not Ruby that calls initialize
, it's Class#new
. You may think that's splitting hairs, because Class#new
is an integral part of Ruby, but the important thing here is: it's not some kind of language magic. It's a method like any other, and like any other method it can be overridden or overwritten to do something completely different.
And, of course, if you don't use new
to create an object but instead do it manually with allocate
, then initialize
wouldn't be called either.
There are some cases where objects are created without calling initialize
. E.g. when dup
ing or clone
ing, initialize_dup
and initialize_clone
are called instead of initialize
(both of which, in turn, call initialize_copy
). And when deserializing an object via, say, Marshal
, its internal state is reconstructed directly (i.e. the instance variables are set reflectively) instead of through initialize
.
ruby initialize method - purpose of initialize arguments
You can set an instance variable in any method in your class.
initialize
is a method that is executed immediately after calling Person.new
.
All external data for new object is passed through the arguments of .new(args)
.
Your line @age = age
- it's the same that @age = nil
.
This is due to the fact that age
is absent in the arguments of initialize
.
Also you have attr_accessor :age
.
It's equal, that you have methods:
def age
@age
end
def age=(age)
@age = age
end
So you can set instance variable like this:
john = Person.new('John')
p john.age #=> nil
john.age = 5
p john.age #=> 5
Accessing an instance variable within the `initialize` method
The "getter method" is defined so that you can use the variable from outside the class:
class TestClass
attr_reader :name
def initialize(name)
@name = name
end
end
# TestClass.new('Ben').name # => 'Ben'
If you don't need to access it from outside the class, you can just use @name
:
class TestClass
def initialize(name)
@name = name
end
def greet
puts "Hello, %s" % @name
end
end
# TestClass.new('Ben').greet # outputs: Hello, Ben
You can use the @name
inside initialize:
class TestClass
def initialize(name)
@name = name
puts "Name backwards: %s" % @name.reverse
end
end
# TestClass.new('Ben') # outputs neB
Initialize is a special method, when you define initialize
instance method, it is automatically marked private
. The class method new
calls it after creating an instance of your class.
Nothing stops you from calling private methods from inside the class:
class TestClass
def initialize(name)
@name = name
puts "Name is now %s" % @name
end
def flip_name
initialize(@name.reverse)
end
end
# t = TestClass.new('Ben') # outputs "Name is now Ben"
# t.flip_name # outputs "Name is now neB"
# t.instance_variable_get(:@name) # => 'neB'
The flip_name
method that calls initialize
works just fine, but of course this is quite unconventional and almost never used, because it does not make much sense.
It's possible to call private methods from outside the class using send
:
# t.send(:initialize, 'Bill') # outputs "Name is now Bill"
# t.instance_variable_get(:@name) # => 'Bill'
Without send, you get NoMethodError
:
> t.initialize('Jack')
NoMethodError: private method `initialize' called for #<TestClass:0x00007fa2df8e4570>
Ruby 1.9 beta releases changed send
to act like public_send
does today, allowing access to only public methods and there was going to be funccall
for calling private methods if you really want to, for unit testing purposes for example. I think it caused too much compatibility issues and the change was reverted.
So in conclusion, yes, you can call initialize
again and it does not cease to exist, but it is almost never done because it makes very little sense. To access instance variables from inside the class, you use @
notation like @name
, to access them from outside of the class, you define a getter.
When and when not to use the initialize method in ruby
The initialize
method is necessary for objects which require something to be done during the object's initialization, that's all. Some objects do not require initialization, for example:
class Dog
def woof
:arf
end
end
However if you wanted to be able to customize how this dog could bark, you could give it an initializer:
class Dog
WOOF_DEFAULT = :arf
attr_reader :woof
def initialize(woof)
@woof = woof || WOOF_DEFAULT
end
end
Now you can configure it during the initialization:
dog = Dog.new(:bork)
dog.woof
# => :bork
You don't always need initialize
, but it is a useful tool for when you do.
In the context of a board, presumably you need to create the board:
class Board
def initialize
# Create 9 cells, each of which is nil by default
@cells = Array.new(9, nil)
end
def move(x, y, side)
# Make a move in a cell if the cell is not occupied (||=)
@cells[x + y * 3] ||= side
end
def to_s
# Produces a string representation of the board state
@cells.map do |cell|
cell || ' '
end.each_slice(3).map do |row|
row.join(' | ')
end.join("\n---------\n")
end
end
Where now you have a board which you can use like this:
b = Board.new
puts b
# | |
# ---------
# | |
# ---------
# | |
puts
b.move(0,1, 'X')
b.move(1,0, 'O')
puts b
# | O |
# ---------
# X | |
# ---------
# | |
Ruby class initialize (constructor) is private method or public method?
Let's see:
class Test
def initialize; end
end
p Test.new.private_methods.sort.include?(:initialize)
This prints true
, so initialize
is a private method. This makes sense, it is only called by the new
class method if the object is created. If we want, we can do something like this:
class Test
def initialize
@counter = 0
end
def reset!
initialize
end
end
Misusing the constructor like this could however lead to problems if it does more than simple variable initialization.
How to call a method immediately after initialization in ruby?
Yes, if you allow to also define initialize
in another module.
module Child
def initialize
super
# ... some_method_stuff
end
end
Something.prepend Child
Why doesn't initialize appear as a method when I call on the instance methods of a class?
instance_methods
returns an array of public and protected methods. However, initialize
is automatically private ref.
CoolBeans.private_instance_methods
# => [:initialize, :default_src_encoding, :irb_binding, :initialize_copy, :initialize_dup, :initialize_clone, :sprintf, :format, :Integer, :Float, :String, :Array, :Hash, :warn, :raise, :fail, :global_variables, :__method__, :__callee__, :__dir__, :eval, :local_variables, :iterator?, :block_given?, :catch, :throw, :loop, :respond_to_missing?, :trace_var, :untrace_var, :at_exit, :syscall, :open, :printf, :print, :putc, :puts, :gets, :readline, :select, :readlines, :`, :p, :test, :srand, :rand, :trap, :load, :require, :require_relative, :autoload, :autoload?, :proc, :lambda, :binding, :caller, :caller_locations, :exec, :fork, :exit!, :system, :spawn, :sleep, :exit, :abort, :Rational, :Complex, :set_trace_func, :gem, :gem_original_require, :singleton_method_added, :singleton_method_removed, :singleton_method_undefined, :method_missing]
# ^^^^^^^^^^^
Ruby class initialize method with default hash
Keyword arguments were introduced with Ruby 2.0.
The documentation gives details, and the Ruby Rogues podcast back then had an interesting discussion about it.
Note that this applies to any method, not only to initialize
.
Ruby: automatically call a method when attribute is set
You can write your own attr_writer
-style method to accomplish this. Feel free to comment if this is unclear.
class Weather
attr_reader :temp
def temp=(val)
@temp = f_to_c(val)
end
def f_to_c(temp)
(temp - 32).to_f * (5.0 / 9.0)
end
end
Related Topics
Sort Strings and Numbers in Ruby
Rails Carrierwave Base64 Image Upload
How to Pass Data from a Controller to a Model with Ruby on Rails
How to Read Whole File in Ruby
Check If an Array Is Subset of Another Array in Ruby
How to Declare a String with Both Single and Double Quotes in Yaml
Ruby on Rails Send_File Doesn't Work Until I Refresh the Page
Reflection on Method Parameters in Ruby
How to Run a .Rb File from Irb
How to Express Infinity in Ruby
Reading and Updating Yaml File by Ruby Code
How to Get the Last SQL Query Performed by Activerecord in Ruby on Rails
Regex, How to Match Multiple Lines
Yaml Indentation for Array in Hash
In Ruby Why Does Nil.Id Return 4
How to Create Symbol (Hash Key) from Association, Using New Ruby (1.9) Hash Syntax