# C# Language Design Notes for Mar 21, 2018

***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***

## Agenda

We discussed various open questions around nullable reference types


# The null-forgiving operator

## Name

Null-acquiescing
Null-forgiving
Null-silencing
Null-quieting
Darnit

## What does it do?

Changes top-level nullability to not-null, as well as silencing warnings even on nested nullability

``` c#
void M(string? ns, List<string?>? ln)
{
    string s = ns!; // silence and change nullability
    var s2 = ns!; // silence and produce string
    ln = null;
    List<string>? l = ln!; // silence and change
    var l2 = ln!;
    // Idea 1
    l! // change nullability at the top level
    l<!> // idea: change nullability at the nested level
    // Idea 2
    (List<string>?!)ln; // I do a cast that should warn but ! silences it
    List<string>? l3 = (!)ln; // Shorthand
}
```

Should `!` only change top-level nullability, and not suppress nested diagnostics? Or the other way around? Is it a problem that it does both and "suppresses too much".

Since we made affordances for legacy code, the need for passing `null!` for instance is less: unannotated APIs already suppress warnings.

Scenarios for `!` now that legacy APIs aren't a scenario:

1. I'm in the middle of converting my own code; need them at the boundary
2. The compiler can't figure it out, but I'm right

Great example of the latter:

``` c#
List<string?> strings;
var query = strings.Where(s => s != null).Select(s => s.Length); // What?? Why warning?
```
Here you can put the `!` in `s!.Length`, but what if you have

``` c#
void M(IEnumerable<string> source) { ... }
List<string?> strings;
M(strings.Where(s => s != null)); // What?? Why warning?
```

Here you need to suppress on the nested nullability, because you know better.

Currently you can say `!` at the end of the argument to set it right. Should that be a different syntax?

What's the problem with `!` doing both jobs?

``` c#
void M(string? ns, List<string?>? ln)
{
    // I happen to know that if ln is not null, it doesn't contain nulls
    List<string>? l = ln!; 
    _ = l.Count; // warning?
}
```

Now `l.Length` is not warned on because `!` did "too much". We wanted it to silence warnings, but it also changed the null state.

The simplest fix with current semantics would be to cast to a nullable type:

``` c#
    List<string>? l = (List<string>?)ln!;  // or
    var l = (List<string>?)ln!;
```

Proposals:

1. Change null state and suppress 4
2. Two syntaxes 5
3. Only suppress warnings 1
4. Only change null-state 0

Approachable and easy to use. They are all about telling the compiler to shut up when you know what you're doing.

For 3, the things we would make people do to change the null state would also be a hurdle.

If we separate it, one may be a temporary feature that will go away over time, once people have transitioned.

We're not going to settle this today. The prototype does "1+" which is even more lenient than 1.



# Special methods

# Hidden diagnostic