Not grasping the method overloading/multi-dispatch thing

Dale Martenson dmartenson@multitech.com wrote in message news:<20C86D2620F6D411A199009005DC0102016D1830@exchange serve.multitech.prv>…

I see this as a big advantage to the language.

  1. Overloading doesn’t break a great language. It just enhances it. Ruby
    would still retain everything that makes it neat.

You can already write ruby code to do everything proposed. The issue
is whether such proposals deserve some sugar. That is, none of these
proposals enhance the scope of what is possible, only what is
encouraged.

  1. It allows for “cleaner” solutions where overloading is the “best” option.
    It could be argued that overloading is needed to satisfy POLS. If Ruby is
    truly the best OO language, how can it not have overloading!! :slight_smile:

Overloaded methods are the same as a conditional on type. To me, this
is never the best option, not when you can put methods on the class to
convert it to the form you need.

I’d be curious to see code that

a. calls for overloading on type
b. couldn’t be handled by pushing code up to the classes of the
argument objects

  1. If Ruby is ever to be JIT-compiled, knowing a parameters type has
    advantages for performance since code can be optimized.
  • meat performance is always more important than metal performance.
  • metal performance is fine, and might get better with parrot / mono
    bytecode.

I feel myself getting religous, so I should hush up.

Hope I wasn’t offensive,

~ Patrick

Because of Rubys dynamic nature this is IMHO always possible. But is it
good design? You will agree, that, as an example, code that formats a
business object for reporting certainly does not belong into the business
object class but in a reporting class. A solution I proposed before is
extracting this kind of methods into a seperate classes which go along
the classes you propose the methods belong into. The polymorphic
dispatching logic then dispatch by type (untested):

class PolyTest
@@receivers = { :to_html => { String => StringAdapter,
Integer => IntegerToHTML },
:to_rtf => { String => StringAdapter,
Integer => IntegerToRTF }
}

def dispatch(method, index, *args)
	r = @@receivers[method][args[index].type]
	r.send(method, self, *args)
end

def to_html(doc, object)
	dispatch(:to_html, 1, doc, object)
end

def to_rtf(doc, object)
	dispatch(:to_rtf, 1, doc, object)
end

def test
	to_html("", "Test") # => calls StringAdapter.to_html("", "Test")
	to_rtf ("", "Test") # => calls StringAdapter.to_rtf("", "Test")
	to_html("", 1)      # => calls IntegerToHTML.to_html("", 1)
	to_rtf ("", 1)      # => calls IntegerToRTF.to_rtf("", 1)
end

end

class StringAdapter
def to_html(doc, string)
doc << "String: #{string}
"
end
def to_rtf(doc, string)

end
end

class IntegerToHTML
def to_html(doc, i)
doc << "Integer: #{i}
"
end
end

class IntegerToRTF
def to_rtf(doc, i)

end
end

-billy.

···

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

Dale Martenson dmartenson@multitech.com wrote in message news:<20C86D2620F6D411A199009005DC0102016D1830@exchange serve.multitech.prv>…

  1. It allows for “cleaner” solutions where overloading is the “best” option.
    It could be argued that overloading is needed to satisfy POLS. If Ruby is
    truly the best OO language, how can it not have overloading!! :slight_smile:

Overloaded methods are the same as a conditional on type. To me, this
is never the best option, not when you can put methods on the class to
convert it to the form you need.

I’d be curious to see code that

a. calls for overloading on type
b. couldn’t be handled by pushing code up to the classes of the
argument objects


Meisterbohne Söflinger Straße 100 Tel: +49-731-399 499-0
eLösungen 89077 Ulm Fax: +49-731-399 499-9

Philipp Meier meier@meisterbohne.de wrote in message news:20020913101910.GC17997@o-matic.net

I’d be curious to see code that

a. calls for overloading on type
b. couldn’t be handled by pushing code up to the classes of the
argument objects

Because of Rubys dynamic nature this is IMHO always possible. But is it
good design? You will agree, that, as an example, code that formats a
business object for reporting certainly does not belong into the business
object class but in a reporting class.

Code should execute in the namespace close to its data. That said,
Ruby lets you use modules to clearly separate the code within a given
namespace. See below.

A solution I proposed before is
extracting this kind of methods into a seperate classes which go along
the classes you propose the methods belong into. The polymorphic
dispatching logic then dispatch by type (untested):

class PolyTest
@@receivers = { :to html => { String => StringAdapter,
Integer => IntegerToHTML },
:to rtf => { String => StringAdapter,
Integer => IntegerToRTF }
}

def dispatch(method, index, *args)
r = @@receivers[method][args[index].type]
r.send(method, self, *args)
end

def to html(doc, object)
dispatch(:to html, 1, doc, object)
end

def to rtf(doc, object)
dispatch(:to rtf, 1, doc, object)
end

def test
to html("", “Test”) # => calls StringAdapter.to html("", “Test”)
to rtf ("", “Test”) # => calls StringAdapter.to rtf("", “Test”)
to html("", 1) # => calls IntegerToHTML.to html("", 1)
to rtf ("", 1) # => calls IntegerToRTF.to rtf("", 1)
end
end

class StringAdapter
def to html(doc, string)
doc << "String: #{string}
"
end
def to rtf(doc, string)

end
end

class IntegerToHTML
def to html(doc, i)
doc << "Integer: #{i}
"
end
end

class IntegerToRTF
def to rtf(doc, i)

end
end

or, using modules:

class PolyTest
def test
"Test".to_html # =~ StringAdapter.to html("", “Test”)
“Test”.to_rfc # =~ StringAdapter.to rtf("", “Test”)
1.to_html # =~ IntegerToHTML.to html("", 1)
1.to_rtf # =~ IntegerToRTF.to rtf("", 1)
end
end

module FormatingMethods
def to html
"<#{ self.tag }>#{ self.class.to_s }:" +
"</#{self.tag}> #{self.to_s}
"
end
def to rtf

end
end

class String
include FormatingMethods
def tag
"b"
end
end

class Integer
include FormatingMethods
def tag
"i"
end
end

Which is the preferable design? Note the differences from the
perspective of a user of the api (PolyTest.test):

No mediating functions. No arguments to forget when calling
:to_html/:to_rtf. No binding between the output stream and
:to_html/:to_rtf, though I realize your example could be changed to
avoid that binding.

The implementation is also short (~10 fewer LOC) and simple – not a
single conditional to implement this behavior!

Once you’ve decided to create an object, you shouldn’t need anymore
conditionals on that type. It’s nice to have such conditionals, and I
use them in my code, but they are refactoring targets to me.

~ Patrick

···

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

Coming from a java background if do not feal comfortable with Mixins,
yet. Altough I must admist this a clever use of them. Nevertheless I fear
a clash of method names if more than a few mixins are used on business
methods. Imaginge you want to extend to example by a to_xml method.
Accidently you name the tag method “tag” like the one for HTML. (Assume
the XML aspect is defined in another place than the HTML.) This could
lend to real confusion, IMHO. I know, I know there are Unit Tests that
should catch this but I stell consider it a slight smell. One would be
on the safe side, if one could tell to call the method defined in a
certain module:

module Foo
def qux
5
end
end

module Bar
def qux
7
end
end

class Baz
include Foo
include Bar
end

Baz.new.qux # => 7

How can I call Foo.qux on Baz??

-billy.

···

On Sat, Sep 14, 2002 at 08:03:10AM +0900, Patrick May wrote:

Philipp Meier meier@meisterbohne.de wrote in message news:20020913101910.GC17997@o-matic.net

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

Because of Rubys dynamic nature this is IMHO always possible. But is it
good design? You will agree, that, as an example, code that formats a
business object for reporting certainly does not belong into the business
object class but in a reporting class.

Code should execute in the namespace close to its data. That said,
Ruby lets you use modules to clearly separate the code within a given
namespace. See below.

or, using modules:

Which is the preferable design? Note the differences from the
perspective of a user of the api (PolyTest.test):

No mediating functions. No arguments to forget when calling
:to_html/:to_rtf. No binding between the output stream and
:to_html/:to_rtf, though I realize your example could be changed to
avoid that binding.

The implementation is also short (~10 fewer LOC) and simple – not a
single conditional to implement this behavior!

Once you’ve decided to create an object, you shouldn’t need anymore
conditionals on that type. It’s nice to have such conditionals, and I
use them in my code, but they are refactoring targets to me.


Meisterbohne Söflinger Straße 100 Tel: +49-731-399 499-0
eLösungen 89077 Ulm Fax: +49-731-399 499-9

Hi –

Coming from a java background if do not feal comfortable with Mixins,
yet. Altough I must admist this a clever use of them. Nevertheless I fear
a clash of method names if more than a few mixins are used on business
methods. Imaginge you want to extend to example by a to_xml method.
Accidently you name the tag method “tag” like the one for HTML. (Assume
the XML aspect is defined in another place than the HTML.) This could
lend to real confusion, IMHO. I know, I know there are Unit Tests that
should catch this but I stell consider it a slight smell. One would be
on the safe side, if one could tell to call the method defined in a
certain module:

module Foo
def qux
5
end
end

module Bar
def qux
7
end
end

class Baz
include Foo
include Bar
end

Baz.new.qux # => 7

How can I call Foo.qux on Baz??

My best shot, subject to wizardly overrule:

You’re right that you can’t do that, because the Baz object sees only
a straight line to its #qux method, not a choice. In general terms,
I’ve found that the best way to think of it is that including a module
is very similar to typing in the module’s code in the file that’s
doing the including. Not identical (because of scoping things, etc.),
but similar.

A consequence of this is that including two modules with clashing
method names can be regarded as a programming error of the same kind
and degree as accidentally writing two methods with the same name in a
single class/file. In other words, you’re responsible for knowing as
much about the modules you include as about the methods you wrote 100
lines back, because they’re all equally part of the object interface
you’re designing.

David

···

On Mon, 16 Sep 2002, Philipp Meier 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

We prevent this at our corporation by having a top level
module for our company and, the larger projects have
their own namespace as well.

See the (what may be bad) example below:

···

On Mon, Sep 16, 2002 at 11:11:14PM +0900, Philipp Meier wrote:

On Sat, Sep 14, 2002 at 08:03:10AM +0900, Patrick May wrote:

Philipp Meier meier@meisterbohne.de wrote in message news:20020913101910.GC17997@o-matic.net

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

Coming from a java background if do not feal comfortable with Mixins,
yet. Altough I must admist this a clever use of them. Nevertheless I fear
a clash of method names if more than a few mixins are used on business
methods. Imaginge you want to extend to example by a to_xml method.
Accidently you name the tag method “tag” like the one for HTML. (Assume
the XML aspect is defined in another place than the HTML.) This could
lend to real confusion, IMHO. I know, I know there are Unit Tests that
should catch this but I stell consider it a slight smell. One would be
on the safe side, if one could tell to call the method defined in a
certain module:


module Cypress

module BigProject

module Math
def sin(x)
end#sin
end#module Math

end#module BigProject

end#module Cypress

So, there is no confusion between
Math::sin(x)

and

Cypress::BigProject::Math:sin(x)
or
include Cypress::BigProject::Math
sin(x)


Jim Freeze

Programming Ruby
def initialize; fun; end
A language with class

Philipp Meier meier@meisterbohne.de wrote in message news:20020916141154.GE17997@o-matic.net

Coming from a java background if do not feal comfortable with Mixins,
yet. Altough I must admist this a clever use of them. Nevertheless I fear
a clash of method names if more than a few mixins are used on business
methods. Imaginge you want to extend to example by a to xml method.
Accidently you name the tag method “tag” like the one for HTML. (Assume
the XML aspect is defined in another place than the HTML.) This could
lend to real confusion, IMHO. I know, I know there are Unit Tests that
should catch this but I stell consider it a slight smell.

Pushing methods into the same namespace by default definately leads
you towards having name conflicts. A friend of mine said “the problem
with globally unique identifiers is there just isn’t enough of them”
:slight_smile:

Jokes aside, the point of this techinique is to reduce complexity
first. The kinds of bugs you get from complexity are real pains, and
finding existing bugs is a pain as well.

I’ve run into namespace conflicts like what you described before, but
always ahead of actually coding the methods. What has happened is
that I’ve gotten frustrated when trying to think of a name for a new
method. When that happens, I try to look for ways of splitting up the
data / methods into smaller objects. In the thread’s example, you
could retain the StringOutput and IntegerOutput objects, and overload
String and Integer with:

class StringOutout
    def to_html
        ....
    end
end

class String
    def get_format
        StringOutput.new( self )
    end
end

class IntegerOutout
    def to_html
        ....
    end
end

class Integer
    def get_format
        IntegerOutput.new( self )
    end
end

The only thing I look for is less code, fewer arguments, and a smaller
overall application. I think that conditionals on classes are
redundant b/c the OO enviroment automatically performs conditionals
on classes for you, only looking in the right classes for the method.
Thus, I think you always get less code by letting the enviroment
handle those conditionals.

~ Patrick