powell@decwrl.UUCP (Mike Powell) (09/06/84)
I would like to provoke a little discussion about the I/O facilities present in
(or absent from) Modula-2. There seem to be 3 + N possible alternatives:
1) Pascal-like I/O
2) What Wirth has proposed (module InOut)
3) No defined I/O
N) Pick your favorite I/O mechanism
1) Pascal I/O (especially the "I") has been widely discussed and criticized,
so I won't rehash it. Using it would at least make Modula-2 more compatible
with Pascal, and would have guaranteed a facility no worse than Pascal's.
2) What Wirth has proposed is not adequate even for many simple programs.
There is only one input stream and one output stream for formatted operations.
Although it is possible for people to define their own I/O modules as needed,
this degenerates into the next alternative.
3) Not defining I/O even in the easy cases will make it impossible to write
portable Modula-2 programs. No interesting textbooks will be written and the
language will not be taught on a large scale.
N) It seems to me that 2 and 3 are both worse than 1. The question is, is
some N better than 1? How about this:
Define a builtin I/O module patterned after Unix/C printf and scanf. I believe
this same (or similar) I/O interface has been used in a variety of languages on
a variety of machines and systems, so it seems pretty portable. Formatted
input and output are accomplished with procedures that accept a variable number
of parameters. The first two parameters are always the file variable and a
format string. Additional parameters may be specified, and they are matched
against the format string to see how to read or write the variables. Although
in C the parameters are not checked (of course, C never checks parameters) and
are blindly used by the library at runtime, Modula-2 could check the parameters
against the format, and even generate calls to implementation-dependent library
routines to perform the I/O.
I liked this idea so much I implemented it in my compiler, and I include the
pseudo-definition module (since it must be built into the compiler to handle
the variable-length parameters lists) below. I'm interested in reactions or
suggestions for other alternatives. I would also like to know what other
operations you think are essential for a "standard" Modula-2 I/O library.
Michael L. Powell
Digital Equipment Corporation
Western Research Laboratory
Los Altos, CA 94022
{decvax,ucbvax}!decwrl!powell
powell@decwrl
Appendix: io.def
This module should not be compiled, but is supplied for documentation purposes.
definition module io;
export qualified
File, Open, Close, Readf, Writef, SReadf, SWritef,
Readc, Writec, Readb, Writeb;
type File = pointer to FileRec; (* Open file variable type *)
var
(* Standard files connected to Unix standard input, output, and error *)
input, output, terminal : File;
procedure Open(name : array of Char; mode : array of Char) : File;
(* open a file *)
(* name : file name; mode = "r" for input, "w" for output *)
(* return value : opened file or nil *)
procedure Close(f : File);
(* close a file *)
procedure Readf(f : File; (* constant *) format : array of Char;
var arg1 : ArgType1; var arg2 : ArgType2; ...) : integer;
(* read a list of values from a file according to a format string *)
(* f : an open file; format : constant string format (like Unix scanf) *)
(* argn : variable for corresponding format item, type must match *)
(* return value : number of values read, < 0 for end of file *)
procedure Writef(f : File; (* constant *) format : array of Char;
arg1 : ArgType1; arg2 : ArgType2; ...);
(* write a list of values to a file according to a format string *)
(* f : an open file; format : constant string format (like Unix printf) *)
(* argn : value for corresponding format item, type must match *)
procedure Readc(f : File; var c : Char) : integer;
(* read the next character from the file *)
(* f : an open file; c : variable to read next char into *)
(* return value : >= 0 if read OK, < 0 if end of file *)
procedure Writec(f : File; c : Char);
(* write a character to a file *)
(* f : an open file; c : value for next char to write *)
procedure SReadf(s : array of Char; format : (* constant *) array of Char;
var arg1 : ArgType1; var arg2 : ArgType2; ...) : integer;
(* read a list of values from a string according to a format string *)
(* s : a string; format : constant string format (like Unix scanf) *)
(* argn : variable for corresponding format item, type must match *)
(* return value : number of values read *)
procedure SWritef(var s : array of Char; format : (* constant *) array of Char;
arg1 : ArgType1; arg2 : ArgType2; ...);
(* write a list of values to a string according to a format string *)
(* s : a string; format : constant string format (like Unix printf) *)
(* argn : value for corresponding format item, type must match *)
procedure Readb(f : File; var buff : array of byte; size : cardinal) : integer;
(* read binary data from a file *)
(* f : an open file; buff : variable to read into *)
(* size : number of bytes to read *)
(* return value : if read OK, = number of bytes read, < 0 if end of file *)
procedure Writeb(f : File; buff : array of byte; size : integer);
(* write binary data to a file *)
(* f : an open file; buff : variable to write *)
(* size : number of bytes to write *)
end io.cca@pur-phy.UUCP (Charles C. Allen) (09/10/84)
Here are a couple of things I would like to see in ANY implementation of a
Modula-2 I/O library:
* The ability to have an 8-bit CHAR. The range of type CHAR could be
extended to 377C, or CHAR could be made a subrange of a new type
that goes to 377C.
* I/O for enumerated types. The usefulness of enumerated types is
drastically reduced if you can't do I/O with them.
I'd be interested in hearing whether existing compilers have these
capabilities.
Charlie Allen
UUCP: pur-ee!Physics:cca, purdue!Physics:cca
INTERNET: cca@pur-phy.UUCPmerlin@emory.UUCP (09/10/84)
Michael Powell has raised some important questions in his discus- sions of modula-2 I/O. I agree with the thrust of his comments but am opposed to some of his specific remedies. I strongly support the need for a standard I/O module. It is essential for the study and promotion of the language. Such a standard should meet several criteria. It must support a comprehensive set of input/output capabilities, including, at a minimum, file and terminal oriented operations. A standard should define unambiguously the results of both successful and unsuccessful I/O requests. Reliable error-detection and error- recovery must be supported in all I/O capabilities. I feel that Wirth's "InOut.def" is an example of a reasonable approach to standardization. It encompasses most of the I/O con- structs that conventional applications require. It needs a con- siderable amount of refinement in order to qualify as a practical standard, since there are many ambiguous or ill-defined com- ponents. I am not championing "InOut.def" as the modula-2 I/O standard. It clearly is a contender and, unless someone can demonstrate how it is woefully inadequate on *functional* grounds, it appears to me to be the appropriate starting point. I must admit a strong aversion to modula-2 clones of the UNIX standard "printf" and "scanf". My grounds for objection are man- ifold. In a fundamental way this approach opposes much of what modula-2 is intended to accomplish. If the language is to enforce strong type-checking then procedure calls with "cross-coupled" parameter lists much be validated during some phase of compilation. The compiler must recognize these specially designated procedures as well as their *internal* syntactical structures. These pro- cedures become aspects of the language itself. It is not incon- ceivable to me that we may wish to consider language-defined I/O mechanisms, but I strongly suggest that this be evaluated as a language design consideration and not as an ad hoc method of in- troducing an I/O standard. There are other serious problems created by this formulation. The code generated for a program requiring, for example, only simple integer I/O may incorporate facilities for many unused I/O conversions. To the extent that the format string is itself de- fined only during program execution, all possible I/O conversions must be made available at run-time. The inability of the pro- grammer to specify only those functions requisite for her pur- poses may hamper development of a variety of systems. Moving on to other concerns. Format-string directed I/O tends to create a need for explicit control-character representation (as with C's backslash notation). The problem is that this couples the logical functioning of input-output procedures with specific characters in data strings. Representations of record, line or file terminators should be details hidden beneath appropriate procedure calls such as Wirth's "WriteLn". This allows a much more effective way to adapt to variations in system-specific control-character conventions. My other objections are more matters of personal taste. These functions exemplify an extreme control-coupled approach to argu- ment transmission that transform procedure calls into veritable input-output *vegematics*. The odd thing is that, apart from familiarity, there is very little to recommend them. Granted they do capture an image of the structure of the input or output in a compact form but only at a substantial cost. We need to act now to establish a simple reliable standard. It does not have to do everything. It is important to remember is that the language is intentionally *modular*. New solutions can be incorporated at a later time as long as we refrain from incor- porating I/O support in the language definition through elaborate compiler enhancements. Marc Merlin Emory University Atlanta, GA (akgau!emory!merlin)
sjc@angband.UUCP (Steve Correll) (09/23/84)
I like Mike Powell's idea of adapting Unix "printf" for use with Modula-2.
Despite its shortcomings, I like the combination of convenience and
(even more important) readability which "printf" provides.
Perhaps the objection to variable-length argument lists could be
answered by taking a hint from the Unix "execv" system call and making
"printf" take exactly two arguments, the first of them being a format
string and the second being an open array of addresses of the desired
data items. (The Unix "argv" argument employs a similar notion.)
As in the Unix implementation, the user would be expected to terminate
the list of addresses with a sentinel like NIL so that the callee knows
where to stop; although this is unnecessary in "printf", where the
format string dictates the number of items required, the redundancy
would allow runtime checking of the number of items. (Note that relying
on the Modula-2 "high" mechanism rather than a sentinel would force the
caller to declare an array of exactly the right size for each call.)
Admittedly, this is a bit less convenient than the C language version,
particularly when the caller must store constants into variables so
as to obtain addresses for them. But I rarely find I want to pass
constants to "printf".
As for the objection that "\n" in the C language poses portability
problems in comparison with "writeln" in Pascal, perhaps the Modula-2
"printf" should regard "\n" as meaning exactly what "writeln" does:
generate a new line in whatever manner is appropriate to the underlying
file system.
While the "\nnn" notation (where n is an octal digit) for specifying an
unprintable character is part of the C language rather than the Unix
"printf", I'd like the Modula-2 "printf" to retain it, since it seems
consistent with spirit of the Modula-2 "nnC" notation.
--Steve Correll
sjc@s1-c.ARPA, ...!decvax!decwrl!mordor!sjc, or ...!ucbvax!dual!mordor!sjc
--
--Steve Correll
sjc@s1-c.ARPA, ...!decvax!decwrl!mordor!sjc, or ...!ucbvax!dual!mordor!sjcrussell@muddcs.UUCP (Russell Shilling) (09/27/84)
> I like Mike Powell's idea of adapting Unix "printf" for use with Modula-2. > Despite its shortcomings, I like the combination of convenience and > (even more important) readability which "printf" provides. Quick note: DECWRL Modula has readf, writef, fprintf, ... VERY nice to use. But the standard Modula InOut is not there, so there would be some porta/compati-bility problems here.
rcd@opus.UUCP (Dick Dunn) (09/28/84)
A couple of comments on printf (or something like it) for Modula-2:
In some sense, building a "real" formatting and I/O system for a language
(if it's not built into the language) is a test of the power of the
language. If you can't do it because the language won't let you express it
in a reasonable fashion, that's a defect in the language that needs to be
fixed. (I'm not saying that Modula-2 is deficient, only that you can apply
this test.)
However, keep in mind that the idea of a format string (as in C or FORTRAN)
which is bound to the I/O list is NOT the only way to do it; in fact it's
probably a poor way to go. It's very seldom that you need a variable
format string and even less common to need the dynamic binding of I/O list
elements to format elements. Pascal's approach shows a hint of a better
way to go, although it comes out as a somewhat clunky special case and it
has to be implemented specially by the compiler. ("Write" in Pascal is NOT
a procedure, no matter what you say:-) Anyway, if you bind format elements
to (input) variables or (output) expressions at compilation time, you can
get much-needed type checking. A general mechanism here would have much
wider applicability than just I/O. In fact, the main problem isn't really
an I/O problem anyway--it has to do with control over the formatting that
happens before the I/O.
--
Dick Dunn {hao,ucbvax,allegra}!nbires!rcd (303)444-5710 x3086
...Cerebus for dictator!chris@umcp-cs.UUCP (Chris Torek) (09/28/84)
Also, have a care for ``internal I/O'' (stuff like F66 ENCODE, DECODE
or F77s array READ and WRITE statements). One of the most annoying
things about Pascal is that it is impossible to write a version of
WRITE that doesn't actually go to a FILE or OUTPUT. (Yes I know it
*can* be done, it's just extremely painful: `wrint' `wrbool' ....)
(Give me sprintf, any day!) (Oops, sorry, this isn't net.lang.c :-) )
--
(This page accidently left blank.)
In-Real-Life: Chris Torek, Univ of MD Comp Sci (301) 454-7690
UUCP: {seismo,allegra,brl-bmd}!umcp-cs!chris
CSNet: chris@umcp-cs ARPA: chris@maryland