scalapass-by-name

Use of Scala by-name parameters


I am going through the book "Functional Programming in Scala" and have run across an example that I don't fully understand.

In the chapter on strictness/laziness the authors describe the construction of Streams and have code like this:

sealed trait Stream[+A]
case object Empty extends Stream[Nothing]
case class Cons[+A](h: () => A, t: () => Stream[A]) extends Stream[A]

object Stream {
    def cons[A](hd: => A, tl: => Stream[A]) : Stream[A] = {
        lazy val head = hd
        lazy val tail = tl
        Cons(() => head, () => tail)
    }
    ...
}

The question I have is in the smart constructor (cons) where it calls the constructor for the Cons case class. The specific syntax being used to pass the head and tail vals doesn't make sense to me. Why not just call the constructor like this:

Cons(head, tail)

As I understand the syntax used it is forcing the creation of two Function0 objects that simply return the head and tail vals. How is that different from just passing head and tail (without the () => prefix) since the Cons case class is already defined to take these parameters by-name anyway? Isn't this redundant? Or have I missed something?


Solution

  • The difference is in => A not being equal to () => A.

    The former is pass by name, and the latter is a function that takes no parameters and returns an A.

    You can test this out in the Scala REPL.

    scala> def test(x: => Int): () => Int = x
    <console>:9: error: type mismatch;
     found   : Int
     required: () => Int
           def test(x: => Int): () => Int = x
                                            ^
    

    Simply referencing x in my sample causes the parameter to be invoked. In your sample, it's constructing a method which defers invocation of x.