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

Ali Çehreli via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sat Feb 11 16:54:37 PST 2017


On 02/11/2017 03:15 PM, 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.
 >
 > 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.

Just to make sure, you don't need to define all those overloads. This is 
sufficient but you have to use a different (and idiomatic construction 
syntax.):

struct Foo
{
     this( const(Foo) source )
     {
         buf = source.buf.dup;
     }

     void opAssign( const(Foo) source )
     {
         buf = source.buf.dup;
     }

     char[] buf;
}

Foo fun(const ref Foo foo, Foo foo2)
{
     auto bar = Foo(foo);
     // Foo bar  = foo;                     // Error: cannot implicitly 
convert expression (foo) of type const(Foo) to Foo
     Foo baz  = foo2;                    // Ok, No need for constructors 
or opAssign
     auto baz2 = const(Foo)(foo2);
     Foo bar2;
     bar2     = foo;                     // uses opAssing( const Foo ) / 
opAssign( const ref Foo )
     Foo bar3;
     bar3     = foo2;                    // uses opAssign( const Foo ) / 
opAssign( Foo )
     Foo bar4;
     bar4     = cast(const Foo)foo2;     // uses opAssing( const Foo )

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

void main() {
}

When you do this:

     Foo bar = foo;

There is an implicit conversion in place, which D does not allow during 
construction. The idiomatic syntax is the following:

     auto bar = Foo(foo);

The construction on the right-hand side is now explicit.

Likewise, prefer the following syntax:

     auto baz2 = const(Foo)(foo2);

Notes:

When you want to treat lvalue sources differently from rvalue sources, 
you can define the following overloads as well (note const(Foo) syntax, 
which is preferred):

     this( ref const(Foo) source )
     {
         buf = source.buf.dup;
     }

     void opAssign( ref const(Foo) source )
     {
         buf = source.buf.dup;
     }

Alternatively, you can define an 'auto ref' function that automatically 
takes both lvalues and rvalues (lvalue by-ref, rvalues by-move). Note 
the empty template parentheses:

struct Foo
{
     this()( auto ref const(Foo) source )
     {
         buf = source.buf.dup;
     }

     void opAssign()( auto ref const(Foo) source )
     {
         buf = source.buf.dup;
     }

     char[] buf;
}

Ali



More information about the Digitalmars-d-learn mailing list