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