# C# Language Design Meeting for January 18th, 2023

## Agenda

- [Nullable post-conditions and `async`/`await`](#nullable-post-conditions-and-asyncawait)
- [Semi-colon bodies for type declarations](#semi-colon-bodies-for-type-declarations)

## Quote of the Day

- "I guess if I want to stay consistent with myself and not be a hypocrite for the third time today." "You're counting the times?" "Yeah... I don't want to go for the hat trick."

## Discussion

### Nullable post-conditions and `async`/`await`

https://github.com/dotnet/csharplang/issues/6888

We took a look at a proposal around enhancing nullable support for `async` methods that return `Task`-like types, as existing nullability attributes are often incorrectly
applied for this type of method. There are some immediate concerns that come to mind:

1. There are a lot of methods that defer awaiting a `Task` or `Task`-like type until after the returned thing. For example, `ConfigureAwait`, `ValueTask.AsTask`, `Task.WhenAll`,
   user libraries to add awaiters to `ValueTuple`s of tasks, etc. We could special case the BCL methods in the compiler, but that is a lot of special cases and wouldn't help
   any user-defined `Task`-like types or methods.
2. Some post-condition attributes, such as `NotNull` on parameters, might be checked up front by the method, before it hits an `await`, and be perfectly fine today (particularly
   since `async` methods cannot have `ref` parameters). The proposal currently suggests changing this, but that doesn't seem generally correct.
3. We don't have a good way to know whether a method is `async` today, so we can only use a broad heuristic to determine whether to apply `MemberNotNull` and other attributes
   before or after `await`ing the result. Further, whether or not a method is `async` isn't quite the heuristic we're looking for: what we're actually looking for is whether
   or not the returned `Task`-like type needs to be `await`ed before the nullability conditions are propagated. For example, a helper method to fill in common parameters and
   otherwise pass through a call to another member is very possibly not marked as `async`, but should have the same behavior as the `async` method it's proxying.

Another spitballed proposal gained a bit of traction as we were discussing the above 3 points: adding a new `RequireAwait` property to our nullability attributes, with some
appropriate defaults, and using that to propagate information on nullability. This has some advantages in being very precise, and likely being easy to guide users towards
(the warning for `await`ing without fulfilling a `MemberNotNull` could mention setting that property, for example, or if a user sets that property and doesn't need to we
could warn), and not requiring significant new amounts of metadata to put on every `async` method to mark it as such.

#### Conclusion

This will go back to the working group for now to continue iterating on the above idea and address the other contention points.

### Semi-colon bodies for type declarations

https://github.com/dotnet/csharplang/discussions/6871

There was some initial confusion on this discussion, as the current implementation actually missed the quoted line in the spec forbidding `;` on non-`record` types. Further,
we realized that the spec, as written today, is actually a breaking change; it would make the following code illegal:

```cs
record R1; // Legal today
```

We think there are potential cases where the `;` body would be useful, mainly in `partial` types that have generated implementations. There are some potential concerns with
future interference on top-level statements, as we may someday allow statements to follow type declarations. That would change `class C; {}` from a guaranteed error to
potentially introducing top-level statements in the file, likely causing confusing compilation errors. However, we trust ourselves to handle this when the time comes.

We also considered the two other declaration types that currently do not permit `;` bodies: `interface`s, and `enum`s. `interface`s have similar justification to `class`es
and `struct`s, where a `partial` interface could add new attributes and generate the rest. `enum`s are not allowed to be `partial` today, so it is unlikely to get much use,
but at the same time we don't see a good reason to leave the syntax inconsistent and special case `enum`s here where no other `type` declaration is.

#### Conclusion

Allow semicolon bodies for all type declarations.
