Hi,
following the discussion on using const, I have written o short doc
about it. See attached file.
I know the idea was to create a wiki page, but it would be better if
this takes the heat on ML first.
jan
Using const qualifier
Variables
Const means that access to that variable won't modify the data represented by
the variable. Constness applies to the type to the left of the const keyword.
If there is none it applies to the one on the right. For simple types types it
means that:
const int foo = 0;
is equivalent to:
int const foo = 0;
you can even use:
const int const foo = 0;
but that does not make much sense.
It gets interesting when const is added to pointer declarations:
const char *foo = "foo" declares variable pointer to constant char data. Thus
this:
const char *foo = "FOO";
foo = "BAR";
is perfectly OK, while
foo[0] = 'B';
produces error: assignment of read-only location ‘*foo’.
The same error:
char const *foo = "FOO";
foo = "BAR";
foo[0] = 'B'; /* error: assignment of read-only location ‘*foo’ */
and even this one:
const char const *foo = "FOO";
foo = "BAR";
foo[0] = 'B'; /* error: assignment of read-only location ‘*foo’ */
Different sitaution is with const pointer to variable data:
char *const foo = "FOO";
foo[0] = 'B'; /* This is OK */
foo = "BAR"; /* error: assignment of read-only variable ‘foo’*/
The basic rule is ALWAYS DECLARE VARIABLES CONST IF YOU DON'T NEED TO MODIFY
THE DATA. This greatly improves readability of the code. If you see a variable
you just need to go to it's declaration (most IDEs know how to do this with one
click/keyboard shortcut), if the variable is const you know its value without
scanning all the code in between. Example:
int init_foo()
{
/* 100+ lines of preparing data */
const int rc = register_new_foo();
if (rc != EOK) {
/* 100+ lines of cleanup */
}
return rc;
}
You don't need to read the cleanup code because it won't modify the return
value.
Even if the cleanup looks something like this:
if (rc != EOK) {
int local_rc = cleanup_x();
if (local_rc != EOK) {
return local_rc;
}
...
local_rc = cleanup_y();
...
return local_rc;
}
Finding returns and going from return line (or any other use) to variable
declaration is fast and easy. It helps if declaration provides as much
information as possible. Using const where possible removes the ambiguity of
variable declarations. It establishes the following rule: const => variable is
not modified in the code, non-const => variable IS modified somewhere in the
code.
Function parameters and return values.
There is no parameter pass/return by reference, all parameters are copies. It
makes little sense declaring them const because they can't be changed by design.
int foo(int bar);
It makes no sense decalring
const int foo_c(const int bar).
There is no way foo can modify what is passed to it.
Return values are only ever read before destruction and storing them to result
variable (or ignoring) so it makes little sense to declare them const.
GCC warns about using const on return values.
DECLARING PARAMETERS AND RETURN VALUES CONST IS OF LITTLE USE.
It exposes function implementation info to the header, but it can be beneficial
in the same way as local variables. If your code (mis)uses parameters as local
variables.
Using pointers is a bit different. It still makes no sense to declare pointer
parameters constant, but USING POINTERS TO CONST DATA IS OF GREAT USE. Example:
int count_something(const struct foo_t *instance);
const struct foo_t *my_foo = get_foo();
const int something_count = count_something(my_foo);
If the data in foo_t changed after a call to this function it's a bug (memory
corruption, ...).
If the data in my_foo are modified after calling:
int count_something_else(struct foo_t *instance);
there is no information. It can be either bug or programmer's brain damage
(modifying data in something named count_*).
It's easy to look for explicit casts when someone needs to modify data
referenced to by const pointer. Therefore:
ALWAYS PASS POINTER TO CONST DATA UNLESS THE FUNCTION ACTUALLY MODIFIES
THE DATA.
There is one problem though: locks and reference counts. If these obects are
part of the structure then even RO access needs to modify parts of the
structure and pointers to const data cannot be used.
_______________________________________________
HelenOS-devel mailing list
[email protected]
http://lists.modry.cz/cgi-bin/listinfo/helenos-devel