bmk@m2.csc.ti.com (Brian M Kennedy) (11/16/90)
I do not find any problem with the C++ definition of const. It is fairly simple and allows me the flexibility of defining what const means for new types that I write. For built-in types and structs/classes without user-defined constructors, const means that the bit representation of the object doesn't change. So, a compiler can place such a const in ROM or compile it out of existence (ie. hard-code it into immediates). For new user-defined types, classes with user-defined constructors, const means that the abstract object doesn't change. The bit pattern may change. Thus, the compiler cannot place such a const in ROM. Furthermore, casting away const-ness on such an object *is* well-defined and portable. The compiler will enforce bitwise const-ness in const member functions of user-defined types -- but that is just a programmer aid. The programmer simply responds "Yes, I know what I'm doing" by casting away the const-ness of the this pointer. Note that this is only valid for classes with user- defined constructors or destructors. Other classes are assumed to have compiler-defined (i.e. bitwise) constness and may be in ROM. MYTH: The "const" keyword in C++ specifies a property of storage, and as such is not particularly useful in an object-oriented program. The const keyword says nothing about storage for classes with user- defined constructors. So, when you define a new object class, you have complete control over the meaning of const. For built-in types, the bit representation *IS* the object. So, saying a const int cannot change bit representation is just as object-oriented as saying a const int cannot change its abstract value. MYTH: casting away const is non-portable This may be true for built-ins and classes without constructors, but is FALSE for classes with user-defined constructors. MYTH: compilers are free to place const objects in ROM This may be true for built-ins and classes without constructors, but is FALSE for classes with user-defined constructors. MYTH: cfront's behavior concerning const is the C++ definition of const cfront does *not* handle const correctly/understandably in all cases. Read Ellis & Stroustrup -- it describes const-ness rather clearly. --------------------------------- Brian M. Kennedy <bmk@csc.ti.com> Computer Systems Laboratory Computer Science Center Texas Instruments Incorporated
jimad@microsoft.UUCP (Jim ADCOCK) (11/27/90)
In article <1990Nov15.181026.24113@csc.ti.com> bmk@m2.csc.ti.com (Brian M Kennedy) writes: |I do not find any problem with the C++ definition of const. It is fairly |simple and allows me the flexibility of defining what const means for new |types that I write. I disagree with all parts of all sentences of the above statement 1/2 :-) |For built-in types and structs/classes without user-defined constructors, |const means that the bit representation of the object doesn't change. So, |a compiler can place such a const in ROM or compile it out of existence (ie. |hard-code it into immediates). A compiler is clearly allowed to put such an object in ROM, but that does not mean that the bit representation of such an object cannot change. Some other conforming compiler can still allow cast-from-const for such objects. Just because some compilers prohibit changing the bits of such objects doesn't mean that all compilers must make such a prohibition. |For new user-defined types, classes with user-defined constructors, const |means that the abstract object doesn't change. The bit pattern may change. |Thus, the compiler cannot place such a const in ROM. Furthermore, casting |away const-ness on such an object *is* well-defined and portable. I disagree. I see nothing in Ellis & Stroustrup that clearly supports such a view. Rather, I see Ellis & Stroustrup specify this as the behavior one would typically expect on most current architectures, rather than a constraint that all conforming compilers/architectures must meet. Contrary to your position, on the top of page 71 they state that the effect of modifying via a cast from const is either to make the original object as-if originally declared non-const, or to cause a run-time exception. This statement is made without restriction as to its applicability to objects with or without constructors, therefor I read this statement as being applicable to all objects, period. |The compiler will enforce bitwise const-ness in const member functions of |user-defined types -- but that is just a programmer aid. The programmer |simply responds "Yes, I know what I'm doing" by casting away the const-ness |of the this pointer. Note that this is only valid for classes with user- |defined constructors or destructors. Other classes are assumed to have |compiler-defined (i.e. bitwise) constness and may be in ROM. I disagree. Compilers cannot in general, in the presence of separately compiled and linked modules, strictly enforce bitwise constness in const member functions. A programmer who casts away const is not stating "Yes, I know what I'm doing" but rather is specifying "I'm willing to accept what my compiler[s] does to me in this situation." |MYTH: casting away const is non-portable | | This may be true for built-ins and classes without constructors, | but is FALSE for classes with user-defined constructors. I disagree. My copy of E&S on the top of page 109 says: "Adding 'const' to a declaration ensures that an object to which the 'const' is applied cannot have its value changed through an expression involving the name being declared unless an explicit type conversion is used to remove the 'constness' -- and possibly not even then." Thus, I interpret Ellis & Stroustrup's wording as to say that casting from const removes a program from the domain of strictly conforming programs to that of at best a conforming program. IE, that program may run as intended by the programmer on some but not all compilers. There are a multitude of reasonable things a programmer could want when doing a cast-from-const, including: *Ignore the fact that this object is constant and change it to some new "constant." Hopefully, said programmer changes from one "constant" to some new "constant" infrequently! *Ignore the fact that this non-const member funtion won't be able to change the value of this read-only object -- I'm only trying to invoke the member function for some other side effects. *Fail my executable with a memory fault if I ever try to actually molest a constant -- I'm storing an address of a const in a non-const pointer, but I'm only using that value as an object ID -- I promise never to access the constant object via the non-const pointer. *Put this object into discardable memory -- Its okay to go back to previous values if the present value of this object is discarded, and a prior value is reloaded. I want the speed of discardable memory, and I'm willing to program in such a manner as to make it all work out right. *I promise that the externally viewable attibutes of this objects won't be changed by the "internal" changes I'm about to make. *Inform me that I have made a programming mistake and tell me about my errors. *Warn me that I may have made a programming mistake and list my possible errors. *I'm calling code in an old library without any significant optimizations, so that issues of constness verses non-constness can be safely ignored. I do not see where Ellis & Stroustrup clearly prohibits many of the above compiler implementation choices. And I do see where E&S does prohibit a few of the above *reasonable* choices. So I don't see E&S as being very clear on these matters. |MYTH: compilers are free to place const objects in ROM | | This may be true for built-ins and classes without constructors, | but is FALSE for classes with user-defined constructors. I believe some compiler could be free to put an object with constructor in read-only memory because Ellis & Stroustrup are less than crystal clear on this matter. They say that most practical architectures prevent switching memory from read-write to read-only after construction, therefor ... They do not say that if such an architecture/compiler were to exist, that that compiler could not so use the read-only memory. In particular, on many systems it could be practical to evaluate at least some global constructors of constant objects once, make a copy of that memory to disk, then mark the entire region of global constants discardable. |MYTH: cfront's behavior concerning const is the C++ definition of const | | cfront does *not* handle const correctly/understandably in | all cases. Read Ellis & Stroustrup -- it describes const-ness | rather clearly. I disagree that Ellis & Stroustrup describes the issue of const-ness clearly. In particular, they do not clearly describe the rights and responsibilities of programmmers verses compilers in this area, but rather only give one description to cover both. What is needed is an ANSI-C like division of the problem into these two areas. In any case, it seems like various people read E&S's descriptions of const in very different ways. This would seem to be sufficient to say that E&S is not clear in this manner. I would hope that the ANSI committee would make the issue of const crystal clear, separating the rights and responsibilities of compilers and programmers, what is a strictly conforming program, verses mearly a conforming program. [And these desires hold doubly true for volatile and const volatile too!] A Humble Proposal: Perhaps cast-from-const can be guaranteed to work as if the object was never declared const iff the object is a non-parameter auto variable. Any compiler with function-level optimization should be able to handle this without great difficulty -- the optimizations then become the same as if the variable were never declared const. In all other situations cast-from-const would be implementation dependent. --Asking more from compilers would seem to have a major impact on optimization.