Best practices

Referential transparency is a key concept in functional programming. If most of your program uses pure functions, then it becomes much easier to do the following:

  • Understand what a program is doing: You know that the function's return value only depends on its arguments. You do not have to think about what the state of this or that variable is in this or that context. You just have to look at the arguments.
  • Test your functions: I will restate this point—the function's return value only depends on its argument. Testing it is very simple; you can try different argument values and confirm that the return value is what you expect.
  • Write multithreaded programs: Since a pure function's behavior does not depend on a global state, you can execute it in parallel on multiple threads or even on different machines. The return values will not change. As our CPUs are built with more and more cores these days, this will help you write faster programs.

However, it is not possible to only have pure functions in a program because, in essence, a program must interact with the outside world. It has to print something, read some user input, or save some state in a database. In functional programming, the best practice is to use pure functions in the majority of the code base and to push the impure side-effecting functions to the boundaries of the program.

For instance, in Chapter 2Developing a Retirement Calculator, we implemented a retirement calculator that mostly uses pure functions. One side-effecting function was the println call in the SimulatePlanApp object, which was at the boundaries of the program. There were other side effects in EquityData.fromFile and InflationData.fromFile; these functions are for reading files. However, the resource files can never change for the duration of the program. For a given filename, we would always get the same file content, and we could substitute the return value of fromFile in all calls without changing the program's behavior. In this case, the side effect of reading a file is not observable, and we can consider theses file-reading functions as being pure. Another side-effecting function was strMain because it could throw exceptions. In the rest of this chapter, we will see why throwing exceptions break referential transparency, and we will learn how to replace it with better functional programming structures.

An impure function fulfills the following two criteria:
  • It returns Unit.
  • It does not take any arguments but returns a type. Since it returns something that cannot be obtained by using its arguments, it must be using a global state.

Note that a pure function can use mutable variables or side effects inside the body of the function. As long as these effects are not observable by the caller, we consider the function pure. In the Scala SDK, many pure functions are implemented using mutable variables to improve performance. Look, for the instance, at the following implementation of TraversableOnce.foldLeft:

def foldLeft[B](z: B)(op: (B, A) => B): B = {
var result = z
this foreach (x => result = op(result, x))
result
}
..................Content has been hidden....................

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