Skip to content

Need An Error Message for Overloading Type-Mismatch #11899

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

Closed
AugustNagro opened this issue Mar 26, 2021 · 9 comments
Closed

Need An Error Message for Overloading Type-Mismatch #11899

AugustNagro opened this issue Mar 26, 2021 · 9 comments

Comments

@AugustNagro
Copy link
Contributor

AugustNagro commented Mar 26, 2021

Compiler version

3.0.0-RC1
EDIT: happens on latest master as well.

Minimized code

import java.util.function.Function

class Future[T](val initial: T) {
  def map[V](v: V): Unit = println(v)
  def map[U](fn: Function[T, U]): Unit = println(fn(initial))
}

val f = new Future(42)
val fn = (i: Int) => i.toString
f.map(fn)

Output

main$package$$$Lambda$50530/134842729@268fb089

(does not matter if using def or lambda syntax)

Expectation

In Scala 2, the same code will not compile . It reports:

type mismatch;
 found   : Int => String
 required: java.util.function.Function[Int,?]

Vertx's Future has two such map methods, for example. As a feature request, it would be very nice to have special handling for java.util.function interfaces so f.map(fn: Function[Int, String]) is not required.

@AugustNagro
Copy link
Contributor Author

I wonder if the java.util.function conversions that already exist could be tweaked so they are preferred over a generic argument.

@abgruszecki
Copy link
Contributor

I confirmed that this happens on latest master as well.

@odersky
Copy link
Contributor

odersky commented Mar 26, 2021

I am not sure what should be done here. The second match is not applicable, but the first one is. So Scala 3's behavior is as we would expect.

@abgruszecki
Copy link
Contributor

We should check what Scala2 does. Could it be the case that there is hardcoded behaviour to prefer the jFunction overload over others if the argument type is a Scala function?

@odersky
Copy link
Contributor

odersky commented Mar 26, 2021

We should check what Scala2 does. Could it be the case that there is hardcoded behaviour to prefer the jFunction overload over others if the argument type is a Scala function?

But then why finish with a type error?

@AugustNagro
Copy link
Contributor Author

@odersky For Scala code it makes sense to pick the generic overload, but that is never what a user wants with a Java library.

Since Java's functional interfaces are now quite prevalent in APIs, I wonder how often this issue manifests, besides Vertx.

One thing off the top of my head would be java.util.Comparator::thenComparing. It has two overloads, one taking a Function, and one a Comparator. But before I could test I found that just sorting with a Comparator in Scala 3 fails:

case class Pair(s: String, i: Int)

val l = new java.util.ArrayList[Pair]()
l.add(Pair("b", 1)); l.add(Pair("a", 5)); l.add(Pair("b", 0))

l.sort(java.util.Comparator.comparing(p => p.s))

With exception

1 |l.sort(java.util.Comparator.comparing(p => p.s))
  |                                      ^
  |    object creation impossible, since def apply(x$0: T): R is not defined 
  |    (Note that T does not match Pair)

The Java signature of comparing is

static <T, U extends Comparable<? super U>> Comparator<T>
    comparing(Function<? super T, ? extends U> keyExtractor);

This code compiles & runs in Scala 2.13.4.

Should I file a new issue, or maybe change the title to 'Java Function Compat Problems'?

@odersky
Copy link
Contributor

odersky commented Mar 27, 2021

I think it is fine to keep it on this issue. It would be good if someone figured out what Scala 2.13's algorithm for treating these things is.

@smarter
Copy link
Member

smarter commented Mar 29, 2021

Should I file a new issue, or maybe change the title to 'Java Function Compat Problems'?

Let's keep separate issues with separate problem. I'm going to close this issue because as far as I can tell the behavior of Scala 3 with these map overloads is perfectly correct (and I don't even see what special case we could add here that wouldn't break legitimate code), the fact that Scala 2 happens to emit an error seems more like a bug than an intentional design decision. IMO, the only issue here is an unfortunate API design choice in Vertex.

@odersky
Copy link
Contributor

odersky commented Mar 30, 2021

#11945 (comment)

odersky added a commit to dotty-staging/dotty that referenced this issue Apr 1, 2021
Applicability testing as used in overloading resolution now considers
a SAM conversion only if the argument is a lambda (possibly an eta-converted
one). This matches exactly what normal adaptation does.

It turns scala#11899 into a pos test (now part of i11938.scala). That is Scala 3
will fallback to a generic alternative where Scala 2 failed with a type error.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants