i read http://www.naildrivin5.com/scalatour/wiki_pages/ScalaFunctions. In that post
he specified Methods and functions are not the same thing
. But he didn't explain anything
about it. can anyone explain what he was trying to say.
views:
690answers:
3One big practical difference between a method and a function is what return
means. return
only ever returns from a method. For example:
scala> val f = () => { return "test" }
<console>:4: error: return outside method definition
val f = () => { return "test" }
^
Returning from a function defined in a method does a non-local return:
scala> def f: String = {
| val g = () => { return "test" }
| g()
| "not this"
| }
f: String
scala> f
res4: String = test
Whereas returning from a local method only returns from that method.
scala> def f2: String = {
| def g(): String = { return "test" }
| g()
| "is this"
| }
f2: String
scala> f2
res5: String = is this
Jim has got this pretty much covered in his blog, but I'm posting a briefing here for reference.
A function is an object that includes one of the FunctionX
traits, such as Function0
, Function1
, Function2
, etc. It might be including PartialFunction
as well, which actually extends Function1
.
Let's see the type signature for one of these traits:
trait Function2[-T1, -T2, +R] extends AnyRef
This trait has one abstract method (it has a few concrete methods as well):
def apply(v1: T1, v2: T2): R
And that tell us all that there is to know about it. A function has an apply
method which receives N parameters of types T1, T2, ..., TN, and returns something of type R
. It is contra-variant on the parameters it receives, and co-variant on the result.
That variance means that a Function1[Seq[T], String]
is a subtype of Function1[List[T], AnyRef]
. Being a subtype means it can be used in place of it. One can easily see that if I'm going to call f(List(1, 2, 3))
and expect an AnyRef
back, either of the two types above would work.
Now, what is the similarity of a method and a function? Well, if f
is a function and m
is a method local to the scope, then both can be called like this:
val o1 = f(List(1, 2, 3))
val o2 = m(List(1, 2, 3))
These calls are actually different, because the first one is just a syntactic sugar. Scala expands it to:
val o1 = f.apply(List(1, 2, 3))
Which, of course, is a method call on object f
. Functions also have other syntactic sugars to its advantage: function literals (two of them, actually) and (T1, T2) => R
type signatures. For example:
val f = (l: List[Int]) => l mkString ""
val g: (AnyVal) => String = {
case i: Int => "Int"
case d: Double => "Double"
case o => "Other"
}
Another similarity between a method and a function is that the former can be easily converted into the latter:
val f = m _
Scala will expand that, assuming m
type is (List[Int])AnyRef
into (Scala 2.7):
val f = new AnyRef with Function1[List[Int], AnyRef] {
def apply(x$1: List[Int]) = this.m(x$1)
}
On Scala 2.8, it actually uses an AbstractFunction1
class to reduce class sizes.
Notice that one can't convert the other way around -- from a function to a method.
Methods, however, have one big advantage (well, two -- they can be slightly faster): they can receive type parameters. For instance, while f
above can necessarily specify the type of List
it receives (List[Int]
in the example), m
can parameterize it:
def m[T](l: List[T]): String = l mkString ""
I think this pretty much covers everything, but I'll be happy to complement this with answers to any questions that may remain.