On Sat, 18 Sep 2010 05:15:38 -0400, Jonathan M Davis <jmdavisp...@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