Skip to content

Latest commit

 

History

History
61 lines (41 loc) · 4.4 KB

LDM-2023-01-18.md

File metadata and controls

61 lines (41 loc) · 4.4 KB

C# Language Design Meeting for January 18th, 2023

Agenda

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

#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 ValueTuples 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 awaiting 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 awaited 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 awaiting 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

#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:

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: interfaces, and enums. interfaces have similar justification to classes and structs, where a partial interface could add new attributes and generate the rest. enums 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 enums here where no other type declaration is.

Conclusion

Allow semicolon bodies for all type declarations.