Path: utzoo!utgpu!news-server.csri.toronto.edu!mailrus!uwm.edu!zaphod.mps.ohio-state.edu!usc!ucsd!helios.ee.lbl.gov!pasteur!madrone.berkeley.edu!twagner From: twagner@madrone.berkeley.edu (Tim Wagner) Newsgroups: comp.std.c++ Subject: 'const' revisited Keywords: const access restrictions Message-ID: <26909@pasteur.Berkeley.EDU> Date: 10 Aug 90 03:34:43 GMT Sender: news@pasteur.Berkeley.EDU Reply-To: twagner@madrone.berkeley.edu (Tim Wagner) Organization: UCB Lines: 114 X-Local-Date: 9 Aug 90 20:34:43 PDT The recent discussion on this newsgroup about the conflicting uses of 'const' gives one pause. Shouldn't something as useful as the two notions here be corrected in C++? The key distinction is between a restriction of access through a particular binding, and a restriction on access to an underlying object. In the first case, the programmer merely wants to tighten the type of a name (binding) to get additional compile-time error-checking for what he/she has decided is an invalid access attempt. In the second case, the object being referred to is truly a constant; the compiler is justified in placing it in read-only storage, and preventing (to the extent possible) any non-read-only access attempt through any binding at all. For a name access restriction, casting into the equivalent non-restricted type makes sense. For object access restriction, casting into the non-restricted type should produce a stern warning, since writing to such an object can produce runtime errors depending on the implementation. One problem that currently exists is the confusion between objects and bindings. Consider the following code: int i; const int& r = i; ... i = 5; /* Legal */ r = 6; /* Compiler warning about assigning to non-const object */ In the second line, the 'const' essentially refers to the binding of the name 'r', NOT to the object 'r' refers to (which is obviously non-const). In the following code, the 'const' refers to the object AND the binding: const int i; int& r = i; ... i = 5; /* Compiler warning about assigning to non-const object */ r = 6; /* No warning, and probably a runtime error */ The confusion over the meaning of 'const' is troublesome, and creates an asymmetry in whether it applies to the object or the binding. In the latter case, one might very well desire a read-write object with a read-only binding through i (but not through r). This is not expressible in the language per se. One possible solution is to apply machine-independent semantics for the keyword volatile. That is, the following chart will obtain: | volatile | none ------------------------- const | A | B ------------------------- none | C | D ------------------------- A: A name declared with these specifiers has a read-only access restriction associated with it (i.e., the name is read-only), but the underlying object is read/write. Casts to B can occur implicitly; casts to C or D must be explicit. B: A name declared with only the 'const' specifier has both the read-only access restriction, AND the object it refers to is declared to be read-only. The compiler is justified in replacing the value (where possible) with its value (i.e., inlining the value), caching it in a register, etc. Casts to A occur implicitly; casts to C or D must be explicit. C: This suggests to the compiler that the object cannot be held in read-only storage, even if it "believes" otherwise. There may be additional optimizing actions that are prevented by the addition of the "volatile" specifier. Casts to D are implicit; casts to A and B must be explicit. D: Normal type. Casts to A,B,and C are implicit. The compiler is free to treat the object as read-only or read-write, depending on what sort of analysis it is capable of. The binding, in any case, is read-write. This has two advantages: it supplies a useful semantic meaning to 'volatile', and it distinguishes between two important, but distinct, meanings of read-only. gcc, for instance, will (in my mind correctly) handle a global declaration of "const volatile int i;" by creating a read-write object (i.e., not in the text segment) with read-only access restrictions for the name 'i'. THIS SHOULD BE CODIFIED INTO LAW! Furthermore, a code fragment such as: int i; const int *p = &i; should be flagged as a violation: the semantics are inconsistent here, as the object 'p' points to is NOT const. This should really be written int i; const volatile int *p = &i; since the BINDING is read-only, rather than the object being pointed to. The use of 'const' already confuses the issue of binding and object; the suggested style requires 'const' to refer to the object and the binding, unless 'volatile' modifies it to refer to the binding only. Since this appears to be the only place where bindings and objects are treated separately already, the change in semantics appears justified. Furthermore, the use of 'volatile' to imply that the object is read/write is consistent with what little semantics are described for it in E&S. If a particular site or implementation requires additional semantics formerly produced by 'volatile', a new keyword or pragma may be used instead. ******************* Tim A. Wagner Graduate Researcher, UCB My opinions are my own, etc. twagner@sequoia.Berkeley.EDU *******************