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