April 15

On Monday, 15 April 2024 at 16:24:51 UTC, Steven Schveighoffer wrote:

>

This seems like an unnecessary restriction.

It's necessary to prevent the creation of dangling stack pointers, since a ref can be bound to a stack variable.

>
  1. DIP 1000 already allows such lifetime forwarding:
void foo(ref int x)
{
    // ref int y = x;
    // return y;
    // same as:
    ref int bar(ref int x2) {
        return x2;
    }
    return bar(x);
}

When you fix foo's return type to be ref int, you get:

>

Error: returning bar(x) escapes a reference to parameter x

April 15

On Monday, 15 April 2024 at 17:20:59 UTC, Dennis wrote:

>

On Monday, 15 April 2024 at 16:24:51 UTC, Steven Schveighoffer wrote:

>

This seems like an unnecessary restriction.

It's necessary to prevent the creation of dangling stack pointers, since a ref can be bound to a stack variable.

Yes, so you don't allow returning the ref in that case? It is trivial to know what a ref is bound to at compile time.

>

When you fix foo's return type to be ref int, you get:

>

Error: returning bar(x) escapes a reference to parameter x

Yes, I forgot to update the message after I fixed the return type in my test, but it compiled for me. I forgot to add @safe as well, I always forget that when testing dip1000.

But also, returning x is disallowed in this case.

You also have to add return to the parameter, and then it compiles.

For reference, the edited code which compiles is:

@safe ref int foo(return ref int x)
{
    // ref int y = x;
    // return y;
    // same as:
    ref int bar(ref int x2) {
        return x2;
    }
    return bar(x);
}

-Steve

April 15

On Monday, 15 April 2024 at 19:21:55 UTC, Steven Schveighoffer wrote:

>

You also have to add return to the parameter, and then it compiles.

For reference, the edited code which compiles is:

@safe ref int foo(return ref int x)
{
    // ref int y = x;
    // return y;
    // same as:
    ref int bar(ref int x2) {
        return x2;
    }
    return bar(x);
}

-Steve

why not

ref int bar(return ref int x2)

is it inferred for nested functions?

April 16

On Monday, 15 April 2024 at 19:21:55 UTC, Steven Schveighoffer wrote:

>

For reference, the edited code which compiles is:

@safe ref int foo(return ref int x)
{
    // ref int y = x;
    // return y;
    // same as:
    ref int bar(ref int x2) {
        return x2;
    }
    return bar(x);
}

-Steve

This also answers your original question. You can't do

@safe ref int fun
    (return ref int a, return ref int b, return ref int c)
{   // ...
    ref int x = b;
    // ...
    return x;
}

...because it uses the same lifetime checks scope uses, and you can't do

@safe int* fun
    (return ref int a, return ref int b, return ref int c)
{   // ...
    scope int* x = &b;
    // ...
    return x;
}

either. In the second example there is a good reason for the limitation, as x could later be assigned to point to a local instead.

It could work though. Either refs and immutable/const scope pointers that don't refer to non-return scope could be made returnable, or we could allow return ref/return scope/ref return scope/return ref scope for local variables too, the rule being that return references can be assigned return references with longer lifetime, but not non-return local references.

April 17

On Friday, 12 April 2024 at 20:43:50 UTC, Walter Bright wrote:

>

https://github.com/WalterBright/documents/blob/984374ca885e1cb10c2667cf872aebc13b4c1663/varRef.md

Ref variables would be useful for refactoring. E.g. to disallow foreach over an array with a non-const ref index - related to:
https://issues.dlang.org/show_bug.cgi?id=24499

foreach (ref i, ref e; array) {
    // code that modifies `i`, causing skipped/repeated elements of foreach

Rewrite to:

for (size_t i; i < array.length; i++) {
    ref e = array[i];
    // code that modifies `i`, which is now less surprising

Currently you'd have to write ref e() => array[i];, which is less intuitive and is not the same if array is reassigned between calls to e.

April 18
On 17/04/2024 9:20 PM, Nick Treleaven wrote:
> On Friday, 12 April 2024 at 20:43:50 UTC, Walter Bright wrote:
>> https://github.com/WalterBright/documents/blob/984374ca885e1cb10c2667cf872aebc13b4c1663/varRef.md
> 
> Ref variables would be useful for refactoring. E.g. to disallow foreach over an array with a non-const `ref` index - related to:
> https://issues.dlang.org/show_bug.cgi?id=24499
> 
> ```d
> foreach (ref i, ref e; array) {
>      // code that modifies `i`, causing skipped/repeated elements of foreach
> ```
> Rewrite to:
> ```d
> for (size_t i; i < array.length; i++) {
>      ref e = array[i];
>      // code that modifies `i`, which is now less surprising
> ```
> 
> Currently you'd have to write `ref e() => array[i];`, which is less intuitive and is not the same if `array` is reassigned between calls to `e`.

Currently the DIP only shows aliasing of variables, expressions like the above do not appear to be supported.

April 17

On Wednesday, 17 April 2024 at 14:07:04 UTC, Richard (Rikki) Andrew Cattermole wrote:

>

Currently the DIP only shows aliasing of variables, expressions like the above do not appear to be supported.

If that was the case this DIP would be completely useless, as you could already do everything it enabled with alias.

I'm sure the intended restriction is the same as with ref function parameters: the expression must be an lvalue.

April 17

On Wednesday, 17 April 2024 at 14:29:17 UTC, Dukc wrote:

>

If that was the case this DIP would be completely useless, as you could already do everything it enabled with alias.

I currently sometimes use pointers to alias members.

// Inside struct LightOptimizer
void moveLightGlobal()
{
    auto light = &this.scene.light;
    light.pos += vec3(...);
}

void onMouseclick(ref GameState gs)
{
    auto ui = &gs.ui;
    ui.startDrag();
    ...
}

I'd prefer using ref since that's safer and enables opIndex overloads, so this DIP seems like a nice addition to me. I tried replacing those cases with alias but it errors:

Error: accessing non-static variable `scene` requires an instance of `LightOptimizer`
April 18

On Wednesday, 17 April 2024 at 16:51:41 UTC, Dennis wrote:

>

On Wednesday, 17 April 2024 at 14:29:17 UTC, Dukc wrote:

>

If that was the case this DIP would be completely useless, as you could already do everything it enabled with alias.

I currently sometimes use pointers to alias members.

[...]

>

I'd prefer using ref since that's safer and enables opIndex overloads, so this DIP seems like a nice addition to me. I tried replacing those cases with alias but it errors:

This isn't particularly hard to do with library code:

struct Ref(T)
{
    T* ptr;

    ref inout(T) deref() inout
    {
        return *ptr;
    }
    alias deref this;
}

Ref!T byRef(T)(return ref T lvalue)
{
    return Ref!T(&lvalue);
}

// Example usage:

struct Light
{
    double pos;
}

struct Scene
{
    Light light;
}

struct LightOptimizer
{
    Scene scene;

    void moveLightGlobal()
    {
        auto light = this.scene.light.byRef;
        light.pos += 1.0;
    }
}
April 19

On Wednesday, 17 April 2024 at 14:29:17 UTC, Dukc wrote:

>

On Wednesday, 17 April 2024 at 14:07:04 UTC, Richard (Rikki) Andrew Cattermole wrote:

>

Currently the DIP only shows aliasing of variables, expressions like the above do not appear to be supported.

If that was the case this DIP would be completely useless, as you could already do everything it enabled with alias.

I'm sure the intended restriction is the same as with ref function parameters: the expression must be an lvalue.

The behaviour could perhaps be defined as follows - if this would compile:

(ref p) { CODE }(lvalue);

Then, with some restrictions on CODE, you can write:

ref p = lvalue;
CODE

And the effects will be equivalent. CODE cannot contain return statements or __traits(parameters), __traits(parent), is(T PS == __parameters) expressions. Have I missed anything else?