Why can't I init a new var from const var?

ag0aep6g via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sat Feb 11 17:08:02 PST 2017


On 02/12/2017 12:15 AM, Random D user wrote:
> I can init a variable from mutable source without defining any
> constructor or assignment operators, but not if the source is const. I
> would imagine the behavior to be the same with mutable and const source,
> since it's just reading the source and copying it.

It works as long as your type has no mutable indirections (pointers, 
array, class objects). You can't just copy an indirection from const to 
mutable, because the referenced (possibly immutable) data would be 
incorrectly typed as mutable.

> Is there a reason for this? Or is this a bug?
> I can workaround this by making copies or casting, that just creates
> ugly code everywhere.
>
> Here's an example (with dmd 2.073):
>
> struct Foo
> {
[...]
>     this( const Foo source )
>     {
>         buf = source.buf.dup;
>     }
[...]
>     char[] buf;
> }
>
> Foo fun(const ref Foo foo, Foo foo2)
> {
>     Foo bar  = foo;                     // Error: cannot implicitly
> convert expression (foo) of type const(Foo) to Foo

Initializations like this don't call the constructor. Instead, they do 
"copy construction" and call a "postblit function" if it's defined.

See https://dlang.org/spec/struct.html#struct-postblit

So, if you want to call a function whenever your struct gets copied, you 
define a postblit function. Like so: this(this) { buf = buf.dup; }

Or if you want to do the dup-ing in specific places only, call the 
constructor explicitly: Foo bar = Foo(foo);

>     Foo baz  = foo2;                    // Ok, No need for constructors
> or opAssign

Note that this does not call the constructor, and does not do the dup. 
If you want this to do the dup, postblit is the way.

[...]
>     //Foo bar = Foo(foo);     // This works provided there is non-const
> opAssign defined.
>     //Foo bar = cast(Foo)foo; // This seems to work as well

I wouldn't have expected the cast to call the constructor, but 
apparently it does. It's in the spec here:

https://dlang.org/spec/expression.html#CastExpression

"Casting a value v to a struct S, when value is not a struct of the same 
type, is equivalent to: S(v)"

So a cast like that is really just a fancy way of calling the constructor.

This seems a bit inconsistent, though. On postblit the spec says that 
copy construction happens with "the same type". The compiler apparently 
sees Foo and const(Foo) as the "same type" in that context. But with the 
cast, the qualifier mismatch is enough to trigger the constructor call 
which is supposed to happen when the types are not the same.

>     return bar;
> }
>
> Foo foo;
> foo = fun(foo, foo);



More information about the Digitalmars-d-learn mailing list