Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

My first impression of Ruby. Lack of overloading? (long)

0 views
Skip to first unread message

Jean Michel

unread,
Dec 28, 2000, 3:24:31 PM12/28/00
to
Hello,
I am a newbye to ruby (I looked at the newsgroup and the web pages some
weeks ago, but did not try to program until I received Dave and Andy's
book last week), although I have a long experience with many other high
and low-level languages. I give here my first impressions before I
forget them, in the hope that they may interest someone and that I may
receive some useful advice (this list seems quite friendly).

First my global impression which survived translation of some of my
scripts is that ruby is a perfect replacement for perl and python (when
translating some scripts I had only some minor annoyances; on the
other hand I could achieve some substantial improvements due to the
higher-level nature of ruby). Some of the minor annoyances were:

- I had trouble using sort! in method-chaining because

irb(main):006:0> [1,2].sort!
[1, 2]
irb(main):007:0> [1].sort!
nil

the reason why sort! does not return its result for arrays of length
1 eludes me.

- In perl, if one wants to sort according to several criteria, one can
write something like that

sort { length($a) <=> length($b) or $a cmp $b }

this does not work in ruby since 'or' behaves completely different --
it can apparently be used only in a very restricted way in boolean
expressions. The closest I could come with is:

sort {|a,b| [a.length,a]<=>[b.length,b]}

but it does not have the same effect as the perl idiom not to
evaluate the second sort criterion when the first suffices.

- I was very surprised that each_pair is not defined for arrays, only
hashes. Of course you can roll your own:

class Array
def each_pair
each_index do |i| yield(i,self[i]) end
end
end

but why is such an essential idiom not pre-defined?

- I have some problems with scopes. In particular, that one can not
define local functions. The closest I could come with is to define a
local Proc object and use .call on it. Is that the recommended way?

The main reason I looked at ruby is that I had very high hopes for this
language: my job is mathematics and I thought ruby might be well suited
for that. Mathematical programming involves defining all the time new
mathematical objects and programming usual and not so usual operations
on them. As an exercise to test ruby for that purpose, I tried to
program fractions and multivariate polynomials. I found along the way
what I perceive as a defect in ruby (lack of overloading), but other
people including matz may have another view which would interest me.

To start with my example I started with:

class Frac
attr_accessor(:num, :den)
def initialize(n,d=1)
@num,@den=n,d
simpl!
end
def simpl!
g=@num.gcd(@den)
@num/=g
@den/=g
end
def to_s
res=@num.to_s
res+="/"+...@den.to_s unless @den==1
res
end
def +(other)
Frac.new(@num*other.den+@den*other.num,@den*other.den)
end
def -(other)
Frac.new(@num*other.den-@den*other.num,@den*other.den)
end
def *(other)
Frac.new(@num*other.num,@den*other.den)
end
def /(other)
Frac.new(@num*other.den,@den*other.num)
end
end

Remark that I do not derive Frac from Numeric, since I want it to work
for an arbitrary Euclidean base ring. Also I just assume that the base
ring has a method for gcd defined. If one wants to use fractions of
integers, one can write

class Integer
def gcd(b)
a=self
while b!=0
a,b=b,a.modulo(b)
end
a
end
end

Now the code above works fine as long as I work only with Fracs. Suppose
now that I want to define the addition of a Frac and an integer:

Frac.new(1,3)+2

In a language like C++, I would use overloading to add a new method for
operator + when the argument is not a Frac. But, and this is my
perceived deficiency, it seems that ruby has no such concept as
overloading. For the moment, a possible technique is to define a
conversion function:

def Frac(a)
if a.type==Frac
a
else
Frac.new(a,1)
end
end

[ by the way here is a minor gripe: I first wrote the above, envisioning the
possibility in the future of more cases, as:

case a.type
when Frac
a
else
Frac.new(a,1)
end

but this does not work, apparently because === is not defined for Class]

and use the conversion function to change my definitions to:

def +(other)
other=Frac(other)
Frac.new(@num*other.den+@den*other.num,@den*other.den)
end

But the call to Frac() is probably more overhead than kernel dispatching
by an overload mechanism. And, now, what about the other direction, i.e.:

2+Frac.new(1,3)

Here one is really at a loss without overloading: the only possible
thing to do is to redefine the method + for integers!
At that stage, I thought I would have to abandon ruby for my purposes.
However I noticed in the book the mention of a library 'Complex' and I
thought I would have a look. Well, miracle,

2+Complex(1,3)

works! This apparently uses a mechanism for which I could not find
non-Japanese documention, involving 'coerce'. If I mimic what I found in
'Complex', that is add:

def coerce(other)
[Frac.new(other), self]
end

now my example works. I would like a clear explanation of exactly what
is the mechanism here. It seems to me that the method + for integers has
a pre-defined hook to look for coerce for an unknown type. It is also
probably to provide a similar hook for future additions that in Complex
one has:

def + (other)
if other.kind_of?(Complex)
re = @real + other.real
im = @image + other.image
Complex(re, im)
elsif Complex.generic?(other)
Complex(@real + other, @image)
else
x , y = other.coerce(self)
x + y
end
end

but I feel:
-the above code is complicated, and clumsy, compared to overloading
-contrary to overloading, there is no possibility to extend an
already-existing method for an already-existing type if no hook has
been provided.

This last point bothers me: it is very nice that in ruby one can
dynamically add to a class, by reopening it. Overloading is a way to
'reopen' a method, and the possibility to reopen a class is not so
useful without it

Ok, now what did I miss, and what is the rationale for no overloading,
or the replacement for it that I missed?

P.S. Before people point it to me, I just noticed that in the library
there is a rational.rb with code similar to the one I outlined above,
excepted more complicated at places for reasons which elude me.

Jim Menard

unread,
Dec 28, 2000, 4:20:31 PM12/28/00
to
I'll try to answer the easy ones.

jmi...@schur.institut.math.jussieu.fr (Jean Michel) writes:

> the reason why sort! does not return its result for arrays of length
> 1 eludes me.

sort! returs nil if the message receiver (the array) is not changed, as do
many (but not all) of the "!" methods.

> - I was very surprised that each_pair is not defined for arrays, only
> hashes. Of course you can roll your own:

Try each_with_index instead.

[1, 2, 3].each_with_index { | value, index |
...
}

This method is defined in the Enumeration (or Enumerable) module.

> - I have some problems with scopes. In particular, that one can not
> define local functions. The closest I could come with is to define a
> local Proc object and use .call on it. Is that the recommended way?

That's certainly possible, but we tend to use blocks instead of anonymous
subroutines.

Jim
--
Jim Menard, ji...@io.com, http://www.io.com/~jimm/
"I invented the term Object-Oriented, and I can tell you I did not have C++
in mind." -- Alan Kay

Dan Schmidt

unread,
Dec 28, 2000, 4:00:26 PM12/28/00
to
I can only answer a few of your questions:

jmi...@schur.institut.math.jussieu.fr (Jean Michel) writes:

| - I had trouble using sort! in method-chaining because
|
| irb(main):006:0> [1,2].sort!
| [1, 2]
| irb(main):007:0> [1].sort!
| nil
|
| the reason why sort! does not return its result for arrays of length
| 1 eludes me.

sort! returns whether the array had to be sorted (which means true
for arrays of length >= 2, false otherwise). This was discussed
recently in comp.lang.ruby and it seemed that most people regard it
as a misfeature. I don't remember if there were any plans to change
it.

| - In perl, if one wants to sort according to several criteria, one can
| write something like that
|
| sort { length($a) <=> length($b) or $a cmp $b }
|
| this does not work in ruby since 'or' behaves completely different --
| it can apparently be used only in a very restricted way in boolean
| expressions. The closest I could come with is:
|
| sort {|a,b| [a.length,a]<=>[b.length,b]}
|
| but it does not have the same effect as the perl idiom not to
| evaluate the second sort criterion when the first suffices.

0 is true in Ruby, so you have to convert 0 to nil using the
nonzero? method of Numeric:

sort { (a.length <=> b.length).nonzero? || a <=> b }

| - I was very surprised that each_pair is not defined for arrays, only
| hashes. Of course you can roll your own:
|
| class Array
| def each_pair
| each_index do |i| yield(i,self[i]) end
| end
| end
|
| but why is such an essential idiom not pre-defined?

It's called each_with_index, found in Enumerable.

--
http://www.dfan.org

Clemens Hintze

unread,
Dec 28, 2000, 8:42:23 PM12/28/00
to

You wrote:
> Hello,

Hello too, :-)

(...)

> First my global impression which survived translation of some of my
> scripts is that ruby is a perfect replacement for perl and python
> (when translating some scripts I had only some minor annoyances; on
> the other hand I could achieve some substantial improvements due to
> the higher-level nature of ruby). Some of the minor annoyances were:
>
> - I had trouble using sort! in method-chaining because
>
> irb(main):006:0> [1,2].sort!
> [1, 2]
> irb(main):007:0> [1].sort!
> nil
>
> the reason why sort! does not return its result for arrays of length
> 1 eludes me.

sort! returns 'nil' if the list was not necessary to be sorted. A list
with only one element cannot be sorted sensefully, hence the
'nil'.

Perhaps that effect of sort! will be changed in future (if my
interpretation of past discussions is right).

> - In perl, if one wants to sort according to several criteria, one can
> write something like that
>
> sort { length($a) <=> length($b) or $a cmp $b }

In Ruby only 'nil' and 'false' are false. All other are true; so also
the value zero! But there is a method Numeric#nonzero? that returns
'nil' if the receiver was zero, otherwise it returns the receiver. You
can use it to write the code block of sort like:

{ (a.length <=> b.length).nonzero? || a <=> b }

(...)

> - I have some problems with scopes. In particular, that one can
> not define local functions. The closest I could come with is to
> define a local Proc object and use .call on it. Is that the
> recommended way?

The trick is here, that you are even not *able* to define a
function. *Neither* a global one *nor* a local one. You can only
define methods. Remember Ruby is fully OOL. Not a hybrid like Python
or C++.

A method, however, *ought* to belong to a certain class. If you
define a method on toplevel outside of every class definition, that
method belongs to class Object and will become a private instance
method of it. As such, it is visible on all places in your code as
every class/module inherits from class Object at last!

So it seems you define a function but in reality you was fooled by
Ruby there! ;-)

So the closest to come to a local function is indeed a local Proc
object. You could use the methods Proc#call or Proc#[] to call such an
instance. Proc instances will also often used as anonymous callback
'functions'. I am sure you will like them :-)

> The main reason I looked at ruby is that I had very high hopes for
> this language: my job is mathematics and I thought ruby might be
> well suited for that. Mathematical programming involves defining

I am not a mathematican, but I am sure it will fit your needs! But
please have also a look to the Ruby Application Archive (RAA)

http://www.ruby-lang.org/en/raa.html

to find some valuable modules, that may help you here for mathematical
tasks. Some among them:

- NArray
- BigFloat
- NumArray
- Polynomial

(...)

> overloading), but other people including matz may have another view
> which would interest me.

Erhm ... what? Lack of overloading? Impossible ... ah you mean
overloading by parameter type, yes? That is indeed not available in
Ruby (nor in Python or Smalltalk, BTW). The reason is that variables
are not typed in such languages. Therefore it is difficult (perhaps
impossible in some cases?) for the compiler to fiddle out on
compilation time what kind of method to be called later on!

You can think from method invocation as sending a method selector to a
certain object. Like that:

a = 3
b = 5
a.send(:+, b) # => 8

If dispatching would not be done via selector only but also by
argument type, the message lookup would slow down, IMO. First find the
*group* of messages that *could* apply, then look whether
argument-type-overloading applied or not. If not call the method; if
yes look for the one with the right argument signature!

And how to handle lookup in parents? Parent contain overloaded
methods, child only one method catching all possible types
... pfffhhh!

Or if you design a class with overloaded-on-arguments methods, how
would you prevent me to overload your methods again but this time
catching *all* possible types of arguments? Not possible? But if I
need to?

I really do not know, if a solution of all this is worth the trouble!
Not that I believe that there *is* a senseful undoubtable and backward
compatible solution that would not bite us another way around or
weaken Ruby's nice dynamic behavior ...

But there is the coerce mechanism ...

(...)

> Now the code above works fine as long as I work only with
> Fracs. Suppose now that I want to define the addition of a Frac and
> an integer:

(...)

> thought I would have a look. Well, miracle,
>
> 2+Complex(1,3)
>
> works! This apparently uses a mechanism for which I could not find
> non-Japanese documention, involving 'coerce'. If I mimic what I
> found in 'Complex', that is add:
>
> def coerce(other)
> [Frac.new(other), self]
> end

That was exactly what I meant with the 'coerce' mechanism.

> now my example works. I would like a clear explanation of exactly
> what is the mechanism here. It seems to me that the method + for
> integers has a pre-defined hook to look for coerce for an unknown
> type. It is also probably to provide a similar hook for future

I think you have understood the coerce mechanism very well! I would
really not know what else to describe to you.

> additions that in Complex one has:
>
> def + (other)
> if other.kind_of?(Complex)
> re = @real + other.real
> im = @image + other.image
> Complex(re, im)
> elsif Complex.generic?(other)
> Complex(@real + other, @image)
> else
> x , y = other.coerce(self)
> x + y
> end
> end
>
> but I feel:
> -the above code is complicated, and clumsy, compared to
> overloading

It depends. Above I have tried to show you the problems we would
struggle in if we add overloading-on-arguments to such a highly
dynamic language like Ruby. I dare to guess that there are cases where
a compiler would even not *able* to tell you what kind of object is
passed to a method right now during compilation time!

So perhaps it is still better to let the method analyze its arguments
if necessary instead of teaching the compiler to guess ...

> -contrary to overloading, there is no possibility to extend an
> already-existing method for an already-existing type if no hook
> has been provided.

Not totally true! You could alias the old method and create a new one
with same name like the old one but different behavior! Like that:

class FooNbr
attr :n
def initialize(n)
@n = n
end
def +(other)
self.n + other.n
end
end

# Not very clever the method FooNbr#+? FooNbr.new(12)+2 wouldn't
# work as 2+FooNbr.new(12) wouldn't work too. So let us change it!

class FooNbr
alias :oldplus :+
def +(other)
if other.type < FooNbr
self.oldplus other
else
x, y = self.coerce(other)


x + y
end
end

def coerce(other)
[self.n, other]
end
end

a = FooNbr.new(12)
b = FooNbr.new(2)
a + b
a + 5
7 + b

You see: although the original FooNbr#+ had no coerce, we have simply
introduced it by 'reopen' the class definition and remembering and
overwriting the original FooNbr#+ method with a new one.

> This last point bothers me: it is very nice that in ruby one can
> dynamically add to a class, by reopening it. Overloading is a way to
> 'reopen' a method, and the possibility to reopen a class is not so
> useful without it

It is not really necessary, IMHO, as I have tried to show you above.

> Ok, now what did I miss, and what is the rationale for no overloading,
> or the replacement for it that I missed?

Let me thank you for your critical questions and remarks. I hope,
though, that I was able to give you some pointer/hints why you
overloading scheme would be more trouble than blessing in my opinion
at least ...

(...)


Best regards,
\cle

Dave Thomas

unread,
Dec 28, 2000, 8:46:10 PM12/28/00
to
jmi...@schur.institut.math.jussieu.fr (Jean Michel) writes:

> write something like that
>
> sort { length($a) <=> length($b) or $a cmp $b }
>
> this does not work in ruby since 'or' behaves completely different --
> it can apparently be used only in a very restricted way in boolean
> expressions. The closest I could come with is:

try using nonzero? (if you've got the book, it's on 355)

> - I was very surprised that each_pair is not defined for arrays, only
> hashes. Of course you can roll your own:

It's called each_with_index (defined in Enumerable)


> Ok, now what did I miss, and what is the rationale for no overloading,
> or the replacement for it that I missed?

I'll leave that one for Matz: there's a section in his book all about
coerce: perhaps he might be able to cut and paste it here.


Dave

Jean Michel

unread,
Dec 29, 2000, 5:04:11 AM12/29/00
to
Hello,
I want to thank evrybody who answered my questions, all replies where
very friendly and helpful.

In article <wsqn1dg...@eris.io.com>, Jim Menard <ji...@eris.io.com> wrote:
>I'll try to answer the easy ones.
>
>jmi...@schur.institut.math.jussieu.fr (Jean Michel) writes:
>
>> the reason why sort! does not return its result for arrays of length
>> 1 eludes me.
>
>sort! returs nil if the message receiver (the array) is not changed, as do
>many (but not all) of the "!" methods.

Even so I am still surprised. How one is to know that in

[1].sort!

the receiver is not changed, but in

[1,2].sort!

it is? Not obvious to me...

>> - I was very surprised that each_pair is not defined for arrays, only
>> hashes. Of course you can roll your own:
>
>Try each_with_index instead.

> ...
>
>This method is defined in the Enumeration (or Enumerable) module.
>

I guess I never tried to look there because for me Enumerable was for
classes were just each exists, no ordering (e.g. is each supposed to
go over the same object in the same order each time?). And why is
the name not each_pair?

>> - I have some problems with scopes. In particular, that one can not
>> define local functions. The closest I could come with is to define a
>> local Proc object and use .call on it. Is that the recommended way?
>
>That's certainly possible, but we tend to use blocks instead of anonymous
>subroutines.

Could you give an example? To give an example of what I was looking for,
I am in the middle of some method with local variables a,b,c and
I have the same piece of code appearing twice:

some computations

print {some complicated debug print_out of the current contents of a,b,c}

some computations modifying a,b,c

print {same as above}

Now a,b,c are different classes, and the debug print_out is not associated
especially to any object so in an ordinary programming language (like Pascal)
the best solution would be a local procedure. Is there a better solution
in ruby than what I did:

debug_print=Proc.new{ the print statement}

and then do
debug_print.call

Best regards,
Jean MICHEL

Jean Michel

unread,
Dec 29, 2000, 5:13:24 AM12/29/00
to
In article <m3ae9gg...@qiao.localnet>,

Clemens Hintze <c.hi...@gmx.net> wrote:
>
>You wrote:
>> Hello,
>
>Hello too, :-)
>
>(...)

Thanks for your long and insightful reply.

>to find some valuable modules, that may help you here for mathematical
>tasks. Some among them:
>
> - NArray
> - BigFloat
> - NumArray
> - Polynomial
>
>(...)

I had a look and did not find the coding globally very consistent or the
mathematics behind always the best. Maybe I can bring my contribution in this
area...

>Erhm ... what? Lack of overloading? Impossible ... ah you mean
>overloading by parameter type, yes? That is indeed not available in
>Ruby (nor in Python or Smalltalk, BTW). The reason is that variables
>are not typed in such languages. Therefore it is difficult (perhaps
>impossible in some cases?) for the compiler to fiddle out on
>compilation time what kind of method to be called later on!

At compilation time, no. But at interpretation time, certainly each object
has a type (class)

>Not totally true! You could alias the old method and create a new one
>with same name like the old one but different behavior! Like that:
>

....

Thank you for the example with 'alias'. Ruby is certainly marvellous in
flexibility: the tools to implement any mechanism are already there!
However, one then has a concern about efficiency. If too much is implemented
in the library the language becomes less efficient. I guess I have to
see in practice how the efficiency works out for a large mathematical
project...

Best regards,
Jean MICHEL

Jean Michel

unread,
Dec 29, 2000, 5:14:36 AM12/29/00
to
In article <m2puicr...@zip.local.thomases.com>,
Dave Thomas <Da...@PragmaticProgrammer.com> wrote:

>jmi...@schur.institut.math.jussieu.fr (Jean Michel) writes:
>
>I'll leave that one for Matz: there's a section in his book all about
>coerce: perhaps he might be able to cut and paste it here.

That would be wonderful!

Jean

Jim Menard

unread,
Dec 29, 2000, 8:20:15 AM12/29/00
to
jmi...@schur.institut.math.jussieu.fr (Jean Michel) writes:

> Even so I am still surprised. How one is to know that in
>
> [1].sort!
>
> the receiver is not changed, but in
>
> [1,2].sort!
>
> it is? Not obvious to me...

Me neither. Now that I've thought about your example, I don't understand it
either. Perhaps someone else can clarify this situation. (I have a feeling
it is explained in the pixaxe book, but that book is at home, not here at
work.)

> >[each_with_index] is defined in the Enumeration (or Enumerable) module.


> >
> I guess I never tried to look there because for me Enumerable was for
> classes were just each exists, no ordering (e.g. is each supposed to
> go over the same object in the same order each time?). And why is
> the name not each_pair?

Hash#each_pair returns Hash key/value pairs. It's really a synonym for
Hash#each. Enumerable#each_with_index, since it is mixed in, is available
to all classes that implement each and mixin Enumerable.

I don't know if each, as defined by classes that mixin Enumerable, should
always return values in the same order. I have never relied on that
behavior.

> >That's certainly possible, but we tend to use blocks instead of anonymous
> >subroutines.
>
> Could you give an example? To give an example of what I was looking for,
> I am in the middle of some method with local variables a,b,c and
> I have the same piece of code appearing twice:
>
> some computations
>
> print {some complicated debug print_out of the current contents of a,b,c}
>
> some computations modifying a,b,c
>
> print {same as above}
>
> Now a,b,c are different classes, and the debug print_out is not associated
> especially to any object so in an ordinary programming language (like Pascal)
> the best solution would be a local procedure. Is there a better solution
> in ruby than what I did:
>
> debug_print=Proc.new{ the print statement}
>
> and then do
> debug_print.call

In this case, I would probably define a "regular" method and call that
method twice. Here, I don't see the advantage of using an anonymous
subroutine.

I'm relatively new to Ruby, and perhaps I am not thinking the "Ruby way".
Could someone else please comment on the appropriate use of blocks and/or
Proc objects here?

"Java: the elegant simplicity of C++ and the blazing speed of Smalltalk."
-- Roland Turner

Ben Tilly

unread,
Dec 29, 2000, 9:16:18 AM12/29/00
to
jmi...@schur.institut.math.jussieu.fr (Jean Michel) writes:
[...]

>Now a,b,c are different classes, and the debug print_out is not associated
>especially to any object so in an ordinary programming language (like
>Pascal)
>the best solution would be a local procedure. Is there a better solution
>in ruby than what I did:
>
> debug_print=Proc.new{ the print statement}
>
> and then do
> debug_print.call

Not addressing the question, just pointing out that you don't
have to make anonymous functions look so ugly in Ruby.

debug_print = proc { the print statement }
# Time passes
debug_print[]

Looks nicer to my eyes.

Cheers,
Ben
_________________________________________________________________
Get your FREE download of MSN Explorer at http://explorer.msn.com

David Alan Black

unread,
Dec 29, 2000, 9:42:04 AM12/29/00
to
On Fri, 29 Dec 2000, Jim Menard wrote:

> I don't know if each, as defined by classes that mixin Enumerable, should
> always return values in the same order. I have never relied on that
> behavior.

I'll bet you have -- class Array mixes in Enumerable, and defines
#each, so every time you #each through an array and expect it to be in
the same order, you're relying on that.

In some cases, one might rely on the enumerated elements *not* being
in the same order:

class DeckOfCards

include Enumerable

def initialize(arr)
@arr = arr
end

def each
a = @arr.dup
yield a.delete_at(rand a.size) until a.empty?
end

end

DeckOfCards.new( %w{ ace two three four jack queen king } ).each \
do |c| puts c end


(No flames about the shuffling algorithm, please -- I just wanted it
to be visually compact.)


David

--
David Alan Black
home: dbl...@candle.superlink.net
work: blac...@shu.edu
Web: http://pirate.shu.edu/~blackdav

pix...@mandrakesoft.com

unread,
Dec 29, 2000, 9:24:21 AM12/29/00
to
jmi...@schur.institut.math.jussieu.fr (Jean Michel) writes:

> >Erhm ... what? Lack of overloading? Impossible ... ah you mean
> >overloading by parameter type, yes? That is indeed not available in
> >Ruby (nor in Python or Smalltalk, BTW). The reason is that variables
> >are not typed in such languages. Therefore it is difficult (perhaps
> >impossible in some cases?) for the compiler to fiddle out on
> >compilation time what kind of method to be called later on!
>
> At compilation time, no. But at interpretation time, certainly each object
> has a type (class)

You can't specify the type of the arguments => the interpreter can't dispatch
based on it.

Languages that does so based on compile-time types: C++, Java...
Languages that does so based on runtime types (late-binding, multiple dispatch):
Common Lisp, CLOS, Dylan (solves the typical covariance/contravariance conflict,
see http://citeseer.nj.nec.com/castagna95covariance.html for more)

Yukihiro Matsumoto

unread,
Dec 29, 2000, 12:22:35 PM12/29/00
to
Hi,

In message "[ruby-talk:8249] Re: My first impression of Ruby. Lack of overloading? (long)"


on 00/12/29, Jean Michel <jmi...@schur.institut.math.jussieu.fr> writes:

|Thank you for the example with 'alias'. Ruby is certainly marvellous in
|flexibility: the tools to implement any mechanism are already there!
|However, one then has a concern about efficiency. If too much is implemented
|in the library the language becomes less efficient. I guess I have to
|see in practice how the efficiency works out for a large mathematical
|project...

Rely on me. ;-)

You will soon know what kind of person I am. Determin then if I'm
worthy enough to rely on. But trust me for now.

Ruby is at least faster than Python, that means fast enough for most
(if not all) of the cases, according to Python people. And NArray
beats NumPy in performance if things I've heard are correct.

matz.

Yukihiro Matsumoto

unread,
Dec 29, 2000, 12:22:32 PM12/29/00
to
Hi,

In message "[ruby-talk:8247] Re: My first impression of Ruby. Lack of overloading? (long)"


on 00/12/29, Jean Michel <jmi...@schur.institut.math.jussieu.fr> writes:

|>sort! returs nil if the message receiver (the array) is not changed, as do
|>many (but not all) of the "!" methods.
|
|Even so I am still surprised. How one is to know that in
|
| [1].sort!
|
|the receiver is not changed, but in
|
| [1,2].sort!
|
|it is? Not obvious to me...

It currently returns nil only for obvious cases (i.e. sorting on array
of 0 or 1 element). It is on the way to either returning no nil, or
returning consistent update status. Stay tuned, and do not rely on
the return value of sort! for a while.

matz.

Yukihiro Matsumoto

unread,
Dec 29, 2000, 12:22:44 PM12/29/00
to
Hi,

In message "[ruby-talk:8218] Re: My first impression of Ruby. Lack of overloading? (long)"


on 00/12/29, Dave Thomas <Da...@PragmaticProgrammer.com> writes:

|> Ok, now what did I miss, and what is the rationale for no overloading,
|> or the replacement for it that I missed?
|
|I'll leave that one for Matz: there's a section in his book all about
|coerce: perhaps he might be able to cut and paste it here.

You mean the coercing section in chapter 7? But it's for numbers only.

I'd add method overloading according their dynamic type of arguments,
iff I can think of a specification which is affordable and consistent
with rest of Ruby. But I have little hope about this issue.

How about using "double dispatch"?

class Foo
def action(arg)
arg.action_Foo(self)
end
end

class Bar
def action_Foo(arg)
... action for combination of Foo and Bar
end
end

class Baz
def action_Foo(arg)
... action for combination of Foo and Baz
end
end


matz.

Masahiro Tanaka

unread,
Dec 29, 2000, 3:18:34 PM12/29/00
to
>From: jmi...@schur.institut.math.jussieu.fr (Jean Michel)
>Subject: [ruby-talk:8249] Re: My first impression of Ruby. Lack of overloading? (long)

> >Erhm ... what? Lack of overloading? Impossible ... ah you mean
> >overloading by parameter type, yes? That is indeed not available in
> >Ruby (nor in Python or Smalltalk, BTW). The reason is that variables
> >are not typed in such languages. Therefore it is difficult (perhaps
> >impossible in some cases?) for the compiler to fiddle out on
> >compilation time what kind of method to be called later on!
>
> At compilation time, no. But at interpretation time, certainly each object
> has a type (class)

So complex.rb does run-time parameter check. Below I write
simplified version of Complex class in C++ and Ruby. Both of
them have almost same capability. Is Ruby version clumsier?
I don't think so. Major difference is parameter type check;
compile-time or run-time.

C++ version:

class complex {
double real, imag;
public:
complex(double a, double b=0) {
real = a;
imag = b;
}
complex operator+(complex a) {
return complex(real+a.real, imag+a.imag);
}
complex operator+(double a) {
return complex(real+a, imag);
}
};

Ruby version:

class Complex
attr_accessor(:real, :imag)
def initialize(a, b=0)
@real = a
@imag = b
end
def +(a)
case a
when Complex
Complex.new(@real+a.real, @imag+a.imag)
when Numeric
Complex.new(@real+a, @imag)
end
end
end

> However, one then has a concern about efficiency. If too much is implemented
> in the library the language becomes less efficient. I guess I have to
> see in practice how the efficiency works out for a large mathematical
> project...

Yes, run-time check spends execution time.
But Ruby has more flexibility like this:

% irb -r complex -r rational
irb(main):001:0> 1/Complex(Rational(3,2),1)
Complex(Rational(6, 13), Rational(-4, 13))

I think this kind of flexibility is big advantage
when the library grows.

M.Tanaka

Christoph Rippel

unread,
Dec 29, 2000, 4:08:40 PM12/29/00
to
"> % irb -r complex -r rational
> irb(main):001:0> 1/Complex(Rational(3,2),1)
> Complex(Rational(6, 13), Rational(-4, 13))
Yup,

but you can (in fact should) templatize your C++ - complex library ...
Ruby does not have any significant advantage here over C++.

Christoph

Masahiro Tanaka

unread,
Dec 29, 2000, 5:33:47 PM12/29/00
to
>From: "Christoph Rippel" <cri...@primenet.com>
>Subject: [ruby-talk:8295] Re: My first impression of Ruby. Lack of overloading? (long)

Sure, not significant here.
But don't you think it's fun to write it without template?

M.Tanaka

Christoph Rippel

unread,
Dec 29, 2000, 6:02:09 PM12/29/00
to
> Sure, not significant here.
> But don't you think it's fun to write it without template?
Sure when it comes to the fun factor Ruby is certainly very hard to beat ...

Christoph

Josh Stern

unread,
Dec 29, 2000, 10:11:33 PM12/29/00
to
Yukihiro Matsumoto <ma...@zetabits.com> wrote:

>I'd add method overloading according their dynamic type of arguments,
>iff I can think of a specification which is affordable and consistent
>with rest of Ruby. But I have little hope about this issue.

Well, just to throw something out there...perhaps there
could be a rule that methods with a special name, e.g.
ending with the '|' character, are actually looked
up based on hashing the method name plus the
argument type ids?


-= Josh

Dave Thomas

unread,
Dec 29, 2000, 10:44:07 PM12/29/00
to
jst...@foshay.citilink.com (Josh Stern) writes:

It'd have to be a fairly clever hash, as you'd have to be able to deal
with subclasses.

Tell me again: what problem are we trying to solve here?


Dave

Josh Stern

unread,
Dec 29, 2000, 11:29:47 PM12/29/00
to
In article <m2d7eam...@zip.local.thomases.com>,

Put another way: if one actually wanted it to have a behavior
similar to, say, Koenig lookup in C++, that would be quite
slow to do dynamically at run time, since the interpreter
would have to keep trying new hashes as it ascended the
hierarchy. But that expense would only apply to somebody
using it in that way, and there would be a pretty
obvious optimization to fix it (overload again for the dynamic
type you care about).

>Tell me again: what problem are we trying to solve here?

You mean why would somebody want to overload a method on arg
types rather than manually do their own dispatch for
different arguments in one method (not very encapsulated)
or create different methods that abort if called with the
wrong arguments? It seems like the interpreter could help
a bit with keeping things straight. If it turned out
that it didn't hurt other things (big 'If') then it
seems like it would be a good feature.

-= Josh


Jean Michel

unread,
Dec 31, 2000, 6:56:30 AM12/31/00
to
In article <978110491.341032...@ev.netlab.zetabits.com>,
Yukihiro Matsumoto <ma...@zetabits.com> wrote:
>...

>How about using "double dispatch"?
>
> class Foo
> def action(arg)
> arg.action_Foo(self)
> end
> end
>
> class Bar
> def action_Foo(arg)
> ... action for combination of Foo and Bar
> end
> end
>

Nice concept. Does not this suggest that method + for Numeric
behave like:

def +(arg)
if arg_can_be_considered_as_numeric
do_addition_as_usual
else
arg.add_Numeric(self)
end
end

rather than the current mechanism with coerce?

Best regards,
Jean MICHEL

GOTO Kentaro

unread,
Dec 31, 2000, 7:35:46 AM12/31/00
to
Hi,

In message "[ruby-talk:8399] Re: My first impression of Ruby. Lack of overloading? (long)"


on 00/12/31, Jean Michel <jmi...@schur.institut.math.jussieu.fr> writes:
>Nice concept. Does not this suggest that method + for Numeric
>behave like:
>
> def +(arg)
> if arg_can_be_considered_as_numeric
> do_addition_as_usual
> else
> arg.add_Numeric(self)
> end
> end
>
>rather than the current mechanism with coerce?

It does not work for operators which are not commutative, e.g.,
expornential operator "**" because "self ** arg" may be interpreted as
"arg ** self". If one would like to solve this problem with the
above, she has to prepare something to specify the order of operands.
But it is very thing done by the current mechanism of coerce :-)

Regards,

-- Gotoken

0 new messages