Scala Reassignment To Val Parameter Statistics

EDIT: I keep getting upvotes here. Just for the record, I no longer think this is important. I haven't needed it since I posted it.

I would like to do following in Scala ...

... but I can't beacuse is a val. Is there any way to declare as var?

Note: there are similar questions but in all of them OP just wanted to modify array.

Please do not advise following:

Mutating the input parameters is often seen as bad style and makes it harder to reason about code.

I think it's valid in imperative programming (Scala allows both, right?) and adding something like would just add clutter.

EDIT: Don't misunderstand. I know that strings aren't mutable and I don't want a reference to reference because I don't want to modify data of caller. I just want to modify local reference to string that caller gave me with my string (eg. orig + '/'). I want to modify that value only in scope of current method. Look, this is perfectly valid in Java:

I don't have to create new variable and i don't have to compute i+1 twice.

scalavariablesmethodsparameters

This is an excerpt from the Scala Cookbook (partially modified for the internet). This is Recipe 9.2, “How to use functions as variables (values) in Scala.”

Back to top

Problem

You want to pass a Scala function around like a variable, just like you pass , , and other variables around in an object-oriented programming language.

Back to top

Solution

Use the syntax shown in Recipe 9.1 to define a function literal, and then assign that literal to a variable.

The following Scala code defines a function literal that takes an parameter and returns a value that is twice the amount of the that is passed in:

(i: Int) => { i * 2 }

As mentioned in Recipe 9.1, you can think of the symbol as a transformer. In this case, the function transforms the value to an value that is twice the value of .

You can now assign that function literal to a variable:

val double = (i: Int) => { i * 2 }

The variable is an instance, just like an instance of a , , or other type, but in this case, it’s an instance of a function, known as a function value. You can now invoke just like you’d call a method:

double(2) // 4 double(3) // 6

Beyond just invoking like this, you can also pass it to any method (or function) that takes a function parameter with its signature. For instance, because the method of a sequence is a generic method that takes an input parameter of type and returns a type , you can pass the method into the method of an sequence:

scala> val list = List.range(1, 5) list: List[Int] = List(1, 2, 3, 4) scala> list.map(double) res0: List[Int] = List(2, 4, 6, 8)

Welcome to the world of functional programming.

Back to top

Discussion

You can declare a function literal in at least two different ways. I generally prefer the following approach, which implicitly infers that the following function’s return type is :

val f = (i: Int) => { i % 2 == 0 }

In this case, the Scala compiler is smart enough to look at the body of the function and determine that it returns a value. As a human, it’s also easy to look at the code on the right side of the expression and see that it returns a , so I usually leave the explicit return type off the function declaration.

However, if you prefer to explicitly declare the return type of a function literal, or want to do so because your function is more complex, the following examples show different forms you can use to explicitly declare that your function returns a :

val f: (Int) => Boolean = i => { i % 2 == 0 } val f: Int => Boolean = i => { i % 2 == 0 } val f: Int => Boolean = i => i % 2 == 0 val f: Int => Boolean = _ % 2 == 0

A second example helps demonstrate the difference of these approaches. These functions all take two parameters and return a single value, which is the sum of the two input values:

// implicit approach val add = (x: Int, y: Int) => { x + y } val add = (x: Int, y: Int) => x + y // explicit approach val add: (Int, Int) => Int = (x,y) => { x + y } val add: (Int, Int) => Int = (x,y) => x + y

As shown, the curly braces around the body of the function in these simple examples are optional, but they are required when the function body grows to more than one expression:

val addThenDouble: (Int, Int) => Int = (x,y) => { val a = x + y 2 * a }Back to top

Using a method like an anonymous function

Scala is very flexible, and just like you can define an anonymous function and assign it to a variable, you can also define a method and then pass it around like an instance variable. Again using a modulus example, you can define a method in any of these ways:

def modMethod(i: Int) = i % 2 == 0 def modMethod(i: Int) = { i % 2 == 0 } def modMethod(i: Int): Boolean = i % 2 == 0 def modMethod(i: Int): Boolean = { i % 2 == 0 }

Any of these methods can be passed into collection methods that expect a function that has one parameter and returns a , such as the method of a :

val list = List.range(1, 10) list.filter(modMethod)

Here’s what that looks like in the REPL:

scala> def modMethod(i: Int) = i % 2 == 0 modMethod: (i: Int)Boolean scala> val list = List.range(1, 10) list: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9) scala> list.filter(modMethod) res0: List[Int] = List(2, 4, 6, 8)

As noted, this is similar to the process of defining a function literal and assigning it to a variable. The following function works just like the previous method:

val modFunction = (i: Int) => i % 2 == 0 list.filter(modFunction)

At a coding level, the obvious difference is that is a method defined in a class, whereas is a function that’s assigned to a variable. Under the covers, is an instance of the trait, which defines a function that takes one argument. (The scala package defines other similar traits, including , , and so on, up to .)

Back to top

Assigning an existing function/method to a function variable

Continuing our exploration, you can assign an existing method or function to a function variable. For instance, you can create a new function named from the scala.math.cos method using either of these approaches:

scala> val c = scala.math.cos _ c: Double => Double = <function1> scala> val c = scala.math.cos(_) c: Double => Double = <function1>

This is called a partially applied function. It’s partially applied because the method requires one argument, which you have not yet supplied (more on this in Recipe 9.6).

Now that you have , you can use it just like you would have used :

scala> c(0) res0: Double = 1.0

If you’re not familiar with this syntax, this is a place where the REPL can be invaluable. If you attempt to assign the function/method to a variable, the REPL tells you what’s wrong:

scala> val c = scala.math.cos <console>:11: error: missing arguments for method cos in class MathCommon; follow this method with `_' to treat it as a partially applied function val c = scala.math.cos ^

The following example shows how to use this same technique on the scala.math.pow method, which takes two parameters:

scala> val p = scala.math.pow(_, _) pow: (Double, Double) => Double = <function2> scala> p(scala.math.E, 2) res0: Double = 7.3890560989306495

If this seems like an interesting language feature, but you’re wondering where it would be useful, see Recipe 9.6, “Using Partially Applied Functions”, for more information.

Back to top

Summary notes

  • Think of the symbol as a transformer. It transforms the input data on its left side to some new output data, using the algorithm on its right side.
  • Use to define a method, to create a function.
  • When assigning a function to a variable, a function literal is the code on the right side of the expression.
  • A function value is an object, and extends the traits in the main scala package, such as for a function that takes no parameters.
Back to top

See Also

Back to top

The Scala Cookbook

This tutorial is sponsored by the Scala Cookbook, which I wrote for O’Reilly:

You can find the Scala Cookbook at these locations:

Back to top

0 thoughts on “Scala Reassignment To Val Parameter Statistics”

    -->

Leave a Comment

Your email address will not be published. Required fields are marked *