8

While creating a map of String to partial functions I ran into unexpected behavior. When I create a partial function as a map element it works fine. When I allocate to a val it invokes instead. Trying to invoke the check generates an error. Is this expected? Am I doing something dumb? Comment out the check() to see the invocation. I am using scala 2.7.7

def PartialFunctionProblem() = {
    def dream()() = {
        println("~Dream~");
        new Exception().printStackTrace()
    }
    val map = scala.collection.mutable.HashMap[String,()=>Unit]()
    map("dream") = dream()      // partial function
    map("dream")()              // invokes as expected
    val check = dream()         // unexpected invocation
    check()                     // error: check of type Unit does not take parameters 
}
duplode
  • 33,731
  • 7
  • 79
  • 150
Fred Haslam
  • 8,873
  • 5
  • 31
  • 31
  • Thanks for the help. When I replaced my dream() calls with dream()_ it behaved as I expected. I'll go out and read more on PartialFunctions so I don't misuse the term again. – Fred Haslam May 21 '10 at 00:26

2 Answers2

12

For convenience, Scala lets you omit empty parens when calling a method, but it's clever enough to see that the expected type in the first case is ()=>Unit, so it doesn't remove all the parens for you; instead, it converts the method into a function for you.

In the val check case, however, it looks just like a function call result getting assigned to a variable. In fact, all three of these do the exact same thing:

val check = dream
val check = dream()
val check = dream()()

If you want to turn the method into a function, you place _ after the method in place of the argument list(s). Thus,

val check = dream() _

will do what you want.

Rex Kerr
  • 166,841
  • 26
  • 322
  • 407
5

Well, the problem is that you got it all wrong. :-)

Here are some conceptual mistakes:

def dream()() = {
    println("~Dream~");
    new Exception().printStackTrace()
}

This is not a partial function. This is a curried method with two empty parameter lists which returns Unit.

val map = scala.collection.mutable.HashMap[String,()=>Unit]()

The type of the values in this map is not partial function, but function. Specifically, Function0[Unit]. A partial function would have type PartialFunction[T, R].

map("dream") = dream()      // partial function

What happens here is that Scala converts the partially applied method into a function. This is not a simple assignment. Scala does the conversion because the type inferencer can guess the correct type.

val check = dream()         // unexpected invocation

Here there's no expected type to help the type inferencer. However, empty parameter lists can be ommitted, so this is just a method call.

Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681