[fa.info-mac] MacPascal Terminal I/O

info-mac@uw-beaver (info-mac) (11/30/84)

From: Stuart Reges <REGES@SU-SCORE.ARPA>
I'm not sure anyone is interested in these messages I have posted about
MacPascal, but I will charge on anyway.  I'm one of those people who digs for
all the details and I've also seen a lot of Pascal systems, so I think I'm in a
good position to write these critiques.

As you all probably know, terminal I/O varies quite a bit from Pascal to
Pascal.  The question for terminal output is usually:

	o When is the text of a WRITE or WRITELN sent to the terminal?

There are two popular schemes:

	o Everytime a WRITELN is executed.
	o Everytime either a WRITE or WRITELN is executed.

MacPascal uses the second of these, which is the right way to go.

Terminal input is not quite so simple.  Most schemes can be distinguished by
answering the following questions:

	o When does the computer pause for input?
	o How much input does the computer expect when it pauses?

Old-style Pascal systems were usually of the form:

	o The computer pauses whenever the input buffer is empty.
	o An entire line of input is read.

This leads to problems because when the program starts executing the input
buffer will be empty and the user will be expected to type input when he hasn't
been prompted for it.  MacPascal uses what is called lazy I/O.  Probably a
better term would be procrastinating I/O.  In lazy I/O the computer delays
obtaining input until it actually needs it (i.e., the input buffer can be empty
as long as we aren't using it).  The computer needs something in the input
buffer whenever there is a reference to INPUT, INPUT^, READ, READLN, GET, EOLN
or EOF.  The answers in MacPascal, then, are:

	o The computer pauses when it needs to.
	o A single character is read.

I think that using lazy I/O is definitely the right way to go, but I think it
was a mistake to choose character-by-character I/O.  This makes it difficult to
read character-by-character, as in:

	program Fun (input, output);
	var str: array [1..20] of char;
	    len: integer;
	begin
	    write ('prompt>');
	    len := 0;
	    while not eoln do
	    begin
		len := len + 1;
		read (str [len]);
	    end;
	    writeln ('Length = ', len);
	end.

This program runs into trouble if the user tries to type something and then
uses the delete key to correct his input.  Consider the following scenario:

	o User types "hi there"
	o User types backspaces to delete the word "there"
	o User types the word "ho" instead

You would want the array to contain "hi ho" but it will instead contain the
word "there" and the backspaces between "hi" and "ho".  Systems that do
line-by-line I/O usually take care of these problems automatically, so that the
programmer doesn't have to worry about processing backspace characters.

You can do line-by-line reading in MacPascal if you use the built-in STRING
type, but that's not standard Pascal.  This is yet another example where we
find that MacPascal works well if you use the neat extensions that have been
provided but doesn't work well if you program the way you normally would in
standard Pascal.

That's a big problem for me because in my course students are using different
machines.  Most of the students are using the University's DEC-20s, but some
students in the class have their own Macintoshes and are using MacPascal.  I
also have TV students all over the country who are using all kinds of
computers.  I always teach standard Pascal and encourage my students to stick
to the standard as much as possible.

MacPascal terminal input has another odd characteristic.  In order to
distinguish it from other Pascal systems you need to look at one more question:

	o When are the characters typed by the user echoed to the terminal?

Usually the answer is "immediately."  In MacPascal, however, the answer is:

	o When the characters are actually read.

The following program illustrates the difference:

	program Fun (input, output);
	var ch: char;
	begin
	    write ('prompt>');
	    while not eoln do
	    begin
		write ('!');
		read (ch);
		write (ch);
	    end;
	    write ('*');
	    readln;
	    writeln ('done');
	end.

The program first pauses for input when it hits the EOLN test.  It doesn't echo
the character at that point, though.  It instead waits until it executes the
READ statement.  We also get the asterisk written out before the carriage
return typed by the user is echoed.  A typical execution yields something like
this:

	prompt>!ww!ee!ii!rr!dd*
	done

If characters were echoed immediately we instead get:

	prompt>w!we!ei!ir!rd!d
	*done

Echoing immediately is much more intuitive.  This weird behavior of MacPascal
makes it harder to explain terminal input conventions and I don't believe it
really gains us anything.

Most Pascal systems have really terrible terminal I/O, so I'm not being overly
critical of MacPascal here.  Think Technologies should be congratulated on
getting something that works fairly well and that follows the standard.  I
think that it would be more useful, however, if the questions were answered as
follows:

	o Empty output buffer on every WRITE/WRITELN.
	o Pause for input only when you need it.
	o Pause for an entire line of input when you pause.
	o Echo characters immediately after they are typed.

(MacPascal has the first two of these right.)
-------

info-mac@uw-beaver (info-mac) (12/04/84)

From: ihnp4!utzoo!henry@uw-beaver.arpa
Sounds like the Mac is all set to stumble over something that the Unix
community learned long ago:  if you want line editing (e.g., backspacing
over typos) to work uniformly across all programs, it must be centralized.

				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry