Subject: Re: Standard output formatting control
From: rpw3@rpw3.org (Rob Warnock)
Date: Sat, 10 Jun 2006 06:29:46 -0500
Newsgroups: comp.lang.lisp
Message-ID: <-ZmdnWNy14u3MBfZnZ2dnUVZ_sKdnZ2d@speakeasy.net>
Thomas F. Burdick <tfb@conquest.OCF.Berkeley.EDU> wrote:
+---------------
| rpw3@rpw3.org (Rob Warnock) writes:
| > In many Common Lisps, especially on Unix/Linux, formatted output
| > is not automatically flushed from buffers by a #\Return, only by
| > a #\LineFeed, so to get this to work as expected you will need to
| > add a (FORCE-OUTPUT) before the (SLEEP 1) [and similarly with the
| > CUP example later]:
| 
| I'm not sure how exactly FORCE-OUTPUT became the favorite
| recommendation of c.l.lisp denizens, but it's a bad thing
| to recommend to a newbie.
+---------------

I respectfully disagree.

+---------------
| To the extent that FORCE-OUTPUT and FINISH-OUTPUT differ, it's
| rare that you actually want the behavior of FORCE-OUTPUT. When
| writing a server application, just before going back into your
| listening loop -- that's the only time that pops to mind where you
| want to start flushing buffers but not wait for the process to complete.
+---------------

In a multi-threaded application FINISH-OUTPUT can (in theory) cause
the current thread to *block* until the output has round-tripped
to the ultimate consumer, which can be a *long* time if there's an
international network delay in the path [and/or the network implemen-
tation is using "delayed ACKs" for efficiency, which most modern stacks
*do* by default!]. FORCE-OUTPUT, by contrast, will start the buffered
data moving [so that the user on the far end of the connection *will*
see it, eventually] but will not block the thread and/or the application.

And conversely, actually getting FINISH-OUTPUT to satisfy its
contract -- "ensure that any buffered output sent to output-stream
has reached its destination" -- can be *VERY* hard in a networked
environment, e.g., with TCP, which normally gives you no user-visible
way of knowing that the data has "reached its destination". [Yes, the
*kernel* stack can find that out, by looking at the ACK count, in the
TCB PCB, but that information is not normally made available to users.]

Or for disk files, FINISH-OUTPUT's contract, taken literally, would
say that when it returns the bits are actually physically on the disk,
secure from (say) a power outage or reboot or crash. This is *not*
likely to be the case unless the entire system from the Lisp app
down through the operating system and out through the disk drive
itself are cooperating to create such "stable storage". Good luck!

As a result, I feel that FORCE-OUTPUT, whose weaker contract is
both more "reliable" [in the sense of being likely to be satisfied
across a wide variety of I/O channels] and also closest to the
C language's "fflush()" [which newbies will likely be used to],
is the one to use -- and to suggest -- by default.

Said another way, yes, FORCE-OUTPUT does not make as strong a
promise as FINISH-OUTPUT, but it is more likely to *fulfill*
its contract!


-Rob

p.s. In CMUCL, FINISH-OUTPUT & FORCE-OUTPUT are identical on
an FD-STREAM [any stream mapped to a Unix file descriptor].
It would be interesting to know for which implementations
they are actually different.

-----
Rob Warnock			<rpw3@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607