Deprecating this(this)

Steven Schveighoffer schveiguy at yahoo.com
Wed Apr 4 10:37:57 UTC 2018


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


More information about the Digitalmars-d mailing list