Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend visibility of ref condition variables to an else branch #20823

Open
Bolpat opened this issue Feb 5, 2025 · 2 comments
Open

Extend visibility of ref condition variables to an else branch #20823

Bolpat opened this issue Feb 5, 2025 · 2 comments

Comments

@Bolpat
Copy link
Contributor

Bolpat commented Feb 5, 2025

Current behavior:

if (auto x = …)
{
    // `x` visible
}
else
{
    // `x` not defined
}

That makes sense insofar as x is something that evaluated to false which usually narrows its range to a single value, so one replace any use of x with 0, false, or null. While not true for user-defined types (which can have an opCast!bool that returns false for non-trivial values), it’s still “morally correct” because any opCast!bool that returns false should indicate a trivial value.

With ref variables, the rationale does not apply. While the referenced value may be trivial, the reference itself isn’t. Assigning it in the else branch is meaningful and should be possible.

ref Object f();

if (ref q = f())
{ }
else
{
    q = new Object(); // error: undefined identifier `q`
}

Open questions:

  • Also extend by-value if variables (for consistency)? (IMO, no)
  • Always extend auto ref variables (for consistency) or only if they’re ref? (IMO, yes)

Note that extending by-value if variables to the else branch is a breaking change, as a local variable declared there may have the same name.

@Bolpat Bolpat changed the title Extend visibility of if variables to else branch if they’re `ref´ Extend visibility of if variables to else branch if they’re ref Feb 5, 2025
@Bolpat Bolpat changed the title Extend visibility of if variables to else branch if they’re ref Extend visibility of ref condition variables to an else branch Feb 5, 2025
@ntrel
Copy link
Contributor

ntrel commented Feb 7, 2025

  1. That would make scoping depend on whether ref is used. I think scoping should always be very clear.
  2. Why not declare ref q above the if statement?

@Bolpat
Copy link
Contributor Author

Bolpat commented Feb 7, 2025

1. That would make scoping depend on whether ref is used. I think scoping should always be very clear.

Yes, intentionally so. IMO, it’s clear insofar as if (ref) simply has different scoping rules than if (auto) because there are reasons why this is pragmatically useful. To me, it’s similar to how static if and if have different scoping rules, too. You have a token that informs you. What I’m not a fan of is different scoping rules for if (auto ref) depending on whether the auto ref becomes ref or not. That would really qualify for “scoping should always be very clear.” Here, I’d say auto ref is the same as ref when it comes to the scope of the variable extending into the else branch.

Thinking practically, when one writes code, I fail to see how it would be a problem. The scoping rules make sense intuitively because why would you want to access an if (auto) variable in the else branch and why would you not want to be able to access an if (ref) variable in the else branch?

I’m not even against extending the scope of an if (auto) variable to the else branch per se, but it would be a breaking change: Currently, you can declare a variable with the same name in the else branch which would be shadowed if the scope were extended (and shadowing locals isn’t allowed in D).

void main()
{
    if (int y = 0) { }
    else { int y = 0; }
}

The only issue I can imagine (and I’ve never seen a forum post about it) is that the current scoping rules make it so in the else branch, if you mention the if (auto) variable, it is simply not in scope, which usually leads to an error, but only because no eponymous symbol with the same name is in scope (usually). If one is, you refer to that one.

int y;
void main()
{
    if (int y = 0) { }
    else { y = 10; }
    assert(.y == 10);
}

Maybe that shouldn’t be allowed (see #20835).

2. Why not declare ref q above the if statement?

Because then, the scope of the variable extends beyond the if statement and would possibly require an additional block to keep the variable’s scope the same. That is needed if another, similar if follows that uses the same variable:

// My suggestion: Stuff just works
void main()
{
    if (ref x = f()) { … } else { x = 1; }
    if (ref x = g()) { … } else { x = 1; }
}
// Your suggestion: Pleasing the compiler
void main()
{
    { ref x = f(); if (x) { … } else { x = 1; } }
    { ref x = g(); if (x) { … } else { x = 1; } }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants