From -8822322887028463306
X-Google-Language: ENGLISH,ASCII-7-bit
X-Google-Thread: f78e5,f9d03435d36a70ff,start
X-Google-Attributes: gidf78e5,public
X-Google-ArrivalTime: 1990-08-10 13:59:16 PST
Path: gmdzi!unido!mcsun!uunet!wuarchive!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
Posted: Fri Aug 10 04:34:43 1990
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
*******************


