19

Say you have the following:

foo(x: String)(y: Int): Int
foo(x: String)(y: Double): Int

Scala does not allow such expression. As far as I can see, the reason for this is that foo("asdf") does not have a well defined type (it's either Int => Int or Double => Int).

Is there a reason why such "polytyped" functions should not be allowed?

Henry Henrinson
  • 5,203
  • 7
  • 44
  • 76
  • https://issues.scala-lang.org/browse/SI-2628 – Bradford Aug 24 '11 at 19:59
  • Scala allows you to define that pair of overloaded methods, but it any call is ambiguous, for reasons outlined by Martin below. Relevant: http://stackoverflow.com/questions/2510108/why-avoid-method-overloading – retronym Aug 24 '11 at 21:55

3 Answers3

23

Overloading resolution in Scala takes only the first parameter list into account. That's why alternatives must differ already in this list. There's a good reason for this: We can then use the resolved function's type to infer the type of subsequent arguments. This enables idioms like:

xs.corresponds(ys) { (x, y) => x < y }

Note that here we need to know the type of corresponds in order to infer the types of x and y. It would be a shame to have this break down when corresponds is overloaded.

Martin Odersky
  • 20,470
  • 9
  • 51
  • 49
  • Thanks for the answer. As a follow-up, wouldn't it be possible to have a list of possible types that can be assigned to x and y, based on what overloaded versions of corresponds are in scope (similar to how implicits work) and just decide on the types only when you have to? Or would this go against the idea of static typing? – Henry Henrinson Aug 24 '11 at 23:22
  • 2
    Any approach that considers lists of possible types risks exponential explosion of type checking times. That's why Scala generally does not do that in its type inference algorithm. – Martin Odersky Sep 04 '11 at 14:21
2

A simple workaround is to use an anonymous object:

def foo(x: String) = new {
  def apply(y: Int): Int
  def apply(y: Double): Int
}
xavlours
  • 743
  • 7
  • 11
2

This isn't the first time this has been asked: it was asked back in 2009. Unfortunately Martin didn't explicitly state what the issues were, other than that it would require a fairly extensive spec change on how overloading works. I've looked at the spec and it's not clear to me where the core issues lie, but I'm not skilled enough in the spec to give a definitive answer either way.

Derek Wyatt
  • 2,697
  • 15
  • 23
  • 1
    This is a slightly different issue. In the question you link to, you have two functions, which would differ only in their return types (`foo(x:Bar):Unit` vs. `foo(x:Bar):Function1[Bar=>Baz,Unit]`) if my reasoning is correct (still not entirely convinced...) – Dirk Aug 24 '11 at 18:25
  • I don't see why the _issue_ is different. The conditions under which the issue is manifested may be different but I think the issue is the same. I've tried all kinds of manipulations but the error never changes. I read that as, overloading is done very early, or takes precedence over "x". – Derek Wyatt Aug 24 '11 at 18:54
  • I'm not sure this is the same. In the scala issue you linked to, it would make sense to have the two functions, as foo() and foo()_ are different, whereas in the current situation, there aren't different ways to express the two possible foo()_ functions. The underlying reason might be the same, but I'm not convinced. I think that was Dirk's point as well, actually. – Henry Henrinson Aug 24 '11 at 21:33