Confused about const

Steven Schveighoffer schveiguy at yahoo.com
Fri Mar 19 20:17:14 PDT 2010


On Fri, 19 Mar 2010 20:58:21 -0400, Paul D. Anderson  
<paul.d.removethis at comcast.andthis.net> wrote:

> I created a struct, call it "S", and some functions that operate on S.  
> But I'm confused about when const is useful.
>
> Being an old Java programmer, I use 'const' the same as I used 'final'  
> in Java. So most of my functions look like this:
>
> S for(const S a, const S b) {
>     S x = a;
>     S y = b;
>     // do some stuff
>     return a;
> }
>
> I declare the parameters const and then copy them to work on them.
>
> I get error messages about not implicitly casting const S to S. So I can  
> make an explicit cast:
>
>     S x = cast(S) a;
>     S y = cast(S) b;
>
> and the error messages go away.
>
> But I think I must have gone off the rails somewhere -- all I want is  
> for the caller to be sure the function doesn't alter a and b. But I end  
> up with lots of casts to/from const. What am I missing??


I'll try to help, const is a very complex thing to understand.  However,  
what it provides is so valuable for interface design that it is worth  
learning.

One thing to remember that const is transitive.  This means that if S  
contains a pointer to something, you have to treat that pointer as if it  
were const too.  This is a difference from Java's final.

If S has a pointer or reference, then a const S cannot be copied to a  
mutable S because you can then change the data through the mutable  
reference without any casts.  I'll give you an example:

struct S
{
   int *a;
}

void foo(const(S) s)
{
    S s2 = s; // this fails to compile because of the possibility for the  
next line.
    *s2.a = 5; // I now just changed the value pointed to by s, which is  
const data!
}

However, if S does not have a pointer or reference, then you can copy a  
const S to a mutable one because then changing the mutable S does not  
affect the const data in the original S.

example:

struct S
{
    int a;
}

void foo(const(S) s)
{
    S s2 = s; // this compiles
    s2.a = 5; // does not change s at all.
}

In answer to your question, what you are missing is what const is for.   
When declaring a function takes a const item, you are declaring that that  
function will not change the argument *or* anything it references.  The  
compiler is trying to enforce that.  Casting away const breaks the  
compiler guarantees, so you should not do that unless you know what you  
are doing.  So what I think is if you want to change the elements of S, or  
return an S parameter that is not const, then you shouldn't declare them  
as const parameters.

One final thing -- there is a brand new feature for D2 that allows you to  
forward the const attributes of parameters to return values.  This is  
under the heading "inout functions" of the documentation.  This feature is  
not implemented properly, even in the latest compiler.  However, once it  
does work, you can use it to declare your function like this:

inout(S) foo(inout(S) a, inout(S) b)
{
    return a;
}

What this means is, during the foo function, it will not modify a or b,  
but once it returns, the return value has the same constancy as the  
parameters.  It basically means "the const you put in is the const you get  
out."

-Steve


More information about the Digitalmars-d-learn mailing list