const

Benji Smith benji at benjismith.net
Fri Mar 28 16:47:17 PDT 2008


Walter Bright wrote:
> Benji Smith wrote:
>> I was thinking the same thing myself, which is one of the reasons I 
>> dislike the constness being part of the type. In C++ "register" isn't 
>> part of the type system. It's just an optimization hint.
> 
> It can't be just an optimization hint. For example, if I pass const(T*) 
> to a function foo(), that means I want to guarantee that foo() does not 
> change it. Having the compiler accept that foo() changes it, and so 
> disable some optimization somewhere, does me no good at all.

I'm still not convinced that whether or not a function modifies its 
argument values has anything to do with the type system. At the very 
least, it only applies to the function's type, not the types of the 
arguments.

The automatic casting of arguments to const, for no purpose other than 
to satisfy the type system, feels wrong to me. With one hand, you're 
creating a restriction in the type system, and with the other hand, 
you're creating a loophole in the type system that only applies to this 
specific case. I can feel occam's razor prickling at my brain, and it 
doesn't sit well with me.

Just because a function promises not to modify its argument doesn't mean 
the function can only accept an immutable value. It should accept any 
value at all, without discriminating based on mutability. In fact, the 
mutability of the arguments only matters *within* the function (and 
further down the call stack). To me, that sounds more like a storage 
class (or some other type of declaration modifier).

But even putting aside the type-system for a moment, I still think that 
much of the emphasis of const-correctness is misdirected.

Asking a method or function to document which arguments it *DOESN'T* 
modify is a lot like asking the police to keep a detailed record of all 
law-abiding citizens, as a roundabout way of tracking down criminals. Or 
calling the doctor everytime you're not sick, so that he can set an 
appointment for you whenever you don't call. What about a special syntax 
to denote all functions that don't throw exceptions?

Wouldn't it make more sense to annotate *MUTABILITY* of function arguments?

Otherwise, you end up with a bunch of 'const' clutter all over the place:

    int str_search(const(char[]) needle, const(char[]) haystack,
       const(char)* start, const(char)* end);

Egads. It's a nightmare.

Isn't this code better, in nearly every way?

    int str_search(char[] haystack, char[] needle, char* start,
       char* end);

At a quick glance, I can see that this function is not going to modify 
any of its arguments (since none of them are marked as 'mutable'), so I 
can pass any values I want. The function doesn't care whether it 
*receives* mutable or immutable values, since it's not going to mutate 
them one way or the other.

On the other hand, I might have a function declared like this:

    void str_replace(mutable char[] haystack, char[] needle,
       char[] replacement, char* start, char* end);

In this case, there's only one argument that might be modified by the 
function. Any caller of this function must ensure that the 'haystack' 
variable provides a mutable view. The other argument values remain 
unrestricted, so the caller of this function only has to fuss about with 
one restriction.

It's easier on the brain that way.

What if, as a library author, I forgot to mark the haystack variable as 
mutable? Or if my code accidentally modifies the contents of one of the 
other variables?

As soon as I touch the data in that array, the compiler should throw a 
huge tantrum.

Shazzam! Const-correct!

And unlike the ever-so-common casting away of "const-ness", casting away 
mutability should be completely impossible.

Under the current regime, the prototype of this method is quite a bit 
more bulky:

    void str_replace(char[] haystack, const(char)[] needle,
       const(char)[] replacement, const(char)* start, const(char)* end);

Resenting all that extra typing, I'm likely to get lazy and leave off a 
few of those const modifiers. Either out of my trademark forgetfulness, 
or just because I'm a spiteful person:

    void str_replace(char[] haystack, char[] needle, char[] replacement,
       char* start, char* end);

Now the compiler is hamstrung. It can't enforce anything. I can change 
the values of any argument without a single warning message.

So much for const-correctness.

There's nothing special about a value not changing (at least, not for 
function arguments), so programmers should't be burdened with annotating 
the mundane case. Mutability of function arguments is much more interesting.

Labeling function arguments as mutable would, in my opinion, provide a 
*stronger* const regime, while simultaneously producing less pointless 
code clutter.

As for 'invariant' data (and its relocation to read-only memory or 
whatever), my opinion is: let the compiler do whatever optimizations it 
wants. I'd rather declare that kind of data as "const", and if the 
compiler can figure out that a pointer to the data is never taken, then 
it can burn the value into silicon as far as I care.

(Incidentally, when I started this thread, I meant no disrespect toward 
Walter or Andrei or anyone else for the massive amount of excellent work 
that they've done. I just wanted to register a few opinions about 
choices that make the language somewhat less appealing to me.)

Thanks, everybody, for listening. I've read all the replies so far, and 
I have a few other things I'd like to say about strings and arrays and 
whatnot, but this post reflects the entirety of my current thinking 
about const.

--benji smith



More information about the Digitalmars-d mailing list