[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: output stream API




>> 1. One specific thing that I just tripped over: The return values of
>> output-bytes, output-char etc. are unspecified. Did I miss
>> something, or shouldn't they rather return the new stream, as a
>> functional interface would?

>
> But there is no "new" stream---output streams are imperative.  What
> would be the point?

Example (?) for functional output streams: A pretty printer take an object to pieces,
produces an output stream for each piece, and composes its return value by
combining these streams---depending on the properties of all pieces and all
streams. (Of couse this example is a little simple-minded because pretty printing
is a little more complicated than that.)

In effect, functional output would be just a way creating data structures storing
the result of converting something to bytes. (In Ocaml, the 'Buffer' module, aka
extensible string buffers, is such a thing---but of course it's state-based.)

Other question: If output streams are imperative, what's the difference with output ports?

>> 4. One source of confusion for me is still the read/write/display legacy
>> of Scheme that went into this SRFI.
>
> Huh?  This SRFI *breaks* with that legacy.  Could you be more specific?

I am referring to the READ/WRITE/DISPLAY naming and meaning here.

The most useful classification for output I came across is as follows:
O1. binary output for machine consumption (e.g. writing a PNG-image),
O2. textual output suitable for machine consumption but not fully unintelligible
(e.g. printing floats such that they can be read back as they were), and
O3. human consumption only ('Hey, no droids in this bar!'), e.g. printing
floats with a meaningful application-specific number of decimal places.
For input, it comes down to reading the different forms of output back in
(which can of course be complicated and can also destroy information).

Now this distinction is not related to the interface by which you input/output
the data (e.g. port or stream) but by the intention you do that with---and by
the tools you need for that. This is not fully reflected in the design of this
SRFI as far as I can see.

For O3. you need something like FORMAT and for O1. you need a set
of tools for producing binary representations for Scheme objects in a
controlled way (e.g. output-u8, output-u16-little etc.). For O2 you still need
a way of producing textual representations of Scheme objects.

The READ/WRITE/DISPLAY approach mixes the tasks of converting
structured Scheme objects into bytes and actually doing I/O. In SRFI-68
I have problems identifying the separation as well (e.g. there is ouput-bytes
and output-string) and I find no reference to where conversion tools will
come from (are they named "output-<type>" or do they produce byte-
vectors all the time or what?).

It is generally a good idea not to try to solve the conversion problem
and the actual I/O in one SRFI. But the distinction/interface could be clearer.

>> 6. It would be great if there were a mechanism specified for passing
>> additional arguments (options) between the levels.
> ...

> That's definitely true.  At the time of writing, I didn't have a good
> solution, so I stuck with using separate procedures for the common
> options.  (I really dislike keyword arguments for various reasons.)  I
> have a better idea now, and I'll try to do something about the issue
> with the next revision.

Great! I do not care what the mechanism looks like, if there is one that works.

> Having said that, note that I fully expect platform-specific options
> to come up, as well as platform-specific methods for creating readers
> and writers.  That's not inherently bad, given that the sets of
> available options *are* platform-specific.  It would be nice to
> standardize on those as well, but they don't fall in the purview of
> this particular SRFI.
>
> (The SML Basis actually has a fourth, OS-specific layer, with variants
> for Unix and Windows.)


Ideally, the baseline functionality is portable, i.e. read a textfile, read a binary
file, write a text file with create/overwrite, and write a binary file with create/overwrite.
That's already revolutionary with respect to R5RS.

Beyond that I would either go for something in which you can easily register
options at any time, or for something using Scheme symbols.

Again, my point is not that every Scheme implementation on Windows knows
how to start the high-throughput tape recorder on the Cray (if it could only find it)
but that there is a heap allocated, inspectable data structure for telling somebody.

For example: Scheme #1 on Windows and Scheme #2 on the Cray talk to each
other. #1: "Tell me how you opened the file, then." #2: (write '((tape . true) (encryption . off)
(user . surprise-mode) (floats . hashed-and-fried))) #1: (define options-2 (read)) #2 exit
#3 (a new Scheme on the Cray) enter, #3: "Hey #1, how did #2 open the file then?"
#1: (write options-2). #3: (define options (read)), ...

I don't particularly like symbols either but they are good at carrying some
message from one place to another, while all the intermediates have no
clue at all. (Symbols are just strings with an efficient equality predicate.)

Long emails this...

Sebastian.