Alternate initializers or alternate class?

T

transfire

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

Thanks,
T.
 
S

Sean O'Halpin

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

Thanks,
T.
I generally find it easier to remember what general kind of thing I
want (i.e. class) than what specific subtype of thing I want
(alternative initializer). For example, the Date class has a whole
load of alternative initializers which I usually have to look up. I
find it easier to wrap those in specific classes.

Using different classes, you have two pieces of information to correlate:
a) class name
b) signature of initializer

Using alternative initializers, you have three:
a) class name
b) method name of alternative initializer
c) alternative initializer signature

Just my tuppence worth.

Regards,
Sean
 
L

Logan Capaldo

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

Thanks,
T.

The second implemented in terms of the first?

class OrderHash
def self.auto(*args)
AutoOrderHash.new(*args)
end
end

Yes, please have your cake and eat it too. :)
 
T

transfire

Logan said:
The second implemented in terms of the first?

class OrderHash
def self.auto(*args)
AutoOrderHash.new(*args)
end
end

Yes, please have your cake and eat it too. :)

Hmmm... I like the "taste" of that ;-)

Thanks,
T.
 
D

Daniel Schierbeck

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
 
S

Sean O'Halpin

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 ;)

Regards,
Sean
 
D

Daniel Schierbeck

Sean said:
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?

class OrderHash
def initialize(*args)
options = args.shift.to_hash if args.last.respond_to? :to_hash
if options and options.has_key? :auto?
do_something_with{|hsh, key| hsh[key] = self.class.new}
end
end
end

I haven't yet read through the OrderHash/Dictionary code, so it might be
better to put it in ::new


Cheers,
Daniel
 
S

Sean O'Halpin

Sean said:
(e-mail address removed) 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.

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
 
T

transfire

Sean said:
+1 - having cake and eating it is a thing devoutly to be wished for ;)

Well, it seemed all well and good but now I find myself having to
create Auto versions of every other subclass of Hash. I have a few, so
that start's to get ugly. hmm....

T.
 
S

Sean O'Halpin

Well, it seemed all well and good but now I find myself having to
create Auto versions of every other subclass of Hash. I have a few, so
that start's to get ugly. hmm....

T.
You don't have to write the code yourself! :)

def make_auto(*classes)
classes.each do |klass|
new_class = Class.new klass do
def initialize(*args)
super(*args){ |h,k| h[k] = self.class.new }
end
end
Object.const_set("Auto#{klass}", new_class)
end
end

class OrderedHash < Hash
# do something here
end

make_auto Hash, OrderedHash

ah = AutoHash.new
aoh = AutoOrderedHash.new

p ah[:a]
p aoh[:b]
__END__
{}
{}

Regards,
Sean
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top