Why is overloading invalid in ruby

I don’t understand why when I try to overload I get an error. Can I
overload somehow?

#!/usr/bin/env ruby

class Summer
def sum(x)
return x + 2
end

def sum(x,y)
return x + y
end

def sum(x,y,z)
return x + y + z
end
end

s = Summer.new
puts s.sum(3)

ERROR:
ArgumentError: wrong number of arguments (1 for 3)

method sum in summer.rb at line 18
at top level in summer.rb at line 18

Ted

On Thu, Jan 27, 2011 at 2:22 PM, Ted F. [email protected]
wrote:

def sum(x,y)

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

The problem is that when you define a method in a class that already has a
method with that name, it replaces it. So your class is left with only
one
method, the one with 3 arguments. The first 2 get destroyed. The more
ruby-esque way to do this is to use optional parameters. Here’s one
simple
solution:

def sum(x,y=0,z=0)
return x + y + z
end

On Thu, Jan 27, 2011 at 11:22 AM, Ted F. [email protected]
wrote:

I don’t understand why when I try to overload I get an error. Can I
overload somehow?

Ruby does not support method overloading. Searching the list archives
should turn up plenty of explanations.

Ben

I guess the answer to your question is “Because you don’t need to”

Overloading refers to two quite distinct situations. One is where you
want to involve parameters of different classes. You might want to add
two numbers or a number and a string. Ruby doesn’t have anything like
the problem with that compared to more typed languages. The Ruby term is
“Duck Typing” which means Ruby will let you supply miscellaneous objects
and then see if they work in the context.

The second meaning - the one you demonstrated - is different numbers of
parameters. As other have pointed out, you can supply different numbers
of parameters to the same methods as long as you tell Ruby this might
happen and tell it how to deal with all the possibilties - with certain
constraints.

The problem is your example is pretty meaningless. You would be unlikely
to want to write a different method for each sum length.

Think of a more realistic scenario and then see if Ruby doesn’t deal
with it.

(In the meantime, notice you really don’t need to wrap your code in the
class Summer. I don’t think it adds anything.)

(Oh dear, I shouldn’t have said that…)

On Friday 28 January 2011 04:22:47 Ted F. wrote:

def sum(x,y)

ERROR:
ArgumentError: wrong number of arguments (1 for 3)

method sum in summer.rb at line 18
at top level in summer.rb at line 18

Ted

Ruby doesn’t support method overloading. What your code does is giving
three
definition of the sum method, with each definition overwriting the
previous
one. This means that the first two definitions have no effect, since
they’re
overwritten by the third. At the end of your code, the sum method is
defined
to take three arguments, so you obviously get an error when you try to
call it
with only one argument.

You can achieve the same result giving some of the arguments default
values:

class Summer

def sum x, y = 2, z = 0
x + y + z
end

end

Now the sum method can be called with one, with two or with three
arguments.
In the first case, y will be 2 and z will be three, so the result will
be
computed as

x + 2 + 0

which is what you wanted. If it’s called with two arguments, x and y
will be
given the values passed as argument and z will be 0.

Another approach is to give sum a variable number of arguments, like
this:

def sum x, *args
args << 2 if args.empty?
res = x
args.each{|i| res += i}
res
end

The * in front of args in the method definition tells ruby that args is
special: it stands in place of any number of arguments, from 0 upwards.
When
the method is called, the first argument is assigned to x. Any other
argument
(if any) is put in an array which is assigned to the variable args. In
particular, if sum is called with only one argument, args will be empty,
so we
insert the value 2 in it (by the way, you could use Array#inject here,
which
is much more elegant than what I wrote).

I hope this helps

Stefano

Ah that’s too bad… I knew I could put some default values for x and y
and z… getting the same effect sort of…

but this isn’t a solution if the methods that I want to “overload” (I
call it
overload, not sure what the proper term should be) are
completely different, and are not differentiated simply by different
values.

Thank you for your reply though.

@aspirer: I know the example is simple, and “overloading” is silly in
such case, but I did intend to apply this to more complicated functions
that have the same names but do different things depending on the number
of parameters.

Ted

On Thu, Jan 27, 2011 at 1:22 PM, Ted F. [email protected]
wrote:

def sum(x,y)

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

Ruby methods don’t really have signatures, so overloading would be quite
difficult.

Disregarding your first sum, which adds 2, for some unknown reason, I
would
write the method like this:

def sum(*numbers)
sum = 0
numbers.each { |number| sum += number }
sum
end

Okay, I would probably actually write it like this, which is the same
thing,
but less accessible to people who haven’t encountered inject or reduce
before.

def sum(*numbers)
numbers.inject { |sum,number| sum + number }
end

It could then be called with any number of arguments and types

sum 1 # => 1
sum 1 , 2 # => 3
sum 5 , 9 , 10 # => 24
sum 8 , 8 , 16 , 32 # => 64
sum 1.5 , 2.3 # => 3.8

In fact, it is flexible enough to take non-numeric types, though you
probably wouldn’t ever use such a thing.

sum ‘a’ , ‘b’ # => “ab”
sum [1,2] , [3,4] # => [1, 2, 3, 4]

Just to clarify what I was proposing (I am prepared to be corrected by
the experts here) - when you specify parameters to a Ruby method, Ruby
passes in variables. In Ruby, variables are references ie pointers to an
object. They of themselves are all the same data type. You can pass in
references to any object type. Ruby doesn’t check the type of object
being referred to. One reason is at no point have you indicated what
type Ruby should expect.

At run time, inside the method body, Ruby will attempt to pass the
method name to the object referred to by your parameter. Only at that
point do we need things to match up.

The next step in the story is that = is a special case. It says make the
variable on the left hand side point to the object on the right hand
side. All other similar looking operators are actually methods on an
object. Ruby simply sends the message to the object concerned and sees
what happens.

In this scenario you can see how Ruby can deal with varying types (the
overloading gets shifted to the object being called - n possible object
types gives you n possible overloads.

However there’s no corresponding way around the number (and order) of
parameters without the less elegant solutions discussed above.

Nobody sems to complain, so I suggest you don’t worry about it. It’s
unlikely to cramp your style.

On Thursday, January 27, 2011 02:55:24 pm Ted F. wrote:

Ah that’s too bad… I knew I could put some default values for x and y
and z… getting the same effect sort of…

but this isn’t a solution if the methods that I want to “overload” (I
call it
overload, not sure what the proper term should be) are
completely different, and are not differentiated simply by different
values.

If they’re not differentiated by different values, how were you
expecting
overloading to work? If the problem is that you need the behavior to be
different, I think default values still work – for example:

def sum_or_inverse a, b=nil
if b.nil?
-a
else
a+b
end
end

But I don’t really know what you were asking.
I agree with Jesús. We need more details.

On Thu, Jan 27, 2011 at 9:55 PM, Ted F. [email protected]
wrote:

Ah that’s too bad… I knew I could put some default values for x and y
and z… getting the same effect sort of…

but this isn’t a solution if the methods that I want to “overload” (I
call it
overload, not sure what the proper term should be) are
completely different, and are not differentiated simply by different
values.

If they are so completely different, maybe the name of the method
should be different.
Can you share a bit more so we can give some recommendations?

Jesus.

David M. wrote in post #978005:

On Thursday, January 27, 2011 02:55:24 pm Ted F. wrote:

Ah that’s too bad… I knew I could put some default values for x and y
and z… getting the same effect sort of…

but this isn’t a solution if the methods that I want to “overload” (I
call it
overload, not sure what the proper term should be) are
completely different, and are not differentiated simply by different
values.

If they’re not differentiated by different values, how were you
expecting
overloading to work? If the problem is that you need the behavior to be
different, I think default values still work – for example:

def sum_or_inverse a, b=nil
if b.nil?
-a
else
a+b
end
end

But I don’t really know what you were asking.
I agree with Jesús. We need more details.

Ok… I didn’t want to post so much code but you asked for it. I am
trying to read a file, with a number of different methods. The methods
allow you to interpret the file as an input and output matrices, input
only or both but with only a number of rows. I was hoping for an easy
overloading method solution, but now I realize that I can’t do that with
ruby.

class CSVFile
attr_accessor :inFile
attr_accessor :file_data
attr_accessor :in_data
attr_accessor :out_data
attr_reader :count

def initialize(file)
@inFile = file
@file_data = []
@count = 0
@in_data = []
@out_data = []
end

def read_data
if inFile.nil? == false
@count = 0
File.foreach(inFile) do |line|
arr = line.chomp.split(’,’)
float_array = arr.map { |x| x.to_f }
file_data.push(float_array)
@count = @count + 1
end
end
return file_data
end

def read_data(num_in, num_out)
if inFile.nil? == false
@count = 0
File.foreach(inFile) do |line|
arr = line.chomp.split(’,’)
float_array = arr.map { |x| x.to_f }
arr_in = []
arr_out = []
for i in 0…num_in
arr_in << float_array[i]
end

    in_data.push(arr_in)
    for j in num_in...(num_in+num_out)
      arr_out << float_array[j]
    end
    out_data.push(arr_out)
    @count = @count + 1
  end
end
return file_data

end

def read_data(num_in, num_out, num_lines)
if inFile.nil? == false
@count = 0
File.foreach(inFile) do |line|
if @count >= num_lines
break;
end

    arr = line.chomp.split(',')
    float_array = arr.map { |x| x.to_f }
    arr_in = []
    arr_out = []
    for i in 0...num_in
      arr_in << float_array[i]
    end

    in_data.push(arr_in)
    for j in num_in...(num_in+num_out)
      arr_out << float_array[j]
    end
    out_data.push(arr_out)
    @count = @count + 1
  end
end
return file_data

end
end

On Fri, Jan 28, 2011 at 3:22 AM, Ted F. [email protected]
wrote:

I don’t understand why when I try to overload I get an error. Can I
overload somehow?

Hi Ted,

sorry no overloading in ruby. overloading gives fixed/absolute power
to compiler/interpreter. ruby is dynamic, everything can be changed at
runtime, anytime. second, ruby is oo, ojbect first progg,
polymorph-based ie.

def sum(x)
return x + 2
^^
lose the return, ruby does not need it here

as others have mentioned, you can use starred args and default params
to mimic overloading. if that does not fit your taste, you can use
named params or hash (it fits mine :slight_smile:

the advantage of named params over static signature/position-based
param is that you have more control of your method since it is really
the params (wc are objects by themselves) that do the playing, not
the positioning (again, emphasizing o-o-ness). ergo, you have better
control and you can test/debug the methods a lot better.

now if that still does not suit your taste, you can do polymorphism,
wc of course comes natural in o-o langgs.

anyway, the ff code shows how to scheme thru named parameters way,

eg,

class Summer
def sum(opt={:none=>“none entered :)”})
case opt.keys.sort
when [:none]
opt[:none]
when [:x]
sumx opt[:x]
when [:x, :y]
sumxy opt[:x], opt[:y]
when [:x, :y, :z]
# you can place more conditions here
sumxyz opt[:x], opt[:y], opt[:z]
when [:a, :x, :y, :z]
sumxyz_xa opt[:x], opt[:y], opt[:z], opt[:a]
else
# you can place other conditions and methods here, do anything
end
end

private

def sumx x
x + 2
end

def sumxy x,y
x + y
end

def sumxyz x,y,z
x + y + z
end

def sumxyz_xa x,y,z,a
sumxyz(x,y,z) ** a
end
end
#=> nil

s = Summer.new
#=> #Summer:0x918e350
puts s.sum()
none entered :slight_smile:
#=> nil
puts s.sum(x:3)
5
#=> nil

note also that the params have been disarranged to show flex

puts s.sum(x:3,y:4)
7
#=> nil
puts s.sum(z:5,x:3,y:4)
12
#=> nil

this last sample call previous method and raises that to power :a

puts s.sum(y:4,a:6,x:3,z:5)
2985984
#=> nil

best regard -botp

On Thu, Jan 27, 2011 at 9:52 PM, Ted F. [email protected]
wrote:

end
end

But I don’t really know what you were asking.
I agree with Jess. We need more details.

Ok… I didn’t want to post so much code but you asked for it. I am
trying to read a file, with a number of different methods. The methods
allow you to interpret the file as an input and output matrices, input
only or both but with only a number of rows.

Infinity = 1.0/0

def read_data(num_in = nil, num_out = nil, num_lines = Infinity)
unless inFile.nil?
@count = 0

File.foreach(inFile) do |line|
# def read_data(num_in, num_out, num_lines)
break if @count >= num_lines

arr = line.chomp.split(',')

float_array = arr.map { |x| x.to_f }

  # def read_data(num_in, num_out)
  if num_in and num_out
 arr_in = []
arr_out = []
 for i in 0...num_in
 arr_in << float_array[i]
end

in_data.push(arr_in)
for j in num_in...(num_in+num_out)
  arr_out << float_array[j]
end
 out_data.push(arr_out)
  elsif num_in or num_out
    raise ArgumentError
  else
    # def read_data
    file_data.push(float_array)
 end

@count = @count + 1
end

file_data
end
end

On Fri, Jan 28, 2011 at 10:52 AM, Ted F. [email protected]
wrote:

Ok… I didn’t want to post so much code but you asked for it. I am
trying to read a file, with a number of different methods. The methods
allow you to interpret the file as an input and output matrices, input
only or both but with only a number of rows.

ok, you’ve defined the class, thanks.
pls also show how’d you call/use so we do not have to invent here.

best regards -botp

Good Evening,

On Thu, Jan 27, 2011 at 6:52 PM, Ted F. [email protected]
wrote:

end

How about this - I’m unsure of some of the variables - they seem a
little
strange but I’m sure you can debug any issues in that respect - I just
used
pretty much what you provided.

def read_data(num_in = nil, num_out = nil, num_lines = nil)
#This just looks a little nicer than the if .nil? == false
unless @inFile.nil?
#Either we are provided the number of lines to use or we use them
all
num_lines ||= @inFile.length
#Instead of counting where we are we just limit our group to what we
want
myFiles = @inFile[0…num_lines]
#Use our limited dataset
File.foreach(myFiles) do |line|
arr = line.chomp.split(‘,’)
float_array = arr.map { |x| x.to_f }
#Make a choice based on the num_in variable
if num_in.nil?
@file_data.push(float_array)
else
#Much simpler here - no need for the loops and temp vars
#Just grab what we need and move along
in_data << float_array[0…num_in]
out_data << float_array[num_in…(num_in+num_out)]
end
end
end

return @file_data
end

On Thu, Jan 27, 2011 at 8:48 PM, Ben B. [email protected]
wrote:

On Thu, Jan 27, 2011 at 11:22 AM, Ted F. [email protected] wrote:

I don’t understand why when I try to overload I get an error. Can I
overload somehow?

Ruby does not support method overloading. Searching the list archives
should turn up plenty of explanations.

For example the recent thread

http://blade.nagaokaut.ac.jp/cgi-bin/vframe.rb/ruby/ruby-talk/377008?376902-377590

and especially

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/377075

Cheers

robert

On Fri, Jan 28, 2011 at 3:17 AM, Robert K.
[email protected] wrote:

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/377075
FWIW, I’d love for Ruby to support operator overloading. JRuby
supports it in Java-based Ruby methods (like the core classes) by
splitting the arities up into different call paths. I hope to do the
same under the covers for “overloaded” optional args forms, so that
this:

def foo(a, b = 1, c = 2)

would compile to the equivalent of this overloaded form:

def foo(a) foo(a, 1, 2)
def foo(a, b) foo(a, b, 2)
def foo(a, b, c) …

When you look at optional args that way it doesn’t seem so odd to take
the next leap and say ruby should allow separate logic for those
different paths rather than simply chaining them. For example, it’s
uncommon but sometimes you’ll see this form:

def foo(a, b = (c = true; 1)) …

‘b’ is an optional arg that, when set to its optional value (i.e.
nothing passed in), also sets c = true. So you can check c to see if
the value of b came from the optional value or not. Gross!

If instead you could actually overload, it would simply be two methods:

def foo(a); b = 2;
def foo(a, b);

The fact that people have to use tricks like b = (c = true; 2) make me
think there’s an opportunity here.

And it would be even cooler if Ruby supported some form of type-driven
pattern matching, so you could have different method bodies for
different input types rather than checking them over and over again.
But that’s a post for another day :slight_smile:

  • Charlie

On Fri, Jan 28, 2011 at 5:13 PM, Charles Oliver N.
[email protected]wrote:

And it would be even cooler if Ruby supported some form of type-driven
pattern matching, so you could have different method bodies for
different input types rather than checking them over and over again.
But that’s a post for another day :slight_smile:

Not very quackish.

On Thursday, January 27, 2011 08:52:03 pm Ted F. wrote:

attr_reader :count
if inFile.nil? == false

    end

end
float_array = arr.map { |x| x.to_f }
out_data.push(arr_out)
@count = @count + 1
end
end
return file_data
end
end

Yeah, there’s a lot of duplicate stuff there. Also, why are you doing
this
when there’s a CSV class in the standard library?

http://ruby-doc.org/stdlib/libdoc/csv/rdoc/index.html

Anyway, it looks like you’re copying and pasting a lot between those
methods, so it also looks like if you DRYed it up a bit, it’d work just
fine
with default arguments. Also, there’s a bunch of ways this could be more
idiomatic… Here’s a rough guess at what you’re trying to do, at least
for
this one method:

def read_data num_in=nil, num_out=nil, num_lines=nil

This does what you said above. Are you sure that’s right?

Shouldn’t it raise an error or something?

return file_data if inFile.nil?

If I were you, I’d have the ‘count’ method pass through to

file_data.length or something, so this could be a local…

@count = 0

Object-oriented programming means letting the object

figure out what to do, instead of calling functions

with that object. The File.foreach was a code smell to me.

inFile.each_line do |line|
break if num_lines && @count >= num_lines

# Note that, unlike a proper CSV parser, this won't handle escaped 

commas.
arr = line.chomp.split(‘,’).map(&:to_f)

if num_in
  # An each would be better than a foreach IMO, but if you want
  # the best speed and readability, why not rely on stuff arrays
  # already know how to do instead of writing the loop yourself?
  arr_in.push arr[0...num_in]

  if num_out
    # num_in and num_out are both counts, right?
    arr_out.push arr[num_in,num_out]
  end
end

@count += 1

end

file_data
end

Warning: I haven’t tested the above code at all, but it looks like it
can
replace the read_data methods you wrote. Let me know. Still, I mostly
did it
as an exercise, because if you were planning to actually work with CSVs,
I’d
think your code should start with:

require ‘csv’

On Fri, Jan 28, 2011 at 11:41 AM, Adam P.
[email protected]wrote:

Well, you could reinterpret “type driven” to be “respond_to driven”.
Almost
the same sentiment, but more embracing of OO as described in Rick’s talk
(
http://confreaks.net/videos/461-rubyconf2010-objects-are-just-objects-aren-t-they
).

Personally, I found it weird to not have overloading when I came from
Java,
because I had fallen into a series of patterns based around it that I
really
liked (one canonical method, with several overload ones for convenience,
that just take their arguments and translate them to the appropriate
method
call of the real one). But now, I think Ruby’s bag of argument tricks
are
much more powerful. Initialization blocks, optional params through hash
support, optional arguments, etc I think are very powerful (might be
nice if
the language supported the hashes a bit better), and really, I almost
never
miss overloading, and I think the things you would lose by supporting it
would not be worth it.