Search code examples
scalastreamimmutabilitymemoization

How Immutability is Achieved in Scala Streams?


It might become silly but I have question regarding to Scala Stream evaluation in immutable fashion.

Lets say I have a Stream like this (All lines executed in repl);

val a = Stream(1,2,3,4,5,6,7,8,9,10);

a: scala.collection.immutable.Stream[Int] = Stream(1, ?)

When I run following lines;

a(3);
a

I get ;

scala.collection.immutable.Stream[Int] = Stream(1, 2, 3, 4, ?)

My first question is how this immutable structure gets changed ? I mean if did like this (assuming variable 'a' defined as 'var'); a = a(3) I might expect such result.

My other question is when I run following lines;

val a = Stream(1,2,3,4,5,6,7,8,9,10);

a: scala.collection.immutable.Stream[Int] = Stream(1, ?)

val b = a;

b: scala.collection.immutable.Stream[Int] = Stream(1, ?)

b(5);

scala.collection.immutable.Stream[Int] = Stream(1, 2, 3, 4, 5, 6, ?)

a

scala.collection.immutable.Stream[Int] = Stream(1, 2, 3, 4, 5, 6, ?)

As you can see in last part after executing 'a', its seems changed again.

If I try this kind of assignment with List type (as far as I know List is strict version of Stream) and do some transformation like drop,take etc.)

val a = List(1,2,3,4,5)
val b = a;
b.dropRight(1)

variable 'a' and 'b' still is still List(1,2,3,4,5)

So how this happened and what is the point that I'm missing ?


Solution

  • Scala Streams provide memoization - they are like lazy lists, but once elements have been generated, they are stored for future retrieval.

    So when you "force" the Stream b to evaluate some of its elements by requesting the element at index 5, the original Stream a (which is the same Stream object) is also forced.

    Key point: doing this doesn't modify the stream (it remains immutable), it just changes which elements have been evaluated and are memoized.

    Your Stream(1,?) and Stream(1,2,3,4,5,6,?) are the same stream, just evaluated to a different degree:

    scala> val a = Stream(1,2,3,4,5,6,7,8,9,10);
    a: scala.collection.immutable.Stream[Int] = Stream(1, ?)
    
    scala> val b = a
    
    scala> a(3)
    res9: Int = 4
    
    scala> a
    res10: scala.collection.immutable.Stream[Int] = Stream(1, 2, 3, 4, ?)
    
    scala> b
    res11: scala.collection.immutable.Stream[Int] = Stream(1, 2, 3, 4, ?)
    
    scala> Stream(1,2,3,4,5,6,7,8,9,10) == a
    res12: Boolean = true
    
    scala> Stream(1,2,3,4,5,6,7,8,9,10) == b
    res13: Boolean = true