Christoph Rippel <crippel / primenet.com> wrote: >"Josh Stern" <jstern / foshay.citilink.com> wrote in message >> As something of an exercise, I mentioned a possible strategy type >overloading >> in Ruby in some earlier messages: >> >> http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/8324 >> http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/8334 >Josh would you mind to give me to 1or 2 ``rubyish'' examples on >how the Koenig lookup would work? Koenig lookup is the system that C++ uses to resolve unqualified function names, possibly as a function of the namespaces where the arguments were declared. When I wrote that, I was thinking about Koenig lookup specifically, but also the general mechanism in C++ for resolving overloaded function calls according to arguments. The Koening part was related to some notion about freezing context, using mechanisms like alias in Ruby. That goes against the grain of the dynamic nature of Ruby; but the point of syntax errors in a compiled language is to catch bugs at compile time, so it seemed to me that it would be nice to catch all possible syntax bugs in Ruby at method definition time. But that is sort of secondary to the basic idea of wanting some type checking. So, let me reinterpret the question now as "How does overloading functions by type work in C++?" and "How might it possibly work in Ruby?" The C++ algorithm for overload resolution of obj.funcName(arg1,arg2) goes roughly something like this (using a function of arity 2 to make the example): a) make a like of all methods for obj and its superclasses named 'funcName' with arity 2. b) whittle down the list to include only those methods where the type of the first argument is the type of arg1 or a superclass of arg1 and the type of the second argument is the type of arg2 or a superclass of arg2. If we now have the empty list, then fail to compile. c) if more than one method remains in the list, see if there is one that dominates the others in the sense that its first argument is at least as 'derived' as the first argument of all the others and its second argumet is at least as 'derived' as all the others (a subclass is more derived than its superclass, or other ancestors). If there is no single dominant method, then fail to compile. Otherwise, the remaining method is the unique choice. There's a lot of other detail, most of which, I think, is not relevant here (though allowing arguments to have modes - e.g. const - is a worthwhile topic in its own right). In order to make sense of such a definition in the Ruby context, it's necessary to extend the partial order 'derived' to consider methods defined in modules. However, Ruby has such an order that it uses for resolving name clashes, so I think the same ordering is appropriate here as well (a module's names take priority over the names of a class that includes the module). And 'fail to compile' translates as raise an exception. Hopefully, the describes a coherent rule. But there is the question of implementation. Ideally I would like to describe an implementation algorithm in Ruby itself, starting with something along the lines of class TypedMethodMaker def defineMethod(*args) if (args.length < 3) raise 'Usage: defineMethod(className,methName,argClass1,argClass2,...argClassN) \ { | argName1, argName2,...,argNameN| ... }' else newProc = args.[args.length-1] if (newProc.kind_of?(Proc)) numArg = newProc.arity ... and so forth for an auxilliary method definition routine. the routine would check that there were no ordinary Ruby methods with the name 'methName' that existed for className or any super class or included module className - except special wrapper methods (see below). Then it would store information in a bunch of nested maps that would later let one map an n-tuple of objects to a proc using the algorithm above, or some variant of it, and call the unique proc or else raise an exception. The implementation would also automatically build a special wrapper in the form of a regular Ruby method methName (or perhaps methName with a special suffix symbox appended like '|') of className; thw wrapper would check arity and do the special overload resolution lookup. Some things that I don't know how to do within Ruby itself are the following: 1) look inside a proc object and make sure it is coherently defined for the types in question 2) maintain the condition about no confliciting ordinary Ruby methods as a dynamic invariant (this would involve complicated hooks and method definitions and module inclusions). 3) get the long number that represents the dynamic type id of an object or the same for a class - this would just be for efficiency instead of using long string representations of the class But all of those things could be done efficiently in the Ruby interpreter. -= Josh