liveBook · Manning

Lazy I/O

As explained in Functional Programming in Scala, Second Edition

Lazy I/O represents input or output operations as deferred computations whose effects occur only when the representation is evaluated.

Lazy I/O represents a file-backed stream as an IO[LazyList[String]], recovering composable stream operations while deferring reads until elements are forced. section 15.1

Listing 15.1 Counting line numbers in imperative style
def linesGt40k(filename: String): IO[Boolean] = IO:
  val src = io.Source.fromFile(filename)             #1
  try
    var count = 0
    val lines: Iterator[String] = src.getLines()     #2
    while count <= 40000 && lines.hasNext do
      lines.next                                     #3
      count += 1
    count > 40000
  finally src.close

The imperative alternative opens a file, advances an iterator, stops early at a limit, and closes the resource explicitly. section 15.1

A tempting lazy representation

A lines function can convert getLines() into a LazyList and append a deferred close operation. This supports operations such as filter, take, map, and indexOfSlice without reading the entire file immediately. section 15.1

The representation remains unsafe when stream traversal is not tightly controlled:

  • Early termination can skip the appended close operation and leak the file resource. section 15.1
  • Repeated traversal can retain all elements or attempt reads from a closed file, depending on memoization. section 15.1
  • Concurrent forcing can produce unpredictable behavior because stream evaluation performs I/O effects. section 15.1

How Functional Programming in Scala, Second Edition covers it

How deep it goes
Defines the representation and demonstrates its resource, reuse, memoization, and concurrency hazards.
Examples
Uses line counting, filtering nonempty lines, bounded searches, and a file-to-LazyList implementation.
What it assumes
Assumes LazyList and IO while contrasting them with imperative iterators, loops, and explicit file closing.
What you can do after
Evaluate lazy I/O as a compositional technique while recognizing when deferred effects compromise resource safety.
How it connects
Connects LazyList, IO, stream processing, resource safety, memoization, and incremental I/O.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Functional Programming in Scala, Second Edition. The section links point to the parts of the book it draws on.