-preview=in might break code

Mathias LANG geod24 at gmail.com
Fri Oct 2 17:01:43 UTC 2020


> Is there a way to prevent this?

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.
Bear in mind that in D, `const` data can change under your feet. 
The following case is similar to your example:
```
char[16] buffer;
foo(buffer, buffer);
void foo (const(char)[] data, char[] buff);
```
And yet, no one complains that it breaks `const`. The fact that 
`in` sometimes means by value, and sometimes by `ref`, seems to 
be the problem. I think, in our explanation of `in`, we ought to 
phrase things this way: `in` passes by `ref` *unless* it is more 
efficient to pass by value. With the added note that mutating the 
parameter through an indirection should not be relied on.


On Friday, 2 October 2020 at 14:48:18 UTC, Steven Schveighoffer 
wrote:
>
> My problem with it isn't necessarily that it uses references in 
> some cases vs. copies in others, it's that the decision is 
> arbitrary and implementation defined.

Not *quite* arbitrary. It's only passed by value if it's 
relatively efficient to do so. That means that anything that'd 
triggers a copy constructor, dtor, postblit, etc... is guaranteed 
to be passed by `ref`.

> Just noticed too, if you want to *force* ref by using in ref, 
> you get this message:
>
> Error: attribute ref is redundant with previously-applied in
>
> That is... not good.
>
> I think in should always mean ref. If you want to pass not by 
> ref, use const.

This limitation was, I think, the main pain point for people 
during the review.
The main reason for disallowing it is that allowing it would open 
the door for overloading based on `in`, which is *definitely* not 
something we want, since it would mean people relying on by-value 
passing of `in`.
While that was the main reason why I went this way (remember I 
experimented with several designs), there were two additional 
benefits that cemented the conviction that it was the way to go.
First, it creates a nice separation between the three parameters 
storage classes: `in`, `ref`, `out`, hopefully simplifying the 
language and making it easier to explain.
Second, it allowed me to bake in a little trick: When `ref` is 
inferred for `in`, the parameter *actually* mangles as `in ref`. 
The point of doing that was to prevent code compiled with 
different compilers, or version of the same compilers, to link if 
they had a mismatch in their inference rules.

Regarding the "in should always be `ref`", I following Kinke's 
advice here, which seems sensible: it should be up to the ABI to 
decide what is the most efficient way to pass a parameter. But 
there is also a reason why you don't want everything to be `ref`. 
Consider the following two types:
```
alias A = void delegate(in char[]);
alias B = void delegate(const(char)[]);
```
I wanted `A` to be implicitly convertible to `B`, because not 
only does it make sense, but it avoids a lot of the code breakage 
I was seeing in druntime.


More information about the Digitalmars-d mailing list