`tac` : Implementation of UNIX's line reverser

The interface for READ-LINE and friends was made before the existence of definitional errors.

There were three return states:

  • Multi-return pack of ~[string data, end of file flag]~

  • NULL

  • An ~escape~ antiform (no longer a legal "keyword")

The case of the ~escape~ antiform pretty clearly should be a definitional error. We can see that it would screw up programs like TAC, with the antiform being truthy. (The original choice was made when they were ornery.)

If you aren't rigged up to handle the user canceling (via EXCEPT) then it should create an error and the program should halt. You don't want it to be conflated with NULL as an ordinary "no more input available, normal completion" condition, and you don't want it to be something that is a branch trigger (which is everything but null these days).

The reason for the end of file flag is that you could do a READ and the other side of the pipe could hang up... not strictly at the point of a newline. Returning NULL in that case might throw away data you were interested in getting. So this was a way of letting you know if it wasn't really a complete string--if you cared.

The EOF Flag Can Be Ignored, And Is A Mistake

The secondary-return-result-EOF isn't a good design, as casual usage will conflate reading an incomplete line with reading a complete line. The other side can hang up on you, and you won't know it.

I think a better answer here is to have a :RAW mode which includes the newline at the end of the string you get. Then you can detect if the newline is there or not. If it's not, your read was prematurely interrupted.

if not (line: read-line:raw except [print "Escape!", quit 1]) [
    print "No more input left to read."
    quit 0
]
if newline <> try last line [  ; need TRY, since string may be empty
   print ["Incomplete line was read:" mold line]
   quit 2
]
try take/last line  ; again, TRY in case string is empty
print ["Complete line read:" mold line]
quit 0

So that gives you coverage of what this layer of abstraction can provide you.

If you don't use the /RAW mode, then the other end of the pipe disconnecting in mid line would cause an abrupt failure.

Seems good to me.

1 Like