Path: utzoo!mnetor!uunet!husc6!cmcl2!brl-adm!umd5!purdue!i.cc.purdue.edu!j.cc.purdue.edu!ksb From: ksb@j.cc.purdue.edu (Kevin Braunsdorf) Newsgroups: comp.lang.c Subject: Re: some objections to 'noalias' Message-ID: <6041@j.cc.purdue.edu> Date: 23 Dec 87 18:05:48 GMT References: <485@cresswell.quintus.UUCP> <1453@cuuxb.ATT.COM> Reply-To: ksb@j.cc.purdue.edu.UUCP (Kevin Braunsdorf) Distribution: na Organization: K Project Lines: 130 Keywords: exclusive, ordinary, volatile, too late Summary: good idea, we need it, but too late In article <492@cresswell.quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes: >The statement that Fortran uses pass-by-value-return is simply false. .... Some Fortran implementations use valret. .... .... tools such as PFORT which can check that the aliasing ... .... Fortran no-aliasing rules are not violated .... .... But then Fortran is a much simpler language than C .... .... there simply isn't any safe way to write this in Fortran .... .... while there is in C. FORTRAN? Right: they chose *not* to deal with the aliasing issue by waving their collective hands at it: "You can't do that!" they said! Then the compiler should check for it: we are back to cc/lint with f77 & pfort? If it requires more info than the compiler has it is not relevent to a compiler discussion. Clearly. Enough about FORTRAN: I could *not* care any less. This shows how C is *trying* to deal with a problem that FORTRAN and other languages just gave up on... read on. .... what is so special about C that it needs a 'noalias' declaration? The aliasing problems in C happen at "deeper" levels due to the pointer to a pointer to a widgit constructs. C is trying to cope with the aliases rather than "forbid" them. > The point that the C compiler already takes a great deal on blind > faith is quite right, and it takes a lot of the steam out of my > objections to 'noalias'. > .... casts significantly harder to debug ... Yes: this hole has positive pressure behind it. When trying to insert a noalias assertion into the code a good programmer will prove to themself that it is not true. And we are still coping with the problem here. > I should make it plain that my objection to 'noalias' was more vehement > than perhaps was warranted, because on the whole I am tremendously > impressed by the work of the ANSI C committee. I am not: recently they have begun to bag things. (#pragma, (char *) == (void *), unary +, enum ~= int) > -- 'noalias' still does not mean "no alias" so the >name< is bad See [Below]. > -- if "other languages do it" was a good enough argument for > giving parentheses more than merely grouping effect, then > "other languages do it" is a good enough argument for > having "noalias" be the default I agree completely: the "other languages do it" was *never* good enough for the (..) "feature". C should re-a range expressions with impunity. (I'd rather see the bag-on "unary +" for goodness sake!) > -- pragma(noalias) is still a better approach > {what does #pragma do? Surely a macro processor which may be > completely separate from the compiler is the wrong place for > such things?} Pragma is the largest BAG-ON I have ever seen in a compiler. It can do anything & nothing all at the same time. (Stop it with the bags!) This noalias type modifier can *really* change the ADT (set of ops & data). >and Marc Mengel has not refuted these claims. OK, I will. [Below] is here. The "noalias" assertion *should* mean that there is no other *active* handle on the data item. It should also tell the compiler that if you see me giving this handle to a function: a) you must sync the data b) compute the required handle (could be address arith here) c) process function call d) mark any temps as invalid (based on this data); the subroutine could have changed it, but we have control again (for now). So basically: diddle(pi) exclusive int *pi; { *pi = 0; /* here we can move 0 to a temp */ while (something()) { *pi += someexpr(); /* here we can use the temp */ } /* possible sync for *pi */ g(*pi); /* *pi in sync yet, use temp? */ /* forced sync point for *pi */ f(pi); /* we sync before the call */ /* force sync before we return */ } You see how the compiler (even in a simple case) can make a register save or no-save choice around the call to g()? In more complex code *only* the compiler is going to be able to keep track of all of the registers and sync points involved. The whole key to the "exclusive" access (Marc and I call it) restriction is that the handle must be the only *active* handle; others may exist; but they may not be in use (even better is that a runtime checker *can* be written for this. {Keep a back pointer to the active handle with the data... really slow but it will find the bugs. And changes the ADT}). Just like checking array bounds, right? Marc has already pointed out the the compiler believes the programmer about pointer casts, pointer references (through nil), array bounds, parameter prototypes (pre-ANSI). What about memory allocation: pi = (int *) malloc(sizeof(char)); ^^^^^ ^^^^ or deallocation: free(& BagMe); /* for a good time */ free(main); /* for a core dump */ or any of a number of other very important semantic restrictions? A C programmer cannot code without thinking of all of these. This feature makes one more aspect of the programmers job clear (alias control). Finally: I do not feel the feature belongs in ANSI C. It is not C. It is too late to add it. It is a bag-on addition. It is a poor choice of keywords. And for all the good it could do it will cause more harm to add it this late in the game. Wait for D or K. Kevin Braunsdorf ksb@j.cc.purdue.edu K Project pur-ee!gawk!klang