This is an excerpt from the 1st Edition of the Scala Cookbook (partially modified for the internet). This is Recipe 4.8, “How to assign a Scala class field to a block or function.”
Problem
You want to initialize a field in a Scala class using a block of code, or by calling a function.
Solution
Set the field equal to the desired block of code or function. Optionally, define the field as lazy
if the algorithm requires a long time to run.
In the following example, the field text
is set equal to a block of code, which either returns (a) the text contained in a file, or (b) an error message, depending on whether the file exists and can be read:
class Foo { // set 'text' equal to the result of the block of code val text = { var lines = "" try { lines = io.Source.fromFile("/etc/passwd").getLines.mkString } catch { case e: Exception => lines = "Error happened" } lines } println(text) } object Test extends App { val f = new Foo }
Because the assignment of the code block to the text
field and the println
statement are both in the body of the Foo
class, they are in the class’s constructor, and will be executed when a new instance of the class is created. Therefore, compiling and running this example will either print the contents of the file, or the “Error happened” message from the catch
block.
In a similar way, you can assign a class field to the results of a method or function:
class Foo { import scala.xml.XML // assign the xml field to the result of the load method val xml = XML.load("http://example.com/foo.xml") // more code here ... }
Discussion
When it makes sense, define a field like this to be lazy, meaning it won’t be evaluated until it is accessed. To demonstrate this, ignore the potential for errors and shorten the class to this:
class Foo { val text = io.Source.fromFile("/etc/passwd").getLines.foreach(println) } object Test extends App { val f = new Foo }
When this code is compiled and run on a Unix system, the contents of the /etc/passwd file are printed. That’s interesting, but notice what happens when you change the block to define the text field as lazy
:
class Foo { lazy val text = io.Source.fromFile("/etc/passwd").getLines.foreach(println) } object Test extends App { val f = new Foo }
When this code is compiled and run, there is no output, because the text
field isn’t initialized until it’s accessed. That’s how a lazy
field works.
Defining a field as lazy
is a useful approach when the field might not be accessed in the normal processing of your algorithms, or if running the algorithm will take a long time, and you want to defer that to a later time.
this post is sponsored by my books: | |||
#1 New Release |
FP Best Seller |
Learn Scala 3 |
Learn FP Fast |