jimad@microsoft.UUCP (Jim ADCOCK) (07/31/90)
Proposed: That when a parameter [including the hidden "this" parameter] is declared "const", or when the object referenced by a parameter is declared "const", than it is not legal to modify that which is declared "const" within the function. This is to say, the trick of casting to a non-const does not work on a parameter declared as "const." Compilers can flag as an error these situations. The reason I propose this restriction on the casting trick is to allow compilers to correctly optimize code when presented with independently compiled libraries. To be able to correctly optimize, compilers need to be able to assume that "const means const" in those libraries. The counter-position is that "const" means that an object appears unchanged from the outside, but individual members of the object may be changed [such as cached values.] However, an optimizing compiler can enregister one or more of those "const" values, such a hybrid, inconsistent object results when the "const"-ness of a function is not correctly stated. Thus if the counter-position is adopted, members of a object cannot reasonably be enregistered across "const" functions. Also, the possibility of placing "const" objects in read-only or write-once memory is eliminated. Let's let "const mean const" and deprecate the cast to non-const trick. [disclaimer: the above represents the opinion of an individual C++ user]
hopper@ux.acs.umn.edu (hopper) (07/31/90)
In article <56163@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes: >Proposed: > >That when a parameter [including the hidden "this" parameter] is declared >"const", or when the object referenced by a parameter is declared "const", >than it is not legal to modify that which is declared "const" within the >function. This is to say, the trick of casting to a non-const does not >work on a parameter declared as "const." Compilers can flag as an error >these situations. > I don't agree with the illegalization of this construct. I think it is against the spirit of the language to illegalize a cast. In C, and C++ a cast is supposed to always work, no matter what object you're casting. I think that it should be legal for compilers to preform optimizations based on the information given by declaring a const parameter, but programmers should be allowed to cast if they feel it neccesary. Have fun, UUCP: rutgers!umn-cs!ux.acs.umn.edu!hopper (Eric Hopper) __ /) /**********************/ / ') // * I went insane to * / / ______ ____ o // __. __ o ____. . _ * preserve my sanity * (__/ / / / <_/ / <_<__//__(_/|_/ (_<_(_) (_/_/_)_ * for later. * Internet: /> * -- Ford Prefect * hopper@ux.acs.umn.edu </ #include <disclaimer.h> /**********************/
fsset@bach.lerc.nasa.gov (Scott E. Townsend) (07/31/90)
In article <1913@ux.acs.umn.edu> hopper@ux.acs.umn.edu (Nils McCarthy) writes: >In article <56163@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes: >>Proposed: >> >>That when a parameter [including the hidden "this" parameter] is declared >>"const", or when the object referenced by a parameter is declared "const", >>than it is not legal to modify that which is declared "const" within the >>function. This is to say, the trick of casting to a non-const does not >>work on a parameter declared as "const." Compilers can flag as an error >>these situations. >> > > I don't agree with the illegalization of this construct. I think it >is against the spirit of the language to illegalize a cast. > > In C, and C++ a cast is supposed to always work, no matter what >object you're casting. I think that it should be legal for compilers to >preform optimizations based on the information given by declaring a const >parameter, but programmers should be allowed to cast if they feel it >neccesary. > >Have fun, >UUCP: rutgers!umn-cs!ux.acs.umn.edu!hopper (Eric Hopper) > __ /) /**********************/ > / ') // * I went insane to * > / / ______ ____ o // __. __ o ____. . _ * preserve my sanity * > (__/ / / / <_/ / <_<__//__(_/|_/ (_<_(_) (_/_/_)_ * for later. * >Internet: /> * -- Ford Prefect * >hopper@ux.acs.umn.edu </ #include <disclaimer.h> /**********************/ I disagree with the statement "In C ... a cast is always supposed to work.." In fact, it does not always work, although you are always allowed to try without the compiler getting too upset. For instance, casting a pointer to a char as a pointer to double is not guaranteed to work, event if the bit pattern at the address is a legal floating-point number. Why? Because some machines don't support arbitrary alignment of operands and many compilers (rightfully IMHO) don't slow down the code with multiple fetches to get around the alignment problem of the hardware. I submit that const cast tricks are in a similar class to char/double cast tricks -- they might work but are not guaranteed and shouldn't be assumed to work. You might even get a bus error trying to write to ROM or a read-only peripheral register. Let the optimizer do their thing without having to worry about a buch of tricks. If you don't want a const, don't use a const! -- ------------------------------------------------------------------------ Scott Townsend | Phone: 216-433-8101 NASA Lewis Research Center | Mail Stop: 5-11 Cleveland, Ohio 44135 | Email: fsset@bach.lerc.nasa.gov ------------------------------------------------------------------------
hopper@ux.acs.umn.edu (hopper) (08/01/90)
In article <1990Jul31.161942.1938@eagle.lerc.nasa.gov> fsset@bach.UUCP (Scott E. Townsend) writes: >In article <1913@ux.acs.umn.edu> hopper@ux.acs.umn.edu (Nils McCarthy) writes: >>In article <56163@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes: >>>Proposed: >>> >>>That when a parameter [including the hidden "this" parameter] is declared >>>"const", or when the object referenced by a parameter is declared "const", >>>than it is not legal to modify that which is declared "const" within the >>>function. This is to say, the trick of casting to a non-const does not >>>work on a parameter declared as "const." Compilers can flag as an error >>>these situations. >>> . . . >> In C, and C++ a cast is supposed to always work, no matter what >>object you're casting. I think that it should be legal for compilers to > >I disagree with the statement "In C ... a cast is always supposed to work.." >In fact, it does not always work, although you are always allowed to try >without the compiler getting too upset. For instance, casting a pointer Small terminology mistake. I meant that it was always supposed to compile, NOT always supposed to work. Sorry 'bout that, UUCP: rutgers!umn-cs!ux.acs.umn.edu!hopper (Eric Hopper) __ /) /**********************/ / ') // * I went insane to * / / ______ ____ o // __. __ o ____. . _ * preserve my sanity * (__/ / / / <_/ / <_<__//__(_/|_/ (_<_(_) (_/_/_)_ * for later. * Internet: /> * -- Ford Prefect * hopper@ux.acs.umn.edu </ #include <disclaimer.h> /**********************/
rfg@NCD.COM (Ron Guilmette) (08/01/90)
In article <56163@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes: >Proposed: > >That when a parameter [including the hidden "this" parameter] is declared >"const", or when the object referenced by a parameter is declared "const", >then it is not legal to modify that which is declared "const" within the >function. Your wording is fuzzy, but I get the idea. Note that for: extern void foobar (const int i); It can't make any difference to an optimizing compiler whether or not the const is in there or not, or whether or not foobar() enforces it strictly. However in the case of: extern void foobar (const int* i); it certainly can make a difference. >This is to say, the trick of casting to a non-const does not >work on a parameter declared as "const." Compilers can flag as an error >these situations. Why so fascist? I prefer warnings in such cases. I can even give you an example where "casting aside const'ness" was indispensible to me on one occasion. Imagine that you have a big program that every so often creates "nodes" (actually structs or classes) of some type. Each time one of these puppies gets created, it gets linked into some larger data-structure consisting of a large set of these things. (Let's just call it a network of "nodes".) Now once these guys are created, they remain essentially constant. So right after they get created and initialized, we totally wipe out any remnant of the original pointers to these guys and from then on use `const*' pointers instead. We pass these around, from routine to routine, throughout this big program, all over the place. Now although 99% of the program is perfectly happy to have the *entire* structures be constant (because no fields are ever modified after initialization) there is one tiny exception. Eventually, we want to print out a list of the contents of each of these "nodes", but we want to make sure that we never print any node more than once. Since the overall data-structure is a network, we (unfortunately) have no easy way to traverse the complete data structure such that we can be assured of only visiting each node one (and only one) time. Whatdaya do? Simple. Add a boolean field to each node called "printed". This gets initialized to false, but whild we are in the printing stage, these fields (in each record) will be set, one-by-one to true. If, during our printing traversal through the data structure, we see a node that has already been "checked off" (i.e. printed == TRUE), we avoid printing that node (redundantly) again. My code (in C) looked kinda like: struct node { const struct node *related1; const struct node *related2; int printed; }; void print_traversal (const struct node *arg) { if ( ! arg->printed) { print (arg); /* Cast aside const'ness */ } print_traversal (arg->related1); print_traversal (arg->related2); } >The reason I propose this restriction on the casting trick is to allow >compilers to correctly optimize code when presented with independently >compiled libraries. To be able to correctly optimize, compilers need to >be able to assume that "const means const" in those libraries. This is already allowed. Read your ANSI C standard. If one uses dirty tricks (like casting away const'ness) the standard sez that your compiler has the right to screw you unless you are very careful. Of course, the standard doesn't use the term "screw you". It prefers "behavior undefined". -- // Ron Guilmette // C++ Entomologist // Internet: rfg@ncd.com uucp: ...uunet!lupine!rfg // Motto: If it sticks, force it. If it breaks, it needed replacing anyway.
bobatk@microsoft.UUCP (Bob ATKINSON) (08/02/90)
In article <1913@ux.acs.umn.edu> hopper@ux.acs.umn.edu (Nils McCarthy) writes: >In article <56163@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes: >>Proposed: >> >>That when a parameter [including the hidden "this" parameter] is declared >>"const", or when the object referenced by a parameter is declared "const", >>than it is not legal to modify that which is declared "const" within the >>function. [...] > I don't agree with the illegalization of this construct. I think it >is against the spirit of the language to illegalize a cast. > > In C, and C++ a cast is supposed to always work, no matter what >object you're casting. This is not true of C or C++. Examining Section 5.4 of E&S reveals the following: "Any type conversion not mentioned below and not explicitly defined by the user (Section 12.3) is an error. Any type that can be converted to another by a standard conversion (Section 4) can also be converted by explicit conversion and the meaning is the same." Pointer to integer casts are valid, subject to restrictions. Integer to pointer casts are valid, subject to restrictions. Pointer to pointer casts are valid, subject to rectrictions. Object to reference casts are valid, subject to restrictions. That's it. In particular, for example, casts of floats to pointers or of one object of user-defined type to one of another UDT in the absence of appropriate user-defined conversions is an error. Bob Atkinson Microsoft
glenn@bitstream.com (Glenn P. Parker) (08/02/90)
In article <1913@ux.acs.umn.edu> hopper@ux.acs.umn.edu (hopper) writes: >In article <56163@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes: >>Proposed: >> >>That when a parameter [including the hidden "this" parameter] is declared >>"const", or when the object referenced by a parameter is declared "const", >>than it is not legal to modify that which is declared "const" within the >>function. This is to say, the trick of casting to a non-const does not >>work on a parameter declared as "const." Compilers can flag as an error >>these situations. >> > I don't agree with the illegalization of this construct. I think it >is against the spirit of the language to illegalize a cast. Until recently (after C++ invented it), C did not have "const". Therein lies some confusion. I submit that it is absurd to put const in the same category with other type names. Const is not a typename, it is a storage qualifier, like "auto" and "static". You can't typecast from auto to static, and I agree with Jim that you shouldn't be able to cast from const to non-const. -- -------------------------------------------------------------------------- Glenn P. Parker Bitstream, Inc. uunet!huxley!glenn 215 First Street glenn@bitstream.com Cambridge, MA 02142-1270
jbuck@galileo.berkeley.edu (Joe Buck) (08/02/90)
In article <GLENN.90Aug1145326@huxley.bitstream.com>, glenn@bitstream.com (Glenn P. Parker) writes: |> Until recently (after C++ invented it), C did not have "const". Therein |> lies some confusion. I submit that it is absurd to put const in the same |> category with other type names. Const is not a typename, it is a storage |> qualifier, like "auto" and "static". You can't typecast from auto to |> static, and I agree with Jim that you shouldn't be able to cast from const |> to non-const. The overloading system in C++ treats const as part of the type; there may be int foo(char*); int foo(const char*); and these may be two different functions. const is part of the type; it's different from static and auto. I've had to write casts from const to non-const because the following situation sometimes arises: a) The writer of some library function declares an argument to be type char*, although the string is not changed by the function; b) I want to pass a const char* to it. I wouldn't want to see this forbidden. I do think it's reasonable to give writers of optimizing compilers carte blanche to assume that a function that takes a pointer to const cannot under any circumstances change the object. If you cheat and do it anyway by casting or other tricks, the compiler is free to break your code; you deserve to lose. Historically (from C) a cast says "trust me, I know what I'm doing". The same should apply in C++. The programmer should be allowed to write any type of cast, and the resulting program may be non-portable if he does. -- Joe Buck jbuck@galileo.berkeley.edu {uunet,ucbvax}!galileo.berkeley.edu!jbuck
karl@haddock.ima.isc.com (Karl Heuer) (08/02/90)
In article <GLENN.90Aug1145326@huxley.bitstream.com> <glenn@bitstream.com> (Glenn Parker) writes: >Const is not a typename, it is a storage qualifier, like "auto" and "static". "int" is an atomic type. "auto" is a storage class. "const" is a type qualifier. The three are distinct concepts. >I agree with Jim that you shouldn't be able to cast from const to non-const. Seems to me that the ANSI C rules have it right: you can cast from const to non-const if you have to, but you can't use the non-const pointer to modify an object that's ultimately const. The compiler could legally put a const object into nonwritable store. Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint
decot@hpisod2.HP.COM (Dave Decot) (08/02/90)
> >I disagree with the statement "In C ... a cast is always supposed to work.." > >In fact, it does not always work, although you are always allowed to try > >without the compiler getting too upset. For instance, casting a pointer > > Small terminology mistake. I meant that it was always supposed to > compile, NOT always supposed to work. No problem. But I still disagree. If the compiler knows it's not going to work, I'd much prefer that it tell me and fail to compile it. Dave Decot
henry@zoo.toronto.edu (Henry Spencer) (08/02/90)
In article <GLENN.90Aug1145326@huxley.bitstream.com> <glenn@bitstream.com> (Glenn Parker) writes: >Until recently (after C++ invented it), C did not have "const". Therein >lies some confusion. I submit that it is absurd to put const in the same >category with other type names. Const is not a typename, it is a storage >qualifier, like "auto" and "static"... The real, underlying problem here is precisely whether const *is* a storage qualifier or not, by intent. Unfortunately, const gets used for two very different purposes: "this is really, truly, a constant" and "I may be allowed to modify this but you aren't". It might have been better to use different words for these two uses. It's a bit late now. -- The 486 is to a modern CPU as a Jules | Henry Spencer at U of Toronto Zoology Verne reprint is to a modern SF novel. | henry@zoo.toronto.edu utzoo!henry
jimad@microsoft.UUCP (Jim ADCOCK) (08/03/90)
In article <1913@ux.acs.umn.edu> hopper@ux.acs.umn.edu (Nils McCarthy) writes: > > I don't agree with the illegalization of this construct. I think it >is against the spirit of the language to illegalize a cast. > > In C, and C++ a cast is supposed to always work, no matter what >object you're casting. I think that it should be legal for compilers to >preform optimizations based on the information given by declaring a const >parameter, but programmers should be allowed to cast if they feel it >neccesary. Okay, lets enumerate some choices about how compilers can choose to handle this problem. I'm assuming that the language definition needs to be such that the traditional separately compiled modules, standard linkers with "type safety" via name mangling is used. 1) Never optimize when calling functions with const parameters. [Pessimistic approach] 2) A function with a const parameter which is cast to a non-const is flagged with a error when it is compiled. 3) A function with a const parameter which is cast to a non-const is flagged with a warning when it is compiled. 4) A function with a const parameter which is cast to a non-const is not flagged when it is compiled, just silently accepted, leading potentially to optimization errors when it is used. --- I'd reject option #1 because I believe C++ code needs to be highly optimized in order to get C-like performance. I'd reject option #4 since compilers can then generate bad [erroneous] code without giving the user any hint that anything is going on. Option #3 has the "advantage" of letting people write functions that will work in some calling sequences, and fail in other calling sequences. These failures would be hard to track down, and impossible to fix -- other than turning optimization off. So I'd prefer to just see option #2. Option #3 [warning] would be acceptible in compilers that don't do much optimizations. A compiler with a flag to turn optimization on and off could switch the level from warning to error -- but this is a poor "solution" given that the "const" function can be compiled with the optimization flag off, and the calling function can be compiled with optimization on. [standard disclaimer]
nadkarni@ashok.nac.dec.com (ashok p. nadkarni) (08/03/90)
How about when a function takes two parameters, one const and the other non-const. If the caller passes the same object (by reference or through a pointer) for each parameter should it be smart enough to know that the const object may have actually changed through the other parameter ? Or is it the responsibility of the programmer writing the calling code (in which case I would never use const for functions taking two or more parameters of the same type). I'm learning C++ and have been staying away from const parameters because I wasn't sure how a compiler would handle the above case. Are there any rules that cover this case ? Ashok Nadkarni
psrc@mtunq.ATT.COM (Paul S. R. Chisholm) (08/06/90)
In article <1990Aug2.164129.25231@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes: > The real, underlying problem here is precisely whether const *is* a > storage qualifier or not, by intent. Unfortunately, const gets used > for two very different purposes: "this is really, truly, a > constant" and "I may be allowed to modify this but you aren't". For example, consider the strchr function (from ANSI C): char* strchr( const char* s, int c ) and how it might be called from two functions, f1 (which takes a char* to search through), and f2 (which is passed a const char* to examine). The declaration of strchr() is intended to state that strchr() will not modify the data pointed to by its first argument. This is implemented by incrementing the pointer until it points to the appropriate character, and then casting *that* pointer from a const char* to a char*. Now, how does that affect strchr()'s callers? f1() has permission from its caller to modify the string; f2() does not. If strchr() returned a const char*, f2() would be fine, but f1() would be handed a pointer it can't use to modify the string. We could declare two polymorphic functions: const char* strchr( const char* s, int c ); char* strchr( char* s, int c) which C++ could distinguish between because of the difference in the first arguments' types; but where's the "promise" that the second function won't modify the data it's passed a pointer to? Left unspoken, for convenience's sake? > It might have been better to use different words for these two > uses. It's a bit late now. I'm afraid so. > Henry Spencer at U of Toronto Zoology, henry@zoo.toronto.edu > utzoo!henry Paul S. R. Chisholm, AT&T Bell Laboratories att!mtunq!psrc, psrc@mtunq.att.com, AT&T Mail !psrchisholm I'm not speaking for the company, I'm just speaking my mind.
jimad@microsoft.UUCP (Jim ADCOCK) (08/17/90)
In article <1029@lupine.NCD.COM> rfg@NCD.COM (Ron Guilmette) writes: >Note that for: > > extern void foobar (const int i); > >It can't make any difference to an optimizing compiler whether or not the >const is in there or not, or whether or not foobar() enforces it strictly. I disagree. A compiler that uses a register passing protocol could very well enregister a const int i before the call to foobar, expecting that foobar would not molest it, and then attempt to reuse i without re-enregistering it. >>This is to say, the trick of casting to a non-const does not >>work on a parameter declared as "const." Compilers can flag as an error >>these situations. > >Why so fascist? I prefer warnings in such cases. When a programmer writes a routine that plays games that are not portable, or may not work in the face of compiler optimizations, thus busting that routine itself, I think that deserves a warning. However, when a programmer writes a routine that appears to be correct by inspection, appears to test out correctly, but in unusual situations can bust the caller's code -- not the callee's code! -- then I think that deserves an error. The resulting bugs would be very insidious to try to track down.