C# Language Design Notes for Nov 16, 2016
=========================================

In this meeting we looked at the proposal for nullable reference types in [nullable-reference-types.md](https://github.com/dotnet/csharplang/tree/7981ea1fb4d89571fd41e3b75f7c9f7fc178e837/proposals/nullable-reference-types.md).

The below has few answers and many questions. It is essentially a laundry list of things to work on as we design the feature.


Nullable types
==============

## Calling it "types"
MVP Feedback: There's a bit of a dissonance between calling it "types" and not having guarantees. Maybe talk about it more like analyzers.

Should this be part of a general annotations framework? Do we want to keep doing this specifically per feature or have a general framework for it? Maybe. Let's keep that in the back of our minds. We don't want to be blocked by figuring that out right now.

## Overload resolution
It's not the intention that knowing something is not-null influences overload resolution.

## Tracking nested reference fields and properties
We need to decide whether to track `x.y` when both are reference types, and to what extent we will track aliasing. Guarantees vs usefulness.

## The dammit operator
Should it generate a runtime check? There are pros and cons. 

It would sort of break with a principle that nullability stuff has no runtime semantics, and also impose runtime cost (though that can be eliminated by a smart compiler, when the next thing that follows - e.g. dereferencing - also already starts with a null check). 

On the other hand it might be good to verify non-nullness right then and there, rather than experience random fallout later. Is it an "I know what I'm doing" or a "check that I know what I'm doing" operator?

## Nested annotations

Is it really that useful to have nested nullability annotations, as in `string?[]` or `List<string?>`? On arrays you almost always have null elements. We suspect that it *is* useful, and would detract from the combo with generics if not there, but on the other hand it is a great simplification to only track nullability at the top level.

One problem with nested nullability is that casts will not be able to check the nullability of type arguments. A cast cannot distinguish `(List<string>)o` from `(List<string?>)o`, since the runtime object in `o` won't know if it was instantiated with `string` or `string?`. So the notion that "all is good after a successful cast" is lost. 

If we *do* allow nullable type parameters, should you be able to say `!` on type parameters that may be nullable?

For generics we should find a few samples that we believe are representative, and focus on them. May be able to reuse ones from the Midori project.

## Warning types
The distinction between nullable and non-null warnings is not useful, and some of them (conversions) kind of belong to both.

## When are types the same
Issue: We need to think about when types are considered to be the same for declarative reasons (overrides, etc)

It's similar to tuples in that we have runtime types ornated with extra compile time information. That's a good analogy for a check list, but we should feel free to reach different conclusions.

## null literals
Rules should apply not just to the null literal but to null constants

## The construction rule
There's a rule that checks that all non-nullable reference fields and properties are initialized by a constructor.

It needs to also look recursively through fields and properties of value types for nested non-null reference types.

We need to decide *when* to check during a constructor. It could be before calling helpers on the instance (since they may assume non-nullability) or only at the end. Usefulness vs guarantee!

## Arrays

Should we disallow/discourage arrays of non-null, to try to avoid the array hole where you have an array of a non-nullable element type, initialized entirely with nulls? 

What should people do to go from `T?[]` to `T[]`? Can `!` be applied for the recursive case? Otherwise, casts may be necessary.

## Default
Is `default(T)` of type `T` or `T?`? If it gives a warning, you could shut it up with `!`.

## Referenced assemblies
Should it be evident from an assembly whether unannotated means non-null or not? 

The compiler would have to be able to embrace the "don't care" old fashioned kind of reference type, even when opted in to non-nullability.

What are the semantics around such "shut-up types", and sources of them?

## Unconstrained type parameters
When T is constrained by U, we need to ensure that T is assignable to T, and T to U. It's more complicated than just saying warn from both sides.

## Are the warnings part of the language
Are this set of warnings part of the language, or are they a "compiler feature" - essentially some built-in analyzers. In the latter case we might allow them to evolve in a breaking way.

## Is nullability always explicit?
It is probably fine that you can get nullable reference types implicitly (e.g. inference from `string`, `null`).

## Locals
Not annotating locals would reduce the number of places that would need to be fixed when turning nullability on. They would then have their nullability inferred instead. It's a trade-off between expressiveness and upgrade burden. This goes to granularity of opt-in as well. It would cause a readability disconnect between locals and fields.

Should `var?` be allowed? should `var` always be nullable? Should it infer its nullability? How to best express intent here?

## Parameters
There's a proposal to allow `!` on parameter types `M(T! x)` to cause a runtime null check to be generated. That would be better written as `M(T x!)`, putting the `! on the parameter, since it's about the parameter itself, and would actually name the parameter in the exception thrown!

## Expressing TryGet
Could get away with non-language flourishes, such as attributes. "DefinitelyAssignedWhenTrue".

## Applying flow analysis to value types
The proposal of also doing the flow analysis for nullable value types is more concerning, because it's adding new runtime semantics.

Also, it may work for dereferencing those values, but not so well if it is an argument: Does it influence overload resolution? What if there are many arguments?

Flow for nullable value types is a nice-to-have add-on, not essential to the proposal.




