Jonathan Allard
Jonathan Allard

Reputation: 19249

Why we define `#initialize` instead of `::new`

In Ruby, when making a new class, we will define the constructor method like so:

class Thing
  def initialize
     do_stuff
  end
end

However, when actually making an instance of the object, we find ourselves not calling initialize on the instance but new on the class.

That being the case, why don't we instead define ::new?

class Thing
   def self.new
     do_stuff
   end
end

Is there something ::new does beind the scenes that initalize doesn't define? Are those two different at all? Would defining ::new work? Or is it just that def initialize is shorter (not) than def self.new?

I'm thinking there must be a good reason for the disparity.

Upvotes: 6

Views: 527

Answers (3)

akuhn
akuhn

Reputation: 27793

To provide access to instance variables.

Instance variables, such as @value, are accessible from instances only but not from within a class method. This differs from languages such as Java where private instance variables have class rather than instance scope and are thus accessible from the static constructor.

class Thing
  def initialize
     @value = 42
  end
end

class Thing
  def self.new
    # no way to set the value of @value !!!!!!!!
  end
end

For those interested in the history of Ruby, the object model with instance-private instance variables goes back to Smalltalk. And you'll find the same pattern in modern Smalltalk dialect like Pharo, new is implemented in Object to call self initialize such that subclasses can easily initialize instance variables.

Upvotes: 7

sawa
sawa

Reputation: 168091

  • To elaborate on Abraham's point, in effect, that is reversing the wrapping relation. If you had allocate as a primitive and usually define new, then you would always have to do common things like calling allocate and returning the object at the end, which is a redundant thing to do. By having new and initialize, the former will wrap the latter, so you only need to define what is wrapped, not the wrapper.
  • new is a class method, so when you define that, you do not have access the instance methods and instance variables by default, and you need to rely on accessors. On the other hand, initialize is an instance method, so it will be easier to work with instance variables and instance methods.

Upvotes: 4

Abraham P
Abraham P

Reputation: 15471

New allocates space for the new object and creates it. It then calls the Objects initialize method to create a new Object using the allocated memory. Usually, the only part you want to customize is the actual creation, and are happy to leave the behind memory allocation to the Object.new method, so you write an initialize method. What new is doing under the hood looks something like this (except in C):

 class Object
    def self.new(*args, &block)
        object = allocate
        object.send(:initialize, *args, &block)
        return object
    end
 end

So when you call Object.new, what actually happens is:

1) Memory is allocated 2) The objects initialize method is called.

Upvotes: 13

Related Questions