Error: cannot implicitly convert expression (this) of type const(S) to S

Steven Schveighoffer schveiguy at yahoo.com
Sat Sep 18 09:58:15 PDT 2010


On Sat, 18 Sep 2010 05:15:38 -0400, Jonathan M Davis <jmdavisProg at gmx.com>  
wrote:

> Okay, if I try and compile the following program.
>
> struct S
> {
>     @property S save() const
>     {
>         return this;
>     }
>
>     int[] _val;
> }
>
> void main()
> {
> }
>
>
> I get the error message
>
> d.d(5): Error: cannot implicitly convert expression (this) of type  
> const(S) to S

Yes, because you are converting "this" from a const(S) to an S to return  
it.

Try:

@property const(S) save() const
{
    return this;
}

>
> If I remove const from save(), then it works, but with const there, it  
> doesn't.
> If I change _val to int or a struct type which does not contain an  
> array, it
> works. If I change _val to a struct type which has a member variable  
> which is an
> array, it doesn't work.

Because arrays are reference types.

You can implicitly convert a const(int) to an int because it's not a  
reference type.  But you can't implicitly convert a const(int *) to an int  
* because it's a reference type.

That axiom of implicit conversion is propagated to structs as well -- if a  
struct has only value types, then it can be implicitly converted,  
reference types cannot.

I'll give you an example of why your version should not work.  Let's say  
it *did* compile, then this function is allowed to violate const:

void foo(const(S) s)
{
    S s2 = s.save;
    s2._val[0]++;
    assert(s2._val[0] == s._val[0]); // oops, I modified s._val[0], but s  
is const!
}

> From the looks of it, there's something about having an array as a member
> variable which makes this blow up. Perhaps it has to do with the fact  
> that _val
> is a reference type and would be shared? Do I need to declare a postplit
> constructor to fix this? Declaring one doesn't seem to help, but maybe I  
> just
> don't know how to declare them correctly.

In reality, you cannot make save const, unless you want to do a deep copy  
(but I recommend against that, save should be a quick operation).

The solution is actually inout.  With inout, you can assert that save does  
not modify the data, but that it doesn't alter the constancy of the actual  
type.

@property inout(S) save() inout
{
   return this;
}

Should work for S, const(S) and immutable(S).

However, inout doesn't work at all right now.  Please vote for bug  
http://d.puremagic.com/issues/show_bug.cgi?id=3748 (oh wait, you already  
did, but others should too :)

-Steve


More information about the Digitalmars-d-learn mailing list