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

[Proposal]: Inline variable declaration and discarding for ref parameters #4355

Open
1 of 4 tasks
tkurucsai opened this issue Jan 23, 2021 · 11 comments
Open
1 of 4 tasks

Comments

@tkurucsai
Copy link

tkurucsai commented Jan 23, 2021

Inline variable declaration and discarding for ref parameters

  • Proposed
  • Prototype: Not Started
  • Implementation: Not Started
  • Specification: Not Started

Summary

Similar to inline variable declarations and discarding results for out parameters (out var x, out _), the language should support declaring variables and discarding results when passing ref parameters as well.

Motivation

It would be nice to have the same features we already have for out:

  • To be able to declare such variables inline.
  • To be able to declare such variables in the scope of a conditional.
  • To be able to get rid of unused variables which are only used to be passed as ref parameters but the returned value is ignored.

Detailed design

Syntax

If you'd like to declare the variable when passing it as a ref parameter:
ref <type> x = <in-value>
or
ref var x = <in-value>

If you have to pass a ref parameter but you don't care about the return value:
ref _ = <in-value>

Semantics

Apart from the mandatory initialization, the compiler should threat those exactly like the inline variable declarations for out parameters.

Example

void ChangeSomething(Something something, ref bool changed) { ... }
ChangeSomething(sg, ref var hasChanged = false)
ChangeSomething(sg, ref _ = false)

Drawbacks

It is something nice to have but not really essential, so maybe this is not a good allocation of development resources.

Alternatives

Declare a variable before the function call.

Unresolved questions

None at the moment

Design meetings

@333fred
Copy link
Member

333fred commented Jan 23, 2021

We've talked about this type of thing before, though I'm not finding the discussion/issue immediately. The problem is that it violates definite assignment rules. out variables are not allowed to be accessed until the callee sets the variable to a value. ref variables do not have such a restriction: they can be accessed before assignment in the callee, which violates C#'s rules that variables must be assigned a value before access.

@tkurucsai
Copy link
Author

ref [...] can be accessed before assignment in the callee, which violates C#'s rules that variables must be assigned a value before access.

This is why in my proposal the initial assignment is mandatory in the argument list of the function call.

@333fred
Copy link
Member

333fred commented Jan 23, 2021

Ah, I missed that. Your proposed syntax is in conflict with #338, and imo it just looks like a lambda declaration in general. I'm personally not a huge fan of the idea: I think adding the ability to declare and assign a variable inline like that is likely to be more confusing than it's worth, particularly given that I've only ever needed this type of pattern once or twice myself. out _ is a common occurrence, but I find that ref _ is generally a sign that I've just made a bug.

@tkurucsai
Copy link
Author

Ah, I missed that. Your proposed syntax is in conflict with #338, and imo it just looks like a lambda declaration in general. I'm personally not a huge fan of the idea: I think adding the ability to declare and assign a variable inline like that is likely to be more confusing than it's worth, particularly given that I've only ever needed this type of pattern once or twice myself. out _ is a common occurrence, but I find that ref _ is generally a sign that I've just made a bug.

You're right: I've updated the proposal to use = instead of => during initialization to resolve the conflict (and it also looks like initialization now :))

Consider the following use cases:
void MingleOrMangle(ref T x) {
  if (Mingle(ref var y = x)) x = y; else Mangle(ref x);
}
void MangleUnlessCanBeMingled(ref T x) {
  if (!Mingle(ref _ = x)) Mangle(ref x);
}

@333fred
Copy link
Member

333fred commented Jan 23, 2021

Consider the following use cases:
void MingleOrMangle(ref T x) {
  if (Mingle(ref var y = x)) x = y; else Mangle(ref x);
}
void MangleUnlessCanBeMingled(ref T x) {
  if (!Mingle(ref _ = x)) Mangle(ref x);
}

I dunno, looks to me like you've just introduced a bug. If x can be mingled, you haven't updated it.

@tkurucsai
Copy link
Author

Consider the following use cases:
void MingleOrMangle(ref T x) {
if (Mingle(ref var y = x)) x = y; else Mangle(ref x);
}
void MangleUnlessCanBeMingled(ref T x) {
if (!Mingle(ref _ = x)) Mangle(ref x);
}

I dunno, looks to me like you've just introduced a bug. If x can be mingled, you haven't updated it.

That is exactly the use case, that's why the function is called 'mangle unless can be mingled' and not 'mangle unless mingled'.

@CyrusNajmabadi
Copy link
Member

CyrusNajmabadi commented Jan 23, 2021

Nothing about that example looks like something is want fwiw. It seems super unclear, and i think it's not a good idea to have tihs.

@HaloFour
Copy link
Contributor

It would kind of be nice if C# officially supported optional ref parameters rather than it being a feature only permitted in COM interop scenarios.

@RikkiGibson
Copy link
Contributor

The compiler has tons of code that looks like this:

HashSet<DiagnosticInfo>? useSiteDiagnostics = null;
DoSomething(..., ref useSiteDiagnostics);

I think the ability to compact it a bit would be really nice.

DoSomething(..., ref var useSiteDiagnostics = null);

This pattern occurs about 160 times in the C# compiler. I don't think this by itself is reason to introduce a language feature, but I do think that there probably are more "real" situations where this feature adds value and those scenarios should be considered when deciding whether to do the feature.

@alrz
Copy link
Member

alrz commented Dec 2, 2021

The compiler has tons of code that looks like this

If not passing a ref parameter, I'd say it's actually common to pass some defaulted variable right away. Roslyn just happens to do that sort of thing a lot.

@TonyValenti
Copy link

I would love this feature.
I have lots of apis where I prefer ref parameters over out parameters because I can provide a default directly in the ref instead of having to have another argument to capture the default value.

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

7 participants