Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't ruby support method overloading?

Tags:

ruby

People also ask

Does ruby have operator overloading?

Ruby permits operator overloading, allowing one to define how an operator shall be used in a particular program. For example a '+' operator can be define in such a way to perform subtraction instead addition and vice versa.

What is method overloading and method overriding in Ruby?

Method Overloading is the concept of defining two or more methods with the same name but different signatures. Method Overriding is the concept of defining two or more identical methods, having the same name and signatures.

What does overriding of a superclass method mean Ruby?

It means that one of the methods overrides another method. If there is any method in the superclass and a method with the same name in its subclass, then by executing these methods, method of the corresponding class will be executed.

Can method overloading possible in parent/child relationship?

Overloading can happen in same class as well as parent-child class relationship whereas overriding happens only in an inheritance relationship.


"Overloading" is a term that simply doesn't even make sense in Ruby. It is basically a synonym for "static argument-based dispatch", but Ruby doesn't have static dispatch at all. So, the reason why Ruby doesn't support static dispatch based on the arguments, is because it doesn't support static dispatch, period. It doesn't support static dispatch of any kind, whether argument-based or otherwise.

Now, if you are not actually specifically asking about overloading, but maybe about dynamic argument-based dispatch, then the answer is: because Matz didn't implement it. Because nobody else bothered to propose it. Because nobody else bothered to implement it.

In general, dynamic argument-based dispatch in a language with optional arguments and variable-length argument lists, is very hard to get right, and even harder to keep it understandable. Even in languages with static argument-based dispatch and without optional arguments (like Java, for example), it is sometimes almost impossible to tell for a mere mortal, which overload is going to be picked.

In C#, you can actually encode any 3-SAT problem into overload resolution, which means that overload resolution in C# is NP-hard.

Now try that with dynamic dispatch, where you have the additional time dimension to keep in your head.

There are languages which dynamically dispatch based on all arguments of a procedure, as opposed to object-oriented languages, which only dispatch on the "hidden" zeroth self argument. Common Lisp, for example, dispatches on the dynamic types and even the dynamic values of all arguments. Clojure dispatches on an arbitrary function of all arguments (which BTW is extremely cool and extremely powerful).

But I don't know of any OO language with dynamic argument-based dispatch. Martin Odersky said that he might consider adding argument-based dispatch to Scala, but only if he can remove overloading at the same time and be backwards-compatible both with existing Scala code that uses overloading and compatible with Java (he especially mentioned Swing and AWT which play some extremely complex tricks exercising pretty much every nasty dark corner case of Java's rather complex overloading rules). I've had some ideas myself about adding argument-based dispatch to Ruby, but I never could figure out how to do it in a backwards-compatible manner.


Method overloading can be achieved by declaring two methods with the same name and different signatures. These different signatures can be either,

  1. Arguments with different data types, eg: method(int a, int b) vs method(String a, String b)
  2. Variable number of arguments, eg: method(a) vs method(a, b)

We cannot achieve method overloading using the first way because there is no data type declaration in ruby(dynamic typed language). So the only way to define the above method is def(a,b)

With the second option, it might look like we can achieve method overloading, but we can't. Let say I have two methods with different number of arguments,

def method(a); end;
def method(a, b = true); end; # second argument has a default value

method(10)
# Now the method call can match the first one as well as the second one, 
# so here is the problem.

So ruby needs to maintain one method in the method look up chain with a unique name.


I presume you are looking for the ability to do this:

def my_method(arg1)
..
end

def my_method(arg1, arg2)
..
end

Ruby supports this in a different way:

def my_method(*args)
  if args.length == 1
    #method 1
  else
    #method 2
  end
end

A common pattern is also to pass in options as a hash:

def my_method(options)
    if options[:arg1] and options[:arg2]
      #method 2
    elsif options[:arg1]
      #method 1
    end
end

my_method arg1: 'hello', arg2: 'world'

Hope that helps


Method overloading makes sense in a language with static typing, where you can distinguish between different types of arguments

f(1)
f('foo')
f(true)

as well as between different number of arguments

f(1)
f(1, 'foo')
f(1, 'foo', true)

The first distinction does not exist in ruby. Ruby uses dynamic typing or "duck typing". The second distinction can be handled by default arguments or by working with arguments:

def f(n, s = 'foo', flux_compensator = true)
   ...
end


def f(*args)
  case args.size
  when  
     ...
  when 2
    ...
  when 3
    ...
  end
end

This doesn't answer the question of why ruby doesn't have method overloading, but third-party libraries can provide it.

The contracts.ruby library allows overloading. Example adapted from the tutorial:

class Factorial
  include Contracts

  Contract 1 => 1
  def fact(x)
    x
  end

  Contract Num => Num
  def fact(x)
    x * fact(x - 1)
  end
end

# try it out
Factorial.new.fact(5)  # => 120

Note that this is actually more powerful than Java's overloading, because you can specify values to match (e.g. 1), not merely types.

You will see decreased performance using this though; you will have to run benchmarks to decide how much you can tolerate.


I often do the following structure :

def method(param)
    case param
    when String
         method_for_String(param)
    when Type1
         method_for_Type1(param)

    ...

    else
         #default implementation
    end
end

This allow the user of the object to use the clean and clear method_name : method But if he want to optimise execution, he can directly call the correct method.

Also, it makes your test clearers and betters.


there are already great answers on why side of the question. however, if anyone looking for other solutions checkout functional-ruby gem which is inspired by Elixir pattern matching features.

 class Foo
   include Functional::PatternMatching

   ## Constructor Over loading
   defn(:initialize) { @name = 'baz' }
   defn(:initialize, _) {|name| @name = name.to_s }

   ## Method Overloading
   defn(:greet, :male) {
     puts "Hello, sir!"
   }

   defn(:greet, :female) {
     puts "Hello, ma'am!"
   }
 end

 foo = Foo.new or Foo.new('Bar')
 foo.greet(:male)   => "Hello, sir!"
 foo.greet(:female) => "Hello, ma'am!"