Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I change the return value of a class constructor in Ruby?

I have a class, Foo. I want to be able to pass the constructor a Foo instance, foo and get the same instance back out.

In other words, I want this test to pass:

class Foo; end

foo = Foo.new
bar = Foo.new(foo)

assert_equal foo, bar

Anyone know how I can do that? I tried this:

class Foo
  def initialize(arg = nil)
    return arg if arg
  end
end

foo = Foo.new
bar = Foo.new(foo)

assert_equal foo, bar  # => fails

but it doesn't work.

Help?

EDIT

Because a number of people have asked for my rationale:

I'm doing rapid analysis of lots of data (many TB) and I am going to have a lot of instances of a lot of objects. For some of these objects, it doesn't make sense to have two different instances with the same data. For example, one such object is a "window" (as in temporal window) object that has two properties: start time and end time. I want to be able to use the constructor in any of these ways and get a window object back:

window = Window.new(time_a, time_b)
window = Window.new([time_a, time_b])
window = Window.new(seconds_since_epoch_a, seconds_since_epoch_b)
window = Window.new(window_obj)
window = Window.new(end => time_b, start => time_a)
...

Some other object that needs a window might be instantiated this way:

obj = SomeObj.new(data => my_data, window => window_arg)

I don't necessarily know what's in window_arg, and I don't really care -- it will accept any single argument that can be interpreted by the Window constructor. In the case of already having a Window instance, I'd rather just use that instance. But the job of interpreting that seems like a concern of the Window constructor. Anyway, as I mentioned I'm churning through many TB of data and creating lots of instances of things. If a window object gets passed around, I want it just to be recognized as a window object and used.

like image 348
Sir Robert Avatar asked Feb 03 '11 16:02

Sir Robert


People also ask

Can a class constructor return a value?

No, constructor does not return any value.

What does .NEW do in Ruby?

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.

How do you initialize a constructor in Ruby?

Constructors are used to initialize the instance variables. In Ruby, the constructor has a different name, unlike other programming languages. A constructor is defined using the initialize and def keyword.

What does .class return in Ruby?

class → class. Returns the class of obj. This method must always be called with an explicit receiver, as class is also a reserved word in Ruby. 1. class #=> Fixnum self.


2 Answers

def Foo.new(arg=nil)
  arg || super
end
like image 44
Jörg W Mittag Avatar answered Sep 19 '22 04:09

Jörg W Mittag


By definition, constructors are meant to return a newly created object of the class they are a member of, so, no you should not override this behavior.

Besides, in Ruby, new calls initialize somewhere within its method body, and its return value is ignored, so either way the value you return from initialize will not be returned from new.

With that said, I think that in your case, you might want to create a factory method that will return different Foo objects based on arguments passed to the factory method:

class Foo
  def self.factory(arg = nil)
    return arg if arg.kind_of? Foo
    Foo.new
  end
end
foo = Foo.factory
bar = Foo.factory(foo)

assert_equal foo, bar #passes
like image 144
Jacob Relkin Avatar answered Sep 21 '22 04:09

Jacob Relkin