Does Ruby Call Initialize Method Automatically

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 duping or cloneing, 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



Leave a reply



Submit