Path: utzoo!utgpu!attcan!uunet!husc6!mailrus!ncar!oddjob!mimsy!chris
From: chris@mimsy.UUCP (Chris Torek)
Newsgroups: comp.lang.modula2
Subject: Re: C v.s. Modula II
Message-ID: <13018@mimsy.UUCP>
Date: 16 Aug 88 06:47:29 GMT
References: <8808151857.AA05996@klaus.olsen.uucp>
Organization: U of Maryland, Dept. of Computer Science, Coll. Pk., MD 20742
Lines: 275

>Chris Torek writes:
>>Mesa is considerably more useful for writing Real Programs than is
>>Modula-II, if only because its I/O really is standard (or at least
>>only has to deal with one O/S!).  So this is more of a Mesa-vs-C:

In article <8808151857.AA05996@klaus.olsen.uucp> nagler%olsen@unizh.UUCP
(Robert Nagler) writes:
>There is more than enough supporting evidence to the contrary since
>DEC-SRC (loaded with PARC people) have been using M2+ which merely
>has built-in monitors, exceptions, and generic pointers.

`Merely'?!

>>>2.  Local changes can require non-local code restructuring.

>>Not if you format well :-) .

>What if you change a parameter from by-value to by-reference (for
>performance reasons).

You have me there (but then that was why I put in the `:-)' ).  But
this is irrevocably tied in with the `var' parameter declaration
format, which I personally hate.

>>>Adding an else-clause can require you to restructure the {}'s.

>>Nope:

>Yup:
>    if (a)
>        if (b)
>            do_this;
>goes to:
>    if (a)
>        if (b)
>            do_this();
>    else
>        do_that();

But (says he) the original code is not `well-formatted':

    if (a) {
	if (b) {
	    do_this;
	}
    }

Adding the else is now trivial.

Basically, this just means using full bracketing even though the
language does not provide fully bracketed constructs (I happen to like
fully bracketed syntax a la Algol, even to the silly sdrawkcab
spellings).

>>>3.  Include files are hard to keep track of, nest, and structure in a...

>>Any automated scheme (Mesa's is semi-automated) tends to work better...

>Wrongo! The advantage of Mesa is *compiled* interfaces.

Funny, our Mesa people seem to spend about half their time working
around this `advantage', since Xerox keeps sending incompatible
revisions of things.  (Not a problem with the language!)

>This is the most significant advance in programming since type checking
>(in my humble opininion).

Hm?  It *is* type checking.  Mesa embeds it in the language by
providing syntax and semantics for it.  You still have to use it by
hand (hence `semi-automated').

>>>5.  I miss MESA INLINE procedures.  They are simpler and (often) more
>>>efficient than C's macro expansions.

>>   inline int unique_integer() { static int next; return (next++); }

>In M2 (Mesa), you would never write a procedure this way.
>Module variables are used instead of static variables.  In fact,
>you wouldn't write a macro this way in C?  What language is that?

It is one of the GNU C compiler's (numerous) extensions to C.

A Mesa module variable is simply a static variable that is local to a
module, just like C file-static (or if exported, just like C
file-global).  As such, it cannot be part of an inline function that is
also accessible-but-still-in-line outside that module.  GCC gets this
right, by allowing inline functions outside modules (and playing naming
games to get it to work at all).

>>Someone else complained about a lack of `var' parameters....
>>      munch(a, b, &c, d, e + 7);
>>I can assume that it cannot change a, b, and d....

>Almost every parameter (>int) in C is passed by-reference, so you
>never know what's being modified.

I disagree with this claim, but even granting it (temporarily! :-) ),
while I do not know what *is* being modified, I *do* know what *cannot*
*be* modified, which to me is at least as important.

>... My biggest problem with Unix man pages is
>that you never know what the function is expecting unless you read
>the detailed descriptions of all the parameters).

Funny, the same would be true if it were M2 and the parameters were
declared `var', without any other changes.  What is needed is access
rights (e.g., Ada---much as I think that language is overdone).

>One of my favorite features of C is:
>    scanf( "%d", i );

# this is one reason why `lint' should be run every time you run the
# compiler (not that there are no reasons not to run lint every time):
% cat t.c
main() { int i; scanf("%d", i); exit(0); }
% lint t.c
t.c:
t.c(1): warning: scanf argument is type (int) rather than pointer (arg 2)
t.c(1): warning: i may be used before set
scanf returns value which is always ignored
%

A deficient implementation is not a reason to complain about the
language!  And, similarly, a good but extended implementation, such as
your M2+, or any other M2 with the (remarkably few, but sometimes
remarkably large, as in I/O) holes filled in is not a reason to praise
the language.

[comparison of 4.2BSD setitimer declarations vs. newly created
equivalent M2 declarations]

>... I needless to say had to read the man page several times to figure
>out that "it_value" was relative to now and that "it_interval" would be
>reloaded *after* "it_value" expired.

In other words, the names and comments in the first part of the manual
entry---the part where the type of the function (including arguments)
is described---are insufficient.  You then provide a different version
written in M2 syntax, with *different names* and *different comments*:

>The first thing to note is that there are no descriptions of the names!
>I don't have comments like "/* and microseconds */" to clutter up the
>brain.   Comments contain *new* information which generally contains
>some semantic content that could not otherwise be provided by the
>M2 part of the declaration.  With this (C-like) M2 declaration,
>I believe I could have guessed how setitimer works.

And from changing the names and the comments, you conclude that the M2
declaration (which you wrote, so naturally you will understand it) is
inherently superiour to the C declaration?

C declarations do have their problems.  The major complaint seems to be
that they are overly terse; I also believe that the various pre- and
post-fix styles are part of the problem.  If `pointer' always came
after the name, or if `function returning' always came before, most of
the mysterious parentheses in C declarations like

	void (*signal(int sig, void (*sigfn)(int sig)))(int sig);
	/* to use the dpANS declaration syntax */

would go away.  But you seem to imply that M2 would somehow automatically
improve naming conventions and commenting, which I find unlikely.

>PROCEDURE Insert(
>    key   : ARRAY OF SYSTEM.BYTE;       (* BTW, can I do HIGH( key ) in C? *)
>    );

I have forgotten what HIGH(key) is supposed to do, but assuming that it
does the obvious---returns the size of the array, in whatever units---
the answer is `yes and no': you can get the size, but the caller must
provide the size; the called procedure can no longer obtain it.  This
is done so that the procedure call conventions need not provide array
descriptors, and because arrays are second-class data objects in C
(which, incidentally, *is* one of C's serious shortcomings).

	void Insert(void *key, size_t keylength);
	/* again, dpANS syntax. also legal is:
	void Insert(void *, size_t)
	   but I think not using parameter names is dumb */

>TYPE
>    IntPtr = POINTER TO INTEGER;
>    SomeProc = PROCEDURE (
>        Object,
>    ) : IntPtr;
>PROCEDURE Foo(
>    bar : Object;
>    val : CARDINAL
>    )   : SomeProc;


(I do not understand the syntax `PROCEDURE(Object,)'.  Since M2 does
not have first class functions, I assume that SomeProc is actually
a pointer to some sort of procedure.  Anyway:)

	typedef int *IntPtr;
	typedef IntPtr (*SomeProc)(XXX);/* where XXX depends on what
					   the above means */

	SomeProc foo(Object bar, unsigned val);

>TYPE
>    Values = [ 0 .. 65535 ];    (* int? short? char? Your guess... *)
>    Bits   = SET OF [ 0 .. 15 ];        (* ditto *)

Ranges are another real shortcoming in C.  But I do wonder what
you get if you declare, e.g.,

TYPE small = [0..12]; VAR a, b : small; ...
     a := 9; b := 11; a := a + b;

How is this defined?  I hope it must be a (presumably run-time) error,
with a compile-time warning allowed if the compiler is good.  (If the
compiler is good enough and can prove that the code above must execute,
a compile-time error would be even better.)

For minimum ranges, the dpANS says that an `unsigned short' must
be able to hold the values in 0..65535, hence it would suffice for
both types above.  Speaking of sets, has M2 fixed the Pascal hole
about sets?  That is, must the compiler do the right thing for

    TYPE bigset = SET OF [0..41];

?  (Pascal allows compilers to abort if the set contains more bits than
fit in a `machine word'---whatever that may be :-) .  While some
implementations allow larger sets, it is NOT part of the language, and
this must be considered in any language discussion.  More below:)

>What's bad about M2?  There are two flavors of implementations:
>one-pass and two-pass.  The two-pass systems are more mature.
>The one-pass systems are probably better, but it is hard to use them
>because we wrote 500 modules using the two-pass style (anyone written
>an automatic converter yet?).

Why should one need a converter?  Either forward declarations are
unnecessary and the compiler had better do the right thing no matter
how many passes it uses internally, or they are required and a two
(or N) pass compiler had better complain if they are not there.
Anything else is not M2 (unless the language definition really says
that compilers can complain depending on how they are implemented!).

[more woes about existing implementations deleted]

The implementation is not the language.  No doubt there are some
terrible implementations of M2, as well as some good ones.  The same is
true of C.  The biggest hole in the language is that it does not
provide any I/O.  Neither does C-the-language-syntax-and-semantics, but
stdio is considered a part of `the language'.  If there were a standard
I/O package for M2, the hole would vanish.

As a `for instance', consider VAX/VMS FORTRAN.  By all accounts this
is a wonderful implementation, and is a language in which it is easy
to write reasonable code that runs quickly and does whatever task is
at hand.  On the other hand, the 4.2BSD f77 FORTRAN compiler is slow,
buggy, produces lousy code, and has a weak library.  Neither one says
anything about the language *per se*.

Basically, my point can be stated thus:  If you have to extend the
language---either in internal syntax or in support libraries---to
accomplish what you must do, the language is insufficient for your
needs.  Since literally everyone has to extend Modula II for anything
that reads input or prints a result, that language is insufficient for
those needs.  Clearly, if you finish your task, the (new) language
*is* sufficient for those needs.

Anyway, while it is possible to compare specific features of one
language with those of another, I think blanket comparisons will always
fail in some way.  I will not claim that C is `better' than M2, nor
vice versa.  I *will* say that I like this feature, or dislike that
one.  I will also go so far as to say that discarding some features in
favour of `better' ones from another language might not improve the
first language after all.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris