Polymorphism


#1

As much as I like Ruby, I do miss the polymorphic behavior of routines
in Java and C++. There are frequently times in which it would be useful
to have constructors (or routines) that take different arguments. I do
see some constructors that may take arguments of different types, so I
know people are doing it, but I’m curious as to how.

The only way I can think of is to start the routine with a check such as
"var.class.name == " and have different logic within the
routine that is taking different argument types. Would some of you let
me know of your techniques? I’m anxious to learn.

—Michael


#2

Michael S. wrote:

As much as I like Ruby, I do miss the polymorphic behavior of routines
in Java and C++. There are frequently times in which it would be useful
to have constructors (or routines) that take different arguments. I do
see some constructors that may take arguments of different types, so I
know people are doing it, but I’m curious as to how.

That’s “overloading”, not “polymorphism”.

You do that in Ruby like this:

def zone(*args)
args.each do |arg|
case arg
when String
string_zone(arg)
when Fixnum
fixnum_zone(arg)
when MechaBattle
mecha_battle_zone(arg)
end
end
end

From here, learn what real polymorphism is! You prob’ly already use
it…


#3

Phlip wrote:

That’s “overloading”, not “polymorphism”.

Before this thread I thought I understood polymorphism. Suddenly
confused, I went off to Wikipedia and there are all sorts of arcane
stuff there. I’m impressed how many technical terms people can use.

Here’s what I think it means: You can declare procedures (and, by
extension, operators) that have identical names (eg ‘hire’, ‘sort’, ‘+’)
but behave differently depending on the nature of the object concerned.
This saves you generating unique names for each type of data. So
polymorphic means ‘behaving differently in different situations’.

If this is the case (forget all the different ways you might achieve
that), then Ruby must deliver mainstream polymorphism because it uses
classes. A class encapsulates procedures and therefore allows names to
be re-used. The appropriate behaviour is selected by the type of the
object concerned.

Again if this simplistic view is correct, your examples are not to do
with Ruby and polymorphism, they are to do with making classes contain
more than one type of object (and why would you feel entitled to do
that?)


#4

2009/4/23 Mike S. removed_email_address@domain.invalid:

Here’s what I think it means: You can declare procedures (and, by
extension, operators) that have identical names (eg ‘hire’, ‘sort’, ‘+’)
but behave differently depending on the nature of the object concerned.

More precisely: they must have identical /signatures/. This is
polymorphism.

If only the name is identical, it is /overloading/. Overloading can
occur in a single class or in a class hierarchy. Ruby does not have
built in mechanisms for overriding but it can be mimicked. Simple
example

def foo(x)
case x
when Fixnum
self + x
when String
“You sent: %p” % x
else
raise NameError, “No overriden version of foo(%p)” % x.class
end
end

Of course the story gets more complicated if you have different length
argument lists etc. I tend to rather use different method names if
there is indeed different behavior. If all arguments can be coerced
into uniform types and the method just needs those types then of
course you can live with one method, e.g.

def bar(n)
n = case n
when String: n
when Float: “%4.1f” % n
when Fixnum: “%4d” % n
else n.to_s
end
n.scan /\d+/
end

Then there is also /overriding/: a class which provides a method
implementation of a super class method with identical signature is
said to /override/ that method. Note that overriding and polymorphism
can come together but they do not need to! (see again C++)

This saves you generating unique names for each type of data. So
polymorphic means ‘behaving differently in different situations’.

Right.

If this is the case (forget all the different ways you might achieve
that), then Ruby must deliver mainstream polymorphism because it uses
classes.

The must have criterion for polymorphism is not classes but late
binding. You can see that nicely in C++ where you need to declare
methods “virtual” in order to get polymorphism.

A class encapsulates procedures and therefore allows names to
be re-used. The appropriate behaviour is selected by the type of the
object concerned.

Again if this simplistic view is correct, your examples are not to do
with Ruby and polymorphism, they are to do with making classes contain
more than one type of object (and why would you feel entitled to do
that?)

I am not sure which examples you are referring to.

Kind regards

robert


#5

2009/4/22 Mike S. removed_email_address@domain.invalid:

Here’s what I think it means: You can declare procedures (and, by

Again if this simplistic view is correct, your examples are not to do
with Ruby and polymorphism, they are to do with making classes contain
more than one type of object (and why would you feel entitled to do
that?)

Posted via http://www.ruby-forum.com/.

May be a time to look at the So-called GOf “Gang of Fours”'s Design
Templates.


John M.
07739 171 531
MSc (DIC)

Timezone: GMT


#6

Robert K. wrote:

def foo(x)
case x
when Fixnum
self + x
when String
“You sent: %p” % x
else
raise NameError, “No overriden version of foo(%p)” % x.class
end
end

I should mention that simple /overloading/ can be achived by delegating
the action to the ‘x’:

def foo(x)
case x
when Fixnum
self + x
when String
“You sent: %p” % x
else
x.foo # Note this line!
end
end

Ruby’s core library uses this technique in several places.


#7

On Thu, Apr 23, 2009 at 3:54 AM, Robert K.
removed_email_address@domain.invalid wrote:

More precisely: they must have identical /signatures/. This is polymorphism.

If only the name is identical, it is /overloading/. Overloading can
occur in a single class or in a class hierarchy.

Of course the story gets more complicated if you have different length
argument lists etc.

I’m not disagreeing with you Robert, but I need to point out that the
concept or equivalent of the ‘name’ of a method varies with the
language, to avoid confusion, let’s call the token which identifies a
group of polymorphic methods the method token.

In Ruby, the method token is quite simple, it’s a simple identifier.

def foo
end

the name of this method is foo.

In Smalltalk, or Objective-C, the token (called a method selector in
Smalltalk, or just a selector in Objective-C) is either as simple
identifier for a method with no parameters which Smalltalk calls unary
messages, or the concatenation one or more simple identifiers each
followed by a colon one for each parameter called keyword messages in
Smalltalk.

Smalltalk also has binary messages/selectors for things like
arithmetic and comparison methods, these selectors are s string of
characters from a restricted set, e.g. + or <=

MacRuby uses a hybrid of the Ruby and Objective-C selector, in
MacRuby, a call of the form

x.foo(1, :bar => 2, :baz => 3)
or using the Ruby 1.9 syntax
x.foo(1, bar: 2, baz: 3)

uses a selector of foo:bar:baz mapping the Ruby practice of using a
final hash parameter to provide ‘keyword arguments’ to Objective-C
style selectors (actually directly to Objective-C selectors). I’m not
sure what tricks MacRuby has up its sleeve for dealing with the fact
that in normal Ruby

x.foo(1, :bar => 2, :baz => 3)
and
x.foo(1, :baz => 3, :bar => 2)

invoke the same method, and have the same effect.

In a statically typed OO language like C++ or Java, the method token
also tied to the highest class in the hierarchy of a type which
introduces a name. If overloading/generics are supported by the
language then it may also be tied to the parameter types.

It’s these kind of subtleties which confound multi-language discussions.


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale


#8

Robert K. wrote:

The must have criterion for polymorphism is not classes but late
binding.

I think this is where we disagree. You seem to be saying polymorphism is
the ability for a piece of code to handle objects of differing types. I
don’t think that is necessary. It’s perfectly alright for each
object-type to have it’s own code to handle a method. The only thing
that needs to be shared is the name, not its implementation. This works
just fine in early-binding contexts.


#9

2009/4/24 Mike S. removed_email_address@domain.invalid:

Robert K. wrote:

The must have criterion for polymorphism is not classes but late
binding.

I think this is where we disagree. You seem to be saying polymorphism is
the ability for a piece of code to handle objects of differing types.

No, that’s not what I said.

I don’t think that is necessary. It’s perfectly alright for each
object-type to have it’s own code to handle a method.

Of course. But this code must be executed.

The only thing
that needs to be shared is the name, not its implementation.

Correct. And depending on the language, the signature of two methods
must be identical to be able to invoke them polymorphic.

This works just fine in early-binding contexts.

Actually no. My C++ is a bit rusty these days but if you do not
declare a method as “virtual” and have a pointer of the base class
type which points to a sub class instance the method invoked is
actually the base class’s method. This can only be remediated by late
binding (declaring as “virtual”) because only then the type of the
object at hand decides about the method invoked.

With the attached program you get:

09:32:19 Temp$ g++ t.cpp
09:32:36 Temp$ ./a.exe
Base:a
Base:b
Base:a
A:b
Base:a
B:b
09:32:43 Temp$

Here, only b() is invoked polymorphic.

Kind regards

robert


#10

2009/4/24 Mike S. removed_email_address@domain.invalid:

2009/4/24 Mike S. removed_email_address@domain.invalid:

I’ve just noticed my email address gets inserted in responses to my
posts. No wonder I get spam. Is this a known fault?

As soon as you post to public forums your email address is in public.
It does not matter whether it is inserted into replies by others.
That’s why I use a GMail account for public communication…

And please do not hijack the thread for a complete different topic.

Cheers

robert


#11

Robert K. wrote:

And please do not hijack the thread for a complete different topic.

Cheers

robert

You could make that remark for virtually any topic except…
polymorphism


#12

On Fri, Apr 24, 2009 at 2:56 PM, Mike S. removed_email_address@domain.invalid
wrote:

Robert K. wrote:

And please do not hijack the thread for a complete different topic.
Brilliant idea, but it must be completely OT!!!
Robert


#13

On Apr 24, 2009, at 12:35 AM, Robert K. wrote:

Actually no. My C++ is a bit rusty these days but if you do not
declare a method as “virtual” and have a pointer of the base class
type which points to a sub class instance the method invoked is
actually the base class’s method. This can only be remediated by late
binding (declaring as “virtual”) because only then the type of the
object at hand decides about the method invoked.

One of the key benefits of polymorphism in the context of statically-
typed languages is that you can pass around objects of a base type
into functions. When one of the virtual (i.e., polymorphic) functions
is invoked, the implementation appropriate to the object actually
passed into the callee is invoked. In the context of a dynamically-
typed language where method dispatch happens at runtime, this kind of
polymorphism may not be as relevant.

The argument in favor of static typing has been had many times on this
list, so I will only rehash it briefly: If you give a compiler some
guidelines in a statically typed language, it can perform a boatload
of optimizations based on things it can infer from size and behavior
of data and it can do some measure of static type checking to increase
the chances that the object you are operating on will support the
method you intend to invoke with the given parameters.

The flip side is that you often find yourself doing “trust me”
explicit type coercion and writing an extraordinary amount of code
just to state an intent. That is an intent that can with a reasonable
amount of care, testing, and clever language design be inferred. I
know that is a bold statement and one that might be a bit contentious
right now because of Twitter’s assertion that moving to static typing
saved them a ton of bugs. Static typing can slow velocity, increase
the density of code, and decrease the readability because of all the
required decorators.

Caveat: Just the opinion of an old grumpy ex-C++ programmer.


#14

2009/4/24 Mike S. removed_email_address@domain.invalid:

I’ve just noticed my email address gets inserted in responses to my
posts. No wonder I get spam. Is this a known fault?