I’d like to use the term
delayed evaluation to cover following two features in scala:
lazy var/val and
byname parameter. They are not quite related to each other, but both are to postpone the evaluation of a given expression or block for the final result.
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.
At present, I think its useful in following scenarios:
It makes sense to use
lazy on a class field if its initialization requires a long time to run, and we don’t want to do the job when we instantiate the class until we actually use the field.
In above example, the initialization of
text needs to retrieve the contents of the text file
/etc/passwd. But 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.
Sometimes we need to initialize fields in a specific order because they have dependency on the other. Then we may produce following ugly codes:
In this spark-streaming demo, the initialization of
ssc depends on that of
sc, which further depends on
conf. We operate the initialize manually, thus we define these fields with
var, and implement the lazy initialization in getters. The shortcoming is obvious, we have to restrict the access of these field through getters, otherwise we may get the null-valued ones! Moreover, defining
var to these fields is not best-practice since they are readonly after initialization. A modified version via
lazy val/var is as follows:
What if a
lazy field depends on a
non-lazy var, which is not properly initialzed? Can the instance be re-used after some
NullPointerException-like error raised? This seems no problem as scala provides a tricky, as @ViktorKlang posted on Twitter:
Little known Scala fact: if the initialization of a lazy val throws an exception, it will attempt to reinitialize the val at next access.
You can check the details here: http://scalapuzzlers.com/#pzzlr-012
The by-name parameter can be considered equivalent to
() => Int, which is a
Function type that takes a Unit type argument. Besides from normal functions, it can also be used with an
apply to make interesting block-like calls.
curry, we re-implement a while-loop in above example.