From: ptkwt@...1.aracnet.com (Phil Tomson) Date: 2002-09-13T16:42:52+09:00 Subject: Re: not grasping the method overloading/multi-dispatch thing In article <9lr1ou4okjrafjrq24pusqi8q9c9fbfkvt@4ax.com>, wrote: >In Phil's example, it seems like "meth" is testing the argument's >class, not its type. According to my copy of _Design Patterns_, the >type of an object is the set of methods to which it can respond. If >two objects respond to the same set of methods then they have the same >type, even if they aren't objects of the same class. > >For me, testing an argument's class is a code smell. Yes, I tend to agree... >What do I care if >"s" is a Foo or a Bar, as long as it responds to the methods I need to >send it? I try to design my classes and methods so that, if I want >method "A" to accept as arguments objects that are created from >different classes, then each of the classes should implement the set >of methods that "A" will send. As far as "A" is concerned, all the >objects have the same type. > >So, for the case where you want to "overload" concat to accept EITHER >String objects or Fixnum objects: > > concat("A", "B") -> "AB" > concat("A", 1) -> "A1" > concat(1, 2) -> "12" > >then you define concat as > >def concat(arg1, arg2) > arg1.to_s + arg2.to_s >end > >Since both String and Fixnum objects respond to to_s, they're both the >same type as far as concat is concerned. > Yes, but what about an example like this (This is some actual code I have which I hesitate to show because I'm sure it's pretty smelly code, but I'm also not sure how else to do this): class Signal #.... def assign_at (relTime=0,function=nil) #schedule an event nextValue = case function when nil Proc.new.call when Proc function.call when Signal proc{function.to_s}.call else #should probably be Fixnum function end @eventQueue[relTime] = nextValue nextValInQueue = @eventQueue.shift @next_value = nextValInQueue if nextValInQueue end def assign(function=nil) if function assign_at(0,function) else assign_at(0,Proc.new) end end #.... end The idea here is that I want Signal objects to be able to be assigned from either Proc objects, other Signals, or values, like: a = Signal.new(0) b = Signal.new(1) sig = Signal.new sig.assign { a * b } #calculate a value based on values of a & b sig.assign b #assign the value of b to sig sig.assign 0 #assign 0 to sig sig.assign_at(10,1) #assign 1 to sig @ time 10 How else could this be done? Proc objects, Signal objects and Fixnums don't really have much in common... But as was suggested earlier, perhaps a method could be added to each of these classes in order to eliminate testing the class of the argument. In this case it looks like a call method could be added to Fixnum which would just return the value of the number, but that wouldn't be quite right since this branch of the case would still need to be handled: when Signal proc{function.to_s}.call ... Since a proc needs to be created from the signal in this case... I was just getting around to looking at this piece of code to see if I could clean it up and it seemed appropriate to show it in this context. (Yeah, there's some funky stuff going on here. This code snippet is from RHDL, it lets Ruby look like a Hardware description language.) Phil