Imagine a box of tissue: Each time you pull out a tissue, the next one becomes available. Stream objects represent a means of accessing every member of a collection one-by-one as if they were being pulled out of a box of tissue.
The interface to a StreamObject has two methods. One for getting the value at the current position in the stream (called item() or value()) and another for getting a StreamObject that represents the next position in the stream (called next() or tail()). StreamObjects are LazyObjects which means that they use LazyEvaluation to calculate both value() and next(). This makes StreamObjects able to do things that normal ExternalIterators (and that is what they really are) cannot. For instance, a StreamObject can represent an infinite collection such as a stream of random numbers or the set of all integers. Also, a stream is guaranteed to yield the same set of successors every time it is accessed, so the same stream can be saved and passed from client to client even if the collection it came from changes. Of course this is not always a desirable quality but the original collection can always generate a new stream that represents its current state. LazyEvaluation also prevents the StreamObject from doing expensive calculations (like accessing a database to obtain a value for the value() method) unless they are actually needed.
But an ExternalIterator can use LazyEvaluation, too. For example, the Stream class in Smalltalk is an ExternalIterator (see subclass ReadStream?) but Random is a Stream that generates an infinite stream of random numbers. So they really aren't that different.
Functional streams yield the same set of successors every time they are accessed, but it seems to me that a stream OBJECT would not. So the name of this page doesn't seem quite right. --
The intent of a StreamObject is that it would imitate a Functional stream exactly and thereby provide the same advantages. I believe that you are correct that a StreamObject is an ExternalIterator that uses LazyEvaluation and has the same interface as a Functional stream. If a StreamObject implemented CallByNeed semantics (presumably through caching) then it would, indeed, return the same set of successors every time it was accessed. However, if the underlying collection were to change during the initial traversal, the StreamObject would fail to reproduce the sequence that the collection held at the time the StreamObject was created. -- PhilGoodwin