Shallow Constitude

In programming languages, there are constructs that are of little pragmatic importance (that is, they do not really affect how code behaves or what code is generated by the compiler) but are of great “social” importance as they instruct the programmer as to what contract the code complies to.

200px-Padlock-light-silver.svg

One of those constructs in C++ is the const (and other access modifiers) that explicitly states to the programmer that this function argument will be treated as read-only, and that it’s safe to pass your data to it, it won’t be modified. But is it all but security theater?

Let us start with a C-style program (that may be C++):

void le_troll_func(const char * buffer)
 {
  for (int i=0;buffer[i];i++)
   buffer[0]=0;
 }

This normally results in some compile-time error:

const-test.cpp: In function 'void le_troll_func(const char*)':
const-test.cpp:24:14: error: assignment of read-only location '* buffer'

The first observation is that despite const, one can discard constness using either C-style or C++-style casts. In C, we can easily re-write it as:

void le_troll_func(const char * buffer)
 {
  for (int i=0;buffer[i];i++)
   ((char*)buffer)[0]=0;
 }

…which compiles without so much as a warning. In C++, we can replace the cast by a const_cast:

void le_troll_func(const char * buffer)
 {
  for (int i=0;buffer[i];i++)
   const_cast<char*>(buffer)[0]=0;
 }

Even the C++ method modifier const is weak. Consider:

class inner_thingie
{
 public: int zoidberg; // why not?
};

class thingie
 {
 private:

  int x;
  inner_thingie * z;

  void le_troll_function() const { z->zoidberg=3; }

  void on_something_else() const { x=3; }
  

  thingie()
   : x(0), z(new inner_thingie)
  { }
 };

Cause compilation error (yes, without ‘s’):

const-test.cpp: In member function 'void thingie::on_something_else() const':
const-test.cpp:15:38: error: assignment of member 'thingie::x' in read-only object

So, while on_something_else() const behaves as expected, le_troll_function() const clearly does not. Apparently, if z is const, the constness isn’t transitive and does not apply to what z points to. ISO 14882:2003 §9.3.2.2 states that const on a function forces *this to be const, but does not imply it propagates, it is limited to this. tl;dr: const is shallow.

*
* *

If const doesn’t seem to enforce a great deal of constraints, is it still worth using? It is of little pragmatic importance—I have yet to find a compiler optimization that takes some real advantage of const—but if it is honored as it should be, const signs a contract between the function (class, library) and the user (the programmer). It helps distinguish functions that read-only data, and those that rewrite it. C (and C++) libraries have been extensively consted when the keyword was introduced to the language (for it hasn’t been there forever) for this reason. So, yes, I think it’s still worth using const, even with its limitations.

*
* *

The const “social contract” of const isn’t very strong, and a programmer can easily deconst data. But if a programmer does it deliberately, you’re to find him and taunt him. Even a second time.

2 Responses to Shallow Constitude

  1. Evan Jones says:

    Re: compiler optimizations: Certainly most compilers at this point optimize constant data appropriately (e.g. const int A = 42; const char B[] = “hello world”;) I also wouldn’t be shocked if its possible to find a case where adding “const” might allow the compiler to hoist something outside a loop, but I’m not a compiler expert. I suspect that in most cases, without the “const” keyword, the compiler can still probably figure out that the variable doesn’t change. The exception might be pointers to const? But again, I’m not an expert …

    • For const int a=42; I would guess that the compiler tries to propagate the constant directly into the code; but since you may also want &a, it will allocate it somewhere anyway. No, I was thinking more of vectorized operations. I can’t really think of a optimization you can do with const you can’t do without when you scan an array, or compute the sum, or the sum of two arrays into a third (and aliasing issues aren’t addressed by the language anyway: it’s your problem to figure out a way to make c[i]=a[i]+b[i] doesn’t write on itself).

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: