[Pharo-project] Few more words about Xtreams

Igor Stasenko siguctua at gmail.com
Fri Feb 26 12:52:02 EST 2010


a) A BufferedXtream
can be implemented ultimately as a wrapper stream, so any stream can
be buffered , using

Xtream>>buffered
   ^ self buffered: self preferredBufferSize

Xtream>>buffered: aBufferSize
   ^ (self wrapWith: BufferedXtream) bufferSize: aBufferSize

Xtream>>preferredBufferSize
  ^ 1024

I think there should be an abstract WrapperXtream, from which you can
inherit various kinds of wrappers, like buffering, conversion etc etc.

b) An ascii/binary mode should be deprecated.

The rationale is:
 generic streams, as well as Collections can't say anything about
nature of elements they working with. It could be anyting, like stream
of collections, or stream of arbitrary objects.
Introducing modes at such basic level implying that all streams should
support either of them, and adding unwanted limiting factors and
complexity.
Its not a problem for more specific streams (like file/socket based
ones) to implement these modes (or any other modes) in more robust
manner. But i strongly suggesting to not introduce any modes in base
class(es).
Moreover, a different streams, potentially could support many various
modes they like (compressed, encrypted etc etc). Marking out
ascii/binary modes seems like a discrimination.

But,  for backwards compatibility, we could use wrappers to support
these modes:

Xtream>>ascii
   ^ self wrapWith: AsciiWrapper

AsciiWrapper>>ascii
  ^ self

and by analogy:

Xtream>>binary
   ^ self wrapWith: BinaryWrapper

BinaryWrapper>>binary
   ^ self

this gives us a freedom for any streams to not care about supporting
these modes explicitly, and in case if they care, they could implement
these messages differently.

c) species.
A use of #contentsSpecies again, introducing a limiting factor,
suggesting that all stream elements is going to be of same kind which
could be put into special collection, which can hold only elements of
specific kind like ByteArray or String.

This message used primarily in conjunction with
#readInto:startingAt:count: and #next:putAll:startingAt: for batch
reads/writes
which heavily depending on passing right collection type (you can't
pass OrderedCollection or Set ;).

My own preference is not _asking_ stream (or collection) for species
of its element, but tell it to allocate the buffer (collection) of the
kind it prefers , with given size.
I.e. instead of:

myBuffer := stream contentsSpecies ofSize: 1000.

use:

myBuffer := stream allocateBufferOfSize: 1000.

Then, in most cases, you (as user) would never want to know the
species of elements for a stream, and should not care about allocating
them and knowing their class!

This is one of the patterns i found more flexible and trying to stick
with it everywhere i can. Instead of using:

someClass := object fooClass.

and then, somewhere use:

thing := someClass new.

i using:

thing := object newThing.

Because, by answering a class, you losing a control of the creation
and proper initialization of these instances and by putting this
responsibility onto user, obviously you opening a space for errors.

A simple example, suppose you want to build a tree. As usual, you
giving the user a way to create new nodes, by exposing the class he
should use to create them:

TreeNode>>nodeClass
  ^ TreeNode

now, a user, to create a subnode should do things like:

newNode := node nodeClass new.
newNode parent: node.

While, if you just give a simple #newChild

TreeNode>>newChild
  ^ self class new parent: self

then, user won't care about proper initialization and write just:

newNode := node newChild.

which is more concise, not requires to use intermediate value (node
class) and much more error safe.

-- 
Best regards,
Igor Stasenko AKA sig.




More information about the Pharo-dev mailing list