Streams provide a powerful abstraction for a number of data structures. Concepts like current position, writing the next position, and changing the way you view a data structure when convenient combine to let you write compact, powerful code. The last example is taken from the actual Smalltalk source code—it shows a general method for making an object print itself onto a string.
printString [ | stream | stream := WriteStream on: (String new). self printOn: stream. ^stream contents ]
This method, residing in Object, is inherited by every
class in Smalltalk. The first line creates a WriteStream
which stores on a String whose length is currently 0
String new simply creates an empty string. It
then invokes the current object with
printOn:. As the
object prints itself to “stream”, the String grows to accommodate
new characters. When the object is done printing,
the method simply returns the underlying string.
As we've written code, the assumption has been that
printOn: would go to the terminal. But replacing a stream
to a file like /dev/tty with a stream to a data
String new) works just as well. The last line
tells the Stream to return its underlying collection, which will
be the string which has had all the printing added to it. The
result is that the
printString message returns an object of
the String class whose contents are the printed representation
of the very object receiving the message.