On 04/04/2018 12:37 PM, Steven Schveighoffer wrote:
With structs, we have the possibility of initialization via different
mechanisms: constructor, postblit, .init. All of these are supported by
the struct member, but currently you can only invoke postblit if you are
in a postblit. And only at the beginning. I would like to see more
flexibility for copying.
For structs, using .init is a valid initialization, so it's completely
different from classes, where a constructor MUST be invoked. Indeed,
there is no mechanism to require calling struct member constructors in
the owner's ctor.
To paraphrase your point: We should be able to initialize a member with
.init or by calling its constructor (over .init). We should not be
forced to initialize it with its postblit.
Makes sense. But I see one tricky case: Can I also choose to use the
blitted value of the member without calling its postblit? I'd say that
can't be allowed.
So the compiler would have to identify that case and reject it. And now
we're in uncharted territory. As far as I see, this is not something
that constructors do (struct or class). They happily accept any .init
value. But postblits can't accept any blitted value. So we can't say:
"Just do what constructors do." We have to come up with new rules.
But we don't want to come up with new rules, we want to say: "Just do
what constructors do." So we require the member postblit, and we say
that the outer postblit operates on the resulting value like a
constructor operates on .init.
And then we see that it breaks the type system, and that any analog
behavior of constructors just means that constructors/.init are broken, too.
x = 42; /* First write. */
s = S(13); /* Second write. Breaking immutable? */
Of course this doesn't compile, because s is considered immutable by
It doesn't compile, because this(this) is a broken mess currently.
The first write doesn't compile either. Obviously, with a properly
implemented immutable this(this), you would at least be allowed to write
With mutable(!) `this(this)`s, both writes are accepted.
What I was saying is that we can't allow postblit to modify data
that has already been postblitted, because of the reason this example is
Still, I'd like to have a more explosive example. The breakage here is
very localized, and could possibly be defined away somehow. Like:
"Unique immutable data is considered 'raw' in constructors and postblit
functions. That means, the data can be mutated. Only when the
constructor/postblit returns does it become 'cooked' and truly immutable."
I don't think you should be able to write to the same field multiple
times in an immutable/const constructor. If so, that's a bug.
Are you counting .init as a write, or is a constructor allowed to build
int x = 1;
int y = 3;
this(int dummy) immutable
writeln(x); /* 1 */
++x; /* Breaking immutable? */
writeln(x); /* 2 */
++y; /* Breaking immutable even though y hasn't been printed
writeln(y); /* 4 */
auto s = immutable S(0);
I think those increments could be considered breaking immutable. Maybe
they must be.
If this were to be outlawed, I'd agree a constructors and postblits are