Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overloading Resolution + Vararg methods: example should be ambiguous #8344

Closed
scabug opened this issue Feb 26, 2014 · 6 comments · Fixed by scala/scala#7680
Closed

Overloading Resolution + Vararg methods: example should be ambiguous #8344

scabug opened this issue Feb 26, 2014 · 6 comments · Fixed by scala/scala#7680
Assignees
Milestone

Comments

@scabug
Copy link

scabug commented Feb 26, 2014

Related to #4728. This compiles, the second alternative is chosen

object t {
  def f(x: Object) = 1
  def f(x: String*) = 2
}
t.f("") // returns 2, should be ambiguous.

According to #4728, it should be ambiguous. I assume the compiler thinks that String* conforms to Object. Maybe because it tests if Seq[String] conforms to Object, not sure.

@scabug
Copy link
Author

scabug commented Feb 26, 2014

Imported From: https://issues.scala-lang.org/browse/SI-8344?orig=1
Reporter: @lrytz
Affected Versions: 2.11.0
See #4728

@scabug
Copy link
Author

scabug commented Feb 26, 2014

@som-snytt said:
I think #8342 will say that autotupling makes the first f applicable to arbitrary strings. There's an issue somewhere with the example with a type parameter.

@scabug
Copy link
Author

scabug commented Feb 26, 2014

@lrytz said:
Right, I forgot about that. Auto-tupling seems just wrong in too many situations.

scala> def f(x: Object) = 0
f: (x: Object)Int

scala> f(1,2,3)
res0: Int = 0

@scabug
Copy link
Author

scabug commented May 12, 2014

@som-snytt said:
Is this open because it's still unambiguous under -Yno-adapted-args? If that should matter? Asking for a friend.

apm@mara:~$ goof -Yno-adapted-args
Welcome to Scala version 2.11.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0).
Type in expressions to have them evaluated.
Type :help for more information.

scala> object t {
     |   def f(x: Object) = 1
     |   def f(x: String*) = 2
     | }
defined object t

scala> t.f("")
res0: Int = 2

scala> def g[A](a: A) = 7
g: [A](a: A)Int

scala> g(1,2,3)
<console>:9: warning: No automatic adaptation here: use explicit parentheses.
        signature: g[A](a: A): Int
  given arguments: 1, 2, 3
 after adaptation: g((1, 2, 3): (Int, Int, Int))
              g(1,2,3)
               ^
res1: Int = 7

@adriaanm
Copy link
Contributor

adriaanm commented Jan 25, 2019

Weird, I guess this should be ambiguous. You can't apply a String* to a method expecting an Object, and you can't supply an Object when expecting one or more String (note that, as a formal, the vararg is expanded, while it it's when an argument. -- see #7680).

@adriaanm
Copy link
Contributor

While deciding which one is more specific, you get the following calls to isCompatibleArgs:

isCompatibleArgs false List(Object) <:< List(String)
isCompatibleArgs true List(String*) <:< List(Object)

the second one should be false too

@adriaanm adriaanm modified the milestones: Backlog, 2.13.0-RC1 Feb 4, 2019
@SethTisue SethTisue assigned adriaanm and unassigned lrytz Feb 4, 2019
@scala scala deleted a comment from scabug Feb 4, 2019
smarter added a commit to dotty-staging/dotty that referenced this issue Sep 3, 2020
We recntly merged scala#9601 which unified our handling of `Object` coming
from Java methods, an unintended consequence of that change is that some
existing Java APIs can no longer be called without running into
ambiguity errors, for example log4j defines two overloads for
`Logger.error`:

    (x: String, y: Object): Unit
    (x: String, y: Object*): Unit

previously we translated `Object` to `Any` but left `Object*` alone, now
they're both treated the same way (translated to a special alias of
`Object`) and so neither method ends up being more specific than the
other, so `error("foo: {}, 1)` is now ambiguous.

Clearly the problem lies with how we handle varargs in overloading
resolution, but this has been a source of issues for years with no clear
resolution:
- scala/bug#8342
- scala/bug#4728
- scala/bug#8344
- scala#6230

This PR cuts the Gordian knot by simply declaring that non-varargs
methods are always more specific than varargs. This has several
advantages:
- It's an easy rule to remember
- It matches what Java does (see
  https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.2)
- It avoids unnecessary wrapping of arguments

The downside is that it doesn't match what Scala 2 does, but our current
behavior isn't a perfect match either (also it seems that Scala 2
handles Java varargs and Scala varargs differently in overloading
resolution which is another source of complexity best avoided, see
`tests/run/overload_repeated`).
smarter added a commit to dotty-staging/dotty that referenced this issue Sep 3, 2020
We recently merged scala#9601 which unified our handling of `Object` coming
from Java methods, an unintended consequence of that change is that some
existing Java APIs can no longer be called without running into
ambiguity errors, for example log4j defines two overloads for
`Logger.error`:

    (x: String, y: Object): Unit
    (x: String, y: Object*): Unit

previously we translated `Object` to `Any` but left `Object*` alone, now
they're both treated the same way (translated to a special alias of
`Object`) and so neither method ends up being more specific than the
other, so `error("foo: {}, 1)` is now ambiguous.

Clearly the problem lies with how we handle varargs in overloading
resolution, but this has been a source of issues for years with no clear
resolution:
- scala/bug#8342
- scala/bug#4728
- scala/bug#8344
- scala#6230

This PR cuts the Gordian knot by simply declaring that non-varargs
methods are always more specific than varargs. This has several
advantages:
- It's an easy rule to remember
- It matches what Java does (see
  https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.2)
- It avoids unnecessary wrapping of arguments

The downside is that it doesn't match what Scala 2 does, but our current
behavior isn't a perfect match either (also it seems that Scala 2
handles Java varargs and Scala varargs differently in overloading
resolution which is another source of complexity best avoided, see
`tests/run/overload_repeated`).
smarter added a commit to dotty-staging/dotty that referenced this issue Sep 3, 2020
We recently merged scala#9601 which unified our handling of `Object` coming
from Java methods, an unintended consequence of that change is that some
existing Java APIs can no longer be called without running into
ambiguity errors, for example log4j defines two overloads for
`Logger.error`:

    (x: String, y: Object): Unit
    (x: String, y: Object*): Unit

previously we translated `Object` to `Any` but left `Object*` alone, now
they're both treated the same way (translated to a special alias of
`Object`) and so neither method ends up being more specific than the
other, so `error("foo: {}, 1)` is now ambiguous.

Clearly the problem lies with how we handle varargs in overloading
resolution, but this has been a source of issues for years with no clear
resolution:
- scala/bug#8342
- scala/bug#4728
- scala/bug#8344
- scala#6230

This PR cuts the Gordian knot by simply declaring that non-varargs
methods are always more specific than varargs. This has several
advantages:
- It's an easy rule to remember
- It matches what Java does (see
  https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.2)
- It avoids unnecessary wrapping of arguments

The downside is that it doesn't match what Scala 2 does, but our current
behavior isn't a perfect match either (also it seems that Scala 2
handles Java varargs and Scala varargs differently in overloading
resolution which is another source of complexity best avoided, see
`tests/run/overload_repeated`).

Fixes scala#9688, supercedes scala#6230.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants