blue-sky
blue-sky

Reputation: 53816

Function is not being lazily evaluated

In below code I'm testing my understanding of Scala lazy evaluation.

I'm attempting process a collection just once within a function definition. But as can be seen below processMap is invoked multiple tiems. Should it not just be invoked once ?

  val a = Array( ("1" , "1") , ("2" , "2"))       //> a  : Array[(String, String)] = Array((1,1), (2,2))

  def toLazyMapDef(aparam : Array[(String, String)]) = {
    lazy val toMap = processMap(aparam)
    toMap
  }                                               //> toLazyMapDef: (aparam: Array[(String, String)])scala.collection.immutable.Ma
                                                  //| p[String,String]
  def processMap(aparam : Array[(String, String)]) = {

    println("in processMap")
    aparam.toMap
  }                                               //> processMap: (aparam: Array[(String, String)])scala.collection.immutable.Map[
                                                  //| String,String]

  println(toLazyMapDef(a))                        //> in processMap
                                                  //| Map(1 -> 1, 2 -> 2)
  println(toLazyMapDef(a))                        //> in processMap
                                                  //| Map(1 -> 1, 2 -> 2)
  println(toLazyMapDef(a))                        //> in processMap
                                                  //| Map(1 -> 1, 2 -> 2)

Upvotes: 1

Views: 121

Answers (1)

Ashalynd
Ashalynd

Reputation: 12563

Here, the lazy val toMap is an internal variable for the function. It is not preserved between the function calls. This might be a better example (we have lazy val as a class member, and we can demonstrate that it's only evaluated once):

case class LazyMapDemo(aparam : Array[(String, String)]) {
    lazy val toMap = processMap(aparam)
    def giveLazyMap = toMap
    def processMap(aparam : Array[(String, String)]) = {
      println("in processMap")
      aparam.toMap
   }
  }    

scala> val a = Array( ("1" , "1") , ("2" , "2"))
a: Array[(String, String)] = Array((1,1), (2,2))

scala> val ld = LazyMapDemo(a)
ld: LazyMapDemo = LazyMapDemo([Lscala.Tuple2;@63f5faaa)

scala> ld.toMap
in processMap
res0: scala.collection.immutable.Map[String,String] = Map(1 -> 1, 2 -> 2)

scala> ld.toMap // processMap not called
res1: scala.collection.immutable.Map[String,String] = Map(1 -> 1, 2 -> 2)

scala> ld.giveLazyMap // processMap not called
res2: scala.collection.immutable.Map[String,String] = Map(1 -> 1, 2 -> 2)

Upvotes: 4

Related Questions