-
Notifications
You must be signed in to change notification settings - Fork 86
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
C# 6.0 feature: nameof expressions #10
Conversation
fa71860
to
5a0f68d
Compare
; | ||
``` | ||
|
||
Grammatically speaking, the *named_entity* operand is always an expression. Because `nameof` is not a keyword, a *nameof_expression* is always syntactically ambiguous with an invocation of the simple name `nameof`. For compatibility reasons, if a name lookup ([§12.7.3](expressions.md#simple-names)) of the name `nameof` succeeds, the expression is treated as an *invocation_expression* -- regardless of whether the invocation is valid. Otherwise it is a *nameof_expression*. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does not read correctly to me. By "Grammatically" is "Semantically" or "Syntactically" meant? From a syntactic view a name_entity is always a name_entity. Now the language the grammar represents may be a subset of the language of expressions but that does not make it an expression either syntactically or semantically. I think what we are trying to say is that a name lookup succeeds then the named_entity is treated semantically as an invocation_expression.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Continuing thought... This para is a backward compatibility statement, should there be some typographical indication that this is what it is? And (having not looked myself so there might be...) should there be a corresponding compatibility note where function declarations are describe a note stating that nameof
should be avoided by is (currently?) allowed for backward compatibility?
|
||
It is a compile-time error for a *named_entity* designating a method group to have a *type_argument_list*. It is a compile time error for a *named_entity_target* to have the type `dynamic`. | ||
|
||
A *nameof_expression* is a constant expression of type `string`, and has no effect at runtime. Specifically, its *named_entity* is not evaluated, and is ignored for the purposes of definite assignment analysis ([§10.4.4.22](variables.md#104422-general-rules-for-simple-expressions)). Its value is the last identifier of the *named_entity* before the optional final *type_argument_list*, transformed in the following way: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this not why a named_entity is not an expression but a named_entity? I.e. something like (typed on the fly, not wordsmithed!) "its named_entity is not an expression (despite its syntactic similarity?) and therefore is not part of definite assignment analysis"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we probably need to talk about Nigel's comments - mine are somewhat more simplistic, I think :)
|
||
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 [§12.7.3](expressions.md#1273-simple-names) and [§12.7.5](expressions.md#1275-member-access) results in an error because an instance member was found in a static context, a *nameof_expression* produces no such error. | ||
|
||
It is a compile-time error for a *named_entity* designating a method group to have a *type_argument_list*. It is a compile time error for a *named_entity_target* to have the type `dynamic`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be worth highlighting somewhere that if the name in the source code nameof
expression is an alias for the entity, it's that source expression that's relevant, not the resolved entity. For example:
using MyAlias = System.Guid;
...
Console.WriteLine(nameof(MyAlias)); // Prints MyAlias, not Guid
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Its value is the last identifier of the named_entity" probably covers it...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: Add a note to explain this after that paragraph.
@@ -5381,6 +5421,7 @@ Only the following constructs are permitted in constant expressions: | |||
- Parenthesized subexpressions, which are themselves constant expressions. | |||
- Cast expressions. | |||
- `checked` and `unchecked` expressions. | |||
- Nameof expressions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Nameof expressions | |
- `nameof` expressions |
|
||
These are the same transformations applied in [§7.4.3](lexical-structure.md#743-identifiers) when testing equality between identifiers. | ||
|
||
> TODO: examples |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suspect that a single example referring to a lot of different kinds of entity would be best here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A number of entities that should be used here:
- a local variable
- a simple type name
- a globally qualified type name (e.g.
System.Int
) - A closed generic name (e.g.
List<int>
). - An open generic type, where it is allowed:
public static void Thing<T>(T arg) { Console.WriteLine(nameof(List<T>)); // writes "List" } public static void DoesntCompile() { Console.WriteLine(nameof(List<T>)); // `T` is not defined }
- The
System
namespace - An additional namespace, such as
System.Collections.Generic
- Tuple member:
var point = (x: 3, y: 4); Console.WriteLine(nameof(point.x));
; | ||
``` | ||
|
||
Grammatically speaking, the *named_entity* operand is always an expression. Because `nameof` is not a keyword, a *nameof_expression* is always syntactically ambiguous with an invocation of the simple name `nameof`. For compatibility reasons, if a name lookup ([§12.7.3](expressions.md#simple-names)) of the name `nameof` succeeds, the expression is treated as an *invocation_expression* -- regardless of whether the invocation is valid. Otherwise it is a *nameof_expression*. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Grammatically speaking, the *named_entity* operand is always an expression. Because `nameof` is not a keyword, a *nameof_expression* is always syntactically ambiguous with an invocation of the simple name `nameof`. For compatibility reasons, if a name lookup ([§12.7.3](expressions.md#simple-names)) of the name `nameof` succeeds, the expression is treated as an *invocation_expression* -- regardless of whether the invocation is valid. Otherwise it is a *nameof_expression*. | |
Because `nameof` is not a keyword, a *nameof_expression* is always syntactically ambiguous with an invocation of the simple name `nameof`. For compatibility reasons, if a name lookup ([§12.7.3](expressions.md#simple-names)) of the name `nameof` succeeds, the *nameof_expression* is treated as an *invocation_expression* -- regardless of whether the invocation is valid. Otherwise it is a *nameof_expression*. |
It is a compile-time error for a *named_entity* designating a method group to have a *type_argument_list*. It is a compile time error for a *named_entity_target* to have the type `dynamic`. | ||
|
||
A *nameof_expression* is a constant expression of type `string`, and has no effect at runtime. Specifically, its *named_entity* is not evaluated, and is ignored for the purposes of definite assignment analysis ([§10.4.4.22](variables.md#104422-general-rules-for-simple-expressions)). Its value is the last identifier of the *named_entity* before the optional final *type_argument_list*, transformed in the following way: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to work out whether this should compile:
Console.WriteLine(nameof(x));
int x = 10;
(It doesn't currently.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is deemed a lookup error, it's already covered - Jon to check that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've currently only found a reference in https://github.com/ECMA-TC49-TG2/csharpstandard/blob/draft-v6/standard/variables.md, which is within a note:
Within the scope of a local variable, it is a compile-time error to refer to that local variable in a textual position that precedes its local_variable_declarator
I'm assuming there must be something normative somewhere... but I can't see anything in 12.7.3. (It's a shame if someone has to read the whole spec to know that the result of a lookup in 12.7.3 is invalid.) Let's discuss whether this needs a new issue...
Jon to spend some time polishing (hopefully). |
I think we can remove the aspects of the "meaning" of the named_entity. New proposal:
(Do we need to say that any other lookup error results in a compile-time error for the nameof_expression?) I'm still not sure about the "access to a local variable before it's declared" - let's discuss that in the meeting. (If it's really only mentioned in a note, we should file an issue about that and make sure it's included in lookup rules.) |
Just remembered that as well as the section I've quoted/proposed, I need to fully spec examples, and add a note around the |
Work done to date on nameof expressions
5a0f68d
to
2ed4b4f
Compare
Local variable part: it's mentioned in https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#1362-local-variable-declarations:
That section of the standard is quite a long way from name lookup, so I'm not sure it should really apply within |
Builds on dotnet#10 - Reworded to avoid the "meaning" confusion - Added examples
closing in favor of #250 (which builds on this branch. |
Work done to date on nameof expressions.
Creating draft PR because of outstanding TODO item.