difficulties with const structs and alias this / template functions

Stanislav Blinov stanislav.blinov at gmail.com
Mon Nov 19 13:34:50 UTC 2018


On Monday, 19 November 2018 at 12:28:43 UTC, Dennis wrote:
> On Monday, 19 November 2018 at 02:39:32 UTC, Stanislav Blinov 
> wrote:
>> You're skimming the examples ;)
>
> I'm not saying your examples don't work, I'm trying to 
> understand the minimum requirements. You said:
>
> "That's [constructors needing to be pure is] only for types 
> with indirections (pointers), since `pure` guarantees that you 
> do not mutate any global state."
>
> My example was only to show that:
> - a const constructor is insufficient for creating an immutable 
> struct S
> - an immutable or pure constructor is sufficient for creating 
> an immutable struct S

Yes, that's what I meant.

> You also showed that an inout constructor is sufficient too.
>
> I don't understand why not any constructor would work. After 
> all:
>
> "value types are all copyable between mutable/const/immutable. 
> So even if `return x + y` would yield a `const T`, you can 
> still instantiate a T from it."

Because the rules still hold:

this(int) -> __ctor(T, int);
this(int) const -> __ctor(const T, int);
this(int) immutable -> __ctor(immutable T, int);

>> Recall that member functions (including constructors) are just 
>> functions in disguise:
>> ...
>> what that boils down to, conceptually, is:
>
> I get what inout does know. But continuing on the constructor 
> lowering, what strikes me is that:
>
> S __ctor(ref const S this, int x) {
>     this.x = x; // allowed, while `this` is a const(S)!
>     // return this; automatically inserted
> }
>
> Knowing that a constructor may mutate the const(this) or 
> immutable(this) members, why can't a mutable(this) constructor 
> be called on an immutable(this), *unless* it is pure (which 
> seems irrelevant to me)?

Because it's not mutation, it's initialization. Just like you 
write:

const int x = 1; // initializes a const int
x = 10; // error, can't mutate

...the first assignment to a member in a constructor is 
initialization:

struct S {
     int x;
     this(int x) immutable {
         this.x = x; // ok, initialization
         this.x = 5; // error, can't mutate
     }
}

When a ctor is `pure`, the compiler knows it doesn't mutate any 
state other than the object's, so it allows conversion to all 
three qualifiers.

What you can do, however, if you don't have an const/immutable 
constructor, is call a mutable constructor explicitly, so long as 
conversion is possible (i.e. value types):

struct S {
     this(int) /* not immutable */ {}
}

immutable S x = 1; // error
immutable S x = S(1); // ok


More information about the Digitalmars-d-learn mailing list