On 22.01.2009, at 19:50, Rich Hickey wrote:

>>
>> Does that mean that calling seq on a stream converts the stream into
>> a seq for all practical purposes? That sounds a bit dangerous
>> considering that so many operations in Clojure call seq implicitly.
>> One can easily have a seq "steal" a stream and not notice it before
>> all memory is used up by the seq.
>>
>
> Calling seq on a stream yields a seq that will forever own the stream
> - if you think about it a bit, you'll see why that has to be the case.
>
> OTOH, that seq is lazy, so I'm not sure what the memory issue is.

If my understanding is correct, then

        (def rand-stream (stream (fn [_] (rand))))
        (take 5 rand-stream)

will create a seq on the stream that is referenced by the stream. As  
long as the stream is referenced by a var, the seq will remain  
referenced as well. Seqs being cached, this means that the whole  
random  number sequence will be kept in memory.

The only way to avoid this seems to be not calling any sequence  
function on a stream. I could use for example

(defn take-stream
   [n s]
   (let [iter (stream-iter s)
        eos  (Object.)
        vs   (doall (for [_ (range n)] (next! iter eos)))]
     (do (detach! iter) vs)))

(take-stream 5 rand-stream)

Writing take-stream made me discover another pitfall: the stream  
seems to keep a reference to its iter object as well, meaning that is  
never released without an explicit call to detach!. I had expected to  
be able to create a "local" iter in a let and have it disappear and  
release the stream when it goes out of scope. I guess that would  
require the stream not to keep a reference to the iter, but just a  
flag that an iter exists. Which in turn requires that the iter resets  
the flag when it goes out of scope. I don't even know if that is  
doable in the JVM.

> Again, I don't see the enormous side effect. Steams form a safe,
> stateful pipeline, you'll generally only call seq on the end of the
> pipe. If you ask for a seq on a stream you are asking for a (lazy)
> reification. That reification and ownership is what makes the pipeline
> safe.

Then why not make a pipeline using lazy sequences right from the  
start? I don't see anything that I could do better with streams than  
with lazy sequences.

Konrad.


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to