October 04, 2020
On Sunday, 4 October 2020 at 20:06:49 UTC, Iain Buclaw wrote:
> If I'd be pressed to bullet point it, I'd put down the following.
>
> When an parameter is annotation with `in`:
> - The parameter is not modifiable.
> - All memory reachable from the parameter can not be clobbered (overwritten).
> - The parameter does not escape.
> - Copy constructors are elided by passing by-ref.
> - Other forms of copy elision may occur if doing so does not change program behaviour.
>
> Is that simple enough for an end-user?

I think that's a pretty good summary, although I'd loosen point 2 to the object itself, not all memory reachable from it.

The main problem people seem to be focusing on in this thread is point 2, the aliasing issue. Firstly, I think people need to realize `-preview=in` is absolutely not about being compatible to previous semantics, but about entirely new semantics for `in`. Secondly, as the potential aliasing problem regards the callers, not the callee, a simple rule of thumb should be something along the lines of: "If you wouldn't pass the lvalue arg to a `const scope ref` parameter due to aliasing concerns, then don't pass it to `in` either without an explicit copy."
October 04, 2020
As for the callee, the only significant change OTOH (except for non-PODs not getting copy-constructed/postblitted and destructed) would be that it cannot make any assumptions about the address of an `in` param (but there's `traits(isRef)` in the presumably extremely rare cases one needs to know whether it was passed by ref or value):

void foo(T)(in T a, in T b)
{
    assert(&a != &b);
}

void test(T)()
{
    T x;
    foo(x, x);
}

void main()
{
    test!int(); // succeeds - the tiny int is passed as 2 distinct values
    test!(int[64])(); // fails - the same large array is passed by ref
}

---

Once a program conforms to these new semantics, especially wrt. to aliasing as mentioned earlier, the compiler- and target-specific implementation details and differences don't matter.
October 04, 2020
On 10/3/2020 7:08 AM, kinke wrote:
> The idea is that `in` is explicit, and users of a function with `in` params should think of such params as `const T& __restrict__` in C++ terms, which should clarify the potential aliasing problem. Whether the thing is optimized to pass-by-value then shouldn't make any observable difference for the caller.

__restrict__ is a C feature only and never made it into the C++ Standard. I implemented it as a no-op in Digital Mars C. The reason is because it relaxes the rules on what optimizations can be performed in ways that can subtly break code. Very, very few C programmers understand exactly what is going on with it, and sensibly avoid it.

If such a user uses __restrict__ with a compiler that ignores it, then uses mine that enforces it and breaks his code, what happens is that *I* get the blame. I can quote the Standard to him all day, but he'll inevitably say "it works with Microsoft C, it doesn't work with yours, you are wrong." I know this because I've had these conversations with customers that relied on bugs in Microsoft C. It's hopeless, so I implement Microsoft C's bugs.

The problem with __restrict__ is that the C compiler is fundamentally incapable of detecting buggy uses of it at compile time. Whether those bugs exhibit at runtime or not is implementation-defined. It's not a surprise that the C++ Standard did not adopt it.

`in` is a nice, friendly looking construct. It looks like pass-by-value, which we're all familiar with, and in fact we've trained users to regard it as pass-by-value because that's the existing behavior for 20 years. Changing its behavior so it *may* introduce memory corruption in very un-obvious and un-checkable ways is a very serious problem.
October 04, 2020
On Sunday, 4 October 2020 at 21:45:03 UTC, Walter Bright wrote:
> The problem with __restrict__ is that the C compiler is fundamentally incapable of detecting buggy uses of it at compile time. Whether those bugs exhibit at runtime or not is implementation-defined. It's not a surprise that the C++ Standard did not adopt it.

And yet all major C++ compilers support it one way or another (AFAIK, just for more aggressive optimizations though, no need to check for overlaps).

Anyway, I probably shouldn't have brought up __restrict__ - simply because every D dev should already know about aliasing pitfalls wrt. regular refs:

int foo(const ref int a, ref int b)
{
    b = 123;
    return a;
}

void main()
{
    int a = 0;
    assert(foo(a, a) == 0); // oops, aliasing
}

> `in` is a nice, friendly looking construct. It looks like pass-by-value, which we're all familiar with, and in fact we've trained users to regard it as pass-by-value because that's the existing behavior for 20 years. Changing its behavior so it *may* introduce memory corruption in very un-obvious and un-checkable ways is a very serious problem.

I've been unhappy about the wasted potential for `in` ever since working on the ABI details of LDC, and new `-preview=in` is something I've wanted for years. Again, the aliasing issue should be quite easily avoided by imagining `in` params as `const scope ref` at the call sites. For those who find that too complicated, well, just don't opt into the preview feature. We'll see how the adoption goes.
October 04, 2020
On Sunday, 4 October 2020 at 21:45:03 UTC, Walter Bright wrote:
> `in` is a nice, friendly looking construct. It looks like pass-by-value

Only because it used to be by-value as you've pointed out. :) - From a tabula rasa syntax standpoint, possibly-by-ref `in` IMO fits nicely as sort-of counterpart to by-ref `out`. Changing it to `in ref` would IMO be too verbose, still slightly confusing (not always a ref - but that'd be in line with `auto ref`... :]) and `in` alone (as `const scope`) wouldn't make much sense anymore, except for backwards-compatibility.
October 04, 2020
On Sunday, 4 October 2020 at 20:42:17 UTC, kinke wrote:
> On Sunday, 4 October 2020 at 20:06:49 UTC, Iain Buclaw wrote:
> `in`. Secondly, as the potential aliasing problem regards the callers, not the callee, a simple rule of thumb should be something along the lines of: "If you wouldn't pass the lvalue arg to a `const scope ref` parameter due to aliasing concerns, then don't pass it to `in` either without an explicit

You need to know the implementation as parameters can alias with globals accessed by the function. So not caller only.

The docs should list everything you need to be mindful of in order to get consistent behaviour from any compliant compiler.
October 04, 2020
On Sunday, 4 October 2020 at 23:06:58 UTC, Ola Fosheim Grøstad wrote:
> You need to know the implementation as parameters can alias with globals accessed by the function. So not caller only.

As-is with all refs today:

struct S { int a; }

int* p;

int foo(const scope ref S s)
{
    *p = 123;
    return s.a;
}

void main()
{
    S s;
    p = &s.a;
    assert(foo(s) == 0); // oops
}
October 04, 2020
On Sunday, 4 October 2020 at 23:17:03 UTC, kinke wrote:
> On Sunday, 4 October 2020 at 23:06:58 UTC, Ola Fosheim Grøstad wrote:
>> You need to know the implementation as parameters can alias with globals accessed by the function. So not caller only.
>
> As-is with all refs today:

The context for that statement was that value/ref is implementation dependent.

Steven also gave another example related to type testing.

All such anomalities should be listed.
October 04, 2020
On Sunday, 4 October 2020 at 22:53:49 UTC, kinke wrote:
> On Sunday, 4 October 2020 at 21:45:03 UTC, Walter Bright wrote:
>> `in` is a nice, friendly looking construct. It looks like pass-by-value
>
> Only because it used to be by-value as you've pointed out. :)

ref gives it away.

October 04, 2020
On Sunday, 4 October 2020 at 23:31:03 UTC, Ola Fosheim Grøstad wrote:
> The context for that statement was that value/ref is implementation dependent.

It might help some if compilers would run unit tests 3 times with different 'in' implementations.

1 mixed value/ref
2 value
3 ref