Sean O'Halpin
7/15/2006 5:40:00 PM
On 7/15/06, Daniel Schierbeck <daniel.schierbeck@gmail.com> wrote:
> Sean O'Halpin wrote:
> > On 7/15/06, Daniel Schierbeck <daniel.schierbeck@gmail.com> wrote:
> >> transfire@gmail.com wrote:
> >> > Jan Molic recently contacted me about a slighlty modified version of
> >> > his OrderedHash class that I distribute in Facets, the Dictionary
> >> > class. There are a few variations of this class initself and Jan
> >> > originally provided these via a subclass. I, on the other, thought
> >> > alternate initializers would be better.
> >> >
> >> > Which is the best approach?
> >> >
> >> > Ex.
> >> >
> >> > class AutoOrderHash < OrderedHash
> >> >
> >> > def new(*args)
> >> > super(*args){ |h,k| h[k] = self.class.new }
> >> > end
> >> >
> >> > end
> >> >
> >> > vs.
> >> >
> >> > class OrderHash
> >> >
> >> > def self.auto(*args)
> >> > new(*args){ |h,k| h[k] = self.class.new }
> >> > end
> >> >
> >> > end
> >>
> >> I actually favor a third approach; keyword argument options.
> >>
> >> OrderHash.new(:auto? => true)
> >>
> >> I think Rails has shown us that such option hashes are extremely
> >> powerful and flexible.
> >>
> >>
> >> Just my $.02
> >> Daniel
> >>
> > I'm a big proponent of keyword arguments (which we implement in the
> > current version of Ruby using option hashes). However, I'm not sure
> > it's appropriate for this usage, i.e. selecting which kind of object
> > is created.
> >
> > You would have to select which alternative initializer to call in
> > OrderHash.initialize and extract each different set of arguments
> > depending on which alternative initializer you're calling. It would
> > add unnecessary complexity and overhead. It also suffers from the
> > cognitive load of having to remember three things (class, selector,
> > which options go with which selector) instead of two (class,
> > initializer signature). Also, if you add another kind of OrderedHash,
> > you have to change OrderHash#initialize.
> >
> > I'm all for keyword ~options~ in initializers which modify some aspect
> > of the newly created object. I'm just not sure you want to have the
> > initializer return different classes of object depending on those
> > options.
> >
> > BTW, the keyword arguments technique has a long history before Rails
> > came along ;)
>
> Who said anything about multiple classes?
Fair enough - I was thinking about the original implementation and
Logan's creative solution.
>
> class OrderHash
> def initialize(*args)
> options = args.shift.to_hash if args.last.respond_to? :to_hash
Don't you think this is rather fragile? What if you want to initialize
with an object that responds to :to_hash but isn't a set of options?
Also, this will fail if no args are passed (minor point).
> if options and options.has_key? :auto?
> do_something_with{|hsh, key| hsh[key] = self.class.new}
> end
Plus similar tests for every other alternative. This doesn't seem to
me to be good design for the reason I gave earlier - if you add new
specialised kinds of hash, you'll have to change (or completely
replace) this initializer. Don't you think it would be a cleaner
design to simply create a new subclass? Isn't this what inheritance is
for? Even reopening the OrderedHash class to add a new alternative
initializer is cleaner.
> end
> end
>
A third point is that having an interface like this means you can't
use OrderedHash and AutoOrderedHash as simple drop-in replacements for
Hash. The same goes for the alternative initializer approach.
Cheers,
Sean