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 nameof to always access instance members from static context (VS 17.7, .NET 8) #4037

Open
3 of 4 tasks
YairHalberstadt opened this issue Oct 20, 2020 · 9 comments
Assignees
Labels
Implemented Needs ECMA Spec This feature has been implemented in C#, but still needs to be merged into the ECMA specification Proposal champion Proposal
Milestone

Comments

@YairHalberstadt
Copy link
Contributor

YairHalberstadt commented Oct 20, 2020

Allow nameof to always access instance members from static context

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

Summary

For background see dotnet/roslyn#48754

The current compiler has some interesting behavior with regards to accessing instance members from a static context:

using System;
public struct C {
    public string P;
    public static string M1() => nameof(P); // Legal
    public static string M2() => nameof(P.Length); // error CS0120: An object reference is required for the non-static field, method, or property 'C.P'
}

Where even though P is an instance member you can access it from a static context, but you can't access P.Length.

The relevant part of the spec is this:

The meaning of the named_entity of a nameof_expression is the meaning of it as an expression; that is, either as a simple_name, a base_access or a member_access. However, where the lookup described in Simple names and Member access results in an error because an instance member was found in a static context, a nameof_expression produces no such error.

This is somewhat ambiguous, but can be interpreted as saying only the top level lookup ignores errors where an instance member was found in a static context, but nested lookups do not. See here dotnet/roslyn#48754 (comment).

My request here is twofold:

  1. Firstly can the LDT clarify the meaning of the spec here.
  2. If the current behavior is not a bug, can we allow this in a future language version.

Motivation

  1. Remove a strange and confusing inconsistency in what's allowed.
  2. Attribute arguments are considered a static context, and accessing instance members is often useful in them, e.g. when using the ForeignKeyAttribute.

Detailed design

Update the spec from:

The meaning of the named_entity of a nameof_expression is the meaning of it as an expression; that is, either as a simple_name, a base_access or a member_access. However, where the lookup described in Simple names and Member access results in an error because an instance member was found in a static context, a nameof_expression produces no such error.

To

The meaning of a named_entity is the meaning of it as an expression; that is, either as a simple_name, a base_access or a member_access. However, where the lookup described in Simple names and Member access results in an error because an instance member was found in a static context, a nameof_expression produces no such error.

Drawbacks

This is not a particularly common scenario, and so probably not worth changing the spec for, if it's decided that the current implementation is not a bug.

Alternatives

Unresolved questions

Design meetings

https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-11-11.md#allow-nameof-to-access-instance-members-from-static-contexts

@jrmoreno1
Copy link

If you change P.Length to C.P.Length, it compiles, which to my mind argues that it is a bug. Instance or not shouldn’t ever impact nameof, that’s just confusing.

@CyrusNajmabadi CyrusNajmabadi self-assigned this Oct 28, 2020
@333fred 333fred modified the milestones: Working Set, Any Time Nov 11, 2020
@333fred 333fred added the Needs Implementation The specification for this issue has been approved, it needs an implementation label Nov 11, 2020
@YairHalberstadt
Copy link
Contributor Author

YairHalberstadt commented Nov 16, 2020

I have an implementation at dotnet/roslyn#48754

@jrmoreno1
Copy link

jrmoreno1 commented Nov 18, 2020

I know c# isn't vb, but I was extremely surprised to find out that the equivalent of:

Sub Main
	Dim d = New Dictionary(Of String, String) 
	Console.WriteLine(Nameof(d.First().Key))
End Sub
void Main()
{
	var d = new Dictionary<string, string>();
	Console.WriteLine(nameof(d.First().Key));
}

doesn't work.

@333fred
Copy link
Member

333fred commented Mar 21, 2023

Sub Main
	Dim d = New Dictionary(Of String, String) 
	Console.WriteLine(Nameof(d.First().Key))
End Sub

This doesn't compile in VB either though: https://sharplab.io/#v2:EYLgtghglgdgNAGxAN2HALiKC4BMQDUAPgJJgAOA9gE7oDOABAMoCed6ApmALABQZVWo1bsuAOgDClBAg4BjdFEow6YgOIcYHalDl8+ABQCuwBLoYSEEOowl8GD5iYYBZaDHuOvAEShgGuAwAvAwAchwA7gy+CkowENQsABQA8gBmzOg6MADmcJnZOQCUnl4OUirSHGIA6jqcADKwHEmhEGAc6Um4YgBiUNTsSUViANIcLEUlvF4AojCBTCZ884GW1nRAA==.

@jjonescz
Copy link
Member

I think no update to C# spec is needed. The quote in this issue comes from closed PR dotnet/csharpstandard#10. The current spec looks fine: §11.7.20 Nameof expressions.

@333fred

@jrmoreno1
Copy link

jrmoreno1 commented Mar 27, 2023

@333fred :

Sub Main
	Dim d = New Dictionary(Of String, String) 
	Console.WriteLine(Nameof(d.First().Key))
End Sub

This doesn't compile in VB either though:

If you use:

Sub Main
	Dim d = New Dictionary(Of String, String)
	Console.WriteLine(NameOf(d.First.Key))
End Sub

it does: https://sharplab.io/#v2:EYLgtghglgdgNAGxAN2HALiKC4BMQDUAPgJJgAOA9gE7oDOABAMoCed6ApmALABQZVWo1bsuAOgDClBAg4BjdFEow6YgOIcYHalDl8BNeszacwYgDKwAjnz4AFAK7AEuhhIQQ6jCXwZ/mTgwAstAwvv4RACJQYAy4DAC8DAByHADuDNEKSjAQ1CwAFADyAGbM6DowAOZw5ZVVAJThEX5SKtIcYgDqOpyWWgXJEGAcpQW4YgBiUNTsYgDSHCwNTbwRAKIw8UxOfJvx7p50QA=

@Pentadome
Copy link

Same with open generic types.

nameof(Foor<>.Bar) doesn't work, but nameof(Foo<object>.Bar) does. Why do I need to specify a type argument if i just want the string "Bar"?

@jnm2
Copy link
Contributor

jnm2 commented Mar 30, 2023

That is quite a wart. Discussion: #2547

@HaloFour
Copy link
Contributor

To keep the spec simple the design of nameof was that it involve no new syntax, it took only what would be already legal syntax and replaced what appeared to be a method invocation with the name constant, if there was no method named nameof in scope. As M(Foo<>.Bar) was not legal syntax, neither would nameof(Foo<>.Bar) be. At this point it feels like this decision has created enough warts that need to be individually addressed that IMO it should be up for reconsideration, especially in the context of potentially making nameof a proper keyword instead of contextual.

@jcouv jcouv assigned 333fred and unassigned CyrusNajmabadi Apr 17, 2023
@jcouv jcouv modified the milestones: Any Time, 12.0 Aug 8, 2023
@jcouv jcouv added Proposal and removed Needs Implementation The specification for this issue has been approved, it needs an implementation labels Aug 8, 2023
@jcouv jcouv added the Implemented Needs ECMA Spec This feature has been implemented in C#, but still needs to be merged into the ECMA specification label Sep 17, 2024
@jcouv jcouv changed the title [Proposal]: Allow nameof to always access instance members from static context [Proposal]: Allow nameof to always access instance members from static context (VS 17.7, .NET 8) Sep 17, 2024
@dotnet dotnet locked and limited conversation to collaborators Nov 19, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Implemented Needs ECMA Spec This feature has been implemented in C#, but still needs to be merged into the ECMA specification Proposal champion Proposal
Projects
None yet
Development

No branches or pull requests

9 participants