Method Overloading/ The Ugly Parts

Method overloading resolution in C style languages is a tricky business, I am referring here to Java an C# in particular. Resolution rules seem obvious for the novice.

 void fn(int x);
 void fn(int x,int y);

So far so simple, but what happens if we have the following

void fn(float x);
void fn(double x);
// call fn with an int 
fn(1);

the value 1 will be resolved into a 32-bit integer and we have 2 candidates, one that takes a float and the other takes a double, both types can hold an int, so which one would it choose? The answer is fn(float). Why? Because fn(float) is more specific. It looks at the candidates, it finds a float and a double, float is a 32-bit signed floating point type and double is a 64-bit signed floating point type and hence we can squeeze any float into a double and hence we choose float 🙂

Now lets do overloading on reference type parameters.

 class Foo{
 }
 class Bar extends Foo{
 }
 void fn(Foo foo);
 void fn(Bar bar);
 // call fn
 fn(null);

So we calling fn with a null parameter. There are 2 candidates Foo and Bar, every Bar is a Foo but not every Foo is a Bar and hence it chooses Bar because it is more specific 🙂
If we have a third candidate that takes a String as follows.

 class Foo{
 }
 class Bar extends Foo{
 }
 void fn(Foo foo);
 void fn(Bar bar);
 void fn(String s);
 // call fn, ambiguous call
 fn(null);

Then it becomes an ambiguous call because there no is relation between String and Bar.
Great.
It really becomes a pain with lambdas and method references. Consider the following.

 ExecutorService executorService = Executors.newSingleThreadExecutor();
  executorService.submit(()->{
            throw new RuntimeException();
  });

Now you guess it. Would it choose Callable or Runnable ?
The answer is Callable because the other candidate Runnable returns void 🙂 .You can assign to a Future as follows

 ExecutorService executorService = Executors.newSingleThreadExecutor();
  Future<Object> future = executorService.submit(()->{
            throw new RuntimeException();
  });

If you want to master it, you should read the specification every night before you go to bed.

Conclusion: There are very good reasons why languages with strong type systems like Haskell don’t allow method overloading.

Advertisements

One Comment

Nice observations. Here’s another caveat involving overloading in the context of using method references at the call-site:
http://blog.jooq.org/2015/07/28/java-8s-method-references-put-further-restrictions-on-overloading

Overloading is nasty in any language.

Leave a Reply

Name and email address are required. Your email address will not be published.

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s

You may use these HTML tags and attributes:

<a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <pre> <q cite=""> <s> <strike> <strong> 

%d bloggers like this: