Thread overview
ref and out parameters on call site
Mar 18, 2020
WebFreak001
Mar 18, 2020
Paul Backus
Mar 30, 2020
WebFreak001
March 18, 2020
I would like to bring it up yet again! (I think this is my 3rd time talking about it lol)

Can we get make the call site of a ref/out function repeat the ref/out keyword like in C#?

Example:
void foo(double a, ref string s, out int[] x);

called with:
foo(doubleValue, ref stringValue, out intArray);

My basic idea was this:
* Force usage of ref/out on call site, otherwise cause deprecation for now.
* If function is called with UFCS, ref is not needed on first argument (before the .)


Reason:
It's currently impossible to know if a function argument mutates a variable or not without jumping into the definition or documentation. Code reviews get orders of magnitude more difficult to get right when calling new functions you aren't familiar with.

I think this would massively help readability and simplify static analysis and code reviews. This also has the added benefit that you can easily unambiguously call both ref and non-ref overloads using an lvalue. It also makes it possible to _require_ functions like template callbacks to have a ref/out parameter.

If we were to go this way, we could go all the way and even allow const/immutable construction out of "out" arguments:

if (generateSomething(out const something)) {
    writeln("yay, something: ", something);
}

Any ideas? Counter arguments why this shouldn't be implemented other than old code breakage?
March 18, 2020
On Wednesday, 18 March 2020 at 17:23:26 UTC, WebFreak001 wrote:
> Any ideas? Counter arguments why this shouldn't be implemented other than old code breakage?

How would `auto ref` and core.lifetime.forward work with this?
March 30, 2020
On Wednesday, 18 March 2020 at 17:46:22 UTC, Paul Backus wrote:
> On Wednesday, 18 March 2020 at 17:23:26 UTC, WebFreak001 wrote:
>> Any ideas? Counter arguments why this shouldn't be implemented other than old code breakage?
>
> How would `auto ref` and core.lifetime.forward work with this?

forward kind of seems like magic with alias right now, so it will probably either break permanently or need to be reimplemented. However I think having more control would be worth a lot.

Current behavior:
class C
{
    static int foo(int n) { return 1; }
    static int foo(ref int n) { return 2; }
}

// with forward
int bar()(auto ref int x) { return C.foo(forward!x); }

// without forward
int baz()(auto ref int x) { return C.foo(x); }

int i;
assert(bar(1) == 1);
assert(bar(i) == 2);

assert(baz(1) == 2);
assert(baz(i) == 2);

New behavior:
assert(bar(1) == 1);
assert(bar(i) == 1);
assert(bar(ref i) == 2); // <- needs implementation somehow though

assert(baz(1) == 1);
assert(baz(i) == 1);
assert(baz(ref i) == 1);

however you can now define
int foo()(auto ref int x) { return C.foo(ref x); }
assert(foo(1) == 2);
assert(foo(i) == 2);
assert(foo(ref i) == 2);