From: jlg@cochiti.lanl.gov (Jim Giles)
Subject: Re: Small Language Wanted
Organization: Los Alamos National Laboratory
Date: Tue, 25 Aug 1992 20:06:46 GMT

In article <1992Aug25.034553.2990@linus.mitre.org>, crawford@church.mitre.org (Randy Crawford) writes:
|> [...]
|> On a single statement basis, I'd agree: FORTRAN has it over C in expressing
|> numeric computations (you forgot to mention the problems C has in evaluating
|> expressions having mixed numeric types).  But if you've ever attempted to
|> modify or even read a large FORTRAN program, you've experienced what I have --
|> a rat's nest.  [...]

Actually, the "rat's nest" problem is about the same for both languages.
The basic problem is that most *programmers* write in an unstructured
way.  C programmers even call themselves (proudly no less!) "hackers".
To extemporize a program and then `hack' at it until it works is *NOT* 
a structured way to proceed (yes, that *is* the meaning of the term
"hacker").

|> [...]     I don't believe it's possible to write modular FORTRAN code:
|> at least, I've never seen it. [...]

I have.  That's all I write in any language. This is true of *any* language 
I use.  Modular coding is a language independent concept and can be done 
in assembler!  In fact, the basis of "structured programming" (the original
definition of the term - not its modern useless meaning) is to write the
algorithm abstractly and select the actual language you're going to use
*afterwords*.  Structured programming consists of iteratively refining
the algorithm to more and more specific forms - the *last* refinement is 
to finally express the sub-modules of the algorithm in the actual programming 
language(s).  In a well designed environment, there should be several
languages available and they should be inter-callable.

|> [...]                         And unless FORTRAN 90 eliminates constructs
|> like computed gotos, FORTRAN code will never become structured or modular.

Computed GOTOs are not relevant to the issue of modular code.  It is possible
to misuse setjump/longjump in C to a much *more* dangerous extent (the jumps
are not local), yet you don't claim that this makes modular code difficult
in C.  Even GOTOs themselves are less restricted in C than in Fortran (you
can jump *into* a nested structure from outside).

Computed GOTOs have nearly *exactly* the same semantics as C's switch
(including the fall-through unless the user explicitly breaks out).  True,
the computed GOTO is not required to properly nest, but C's ordinary GOTO
isn't either.

|> [...]
|> >  The only real thing that I miss in Fortran 77 is a pointer type.  There are
|> >many times when I wanted to pass pointers to functions through common blocks.
|> 
|> I'd say this statement is a perfect example of where the difficulty lies in 
|> FORTRAN: unstructured programming conventions and poor software engineering 
|> practices.  [...]

You mean like C's overuse of explicit pointers?  This is usually a *very*
poor software engineering practice.  It's worse than overusing GOTOs and
results in similar symptoms (spaghetti).  Things for which aliasing is not 
explicitly part of what you want to do should *never* be forced be implemented 
with explicit pointers.  This includes such things as dynamic memory, recursive
data structures, aggregate reshaping (that is, treating a 10x10 array as
a 100 long rank-one array for a while), etc..

|> [...]  The problem lies in FORTRAN's common blocks and the popular 
|> excessive use of global variables, [..]

Most C programs (that I've seen) excessively use globals too.  
True, C has a poor MODULE-like functionality in the form of file-scoping 
rules.  Most Fortrans already have modules or soon will.  Even so, *real* 
modules have more similarity to COMMONs than to file-scoping: being named 
aggregates.  MODULEs can hold procedures as well as data (which makes
MODULE-private objects useful) and MODULEs are name associated instead
of storage associated, but those are the only differences from COMMON
(important though they are!).  C files are not *named* aggregates though.
All objects exported from them are *individually* global.  This is a much
more serious deficiency.

|> [...]                                    poor control over subroutine argument 
|> passing-by-value/passing-by-reference, [...]

C *requires* explicit user selection of these.  I've never found this
level of "control" particularly useful.  Especially since it is sometimes
desirable to alter a procedure which does one so that is does the other:
in C this requires altering all the *calls* to the procedure.

|> [...]                           NO user-defined data types, no recursion, [...]

Well, yes and no.  Not having these things is better than having them in
a poorly implemented form (as C's user defined types are).  Yes, recursion
is sometimes useful (though always less efficient - or, at best, equal *if*
your optimizer is up to snuff).  Missing featurers can always be added by 
future standards, poorly designed ones are very difficult to remove.  Both 
of these are in Fortran 90.

|> [...]
|> poor-to-nonexistant looping constructs, [...]

Huh?  Minor syntactic sugar is missing.  This makes *some* loops harder
to *read*.  C also has illegible looping constructs - especially the 
ubiquitous for() loop (which some style guides recommend for *all* 
C loops).  True, I'd like different syntax for WHILE and UNTIL loops,
different syntax for N TIMES loops, loops with iteration variables
defined (both covarying, and independently varying), etc. (in fact, 
I think this is a very improtant issue since I think syntax is the
most important aspect of a language's legibility).  Neither language 
has a full set and those that C has are equipped with built-in 
legibility problems.  Fortran 90 is closer than either to a well
designed set of control flow constructs in general - loops being
a particular case.

|> [...]                                a dependency on gotos (and the very 
|> existence of computed gotos)  to a lack of [...] switch/case constructs, 
|> etc, etc.

This is being inconsistent.  Computed GOTO and C's switch have nearly
identical semantics.  Just because C doesn't use the four characters
`g', `o', `t', and `o' doesn't alter this.  If your complaint is that
*neither* language has a really *good* select/case feature, then I would
agree.  Fortran 90 does is an improvement in this respect over both.

|> [... reordered ...] and archaic conditionals from .NE.

OK.  On the other hand, a preprocessor which converts <, <=, ==, /= (I would
prefer ~= here), >=, and > to their corresponding Fortran is trivial to write.  
I agree, these should be in the standard - they *are* in Fortran 90.  Also, 
.AND. should be written as /\, .OR. should be written as \/, .NOT. should be 
written as ~, and .XOR. *could* be >< (though ASCII is inadequate to present 
a really good xor operator), etc. - the committee was timid in its additions.

If you want to complain about bad operators though, C is the language with 
the worst.  Over 40 operators and 15 precedence levels (more than any other
language I've ever seen).  Many of the operators are poorly chosen from the
available character set and are, as a result, difficult to read as well as
difficult to learn.  The operators are at odds with the use of the same
characters in other conventional notations.  For example `||' in mathematics
means "is parallel to"; `|' in most gramatical notations is "exclusive or"
(and elsewhere in UNIX is "pipe"); `!' of course is an exclamation (or a
factorial); K&R C doesn't allow unary plus (why?); unary minus has a different
precendence than infix minus; there are, unnecessarily, *two* selector operators
of `struct' variables (depending on whether they are pointed at or not); etc..
Add to that: contrary to human-factors studies on productivity and syntax,
C has expression level operators which cause side-effects.

|> [...]
|> While none of these affect the ability of the language to express numeric
|> computation on a single statement basis, any program of more than about 200
|> lines begins to get unwieldy and critical mass occurs at about 1000 lines.
|> This is unacceptable in modern programming languages, and _I_ think it
|> relegates FORTRAN and her afficionados to the dark ages of software engineering.

I also would put the trade-off between C and Fortran at about 200 to 1000
lines of code.  Fortran is much better for the larger codes.  C is like 
Basic in that it's mainly good for trying out simple algorithms in the small
and not for large projects at all.  *If* your algorithm can be efficiently
decomposed into lots of small independent procedures that don't need to
process arrays as first-class objects, C *can* still be used effectively.

|> [...]
|> I think the real advantage that C has over FORTRAN (and Pascal has over C) is
|> especially among undisciplined numerical programmers, where the "better" 
|> language allows sufficient expressiveness to solve the problem, yet less 
|> opportunity to write bad code.  And it's easier for "part-time" programmers to 
|> write bad code in FORTRAN than in C.

Well, it's harder for part-time programmers to learn enough C to write
good code with it.  The typical learning curve for C is longer than for any
other language I'm familiar with.  Parttime programmers are, by definition, 
not people with the time to spend on this kind of learning - even if C 
coding really did result in better coding practices (which I've not noticed 
to be true).  With respect to learning, Pascal and C are on the opposite
ends of the spectrum, with Fortran between them.  For ad-hoc learning - 
typified by the usual C approach - Fortran is the easiest to learn of all: 
Pascal was designed to be a teaching tool, but only in a well-ordered 
learning environment.

For a C-level language which is much better designed and *vastly* easier to 
learn and to use, try Turing (invented at the University of Toronto).  It's 
slowly becoming more widely available.  There are probably numerous others
I'm not aware of.

|> As I see it, a programming language has to be judged in the real world not by 
|> what programmers can do _with_ it, but by what they can do _to_ it.

Oh, well if you want *extensible* languages, the functional languages (Scheme,
ML, Haskell, etc.) are the best.  Object oriented languages come in a distant
second best (with C++ trailing that pack in terms of design quality).  A close
third comes in the form of languages with generic procedure interfaces (a`la
Ada, though Ada has other problems - though it's still better than C overall).
It's not clear but that generic procedures might not be better than the object
oriented approach, but with Ada the only widespread example of the former, it's
hard to tell.

-- 
J. Giles
Newsgroups: comp.edu,comp.lang.fortran,comp.lang.misc,comp.arch,sci.math