Not grasping the method overloading/multi-dispatch thing

LOL. Yep. The info needed is implicit in the method. The “TypeMaps” could be
built by parsing the method to see what methods were invoked on the args. I
wonder if something like this is the “implicit typing” I read that some
compilers do.

···

On Thursday 12 September 2002 06:36 pm, Tom Sawyer wrote:

On Thu, 2002-09-12 at 17:09, Albert Wagner wrote:

That is true. Yet, there is an implied contract where arg1 and arg2 must
respond to #to_s. As a mind game, assuming that argument typing were
really desirable, and forgetting for a moment the objections, what would
be a cool way to specify the behaviour expected from argument objects?
(Not using initializing code like #responds_to, etc.) Smalltalkers
tended to adopt the convention of prefixing a class name with a- or an-
(aString, anInteger); but Smalltalk was single inheritance, without
mixins.

that’s an interesting question. so rather then meth(Integer i) meaning i
is kind_of Integer, rather it should mean responds_to all the same
methods as Integer?

but how do you take only a intersection of it? perhaps not perfect but
set theory might be useful, though perhap a bit odd. (borrowing from
array):

def meth(Integer & Array i)

meaning i is something that responds to the methods common to Integer
and Array. odd isn’t it? of course other set operators could be used.
and you could define “TypeMaps”, essentially empoty classes with dummy
methods just for this purpose.

my only problem with the whole type vs. calss argument, is what if two
objects have two differnt method with the same name that return
completly different types or classes of object? so return values need to
be taken into consideration too. in fact that’s really wahts important
–not that the methods have the same name, but that they produce the
same type or class (which? both?) of thing.

this is getting messy.

You could, of course, subclass the class that owns fred and then
implement your match; if nothing matches, then you call the base
parent. Or, perhaps, you use the aliasing feature.

-austin
– Austin Ziegler, austin@halostatue.ca on 2002.09.12 at 21.07.41

···

On Fri, 13 Sep 2002 07:22:35 +0900, Paul Brannan wrote:

On Fri, Sep 13, 2002 at 05:41:20AM +0900, Rich Kilmer wrote:

def fred(*args)
case args.collect { |a| a.type}
when [Float, Fixnum, String]
f, i, s = args
# …

With this mechanism, how can I add a new signature to the list?
What if I want to extend fred() to work with GMP Integers?

paul@NoSpAmPlEaSe.argelfraster.org (Paul J. Sanchez) wrote in message news:86hegvym6h.fsf@daemon.argelfraster.org

What happens when two programmers, working on different pieces of a
large project, add different methods with the same name to a base
class?

they look at the cvs logs, contact each other, and figure out a
solution?

Alternatively, in the more likely situation, what if one programmer
makes a method overly restrictive, forcing the other person to do type
conversions where a guarding .to_type would have sufficed?

~ Patrick

Paul Brannan pbrannan@atdesk.com wrote in message news:20020912181534.W25425@atdesk.com

In Ruby it’s not really considered a downside… it seems to be an
acceptable practice.

But should it be? If I write a class, and someone modifies it, he had
better have a darn good reason for modifying it. If everyone goes
around messing with the Integer and Float classes, how can we make any
guarantees about the behavior of Integers and Floats?

Most changes to behavior are additions, not subtractions. I consider
all of the below to be useful, but perhaps not common enough to be
part of the standard distribution:

asserts

anArray.assert_includes( anotherArray )
integer.assert_valid_character

formating

aString.to_headline
aString.to_title_widget

comparisons

aString.diff( anotherString )

This is in addition to the sorts of methods on finds in java under
StringUtils.

~ Patrick

···

On Fri, Sep 13, 2002 at 05:40:53AM +0900, Phil Tomson wrote:

Paul, in the former thread Robert Feldt showed another
implementation in [ruby-talk:26792] that lets you do what you
asked for. I came up with the following implementation based on
Robert’s code. Don’t know why I didn’t post it to the list then.
Maybe because it still lacks some necessary features.

Regards,
Pit

class Module

@@dispatch_db = Hash.new

def overload( meth, *classes, &code )
( @@dispatch_db[ [ self, meth ] ] ||= {} )[ classes ] = code
unless instance_methods.include?( meth )
class_eval <<-EOS
def #{meth}( *args )
Module.dispatch( #{self}, :#{meth}, *args )
end
EOS
end
end

def dispatch( cls, meth, *args )
@@dispatch_db[ [ cls, meth ] ].each do | classes, code |
catch( :nomatch ) do
classes.size.times do | i |
begin next if classes[ i ] === args[ i ]; rescue; end
throw( :nomatch )
end
return code[ *args ]
end
end
raise “dispatch error”
end

end

Test:

class C
overload :m, String, Integer do | s, i |
puts “m String, Integer called with #{s} and #{i}”
end
end

c = C.new
c.m( “Test”, 15 ) # → String, Integer
begin c.m( 2, “Test” ) rescue puts $! end # → dispatch error

class C
overload :m, Integer, String do | i, s |
puts “m Integer, String called with #{i} and #{s}”
end
end

c.m( 2, “Test” ) # → Integer, String

class C
overload :m, 0…9, String do | i, s |
puts “m Digit, String called with #{i} and #{s}”
end
end

c.m( 2, “Test” ) # → Digit, String
c.m( 20, “Test” ) # → Integer, String

···

On 13 Sep 2002, at 7:22, Paul Brannan wrote:

On Fri, Sep 13, 2002 at 05:41:20AM +0900, Rich Kilmer wrote:

def fred(*args)
case args.collect { |a| a.type}
when [Float, Fixnum, String]
f, i, s = args
# …

With this mechanism, how can I add a new signature to the list? What
if I want to extend fred() to work with GMP Integers?

The goal wasn’t to add type checking; it was to add dispatching based on
argument type.

Paul

···

On Fri, Sep 13, 2002 at 02:02:20PM +0900, Patrick May wrote:

Well, that’s the situation we’re in now – you can write methods that
check the types of their arguments, but it is difficult. Making it
easy, then making it difficult doesn’t make sense to me.

Other folks have already answered the general version of this question much more
authoritatively and eloquently than I can.Somewhere later on in this thread,
Patrick May says “Conditionals on type are a smell of code that could
be moved from the users of a class to the class itself.” I agree, and
you’ve already hinted at part of a solution: add a method to Signal that
does the proc{function.to_s}.call. Add a similarly named method to Proc
(or a subclass of Proc and then require the argument to be an object of
the subclass).

That doesn’t help for Fixnum or nil arguments, though. Here I gotta tell
ya, this makes me think it’s time for some refactoring. Since “function”
can be any of 4 wildly different things, I wonder if assign_at is doing
the work of more than one method. Just thinking out loud, you
understand.

Lastly, I admit I’m not smart enough to have thought of Phillip’s
approach. But you know, that hash looks like it’s sending methods based
on an object’s type, and Ruby will do that for us anyway if we ask it.

···

On Fri, 13 Sep 2002 13:43:05 -0400, Philipp Meier wrote:

On Fri, Sep 13, 2002 at 04:42:52PM +0900, Phil Tomson wrote:

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

What about the following?

class Signal

@function_handlers = { nil => NilHandler.new,
Proc => ProcHandler.new,
Signal => SignalHandler.new,
Object => DefaultHandler.new
}

def assign_at(rel_Time=0, function=nil)
nextValue = @function_handlers[function.type].invoke(function) …
end
end

class SignalHandler(function)
proc{function.to_s}.call
end

class DefaultHandler(function)
function
end

-billy.

In article 3b3ad3b4.0209132239.2ceb8d91@posting.google.com,

I just got a better idea for RHDL:
class Signal
def call
proc{self.to_s}.call
end
#…
def assign_at (relTime=0,nextValue=Proc.new)
nextValue = nextValue.call if nextValue.respond_to? :call

@eventQueue[relTime] = nextValue
nextValInQueue = @eventQueue.shift
@next_value = nextValInQueue if nextValInQueue

end

def assign(nextValue=Proc.new)
assign_at(0,nextValue)
end
#…
end

2 changes:

  • made the common function call, so you don’t have to change Proc
  • made function.call a guard, so that you don’t have to change Object

This is kind of cheating, since I’m checking some type.

Well, you’re only checking if nextValue responds to call which is a lot
better than the case statement that was there before…

But this is
why I like Ruby giving a way to do so, even if I don’t prefer it :slight_smile:

Thanks for looking at this, I’ll give it a try.

Phil

···

Patrick May patrick-may@monmouth.com wrote:

In article 3b3ad3b4.0209132239.2ceb8d91@posting.google.com,

···

Patrick May patrick-may@monmouth.com wrote:

I just got a better idea for RHDL:
class Signal
def call
proc{self.to_s}.call
end
#…
def assign_at (relTime=0,nextValue=Proc.new)
nextValue = nextValue.call if nextValue.respond_to? :call

@eventQueue[relTime] = nextValue
nextValInQueue = @eventQueue.shift
@next_value = nextValInQueue if nextValInQueue

end

def assign(nextValue=Proc.new)
assign_at(0,nextValue)
end
#…
end

Patrick,

I tried out your code suggestion in RHDL and it seems to work fine (the
unit tests still pass ;-). I like it.

Thanks.

Phil

–snip–

Usually I don’t go for “me too!”, or “brilliant!” -kind of comments, but I
think this definitely merits the latter.

This I definitely the most rubyish version of overloading methods I have
yet seen.

On a related note, for me the two most promising things to show up in
ruby-talk this week are this and the idea of using _ as a prefix identifier
for block-local variables and arguments.

Both are elegant and have a distinctive ruby-like flavor in my mouth.

– Nikodemus

···

On Fri, 13 Sep 2002, Pit Capitain wrote:

Paul, in the former thread Robert Feldt showed another
implementation in [ruby-talk:26792] that lets you do what you
asked for. I came up with the following implementation based on

asserts

anArray.assert_includes( anotherArray )

Why should this be in the Array class? What’s wrong with:

Assert.assert_includes(anArray, anotherArray)

(same goes for most of the other examples; they really don’t belong in
the classes you’ve placed them).

formating

aString.to_title_widget

Is this widget a Fox widget or a QT widget? What happens if two
programmers both write a to_title_widget method, one that creates a QT
widget and another that creates a Fox widget? One programmer’s code is
likely to break.

Paul

···

On Fri, Sep 13, 2002 at 01:22:16PM +0900, Patrick May wrote:

Definitely looks cool!

Some issues (and “necessary features” that are lacking):

  1. Passing a block to overload() means that you don’t have access to
    instance variables (self isn’t set properly when the block is
    called).

    Maybe it would be nifty if Ruby gave the user an interface to
    change a Proc’s “self”.

  2. I don’t like passing a string to class_eval. I think this could be
    implemented with define_method.

  3. Ideally I should be able to pass a block to the method.

  4. The dispatch method is O(n). I wish I had a good solution to this
    problem; iterating over all the ancestors of all the arguments is
    likely to be slower (a giant table of all possible signatures could
    be kept, if we had a callback for knowing when a class gets a new
    subclass).

Paul

···

On Fri, Sep 13, 2002 at 05:51:48PM +0900, Pit Capitain wrote:

Paul, in the former thread Robert Feldt showed another
implementation in [ruby-talk:26792] that lets you do what you
asked for. I came up with the following implementation based on
Robert’s code. Don’t know why I didn’t post it to the list then.
Maybe because it still lacks some necessary features.

In article pan.2002.09.13.18.54.31.523405.2402@nc.rr.com,

Other folks have already answered the general version of this question much more
authoritatively and eloquently than I can.Somewhere later on in this thread,
Patrick May says “Conditionals on type are a smell of code that could
be moved from the users of a class to the class itself.” I agree, and
you’ve already hinted at part of a solution: add a method to Signal that
does the proc{function.to_s}.call. Add a similarly named method to Proc
(or a subclass of Proc and then require the argument to be an object of
the subclass).

That doesn’t help for Fixnum or nil arguments, though. Here I gotta tell
ya, this makes me think it’s time for some refactoring. Since “function”
can be any of 4 wildly different things, I wonder if assign_at is doing
the work of more than one method. Just thinking out loud, you
understand.

Oh, I definately understand what you’re saying and under a different set
of constraints I would do just that (refactor). It’s just that the goal
here is to basically make Ruby look like another programming language
(technically an HDL [Hardware Description Language]). I don’t want users
to have to remember that there are several different assign methods
for Signals, like: assign_signal, assign_Fixnum, assign_function or
assign_proc. These are details they really don’t care to know. So I’m
trying to help out the users in this case who will be coming from an
HDL like VHDL or Verilog (and these are generally hardware engineers) so
RHDL doesn’t seem too foreign to them.

I think it was Joel V. who said in a recent post that Ruby’s procs are
great for creating little languages that are appropriate for certain
domains - that’s pretty much what I’ve done with RHDL.

Lastly, I admit I’m not smart enough to have thought of Phillip’s
approach. But you know, that hash looks like it’s sending methods based
on an object’s type, and Ruby will do that for us anyway if we ask it.

I need to look deeper at his approach, but my first impression was that
it wasn’t what I’m looking for.

Phil

···

Tim Hunter cyclists@nc.rr.com wrote:

Thanks for the credit Pit; your solution is nice. I’m still not sure
whether more complex dispatch would really add something to Ruby or not.
I think David’s “philosophical” concers are what matters the most; to me
the technical issues can be solved if matz and/or the community want.

If someone want to get serious about the technical side of this be sure
not to miss the papers/links:

Efficient Dynamic Multimethod Dispatch
http://www.ai.mit.edu/projects/dynlangs/Talks/multimethod-dispatch.htm

Predicate Dispatching: A Unified Theory of Dispatch
http://www.cs.washington.edu/research/projects/cecil/www/pubs/gud.html

Efficient Multiple and Predicate Dispatching
http://citeseer.nj.nec.com/chambers99efficient.html

and recent papers by the same authors; at least they were the state of the
art a year ago.

Well I’m off again,

Robert Feldt

···

On Fri, 13 Sep 2002, Nikodemus Siivola wrote:

On Fri, 13 Sep 2002, Pit Capitain wrote:

Paul, in the former thread Robert Feldt showed another
implementation in [ruby-talk:26792] that lets you do what you
asked for. I came up with the following implementation based on

Paul Brannan pbrannan@atdesk.com wrote in message news:20020913102550.C25425@atdesk.com

asserts

anArray.assert_includes( anotherArray )

Why should this be in the Array class? What’s wrong with:

Assert.assert_includes(anArray, anotherArray)

anArray.assert_includes( anotherArray ) was an array specific assert
that raised a helpful array-specific error message. It would say
something like ‘expected[3] => “foo” not found.’

The class-specific semantics combined with a chance to reduce the
number of args led us to use that method. We had a similar, but
different method for hashes.

(same goes for most of the other examples; they really don’t belong in
the classes you’ve placed them).

formating

aString.to_title_widget

Is this widget a Fox widget or a QT widget? What happens if two
programmers both write a to_title_widget method, one that creates a QT
widget and another that creates a Fox widget? One programmer’s code is
likely to break.

In a given application, you could safely make an assumption that the
widget matched the graphics library that the rest of the app used :slight_smile:

I give such examples b/c aString.to_title_widget will never be in a
standard api, but it’s very useful to be able to add it if needed.

~ Patrick

P.S. I think that object.diff( other ), returning a text description
of difference, could be a great pattern with Test::Unit. A problem
with large strings or arrays is hunting for the difference in the
failure message. Object.diff gives assert_equals a place to get a
class specific comparison message.

···

On Fri, Sep 13, 2002 at 01:22:16PM +0900, Patrick May wrote:

Hi –

···

On Sat, 14 Sep 2002, Phil Tomson wrote:

Oh, I definately understand what you’re saying and under a different set
of constraints I would do just that (refactor). It’s just that the goal
here is to basically make Ruby look like another programming language
(technically an HDL [Hardware Description Language]).

Will this supersede the other Ruby? :slight_smile:

David


David Alan Black | Register for RubyConf 2002!
home: dblack@candle.superlink.net | November 1-3
work: blackdav@shu.edu | Seattle, WA, USA
Web: http://pirate.shu.edu/~blackdav | http://www.rubyconf.com

In article Pine.LNX.4.44.0209140640310.2346-100000@candle.superlink.net,

···

dblack@candle.superlink.net wrote:

Hi –

On Sat, 14 Sep 2002, Phil Tomson wrote:

Oh, I definately understand what you’re saying and under a different set
of constraints I would do just that (refactor). It’s just that the goal
here is to basically make Ruby look like another programming language
(technically an HDL [Hardware Description Language]).

Will this supersede the other Ruby? :slight_smile:

The Ruby we all know and love or the other Ruby from the late '80s early
'90s that just happened to be an HDL?

No, RHDL couldn’t supercede the Ruby we all know and love since it’s built
on it :wink:

Phil

Hi –

In article Pine.LNX.4.44.0209140640310.2346-100000@candle.superlink.net,

Hi –

Oh, I definately understand what you’re saying and under a different set
of constraints I would do just that (refactor). It’s just that the goal
here is to basically make Ruby look like another programming language
(technically an HDL [Hardware Description Language]).

Will this supersede the other Ruby? :slight_smile:

The Ruby we all know and love or the other Ruby from the late '80s early
'90s that just happened to be an HDL?

Perish the (first of these) thought(s)! :slight_smile:

No, RHDL couldn’t supercede the Ruby we all know and love since it’s built
on it :wink:

Yeah, I was thinking of the HDL – amusing to have an HDL Ruby and a
Ruby HDL :slight_smile:

David

···

On Sun, 15 Sep 2002, Phil Tomson wrote:

dblack@candle.superlink.net wrote:

On Sat, 14 Sep 2002, Phil Tomson wrote:


David Alan Black | Register for RubyConf 2002!
home: dblack@candle.superlink.net | November 1-3
work: blackdav@shu.edu | Seattle, WA, USA
Web: http://pirate.shu.edu/~blackdav | http://www.rubyconf.com