csharplang/meetings/2018/LDM-2018-04-25.md
2018-05-18 16:04:30 -07:00

153 lines
4.2 KiB
Markdown

# C# Language Design Notes for Apr 25, 2018
***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***
## Agenda
# Warn on nullable ref type argument when T has `class` constraint
``` c#
static void F<T>(T t) where T : class { t.ToString(); /* no warning */ }
F(maybeNull); // warning: string? does not satisfy 'class' constraint
F<string?>(string.Empty); // warning: string? does not satisfy 'class' constraint
```
This is a real danger, and we should be warning here.
Note that in both cases the warning is about constraint checking: even in the second line we infer `string?` and it warns on constraint check.
We should probably have the error message say that this is because of nullability.
# Warn on nullable reference type argument when T has non-nullable reference type or interface type constraint
``` c#
static void F<T>(T t) where T : IDisposable { }
F(maybeNull); // warning: Stream? does not satisfy 'IDisposable' constraint
```
Yes, warn for same reasons.
We also want to warn (or error) on inconsistent nullability in constraints. Specifically if one constraint is known to be non-nullable and another is known to be nullable.
What about
``` c#
class C<T, U, V> where T: class? where U : T, IDisposable where V : T, IDisposable?
{
// Fine
}
class D<T, U, V> where T: class where U : T, IDisposable where V : T, IDisposable?
{
// Warn on V
}
```
``` c#
... where T : Node<T>?
... where T : Node<T?> // both currently allowed, but not where T : Node<T?>?
... where T : class, INode<T?>
... where T : class?, INode<T>?
```
``` c#
static void F<T>(T t) where T : IFoo<string?> { }
IFoo<string> foo;
F(foo); // warning, unless IFoo is covariant
```
Another kind of clash:
``` c#
interface IBar : IFoo<string> {}
static void F<T>(T t) where T : IFoo<string?>, IBar { }
```
We want to warn on this: maybe find shared base interfaces between the two constraints, and check if they have consistent nullability.
Other, slightly more complex example, same conclusion:
``` c#
interface IBar : IFoo<string?> {}
static void F<T, U>(T t) where T : IFoo<U>, IBar where U : class{ }
```
# Allow nullable reference types and interface types as constraints
`where T : Person?, IDisposable?`
Yes
# Allow `class?` constraint
Yes
How do we express in metadata?
Let's put top-level nullability as an attribute on the type parameter itself, rather than on the constraints. We can noodle more on this later.
# Allow `object` constraint
``` c#
static void F<T>(T t) where T : object { }
F(maybeNull); // warning: constraint violated
```
## Need to talk about relationship to value types soon
``` c#
int? i = null;
object o = i;
o.ToString();
```
# Allow `object?` explicitly?
It's the "most general" constraint that is implied by unconstrained generics. Today we disallow `object` because of that.
We don't know that this is a terribly useful restriction today, but we'll keep doing it (now with `object?`) unless we get evidence to the contrary.
# Warn on dereference of T when T is unconstrained?
Yes, if a type parameter `T` can be instantiated with a nullable reference type, then we should track null state and warn on unguarded dereference.
The warning when occurring on unconstrained generics might suggest using the `object` constraint.
# Warn on assignment to `object` of unconstrained `T`?
Yes. This can be a `W` (cosmetic) warning when the `object` variable is a local.
# default(T) with unconstrained T
``` c#
T M<T>()
{
T t = default(T); // W warning
return default(T); // safety warning
}
```
This is something completely safe. I don't want it to warn!:
``` c#
T M<T>()
{
var t = default(T);
if (something) t = somethingelse;
if (t != null) WriteLine(t.ToString());
}
```
This could be an argument for allowing `T?` that is not about special methods. Or it is an argument against having the W warnings at all.
Let's keep this example around and revisit. But for now, let's consider `default(T)` to be potentially null, and therefore warn on its unguarded use.
# Annotations
We would like to deal with methods with special null semantics, such as string.IsNullOrEmpty, TryGetValue, Assert.NotNull, Object.Equals, Object.ReferenceEquals.
We'll come back to this later.