Talk:Const-correctness
From Wikipedia, the free encyclopedia
Contents |
[edit] Other Languages
Anyone know of other languages that support this? Wouter Lievens 10:47, 28 Apr 2005 (UTC)
- Strange, I never noticed before you asked: c++ is the only major language I can confirm uses const variables... Maybe it's because it sounds like such an oxymoron. Java seems to have a const keyword, but doesn't use it. Java's final keyword is similar when used with a member variable however. I believe that const may be valid C now since C99, but it'd be better to double-check that. I know of no other language with anything anologous to mutable. Const correctness seems to be a wholly C++ phenomenon. TheIncredibleEdibleOompaLoompa 17:19, 2005 Apr 28 (UTC)
- C# also has a const keyword (and a readonly keyword), though it really has nothing like const correctness in C++. IIRC, it makes a reference immutable, not the object itself. OracleofTroy
-
-
- Yeah Java has final and C# has const but it's not the same. What really matters (in this article) is the const correctness of methods. Wouter Lievens 07:48, 12 May 2005 (UTC)
-
-
- The const keyword exists since ANSI C. However, I consider it bad that the article uses "C/C++" or "C and C++" and then goes on using examples that work with C++ only (except the first). --82.141.48.135 4 July 2005 07:25 (UTC)
-
-
- You're right that the article should be more clear. ANSI C doesn't support const-correctness in the most important sense: applying const to object methods (because it doesn't support objects as such). --Flex July 4, 2005 11:24 (UTC)
-
-
-
-
- Are you sure about that? Let me transcode the C++ code to C:
-
-
struct C {
int i;
int (* Get)(const struct C *self); /* Note the const tag */
void (* Set)(struct C *self, int j);
};
/* The method implementations must of course still be wired (by a constructor) */
int C_Get(const struct C *self) { return i; } /* Note the const tag */
void C_Set(struct C *self, int j) { self->i = j; }
void
Foo(struct C *nonConstC, const struct C *constC) {
int y = nonConstC->Get(nonConstC); /* Ok */
int x = constC->Get(constC); /* Ok: Get() is const */
nonConstC->Set(nonConstC, 10); /* Ok: nonConstC is modifiable */
constC->Set(constC, 10); /* Error: Set() might modify constC! */
}
-
-
-
- If you try to compile this with GCC (for example) you get a warning for the last line: "warning: passing arg 1 of pointer to function discards qualifiers from pointer target type". So in my opinion, you can have this kind of "const correctness" in C, too. --82.141.48.146 7 July 2005 09:51 (UTC)
-
-
-
-
-
-
- Very few would attempt to write C++ code using C :-), but your point is well taken nonetheless. ANSI C does support const-correctness as far as it goes. Among object-oriented languages, C++ natively supports const-correctness with objects whereas Java and C# do not. --Flex 12:59, July 13, 2005 (UTC)
-
-
-
[edit] Immutability
I barely know the semantic of const, so I may be wrong but isn't this article talking about the same thing as immutable object? Of course, there is a difference but I don't think it is much to warrant two separate articles. So I am adding merge tag. Feel free to correct me if necessary. -- Taku 09:55, Jun 23, 2005 (UTC)
- Const correctness is a programming technique that maximizes the use of immutable objects and allows for a simple design by contract. It applies in several programming languages, but the only one in widespread use is C++, which is what the bulk of this article covers. I don't think they should be merged necessarily, but I wonder if this article belongs in the Wikipedia rather than a Wikibook on C++. --Flex 11:40, 23 Jun 2005 (UTC)
-
- While I am not C++ guru, this article, it seems to me, is little too verbose. For example, it says "const char *p" is the same as "char const *p", and this is clearly redundant; we are not writing a tutorial. Besides, the article seems to simply have random facts related to const rather than one specific idea (Actually I am not quite getting what this article is trying to say :) For instance, the discussion about volatile seems off-topic; if I understand correctly, it's basically the marker for lessening aggressive optimization. I don't believe that we can simply the content of this page to immutable object without any revision. But I still think it makes more sense to give some context, and for this the merger may help. What do ya think? -- Taku 12:38, Jun 23, 2005 (UTC)
-
-
- Well, the volatile section is there because C++ also supports "volatile correctness," but its application is much rarer. (Consider: const_cast is so named because it is usually used to strip the const qualifier, thought it can strip volatile qualifier, also. Calling it qual_cast [or something like that] apparently seemed like overkill to the C++ committee.) If it is determined that const correctness deserves its own article, volatile correctness also make an appearance but as a subsection rather than its own article because its use is rare and its usage syntax is basically the same as const's.
-
-
-
- Anywho, you're right that the article does tend more toward tutorial and loses sight of explaining const correctness as a concept. Let me try to make some revisions to correct that. Then we can decide if it needs to be merged. Personally, I think the concept of const correctness deserves its own page, but I could be persuaded. --Flex 13:13, 23 Jun 2005 (UTC)
-
-
-
-
- There's an important difference, in that an immutable object is an abstract concept, for it can be enforced (badly) using conventions rather than using language techniques. Const correctness is a technique for implementing partial static verification of object immutability. However, I (as article creator) see no reason why this information cannot be integrated into immutable object. So go ahead if you want. Wouter Lievens 13:40, 23 Jun 2005 (UTC)
-
-
-
-
-
- Ok, I (as major rewriter) have made the promised changes. What sayest ye now? --Flex 14:28, 23 Jun 2005 (UTC)
-
-
- I am still not so sure. For one, is there any relation between a value with const and method with const, aside from the use of a term const? When discussing method with const, I think we also have to talk about mutable, but it seems to be beyond the scope of this article. I rewrote the intro a bit. Please correct me if I have missed something. -- Taku July 4, 2005 19:37 (UTC)
Both articles are way more than stubs, and their topics really don't overlap much. I've been bold and removed the merge notices. --Quuxplusone 22:15, 21 July 2005 (UTC)
[edit] const, volatile, and hardware
I've been building hardware and writing plain ANSI C for some time. I suspect "const" and "volatile" would be easier to understand if we approached it from a hardware point of view. (On the other hand, perhaps it just *seems* simpler that way because I'm more familiar with hardware than with C#).
Let me hash out a rough draft here:
Modern CPUs use a von Neumann architecture, composed of a central processing unit, some random access memory, and the bus between them.
Each word of RAM only responds to one particular address, and ignores all other addresses.
Almost always there are other devices on the bus -- each one responds to its own particular address.
ROM also watches the bus, responding only to *reads* to a particular address, ignoring all writes.
Many microprocessors have a reasonable amount of ROM, but only a few precious bytes of RAM.
When a program is intended to go into a ROM, the programmer marks some data structures as "const". This tells the the compiler that it is permissible to put that data into the ROM.
Some subroutines modify data structures. Since it never makes sense to try to modify data values in ROM, good compilers will refuse to compile code that has this problem.
Other peripherals also watch the bus, waiting for their particular address to be selected, and either given a command, or a request for data. Now, if the program (as written) writes the value '\f' to normal RAM twice, it doesn't matter if the compiler re-arranges things so that it only writes it once (or, for that matter, 5 times). However, let me assure you that people will notice the difference between a formfeed character being sent to the printer once, twice, or 5 times.
Some serial ports buffer the data from the line, and have a special address for reading the next byte (which removes that byte from the buffer). If a program (as written) reads from some RAM address 1000 times (without any intervening write), it doesn't matter if the compiler re-arranges things so that it only reads that value once (and caches it in a register for the next read) (or, for that matter, reads it 2000 times). However, let me assure you that people will notice the difference between a program that responds to the real activity on a keyboard, vs. a program that reads only the first keystroke, caches that value, and from then on ignores anything typed on the keyboard, vs. a program that ignores every other keystroke.
The programmer tells the compiler which locations are associated with peripherals with the "volatile" flag. The compiler that it is permitted to do all kinds of clever caching optimizations for things in RAM and ROM, but "volatile" indicates data locations that are *not* normal RAM or ROM. This tells the compiler to *always* read or write values only the *exact* number of times the program actually specifies a read or write, and to keep them in the same order.
Sometimes the keystroke buffer is simulated by an interrupt routine that talks to the keyboard using a more complicated protocol, then the interrupt routine deposits the result into a particular byte in RAM.
To the application program, it doesn't matter if the keystroke buffer is a piece of hardware, or simulated by an interrupt routine. Since the programmer who wrote the application intends for that location to be treated as if it were a hardware peripheral, even in the case where it is really a bit of normal RAM being fed by an interrupt routine, that programmer continues to mark it as "volatile".
Do you think this approach (after a considerable amount of polishing) would be helpful in understanding? Or is it just more confusing ? Did I go into too much / not enough detail ? (Perhaps I should describe an even simpler, semi-fictional machine ?) --DavidCary 05:36, 16 July 2005 (UTC)
- Hi, David. As an embedded programmer myself, I think this approach would actually be misleading because const and volatile have uses in programs that don't touch hardware. In particular, the part about const indicating what a compiler can put in ROM is highly compiler-specific behavior (i.e., the standard that defines the language doesn't present it that way, I'm almost positive). In fact, that might be an incompatible extension because the const_cast operator is supplied explicitly to strip const-ness from an object. All this is to say that const correctness is more about program readability and design than about low-level interactions with hardware. --Flex 18:20, July 16, 2005 (UTC)
How would you use "volatile" in a program that didn't touch hardware ? (I use it to mark (a) peripheral registers, (b) bytes of RAM that are read or written by some interrupt routine pretending to be peripheral registers (or perhaps pretending to be a parallel processor). Is there a (c) another way of using "volatile" ?)
I agree that "const" is very useful in programs that don't touch hardware -- because it makes some things more readable. But I pretend that things marked "const" behave as if the compiler puts them in ROM, even when I know they are really in RAM (or perhaps optimized away to nothingness). How is that any more misleading than all the other as if C things? I'm pretty sure there is no such thing as a const_cast operator in plain ANSI C. The const_cast operator is a C++ thing, and I am still mystified by it.
Would you agree that real peripheral registers must always be marked with "volatile" and/or "const" to get the compiler to handle them correctly ? I think it's helpful, when reading an encyclopedia article about some new-to-me concept, to read about why something is (objectively) necessary in some cases, before I read about how it is (subjectively) "more readable" in other cases.
--DavidCary 12:28, 18 July 2005 (UTC)
- Hi, David. The article as I read it is about const-correctness, the programming technique, and the language support for it, not const in general. I think hardware issues are beyond the scope of the article (there's already some debate about whether even the existing text belongs in the Wikipedia -- see the discussions above).
- const_cast doesn't exist in C and exists in C++ primarily for compatibility with const-incorrect libraries and legacy code, which may not be modifiable. In any case, it adequately demonstrates the difference between physical constness and logical constness - the latter can be stripped, while the former cannot (without producing confusion at best or undefined/erroneous behavior at worst). Perhaps that distinction should be clearer (I think it was more explicit in a previous version), but the intro correctly says "The idea of
const
-ness does not imply that the variable as it is stored in the computer's memory is unwriteable. Rather,const
-ness is a compile-time construct that indicates what a programmer may do, not necessarily what he can do."
- Using volatile is usually (always?) required for dealing with memory mapped peripherals, yes, but that is not its only use. (It can be used for an object stored in memory and shared between two processes, for instance.) Furthermore, Bjarne Stroustrup says, "There are no implementation-independent semantics for volatile objects; volatile is a hint to the compiler to avoid aggressive optimization involving the object because the value of the object may be changed by means undetectable by a compiler" (C++ Annotated Reference Manual, p. 110). It is only mentioned (in what is essentially a footnote for the sake of completeness) because there is theoretically such a thing as "volatile correctness" that deals with any type of object (not just PODs), though it is so obscure that it doesn't deserve its own article (IMHO). Cheers! --Flex 14:36, July 18, 2005 (UTC)
- You need "volatile" if you use setjmp/longjmp for example to prevent the compiler from optimizing access to variables in that scope. I believe you also need it for variables that are set by signal handlers and checked outside of the handler like "while (!signal_received) { ... }". --82.141.48.32 20:51, 24 July 2005 (UTC)
[edit] Title Suggestion
Static validation of object immutability would be a good alternative title, albeit a bit too long. Wouter Lievens 17:08, 18 July 2005 (UTC)
- That's a good brief definition, but IMHO it doesn't work well for a title. "Const correctness" is the term that is commonly used for the concept, and consequently, it should be the title. --Flex 17:30, July 18, 2005 (UTC)
[edit] restrict in C99
The article used to say the following, in the section "restrict in C99":
- The C99 language special cases a restrict qualified pointer to a const qualified type in order to notify a compiler that it can assume "strong const" semantics.
Does anyone know what the writer had in mind? After all, in the example given (which is still in the current revision, but won't be for much longer, if I remember to come back and take it out), it seems to me that the compiler would be able to change
void foo(int *);
int bar(int *a)
{
const int *b = a;
foo(a);
return *b; /* const, non-volatile value cannot have been modified by the intervening code */
}
into
void foo(int *);
int bar(int *a)
{
int ret = *a;
foo(a);
return ret;
}
without any restrict
-based contortions on the programmer's part. A Google search for "strong const" doesn't turn up anything enlightening. --Quuxplusone 04:22, 22 August 2007 (UTC)
- No, a conforming C compiler would not be able to do the optimization you describe, because "const" does not imply that the object is immutable to everyone, merely that it is read-only when accessed via that particular pointer. So, in your example, the compiler has to assume that a call to "foo" could have changed the value pointed to by "b". On the other hand, with "const restrict", it knows that within the scope of that pointer, noone else is accessing the value through any other means, and thus the optimization becomes possible. Thus, "weak const" == "I cannot change this", "strong const" == "noone can change this". -- int19h (talk) 10:15, 5 April 2008 (UTC)
[edit] final methods in C++
The article states "Similarly, C++ does not have any feature equivalent to Java's final modifier for methods, although its effect on classes can be simulated by a clever abuse of the C++ friend keyword.[3]"
It needs clarifying to the non-guru C++ users, that the default behavior for C++ member functions is to be hidden, but not overridden. There is no method hiding in Java. Someone might think that you can't prevent overriding in C++, which is not true. The fact is how ever that you cannot prevent hiding in C++. —Preceding unsigned comment added by 84.36.31.228 (talk) 13:20, 31 October 2007 (UTC)
[edit] Volatile pointer example
Removed from the article:
- The programmer may also create
volatile
pointers, though their applications are rarer:
// Set up a pointer to a read-only memory-mapped register that
// contains a memory address for us to dereference
const int * volatile const tableLookup = reinterpret_cast<int*>(0x8004);
int currentTableValue = *tableLookup; // Dereference the memory location
int newTableValue = *tableLookup; // Dereference it again
- Since the address held in the
tableLookup
pointer can change implicitly, each dereference might go to a different location in the lookup table, socurrentTableValue
is not necessarily equal tonewTableValue
.
The code doesn't match the comments, and the accompanying English text glosses over the key point of confusion. The semantics of the code are: Take the value 0x8004 and convert it (at compile time) to a pointer; at runtime, store this pointer value in memory (at a location named "tableLookup
"; dereference it twice, but allowing for the possibility that someone else could be overwriting "tableLookup
" in between accesses. (C and C++ are fuzzy on what exactly "volatile" means, but "someone else overwriting it" (plus "someone else reading it", which is irrelevant here) is a good enough approximation of how modern compilers treat it.)
However, since the symbol "tableLookup
" has internal linkage, there is no plausible way for anybody else to be modifying the value at that address (which was determined randomly by the compiler, if it exists at all; remember, &tableLookup
is not (int*)0x8004
; that's the value stored in tableLookup
). Since tableLookup
was declared const
, the C++ compiler is not even required to allocate storage for an object called tableLookup
at all! You'll see this happen if you remove the volatile
qualifier. I don't think there's any wording in the C++ standard that forces the compiler to allocate space for tableLookup
just because it's volatile
.
The critical points about the semantics of the above code are: The value stored at 0x8004 is const
and can be assumed not to change. The tableLookup
object itself (if it exists) is const volatile
. The compiler (theoretically) cannot assume that the assignment to currentTableValue
reads from address 0x8004. But the comments and English commentary don't seem to match these points, and the code itself is kind of pointless, so I suspect that the original writer was laboring under misconceptions about the semantics of what he wrote. --Quuxplusone (talk) 07:22, 13 May 2008 (UTC)
- I think you may be mistaken. Regardless of linkage, a volatile variable (pointer or not) could change due to any number of circumstances outside the compiler's control or visibility (e.g., an on-chip peripheral's memory location, a memory hardware/firmware register). However, on re-reading, I think it's fine to omit this bit, which does make the coverage more complete but which is such a rare avis that it may serve to confuse rather than elucidate and for which a reliable source is not easily found AFAICT. --Flex (talk/contribs) 02:43, 14 May 2008 (UTC)
[edit] Reference numbering is incorrect
The reference numbering in the article is wrong, but I don't want to edit the article as I lack the expertise.
Reference pointer [3] at the end of the section "final and JAVA" refers to number "4." in the reference list. This is caused by the fact that the ID of reference number 3 ("endnote_cleverabuse") is not used in the article.
92.233.157.159 (talk) 20:25, 23 May 2008 (UTC)