In Ruby, what's the relationship between 'new' and 'initialize'? How to return nil while initializing?

RubyConstructorReturnNew OperatorInitializer

Ruby Problem Overview


What I want is:

obj = Foo.new(0)  # => nil or false

This doesn't work:

class Foo
  def initialize(val)
    return nil if val == 0
  end
end

I know in C/C++/Java/C#, we cant return a value in a constructor.

But I'm wondering whether it is possible in Ruby.

Ruby Solutions


Solution 1 - Ruby

>In Ruby, what's the relationship between 'new' and 'initialize'?

new typically calls initialize. The default implementation of new is something like:

class Class
  def new(*args, &block)
    obj = allocate

    obj.initialize(*args, &block)
    # actually, this is obj.send(:initialize, …) because initialize is private

    obj
  end
end

But you can, of course, override it to do anything you want.

>How to return nil while initializing? > >What I want is: > > obj = Foo.new(0) # => nil or false > >This doesn't work: > > class Foo > def initialize(val) > return nil if val == 0 > end > end > >I know in C/C++/Java/C#, we cant return a value in a constructor. > >But I'm wondering whether it is possible in Ruby.

There is no such thing as a constructor in Ruby. In Ruby, there are only methods, and they can return values.

The problem you are seeing is simply that you want to change the return value of one method but you are overriding a different method. If you want to change the return value of method bar, you should override bar, not some other method.

If you want to change the behavior of Foo::new, then you should change Foo::new:

class Foo
  def self.new(val)
    return nil if val.zero?
    super
  end
end

Note, however, that this is a really bad idea, since it violates the contract of new, which is to return a fully initialized, fully functioning instance of the class.

Solution 2 - Ruby

There are important differences between the two methods.

new is a class method, which generally creates an instance of the class (this deals with the tricky stuff like allocating memory that Ruby shields you from so you don't have to get too dirty).

Then, initialize, an instance method, tells the object to set its internal state up according to the parameters requested.

Either of these can be overridden depending on what you want. For example, Foo.new might actually create and return an instance of FooSubclass if it needs to be clever enough to do that.

However, often it's better to delegate use cases like these to other class methods which are more explicit about what they do, for example Foo.relating_to(bar). Breaking other peoples expectations about what methods like new should do will confuse people more than it will help them in the long run.

As an example, look at the implementation of Singleton, a module which allows only one instance of a particular class to exist. It makes the new method private, and exposes an instance method which either returns the existing instance of the object, or calls new if it hasn't been created yet.

Solution 3 - Ruby

You can something like this:

class Foo

  def self.init(val)
    new(val) unless val == 0
  end
  
  def initialize(val)
    #...
  end
end

Example of usage:

obj = Foo.init(0)
 => nil
obj = Foo.init(5)
 => #<Foo:0x00000002970a98>

Solution 4 - Ruby

Wanting to do

class Foo
  def initialize(val)
    return nil if val == 0
  end
end

would make for inconsistent code.

If you had

class Foo
  def initialize(val)
    return nil if val == 0
    @val = val
    @bar = 42
  end
end

what would you want to get back if you did Foo.new(1)? Would you want 42 (the return value for Foo#initialize), or a foo object? If you want a foo object for Foo.new(1), then why would you expect return nil to make Foo.new(0) return nil?

Solution 5 - Ruby

It is solved by simply creating an object variable like this:

class Foo
   def initialize(val)
       @val = val
       return nil if @val == 0
   end
end
obj = Foo.new(0)

Output:-
=>#<Foo:0x1243b8 @val=0>

The output varies in different computers.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionChris XueView Question on Stackoverflow
Solution 1 - RubyJörg W MittagView Answer on Stackoverflow
Solution 2 - RubyGarethView Answer on Stackoverflow
Solution 3 - RubyFlexoidView Answer on Stackoverflow
Solution 4 - RubyAndrew GrimmView Answer on Stackoverflow
Solution 5 - RubyluciferView Answer on Stackoverflow