This page is part of the web mail archives of SRFI 91 from before July 7th, 2015. The new archives for SRFI 91 contain all messages, not just those from before July 7th, 2015.
Date: Fri, 14 Apr 2006 09:37:23 -0400 From: Marc Feeley <firstname.lastname@example.org> On 14-Apr-06, at 8:49 AM, John Cowan wrote: > Marc Feeley scripsit: > >> It is a pain to carry those two ports around in the code when the >> program needs to communicate bidirectionally with some other entity >> (another process, a user at a terminal, a socket, etc). Moreover the >> separation of a conceptually bidirectional channel into distinct >> ports (input and output) destroys the conceptual link that they >> have. This hinders program understanding. For example, with >> bidirectional ports (close-port port) will close both sides of the >> bidirectional port (i.e. the link between the input and output port >> is preserved). With two unidirectional ports you have to duplicate >> some operations (closing ports, changing port settings, ...). > > I find this rationale convincing (and think it should be added to the > SRFI). OK. I find this rational unconvincing: I see no reason why introducing a third object (say socket, tty, &c.) would hinder program understanding any more than the bidirectional ports do -- personally, I think bidirectional ports do more to hinder it. If we introduce this third object, then we can simplify the model of input and output ports very much, so that an input port is purely a source and an output port purely a sink, and we can specify any options common to the resource that they are both associated with on the third object; for instance, we could have a (SET-SOCKET-OPTION socket level option value). This furthermore simplifies issues about closing; see below. Continuing on the socket theme, port I/O doesn't even make sense for some sockets, such as stream listener sockets and unconnected datagram sockets. In these cases it would be absurd to represent the socket as a port, while it makes very much sense to represent it as a distinct `socket' object, from which in certain cases (specifically, connected sockets) one can obtain ports. > However, the socket API does permit closing input and output > sides of the socket separately, and there are use cases for this, > so it > should be at least permitted though not the default. > > For example, when you want to send an arbitrary-length undecorated > document to a server and retrieve an arbitrary-length undecorated > document > back, the simplest way to convey "end of document" is to close the > output > side, while leaving the input side open in order to receive the reply. > That was the intent of the passage: When an operation is said to apply to an input port it also applies to a bidirectional port. When an operation is said to apply to an output port it also applies to a bidirectional port. but I guess it is not clear that this also applies to the port closing operations so I will add a note to that effect. So yes you can: (let ((tty (open-file "/dev/tty"))) ; bidirectional port ... (close-input-port tty) ... (close-output-port tty)) And similarly for any bidirectional port (presumably sockets when they are specified by another SRFI). For the record Gambit has: (open-tcp-client (list server-address: "www.apple.com" port-number: 80 eol-encoding: 'cr-lf))) I think this is actually a bad idea. It's not entirely clear when the resource itself gets closed, versus when individual directions are closed. CLOSE-PORT, it seems, cannot be defined as (define (close-port port) (if (input-port? port) (close-input-port port)) (if (output-port? port) (close-output-port port))), if it does more than just CLOSE-INPUT-PORT and CLOSE-OUTPUT-PORT; either that or both CLOSE-INPUT-PORT and CLOSE-OUTPUT-PORT must have complicated definitions in order to close the resource only if both directions are closed -- but even then that doesn't work very well with sockets. If we were to introduce a third kind of object, and to disjoin input ports from output ports, then this ambiguity would be gone. For instance, if we have a socket, and two ports for the two directions of communication, then we can have (CLOSE-SOCKET socket), to actually close the socket and release any resources in the operating system for it; (CLOSE-INPUT-PORT inport), to shutdown the socket in the receive direction; and (CLOSE-OUTPUT-PORT outport), to force any buffered output and such, and to shutdown the socket in the send direction.