Initializing an Immutable Field with Magic: The "Fake Placement New" Technique

ag0aep6g anonymous at example.com
Fri Jul 26 12:12:19 UTC 2019


On 26.07.19 13:14, FeepingCreature wrote:
> On Friday, 26 July 2019 at 10:53:32 UTC, ag0aep6g wrote:
>> My point is that you can't do either. You can't mutate immutable data. 
>> Doesn't matter whether you try it with a `cast` or with `__ctor`. Both 
>> ways are not allowed.
> 
> Sure you can. Look at the link, you're doing it :)

What you can do is write invalid programs that seem to behave as you 
want. But they're invalid. They might explode any time.

> More specific, immutable is kind of awkward. You have to differentiate 
> between immutable types and immutable memory. Those are *often* the 
> same, but not always.

As far as I understand, they're the same to the language. Consequently, 
they're the same to me. D doesn't have C++'s const where it matters how 
the data was declared originally.

> The thing you cannot do is mutate memory that was *allocated* immutable 
> - ie. that came out of new T or T() where T was marked immutable, or had 
> immutable fields. But that doesn't happen with immutable fields inside a 
> union, because unions screen off all that stuff; they can't not, because 
> immutable fields and mutable fields may freely overlap. So instead of 
> forbidding mutable-immutable overlap in unions, the language basically 
> just throws up its hands and goes "yeah, whatever."

Do we have it in the spec somewhere that unions defeat immutable? I'm 
skeptical if that can be sound.

As far as I know, we usually say that this function:

     void f(immutable int* p)
     {
         /* ... do something with *p ... */
         g();
         /* ... do more stuff with *p ... */
     }

can assume that `*p` is the same before and after calling `g`. But if 
unions have the power to defeat immutable, that assumption is invalid.

Or maybe we can only use that super power of unions if we take care that 
no other code can observe what we're doing? Can that be specified 
without undermining the assumption above?

> So when you're switching a tagged union to an immutable member, you're 
> not dealing with "immutable memory", you're, effectively, dealing with 
> an uninitialized field. And you can always set an uninitialized field to 
> a new value, whether it's immutable or not, because that's *how the 
> constructor hack works in the first place*. If abusing a constructor 
> like this was broken, the constructor would *itself* be broken.

That might make sense, but it's at odds with the current spec and 
implementation. If an immutable union field is considered uninitialized 
until written to, then the language should forbid accessing it before 
that (in @safe code). We can't have `immutable` data change its 
observable value.


More information about the Digitalmars-d mailing list