Thread overview
Constructor qualifiers; bug or expected behavior?
Apr 02, 2018
RazvanN
Apr 02, 2018
Eduard Staniloiu
Apr 02, 2018
Seb
Apr 02, 2018
H. S. Teoh
April 02, 2018
Hi all,

Let's say we have this code:

struct B
{
    int a;
    this(int a) immutable
    {
        this.a = 7;
    }

    this(int a)
    {
        this.a = 10;
    }
}

void main()
{
    B a = immutable B(2);
    writeln(a.a);
    a.a = 4;

    immutable B a2 = immutable B(3);
    writeln(a2.a);
    a2.a = 3;        // error : cannot modify
}

Both a and a2 will be constructed using the immutable constructor, however a is not immutable (a.a = 4 will compile fine). Is this the intended behavior? Shouldn't the compiler warn me that I'm trying to create a mutable object using the constructor for an immutable object? I couldn't find any documentation about this.


April 02, 2018
On Monday, 2 April 2018 at 10:26:32 UTC, RazvanN wrote:
> Hi all,
>
> Let's say we have this code:
>
> struct B
> {
>     int a;
>     this(int a) immutable
>     {
>         this.a = 7;
>     }
>
>     this(int a)
>     {
>         this.a = 10;
>     }
> }
>
> void main()
> {
>     B a = immutable B(2);
>     writeln(a.a);
>     a.a = 4;
>type `B`
>     immutable B a2 = immutable B(3);
>     writeln(a2.a);
>     a2.a = 3;        // error : cannot modify
> }
>
> Both a and a2 will be constructed using the immutable constructor, however a is not immutable (a.a = 4 will compile fine). Is this the intended behavior? Shouldn't the compiler warn me that I'm trying to create a mutable object using the constructor for an immutable object? I couldn't find any documentation about this.

The compiler does an implicit conversion from the type `immutable B`
to the type `B`. It is able to do safely do so because `struct B` has only
value types that can be copied.

The same thing happens for
    immutable x = 1;
    int y = x;

If you add an indirection in `struct B`, as such

struct B
{
    int a;
    int* p;
    /* ... */
}

Then you can see that the implicit conversion fails with
"onlineapp.d(22): Error: cannot implicitly convert expression B(0, null).this(2) of type immutable(B) to B"

I put the code at
https://run.dlang.io/gist/83756973012fcb4fec2660a39ffdad90&args=-unittest?args=-unittest

The same conversion rules that apply to built in qualified types applies to structs. I'm guessing the same is for classes but I haven't played that much with those so a second opinion would be nice :)

Cheers,
Edi
April 02, 2018
On Monday, 2 April 2018 at 11:41:55 UTC, Eduard Staniloiu wrote:
> On Monday, 2 April 2018 at 10:26:32 UTC, RazvanN wrote:
>> [...]
>
> The compiler does an implicit conversion from the type `immutable B`
> to the type `B`. It is able to do safely do so because `struct B` has only
> value types that can be copied.
>
> The same thing happens for
>     immutable x = 1;
>     int y = x;
>
> If you add an indirection in `struct B`, as such
>
> struct B
> {
>     int a;
>     int* p;
>     /* ... */
> }
>
> Then you can see that the implicit conversion fails with
> "onlineapp.d(22): Error: cannot implicitly convert expression B(0, null).this(2) of type immutable(B) to B"
>
> I put the code at
> https://run.dlang.io/gist/83756973012fcb4fec2660a39ffdad90&args=-unittest?args=-unittest
>
> The same conversion rules that apply to built in qualified types applies to structs. I'm guessing the same is for classes but I haven't played that much with those so a second opinion would be nice :)
>
> Cheers,
> Edi

FYI sth. seems to have gone wrong with the current migration to authenticated Gists.
Sorry about the inconvenience, the hotfix is already in the deploy queue and for this - the exported URL should have been:

https://run.dlang.io/gist/83756973012fcb4fec2660a39ffdad90?args=-unittest
April 02, 2018
On Mon, Apr 02, 2018 at 10:26:32AM +0000, RazvanN via Digitalmars-d-learn wrote:
> Hi all,
> 
> Let's say we have this code:
> 
> struct B
> {
>     int a;
>     this(int a) immutable
>     {
>         this.a = 7;
>     }
> 
>     this(int a)
>     {
>         this.a = 10;
>     }
> }
> 
> void main()
> {
>     B a = immutable B(2);
>     writeln(a.a);
>     a.a = 4;
> 
>     immutable B a2 = immutable B(3);
>     writeln(a2.a);
>     a2.a = 3;        // error : cannot modify
> }
> 
> Both a and a2 will be constructed using the immutable constructor,
> however a is not immutable (a.a = 4 will compile fine). Is this the
> intended behavior?
> Shouldn't the compiler warn me that I'm trying to create a mutable
> object using the constructor for an immutable object? I couldn't find
> any documentation about this.

What's happening here is that B is a value type, meaning that assignment makes a copy of the object. Since B has no fields that contain indirections, when a copy of B is made, it is completely independent of the original immutable object, so it's perfectly fine to make the copy mutable.


T

-- 
Meat: euphemism for dead animal. -- Flora