Reusing Function Values

Function values help create more reusable code and eliminate code duplication. But, embedding a piece of code as an argument to a method doesn’t encourage reuse of that code. It’s easy to avoid that duplication—you can create references to function values and therefore reuse them as well. Let’s look at an example.

Let’s create a class Equipment that expects a calculation routine for its simulation. We can send in the calculation as a function value to the constructor:

FunctionValuesAndClosures/Equipment.scala
 
class​ Equipment(​val​ routine : ​Int​ => ​Int​) {
 
def​ simulate(input: ​Int​) = {
 
print(​"Running simulation..."​)
 
routine(input)
 
}
 
}

When we create instances of Equipment, we can pass in a function value as a parameter to the constructor, like so:

FunctionValuesAndClosures/EquipmentUseNotDry.scala
 
object​ EquipmentUseNotDry ​extends​ App {
 
val​ equipment1 = ​new​ Equipment(
 
{input => println(s​"calc with $input"​); input })
 
val​ equipment2 = ​new​ Equipment(
 
{input => println(s​"calc with $input"​); input })
 
 
equipment1.simulate(4)
 
equipment2.simulate(6)
 
}

Here’s the output:

 
Running simulation...calc with 4
 
Running simulation...calc with 6

In the code, we want to use the same calculation code for both the Equipment instances. Unfortunately, that code is duplicated. The code is not DRY, and if we decide to change the calculation, we’d have to change both. It would be good to create the calculation once and reuse it. We can assign the function value to a val and reuse it like this:

FunctionValuesAndClosures/EquipmentUseDry.scala
 
object​ EquipmentUseDry ​extends​ App {
 
val​ calculator = { input : ​Int​ => println(s​"calc with $input"​); input }
 
 
val​ equipment1 = ​new​ Equipment(calculator)
 
val​ equipment2 = ​new​ Equipment(calculator)
 
 
equipment1.simulate(4)
 
equipment2.simulate(6)
 
}

The output is shown here:

 
Running simulation...calc with 4
 
Running simulation...calc with 6

We stored the function value into a reference named calculator. Scala needed a little help with the type information when we defined this function value. In the earlier example, Scala inferred the parameter input as Int based on the context of the call. However, since we’re defining this function value as stand-alone, we had to tell Scala the type of the parameter. We then passed the name of the reference as an argument to the constructor in the two instances we created.

In the previous example, we created a reference calculator to a function value. This may feel more natural since we’re used to defining references/variables within functions or methods. However, in Scala, we can define full functions within other functions. Thus, there’s a more idiomatic way of achieving the goal of reuse. Scala makes it easy to do the right thing. We can pass in a normal function where a function value is expected.

FunctionValuesAndClosures/EquipmentUseDry2.scala
 
object​ EquipmentUseDry2 ​extends​ App {
 
def​ calculator(input: ​Int​) = { println(s​"calc with $input"​); input }
 
 
val​ equipment1 = ​new​ Equipment(calculator)
 
val​ equipment2 = ​new​ Equipment(calculator)
 
 
equipment1.simulate(4)
 
equipment2.simulate(6)
 
}

We created our calculation as a function and passed in the name of the function as an argument to the constructor when we created those two instances. Scala comfortably treated that as a reference to a function value within the Equipment.

We don’t have to compromise on good design principles and code quality when programming in Scala. On the contrary, it promotes good practices, and we should strive to make use of that when coding in Scala.

Saving away function values in variables and the ability to pass functions are not the only ways to reuse function values, as you’ll see in the next section.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.216.143.65