That said, let it be known that I struggle with one of the C language's simplest constructs, the const keyword.
Sure, I know the const keyword. I know its syntax and meaning. I know some of its peculiarities, such as that the declaration char const * * const foo declares foo to be a mutable array of immutable C strings and that foo itself is immutable. I know that the const keyword trips up a lot of intermediate-level C developers when it's mixed with pointers. I'm not one of those people.
Like I said, I see C programs as patterns, and here lies my problem with the const keyword; I don't understand how it best fits into a program's pattern. Here's an example.
This is an example of a function, foo_copy, that takes an object of type foo_t and creates and returns a copy of the object. The question is: should the function argument be of type foo_t const * or foo_t *? To const or not to const?struct foo;
typedef struct foo foo_t;
foo_t *foo_copy(foo_t const *src);
In most cases, adding the const keyword provides a pleasant safeguard, both for the function foo_copy itself as well as its callers (and their callers and so on). Calling functions can be assured that the state of the object pointed to by src will not change. And we expect that its state won't change.
But there is at least one case in which the object's state should change, and that is when the object is not actually copied but is instead reference-copied. Take the following implementation of foo_copy.
This will generate a compiler error, though the spirit of the function is correct. The developer then has two options: one, to remove the const keyword from the argument specification and two, to add a const-removing cast to the offending line like so: ((foo_t *) src)->ref_cnt++. The first option potentially breaks existing code that expects the function's const-ness. The second option is impure and, I would argue, more dangerous than goto, both in principal and in practice.foo_t *foo_copy(foo_t const *src)
{
assert(src != NULL);
src->ref_cnt++;
return src;
}
This example exposes a fundamental problem with the const keyword, which is that the keyword breaks the barrier between interface and implementation. Const poses as a keyword that denotes interface, but it is actually a keyword that specifies, in part, implementation. It transforms, however slightly, a black box into a gray box.
I want to discard the const keyword and avoid it in my function prototypes, but the problem with that is that const does have its value. Like assert, it cannot guard against all faults but it can catch some of them, and it does so without increasing size or hindering performance. But languages such as Java do not have const. Historically, I have believed this to be a deficiency in those languages, but now I wonder whether those languages' designers well understood const's deficiencies and saw the construct as a dangerous (though well meant) crutch and decided to take that crutch away from their developers.
Only one thing about the matter is certain to me: I am a C expert, not a C master.
2 comments:
Grasshopper,
I see part of your problem.
You keep trying to spell foot like this foo_t. There is no underscore in this word.
The other part of your problemis there are not enough *. const is a diva try ****** and maybe there will be paparazzi as well as improved performance.
--See Master Extrodinare
ps Today my verification word is bingstai, what is its definintion?
IMHO
C++ distinction of a const/non-const method/arguments/variables express disrespect to the concept of interfaces. C++ spec. does not mention it is 'programming by interface'[which I would call collaboration by interface]. Same is the case with Java Collection Interface API where they could have separated non & non-const interfaces and didn't.
Post a Comment