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