[comp.lang.pascal] I/O

schwartz@shire.cs.psu.edu (Scott Schwartz) (07/14/89)

Robert Keiser writes:

|      WRITELN('WHAT IS YOUR NAME');
|      READLN; (* FORCE A GET *)
|      I := 1;
|      WHILE NOT EOLN DO
|       BEGIN
|        READ(NAME[I]);
|        I := I + 1;
|      END;

| I mean, it would seem that to follow the way Pascal is supposed to
| work with the "look ahead" buffer it would require something special
| to avoid the above example.

A pure implementation of Pascal I/O would have the program block just
after it began executing while it waited for the INPUT buffer to get
filled. 

The most common technique for making interactive I/O work sensibly is
called "lazy I/O", and arranges not to block for input until necessary.

In your example, the "READLN (* FORCE A GET *)" doesn't seem to be
what you really want to do, since it could potentially discard valid
input in addition to filling the buffer.

Beyond that, I would have expected the EOLN to force the (buffer
filling) GET, since that's when you actually require the data.
Similarly, if you had some thing like "foo := input^" as the first use
of "input", the buffer would be filled at that point.  (Of course, the
runtime system should only do the inplicit GET once, to initialize the
input stream, not each time you do that statement.  Some pascal to C
translators screw this up.)

A quick test with Sun's Pascal compiler shows that omitting the READLN
results in a working program, as expected.

--
Scott Schwartz		<schwartz@shire.cs.psu.edu>

RDK%vm.temple.edu@cunyvm.cuny.edu (Robert Keiser) (07/14/89)

On 14 Jul 89 03:15:01 GMT you said:
>
>Robert Keiser writes:
>
>|      WRITELN('WHAT IS YOUR NAME');
>|      READLN; (* FORCE A GET *)
>|      I := 1;
>|      WHILE NOT EOLN DO
>|       BEGIN
>|        READ(NAME[I]);
>|        I := I + 1;
>|      END;
>
>| I mean, it would seem that to follow the way Pascal is supposed to
>| work with the "look ahead" buffer it would require something special
>| to avoid the above example.
>
You left out one important line, the program statement.  I didn't keep what
I wrote but it went something like this:
        PROGRAM TESTIO (INPUT/,OUTPUT);
That slash after the INPUT filename is important.  It tells the compiler not
to put in that initial GET when it generates the code.  Without that READLN
the program won't work (I'm talking about the Cyber implentation).

>A pure implementation of Pascal I/O would have the program block just
>after it began executing while it waited for the INPUT buffer to get
>filled.

Yes except that I told the compiler I was working with an interactive file
(again due to the slash).

>The most common technique for making interactive I/O work sensibly is
>called "lazy I/O", and arranges not to block for input until necessary.

This is the answer to my question, except, how does "lazy I/O" work?  Is it
part of the readln procedure or is it something special?

>In your example, the "READLN (* FORCE A GET *)" doesn't seem to be
>what you really want to do, since it could potentially discard valid
>input in addition to filling the buffer.

No it won't discard valid input because INPUT^ is not set to anything because
of the slash.  Besides, I want to fill the buffer for the next read.

>Beyond that, I would have expected the EOLN to force the (buffer
>filling) GET, since that's when you actually require the data.

The EOLN will only LOOK at INPUT^, it should not try to get any data from the
input buffer.

>Similarly, if you had some thing like "foo := input^" as the first use
>of "input", the buffer would be filled at that point.  (Of course, the
>runtime system should only do the inplicit GET once, to initialize the
>input stream, not each time you do that statement.  Some pascal to C
>translators screw this up.)

Again, "foo := input^" will not fill any buffer (at least it shouldn't, if
it did you wouldn't need GET) it will only assign the value of input^ to foo.

>A quick test with Sun's Pascal compiler shows that omitting the READLN
>results in a working program, as expected.

Again, I did try this on a Cyber and it worked fine.  In fact, this method is
taught to our students as a way to do interactive I/O.

For completness sake the following is what it would look like without that
slash.

?            <- the ? is from the initial GET (on the cyber, if you request
                input from a file that the operating system knows is attached
                to the terminal, it will force the ?.)  At this point I would
                have to enter something but unless I knew what the program was
                going to ask me for I wouldn't know what to enter.  If I press
                the <cr> then this is what would happen
WHAT IS YOUR NAME


  PROGRAM TERMINATED AT LINE # IN PROGRAM TESTIO.
  TRIED TO READ INPUT PAS EOS/EOF.

This would then be followed by the variable values at the time of termination.
If I took out the READLN; I would get the exact same result.

Finally, I would like to thank Steve for his response.  I understand his
misunderstanding (sounds interesting doesn't it :-) about how the Cyber Pascal
work.  He did, however, give me a hint of how this process works on other
systems.  Now Steve, what is "lazy I/O".

Robert Keiser    <rdk@templevm>

schwartz@shire.cs.psu.edu (Scott Schwartz) (07/15/89)

In article <20249@adm.BRL.MIL> Robert Keiser <rdk@templevm> writes:
[ A continuing discussion of cyber implementation of pascal.
  The example in question looks like: 	

  PROGRAM TESTIO (INPUT/,OUTPUT);    	

    WRITELN('WHAT IS YOUR NAME');	
    READLN; (* FORCE A GET *)		
    I := 1;				
    WHILE NOT EOLN DO			
    BEGIN				
      READ(NAME I]);			
      I := I + 1;			
    END;				
]

Robert writes:
| That slash after the INPUT filename is important.  It tells the compiler not
| to put in that initial GET when it generates the code.  Without that READLN
| the program won't work (I'm talking about the Cyber implentation).

I think Robert and I are talking at cross purposes.   In his original
article he asked how this is done on other systems (VAX, PC).  I tried
to answer that question.   I also offered some explaination about why
the implementation he describes for the cyber seems wrong, and wouldn't
work as expected on what I consider a correct implementation of PASCAL.

| >The most common technique for making interactive I/O work sensibly is
| >called "lazy I/O", and arranges not to block for input until necessary.
| 
| This is the answer to my question, except, how does "lazy I/O" work?  Is it
| part of the readln procedure or is it something special?

It is part of the runtime system, and effects I/O that goes to
terminals.  The idea is that while pascal could fill the I/O buffer as
soon as a file is opened (initializing the file is like doing a GET to
retrieve the first record), it works out better to defer this
operation until the file is actually used (via file^ or something) for
the first time.  Essentially each file operation checks to see if the
file has been initialized, and if not, initializes it.

| >In your example, the "READLN (* FORCE A GET *)" doesn't seem to be
| >what you really want to do, since it could potentially discard valid
| >input in addition to filling the buffer.
| 
| No it won't discard valid input because INPUT^ is not set to anything because
| of the slash.  Besides, I want to fill the buffer for the next read.

But READLN _discards_ everything up to the end of line, right?  If
what you want is a GET, do that, not a READLN.  I don't see the
rationale behind the behavior you describe.

| >Beyond that, I would have expected the EOLN to force the (buffer
| >filling) GET, since that's when you actually require the data.
| 
| The EOLN will only LOOK at INPUT^, it should not try to get any data from the
| input buffer.

Correct, except we bend the rules when doing lazy I/O to make interactive
I/O work as expected.

[ ... ]
| >A quick test with Sun's Pascal compiler shows that omitting the READLN
| >results in a working program, as expected.
| 
| Again, I did try this on a Cyber and it worked fine.  In fact, this method is
| taught to our students as a way to do interactive I/O.

They are in for a big surprise when the try to use a different
implementation.  On a Sun, and most other platforms, I would guess,
your code yields totally incorrect results.   Sounds like cyber
has a really strange implementation.

[ Robert gives an example of what happens without the slash in the
  program line ]

What happens when you leave in the slash, but delete the READLN?
Does EOLN bomb out at that point? 

What happens when you replace the READLN with a GET (thus making
the comments and the code agree!!)?



--
Scott Schwartz		<schwartz@shire.cs.psu.edu>

haveraaen-magne@CS.YALE.EDU (Magne Haveraaen) (07/15/89)

There are more ways to implement interactive I/O in Pascal than hitherto
discussed on the net.  A very simple and powerful scheme is as follows
(and it was implemented in ND-Pascal from Norsk Data):

Assume the input file of every program is initialized with the rest of the
program call line. If there are no parameters, the input buffer will be
initialized with an eoln (the return character you entered after the
program name to start program execution). If some program parameters where
given, these would comprise the first line, and would be readable with
Pascal's read procedures. The scheme for writing a interactive dialogue
would be (as already suggested on the net):

	:
	writeln('question 1');
	readln; (*synchronize on first line*)
	read(answer);
	process(answer);
	writeln('question 2');
        readln; (*synchronize on next line*)
        read(answer);
        process(answer);
	:

In Sun Pascal (and other unix Pascals) one must omit the first "readln" in
a dialogue, creating an unnecessary special case. This is aggravating if
you e.g.  want to have a general read-procedure that checks input and
repeats the question if errors are made.

Another advantage of this approach is that program parameters may now be
read by Pascal's standard read procedures. This makes it very simple to
read an integer parameter. And if you are so unixified that you have to
look in an array for the program's parameters - well it is fairly easy
creating a procedure that will initialize the global array by reading the
initial line.

Magne		<haveraaen@cs.yale.edu>