Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't scala infer the type of the omitted parameters in partial application?

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)
like image 355
Ashkan Kh. Nazary Avatar asked Oct 11 '12 16:10

Ashkan Kh. Nazary


2 Answers

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.

like image 116
nonVirtualThunk Avatar answered Oct 23 '22 16:10

nonVirtualThunk


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.)

like image 34
som-snytt Avatar answered Oct 23 '22 16:10

som-snytt