[net.lang.ada] text_io problems solved

hilfingr@UCBRENOIR (Paul Hilfinger) (09/19/85)

A recent note finally gives me a chance to show off one of my favorite Ada
examples.

>    Something that has always struck me as incredibly inconvenient
>    about Ada IO is the fact that it does not offer the convenience
>    and simplicity of things like C's printf or the richer IO
>    facilities in PL/1 and FORTRAN. Formatting a page of output, or
>    even printing a series of variables and descriptive information
>    for debugging purposes is a real pain in Ada because of the need
>    to use numerous simple calls.
>
>    Unfortunately there is no easy way to get around this limitation.
>    Within limits you can synthesize a printf type mechanism by
>    defining a bunch of overloaded IO routines [at the cost of a
>    combinatorial explosion.]
>
>    Likewise, you could build an IO package using "union types"
>    synthesized out of variant records and unchecked conversion, but
>    this is dangerous and inconvenient.... So, we are pretty
>    much stuck with a cumbersome IO mechanism....
>
>    Jerry Rudisin

Not so! These particular options don't come close to exhausting the
possibilities of Ada's definitional features.

I offer the info-ada community an exercise: Devise a set of package
definitions (generic and otherwise) so that, with appropriate context clauses
and generic instantiations, the user can write the following calls, with
meanings as given in the comments that follow them.

    PUT( "X = " & X & ", Y = " & Y);
        -- As in Pascal's write('X = ', X, ', Y = ', Y).  X and Y may have
	-- any combination of type STRING, CHARACTER, or any integer, 
	-- enumeration, and floating  point types.  At most one generic 
	-- instantiation per type to be output is required (no combinatorial 
	-- explosion allowed).
    PUT( +X & Y & Z);
        -- As in Pascal's write(X,Y,Z).  This example is a hint: PUT(X&Y&Z)
	-- won't work unless X is type STRING or CHARACTER! (Mumble).
    PUT( "X = " & FMT(X,3) & ", Y = " & FMT(Y,11,4) );
    	-- As in Pascal's write('X = ',X:3,'Y = ',Y:11:4).  The Ada is not as
	-- concise as the Pascal.  See the discussion below under ``Pet
	-- Peeves''

Well, you get the idea.  Now let's turn to C.  Change the exercise above to
work instead for the following example.

    PUT("X = %d, Y = %d", +X & Y );
        -- As in printf("X = %d, Y = %d", X,Y);

Unfortunately, we can't use the same tricks for input; so it goes.


PET PEEVES

The examples above uncover some of my own favorite problems with Ada. First,
there is the rule 4.3(7) (``The type of an aggregate must be determinable
solely from the context in which [it] appears, excluding the aggregate
itself, but using the fact that this type must be composite....''). This
makes it impossible to set things up so that I can write, for example,

    PUT( "X = " & (X,3) & ", Y = " & (Y,11,4) );

because I could not distinguish the type STRING (also a composite type) from
whatever the types of the aggregates are. (Exercise: If 4.3(7) were gone, and
the compiler were free to use the contents of an aggregate to disambiguate
its type, what definitions would I need to make this last statement work as
intended?)

There is no technical justification for 4.3(7). It was intended, in part, to
simplify overload resolution. It doesn't significantly simplify any of the
type-checking/overload resolving schemes I know (indeed, it complicates
some), and I've never understood why anyone thought it would. Also, it was
intended to ``avoid confusing the programmer with surprising resolutions.''
However, one would expect programmers to be surprised by AMBIGUITY, not by
its lack. They write something, expecting it to mean a particular thing, and
if that was, in fact, its only possible meaning, they are not surprised that
it works. Besides, 4.3(7) is COMPLEX. Overloading would be better understood
if the rule were closer to ``It is an error for there to be more than one
possible legal interpretation for a complete context.'' There are some
surprises lurking here--places where resolutions are possible where one
wouldn't have thought it or vice-versa--but they are mostly harmless
pathologies with which to amuse idle language lawyers.

I could also have cleaned up the FMT notation if it were possible to define
more operators. For example:

    PUT( "X = " & X::3 & ", Y = " & Y::11::4 );

Exercise: What definitions are needed to make THIS work as intended, assuming
"::" is a definable multiplying_operator?

Simplicity may have been the reason for limiting the set of operators; I'm
not sure. I have reason to believe, however, that certain other members of
the Ada Design Team have had second thoughts on the matter, which is
something, at least.

Paul Hilfinger