This project is read-only.

C# Language Design Notes for Oct 7, 2013 (Part II)

Topics: C# Language Design
Jul 22, 2014 at 12:02 AM
This is Part II. Part I is here.

The nameof operator

The nameof operator is another feature that was summarily dismissed as a tag-along to a bigger, more unwieldy feature: the legendary infoof operator.
PropertyInfo info = infoof(Point.X);
string name = nameof(Point.X); // "X"
While the infoof operator returns reflection information for a given language element, nameof just returns its name as a string. While this seems quite similar at the surface, there is actually quite a big difference when you think about it more deeply. So let’s do that!

First of all, let’s just observe that when people ask for the infoof operator, they are often really just looking to get the name. Common scenarios include throwing ArgumentExceptions and ArgumentNullExceptions (where the parameter name must be supplied to the exception’s constructor), as well as firing Notify events when properties change, through the INotifyPropertyChanged interface.

The reason people don’t want to just put strings in their source code is that it is not refactoring safe. If you change the name, VS will help you update all the references – but it will not know to update the string literal. If the string is instead provided by the compiler or the reflection layer, then it will change automatically when it’s supposed to.

At a time when we are trying to minimize the use of reflection, it seems wrong to add a feature, infoof, that would contribute significantly to that use. nameof would not suffer from that problem, as the compiler would just replace it with a string in the generated IL. It is purely a design time feature.

There are deeper problems with infoof, pertaining to how the language element in question is uniquely identified. Let’s say you want to get the MethodInfo for an overload of a method M. How do you designate which overload you are talking about?
void M(int x);
void M(string s);
var info = infoof(M…); // Which M? How do you say it?
We’d need to create a whole new language for talking about specific overloads, not to mention members that don’t have names, such as user defined operators and conversions, etc.

Again, though, nameof does not seem to have that problem. It is only for named entities (why else would you want the name), and it only gives you the name, so you don’t need to choose between overloads, which all have the same name!

All in all, therefore, it seems that the concerns we have about infoof do not apply to nameof, whereas much (most?) of its value is retained. How exactly would a nameof operator work?

Syntax

We would want the operator to be syntactically analogous to the existing typeof(…). This means we would allow you to say nameof(something) in a way that at least sometimes would parse as an invocation of a method called nameof. This is ambiguous with existing code only to the extent that such a call binds. We would therefore take a page out of var’s book and give priority to the unlikely case that this binds as a method call, and fall back to nameof operator semantics otherwise. It would probably be ok for the IDE to always highlight nameof as a keyword.

The operand to nameof has to be “something that has a name”. In the spirit of the typeof operator we will limit it to a static path through names of namespaces, types and members. Type arguments would never need to be provided, but in every name but the last you may need to provide “generic dimension specifiers” of the shape <,,,> to disambiguate generic types overloaded on arity.

The grammar would be something like the following:
nameof-expression:
  • nameof ( identifier )
  • nameof ( identifier :: identifier )
  • nameof ( unbound-type-name . identifier )
Where unbound-type-name is taken from the definition of typeof. Note that it always ends with an identifier. Even if that identifier designates a generic type, the type parameters (or dimension specifiers) are not and cannot be given.

Semantics

It is an error to specify an operand to nameof(…) that doesn’t “mean” anything. It can designate a namespace, a type, a member, a parameter or a local, as long as it is something that is in fact declared.

The result of the nameof expression would always be a string containing the final identifier of the operand. There are probably scenarios where it would be desirable to have a “fully qualified name”, but that would have to be constructed from the parts. After all, what would be the syntax used for that? C# syntax? What about VB consumers, or doc comments, or comparisons with strings provided by reflection? Better to leave those decisions outside of the language.

Conclusion

We like the nameof operator and see very few problems with it. It seems easy to spec and implement, and it would address a long-standing customer request. With a bit of luck, we would never (or at least rarely) hear requests for infoof again.

While not the highest priority feature, we would certainly like to do this.
Aug 14, 2014 at 5:58 PM
This would be such a help for so many scenarios I can think of.

But what generic-type notation would you return? C# or IL? Could we have some affordance to allow us to choose?
nameof(List<>) // returns "List<>", vs
ilnameof(List<>) // returns "List`1"
Aug 14, 2014 at 7:18 PM
IIRC it simply returns List without any arity.
Aug 27, 2014 at 9:29 PM
I hope that nameof allows me to simplify a common class which is found quite often in projects, the class commonly named Guard/Check/Verify. Let me explain better: It's fairly common to have an utility class to check for null e.g.
public static class Check
{
    public static void NotNull<T>(T mayBeNull, string argumentName) where T : class
    {
        if (mayBeNull == null)
        {
            throw new ArgumentNullException(argumentName);
        }
    }
}
What is ugly with this class is its usage, for example
public ProcessPaymentResult ProcessPayment(Order order)
{
    Check.NotNull(order, "order");
    ....
}
The ugly part is obviously pass the name of the variable as a plain string. There are a tons of versions around the net, but none of those is effective, most versions plays around with lambdas but I personally don't like it very much.
When I heard about nameof my thoughts goes on that class hoping to realize a simple end elegant version of that particular class so it would be nice IMO to have the ability to get the name of the variable passed to a function. This is my simple pseudo C# for that feature:
public static class Check
{
    public static void NotNull<T>(T mayBeNull, string argumentName = nameof(mayBeNull)) where T : class
    {
        if (mayBeNull == null)
        {
            throw new ArgumentNullException(argumentName);
        }
    }
} 
In this case nameof should not resolve the name of the mayBeNull variable, but the name of the parameter calling the NotNull function.

Any comment are appreciated.
Cheers, Max

P.S.

Am I missing something or nameof does not work with types? (at least in VS14 CTP3) e.g. .
nameof(List<>)
Sep 4, 2014 at 10:07 PM
We considered some of this, but ended up not supporting it directly. You could still use nameof, but will need to refer to the item twice at the callsite. Also, types should work fine, though the rightmost thing in a nameof must be an identifier, not a generic name. See the example below:
using System;
using System.Collections.Generic;

class Program
{
    static void Main(string[] args)
    {
        Check.NotNull(args, nameof(args));
        Console.WriteLine(nameof(List));
    }
}

public static class Check
{
    public static void NotNull<T>(T t, string name) where T : class
    {
        if (t == null) throw new ArgumentNullException(name);
    }
}
Oct 3, 2014 at 11:04 AM
How about using this for INotifyPropertyChanged?
Oct 3, 2014 at 3:40 PM
You can absolutely use this for INotifyPropertyChanged, though personally, I tend to use a different pattern. All of my View Model classes inherit from a class that has the PropertyChanged event, and a method that uses the [CallerMemberName] feature like this.
        protected void SetProperty<T>(ref T field, T value, [CallerMemberName]string propertyName = null)
        {
            if (!EqualityComparer<T>.Default.Equals(field, value))
            {
                field = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
Then in view models I can have properties that are simple like:
        private int _age;
        public int Age
        {
            get { return _age; }
            set { SetProperty(ref _age, value); }
        }