Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VarArgs A* vs Seq[A] parameters to function

Tags:

scala

I'm using Scala 2.11 . If I create a function like :

def func1 (a: Int* ) : Int = a.reduce(_+_)

I call it using

func1(1,2,3,4)
// 10
func1(Seq(1,2,3,4) : _*)
//10

which is fine.

But when I try to define a function literal like :

val func2:(Int*) => Int = _.reduce(_+_)

I get an error saying :

<console>:5: error: type mismatch;
 found   : Int* => Int
 required: Seq[Int] => Int
  lazy val $result = INSTANCE.`func2`

Why does it want a Seq[Int] in the second case but not in first though the definition is the same?

How are the varargs being passed in the first case such that reduce is able to get invoked over them?

like image 348
philantrovert Avatar asked Sep 06 '17 09:09

philantrovert


1 Answers

Scala makes a distinction between methods and functions. Your func1 is a method whose parameter is repeated, and this is desugared under the hood into a simple Seq. On the other hand, your func2 is a function, and repeated parameters are not allowed in that context.

If the compiler expects a function but is given a method instead, it performs eta-expansion. For example, method def(s: String) = s is turned into a function (s: String) => s. I'm saying this to make a point that distinction between methods and functions is very clear and very important.

Note that the link I provided says "Function Declarations and Definitions", which is a kind of clumsy naming, since it's actually talking about methods, not functions. Function is a value just like any other and it can be e.g. kept in a collection or returned from another function. Methods can't.

One final comment and I'm done: don't make a common mistake and think "def is method, val is function". Function can also be defined using a def instead of val, in which case it's still a function value, but it's evaluated at the point of usage instead of point of declaration. Best way to differentiate methods from functions is to check for the parameters: def foo(someParameter: X): Y is a method. Functions cannot have the "(someParameter: X)" part. Instead, function is just a value, and its type is X => Y:

// method
def foo(x: X): Y = // some code that returns Y

// function
def foo: X => Y = (x: X) => // some code that returns Y

I deliberately used def for function too to make a point (to prevent readers from making the val-def mistake), but it's more common to define functions using val.

like image 90
slouc Avatar answered Nov 14 '22 22:11

slouc