In the following code example, I do not understand why the function fun can be passed as an argument to the method addAction. The method fun is of type Unit, while the method addAction expects a function of type () => Unit.
If fun is of type () => Unit, then why does the compiler complain that fun is of type Unit, when I try to add fun to the actions list: actions = fun :: actions?
package myscala
object MyScala {
def fun() { println("fun1 executed.") }
def addAction(a: () => Unit) {
actions = a :: actions
}
var actions: List[() => Unit] = List()
def main(args: Array[String]) {
// the following line would produce a compiler error (found: Unit, required: () => Unit), it's OK
// actions = fun :: actions
actions = (() => fun) :: actions // OK
// I would expect the same compiler error here (found: Unit, required: () => Unit), but it's OK why?
addAction(fun)
actions.foreach(_()) // prints twice "fun1 executed"
}
}
Take this as an introductory example:
Both lines compile and (thanks to type inference) they look equivalent. However
a1is of typeUnitwhilea2is of type() => Unit… How is this possible?Since you are not explicitly providing type of
a1, compilers interpretsfunas a methodfuncall of typeUnit, hence the type ofa1is the same as type offun. It also means that this line will print fun1 executed.However,
a2has explicitly declared type of() => Unit. The compiler helps you here and it understands that since the context requires a function of type() => Unitand you provided a method matching this type, it shouldn’t call that method, but treat it as first class function!You are not doomed to specify type of
a1explicitly. Saying:Do you now understand where your problem is?