[DIP idea] out variables
12345swordy
alexanderheistermann at gmail.com
Tue Jan 26 02:44:20 UTC 2021
On Tuesday, 26 January 2021 at 01:01:54 UTC, Q. Schroll wrote:
> Main goal: Make the `out` parameter storage class live up to
> promises.
> In current semantics, `out` is basically `ref` but with
> documented intent. The initialization of the parameter is more
> like a detail.
>
> General Idea
> ============
>
> The idea of an out variable is one that **must** be passed to a
> function in an `out` parameter position. Basic example:
>
> int f(out int value);
> int g(int[] value...);
> int h(out int a, out int b);
>
> out int x;
> // g(x); // illegal: reads x, but x is not yet initialized.
> // h(x, x); // illegal:
> // reads the second x before the initialization of
> first x is complete.
> f(x); // initializes x.
>
> An `out` variable cannot be read until initialized by a
> function call in an `out` parameter position. Since D has exact
> evaluation order, it is easily determined that one usage of `x`
> initializes it and another in the same overall expression reads
> it (and not the other way around):
>
> out int x, y;
> /*1*/ if (h(x, y) > 0 && x < y) { .. }
> /*2*/ g(f(x), f(y), x, y);
>
> Evaluation order says in /*1*/ that h(x, y) is executed before
> x and y are read for testing `x < y`.
> Evaluation order says in /*2*/ that f(x) and f(y) are executed
> before x and y are read for passing them to g.
>
> Also, multiple execution paths can lead to different
> initialization points:
>
> out int x, y, z;
> if (g(0)) { f(x); f(y); f(z); } else h(x, y);
> // x, y are initialized.
> g(x, y); // okay: x and y initialized on both branches
> g(z); // invalid: z might not be initialized.
>
> It is always possible to initialize `out` variables using an
> ordinary assignment:
>
> out int x, y, z;
> if (g(0)) { /*as above*/ } else { h(x, y); z = 0; }
> g(z); // valid: z initialized on both branches
>
>
> Templates
> =========
>
> Similar to `ref`, there will be `auto out` which infers `out`
> based on the arguments passed. `auto out` can be combined with
> `ref` (meaning pass by reference always, but if the argument is
> an out value, this is its initialization) and `auto ref`
> (meaning pass by reference if possible, and if the argument is
> an out value, this is its initialization; it cannot be passed
> by value and be initialized).
>
> With __traits(isOut, param) one can test whether `auto out`
> boiled down to `out` or not.
>
> After being (potentially|definitely|?) initialized, `out`
> variables do not trigger `auto out` to become `out`.
>
>
> In-place `out` Variables
> ========================
>
> When calling a function with an `out` parameter, instead of
> passing an argument, a fresh variable can be declared instead:
>
> if (f(out int x) > 0 && x > 0) { g(x); } else { .. }
> if (g(0) && f(out x) > 0) { g(x); } else { .. }
>
> The type of an in-place out variable can be left out, when it
> can be inferred from the called function. [Clearly it can be
> done in some cases and clearly it cannot be in all templates.
> Exact rules TBD.]
> In the first else branch, `x` can be used, since regardless
> whether the `f(out int x) > 0 && x > 0` is true or false,
> evaluating it will initialize `x`.
> In the second else branch, `x` cannot be used because `x` might
> not be initialized if g(0) is false.
> The visibility of in-place out variables is limited to the
> statement they're declared in. For `if` statements this
> encompasses both branches, but for expression statements, it
> only encompasses that expression:
>
> x = f(out a) + a; // valid
> y = f(out b);
> // y += b; // error, b not visible
> out int c;
> f(c);
> z += c; // valid
>
> One obvious use-case is functions that return a bool value
> indicating success and the result is an `out` parameter.
> Usually, these functions' names begin with try:
>
> if (tryParseInt(str, out x)) { use(x); }
>
> Another could be unpacking:
>
> out T x;
> out S y;
> tuple.unpack(x, y);
> // or
> if (tuple.unpack(out a, out b) && condition(a, b)) { .. }
>
> What do you think? Worth it?
in, out, inout need some badly reworking to do. Their is a
preview for in, but not for others sadly.
-Alex
More information about the Digitalmars-d
mailing list