-preview=in might break code

Iain Buclaw ibuclaw at gdcproject.org
Sun Oct 4 14:19:41 UTC 2020


On Saturday, 3 October 2020 at 05:02:36 UTC, Andrei Alexandrescu 
wrote:
> On 10/2/20 6:11 PM, Walter Bright wrote:
>> On 10/2/2020 10:31 AM, Steven Schveighoffer wrote:
>>> And this might not be true on a different compiler.
>> 
>> This is looking like a serious problem.
>
> They say one should choose one's fights wisely, so I spent some 
> time
> pondering. I could just let this thread scroll by and not think 
> twice
> about it. By next week, I may as well forget.
>
> But then I realized this is /exactly/ the kind of crap that 
> we'll all
> scratch our heads six months from now, "How did this ever pass 
> review?

I take offense to that.  I'd prefer if you'd moderate your tone 
please.

> Who approved this? How in the world did a group of competent,
> well-intended people, looked at this and said - yep, good idea. 
> Let's."
>
> ???
>

*You* approved it.

https://github.com/dlang/dmd/pull/11000#issuecomment-675605193


> This glib take is EXTREMELY concerning:
>
>> In the general case, no. You can have two distinct pointers 
>> with the
>> same value, and there's nothing the frontend can do to detect 
>> it.
>> 
>> This scenario has been brought up during the review. I doubt 
>> it will,
>> in practice, be an issue though. This is not a common pattern, 
>> nor
>> does it seems useful. It rather looks like a code smell.
>
> Wait a SECOND! Are we really in the market of developing and 
> deploying language features that come unglued at the slightest 
> and subtlest misuse? We most certainly shouldn't.
>
> I sincerely congratulated Mathias and the other participants 
> for working on this. It's an important topic. Knowing that all 
> those involved are very good at what they do, and without 
> having looked closely, I was sure they got something really 
> nice going that avoids this absolutely blatant semantic 
> grenade. And now I see this is exactly it - we got a -preview 
> of a grenade. How is this possible? How can we sleep at night 
> now?
>
> Again: take a step back and reconsider, why did this pass 
> muster?
>
> This is important, folks. It's really important as parameter 
> passing goes to the core of what the virtual machine does. You 
> can't say, meh, let's just fudge it here, and whatever is 
> surprising it's on the user.
>
> Please, we really need to put back the toothpaste in the tube 
> here. I could on everybody's clear head here to reconsider this.

Frankly, I think you are making a mountain out of a molehill 
here.  You are imagining a problem that doesn't exist; and if one 
does find an issue, the fault lies with the DMD compiler and not 
the D language specification.  Though evidently having clearer 
wording in the spec benefits all.

If you read nothing more of this reply, at least finish up until 
the end of this paragraph.  Please hold fire until GDC and LDC 
have implemented this feature, then we can discuss the pitfalls 
that we've encountered with it.  Basing decisions on behaviors 
observed with DMD is not the right approach, and if you are 
currently finding the situation to be a mess, it is a mess of 
DMD's own doing.

Plucking a fitting example from a Phobos unittest that 
demonstrates the kind of things DMD let's people get away with:
```
RefCounted!int* p;
{
     auto rc1 = RefCounted!int(5);
     p = &rc1;
     assert(rc1 == 5);
     assert(rc1._refCounted._store._count == 1);
     auto rc2 = rc1;
     assert(rc1._refCounted._store._count == 2);
}
assert(p._refCounted._store == null);
```
Why is this not a compile-time error?  DMD just isn't punishing 
users enough for the buggy code they've written.

- - -

I don't really have the heart to go through and unpick all points 
raised in this thread, but I think it's worth sharing the three 
key conclusions I took away from reviewing the pull request:

1. This is behind a -preview flag, and so should be treated as 
experimental.  Nothing breaks by having it there.  Nothing breaks 
if it were to be suddenly removed without any deprecation cycle.

2. Aliasing was raised multiple times throughout the review, I 
even gave this example at time to demonstrate my concerns:
```
void bar(in int a, out int b) { }
int a = 42;
bar(a, a);
```
But ultimately, worrying about this is missing the point, as the 
problem is already present in the compiler even without 
`-preview=in`, and Walter is working on fixing it.  In the 
meantime, these sorts of cases are relatively trivial to pick up 
and can be added as warnings in GDC and LDC until the front-end 
implements the semantic guarantees.

3. There is no danger of ref/non-ref mismatches in ABI, because 
`in` parameters that are inferred `ref` are going to be passed in 
memory anyway.

In the following:
```
alias A = void delegate(in long);
alias B = void delegate(const long);
```
Either `long` always gets passed in memory, or always gets passed 
in registers, in both cases, they are always going to be 
covariant.  The same remains true whatever type you replace 
`long` with.

The one place where `in` parameters start to get interesting is 
rather at the call site.  I think it is best illustrated with the 
following:
```
struct Foo { this(this); }
void fun1(const Foo f) { }
void fun2(in Foo f) { }
```
The compiler already ensures that non-trivially copy-able types 
never end up in a situation where a temporary is needed.  So 
`Foo` is always passed by ref, otherwise there'd be a double copy 
done at the call site.

So once again, both are covariant as far as the callee is 
concerned.  But in the case of `fun2`, the caller does something 
different.  The copy constructor is elided entirely, and that is 
the crux of the optimization that is at play here.  If you've 
assumed anything else, you're assumptions are sorely misplaced.

- - -

I've also skimmed past a passing concern that the ABI between 
compilers would be different.  Well, let me rest assure you that 
DMD, GDC and LDC have never been compatible in the first place, 
so there's no point worrying about that now.  Though DMD is 
really the one at fault for all incompatibilities by choosing to 
have a non-standard calling convention for extern(D) code...


More information about the Digitalmars-d mailing list