June 23, 2015
On 6/22/15 4:09 PM, Timon Gehr wrote:
> There is no reason to prevent templates from using the mechanism that
> generates only one copy. The two mechanisms shouldn't share the same
> syntax, because then there is no way to tell them apart for template
> functions.

I understand. For my money I'd be okay with what's being proposed instead of complicating the language yet again for the perfect solution. -- Andrei
June 23, 2015
On Monday, 22 June 2015 at 21:30:45 UTC, Daniel N wrote:
> On Monday, 22 June 2015 at 20:56:12 UTC, Jonathan M Davis wrote:
>> won't mutate the argument, but if you allow it with ref in general, then you stand no chance of being able to look at a function signature and deduce whether the function intends to mutate an argument or not.
>>
>> - Jonathan M Davis
>
> It's no worse than auto ref. It's only by convention that auto ref functions doesn't mutate, at least I follow that convention, but when looking at someone else's function, all bets are off.

No, you can't guarantee that an auto ref parameter won't be mutated, but auto ref clearly indicates that you intend to accept both lvalues and rvalues, meaning that it would be stupid to be writing the function with the idea that you would be passing in an argument which would be mutated. ref on the other hand clearly indicates the intention to mutate the argument.

- Jonathan M Davis
June 23, 2015
On Tuesday, 23 June 2015 at 01:07:17 UTC, Jonathan M Davis wrote:
> No, you can't guarantee that an auto ref parameter won't be mutated, but auto ref clearly indicates that you intend to accept both lvalues and rvalues, meaning that it would be stupid to be writing the function with the idea that you would be passing in an argument which would be mutated. ref on the other hand clearly indicates the intention to mutate the argument.
>
> - Jonathan M Davis

That is why, as a good API designer, you'd express that fact by adding const ontop of it, i.e. const ref.

Only for the few rare cases where you need to account for lazy-caching or similar mutating constructs, you'd be grateful to have the nice escape hatch, plain ref.

Daniel N

June 23, 2015
On Tuesday, 23 June 2015 at 01:01:26 UTC, Andrei Alexandrescu wrote:
> On 6/22/15 4:09 PM, Timon Gehr wrote:
>> There is no reason to prevent templates from using the mechanism that
>> generates only one copy. The two mechanisms shouldn't share the same
>> syntax, because then there is no way to tell them apart for template
>> functions.
>
> I understand. For my money I'd be okay with what's being proposed instead of complicating the language yet again for the perfect solution. -- Andrei

There is no perfect solution. :) Some are for in/scope ref, some are against it. Some are for auto ref, some are against it and even a few are for const ref but most are against it. So the perfect solution does not exist. And since scope/in ref was already rejected (DIP 36) I think auto ref is the only choice to introduce this feature without introducing a new attribute. And since you reverted the introducing of virtual because it has not enough value, I'm sure that introducing a new attribute just to accept both, lvalues and rvalues, wouldn't have enough value as well. I think the way it is implemented right now is good enough, but what matters is what you and Walter think.
June 23, 2015
On Monday, 22 June 2015 at 18:10:11 UTC, Andrei Alexandrescu wrote:
> On 6/22/15 9:54 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm@gmx.net>" wrote:
>> `auto ref` without a working `scope` implementation is unsafe.
>
> I'm unclear on this. With the existence of the return attribute, what's unsafe about auto ref? -- Andrei

DIP25 _is_ a working `scope` implementation, for that matter, albeit incomplete. (Strictly speaking, it's not the `return` attribute that makes it safe, but the fact that under this proposal `ref` implies what `scope` was originally supposed to mean.)

You're right that if DIP25 is all we'll ever get (i.e. the `scope` keyword will never have any meaning), then `auto ref` might not be so bad a choice, although it still leaves the fact that it does something different for template and non-template functions. But it would create other inconsistencies with other kinds of references, e.g.

    void bar(ref MyStruct s);
    void foo(MyClass c);

    void baz() {
        MyStruct s;
        Scoped!MyClass c;
        bar(s); // safe
        foo(c); // not safe, reference may escape
    }

For consistency, I would much prefer if `ref` and scope-ness were kept independent, because they are orthogonal concepts. Why should one kind of reference imply `scope`, but not others?
June 23, 2015
On Monday, 22 June 2015 at 23:43:07 UTC, Timon Gehr wrote:
> The problems with transitive const to be encountered in day-to-day C++ work are few.

Trolling as always. You know what I meant. Haven't had to resort to mutable fields and/or const_casts in a long time. Mostly a matter of good design imho.

As different behavior for templated `auto ref` and non-template `auto ref` seems to be an issue for more people here, why don't just rename the non-templated one `scope ref`, so that it's usable for templates too and also enables the `in ref` shortcut for const? I find `const auto ref` extremely clumsy.
June 23, 2015
On Monday, 22 June 2015 at 19:05:28 UTC, kinke wrote:
> On Monday, 22 June 2015 at 16:54:50 UTC, Marc Schütz wrote:
>> With the difference that C++ requires const-ness.
>
> Yep, so `in ref T` translating to `scope const ref T` would be D's convenient and safe counterpart to C++' `const T&` parameters, for their main use case: passing pure-input arguments of types which are or may be costly to copy (post-blit ctor, dtor, or simply big). I explicitly mention 'may be' here because in templates one often doesn't know (containers...).

To clarify: What I meant by my comment was that const-ness should not be a precondition for allowing rvalue refs. Mutable rvalue refs are fine.

>
> As I have already pointed out in another thread, I'd go one step further and propose an extremely convenient `in T` for this very common use case:
>
> * The argument is passed by value (`const T`) if the compiler assumes moving/copying is more efficient than passing a reference (with its indirection on the callee side) for the particular target environment (hardware, ABI), e.g., for plain-old-datatypes T fitting into 1-2 registers, and Object references obviously.
> * Otherwise, the argument is passed by-ref (`in ref T`). As `in T` doesn't mention any ref at all, it's clear that the hidden reference cannot escape.

Theoretically, `immutable ref` by itself would already allow these semantics (without the `scope` that `in` implies). Because (disregarding identity/addresses) for an immutable object there is no observable difference between pass-by-value and pass-by-reference. The same is not always true for `const ref`, whenever aliasing is possible:

    void foo(const ref int a, ref int b) {
        int x = a;
        b++;
        assert(x == a); // can fail if both refer to the same variable
        // similar with global variables
    }

To guarantee this from the caller's POV, the callee must be pure and the parameters must be known not to alias each other.
June 23, 2015
On Tuesday, 23 June 2015 at 06:49:50 UTC, Daniel N wrote:
> On Tuesday, 23 June 2015 at 01:07:17 UTC, Jonathan M Davis wrote:
>> No, you can't guarantee that an auto ref parameter won't be mutated, but auto ref clearly indicates that you intend to accept both lvalues and rvalues, meaning that it would be stupid to be writing the function with the idea that you would be passing in an argument which would be mutated. ref on the other hand clearly indicates the intention to mutate the argument.
>>
>> - Jonathan M Davis
>
> That is why, as a good API designer, you'd express that fact by adding const ontop of it, i.e. const ref.

Which does not generally work in D. It can in some cases, but const is so restrictive in D that you simply cannot use it just because you don't intend to mutate a variable. Too many types won't work with const, and many types _can't_ work with const. const has its uses, but you have to be careful with it, and in the general case, that means that you can't put it on function parameters just to indicate that the function argument is not going to mutated.

- Jonathan M Davis

June 23, 2015
On Tuesday, 23 June 2015 at 09:57:26 UTC, Marc Schütz wrote:
> On Monday, 22 June 2015 at 19:05:28 UTC, kinke wrote:
> [...]
> To clarify: What I meant by my comment was that const-ness should not be a precondition for allowing rvalue refs. Mutable rvalue refs are fine.

I know and see it the same way.

>> As I have already pointed out in another thread, I'd go one step further and propose an extremely convenient `in T` for this very common use case:
>>
>> * The argument is passed by value (`const T`) if the compiler assumes moving/copying is more efficient than passing a reference (with its indirection on the callee side) for the particular target environment (hardware, ABI), e.g., for plain-old-datatypes T fitting into 1-2 registers, and Object references obviously.
>> * Otherwise, the argument is passed by-ref (`in ref T`). As `in T` doesn't mention any ref at all, it's clear that the hidden reference cannot escape.
>
> Theoretically, `immutable ref` by itself would already allow these semantics (without the `scope` that `in` implies). Because (disregarding identity/addresses) for an immutable object there is no observable difference between pass-by-value and pass-by-reference. The same is not always true for `const ref`, whenever aliasing is possible:
>
>     void foo(const ref int a, ref int b) {
>         int x = a;
>         b++;
>         assert(x == a); // can fail if both refer to the same variable
>         // similar with global variables
>     }
>
> To guarantee this from the caller's POV, the callee must be pure and the parameters must be known not to alias each other.

This is obviously true. Rvalues aren't affected as they cannot alias another parameter by definition. Lvalues are if passed by ref and the same instance is accessible by mutable ref from another parameter or global. But as shown by your example, that danger is always there. The proposed `in` semantics make it less obvious, that's true, but I still think it'd be worth it, as these aliasing bugs are a pain to track down, but in my experience extremely rare.
June 23, 2015
On Tuesday, 23 June 2015 at 11:03:10 UTC, Jonathan M Davis wrote:
> Which does not generally work in D. It can in some cases, but const is so restrictive in D that you simply cannot use it just because you don't intend to mutate a variable. Too many types won't work with const, and many types _can't_ work with const. const has its uses, but you have to be careful with it, and in the general case, that means that you can't put it on function parameters just to indicate that the function argument is not going to mutated.
>
> - Jonathan M Davis

Thus the solution cannot require const.

auto is worse because, if you later decide you need to add a template parameter then the meaning is changed and you get a _hidden_ performance issue.

Thus requiring neither auto nor const is the least evil of the above.

You could always use comments, or even dummy aliases to make the code self-documenting:

alias view(T...) = T;
void example(ref view!int i) {}