Const correctness revisited (proposal)
Oliver Dathe
o.dathe at gmx.de
Sun Mar 23 19:53:35 PDT 2008
Hello D folks,
I'd like to introduce some suggestions for D2:
1.) Enforceable immutability of function calls regarding parameters
2.) Parameter related tail constness
3.) Enforceable tail constness on calls
In thread [1] the problem was stated, what a clean D2 version of a
function may look like, that returns a mutable slice from an input
string which (the input string) may not be mutable by the function
itself. There were no really clean solutions avoiding casts and
templates. Therefore I'd like to suggest to think about how to force
constness/immutability of functions and calls regarding parameters.
Proposals:
1.) Enforceable immutability of function calls regarding parameters
I'd like to suggest that, at the time we call a function, we may be able
to force some overlay constness regarding the parameters. e.g.
char[] foo(char[] source, char[] pattern) {} // example of Steven [1]
char[] x = "some input";
char[] y = foo(const x, "somepattern"); // (1) note the const
(1) The const means we want foo() to not mutate this parameter (with the
respective transitivity to underlying calls which take x as parameter).
If there is no version of foo() that could meet this requirement (at
least implicitly), it is an error. Note that the typeof(source) remains
plain char[] here.
Ok, usually if the creator knew he does not want to mutate a parameter
he would declared it as const. But, there may be several reasons not to
do so: a.) D1 b.) if he wants to return a mutable char[] slice of source
he has to cast away the const which is not desirable in general.
Having parameter source be of type char[] gives us the opportunity to
return a mutable slice without casting away constness. Calling foo(const
x, ...); gives us the opportinity to ensure that x is not mutable by
foo() while already having typeof(source)==char[].
You may also want to take some void d1function(char[] x); and call it
e.g. with some const(char)[] argument, which may then internally be
translated to casting away the constness but forcing immutability of x
in d1function().
Now let us extend this to a more general scheme:
2.) Parameter related tail const correctness
If we think of how to bring this kind of overlay constness to the
function declaration, we may come up with adding a tail constness
regarding parameters:
char[] bar(char[] a const, int b) {...} // (2)
(2) bar() is forced to be compilable if parameter a virtually was const
char[] but the actual typeof(a) remains char[]. If bar() tries to mutate
parameter a, that would be an error.
This also implies that if bar() calls foo(x,...) the call internally
would force this overlay constness in foo() regarding x (transitive), so
the call silently becomes foo(const x,...); behind the scenes.
Advantages of parameter related tail constness:
a.) It is some sort of injected, transparent and transient overlay
constness only regarding the functions scope.
b.) Usual advantages with const correctness like detecting accidental
mutation but you may already stick with the basic types.
c.) As expressive to the reader as if the parameter type was constified
but it just stays basic.
d.) You may stick with the easygoing D1 typing style, but you get the
opportunity to let a 'silent const guard' work for you behind the scenes.
e.) It just naturally extends the tail constness concept from 'this' to
parameters.
f.) May encourage SafeD [3][4]
g.) Compiler/Optimizer may already deduce this attribute?
h.) No different bytecode version
Recall Stevens problem [1] is solved with either
char[] foo(char[] input const; char[] pattern){...}// at declaration
// or
char[] mutableslice = foo(const x; "mypattern"); // at function call
// or both
3.) Enforceable tail constness on calls
Try to force the call to be immutable regarding their respective object.
The call must either be explicitly tail const [2] or implicitly by not
mutating the object.
z = obj.foo(x,y) const; // (3)
z = obj.foo(x,y) invariant; // (4)
func("input") invariant; // (5)
(3) Forces foo() to be explicitly or implicitly tail const. If that is
not possible it is an error.
(4) and (5) world-immutability. See [2]
[1]
http://www.digitalmars.com/d/archives/digitalmars/D/const_debacle_68011.html
[2] http://s3.amazonaws.com/dconf2007/WalterAndrei.pdf p.29
[3]
http://www.digitalmars.com/d/archives/digitalmars/D/Memory_Safety_68031.html
[4] http://www.digitalmars.com/d/2.0/safed.html
-Oliver
More information about the Digitalmars-d
mailing list