From: rgiar@... (Rob Giardina) Date: 2002-09-18T02:28:20+09:00 Subject: Re: not grasping the method overloading/multi-dispatch thing (warning: long) I've been following the multi-methods thread closely and having recently completed the book "The Art of the Meta-Object Protocol" by Kiczales et al. (matz Must have read this book, it's so ruby-ish (and ruby is so MOP-ish)), so I've got multi-methods on the brain. My infatuation aside, I've been following everyone's arguments and my opinion is that multi-methods may not be needed in Ruby due to Ruby's special ability to redefine classes on the fly. Some background: I see overloading/multi-methods/paramater typing as useful in those cases where we want to *multiply*, over a given operation, one set of types by another. For example, we might have some graphical objects and a Screen or a Printer on which to draw them. So that would be multiplying over the print operation: { Screen, Printer } *print* { Circle, Triangle, Square } Or, perhaps the normal Xml printing problem over the toXmlString operation: { XmlSerializer, RdfSerializer } *toXmlString* { DataNode, OpNode, TypeNode } Or, various execution contexts over *execute* on various command types: { ImmediateExecutor, QueuedExecutor, SecureExectutor } *execute* { ReadOnlyCommand, TransactionalCommand, TaintedCommand } So my question for myself and everyone else is: Where does this multiplied -between- logic belong in Ruby? In Other Languages, (Java, C++, CLOS), it belongs in the class itself and the dispatch decision among the various overloaded methods is made on the TYPE of the given arguments. Java: class XmlSerializer { public void serialize( DataNode n ) { /* do stuff to DataNode */ } public void serialize( OpNode n ) { /* do stuff to OpNode */ } public void serialize( TypeNode n ) { /* do stuff to TypeNode */ } } In CLOS, quite differently, it belongs -between- the class definitions, but the decision is still based on type. To me, this is appropriate (just ask the AspectOriented folks) but this style still requires typed parameter lists and multi-methods... ;;you don't really need this per-se since all the logic is in the ;;serialize methods, but let's pretend we've got a bunch of possible ;;serializer types (defclass xml-serializer () ()) (defgeneric serialize (stream node)) (defmethod serialize ((stream xml-serializer) (node data-node)) ;;data node stuff) (defmethod serialize ((stream xml-serializer) (node type-node)) ;;type node stuff) (defmethod serialize ((stream xml-serializer) (node op-node)) ;;op node stuff) So, in Ruby, where does this -between- stuff currently belong? You could do the dispatch yourself inside one (or each) of the classes on one side of the multiplication (ala Java): class XmlSerializer def serialize( node ) case node when TypeNode: serializeTypeNode( node ) when DataNode: serializeDataNode( node ) end end end Or you could put it inside one (or each) of the classes on one side, and use an idiom that I think captures the -between-ness in a uniquely Ruby way (akin to DoubleDispatch): class XmlSerializer #this is the 'owner' of this -between- logic #the key is to define specialized operations on all of the #intended partner types class << TypeNode def between-XmlSerializer-Nodes-serialize( serializer ) # do TypeNode stuff end end class << DataNode def between-XmlSerializer-Nodes-serialize( serializer ) # do DataNode stuff end end class << OpNode def between-XmlSerializer-Nodes-serialize( serializer ) # do OpNode stuff end end # and now, the main method def serialize( node ) node.between-XmlSerializer-Nodes-serialize( self ) end end This method has a few stengths: 0) easy to understand 1) you circumvent overloading/multi-methods (NOTE: you can define -between- methods as high-up in the target class heirarchy as you like, for example on the generic Node class) 2) requires no changs to ruby 3) captures the 'cross-cutting' nature of the AspectOriented ideas (modularizes the concern) 4) namespaces the methods in the target classes to prevent collisions Is this the extent of the usefullness of overloading/multi-methods or do we need more? Also, is this too weird? We are changing other classes' definition's without their consent, but it does seem Ruby-ish to me... -Rob -- Thus far we seem to be worse off than before - for we can enormously extend the record; yet even in its present bulk we can hardly consult it. --Vannevar Bush, 1945