Friday, June 13, 2008

Creating Alternate Ruby Objects

One of the things I've found slightly frustrating about Ruby is the new method. Nearly twenty years ago I was writing code in Objective-C on NeXT, which had explicit allocation and initialization:
   Object foo = [[Foo alloc] init]
Using this invocation, foo could be any sort of Object, and init could return any sort of Object. Ruby (and most other OO languages, for that matter) combine the alloc-init into a 'new' method:
   foo =
The problem is that the object returned is a Foo, at least unless a class supplied its own specialized new.

In a short paper I've written, Creating Alternate Ruby Objects, I discuss a generalized mechanism that allows object remapping in new. This enables a class' new method to return a different object than the one allocated, according to decisions made in the initialize method.

The mechanism has been added to the release 1.0.4 of my eymiha rubygem in my Chunks of Ruby Infrastructure Project on RubyForge.


Jim said...

Dave, do you have a use case for the remapping new? I'm having a hard time imagining where it would be useful.

Also, the implementation of remap seems confusing:

(1) You create the object using the original new.

(2) you replace that object with a different object is that newly created object is in the remap hash.

I'm a little unclear how a newly created object gets placed in the remap hash before it is created.

Dave Anderson said...

There are a few that make sense, such as when an instance should be shared among multiple callers, or when the instance is being wrapped by an instance of another class, or when the program logic indicates that some other instance is more appropriate, or when the instantiation of an object takes a long time and a pool of already-instantiated objects is maintained by another thread. There are a bunch of possible uses.

The implementation is straightforward... the caller asks for an instance by calling new, new calls allocate, allocate returns an unintialized instance A, new calls initialize on the A, A decides a more appropriate object B should be returned and adds A=>B into the remap Hash, initialize returns, new looks in the remap using the A as the key, if new finds mapping (A=>B in this case) it deletes the mapping and returns the value (B).

If A=>B had not been added to the remap Hash by initialize, new would not have found a remapping after initialize returned, and so A would be returned by new.