[comp.lang.modula2] C vs. M2

nagler%olsen@unizh.UUCP (Robert Nagler) (08/15/88)

In reply to: Steve Losen     scl@virginia.edu

> Bitwise operators  & (and), | (or), ^ (xor), ~ (complement)
Modula-2 has types called SET and BITSET.  The operations of set
inclusion, exclusion, subtraction, union, intersection, etc. are
supported.  For example, in order to do set subtraction in C you must:
        x = y & ~z;
In M2, this statement is:
        x = y - z;

> Shift operators >> (right shift) << (left shift).
In the old days, one used to use / and * to get these operations.
Well, you know, this still works.  I realize this is a bit archaic,
but I rarely have the need for these operations if I have proper set
arithmetic.  For example, the following is quite common in C:
        x &= ~( 1 << 5 );
In M2, this is:
        EXCL( x, 5 );

> Pre and post increment/decrement operators (++, --);
INC, DEC are a hack in M2 to satisfy people who think they can out-code
a compiler. (With most M2 compilers, this is understandable...).

> The ? : operator, eg, x = (y < 2 ? 10 : 20) + y;  is the same as
>       if (y<2) x = 10 + y; else x = 20 + y;
Pardon me, but did you ever program in APL?

> Treatment of assignment (=) as an expression, eg, x = (y = 10) + 1; is
>       equivalent to y = 10; x = 10 + 1;
How often do you use this stuff?  BTW, you left out such fancy things as:
        if ( a = x, b = y ) do_it;
        if ( a == ( b = c ) ) foo_bar;
Oh yes, M2 doesn't allow underscores, but it is case sensitive.

> Large assortment of assignment operators (+=, -=, *=, /=, &=, |=, etc)
>       eg, x *= 2; is equivalent to x = x * 2;
M2 doesn't go into that sort of thing.  Seems like even the most
rudimentary expression optimizer could take care of this problem
lickety-split.

> Guaranteed left to right short circuit evaluation of logical expressions
Have you ever used M2?  Most of the expression semantics are identical
to that of C.

You can't really compare M2 and C.  They are two different beasts.
Modula-2 is a system programming language for writing portable modular
software.  C is a system programming language for writing device drivers
and small utilities such as awk, grep, ls, etc.  If you have ever tried
to maintain a large system written in C, you understand what I mean.

Granted that C allows you to program "efficiently", but then you might
ask the question: if C is so efficient, why do most people write functions
like swab, bcopy, bcmp, printf, etc. in assembler?  It has been my
experience that C programs run faster only because of the "register"
primitive.  However, the fastest C code I have seen ignores this
declaration (or rather, uses it as advice).   It has also been my
experience that the software development process goes much faster in M2
as opposed to C simply because of modules and type checking.  Funny how
the 90/10 rule applies not just to code, but also to programming languages.

Rob

PS. Riddle of the day.  How do you do the following in C?
    TYPE
        RealPtr = POINTER TO REAL;
        X = PROCEDURE (
            CARDINAL
            ) : RealPtr;
        A = ARRAY [ 0 .. 5 ] OF X;
    VAR
        x : POINTER TO A;

Ok, skip the CARDINAL parameter, but I'd like to see the rest.

vixie@decwrl.dec.com (Paul Vixie) (08/16/88)

# > Pre and post increment/decrement operators (++, --);
# INC, DEC are a hack in M2 to satisfy people who think they can out-code
# a compiler. (With most M2 compilers, this is understandable...).

It's a question of appearance.  I can say

	while (*p++ = *q++)
		;

But then, does M2 have arithmetic for pointers?  Also, INC and DEC are not
functions which return the new value -- why not?

# > The ? : operator, eg, x = (y < 2 ? 10 : 20) + y;  is the same as
# >       if (y<2) x = 10 + y; else x = 20 + y;
# Pardon me, but did you ever program in APL?

Another question of appearance.  I like:

	printf("%d block%s\n", i, (i=1)?"":"s");

# > Large assortment of assignment operators (+=, -=, *=, /=, &=, |=, etc)
# >       eg, x *= 2; is equivalent to x = x * 2;
# M2 doesn't go into that sort of thing.  Seems like even the most
# rudimentary expression optimizer could take care of this problem
# lickety-split.

Yes, it's true, a good compiler will find the best way no matter how you
say it.  But again, appearance gets my vote:

	foo[i]->bar.size += newsize;
vs.
	foo[i]^.bar.count = foo[i]^.bar.count + newsize;
	
I get to say what I mean.  Yes, I know about INCR, but this is only one case.

# You can't really compare M2 and C.  They are two different beasts.

I agree.  M2 ends up being more elegant, or at least I end up being more
elegant when I use it.  :-).  C lets you do some things more clearly, but
the code ends up being a lot more dense per square inch of EMACS windows,
and C has things that I sometimes can't help taking advantage of, in spite
of the pain I experience later trying to understand what I did.

Both languages have their place.

# PS. Riddle of the day.  How do you do the following in C?
#     TYPE
#         RealPtr = POINTER TO REAL;
#         X = PROCEDURE (
#             CARDINAL
#             ) : RealPtr;
#         A = ARRAY [ 0 .. 5 ] OF X;
#     VAR
#         x : POINTER TO A;
# 
# Ok, skip the CARDINAL parameter, but I'd like to see the rest.

Sigh.  You're going to love this.  Let's skip the CARDINAL parameter, as you
suggest, since non-ANSI C doesn't let you specify parameters when you declare
a function.

typedef		real		*RealPtr;
typedef		RealPtr		(X)();
typedef		X		A[6];

/*var*/		A		*x;

M2 is _much_ clearer.  Anybody got an example of something like this that
C does more clearly?  Something useful would be nice...

Calling one of A's functions is fun:

	(*((*A)[i]))(param1, param2);

(I may have too many parens.  I always puzzle over this part of C.)
-- 
Paul Vixie
Digital Equipment Corporation	Work:  vixie@dec.com	Play:  paul@vixie.UUCP
Western Research Laboratory	 uunet!decwrl!vixie	   uunet!vixie!paul
Palo Alto, California, USA	  +1 415 853 6600	   +1 415 864 7013

kbad@atari.UUCP (Ken Badertscher) (08/17/88)

in article <49@volition.dec.com>, vixie@decwrl.dec.com (Paul Vixie) says:
> Yes, it's true, a good compiler will find the best way no matter how you
> say it.  But again, appearance gets my vote:
> 
> 	foo[i]->bar.size += newsize;
> vs.
> 	foo[i]^.bar.count = foo[i]^.bar.count + newsize;
> 	
> I get to say what I mean.  Yes, I know about INCR, but this is only one case.
 
  Don't forget WITH!
 
	WITH foo[i]^.bar DO
		count = count + newsize
	END;
 
  Or even, since you mentioned it,
 
	WITH foo[i]^.bar DO INC(count,newsize) END;
 
  And to jump into the middle of the discussion, all I really have to add
is that Modula-2 "feels" a lot nicer to me.  The verbosity doesn't bother
me, as someone said, I find myself being more eloquent with the more
eloquent language.  I do think it is valid to compare the languages,
but many of the discussions I've ever read end up haggling over natty
details like case sensitivity and amount of typing (hmm... unintended
double entendre there, I initially meant "number of keystrokes", but
"strict type checking" applies as well ;-).
  I spent my software engineering "apprenticeship" helping build a set of
libraries for a Modula-2 environment, and I now find myself doing most
of my programming in C (not by choice, I assure you).  I miss the comforts
of strong type checking and DEFINITION MODULEs, and the rest.  Some find
it oppressive, I find it helpful.  And the bigger the program, the more
helpful it is, in my experience.
 
-- 
 Ken Badertscher                 | Hey, umm, the stuff I said up there
 Atari R&D Software Test/Support | is, like, what _I_ think, okay?
 {portal,ames,imagen}!atari!kbad | So, y'know, don't bug Atari about it.