On 4/3/18 5:44 PM, ag0aep6g wrote:
On 04/03/2018 10:51 PM, Steven Schveighoffer wrote:
On 4/3/18 4:26 PM, ag0aep6g wrote:
[...]
If there's a problem with running two postblits on the same field, then I think constructors probably have similar issue. I'm having a hard time finding a good example, though. One where we could break immutable in an obvious way or some such.

You may NOT want to run a postblit on the member. If all you are going to do, for example, is reassign a variable, then running the postblit, and then the destructor, just so you can overwrite it is pointless.

Same with class constructors: You may not want to run `super` when you're just going to overwrite what it did. But the language doesn't give you a choice. It'll be called one way or another.

At least you can invoke the one you want, with postblit there is only one "choice".

But this is a red herring -- we already have struct constructors, and that requirement of invoking constructors on members is not present.

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.

I'm not saying that imitating how constructors work will make the best possible copying mechanism. Something else might be superior in every way. It's just that so far the arguments against a constructor-like postblit also seem to apply to constructors as they are implemented.

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.

Stop thinking class constructors, and think struct constructors instead.

But more importantly, if the postblit of the member does something crazy like stores a reference to itself as an immutable elsewhere, and then the compiler allows overwriting, we now have problems.

I'd love to see an example of this in code. The best I can come up with would be something like this (doesn't compile):

----
import std.stdio;

immutable(int)* p;

struct S
{
     int x;
     this(this) immutable
     {
         x = 42; /* First write. */
         .p = &this.x;
         writeln(p, " ", *p); /* Prints some address and 42. */
     }
}

struct T
{
     S s;
     this(this) immutable
     {
         s = S(13); /* Second write. Breaking immutable? */

Of course this doesn't compile, because s is considered immutable by now. 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 showing.

         writeln(p, " ", *p); /* Same address, but 13. */
     }
}

void main()
{
     immutable T foo;
     immutable bar = foo;
}
----

But that's essentially the same as the class example I posted. `*p` would only change values during the postblit run. Just like a constructor chain can write to the same field multiple times.

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.

That's kinda iffy, but I can't find a way to demonstrate some real, obvious damage.

Any place where an immutable can be observed to change between two reads is breaking immutable.

-Steve

Reply via email to