I like it. Nice and general, fills a gap missing in C. It's not C,
but it could be D (it *should* be D, not P (pee?)).
Maybe we should start a new newsgroup/mailing-list for the discussion
of such things. It seems like a lot of the current discussion here is
about things that will never make it into ANSI C such as a power
operator, `noalias' :-) et cetera. Sure would improve the S/N ratio
for those interested only in C.
=========
The opinions expressed above are mine.
"The limits of my language mean the limits of my world."
-- Ludwig Wittgenstein
But wait, we can do better. Why limit yourself to two operands? Let's
look at some other programming language (like Icon) and get the
correct operator.
The magic operator is
i(x1, x2, x3, ..., xn)
Looks like a function call eh? It's not. i is an integer in the
range from 1 to n and the operator produces the outcome of xi.
So a simple swap is
a = 1(b, b=a); /* much cleaner than ,, */
The the wonderful thing is it wont break any code. So everyone
write your ANSI rep now!!!! 8^)
BTW my vote for min and max is ?< and ?>. Also why not ?: that
produces it first operand if it is not zero else it produces it second
that why the getc macro becomes
#define getc(file) (*(file)++->char ?: _fillbuf(file))
/* note _fillbuf is smart enough to figure out if there was
a '\0' in the input stream or if it was actually at the
end of a buffer and of course the buffer size is BUFFSIZE + 1 */
just thinking aload
-bob
--
Robert R. Rose
Northern Arizona University, Box 20023
Flagstaff, AZ 86011
.....!ihnp4!arizona!naucse!rrr
Sounds good to me.
I've been collecting interesting ideas about ``D'' off the net for a while.
If y'all would like to send me your 1 or two favorite "improvements" to
C to be incorporated in "D", I'll send you a summary in response.
Not that I intend to write D or P or whatever, but if somebody wants my
ideas (take my ideas, please!)
;-D on (Creativity is ... hard to define) Pardo
pa...@cs.washington.edu ..!ucbvax!uw-beaver!uw-june!pardo
In article <11...@brl-adm.ARPA> ds...@NSWC-OAS.arpa (Dave Sill) writes:
>>Some years ago I invented the hypothetical notation "e1 ,, e2", which would be
>>like the comma operator in that it evaluates its left operand before its
>>right operand, but (unlike comma) the result would be the value of the left
>>operand. Look what this buys us:
>> a,, a=b /* displacement operator, like a :=:= b */
>> a=(b,, b=a) /* a simple swap */
>> x,, ++x /* same as x++; but generalizable */
>> free(stack,, stack=stack->next) /* pop stack */
>> stack->value,, pop(stack) /* pop and return stacked value */
>
>I like it. Nice and general, fills a gap missing in C. It's not C,
>but it could be D (it *should* be D, not P (pee?)).
Actually, the last project course at the late Wang Institute developed
a compiler and editor for the D language called Turbo-D. The D language
we used was taken from Dijkstra's guarded command language in his book
"A Discipline of Programming." For the simple swap you have shown, the
D syntax seemed to be much cleaner:
a,b := b,a
The language had some other features, including non-determinate selection
of guards for loops and conditional statements. The project was fun, the
language was useful, and the compiler was fast.
--
Gary F. Pollice | Remember the Wang Institute!!
Sun Microsystems | ARPAnet: gpol...@sun.com
Two Federal Street | UUCP: {decwrl,ihnp4,hplabs,ucbvax}!sun!gpollice
Billerica, MA 01821 | (617)671-0374
If `i' is constant, this is no more powerful than `(x1, ..., xi,, ...,, xn)'
which produces the same result. If `i' is allowed to be an arbitrary integral
expression (which I presume is the case in interpretive Icon), then it is
indeed more powerful but also more expensive to compute. Part of the beauty
of `,,' is that it has a cost comparable to `,'.
>[How about an operator] that produces it first operand if it is not zero else
>it produces it second
I considered proposing that the `||' operator be so extended (yes, this could
break existing code, but only if the operands are nonboolean AND the result is
being used in a nonboolean context). After thinking about it, though, I
decided that this is a step backwards. In programs that properly distinguish
between booleans and integers, there's nothing particularly magic about
`compare against zero'. Why should there be a special-purpose notation for
`e1 != 0 ? e1 : e2' but not for `e1 != -1 ? e1 : e2', say?
What you really want is the `it' pronoun, often used in PDL.
IF long-hairy-expression != 0
RETURN it
ELSE
RETURN other-expression
ENDIF
Karl W. Z. Heuer (ima!haddock!karl or ka...@haddock.isc.com), The Walking Lint
KWZH: We need a construct like `e1 UNLESS IT==0 INWHICHCASE e2'.
GCJ: Yes, and also `IFONTHEOTHERHAND ... WEMAYSAFELYASSUME'.
Actually, if 'i' is an arbitrary integral expression, it isn't that much more
expensive to implement than if it's a constant - most of the evaluation
mechanism is already in place in C (excuse me, 'D'). The only extra expense
over computing the value if 'i' is a constant is the cost of evaluating the
expression for 'i' and a simple transfer.
Sigh, let's just keep postnews happy here...
--
Steve Wampler
{....!arizona!naucse!sbw}
Can you find out if it can be posted? I'd like a (V)HLL like the
Dijkstra language to write hard, complex but non-machine-related
things in. A (M)HLL like P would be nice too (:-)).
--dave
--
David Collier-Brown. {mnetor yunexus utgpu}!geac!daveb
Geac Computers International Inc., | Computer Science loses its
350 Steelcase Road,Markham, Ontario, | memory (if not its mind)
CANADA, L3R 1B3 (416) 475-0525 x3279 | every 6 months.
Sorry, I stand by my statement. If this `pick' operator is supposed to be a
generalization of my proposed `,,' operator, it must preserve the guarantee of
evaluating all of the `x?' operands, in left-to-right order. It sounds like
you're thinking of the expression equivalent of `switch', which would evaluate
exactly one of them. (Which may also be useful, but that's a separate topic.)
Actually, no. However, I wasn't thinking of this as an exact replacement
for the ',,' operator, just as something that does equivalent work. You
can evaluate all the operands and then fairly easily make an arbitrary one
of them available. Think of 'i(x1, x2, x3,..., xn)' as being analogous to
calling a function 'i' that returns its ith argument. Then think of ways
to avoid implementing 'i' as a function. I suppose that compared to the ',,'
operator, there is the overhead of verifying that 'i' evaluated to the
proper range, but that is really a cost of the extra generality, and can
be eliminated if 'i' is a constant.
Of course, the evaluation order for ',,' is well defined, while the
evaluation order (in 'C' at least) for 'i(...)' would match the evaluation
order for function calls, which is much messier. (In 'D', however....).
I think ',,' is an interesting operator, but I personnally prefer 'i(...)',
having used it extensively in Icon - it seems 'more natural' to me. To each
his own.
--
Steve Wampler
{....!arizona!naucse!sbw}
The first thing I would remove is the automatic conversion of arrays to
pointers. This was an understandable mistake, but a mistake nevertheless.
Removing it clears the way for treating arrays as first class objects. (A
consequence of this change is that "a[b]" is no longer definable as
"*(a + b)". We still have that it is equivalent to "*(&a[0] + b)", but this
cannot, of course, be used as a definition.)
Second on the list is defaulting of variables. An undeclared variable
should be an error, not an int. Likewise for functions. I would favor
mandating ANSI-style function prototypes. (Except that the "f(void)"
construct would not be needed -- "f()" means a function with no arguments.)
Another thing that should go is the assumption that the unit of storage is
the byte. The base unit of storage is the bit, and sizeof should return the
number of bits in the object. This enables to treat objects smaller than a
byte as first class objects.
I would also like to do away with having control statements control single
statements. For example, instead of writing "if (foo) {stmt1; stmt2;}" I
would write "if (foo) stmt1; stmt2; end;". Likewise, I would rewrite the
"for" statement as "for <stmts> while (<exp>) next <stmts> do <stmts> end;".
The "while" and "do ... while" I would generalize to "loop <stmts> while
(<exp>) <stmts> end;". In keeping with the spirit of C, we avoid
superfluous words, and keep the ones we do use short.
With these changes, the {} statement delimiters become much less useful. I
would probably drop them, and add a "begin ... end;" construct for those
cases where a local declaration is desired.
Another shortcoming to be fixed is the automatic fallthrough for select
statements. The default should be exit the statement when a new case is
encountered, with an option to fall through. I don't much like the current
syntax, either. In any event, the syntax should include specifying multiple
values for a case (what is now accomplished by "case a: case b:").
To get even more radical -- with typedefs, enums, const declarations, and
(if we add them) inline functions, do we really need the pre-processor any
more? Some kind of include statement should be provided, of course. Any
decent compiler will optimize "const int foo = 1; if (foo) ... else ...
end;", so preprocessor conditional compilation is hardly necessary.
I would omit the automatic insertion of a null byte at the end of character
constants. If you want nul terminated strings, write the nul. If you want
strings with counts, the language should not get in your way.
I think I would also drop the convention that 0 is a null pointer. Make
"null" a keyword, representing a null pointer of any type.
--
Frank Adams ihnp4!philabs!pwa-b!mmintl!franka
Ashton-Tate 52 Oakland Ave North E. Hartford, CT 06108
Yes, you can implement it as
(temp[1]=x1, temp[2]=x2, ..., temp[n]=xn, temp[i])
if you're willing to live with the space requirement. (This was noted in the
first draft of my earlier article, but I cut it before posting.)
>I suppose that ... there is the overhead of verifying that 'i' evaluated to
>the proper range ...
Actually, it would be well within "the spirit of C" to let an out-of-range
selector be an undefined condition. Then the verification can be omitted.
>Of course, the evaluation order for ',,' is well defined, while the
>evaluation order (in 'C' at least) for 'i(...)' would match the evaluation
>order for function calls, which is much messier.
And in private correspondence:
>Also, note that, in 'C' at least, the types of e1,...,en
>must match (this isn't true in Icon).
This is important. If we add this `pick' operator but not `,,' on the grounds
that the former can simulate the latter, we would have to assert that
(a) `pick' guarantees to evaluate its right operands left-to-right, and
(b) the right operands must all have the same type if the left operand is
nonconstant, but may be of varying types if the left operand is constant.
(a) is an arbitrary restriction that shouldn't apply to `pick' for the same
reason that it shouldn't apply to function calls (we should let the compiler
do whatever is the most efficient thing), and (b) is a kludge of the same
magnitude as the recently-proposed enhancement to "++" for non-lvalues.
It looks like the best solution is to add both operators! (After all, we're
talking about a hypothetical `D' language here.)
In article <25...@haddock.ISC.COM> ka...@haddock.ima.isc.com (Karl Heuer) writes:
>I considered proposing that the `||' operator be so extended ...
>After thinking about it, though, I decided that this is a step backwards...
>Why should there be a special-purpose notation for `e1 != 0 ? e1 : e2' but
>not for `e1 != -1 ? e1 : e2', say?
>
>What you really want is the `it' pronoun, often used in PDL.
> IF long-hairy-expression != 0
> RETURN it
> ELSE
> RETURN other-expression
> ENDIF
An obvious (at least to me) way to extend C to provide this is using the
?: operator. e1 ? e2 : e3 compiles to something vaguely like:
calculate e1
jump-if-zero L1
calculate e2
jump-always L2
L1: calculate e3
L2: ...
so, something like "e1 ? : e3" could consistently compile to something like:
calculate e1
jump-if-zero L1
jump-always L2
L1: calculate e3
L2: ...
i.e. just missing the "calculate e2" line, corresponding to the absence
of code in this part of the expression. (yes yes, the two adjacent
jumps can be reduced to one jump.)
Obviously, this would not break any existing code as "e1 ? : e2" is
currently a syntax error. And I think this answers Karl Heuer's
question quoted above.
ajr
--
"noalias considered sailaon"
Actually, there is a much more natural and powerful way to handle this in D:
one of the nicer things about C is the way you can get letters out of strings
by doing things like:
"abcdefghijklmnopqrstuvwxyz"[letter]
Why not extend this and allow in-line arrays? This would allow the "choose"
operator to work as, for example:
array int {x1, x2, x3, ...}[i]
This of course means that "abc" is exactly the same as
array char {'a', 'b', 'c', '\0'}
. . . just another silly idea.
--
--Brian.
(Brian T. Schellenberger) ...!mcnc!rti!sas!bts
DISCLAIMER: Whereas Brian Schellenberger (hereinafter "the party of the first
--
Gary Sarff {uunet|ihnp4|philabs}!spies!argus!gsarff
To program is human, to debug is something best left to the gods.
"Spitbol?? You program in a language called Spitbol?"
The reason computer chips are so small is that computers don't eat much.
Uh oh. A ray of sensibility on the net! :-)
Oddly enough (or perhaps given the impending Standard, it is not
so odd), I have been considering the same sort of thing myself.
For those who want to wade through details (such as they are), they
appear below.
One of the nicest things about the C language is what it does NOT
do. The language is small enough to learn and comprehend entirely
in a short time; the list of language oddities is not empty, but
is small (most of them appear below).
>The first thing I would remove is the automatic conversion of arrays to
>pointers.
I am not sure I would make this `first', but I agree. In fact, this
is a side effect of what I would do with aggregate types.
>Second on the list is defaulting of variables. An undeclared variable
>should be an error, not an int.
(An undeclared variable *is* an error, unless you claim `register i'
leaves `i' undeclared.)
>Likewise for functions.
agree; unsure about C++/ANSI syntax
>Another thing that should go is the assumption that the unit of storage is
>the byte.
I thought about this; it gets sticky, and I am still unsure. C's
structure bitfields are the wrong way to get at bits; in particular,
it would be nice to have arrays of bits. But the basic unit of
storage has a way of creeping into the rest of the language, no
matter how hard one attempts to keep them apart.
>I would also like to do away with having control statements control single
>statements. For example, instead of writing "if (foo) {stmt1; stmt2;}" I
>would write "if (foo) stmt1; stmt2; end;". Likewise, I would rewrite the
>"for" statement as "for <stmts> while (<exp>) next <stmts> do <stmts> end;".
>The "while" and "do ... while" I would generalize to "loop <stmts> while
>(<exp>) <stmts> end;".
I disagree with the details, but will note that some human factors
studies have shown (and I agree) that a paired `end' is better than
a single `end', e.g., `if e stmts endif', `while e stmts endwhile'.
On the other hand, other studies have shown that `noise words' inhibit
understanding. I am undecided about this.
>Another shortcoming to be fixed is the automatic fallthrough for select
>statements.
agree
>To get even more radical -- with typedefs, enums, const declarations, and
>(if we add them) inline functions, do we really need the pre-processor any
>more?
Probably. Inline functions should most certainly be added; they
nearly obviate the need for macros.
>I would omit the automatic insertion of a null byte at the end of character
>constants. If you want nul terminated strings, write the nul. If you want
>strings with counts, the language should not get in your way.
A general aggregate constructor is necessary. A specific version of
one that constructs null-terminated strings might be declared in
<strings.h> (or its equivalent). I would like to be able to create
C-style arrays (blocks of memory) as easily as `real arrays' (with
dope vectors). If I could come up with some way of merging arrays
and structures/unions into a single `aggregate' type....
>I think I would also drop the convention that 0 is a null pointer. Make
>"null" a keyword, representing a null pointer of any type.
This would, at one stroke, eliminate half the confusion that plagues
comp.lang.c .... (about 1/3 :-) )
I think the following are important considerations:
- the language should be made as small as possible, but no smaller.
- we should assume that compilers for this language are going to
do a great deal of optimisation; in particular, they will optimise
across entire compilations, not just single files.
- it should be relatively easy to translate `old C' to the new
language.
- it might also be a good idea to steal liberally from C++ (which
of course steals liberally from SIMULA and others).
Very few of my ideas along this line are firm. My biggest worry
is that if the language is too small and malleable, it will suffer
from the same problems as some of the old dynamically-extensible
languages. One solution is to make the language small but the
support `library' (including headers that define standard aggregates
like C-style arrays and strings) a `part' of the language.
--
In-Real-Life: Chris Torek, Univ of MD Computer Science, +1 301 454 7163
(hiding out on trantor.umd.edu until mimsy is reassembled in its new home)
Domain: ch...@mimsy.umd.edu Path: not easily reachable
It isn't that bad, really -- I once went through an earlier C dpANS
and identified all the changes necessary to support a distinction
between "byte" (smallest accessible storage unit, which could be a
bit if you wanted to make it so) and "character" (smallest unit of
text). The particular type names I used were "short char" and "char",
respectively. It turned out that it wasn't too difficult to make
the distinction. The idea lost out to the "multi-byte character"
approach embodied in the current draft, which is a pity since that
doesn't support bit addressability and it requires specific calls
to convert MBC sequences to and from textual units (wchar_t). If
you guys really are planning on developing the language D, I hope
you'll consider something along these lines. By the way, if that
becomes a real project, it should get its own mailing list; there's
too many suggestions for changes to C in this newsgroup already..
However, some means of fall through should be provided, BUT it should be
explicitly expressed.
>
> >To get even more radical -- with typedefs, enums, const declarations, and
> >(if we add them) inline functions, do we really need the pre-processor any
> >more?
>
> Probably. Inline functions should most certainly be added; they
> nearly obviate the need for macros.
Not probably, definately we still need the pre-processor. The
pre-processor supports a limited form of types as parameters.
Example:
#define alloc(type) ((type *) malloc(sizeof(type)))
Unless you are going to support some other form of polymorphism that
will allow the above to be expressed, leave in the pre-processor.
> >I think I would also drop the convention that 0 is a null pointer. Make
> >"null" a keyword, representing a null pointer of any type.
>
> This would, at one stroke, eliminate half the confusion that plagues
> comp.lang.c .... (about 1/3 :-) )
Unless you require function prototypes to be within scope, null
will not do you much good.
>
> I think the following are important considerations:
>
> - the language should be made as small as possible, but no smaller.
I agree, a very very very important point.
>
> - we should assume that compilers for this language are going to
> do a great deal of optimisation; in particular, they will optimise
> across entire compilations, not just single files.
Which brings up a question, what happens to the asm statement then.
If you have the write you code such that you have no idea
where variables are stored, how can you reliable use assemble statement
that play with storage. I think the conclusion will be trash asm.
--
Eddie Wyatt e-mail: e...@ius1.cs.cmu.edu
1) It need not be upward compatible with C, but automatic upward
translation should be possible. At the very least, automatic
translation with reliable automatic flagging of nonportable
constructs should be possible.
2) Syntactic changes should be avoided unless a definite gain can
be shown. "I like it better another way" is not sufficient.
Changes to syntax tend to arouse opposition all out of proportion
to their importance. The major problems in language design are
not syntatic.
3) C started life as a weakly typed language, and has been modified
slowly into a strongly typed one. This has resulted in some
strange semantics. This needs to be dealt with.
4) The basic model of a static language close to the machine should
be retained. Attempts to bolt on a very dynamic environment
with heavy underlying machinery, along the lines of LISP or
Smalltalk, should be resisted.
5) The semantics of types is probably the most important issue
to be addressed.
6) The semantics of finite-precision integer arithmetic need to
very well thought out. The semantics of arithmetic should
be independent of the underlying hardware, so that the same
answer is obtained on all machines for all valid operations.
(This is possible, and can be done efficiently, but the
solutions are not well known.)
John Nagle
I think the language you want was already designed by Nicolas Wirth: Pascal.
-charles
--
Charles Daffinger \ Take me to the river / (812) 339-7354
Box 1662 \ drop me in the water / cd...@iuvax.cs.indiana.edu
Bloomington, IN 47402-1662 {pur-ee,rutgers,pyramid,ihnp4}!iuvax!cdaf
Home of the Whitewater mailing list: whitewate...@iuvax.cs.indiana.edu
I think not. I think it will be to change the semantics of asm into a
varargs function (which may even have the register allocator at its
disposal?):
void
dumb_function( doit_to )
int *splat;
{
enum Labels { START = 1, LOOP, DONE };
extern int splodge;
int r1, r2;
_reg_alloc(2);
asm( START, "movl", ADDR, &splodge, REG, r1 = _register() );
asm( 0, "clrl", REG, r2 = _register() );
asm( LOOP, "tstl", REG, r2 );
asm( 0, "bgeq" LAB, DONE );
asm( 0, "addl", ADDR, sizeof( some_type ), REG, r1 );
asm( 0, "subl", ADDR, sizeof( some_type ), ADDR, splat );
asm( 0, "brb", LOOP );
asm( DONE, NULL );
_reg_unalloc();
/* r1 is just thrown away ... */
}
Alternatively, the opcode could specify the format of the arguments that
it takes (much as printf works), but I think this is unnatural, since if
you had a bunch of typedefs, you couldn't just do:
#ifdef VAX
#define ADD "addl"
#else
#define ADD "add"
#endif
(or something slightly less sick, but I hope this puts the idea across).
No, I haven't thought to closely about this, there may be some fatal flaw.
The worst thing is that this is almost portable ;->
;-D on (Well, C is just portable SNOBOL ;-) Pardo
Yeah, I think so. There are even those who want to change
= to :=. Computer users (I stress users -- see below) seem to be the
biggest complainers of all "scientists". Algol and PL/1 were designed
a long time ago, everyone thought that they would be THE programming
languages for all humanity/applications. Now people think that ADA
and Modula 2 are THE programming languages. Not many people stop to
look at history. C was just something Ritchie came up with -- it
wasn't a _software_engineering_environment_, just a simple, portable,
utility. It has probably become (along with UN*X) the second greatest
computer science accomplishment ever. It was not due to some great
"design by commitee", just necessity.
A guy I work with sometimes asks the question: "now that we
have all these great modular languages like ADA and Modula 2, I would
think there would be more software using them". This has to do with
Mac stuff which is mostly written in C. The answer is simple: computer
systems people (I stress systems people -- see below) are more interested
in getting the job done. Let's face it, a compiler is just a tool.
It does not write code for you, it does not find algorithmic errors
for you, it is just a way to avoid assembly (this is the reason FORTRAN
is the first greatest computer science accomplishment).
If you don't like C, don't use it. There must be at least 100
different programming languages, none of which are radically different
from Algol, FORTRAN, or LISP. All three of these were invented in the
late 50's-early 60's, so I think you can find what you are looking for
in some variant.
C was designed as a systems implementation language, not THE
language for all humanity/applications. I think it does a very, very
good job. What most people are suggesting (with respect to D) is
another Algol, PL/1, ADA, Modula 2 and whatever else comes up in the
next five years. It will suffer the same fate: crash and burn.
#define systems_person one who gets the job done
#ifdef systems_person
#define user !systems_person
#else
#define user one who waits for someone|something to do the job for him
#endif
I think Henry Spencer's quote says it all: "those who do not understand
UNIX are condemned to reinvent it, poorly".
This is not meant as a flame, just my personal observations.
If we have the compiler replace names by locations (register and/or memory)
of the variables used, there is no more problem with global optimization
than before. In fact, we should do this in C; it is not prohibited by the
language standards, and it certainly makes more sense to be able to write
assembler statements in which the location of the variable is inserted by
the compiler.
Most of the C compilers I know do not do this; it is at the least annoying
not to be able to write such things as
asm(" addl x,y,z");
asm(" addwc u,v,w");
and have the compiler include those location for the variables. (What I do
is to first compile as above and then edit, but it does not always work.)
We also should get rid of those quotes in the process; since asm is a reserved
operator, and its structure requires that what follows starts with ("
and ends with "), while the parentheses may be useful as separators, the
quotes are totally unnecessary (and have been known to cause errors).
--
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907
Phone: (317)494-6054
hru...@l.cc.purdue.edu (ARPA or UUCP) or hru...@purccvm.bitnet
Indeed they are not. Can you post a pointer to these solutions?
--
Gideon Yuval, +972-52-522255 (work), -2-690992 (home), yu...@taux02.nsc.com
Agreed.
|>I would also like to do away with having control statements control single
|>statements. ... "if (foo) stmt1; stmt2; end;" ...
|>"for <stmts| while (<exp|) next <stmts| do <stmts| end;" ...
|>"loop <stmts| while (<exp|) <stmts| end;".
|
|I disagree with the details,
I would like to see other proposals.
|[may prefer 'endif' to 'end', but has doubts]
I debated whether to put in 'endif', etc., or 'end' in the above, and
finally opted for the shorter form. Ask me on another day and you might get
a different answer.
|A general aggregate constructor is necessary.
Any suggestions on how to do this?
|I think the following are important considerations:
|
| - the language should be made as small as possible, but no smaller.
|
| - we should assume that compilers for this language are going to
| do a great deal of optimisation; in particular, they will optimise
| across entire compilations, not just single files.
I don't think we should *require* this. The language should still have a
place for the fast and cheap compiler, which still produces reasonably good
code.
| - it should be relatively easy to translate `old C' to the new
| language.
|
| - it might also be a good idea to steal liberally from C++ (which
| of course steals liberally from SIMULA and others).
Yes, but I would not put the object oriented stuff into D. For that, you
get D++.
Overloaded functions are fine, though.
|My biggest worry is that if the language is too small and malleable, it
|will suffer from the same problems as some of the old dynamically-extensible
|languages. One solution is to make the language small but the support
|`library' (including headers that define standard aggregates like C-style
|arrays and strings) a `part' of the language.
Definitely. Library development should go on in parallel to the language
development, and whatever flexibility the language provides should be
reflected in the library.
Here is an alternative to endif et al. Use labels to start blocks and
'end labels' to end them. For example,
if (boolean expression)
foo: ....
end foo
else
bar: ....
end bar
This may look odd, but it does have the advantage that it makes the block
delimiting explicit. One would also need to be able to use unlabelled blocks
(in macros, for example), so
if (boolean expression)
....
end
else
....
end
would also fly. A disadvantage (from some viewpoints) is that, since labels
now delimit control blocks, they can't be used for goto's.
Sometimes, I think this might be a good idea.
--
In the fields of Hell where the grass grows high
Are the graves of dreams allowed to die.
Richard Harter, SMDS Inc.
Ah, but if you you don't make the representation of the null pointer
be the same as that of an integer (or anything else) then you can make
it illegal to pass it (uncast) to a function for which there is no
prototype. You can't do that with zero, unless you want to have to say
(int)0 to pass an integer zero.
Of course, when designing a new language you certainly could require
that functions never be used unless there is a prototype (or
"declaration" as one might call it) in scope.
-- Richard
--
Richard Tobin, JANET: R.T...@uk.ac.ed
AI Applications Institute, ARPA: R.Tobin%uk.a...@nss.cs.ucl.ac.uk
Edinburgh University. UUCP: ...!ukc!ed.ac.uk!R.Tobin
Um, perhaps you should learn C before you start designing D...? An
undeclared variable *is* an error.
> Another thing that should go is the assumption that the unit of storage is
> the byte. The base unit of storage is the bit, and sizeof should return the
> number of bits in the object. This enables to treat objects smaller than a
> byte as first class objects.
Here we have a key decision: is D to share C's emphasis on generation
of efficient code? (Bearing in mind that this had a lot to do with C's
success.) If so, then trying to forget that bytes exist is a serious
mistake. Most machines cannot handle bits with anywhere near the efficiency
with which they handle bytes; the appropriate base unit for efficient code
*is* the byte.
> ... In keeping with the spirit of C, we avoid
> superfluous words, and keep the ones we do use short.
>
> With these changes, the {} statement delimiters become much less useful. I
> would probably drop them, and add a "begin ... end;" construct...
Please explain how avoiding superfluous words and keeping necessary ones
short is consistent with changing {/} to begin/end for no particular reason.
> To get even more radical -- with typedefs, enums, const declarations, and
> (if we add them) inline functions, do we really need the pre-processor any
> more? ...
The C++ people claim that the answer is "not much", given inline functions
in particular. They do still use it for some specialized problems, though.
> I would omit the automatic insertion of a null byte at the end of character
> constants. If you want nul terminated strings, write the nul. If you want
> strings with counts, the language should not get in your way.
Pray tell, how do you write a counted-string constant? I would suggest
that "abc" should mean a length-3 string with any necessary terminator,
regardless of what flavor of string is in use. That way you get a choice,
without recoding all your string constants.
--
Those who do not understand Unix are | Henry Spencer @ U of Toronto Zoology
condemned to reinvent it, poorly. | {allegra,ihnp4,decvax,utai}!utzoo!henry
This does of course assume that all locations are addressable in all
instructions, which is emphatically not the case on many machines.
> We also should get rid of those quotes in the process...
What if I want to write asm("mov ')', r0")? The quotes are a reasonable way
of keeping the syntax of the assembler entirely out of the compiler's own
syntax handling, which is a good thing, especially for portable compilers.
So far I agree.
> (A consequence of this change is that "a[b]" is no longer definable as
> "*(a + b)".
Here I disagree. We can have it both ways. Allow automatic conversion
of arrays to pointers *where pointers are required*. That is, if you say
"b = a;", where a is an array, you get *either* a pointer assignment or
an array assignment, depending on whether b is a pointer or array variable.
The present definitions of * and [] can then be happily retained. In fact,
the entire present treatment of arrays can be happily retained, and thus
arrays-as-first-class-objects could go into C itself -- except for one thing.
Function calls.
If the rule was that a prototype of the form "void fun (int a[4], int *b);"
declared a function with one array and one pointer argument, then calls to
this function could follow the semantics I outlined above; a call of the form
fun(a,a); would pass the whole array a as the first argument, and a pointer
to its start as the second argument. (Barring some form of "conformant
arrays", the dimension 4 would have to match exactly.)
Of course, in the present draft, that declaration declares a function with
two pointer arguments. If this becomes as entrenched in the language in
connection with the new prototype syntax as it is with the old function
definition syntax, we will never get arrays-as-first-class-objects.
This is one reason why I and others have suggested that declarations such
as the above should at least cease to have their present meaning.
Mark Brader "C takes the point of view
SoftQuad Inc., Toronto that the programmer is always right"
utzoo!sq!msb, m...@sq.com -- Michael DeCorte
Perhaps what the original poster meant by his statement was that, for
instance, the following is legal:
foo (a, b)
char a; /* b is implicitly an int */
{
...
}
(Chapter and verse: K & R, Appendix A, Section 10.1, "Any identifiers
whose type is not given are taken to be _int_.").
Of course, in the above example, 'b' is not a variable, but a formal
parameter. Still, this is a problem... I once had a hard-to-find bug
that resulted from a missing formal parameter declaration defaulting to
int. _Has_ this been changed in ANSI C?
--
I am the Lizard King "Vous cherchez Jim, Monsieur?"
and I can do anything
-- caretaker at Gordan Palameta
-- Jim Morrison Pere Lachaise mnetor!lsuc!maccs!gordan
Perhaps the original author was referring to letting undeclared identifiers
which are followed by something that looks like an actual parameter list
default to being an extern function returning int, and to the ability to
elide int from declarations (which, if I rightly understand the X3J11 Draft,
can still be done as long as there's *some* keyword that lets the compiler
conclude that it's looking at a declaration). If that's indeed what the
original author was referring to, I sincerely agree with him. (It would
be nice if X3J11 deprecated it, too--which it may have, I don't recall.)
James Jones
PL/I has a similar feature, one can write
label: DO;
statements
END label; /* I may have this wrong */
There is a difference, though. In BCPL, the tags on the brackets must
match exactly, but in PL/I a tagged END may close any number of tagged
and untagged DOs.
Can anyone who has experience with using this feature suggest why it has
remained rare. In particular, does anyone know why it isn't in C, given
that it was in BCPL? (Not that I think it's needed.)
This is another reason for the user to be able to force the compiler to put
things in registers. The stupid compiler should not be able to force the
user to use many instructions because it does not see the need for register
variables. This applies also to such constructs as register pairs, triples,
etc. Naturally, this would require some way of modifying the register number,
but so what? This is simple, compared to the machinations that compilers
now undertake.
Also, it is rash to assume that the programmer does not make mistakes. If the
location types of the arguments do not work with the instruction, this is a
programming error; what are diagnostic and error messages for?
> > We also should get rid of those quotes in the process...
>
> What if I want to write asm("mov ')', r0")? The quotes are a reasonable way
> of keeping the syntax of the assembler entirely out of the compiler's own
> syntax handling, which is a good thing, especially for portable compilers.
Someone has posted an example where the failure was due to a " in the assembler
instruction. It is just as easy, since C requires a ; to end a statement, to
tell the compiler that until it sees ); to continue processing for the
assembler, and to have some escape mechanism for inserting ); into the
assembler statement. Alternatively, if we get rid of the ;s as mandatory
terminators (which I think is a good idea), have an escape mechanism for
inserting ) in an assembler statement. Is this worse than not being able
to put ", or even "), in an assembler statement?
>He has just re-invented BCPL.
Er, you give me too much credit. A feature of BCPL, perhaps,
but not the whole thing> :-)
>Where C has { and }, BCPL had $( and $).
>The name for these was "section brackets". There was an extra hack:
>"tagged section brackets". If <id> looked like an identifier,
>$(<id> and $)<id> were tagged section brackets (each was a single token).
>So in BCPL this example would be
> TEST boolean-expression THEN
> $(FOO
> ...
> $)FOO
> ELSE
> $(BAR
> ...
> $)BAR
>PL/I has a similar feature, one can write
> label: DO;
> statements
> END label; /* I may have this wrong */
>There is a difference, though. In BCPL, the tags on the brackets must
>match exactly, but in PL/I a tagged END may close any number of tagged
>and untagged DOs.
>
>Can anyone who has experience with using this feature suggest why it has
>remained rare. In particular, does anyone know why it isn't in C, given
>that it was in BCPL? (Not that I think it's needed.)
As it turns out I do have experience with this exact feature in PL/I.
I once inherited a 40,000 line PL/I program with a 5000 line main program
which used nested tagged begin/end blocks. I can tell you that multiple
closure is a real disaster. Fundamentally, the problem is that you can
remove an end statement, thereby changing the block structure of the program,
and the program is still syntactically correct and compiles. In a large
program which runs across many pages you can't visually confirm that all
the blocks align properly. It's been a long time now, and I can't recall
the gory details any more. However the practical effect was the same as
having a C switch construct with some of the terminating case 'break'
statements unintentionally missing.
As a side point, I like the suggestion that someone made that there be
a fallthrough statement rather than automatic fallthrough.
As to rarity of usage, I suspect the problem is that it is a nice feature
if you use it in a standardized disciplined manner, but that if it is not
obligatory it will be used haphazardly, and that it has no particular value
in that case. Now that I think on it, you don't need it for small pieces
of code, where everything is clear. It may have some value for large
programs (as in large number of lines per file). However my experience
is that the way to deal with the difficulties created by writing large
procedures is not to not write large procedures! :-).
OK, Richard, you win -- D should not have labelled blocks.
Be careful; cause and effect are circular here. I've been contacted by
more than one computer architect who wanted bit addressability but had
trouble convincing management to accept the slightly added expense because
they would observe that such a facility could not be exploited from popular
high-level languages. In fact, I have many applications for bit arrays
and bit maps, and there is a severe performance penalty caused by lack of
hardware support for them (and high-level language access to such support).
My "short char" proposal did not REQUIRE bit addressability, but it did
allow it to be exploited if the implementor decided it was wanted.
(1 = sizeof(short char) <= sizeof(char).) The other main implementation
would be to let a "short char" be an 8-bit byte and a normal "char" be
big enough to hold an entire textual unit (typically 16 bits in Japan).
Unfortunately not many committee members seem to be bit-map programmers...
>Please explain how avoiding superfluous words and keeping necessary ones
>short is consistent with changing {/} to begin/end for no particular reason.
A better reason for a change here is the problems cause by "dangling else"
and accidental ";" after the closing ")" of a while(). The idea that such
clauses control a single statement (which might be a compound statement)
makes C susceptible to such errors; using unique bracketing keywords would
be safer.
while condition do ;-separated_statements done
if condition then ;-separated_statements else ;-separated_statements fi
If would also be nice if such statements could return values (so ?: could
be dispensed with). Better yet, adopt notation more supportive of concurrent
processing, such as Dijkstra's "guarded" commands. Why not support the future?
No, like other warts, since this is widely used in correctly-written
(according to K&R rules) C code, and since it does not pose any true
technical problems, it must continue to be tolerated. Fix it in "D".
IF x > y
THEN max := x;
ELSE max := y;
END;
(I think I have the semicolons right; I'm sure about the one after END)
When these structures are nested deeply, one may be confused about
just what is being ended. To reduce confusion, the programmer may
insert any number of tokens from the opening statement between the
END and the semicolon:
IF x > y
THEN max := x;
ELSE max := y;
END IF x > y;
These tokens are optional, but if they appear, they must match
the corresponding tokens from the opening statement.
So, you would like to have to write
switch(var)
{
case foo: fallthrough;
case bar: fallthrough;
case baz: fallthrough;
case mung: /* code to do something for all four cases */
}
?
Or add yet another special case (automatic fallthrough if and only if there
is no code between the two labels)?
--
{harvard,uunet,ucbvax}!b.gp.cs.cmu.edu!ralf -=-=- AT&T: (412)268-3053 (school)
ARPA: RA...@B.GP.CS.CMU.EDU |"Tolerance means excusing the mistakes others make.
FIDO: Ralf Brown at 129/31 | Tact means not noticing them." --Arthur Schnitzler
BITnet: RALF%B.GP.CS.CMU.EDU@CMUCCVMA -=-=- DISCLAIMER? I claimed something?
There is another thing that should be reintroduced: case ranges in switch
statements. These were part of B (although they were not in BCPL):
switch (x) {
case <0: /* ... */
break;
case 0::10: /* ... */
break;
case >10: /* ... */
default:
}
While I'm totaly against changing the existing functionality of the
sizeof() operator, what I would be totaly in favor of would be the
addition-to-ansi-C of a new operator that would have a similar
functionality, but which would return the number of -bits- in
something. The name bitsize() would be my suggested name for this
operator.
This would provide one MAJOR advantage. It would allow writing code
or header files that would be 100% portable without having to know
about each and every compiler/OS/machine's identifer defines. If you
needed a 12 bit integer type, your headers could have #if statements
that would provide the next integer type equal or larger that 12 bits.
No more #ifdef'ing special integer types individualy for each system
when you're trying to make efficient code run on multiple machines.
An additional minor advantage would be the capability of writing
the kinds of functions we normaly use sizeof for to work with bitfield
variables..
This is a relatively minor addition to any existing compiler
(multiply sizeof by 8 for most machines... and return the bitsize
that's probably already a field in the evaluation structure for a
bitfield variable...) and would make some major advancements possible
in source code portability...
Doug Gwyn, I'd appreceate hearing your reaction on this suggestion.
If it's never come up as a suggestion, feel free to play with it. If
it's been considered and rejected, I'd like to hear the reasoning
behind the rejection.
---
John Stanley (jo...@viper.UUCP)
Software Consultant - DynaSoft Systems
UUCP: ...{amdahl,ihnp4,rutgers}!meccts!viper!john
More likely: Modula-2
After all, that was what Wirth intended to design when he designed Pascal.
#include <disclaimer.h>
Jonathan Leffler (jo...@sphinx.co.uk)
Note that this does *not* solve the dangling else problem. That being the
case, I see no reason to prefer it to the current syntax.
Mea culpa. The C compilers I use give warnings for undeclared functions and
several other things, which I treat as errors; so sometimes I forget which
ones are really errors.
The point still stands as regards undeclared functions, though.
>> Another thing that should go is the assumption that the unit of storage is
>> the byte. The base unit of storage is the bit, and sizeof should return the
>> number of bits in the object. This enables to treat objects smaller than a
>> byte as first class objects.
>
>Here we have a key decision: is D to share C's emphasis on generation
>of efficient code?
Yes.
>If so, then trying to forget that bytes exist is a serious
>mistake. Most machines cannot handle bits with anywhere near the efficiency
>with which they handle bytes; the appropriate base unit for efficient code
>*is* the byte.
This makes C nicely efficient on *many* machines; but there are others on
which a larger size would be much better. Not every machine is byte
addressable.
Conversely, on those machines which *do* have bit addressing, C provides
very inefficient access to it.
We need to figure out how to make D efficient without regard to the
addressing unit of the machine. Off-hand, I'm not sure how to do that.
>> ... In keeping with the spirit of C, we avoid
>> superfluous words, and keep the ones we do use short.
>>
>> With these changes, the {} statement delimiters become much less useful. I
>> would probably drop them, and add a "begin ... end;" construct...
>
>Please explain how avoiding superfluous words and keeping necessary ones
>short is consistent with changing {/} to begin/end for no particular reason.
I was thinking that with the other changes I proposed, the compound
statement would be needed only for declaring variables local to part of a
function. This use is not important enough to justify allocating two special
symbols to it.
This overlooks the compound statement forming the body of the function. This
is easily enough dealt with by making the function syntax be:
type declarator declarations statements end ;
instead of
type declarator { declarations statements }
One possible use for the braces would be as type parentheses, so one could
write:
{int *} a, b;
to make both a and b pointers to int. I think using this for casts would
improve readability as well. (That is, replace the parentheses around the
cast type with braces.)
This is an off-the-cuff idea, there may be better ones.
>> do we really need the pre-processor any more? ...
>
>The C++ people claim that the answer is "not much", given inline functions
>in particular. They do still use it for some specialized problems, though.
Overall, the preprocessor seems to be used as a way to hack prototypes for
the next extension to the language. C++ people tend to use it for
parameterized types, early C used it for consts and enums, etc. This may be
an argument for keeping it.
>> I would omit the automatic insertion of a null byte at the end of character
>> constants. If you want nul terminated strings, write the nul. If you want
>> strings with counts, the language should not get in your way.
>
>Pray tell, how do you write a counted-string constant?
struct string {char * data; int size};
char dummy[] = "This is my string."
struct string s = {&dummy, sizeof(dummy)};
If you want the length immediately preceding the string, you need new syntax
and/or the pre-processor to avoid writing the string twice.
>I would suggest that "abc" should mean a length-3 string with any necessary
>terminator, regardless of what flavor of string is in use. That way you get
>a choice, without recoding all your string constants.
And how do you specify what flavor of string is "is use?".
#asm <statement>
instead of
asm("statement");
This is almost worth doing in C; I would certainly do it in D (assuming the
preprocessor is kept).
The basic ideas are that "a[]" is an array lvalue, and that aggregate
constants are natively typeless and must always be either cast or assigned
to the appropriate type. Two examples follow.
(Watch out for the extensions to printf(3S) and scanf(3S) for array handling.)
I will explain any of this if desired.
EXAMPLE 1
int thing(i, a, b)[2]
int i, a[2], b[2];
{
int val[2];
val[0] = a[i] - b[0];
val[1] = a[i] - b[1];
return (val[]);
}
main()
{
typedef int PAIR[2];
char *message = "END-OF-EXAMPLE";
PAIR p1, p2, p3[2];
p1[] = {2, -3};
printf(p1: "%(2)4d\n", p1);
p2[] = {1, 7};
printf("p2: %(2)4d\n\n", p2);
p3[0][] = thing(0, p1[], p2[]);
p3[1][] = thing(1, p1[], (PAIR) {1, 7});
printf("p3: %(2; )(2, )d\n\n", p3);
printf("%(* )c\n", strlen(message), message);
printf("%(*:-])c\n", strlen(message)*2/3, (char *)NULL);
}
prints
p1: 2 -3
p2: 1 7
p3: 1, -5; -4, -10
E N D - O F - E X A M P L E
:-]:-]:-]:-]:-]:-]:-]:-]:-]
ANOTHER EXAMPLE
main()
{
int array[10][10];
int array2[100][10] = {0}; /* fills entire auto array with 0s */
int row;
scanf("%(10 )(10 )d&q