2
votes
class A {
  def a(): Unit = ()
  def b[T](f: A => T): T = f(new A())
  def c(): Unit = b { _.a() }
  def d(): Boolean = b { w => w.a(); true }
//def e(): Boolean = b { _.a(); true } // does not compile - why not, if c compiles?
}

In the e() method of the above class, I thought the compiler would be able to infer the type of "_" as it does in c(). However, with scala 2.11.7, e() results in a "missing parameter type for expanded function. Why? Is it something the compiler ought to be able to (=compiler bug) or is the compiler correct in complaining?

2
Short answer: because 'e' does not give a clue about what the expression "_.a()" returns. In the 'c' method, you have clearly defined that the return type of the expression should be Unit, so the compiler has more information. - Felix

2 Answers

2
votes

I think this is because b { _.a(); true } get's translated by compiler into b { w => { w.a() }; true }, instead of intended b { w => { w.a(); true } }. So it computes the whole expression and tries to pass the expression of type Boolean to b instead of A => Boolean. At least that's the only explanation I see, unfortunately I do not know how to check that. Compiler's error seems to be quite honest in trying to say this.

Overall you should not use _ wildcard with complex expressions. They are designed only for simple ones

I also think @Felix comment to your question is correct as well - partially it is the problem also. Compiler has ambiguity: T can be Unit or Boolean, and it just solves it incorrectly. Unfortunately it doesn't help even if you define b to accept A => Boolean

P.S. By the proper compiler message I meant this one:

Error:(24, 36) type mismatch;
 found   : Boolean(true)
 required: Main.A => Boolean
    def e(): Boolean = bb { _.a(); true } // does not compile - why not, if c compiles?
                               ^
0
votes

Firstly, I don't think it's a bug of scala compiler.

for the function d(), it should be expanded as:

def d(): Boolean = b { w => {w.a(); true} }

not

def d(): Boolean = b { {w => w.a()}; true } 

so maybe it will cause some ambiguities.

for the function e(), because compiler don't know what's specified type of wildcard _.

The example:

scala> def f(s: String): String = s
f: (s: String)String

scala> List("foo", "bar").map(f(_.toUpperCase))
<console>:12: error: missing parameter type for expanded function ((x$1) => x$1.toUpperCase)

scala> List("foo", "bar").map(i => f(i.toUpperCase))
res3: List[String] = List(FOO, BAR)

because for anoymous function, the compiler can't infer what's type of wildcard _.

def e(): Boolean = b { _.a(); true } 

the compiler don't know what's the type of _ in the above code.

because it can be translated as:

def e(): Boolean = b {{_.a()}; true } 

or:

def e(): Boolean = b {{x => x.a()}; true }