Experience with Java taught me to loath ethe "do I/O
by composing lots of little wrappers" approach for
several reasons:
��- the fact that the commonest case was not the
���� default case, so that simple obvious code was
���� somewhere between disgracefully slow and wrong
��- the extra complexity needed to get it right
���� (having to know a plethora of wrapper classes
���� instead of just getting sensible defaults)
��- the poor performance.

In my own Smalltalk system I hewed to the ANSI
Smalltalk standard and if you do
������ FileStream read: aFileName
or�� FileStream write: aFileName
you get a text file using the encoding set by
your environment's locale, the native line ending
convention, Simple, easy, and leaves Java's
I/O performance in the dust.

Of course wrappers are available for the rare
cases when you need them, but you don't _have_
to use them.�� One reason this matters is that
there are two ways to write a stream:

�� s2 := WrapperClass on: s1
������ -- closing s2 just closes s2, not s1.
�� s2 := WrapperClass onOwn: s1
������ -- closing s2 closes s1 as well

And yes, both of these *are* used.


On 24 June 2018 at 04:53, Sven Van Caekenberghe <sven@stfx.eu> wrote:
Peter,

> On 23 Jun 2018, at 15:39, Peter Uhn��k <i.uhnak@gmail.com> wrote:
>
> Hi,
>
> I'm starting to familiarize myself with new streams, and one thing I've noticed is the removal of #lineEndConvention (which I use all the time).
>
> So a statement like this
>
> aFile writeStreamDo: [ :stream |
>�� �� �� ��stream lineEndConvention: #lf.
>�� �� �� ��stream << '...'
> ].
>
> has to be written like so
>
> aFile writeStreamDo: [ :rawStream | |stream|
>�� �� �� ��stream := (ZnNewLineWriterStream on: rawStream) forLf.
>�� �� �� ��stream << '...'
> ].
>
> which feels very messy because I am mixing writing with the configuration. And I don't even take account for buffered/encoded decorators. Plus it increases the incidental complexity -- I need another variable, and I can accidentally write to the wrong stream, etc.
>
> Would a method like #writeStream:do: (or #writeStreamTransform:do:) make sense? E.g.
>
> aFile writeStreamTransform: [ :stream | (ZnNewLineWriterStream on: stream) ] do: [ :stream |
>�� �� �� ��stream << '...'
> ]
>
> To separate the composition from the usage?
>
> Thanks,
> Peter

The goals of the 'new' (they have existed for quite a while) streams is to go from single big complex do all classes and replace that with a composition of much simpler single purpose classes. Another goal is to reduce the API so that it becomes easier to create new stream classes. Of course, a consequence is that you need composition to get the functionality you want. But I think you understand the tradeoff.

If the mixing of configuration/setup with writing/reading bothers you, then I would suggest using two methods. One that does only the writing/reading assuming a limited API, and another that does the configuration/setup, using composition.

Note that the streams that you get already are a composition (most often a BinaryFileStream wrapped in a Buffered stream wrapped in a Encoding/Decoding stream). EOL translation is not a standard part of that. But there is quite some system code that does uses EOL translation.

Sven