From: Sean O'Halpin Date: 2006-07-16T02:39:59+09:00 Subject: Re: Alternate initializers or alternate class? On 7/15/06, Daniel Schierbeck wrote: > Sean O'Halpin wrote: > > On 7/15/06, Daniel Schierbeck 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