Path: utzoo!utgpu!water!watmath!clyde!att!osu-cis!tut.cis.ohio-state.edu!bloom-beacon!mit-eddie!ll-xn!ames!pasteur!agate!ucbvax!unizh.UUCP!nagler%olsen
From: nagler%olsen@unizh.UUCP (Robert Nagler)
Newsgroups: comp.lang.modula2
Subject: Re: C v.s. Modula II
Message-ID: <8808151857.AA05996@klaus.olsen.uucp>
Date: 15 Aug 88 18:57:27 GMT
Sender: daemon@ucbvax.BERKELEY.EDU
Reply-To: Info-Modula2 Distribution List 
Organization: The Internet
Lines: 220

Question:  Do people like these conversations?  I seems to me
    that C vs. M2 on an M2 mailing list is a bit silly.  I realize
    the need for open debate, but anyone who has done serious work
    in M2 (Son of Mesa) would undoubtably agree that M2 is superior
    to C.  Please respond to me directly to keep down the temperature
    on the net.

Sorry for the length, but it seems there is a lot of misinformation
going around.

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:

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.  They also
did an AGC, but I don't see as a must (as I've mentioned a while
ago in another note).   We do "Real Programs" here which deal with
Real Customers on a 24 hour a day basis all year long (except when
the A/C goes out).  Everyone who sees our work says: "You did this
ALL in M2?"  Funny, how empirical evidence kills even the most
die-hard blow-hards.

>>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).  In M2, this would simply be a change to
the def mod.  In C, you would have to change *every* single reference
to that procedure.  Ah yes, we always pass our parameters by reference
in C, therefore this should never occur? [See below]

>>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();
In M2, this couldn't happen (in Pascal, it could).

>>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.  This is
the most significant advance in programming since type checking
(in my humble opininion).  If someone changes a structure in C,
you may never know about it (I've seen "make -t" abused too often).
Compiled interfaces eliminate this problem.

>>5.  I miss MESA INLINE procedures.  They are simpler and (often) more
>>efficient than C's macro expansions.
>Actually, they are not always simpler.  What are the semantics of the
>static variable below?:
>        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?

>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.  [This convention seems to have been
adopted by an earlier inadequacy in C compilers.  Kind of like "stay away
from enumerated types."]   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).

One of my favorite features of C is:
    scanf( "%d", i );
I can't tell you how many times I have had to help novice C programs
with this.  If "i" is on the stack, you get pretty random results.
    scanf( "%s\n", "Some string to print" );
Is also interesting.  Sometimes people make mistakes, but far be it
for the compiler to tell them that they are stupid.

-- END Reply -- BEGIN A Different Perspective

The following is *my* comparison between C and M2.  I have taken a
typical procedure in Unix (which I was so fortunate enough to use
the other day) and declared it in M2 and C.  The C declaration is
first.  The function "setitimer" was taken from the "man page" and
the supporting declarations were taken from an include file "sys/time.h"
comments were included (were appropriate).

struct timeval {
    long    tv_sec;         /* seconds */
    long    tv_usec;        /* and microseconds */
};
/*
 * Names of the interval timers, and structure
 * defining a timer setting.
 */
#define ITIMER_REAL     0
#define ITIMER_VIRTUAL  1
#define ITIMER_PROF     2

struct  itimerval {
    struct  timeval it_interval;    /* timer interval */
    struct  timeval it_value;       /* current value */
};

setitimer(which, value, ovalue)
int which;
struct itimerval *value, *ovalue;

Is "value" modified?  What is the return value of the function?  Ah
yes, -1 means false and 0 means true.  WAIT, 0 means false in C and
non-zero means true.   However, 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.
Believe it or not, I have looked at this man page on several different
occasions and still have trouble remembering which way is up.

In M2, I would define the procedure as follows:
TYPE
    Time = RECORD
        seconds      : CARDINAL;
        microseconds : CARDINAL;
    END;
    TimerSetting = RECORD
        interval : Time;  (* Value to reload after "first" expires *)
        first    : Time;  (* Relative amount to "now" for expiration *)
    END;
    TimerTypes = (  (* Three distinct timers per process which measure: *)
        real,   (*    real time *)
        virtual,    (*    time when process is in user code *)
        profile     (*    virtual and time when process runs in kernel.
                          Warning: SIGPROF interrupts system calls! *)
    );
PROCEDURE setitimer(
        which    : TimerTypes;
        value    : TimerSetting; (* If value.first = 0, turn off timer *)
    VAR oldValue : TimerSetting
    )        : BOOLEAN;          (* FALSE ==> failure; see errno (ugh!)*)

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.

We use a lot of C-Unix interfaces in our Modula-2 via special def mods
supported by the Sun Compiler (thanx Sun).  In all cases, we immitate the
C declarations as they are defined in C.  In no cases, have I been unable
to translate the C declarations.   However, if I were given the reverse
to do in C, you would be hard-pressed to do some of the following:

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

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

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


I have spoken before about these trivialities as above as well
as the real features of M2.  I am interested in honest answers.
How many of the "C" people who read this list have programmed
in Modula-2 (or Mesa for that matter)?  Do you want to know what
real problems are?  Do you care?

I've programmed in C for five years and in Modula-2 for four years.
I liked C, because it freed me from Pascal.  I like M2, because it
allows me to design and build systems quickly and efficiently.  With
C I am still trying to figure out which makefiles I *must* include
before I include the one I want (among other things).

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?).  Most of the M2 implementations
don't do: automatic inlining (not so hard), register allocation (local
would be fine), any amount of code optimization, and/or code elimination.

The problem is that no one takes a half a minute to think what it
would take to make a good M2 compiler.  (I'll supply a empirically
proven portable library free of charge.)  Forget the past, one
company says, and implements a great one-pass compiler.  Another
company rewrites their compiler/linker (from scratch) and now it
doesn't link our system so we have to stick with the old version.
However, almost every PC M2 compiler comes with its own handy-dandy
text editor so that it will sell to the people who use it once and
then shelve it.  Short-sightedness (both forwards and backwards)
is killing M2.  The language itself isn't nearly as bad as the
implementation madness.

Even with all of these problems I can still write a program that uses
>100 light-weight processes, screen graphics, and user interrupts and
port it from the PC to the Sun in under an hour.  The LWP model was
ported in a couple of days from the PC to the Sun.  You just don't
know until you've tried it.  M2 ain't so bad.

Once again, sorry for the length.  I hope this helps someone.

Rob Nagler     mcvax!olsen!nagler@uunet.uu.net
Olsen & Associates/Research Institute for Applied Economics/Zuerich