On Sep 14, 2009, at 10:23 AM, John Cowan wrote:

> This is a proposal for adding custom I/O ports to R7RS small Scheme.
> I am publishing this document to invite wide comment.  There is  
> nothing
> official about it.  I retain sole responsibility for it, including
> all errors.
>
> Custom ports in R6RS are like those in most systems: basically a set  
> of
> procedures which are invoked when standard port operations are  
> executed.
> For example, if you create a custom character input port, you may then
> call read on it, and the normal read algorithm will be invoked, but it
> will read characters not from a file or a string, but rather from  
> one of
> the procedures set up when the port was created, the one corresponding
> to read-char.
>
> However, the R6RS interface to creating custom ports, like all  
> others I
> have seen, is highly inflexible.  The set of procedures varies  
> depending
> on whether the port is input or output, binary or character-based.
> If you get the order of procedures wrong, you lose.  And if new basic
> procedures or port types are added by an implementation, the existing
> port constructors will require supplementation with new constructors.
>
> Therefore, I am proposing a pattern whereby a custom port is not a  
> record
> of procedures, but a special case of what Common Lisp calls a  
> disembodied
> property list: a map from symbols to procedures.  (This does not  
> imply, of
> course, that a custom port must be implemented using a list.)  When  
> such
> a port is created, it has a variety of default behaviors corresponding
> to the standard port operations.  The resulting port isn't good for
> anything much.
>
> To make the port useful, you replace its behaviors: for example, you
> can redefine read-char with an implementation-dependent procedure that
> reads from a network port.   You can replace not only the lowest-level
> ones but higher-level ones: for example, you can redefine read to
> do non-Scheme parsing if you want.  Removing a behavior causes it to
> revert to the default.  Some symbols and their associated behaviors  
> are
> input-related, some are output-related, some are neither.  You can  
> also
> change non-standardized behaviors which your Scheme implementation  
> provides.
>
> 5 identifiers are bound to procedures by this proposal:
>
> (port? object) answers true if its argument is a port.  This is made
> necessary by the fact that custom ports can be input ports, output
> ports, both, or neither.  A custom port returns #t to input-port?   
> if it
> has a non-default behavior for any input-related symbol.  Likewise,
> it returns #t to output-port? if it has a non-default behavior for any
> output-related symbol.
>
> (make-custom-port) returns a custom port with default behaviors.
>
> (custom-port-get custom-port symbol) returns the behavior of the
> custom-port associated with the symbol.  The standard symbols are the
> names of standard procedures, and the procedures returned take the  
> same
> number of arguments with the same semantics as those standard  
> procedures.
>
> (custom-port-set! custom-port symbol procedure) changes the behavior
> associated with symbol in custom-port to procedure.
>
> (custom-port-remove! custom-port symbol) reverts the behavior  
> associated
> with symbol in custom-port to the default.
>
> Here are the 6 standard input-related symbols and their default  
> behaviors.
>
> read                    Performs the normal read algorithm
> read-char               Returns an eof-object
> peek-char               Returns an eof-object
> read-line               Performs the normal read-line algorithm
> read-u8                 Returns an eof-object
> peek-u8                 Returns an eof-object
>
> Here are the 5 standard output-related symbols and their default
> behaviors.
>
> write                   Performs the normal write algorithm
> display                 Performs the normal display algorithm
> newline                 Performs the normal newline algorithm
> write-char              Does nothing
> write-u8                Does nothing
>
> Here are the remaining 2 standard symbols and their default behaviors.
>
> port-u8-position        Does nothing
> set-port-u8-position!   Does nothing

I've read over this proposal, and I have some substantial issues with  
it:

* I don't think Small Scheme needs any definition of ports which is  
more complex than that needed to read program text. Adding binary  
ports adds too much in the way of assumptions about the environment in  
which the small scheme implementation lives.

* I don't like the property list method you're using for custom port  
objects. What is wrong with `port-set-read-procedure!', `port-set- 
write-procedure!', etc.? How does naming some procedures with two  
symbols instead of one help anything?

* I don't like the assumption that ports are bivalent. This is a  
complex thing to get right. One can take a file which is properly  
encoded in UTF-8 and wind up introducing a decode error by mixing  
binary and character operations on the same port. Bivalent ports can  
be completely and usefully provided by a library on top of binary  
ports if users desire them.

* I don't like the assumption that ports should naturally provide both  
input and output. This isn't true in general. It's better to separate  
out the types and have some way of creating an I/O port out of an  
input port and an output port.

* I don't like the inclusion of `read-line' and `newline' procedures.  
Why is it useful to change the behavior of these procedures? This  
seems like an opportunity for error.

* I don't like the hook for `read' and `write'. I don't even know why  
it's there. If I'm going to replace it with something else, isn't that  
something deserving of a different name?

I think what the R6RS provided is an attempt to get all of these  
fiddly little details right. If anything goes into a smaller language,  
it needs to avoid these details as much as possible, in particular the  
details of how to work with encodings. Otherwise you're going to wind  
up with something that is too underspecified to work in general, or  
just missing important functionality. I think it'd be OK to add in the  
concept of a user-defined *binary* port, because experience shows that  
the details can be taken care of in a library if binary ports are  
provided.
--
Brian Mastenbrook
[email protected]
http://brian.mastenbrook.net/

_______________________________________________
r6rs-discuss mailing list
[email protected]
http://lists.r6rs.org/cgi-bin/mailman/listinfo/r6rs-discuss

Reply via email to