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]: Allow var variables to be used in a nameof in their initializers #4384

Closed
1 of 4 tasks
333fred opened this issue Feb 2, 2021 · 13 comments
Closed
1 of 4 tasks

Comments

@333fred
Copy link
Member

333fred commented Feb 2, 2021

Allow var variables to be used in a nameof in their initializers

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

Summary

Today, the following code is invalid:

var a = nameof(a);

Despite this code being valid:

string a = nameof(a);

This proposal makes the first example legal.

Motivation

This is confusing to encounter (not helped by the bad Roslyn diagnostic we give, see dotnet/roslyn#45146, but that's beside the point), and takes some serious spec-lenses to understand why the restriction exists. nameof(identifier) is always a string, and we should make it fine to use a var variable this way.

Detailed design

We modify this section of the specification (edit is to the last bullet, in bold):

In the context of a local variable declaration, the identifier var acts as a contextual keyword (Keywords).When the local_variable_type is specified as var and no type named var is in scope, the declaration is an implicitly typed local variable declaration, whose type is inferred from the type of the associated initializer expression. Implicitly typed local variable declarations are subject to the following restrictions:

In the context of a local variable declaration, the identifier var acts as a contextual keyword (Keywords).When the local_variable_type is specified as var and no type named var is in scope, the declaration is an implicitly typed local variable declaration, whose type is inferred from the type of the associated initializer expression. Implicitly typed local variable declarations are subject to the following restrictions:

  • The local_variable_declaration cannot include multiple local_variable_declarators.
  • The local_variable_declarator must include a local_variable_initializer.
  • The local_variable_initializer must be an expression.
  • The initializer expression must have a compile-time type.
  • The initializer expression cannot refer to the declared variable itself except as the argument to a nameof_expression.

Drawbacks

All change is scary.

Alternatives

Do nothing.

Unresolved questions

Design meetings

https://github.com/dotnet/csharplang/blob/1754aaafffe270c19d8578af30a2eb768de3ee49/meetings/2021/LDM-2021-02-10.md#allow-var-variables-to-be-used-in-a-nameof-in-their-initializers

@JustNrik
Copy link

JustNrik commented Feb 3, 2021

void Foo(int value, string paramName = nameof(value))
{
}

isn't valid either, can this be covered as well? Thought the error is different but I'm curious to know why it isn't valid

@lechu445
Copy link

lechu445 commented Feb 3, 2021

[return: NotNullIfNotNull(nameof(parameter))]
public static string? Foo(string? parameter)
{
}

and this is not valid

@CyrusNajmabadi
Copy link
Member

and this is not valid

This is already tracked by another issue.

@CyrusNajmabadi
Copy link
Member

isn't valid either, can this be covered as well?

No. please open a discussion on this :) Thanks!

@KalleOlaviNiemitalo
Copy link

The following would then not be allowed, because it refers to s in the argument to a nameof_expression, rather than as the argument. It seems OK not to allow this.

var s = nameof(s.Length);

@333fred
Copy link
Member Author

333fred commented Feb 3, 2021

The following would then not be allowed, because it refers to s in the argument to a nameof_expression, rather than as the argument. It seems OK not to allow this.

var s = nameof(s.Length);

Correct. That would involve knowing the type of s at that point. We just want to allow it when it's the argument to the nameof expression, nothing deeper.

void Foo(int value, string paramName = nameof(value))
{
}

isn't valid either, can this be covered as well? Thought the error is different but I'm curious to know why it isn't valid

Let me dig into why that isn't allowed today. I'd be ok with supporting it.

@333fred
Copy link
Member Author

333fred commented Feb 3, 2021

void Foo(int value, string paramName = nameof(value))
{
}

isn't valid either, can this be covered as well? Thought the error is different but I'm curious to know why it isn't valid

Let me dig into why that isn't allowed today. I'd be ok with supporting it.

So, this comes down the scoping rules laid out here: https://github.com/dotnet/csharplang/blob/master/spec/basic-concepts.md#scopes. Specifically, the lines that read like:

The scope of a parameter declared in a method_declaration (Methods) is the method_body of that method_declaration.

This would be covered by #373, I think.

@MgSam
Copy link

MgSam commented Feb 5, 2021

All change is scary.

So true.

@Youssef1313
Copy link
Member

Should the following be allowed?

I'd say no, but wanted to point out this scenario to consider.

public class C
{
    private string a = "";

    public void M()
    {
        var a = nameof(a);
    }

    private static string nameof(object o) => "NameOfStaticMethod";
}

@333fred
Copy link
Member Author

333fred commented Feb 6, 2021

Should the following be allowed?

I'd say no, but wanted to point out this scenario to consider.

public class C
{
    private string a = "";

    public void M()
    {
        var a = nameof(a);
    }

    private static string nameof(object o) => "NameOfStaticMethod";
}

Nope. A method call is not a nameof_expression. It is a good test case though.

@HurricanKai
Copy link
Member

HurricanKai commented Feb 9, 2021

in regards to this sample:

var s = nameof(s.Length);

Correct. That would involve knowing the type of s at that point.

the type can be inferred though. nameof always returns a string, therefore even a "recursive" definition like that could be valid.
I don't see much use though, I mean that's just the same as nameof(string.Length)

@333fred
Copy link
Member Author

333fred commented Feb 9, 2021

in regards to this sample:

var s = nameof(s.Length);

Correct. That would involve knowing the type of s at that point.

the type can be inferred though. nameof always returns a string, therefore even a "recursive" definition like that could be valid.
I don't see much use though, I mean that's just the same as nameof(string.Length)

This particular use case is degenerate. But it could be more like var s = Method(nameof(s.Length));, where Method is defined as T Method<T>(T arg) => arg;.

@Rekkonnect
Copy link
Contributor

Another thing is that the following code is also valid:

dynamic s = nameof(s);

@333fred 333fred closed this as not planned Won't fix, can't repro, duplicate, stale Dec 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants