61

I was just hit with a minor issue in C#, it was just a copy-paste mistake but don't know how C# accept it.

This code gets compiled successfully...HOW

namespace DemoNS
{
    class DemoClass
    {
        String _ = new String('a', 1);        
    }
}

Is there any default significance of variable named _?

3
  • 6
    As svick notes, it's as valid as any other name. However, calling a variable _ is probably really bad practice. Commented Jun 10, 2011 at 14:55
  • 5
    I would ask why you think it would or should not work? Commented Jun 10, 2011 at 16:52
  • 1
    Definitely, I am not using "_" as variable name. I just unknowingly named it. Commented Jun 12, 2011 at 18:23

5 Answers 5

105

Nowadays with C# 7.0 the _ does have significance sometimes. It became the discard operator for the new out var feature. It is used when a function returns a value and you want to notify the compiler that you won't be using it - so it can be optimized out. Or when deconstructing (Another C# 7.0 feature) you can use it to ignore part of the tuple that you are not interested in.

Example out var

void Test(out int i) => i = 1;

Test(out _); // _ was never declared, it will still compile in C# 7.0

var r = _;   // error CS0103: The name '_' does not exist in the current context

Example deconstructing a Tuple

var Person = ("John", "Smith");

var (First, _) = Person; // '_' is not a declared

Debug.Print(First); // prints "John"
Debug.Print(_); // error CS0103: The name '_' does not exist in the current context

A problem arises if you do declare your own variable named _ and then use the discard operator it will cause ambiguity. This issue has been reported Here.

EDIT Above problem is not a problem as @maf-soft points out in comments. If _ was declared it is treated like a regular variable like it was pre C# 7.0.

EDIT 2021 A little overdue

In c# 8.0 _ also became the catch all operator in a switch expression, officially named the discard operator

Example discard operator

var moreThan20 = val switch
{
    >20 => "Yes",
    >50 => "Yes - way more!",
    _ => "No",
};

The discard operator assigns a value when no other pattern matches

Sign up to request clarification or add additional context in comments.

5 Comments

I'd like to add that if you declare a variable named _, it is used as before, so old code won't break (this wasn't completely clear in your answer). That's ok for me, but maybe a warning would be good.
I'm not sure if that discard operator really belongs to the out var feature (yes, your source link gives that impression).
@maf-soft you are right. I am goint to comment on referenced gist.
Another interesting reference: stackoverflow.com/questions/42920622/… - and interestingly other ideas for the discard operator were using the void keyword :)
It's very unexpected. It's not like C#.
48

No, there is no default significance, _ is just a variable name like any other.

I like to use it in similar way to Prolog's anonymous variables: when you're creating a lambda that ignores one of its parameters, you can name it _:

EventHandler handler = (_, e) => Console.WriteLine(e);

On the other hand, I wouldn't use it anywhere else, you should use a descriptive name instead.

EDIT: Note that in C# 7.0, _ sometimes has special meaning. For example, you can write _ = new String('a', 1);, even if you didn't declare a variable named _.

8 Comments

On a serious note though: don't use it.
Idiomatic in lambdas where you don't care about an argument.
And for reference (though a little antiquated) here is the identifier spec: msdn.microsoft.com/en-us/library/aa664670.aspx
@Justin: eh, I've done a lot of functional programming (OCaml, et al) and that's a habit likely brought over from there.
Underscore is also idiomatic in Python, when you do not care about an argument / parameter / value.
|
25

The previous answers were all useful, but I think they missed a use case. If you don't want to work with a function's return value, you can use the _ character, i.e.:

instead of

int returnvalue = RandomFunction();

you can do

_ = RandomFunction();

6 Comments

What's the benefit of _ = RandomFunction(); over RandomFunction(); (i.e. simply not assigning the return value at all)?
Technically it does the same thing, but explicitly marking that you do not want to use the returned value 1) creates cleaner code and 2) tells the IDE that you did it intentionally, thus you won't get a warning for that.
@OlivérRaisz Do you really think it creates cleaner code? If we have a "query" style function like this, which should not have side effects: _ = GetUsers(); To me, this code is implying that there are side effects, why else would we discard the return value? On the other hand, if we have a "command": _ = DeleteAllUsers(); In this case we just took the perfectly clean command call and made visually look like a query. In a lambda or to denote arguments that will go unused I think it works better, but for anyone reading, maybe don't sprinkle these all over the place...
@OscarLundberg: I don't see the logic in your comment. DeleteAllUsers(); should be a void returning function; _ = DeleteAllUsers(); should be a compiler error. If GetUsers(); has no side-effects but returns a value, then it would be pointless to call it without using the return value. In both cases, the code you show would not be written. The only time there is a reason to use _ = SomeFunction(); is if the function is being called for a side-effect, but its return value is not needed. _ = tells future programmers: "I am calling this for its side-effect".
Thank you for clarifying. That is a useful principle where appropriate (as demonstrated by EIFFEL language in 1986) but IMHO is irrelevant to this discussion, which begins with the assumption that, for whatever reason, one has a function that causes side-effects and returns a value. For example, it is quite common for an action-performing function to return a success/fail bool or an error code. Usually one should handle that result, but (rarely) there are reasons not to. _ = does exactly what this answer says it does: makes it clear that programmer deliberately is ignoring the return value.
|
5

_ is a valid character the same as a or i and syntactically variables can start with _ so a single character name of _ is perfectly syntactically correct. Not a really good choice but will compile and work fine.

2 Comments

this is not valid anymore with c#
@VineetYadav. I don't see any update to c# that disallows this. Perhaps there is some compiler option? In C# 7 language spec / Discards, there is this sentence: "The example assumes that there is no declaration of the name _ in scope.". [Implying that _ is still a valid name. So that old code wouldn't break.] AFAIK, later c# specs simply added new features. Why would they invalidate existing code?
5

Its a discards, which is a placeholder variable and unused. It tells compiler that not interested in output value. Example: Created a File handing class. Constructor will initiate the process. And, we have Copy, Delete operation. Suppose, one particular class has the responsibility to initiate the process but no need to worry about other operations. Then I will declare like _ = new FileListener(); I will not worry about output. Other class can have instantiate FileListener obj = new FileListener(); or can call other operation as FileListener.CopyFile()

Sample:

    class Program
        {
            static void Main(string[] args)
            {
   /// Ignore the instance value but initialized the operation by instantiation
                _ = new FileListener();
                
                Console.WriteLine("Hello World!");
            }
        }
        
        public class FileListener 
        {
            public FileListener()
            {
                /// Logic to listen external file changes
            }
            public static void DeleteFile()
            { }
            public static void CopyFile()
            { }
        }

1 Comment

Thanks for taking out time to explain this. It makes more sense now. Cheers <3

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.