On Fri, 19 Mar 2010 20:58:21 -0400, Paul D. Anderson <paul.d.removet...@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

Reply via email to