Nacht
Nacht

Reputation: 11346

Scala compilers complains about "ambiguous reference to overloaded definition" when asking for a function in the second parameters set

This seems strange. The following will compile fine:

def foo(s: String) = "balsh"
def foo(s: String)(s2: String) = "kahsd"

If I make the second parameter implicit, it still compiles fine and all.

However, the following will not:

def foo(s: String) = "bjda"
def foo(s: String)(fun: String => String) = fun(s)

^that one will not compile due to "ambiguous reference to overloaded definition".

My original thought was that the way Scala was converting functions to Java was causing the signatures of the two to be the same. However, looking at the compile coded (for the second function only since it would not compile with both) with javap, you would see that such a function is actually converted into:

public java.lang.String foo(java.lang.String, scala.Function1);

So a separate method is created, with a different signature. So why is this failing to compile?

Now to make matters even more confusing, the following actually compiles fine!

def foo(s: String) = "bjda"
def foo(s: String, fun: String => String) = fun(s)

If you make the function part of the first set of parameters, then everything is fine!

Does anyone know why this is happening?

EDIT:

So I just tried this:

object main {
  def write(s: String) = "sasd"
  def write(s: String)(implicit s2: String => String) = s2(s)
}

I simply made the function in the second parameter implicit. Lo and behold, this compiles.

This is the java code it produces:

public final class main$ extends java.lang.Object{
    public static final main$ MODULE$;
    public static {};
    public java.lang.String write(java.lang.String);
    public java.lang.String write(java.lang.String, scala.Function1);
}

This is what I would have expected from the original one without the implicit!

Upvotes: 3

Views: 880

Answers (2)

bjfletcher
bjfletcher

Reputation: 11498

If anyone wants to avoid the implicit hack, here's another way:

def foo(s: String) = "balsh"
def foo(t: String)(s2: String) = "kahsd"

where the second function's parameter name is changed to something different. Then when you want the first one:

foo(s = "foo")

and when you want the second:

foo(t = "foo")

Upvotes: 0

johanandren
johanandren

Reputation: 11479

I'd guess there is no way for the compiler to select between the two as they are really just differing in return types. It is not possible to dispatch based on the return type of a function only the parameters. Think of the signatures like this:

def foo(s: String): String
def foo(s: String): String => String

Not sure why you get it to work if you make it implicit, I get the same error (as I would expect).

def foo(s: String, fun: String => String) 

on the other hand has a different parameter list which is possible to dispatch to.

Upvotes: 0

Related Questions