Stream.iterableStream bit scary.

30 views
Skip to first unread message

Clinton Selke

unread,
Aug 19, 2015, 8:15:12 AM8/19/15
to Functional Java
Say we start with an java.util.ArrayList being converted to a stream from a call to foo():

  private P1<Stream<Integer>> longTermStream;

  public void foo() {
      ArrayList<Integer> myInts = new ArrayList<>();
      myInts.add(1);
      myInts.add(2);
      myInts.add(3);
      myInts.add(4);
      Stream<Integer> someStream = Stream.iterableStream(myInts);
      longTermStream = someStream.tail()._1().tail();
  }

Stream.iterableStream() uses Stream.iteratorStream() internally which is fine.
And Stream.iteratorStream() is memoizing the result of each call to Iterator.next() which is also fine.
However Stream.Cons uses a WeakReference for the tail meaning that this might be more eagerly
freed by the garbage collector at some point in time, which is fine for Stream build from pure stuff
(because it can be recalculated and recached without changing the result).

But an Iterator is impure!

And I was sure I had a problem with this before on an older version of FJ. (Not sure if its been discussed/fixed already)

After calling foo(), printing the value of longTermStream to give would give <3,4>. But then get the program to do something else
non-related for a while and come back the the longTermStream value 30 minutes later,
... then print out its value BOO HISS CRASH  NoSuchElementException 
The cache gets clears and the Iterator gets called again even though its reached the end of its iterating.

I think I was using FJ 3.0 when I had this problem. Its not a problem if the Stream is used and discarded straight away, and maybe
that is the intension when using Streams, and use another data type for long term storage.

Has anyone else noticed or had this problem before?

Clinton.

Mark Perry

unread,
Aug 19, 2015, 9:58:37 AM8/19/15
to Functional Java
Clinton,

I have had this problem surface in a number of ways:
- your problem where the stream weak references get garbage collected when the stream was created from an iterableStream or iteratorStream
- The data structure used to create the stream changes and accessing the stream produces ConcurrentModificationException
- multiple streams are created from the same iterator producing unusual behaviour.

Stream's iterableStream and iteratorStream are definitely scary due to the mutation involved.  I typically create a List and then stream the list.  This can then be used reliably to create streams and used in the stream functions.

I have cursed these two methods previously and they seem problematic given Streams lazy nature.  List has iterableList, but this causes fewer problems due to eagerness.  I'd say any mutable structure can have this problem in the presence of multiple threads.

Mark



Reply all
Reply to author
Forward
0 new messages