[net.lang.c] What Can't C Do?

tim@unc.UUCP (Tim Maroney) (03/12/84)

The greatest advantages of C are its brevity and its generality.  There is
very little that you can't do in C, unlike other "general-purpose"
programming languages such as Fortran and Pascal.  However, there are some
things that C can't do, at least not without postprocessing the assembly
language output.  That practice is A Very Bad Thing Indeed, since it tends
to be very nonportable (some C compilers don't even produce assembly
language! -- but that's obviously not the only reason for nonportability)
and difficult for anyone except the person who wrote the code to understand.
Furthermore, it makes assumptions about the format of the assembly code that
may be invalidated by an intelligent optimizer.  You can turn off the
optimization in most such cases, of course, but then you are sacrificing
performance.

Now that an ANSI standard for C is in the works, people are putting forth
their suggestions for "improving" C again.  Most of these involve making it
easier to do certain things that it is possible to do now (for instance,
dynamically typed data like Pascal's variant records).  I'm not interested
in these very much, but I am interested in widening C's generality and thus
ending once and for all this practice of assembly language postprocessing.

The most common use of ALPP (as I'll call it for short) seems to be changing
variable references into references to OS-specific objects such as device
registers.  In these cases, optimization is usually turned off as well, so
that each time the object is referenced in C code a real reference is
generated (instead of using modern register-optimization techniques).  There
was some discussion of this on this group a few months back, and the only
"solution" I can recall was to introduce a new storage class specifier (one
suggestion for its name was "volatile") for such variables.  This solves
only the problem of having to turn off optimization, though; you still have
to do ALPP to give the references the proper name.  A better solution would
allow the C programmer to declare a certain identifier as being equivalent
to an OS name, and the variable would implicitly be considerd volatile.
Logically, the declaration is three-operand (type, identifier, OS name)
rather than the normal C two-operand (type, identifier), so the syntax is a
little problematic.  One solution would be to disallow initialization of
such variables, and put in the initialization field a string with the OS
name; this would be consistent with the C practice of making code weird and
hard to understand. :->  I'd like to hear (in this group rather than in
mail) other suggestions for the syntax of this solution, or other solutions
to the same problem.

Another not-too-uncommon use for ALPP is global register declaration, that
is, changing all references to an external variable to register references.
This is useful in language interpreters (to use registers for function
return values), and possibly in other applications as well.  Syntactically,
this is easy to solve; just allow the "register" storage class specifier at
the external level.  However, it presents some problems for the compiler
when dealing with separately-compiled files, since the register used for
each identifier must agree in all the object files.  It would not be a good
idea to defer this to the linker, since linkers typically perform only the
function of filling in variable and function addresses; on some
architectures, filling in register references is a significantly different
task.  I'd like to hear suggested solutions for this problem as well, also
posted and not mailed.

That about wraps it up for now.  I'd like to hear other uses of ALPP and
suggested solutions.  I'd also like to know what "asm" is most commonly used
for, again preferably with ways to eliminate its necessity or at least to
clean it up.

I'll leave you with about the only change I'd like to see in C that doesn't
increase generality: string comparison operators.  Ideally, these would just
be "==", "<", ">", "<=", and ">=", but those already have meaning for
strings (i.e., char *), that of pointer comparison.  Either new operators or
a new built-in data type would be needed.
--
Tim Maroney, University of North Carolina at Chapel Hill
mcnc!unc!tim (USENET), tim.unc@csnet-relay (ARPA)

All opinions expressed herein are completely my own, so don't go assuming
that anyone else at UNC feels the same way.

ka@hou3c.UUCP (Kenneth Almquist) (03/14/84)

One way to reference device registers without using assembly language
is to use preprocessor defines like:

#define reg (*(int *)0177430)

Any C compiler that optimizes this sort of reference is likely to have
problems with other types of C code, such as signal handlers.
					Kenneth Almquist

rcd@opus.UUCP (03/14/84)

<>
The referenced article was mostly on the track of "there are some minor
problems, but let's leave well enough alone..."  But then...

 > I'll leave you with about the only change I'd like to see in C that doesn't
 > increase generality: string comparison operators.
I wish this idea would die.  It's often useful to look at the language
material written by the authors of the language - it provides useful
insights.  From "The C Programming Language" by Kernighan & Ritchie (the
blue and white book):
	Although the absence of some of these features may seem like a
	grave deficiency ("You mean I have to call a function to compare
	two character strings?"), keeping the language down to modest
	dimensions has brought real benefits.
It's useful to realize that the authors not only though about string
comparison operators; they decided at that time that they were not
appropriate to the level or size of the language.

Languages don't get "large" all at once.  It happens a feature at a time.
Sure, everybody likes the language, and it's really OK as is, but there's
just this ONE thing that really ought to be changed...only nobody's "just
one thing" is the same as anybody else's.

And when it comes to standardization, remember that it's a long process
even when everyone is in near-perfect agreement at the start.  If you open
up the just-one-thing bag, you'll still be waiting for a standard ten years
from now.

-- 
{hao,ucbvax,allegra}!nbires!rcd

stew@harvard.UUCP (Stew Rubenstein) (03/14/84)

While you're on the subject, what about == to compare two structures?
This is even more reasonable, in that structure assignment is supported
currently.

Actually, I'd like to be able to do struct = 0; or struct = (struct foo) 0;
to clear a structure but I realize that is a little more difficult.  Still,
if you special case 0 to represent an invalid pointer then special casing
it to be a blank structure should not be too unpalatable.

	stew rubenstein
	{decvax,linus}!genrad!wjh12!harvard!lhasa!stew

tim@unc.UUCP (03/15/84)

There are some tricky issues involved in structure comparison, and there is
no single best way to do it for all applications.  The difficulty comes in
when you have pointers as attributes (sorry, "members") of structures.  You
can do a standard quasi-numerical comparison on them, but that means that
two pointers to different but equivalent objects will be considered unequal,
which is not always what you want.  On the other hand, if you descend into
pointers, you will probably need to do it by user-invisible functions, which
any true C hacker would gag at, and you run the risk of hitting a cycle in
the structure and recursing until the stack overflows.

The first method seems to be the only one tolerable; my question is, how
usefiul would it be?  Obviously, it would be good for complex numbers and a
few other applications.  What does everyone else think?

Now about string comparison.  After I suggested this, someone accused me of
being insensitive to the perils of creeping featurism.  I assure you that I
am well aware of that problem; otherwise, I would have had a lot more
suggestions.  However, I don't think that extending comparison operators to
apply to an existing data type, for which there is already a common ordering
function known and often used, is really "adding" something -- it is just
making the comparison operators more orthogonal.  I would also support doing
this in a more general way by allowing array comparisons when the array is
of a comparable data type; the compiler can frequently generate more
efficient code for this than the user easily can anyway.  The big problem
with all this is that there is really no such thing as arrays in C.  There
are pointers, but comparison is already defined for them.  A smaller problem
is that there are two types of (non)arrays which we'd want to compare:
fixed-length and null-terminated.  Can anyone come up with a clean solution
for these problems?  I would rather have just the string comparison than no
extension of comparison at all, in any case.
--
Tim Maroney, The Censored Hacker
mcnc!unc!tim (USENET), tim.unc@csnet-relay (ARPA)

All opinions expressed herein are completely my own, so don't go assuming
that anyone else at UNC feels the same way.

rcd@opus.UUCP (03/16/84)

<>
 > While you're on the subject, what about == to compare two structures?
 > This is even more reasonable, in that structure assignment is supported...
Yet another bad idea.  This is much harder than it looks, for at least the
following reasons:

First, because of alignment constraints, structures may contain "holes" -
space allocated but not used.  Consider a 16-bit machine with a word
alignment constraint on ints and
	struct {int a; char b; int c;} . . .
In order to get both a and c aligned correctly, there's a one-byte hole
after b (assuming typical allocation of fields).  If the compiler is to
generate code to compare two instances of these structs, it has to skip
over the holes to avoid a spurious inequality result.  (Remember that even
though external variables can be initialized by the compiler - holes and
all - automatic variables may not be and usually aren't because of cost.)

A variant of the same problem occurs if the structure contains a union.
There is no way to know which part of a union is currently in effect, so
there's no way to know how much should be compared if the elements of the
union do not have the same length.
-- 
{hao,ucbvax,allegra}!nbires!rcd

ka@hou3c.UUCP (Kenneth Almquist) (03/18/84)

One thing that C lacks is a method of testing for arithmetic overflow.
This makes it difficult to write efficient interpreters for "normal"
languages that check for overflow.  I suspect that many C programs sim-
ply assume that overflow will not occur and produce incorrect results
when it does occur.

I don't have any good proposals for integrating such a facility into C.
				Kenneth Almquist

nather@utastro.UUCP (Ed Nather) (03/19/84)

<>
Discussions of string comparison usually start with two assumptions
that I believe are false:

	1. A language is deficient if it lacks string comparisons;
	2. They *could* be included, at modest cost in complexity.

In the various C programs I have written that involve string comparisons,
I find the ability to call a function to do exactly the right thing a
real convenience.  Sometimes I want to compare a substring to a string
both of which are null-terminated; next time the substring may not be.
Sometimes I want the pointer updated to point to the first character
that didn't compare, sometimes not.  I may want the *second* appearance
of a substring rather than the first or last.  

If every possible option were included as part of a language the cost in
complexity would not be modest -- and I'd never remember all the options.
Alternatively, if only the basic, vanilla comparisons are included, it
won't do what I want, I'll have to write a function call anyway, then
explain in a comment why I had to do it that way, fuming all the while.

After all this, an opinion:  Leave the string comparisons OUT.
-- 

                                       Ed Nather
                                       ihnp4!{ut-sally,kpno}!utastro!nather
                                       Astronomy Dept., U. of Texas, Austin

hamilton@uiucuxc.UUCP (03/19/84)

#R:unc:-692200:uiucuxc:21000009:000:419
uiucuxc!hamilton    Mar 18 23:04:00 1984

phil@unisoft.UUCP (Phil Ronzone) (03/20/84)

>> <>
>>  > While you're on the subject, what about == to compare two structures?
>>  > This is even more reasonable, in that structure assignment is supported...
>> Yet another bad idea.  This is much harder than it looks, for at least the
>> following reasons: ....

However -- comparing two structure of identical names is useful. Tells the
compiler to do byte-for-byte compare inline. Equality and inequality are
obvious, but I wouldn't want to count on  < or >.

Just to provoke net.lang.c.flame, how about my favorite extension to C?

                     break(expr);

rcd@opus.UUCP (03/20/84)

<>
Articles suggesting string comparison in C so far have addressed the issues
of "does it belong there?" and such.  A very different issue is that the
correct string-comparison algorithm is anything but obvious.  Using the
native collating sequence - even in the ASCII part of the world - is only a
primitive solution.  Text can seldom be compared "reasonably", in terms of
human expectations, with the ASCII ordering.  For one thing, "dictionary
order" is different from ASCII, since it regards case of letters as less
significant than differing letters.  Comparisons of names present another
problem (and a messy one) - you have to get Mc and Mac together, etc.  Then
there's the language problem - for example, in Spanish "ll" and "ch" are
treated as single letters.  Probably the situations in which the native
collating sequence is correct are limited to numeric comparisons (integers
only, of course) and general string comparisons where ANY order is OK as
long as it satisfies the rules of an ordering relation - as in searching,
building ordered trees, etc.
-- 
{hao,ucbvax,allegra}!nbires!rcd

aaw@pyuxss.UUCP (Aaron Werman) (03/20/84)

Here is a neologism that I had wanted to add to C back in the
seventies, when C wasn't considered the next COBOL:
	add a GENSYM to the preprocessor (you know, that macro in
	LISP/assemblers that creates a new, different identifier
	whenever invoked, allowing harrowing language additions)
I shudder to think of it now, when it it is considered a reasonable
applications development language.
			{harpo,houxm,ihnp4}!pyuxss!aaw
			Aaron Werman

guy@rlgvax.UUCP (Guy Harris) (03/20/84)

>> <>
>>  > While you're on the subject, what about == to compare two structures?
>>  > This is even more reasonable, in that structure assignment is supported...
>> Yet another bad idea.  This is much harder than it looks, for at least the
>> following reasons: ....

> However -- comparing two structure of identical names is useful. Tells the
> compiler to do byte-for-byte compare inline. Equality and inequality are
> obvious, but I wouldn't want to count on  < or >.

You missed his point; to correctly compare two structures a byte-for-byte
comparsion should *not* be done.  The bytes which are not part of structure
members, but which are just padding to put structure members on the right
boundary, *must* not be compared or two structures which "should" be equal
won't compare equal.

Yes, the comparison would be nice, but it's not trivial to implement and
won't compile into a simple comparison.  Also, < and > are flatly impossible;
what about

	struct complex {
		double	realpart;
		double	imagpart;
	};

Any result of < and > would be misleading as the complex numbers aren't an
ordered field.

	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy

eric@wucs.UUCP (Eric Kiebler) (03/22/84)

[And down in the lovely muck I've lain;  Happy -- 'til I woke again!]

For a good example of "lets give each function name an infix
operator", look at Icon.  That language is Martian.  Powerful,
but Martian nonetheless.  It is the kind of language you will like if
you like that kind of language.

We could always drag APL through the dirt, but it's supposed to look like that.

Has anyone out there developed any packages of macros or preprocessors
to add abstract data types to C?  Was it worthwhile if so?

Has anyone out there used PPI's objective-C?  How about class-c from
Always Talking and Talking?

eric
-- 
..!ihnp4!afinitc!wucs!eric

grunwald@uiuccsb.UUCP (03/27/84)

#R:unc:-690000:uiuccsb:9000017:000:626
uiuccsb!grunwald    Mar 26 09:13:00 1984

On the subject of language features:

Why not take a step into the seventies and introduce abstract data types to the
language? I understand that a version of Bell internal C does this already.

Then, as in CLU and Ada, your cluster/package specification allows you to
define equality, similarity, orderings, assignment etc. This eliminates the
need for the "string" type and string operations proposed, the structure
equality question would be simpler and, if you design it properly, you could
propably even implement structured assignment as suggested.

It seems to be the most general tool to solve a plethora of problems.