[comp.lang.c] Modula2's godawful IO.

rgr@m10ux.UUCP (Duke Robillard) (04/06/88)

In article <764@ndsuvax.UUCP> ncreed@ndsuvax.UUCP (Walter Reed) writes:
>Here is an example of why these things bother me.
>	IF (x = TRUE) THEN
>		WriteString("Error #");
>		WriteCard(e);
>		WriteString(" in line #");
>		WriteCard(l);
>		WriteString(" detected.");
>	END;

I really like modula2.  It's probably my favorite language.  But
this WriteCard, WriteString stuff makes me want to pop someone in the nose.
It's as if someone told Prof. Wirth "heh, pascal's io is pretty bad, but
I bet you could make it EVEN WORSE."

I hate C as much as the next guy, but it seems to me that printf is
the solution.  Has anyone ever written some kind of front end for a 
modula compiler to turn printf's into WriteSh*t's?  It doesn't seem 
like it would be too hard, although you probably couldn't do it with a
macro processor like m4...could you?
-- 
+                                
|       Duke Robillard
|       AT&T Bell Labs           m10ux!rgr@ihnp4.UUCP                 
|       Murray Hill, NJ          {any biggy}!ihnp4!m10ux!rgr

bds@lzaz.ATT.COM (BRUCE SZABLAK) (04/08/88)

In article <535@m10ux.UUCP>, rgr@m10ux.UUCP (Duke Robillard) writes:
> I hate C as much as the next guy, but it seems to me that printf is
> the solution.

I like C++'s overloading of the << and >> operator's even better than
printf. It allows you to define custom print routines for each structure
(class) declared, and then to print (to stdout for example) you do:
	cout << god_awful_structure_instance;
The advantage of this approach over using procedures in
modula2 or pascal is (besides previty) that you don't have to
remember the type of structure your variable is; the compiler figures it out.

avi@taux01.UUCP (Avi Bloch) (04/11/88)

>
>I hate C as much as the next guy, but it seems to me that printf is
>the solution.  Has anyone ever written some kind of front end for a 
>modula compiler to turn printf's into WriteSh*t's?

Another, more general solution, is the one we took when developing National's
Modula-2 compiler. We wanted to be able to interface with any C routine, even
those that weren't as strict as Modua-2 routines (e.g. num. & type of parameters
procedure or function, etc.). The following is an excerpt from the manual on the
extension we added for this purpose:

PSEUDO-MODULE 'C'
-----------------

A pseudo-module 'C' has been implemented which, like the pseudo-module SYSTEM
does not actually exist but is built into the compiler. Module C is used to
import C routines that cannot be defined using a Modula-2 definition, e.g.
routines that have a variable number of parameters (see following example).
Objects imported from module C have the following properties:

    - The object must be a procedure.
    - No type-checking is done on parameters to such procedures.
    - The procedures can receive any number of pararmeters.
    - The procedures can be called using either a procedure call or a function
      call.
    - Values returned by such procedures are of type WORD.

Example:

    Give the IMPORT statement:

	FROM C IMPORT printf;
    
    all of the following statements are legal:

	printf;
	printf(string, integer, longreal);
	cardinal = printf(string, integer, longreal);

gak@mhuxm.UUCP (Vincent Hatem) (04/11/88)

In article <535@m10ux.UUCP>, rgr@m10ux.UUCP (Duke Robillard) writes:
> In article <764@ndsuvax.UUCP> ncreed@ndsuvax.UUCP (Walter Reed) writes:
> >Here is an example of why these things bother me.
> >	IF (x = TRUE) THEN
> >		WriteString("Error #");
> >		WriteCard(e);
> >		WriteString(" in line #");
> >		WriteCard(l);
> >		WriteString(" detected.");
> 	:
>	:
> the solution.  Has anyone ever written some kind of front end for a 
> modula compiler to turn printf's into WriteSh*t's?  It doesn't seem 
> 	:
> |       Duke Robillard
> |       AT&T Bell Labs           m10ux!rgr@ihnp4.UUCP                 
> |       Murray Hill, NJ          {any biggy}!ihnp4!m10ux!rgr

Come on... give me a break. If you don't like the I/O subsystem, why don't
you re-write it??? A front-end translator in m4 is silly.

Besides, the whole idea of the WriteCard()-style I/O system is to remove the
20K overhead that printf() adds to programs. 95% of the functionality of 
printf() is never used, and you're just making your text segment larger.

I've worked on a replacement for printf() in Modula-2 which allowed most of
the basic formatting of numbers/strings which are used regularly. It also
allowed for OOP Object I/O function definitions, which allow you to tell it
to Write an Object with the functionality of a c++ construct such as this:
	cout << some_object_instance;

I'd post it, but it is based on a new I/O system (which I also worked on),
which is incompatible with Wirth's I/O system. (there used to be talk of 
making the library we wrote Freeware, but I haven't seen it yet...)



-- 
Vincent Hatem
AT&T International, International Systems Operations, UNIX Technical Support
                        Telefon: (201) 953-8030
		Please send all e-mail to: ihnp4!atti01!vch

rgr@m10ux.UUCP (Duke Robillard) (04/12/88)

In article <96@lzaz.ATT.COM> bds@lzaz.ATT.COM (BRUCE SZABLAK) writes:
>In article <535@m10ux.UUCP>, rgr@m10ux.UUCP (Duke Robillard) writes:
>> I hate C as much as the next guy, but it seems to me that printf is
>> the solution.
>
>I like C++'s overloading of the << and >> operator's even better than
>printf. It allows you to define custom print routines for each structure
>(class) declared, and then to print (to stdout for example) you do:
>	cout << god_awful_structure_instance;

Yeah, but that doesn't help me print out an error message, two strings,
and an integer return code.  I don't want to have to write a method
for every print....



-- 
+                                
|       Duke Robillard
|       AT&T Bell Labs           m10ux!rgr@ihnp4.UUCP                 
|       Murray Hill, NJ          {any biggy}!ihnp4!m10ux!rgr

alan@pdn.UUCP (Alan Lovejoy) (04/12/88)

In article <96@lzaz.ATT.COM> bds@lzaz.ATT.COM (BRUCE SZABLAK) writes:
>I like C++'s overloading of the << and >> operator's even better than
>printf. It allows you to define custom print routines for each structure
>(class) declared, and then to print (to stdout for example) you do:
>	cout << god_awful_structure_instance;
>The advantage of this approach over using procedures in
>modula2 or pascal is (besides previty) that you don't have to
>remember the type of structure your variable is; the compiler figures it out.

Overloading or procedure-name-abstraction is badly needed in Modula-2.
However, it needs to be applicable to ANY AND ALL procedures and
operators.  For printing, I prefer:

  Print(object, fieldWidth);

The programmer writes a Print procedure for each data type he defines
and/or wants to print.  

Better yet, he writes a "BinToStr" procedure for each data type.  Then Print 
can be defined generically once:    

  PROCEDURE Print(object; fieldWidth: CARDINAL);
    VAR
      str: ARRAY [0..79] OF CHAR;
  BEGIN
    BinToStr(object, fieldWidth);
    Display.WriteString(str);
  END Print;

Notice that this also requires the additional capability to define
parameters of unspecified type.  To compile this procedure, the
compiler generates abstract pseudo-code which is data-type independent 
as its final output instead of object code.  Object code for the procedure 
is generated each time the compiler discovers an actual call to the procedure, 
because only then can it know the data type of the typeless argument and
generate the correct code.
    

-- 
Alan Lovejoy; alan@pdn; 813-530-8241; Paradyne Corporation: Largo, Florida.
Disclaimer: Do not confuse my views with the official views of Paradyne
            Corporation (regardless of how confusing those views may be).
Motto: Never put off to run-time what you can do at compile-time!  

bds@lzaz.ATT.COM (BRUCE SZABLAK) (04/13/88)

In article <547@m10ux.UUCP>, rgr@m10ux.UUCP (Duke Robillard) writes:
> In article <96@lzaz.ATT.COM> bds@lzaz.ATT.COM (BRUCE SZABLAK) writes:
> >I like C++'s overloading of the << and >> operator's even better ...
> 
> Yeah, but that doesn't help me print out an error message, two strings,
> and an integer return code.  I don't want to have to write a method
> for every print....
> 

In C++:

#include <stream.h>

Then:
...
  cout << "error message " << string1 << " " << string2 << " " << rc;
...

The header file defines printing for the ususal types.

dhesi@bsu-cs.UUCP (Rahul Dhesi) (04/13/88)

In article <730@mhuxm.UUCP> gak@mhuxm.UUCP (Vincent Hatem) writes:
>Besides, the whole idea of the WriteCard()-style I/O system is to remove the
>20K overhead that printf() adds to programs.

Actually, the story I hear is that WriteCard was originally meant
(back when Wirth was developing languages on an old CDC machine)
to punch a card.  Nostalgia being what it is, WriteCard now
prints unsigned integers.

If you'll believe that, you'll also probably believe that Modula-2
is an improvement on Pascal.
-- 
Rahul Dhesi         UUCP:  <backbones>!{iuvax,pur-ee,uunet}!bsu-cs!dhesi

mike@turing.UNM.EDU (Michael I. Bushnell) (04/13/88)

In article <730@mhuxm.UUCP> gak@mhuxm.UUCP (Vincent Hatem) writes:

>Besides, the whole idea of the WriteCard()-style I/O system is to remove the
>20K overhead that printf() adds to programs. 95% of the functionality of 
>printf() is never used, and you're just making your text segment larger.

On 4.3 BSD on a Vax, I get the following:

% size doprnt.o
text	data	bss	dec	hex
2196	36	0	2232	8b8

% size printf.o
text	data	bss	dec	hex
40	36	0	76	4c

To use printf, it ups your text segment by a whole 2236 bytes.  Wow.
It also isn't too slow: 4.3BSD doprnt is coded in assembly language
and manages to be quite fast.  Puts is about 10% of that (200 bytes)
but isn't really any faster.  But CERTAINLY NOT a "20K" overhead.  Go
ahead and use printf.  It doesn't really cost you that much.



                N u m q u a m   G l o r i a   D e o 

			Michael I. Bushnell
			HASA - "A" division
14308 Skyline Rd NE				Computer Science Dept.
Albuquerque, NM  87123		OR		Farris Engineering Ctr.
	OR					University of New Mexico
mike@turing.unm.edu				Albuquerque, NM  87131
{ucbvax,gatech}!unmvax!turing.unm.edu!mike

faustus@ic.Berkeley.EDU (Wayne A. Christopher) (04/13/88)

In article <730@mhuxm.UUCP>, gak@mhuxm.UUCP (Vincent Hatem) writes:
> Besides, the whole idea of the WriteCard()-style I/O system is to remove the
> 20K overhead that printf() adds to programs. 95% of the functionality of 
> printf() is never used, and you're just making your text segment larger.

I doubt this is the reason -- hardly anybody cares about text segment size
any more, and in any case, printf is only 2K, not 20K.  (In Ultrix -- your
mileage may vary.)

	Wayne

uday@mips.COM (Robert Redford) (04/13/88)

In article <2608@bsu-cs.UUCP>, dhesi@bsu-cs.UUCP (Rahul Dhesi) writes:
> Actually, the story I hear is that WriteCard was originally meant
> (back when Wirth was developing languages on an old CDC machine)
> to punch a card.  Nostalgia being what it is, WriteCard now
> prints unsigned integers.

     WriteCard stands for WriteCardinal. There is a standard library module
     CardinalIO that deals with the IO of cardinal numbers. In fact there is
     a predefined data type CARDINAL. It has nothing to do with cards.


                                              ..Uday
       

gjditchfield@violet.waterloo.edu (Glen Ditchfield) (04/13/88)

In article <547@m10ux.UUCP> rgr@m10ux.UUCP (Duke Robillard) writes:
>In article <96@lzaz.ATT.COM> bds@lzaz.ATT.COM (BRUCE SZABLAK) writes:
>>I like C++'s overloading of the << and >> operator's even better than
>>printf. It allows you to define custom print routines for each structure
>>(class) declared, and then to print (to stdout for example) you do:
>>	cout << god_awful_structure_instance;
>
>Yeah, but that doesn't help me print out an error message, two strings,
>and an integer return code.  I don't want to have to write a method
>for every print....

Neither would I.  Fortunately for us, the i/o operators can be chained.
	cout << "Error: file " << fname << ", line " << lnum
	     << error_msg << "\n";
I think this is a big improvement over calls to overloaded "Print" procedures.

Details: "<<" associates left-to-right.  `cout << "Error: file "' returns
cout as it's value, which is used as the left operand by `<< fname'.  When
streams like cout (or the standard input, "cin") are used in an integer
context, the stream-to-int conversion returns the stream's status, so you
can write input loops like
	while ( cin >> val ) { ...
If a programmer-defined type must be read or written, the programmer writes
"<<" and ">>" operators for it.

ecb@pluto.uucp (Eric Brown) (04/16/88)

In article <942@unmvax.unm.edu> mike@turing.UNM.EDU.UUCP (Michael I. Bushnell) writes:
>To use printf, it ups your text segment by a whole 2236 bytes.  Wow.
>Puts is about 10% of that (200 bytes)
>but isn't really any faster.  But CERTAINLY NOT a "20K" overhead.  Go
>ahead and use printf.  It doesn't really cost you that much.

Now include the size of the floating point libraries.  On Microsoft 5.0 C,
calling printf links the floating point emulator, which is about 30K of code.
Is this significant?  I think so.  I once hacked out 300K out of a suite of
programs by transforming printf's to puts'es and also by using an integer-only
printf.  Sometimes, every byte counts.  Not all the world is a vax, you know.

	-Eric, Called Ultrahacker

rgr@m10ux.UUCP (Duke Robillard) (04/17/88)

In article <6366@watdragon.waterloo.edu] gjditchfield@violet.waterloo.edu (Glen Ditchfield) writes:
]In article <547@m10ux.UUCP] rgr@m10ux.UUCP (Duke Robillard) writes:
]]In article <96@lzaz.ATT.COM] bds@lzaz.ATT.COM (BRUCE SZABLAK) writes:

]]]	cout << god_awful_structure_instance;

]]Yeah, but that doesn't help me print out an error message, two strings,
]]and an integer return code.  I don't want to have to write a method
]]for every print....
]
]Neither would I.  Fortunately for us, the i/o operators can be chained.
]	cout << "Error: file " << fname << ", line " << lnum
]	     << error_msg << "\n";

    This is cool.  The syntax is a little bulky (how un-C-like) but
overall it looks good.

]I think this is a big improvement over calls to overloaded "Print" 
]procedures.

    However, I don't really see that this is any different than 
overloading a print procedure.  all you're doing is overloading "<<"
(i.e. making it handle strings, integers, reals, whatever), right?



-- 
+                                
|       Duke Robillard
|       AT&T Bell Labs           m10ux!rgr@ihnp4.UUCP                 
|       Murray Hill, NJ          {any biggy}!ihnp4!m10ux!rgr

djones@megatest.UUCP (Dave Jones) (04/19/88)

in article <553@m10ux.UUCP>, rgr@m10ux.UUCP (Duke Robillard) says:

...

  [ cout << foo << bar; // etc. ]

> 
>     However, I don't really see that this is any different than 
> overloading a print procedure.  all you're doing is overloading "<<"
> (i.e. making it handle strings, integers, reals, whatever), right?
> 

That's right.  It's just easier to type and to read than having a
jillion "print"'s.

For better or worse (*better* in my opinion), C++ classes don't tend
to "know how to print themselves".  Instead you overload the << operator
to print new classes.   Also remember that in C++, "int" is not a class!!  
So the function can't be a member of class int. Translated into 
Smalltalk, the class "int" does not recognize the message "<<".

"Print an int" _could_ be an external function, defined this way:

   ostream& operator<< (ostream& o, int a) {return o << (long)a;}

There is an argument to be made that it SHOULD be declared this way,
to reduce the number of member functions of ostream. That is to say,
to reduce the number of types which ostream "knows about".

But the way things are actually implemented, the function is a member of 
ostream, and has this declaration:

    ostream& operator<<(int a) { return *this<<long(a); }

chris@mimsy.UUCP (Chris Torek) (04/21/88)

>In article <942@unmvax.unm.edu> mike@turing.UNM.EDU.UUCP (Michael
>I. Bushnell) writes:
>>To use printf, it ups your text segment by a whole 2236 bytes. ...

In article <230@jupiter.olyis.UUCP> ecb@pluto.uucp (Eric Brown) writes:
>Now include the size of the floating point libraries.  On Microsoft 5.0 C,
>calling printf links the floating point emulator, which is about 30K of code.
[stuff deleted]
>Not all the world is a vax, you know.

Conversely, not all the world is an IBM PC with a Microsoft compiler.
It is not difficult[*] to arrange for the linker to pull in a simple
printf() if the rest of the program does not use floating point, and a
full-blown floating point printf if it does.  Just because Microsoft's
implementation is poor (in terms of space, at any rate) is no reason to
castigate printf itself.

-----
[*]What, never?  Well, hardly ever.  The trick is to have the linker
examine the undefined externals for floating-point library references,
and if present, link with `bigprintf.obj'; otherwise it should use
`littleprintf.obj'.  It is just a Small Matter of Programming.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

dhesi@bsu-cs.UUCP (Rahul Dhesi) (04/22/88)

In article <11154@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>It is not difficult[*] to arrange for the linker to pull in a simple
>printf() if the rest of the program does not use floating point, and a
>full-blown floating point printf if it does.

Turbo C 1.0 seems to do this.
-- 
Rahul Dhesi         UUCP:  <backbones>!{iuvax,pur-ee,uunet}!bsu-cs!dhesi

friedl@vsi.UUCP (Stephen J. Friedl) (04/22/88)

In article <11154@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes:
> It is not difficult[*] to arrange for the linker to pull in a simple
> printf() if the rest of the program does not use floating point, and a
> full-blown floating point printf if it does.  [....]
>
> [*]What, never?  Well, hardly ever.  The trick is to have the linker
> examine the undefined externals for floating-point library references,
> and if present, link with `bigprintf.obj'; otherwise it should use
> `littleprintf.obj'.  It is just a Small Matter of Programming.

This brings up an interesting question.  The C compiler on the
Onyx Z8000 (R.I.P.) would generate a symbol "_fltused" if any
floating point of any kind was used in that particular module.
When the linker went to resolve everything, it loaded in the
floating-point emulator if this symbol was found and didn't if it
wasn't.  As far as I could tell, this symbol was nothing more
than a indicator to ld(1).  Does anybody else do this?  It seems
so much more reasonable than the ubiquitous "-f" flag.

-- 
Steve Friedl       V-Systems, Inc.      Resident access(2) basher
friedl@vsi.com   {backbones}!vsi.com!friedl    attmail!vsi!friedl

henry@utzoo.uucp (Henry Spencer) (04/24/88)

> >Now include the size of the floating point libraries.  On Microsoft 5.0 C,
> >calling printf links the floating point emulator, which is about 30K of code.
> >...Not all the world is a vax, you know.
> 
> It is not difficult[*] to arrange for the linker to pull in a simple
> printf() if the rest of the program does not use floating point, and a
> full-blown floating point printf if it does...

In fact, if your C implementation has a limited address space and a bulky
floating-point library and does NOT do this, complain to the implementors.
It's not a novel or strange idea.  The very first C implementation, on the
pdp11, used this trick.  If Microslop can't be bothered, don't buy their
compiler.
-- 
"Noalias must go.  This is           |  Henry Spencer @ U of Toronto Zoology
non-negotiable."  --DMR              | {ihnp4,decvax,uunet!mnetor}!utzoo!henry

henry@utzoo.uucp (Henry Spencer) (04/24/88)

> ... The C compiler on the
> Onyx Z8000 (R.I.P.) would generate a symbol "_fltused" if any
> floating point of any kind was used in that particular module.
> When the linker went to resolve everything, it loaded in the
> floating-point emulator if this symbol was found and didn't if it
> wasn't.  As far as I could tell, this symbol was nothing more
> than a indicator to ld(1).  Does anybody else do this? ...

Onyx borrowed this from the original pdp11 C implementation, in fact, which
used this technique to pick up a non-floating-point printf if floating
point was not in use.  It didn't even require any special trickery in the
linker:  generate an external reference to fltused when floating-point is
used; have two versions of the internal floating-point-formatting function,
one which implements the full show and also defines fltused and one which
does the integer subset and doesn't define fltused; and arrange for the
fltused version to be seen by the linker before printf and the non-fltused
version are seen.

> ... It seems so much more reasonable than the ubiquitous "-f" flag.

It's a reasonable substitute for -f only if you assume that the hardware
never has proper floating-point support, or if you don't care about hauling
the floating-point software along unnecessarily.  The Onyx came under the
former heading, as I recall.
-- 
"Noalias must go.  This is           |  Henry Spencer @ U of Toronto Zoology
non-negotiable."  --DMR              | {ihnp4,decvax,uunet!mnetor}!utzoo!henry

gwyn@brl-smoke.ARPA (Doug Gwyn ) (04/24/88)

In article <230@jupiter.olyis.UUCP> ecb@pluto.UUCP (Eric Brown) writes:
>In article <942@unmvax.unm.edu> mike@turing.UNM.EDU.UUCP (Michael I. Bushnell) writes:
>>Go ahead and use printf.  It doesn't really cost you that much.
>Now include the size of the floating point libraries.

Sounds to me like to need to have a little talk with your compiler vendor.
There is no need to link floating-point support into the process image
when the application has made no use of floating point.  Even the old PDP-11
UNIX got this right -- there were two _doprnt entries in the library, one for
use with floating-point and one without; the choice was tied to whether or
not the compiler had generated a ".fltused" reference.

mcdonald@uxe.cso.uiuc.edu (04/25/88)

>In fact, if your C implementation has a limited address space and a bulky
>floating-point library and does NOT do this, complain to the implementors.
>It's not a novel or strange idea.  The very first C implementation, on the
>pdp11, used this trick.  If Microslop can't be bothered, don't buy their
>compiler.
-- 

The following program
#include <stdio.h>
main()
{
  int i = 5;
  printf("%d is an int\n",i);
}
compiles and links under Microsoft C 5.00 to a .exe file 7089 bytes long.
Changing "int" to "double" and %d to %lf results in a file 21242 bytes long.
The Microsoft C compiler is quite good, better than most Unix ones, I would 
guess. It has myriads of options that allow you do get just what you want.

Doug McDonald

swarbric@tramp.Colorado.EDU (Frank Swarbrick) (04/27/88)

In article <225800026@uxe.cso.uiuc.edu> mcdonald@uxe.cso.uiuc.edu writes:
:The following program
:#include <stdio.h>
:main()
:{
:  int i = 5;
:  printf("%d is an int\n",i);
:}
:compiles and links under Microsoft C 5.00 to a .exe file 7089 bytes long.
:Changing "int" to "double" and %d to %lf results in a file 21242 bytes long.
:The Microsoft C compiler is quite good, better than most Unix ones, I would 
:guess. It has myriads of options that allow you do get just what you want.

I just thought I'd mention this, Turbo C 1.5 gets EXE files of 5750 bytes
and 19662 bytes respectivly with this code...

Frank Swarbrick (and his cat)           swarbric@tramp.Colorado.EDU
...{ncar!nbires}!boulder!tramp!swarbric
"The shifting shafts of shining weave the fabric of their dreams..."