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