I will ask about this with an example of Scala, but it is possible that this affects other languages ββthat allow hybrid imperative and functional styles.
Here is a short example ( UPDATED , see below):
def method: Iterator[Int] { // construct some large intermediate value val huge = (1 to 1000000).toList val small = List.fill(5)(scala.util.Random.nextInt) // accidentally use huge in a literal small.iterator filterNot ( huge contains _ ) }
Now iterator.filterNot works lazily and it's great! As a result, we expect the returned iterator to not consume much memory (indeed, O (1)). Unfortunately, we made a terrible mistake: since filterNot lazy, it refers to the literal huge contains _ function.
Thus, although we thought that this method would require a large amount of memory during its operation and that this memory could be freed immediately after the method was completed, in fact the memory was stuck until we forget the returned Iterator .
(I just made a mistake that took a long time to track down! You can catch such things by looking at the heaps of the dump ...)
What are the best methods to prevent this problem?
It seems that the only solution is to thoroughly test functional literals that go beyond the scope and that capture intermediate variables. This is a little inconvenient if you create a lax fee and plan to return it. Can anyone think of some good tricks, Scala-specific or others, that avoid this problem and allow me to write good code?
UPDATE: the example I gave earlier was dumb, as the huynhjl answer below shows. It was:
def method: Iterator[Int] { val huge = (1 to 1000000).toList // construct some large intermediate value val n = huge.last // do some calculation based on it (1 to n).iterator map (_ + 1) // return some small value }
In fact, now that I understand a little better how it works, I'm not so worried!
scope scala lazy-evaluation function-literal
Scott Morrison
source share