Sitemap

[Don’t .NET] Just an underscore?

2 min read19 hours ago

--

As you probably know, _ is useful when an API gives you a value you don’t care about:

bool isValid = int.TryParse("42", out _);

You need to know whether parsing succeeded, but not what the number was. So, discard it. You can do the same when deconstructing a tuple:

var (_, _, name) = (10, 20, "Ada");

Two underscores, no duplicate variable names. So far, so good. However, _ is also a perfectly valid C# identifier:

int _ = 0;
int.TryParse("42", out _);
Console.WriteLine(_); // 42

This time, out _ refers to the existing variable. Nothing was discarded. Giving your variable an uninformative name doesn’t make it disappear.

Lambdas have a similar surprise:

Func<int, int> echo = _ => _;
Console.WriteLine(echo(42)); // 42

A single parameter named _ is still a parameter you can use. Since C# 9, you need two or more parameters with that name to make them discards:

Func<int, int, int> answer = (_, _) => 42;

Yes, one underscore and two underscores follow different rules. Backward compatibility has its demands.

Now, try the tuple idea in JavaScript:

const [_, _, name] = [10, 20, "Ada"];
// SyntaxError: duplicate binding

JavaScript sees two const bindings with the same name. let won’t save you either. To skip array elements, you need empty positions:

const [, , name] = [10, 20, "Ada"];
console.log(name); // Ada

Python accepts the repeated underscores, but for a different reason:

_, _, name = (10, 20, "Ada")
print(_) # 20

It assigns to an ordinary variable twice. The second value wins. Likewise, for _ in range(3) leaves _ equal to 2 after the loop. You may not care about the value, but Python still keeps it.

Get Guriy Samarin’s stories in your inbox

Join Medium for free to get updates from this writer.

Unless you’re inside a case pattern, available since Python 3.10:

_ = "unchanged"
match (10, 20, "Ada"):
case (_, _, name):
print(name) # Ada
print(_) # unchanged

Here, _ is a wildcard and doesn’t bind a name. Same character, different context.

Python also uses _ for the last displayed result in its standard interactive interpreter, and commonly as an alias for a gettext translation function. Assigning your own throwaway value to it can shadow the former or overwrite the latter. A surprisingly busy name for something you supposedly don’t need.

And if you put it between digits, all three languages agree:

1_000_000_000

Still one billion. Those underscores are numeric separators; nothing is being discarded.

So, before borrowing the _ habit from another language, check what it actually means in that particular place. Even C# doesn’t give you just one answer.

References:

--

--

Guriy Samarin
Guriy Samarin

Written by Guriy Samarin

Software developer. Web (mostly backend) development now. My stack — .NET (APS.NET Core MVC).