C# Language Design Notes, Nov 15, 2016
======================================

> *Quote of the day*: "Bad people don't get good features!"


Agenda
------

- Tuple name warnings
- "Discards"


Tuple name warnings
===================

There are two kinds of warnings on the table regarding names in tuples:

1. A warning on tuple *literals* only, if the literal uses an element name that isn't in the target type
2. A warning on all expressions of tuple type if an element name in the expression is used for a *different* element in the target type

The first warning helps get the names right when writing a tuple literal, and while maintaining it. It is already in the product:

``` c#
(int x, int y) t = (a: 1, b: 2); // Oops, forgot to update tuple literal? Names a and b would be lost
```

The second warning would help guard against bugs due to reordering of tuple elements:

``` c#
(string firstName, string lastName) GetName();

(string lastName, string firstName) name = GetName(); // Oops, forgot to swap the element names in name?
```

This warning is currently *not* in the product. We would like it to be, but don't have the runway to implement it.

In the future it could be added as an analyzer, or as a compiler warning protected by warning waves (#1580).


"Discards"
==========

We got great feedback on "wildcards" at the MVP Summit, including changing its name to the term "discards", which is spreading in industry.

We are also encouraged to use `_` as the discard character instead of `*`. It works better visually, and is what many other languages already use.

There is a small matter of `_` already being a valid identifier. In order for it to coexist as a discard with existing valid uses we need to use a few tricks. Here are the essential rules:

1. A standalone `_` when no `_` is defined in scope is a discard
2. A "designator" `var _` or `T _` in deconstruction, pattern matching and out vars is a discard

Discards are like unassigned variables, and do not have a value. They can only occur in contexts where they are assigned to.

Examples:

``` c#
M(out _, out var _, out int _); // three out variable discards
(_, var _, int _) = GetCoordinates(); // deconstruction into discards
if (x is var _ && y is int _) { ... } // discards in patterns
```

One use case is to silence warnings when dropping Tasks from async methods:

``` c#
_ = FooAsync();
```

We also want to allow discards as lambda parameters `(_, _) => 0`, but don't expect that to make it in C# 7.0. Today `_` is allowed as an ordinary identifier; the rule would be that it would become a discard if there's more than one.

We can also consider allowing top-level discards in foreach loops:

``` c#
foreach (_ in e) { ... } // I don't care about the values
```

But that does not seem too important, especially since you can use `var _` to the same effect.

In general, whenever use of standalone `_` as a discard is precluded, either by syntactic restrictions or by `_` being declared in the scope, `var _` is often a fine substitute with the same meaning. However, if the declared `_` is a parameter or local, there are situations where you are out of luck:

``` c#
public override void M(int _) // declaring _ to signal that this override doesn't care about it
{
	_ = TryFoo();     // Error: cannot assign bool result to int variable _
	var _ = TryFoo(); // Error: cannot declare local _ when one is already in scope
}
``` 

These situations are always local to a member, so it is relatively easy to rewrite them, e.g. to rename the incoming parameter. We could consider accommodating them in the future: the error for a local redeclaration of `_` when one is already in scope could be changed to allowing it, but consider the second declaration a discard. This may be too subtle, and not useful enough, but it is worth considering post C# 7.0.