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

Scala -> Java compatibility. Compiler can't choose most specific overloaded method #4775

Closed
scabug opened this issue Jul 6, 2011 · 9 comments · Fixed by scala/scala#7680
Closed
Assignees
Milestone

Comments

@scabug
Copy link

scabug commented Jul 6, 2011

Java example:

// JavaClass.java
public class JavaClass {
  public static class Element {

  }

  public static <T extends Element> int foo(Element a, Class<T> b, boolean c, Class<? extends T>... d) {
    return 1;
  }

  public static <T extends Element> int foo(Element a, Class<? extends T> b, boolean c) {
    return 2;
  }

  public static <T extends Element> int foo(Element a, Class<? extends T>... b) {
    return 3;
  }

  public static <T extends Element> int foo(Element a, boolean b, Class<? extends T>... c) {
    return 4;
  }

  static {
    foo(new Element(), Element.class, false);
  }
}

Scala example:

// ScalaClass.scala
class ScalaClass {
  JavaClass.foo(new Element, classOf[Element], false)
}

Obviously two methods are applicable, but one of them is definetely more specific (which is without varargs).

@scabug
Copy link
Author

scabug commented Jul 6, 2011

Imported From: https://issues.scala-lang.org/browse/SI-4775?orig=1
Reporter: @Alefas
See #2991

@scabug
Copy link
Author

scabug commented Aug 15, 2011

@paulp said:
Minimized:

class A {
  def f[T](x: T): T = x
  def f[T](x: T, xs: T*): T = x
  
  f(5)
  
  // but this works:
  def g(x: Int): Int = x
  def g(x: Int, xs: Int*): Int = x

  g(5)
}

@scabug
Copy link
Author

scabug commented Aug 15, 2011

@paulp said:
Oops, missed the error.

b.scala:5: error: ambiguous reference to overloaded definition,
both method f in class A of type [T](x: T, xs: T*)T
and  method f in class A of type [T](x: T)T
match argument types (Int)
  f(5)
  ^
one error found

@scabug
Copy link
Author

scabug commented Aug 15, 2011

@paulp said:
OK, first of all this happens trying to infer the type parameters. So in my minimization, and in the general case, you could make this call like this:

foo[Element](new Element, classOf[Element], false)

However in this particular case, the fact that classOf returns Class[T] but getClass returns Class[_ <: T] means it still appears ambiguous. Here are two ways you can actually call it.

foo[Element](new Element, (new Element).getClass, false)
foo[Element](new Element, (classOf[Element] : Class[_ <: Element]), false)

@scabug
Copy link
Author

scabug commented Aug 16, 2011

@paulp said:
Reading section 6.26.3 of the spec, I can't even find what language implies def f[T](x: T): T should be favored over def f[T](x: T, xs: T*): T. It seems like everyone takes for granted, that the first would be favored over the second if both were applicable, but if it's in the spec it must emerge indirectly from language too complicated for me to dissect right now.

@scabug
Copy link
Author

scabug commented Aug 16, 2011

@adriaanm said:
the first version is more specific, the one with the vararg is more general

@scabug
Copy link
Author

scabug commented May 25, 2012

Espen Wiborg (espenhw) said:
This looks very similar to #2991, which was closed with NotABug.

Interestingly, you can explicitly call the varargs f with f(5, Seq.empty: _*) but there is no way to specify the non-varargs method (at least I can't come up with one).

I've tried to wrap my head around the language in the relevant bit of the JLS (section 15.12.2.5);
the "informal intuition" supports favoring def f[T](x: T): T, but I find nothing supporting that in the formal definition. I won't even try to understand section 6.26.3 of the Scala spec on a Friday afternoon. :)

@scabug
Copy link
Author

scabug commented Mar 6, 2013

daveclay said:
Just ran into this in a real-life example writing a unit test using Mockito:

        when(serviceReference.getProperty("name")).thenReturn(name)

Results in the compilation error:

scala: ambiguous reference to overloaded definition,
both method thenReturn in trait OngoingStubbing of type (x$1: Object, x$2: <repeated...>[Object])org.mockito.stubbing.OngoingStubbing[Object]
and  method thenReturn in trait OngoingStubbing of type (x$1: Object)org.mockito.stubbing.OngoingStubbing[Object]
match argument types (String)
        when(serviceReference.getProperty("name")).thenReturn(name)
                                                   ^

And to fix this, I have to be explicit in typing the instance of OngoingStubbing:

        when(serviceReference.getProperty("name")).asInstanceOf[OngoingStubbing[String]].thenReturn(name)

Which can get pretty ridiculous, depending on the thing I'm stubbing:

        when(bundleContext.getService(serviceReference)).asInstanceOf[OngoingStubbing[LoginHandler[AuthData, User, String]]].thenReturn(handler)

It's not Friday yet, but I guess it is time to get beer and/or pray.

@scabug
Copy link
Author

scabug commented Sep 22, 2015

matan said:
Is there currently any horizon to a solution? is the underlying issue very complex? it has recently come up in https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!msg/gremlin-users/M7knBWSHVi4/B4RPkh6nBAAJ. A solution can de-cumbersome scala wrappers for java api.

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