3.4 KiB
C# Language Design Notes for Mar 29, 2017
Raw notes, yet to be cleaned up - read at your own peril
Agenda
Nullable scenarios
Identify all the scenarios where nullable needs to be right.
Philosophical debate about what the feature is. Should it be as strict as possible, or more forgiving? Is it more a type feature or more a helpful warning feature.
We've made decisions about where we are on that spectrum. Do we trust that as a starting point, or do we want to reexamine those at this point?
Example: We want to track variables with flow analysis. for simple names x
(local variables, parameters) that has reasonably high fidelity. As we move to x.y.z
the confidence goes down, but the usefulness goes up.
Let's agree right now that we're pretty far from the perfect guarantee. It's not that there is anything fundamentally wrong with that, there's just no way to fit it. Let's make lemonade.
We have design choices and we have interesting scenarios. Two kinds:
- Here are settings where people get into problems with nulls, and look at whether the feature solves it
- Understand false positives and negatives too: getting errors that incorrectly flag a "problem", and not being told about a problem.
False alarms are a problem, because they will discourage people from taking on the feature, and from taking the reports seriously. We can't be too strict.
Also an issue of writing the libraries: is this sufficiently expressible?
Another measure of success: How much does a client of a newly annotated old library have to change in order to accommodate?
Example: If we are going to say that you annotate your locals, that might be more consistent with the rest of the language, but might also cause more code to need to be changed.
This may be a question of gradual adoption strategies. It could be that you start out consuming nullables (which are the new thing, syntactically), without making unannotated mean "non-null".
Generics is always a fun situation. Are they in subtyping relationship? That informs variance. And so on.
Next steps: Get some samples going.
Span<T>
safety
span-safety.md
Span<T>
is special: it logically contains a ref
and a size/range. Can't be allowed to tear, and may reference things on the stack: Therefore can't live on the heap. Also, needs to respect the lifetime of a local to which it has a ref. We'll introduce a notion of "ref-like" types, in anticipation of more of these.
Other "ref-like" types already exist (e.g. TypedReference
), but are pretty obscure and unsafe. We won't let our design influence by them, but might opportunistically unify. Also their implementation in the compiler can serve as a checklist for dealing with the new notion of ref-like types.
Declaration: need something in metadata. Old compilers will ignore it. We cannot poison a type with modreq's. We could Obsolete
the type, and the new compiler could recognize it somehow.
For now we shouldn't support language-level declaration of ref-like types. There's a whole set of rules we'd need to figure out for such declarations; instead we are good with just recognizing this in metadata and acting accordingly for now.
ref-like types cannot be passed by passed by ref, only by in
, Therefore they must be readonly structs, so that this
is not passed by ref.
In general, these rules are quite restrictive in certain ways. Let's try it and see if it works in our scenarios. There may be an unsafe
opt-out, or we may nuance the rules.