diff --git a/meetings/2018/LDM-2018-03-21.md b/meetings/2018/LDM-2018-03-21.md new file mode 100644 index 0000000..4e0ea00 --- /dev/null +++ b/meetings/2018/LDM-2018-03-21.md @@ -0,0 +1,107 @@ +# 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? ln) +{ + string s = ns!; // silence and change nullability + var s2 = ns!; // silence and produce string + ln = null; + List? 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?!)ln; // I do a cast that should warn but ! silences it + List? 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 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 source) { ... } +List 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? ln) +{ + // I happen to know that if ln is not null, it doesn't contain nulls + List? 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? l = (List?)ln!; // or + var l = (List?)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 \ No newline at end of file