consider this :
scala> def sum(x:Int,y:Int) = x+y
sum: (x: Int, y: Int)Int
scala> sum(1,_:String)
<console>:9: error: type mismatch;
found : String
required: Int
sum(1,_:String)
Apparently Scala is very well aware of the exact type of _
in sum(1,_)
but you have to say sum(1,_:Int)
. Why ?
Apparently Scala randomly(?) picks one:
scala> def sum(x:Int,y:String) = 1
sum: (x: Int, y: String)Int
scala> def sum(x:Int,y:Double) = 1
sum: (x: Int, y: Double)Int
scala> class Ashkan
defined class Ashkan
scala> sum(1,_:Ashkan)
<console>:10: error: type mismatch;
found : Ashkan
required: Double
sum(1,_:Ashkan)
Judging from this issue, it sounds like they could do it, but for the general case it would be too complex relative to the benefits it would provide. The reason it would be complex generally, would be the possibility of overloaded methods. In the case where you also had:
def sum (x : Int , y : Double ) = x + y
in scope, it would be ambiguous which function you meant without the type specification. In the case where there is no overloading, the type inference could easily figure it out, but I get the sense they don't feel it is worth it to provide for that specific case.
In short, it sounds like it is a practical, as opposed to theoretical limitation.
I believe the error message is generated by simply grabbing the first function with the appropriate name and arity, which in the case of a non-overloaded function gives the impression that it has reasoned out the types fully.
I would suggest that it is an extension of this side-bar or box in The Good Book, which expresses the Principle of Least Surprise:
http://www.artima.com/pins1ed/functions-and-closures.html#8.7
Or let's not call it "Least Surprise," but the lesser of two surprises.
Consider the following case where you're asking the compiler to pick between two inherited functions. If normal rules for overloading apply, it will pick the method defined in the subclass. But is that a good policy?
scala> class Foo {
| def f(x: Int, y: Int) = x + y
| }
defined class Foo
scala> class Bar extends Foo {
| def f(x: Int, y: String) = x + y.toInt
| }
defined class Bar
scala> class Baz extends Bar {
| val f = super.f(1, _) // overloading says f(Int,String), did you mean it?
| }
In an object-oriented world, there are too many ways to surprise yourself, so there is a small tax to pay. The sanity tax.
(Note that in this example, it's possible for overloading resolution to kick in, but by requiring you to specify f(1, _: MyWhatever)
, we've defined what applicability means.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With