114 lines
6.4 KiB
Markdown
114 lines
6.4 KiB
Markdown
|
# C# Language Design Meeting for July 20th, 2020
|
||
|
|
||
|
## Agenda
|
||
|
|
||
|
1. [Finishing Triage](#finishing-triage)
|
||
|
a. [Extend with expression to anonymous type](#Extend-with-expression-to-anonymous-type)
|
||
|
b. [Required properties](#Required-properties)
|
||
|
c. [Shebang support](#shebang-support)
|
||
|
2. [Private reference fields in structs with `SkipLocalsInit`](#Private-reference-fields-in-structs-with-`SkipLocalsInit`)
|
||
|
|
||
|
## Quote of the Day
|
||
|
|
||
|
"If you go get a beer from the fridge or wherever you keep them and drink it right now, I'll refund you."
|
||
|
|
||
|
## Discussion
|
||
|
|
||
|
### Finishing Triage
|
||
|
|
||
|
#### Extend with expression to anonymous type
|
||
|
|
||
|
https://github.com/dotnet/csharplang/issues/3530
|
||
|
|
||
|
We don't see any reason why we couldn't extend `with` expressions to handle anonymous types, and we universally support
|
||
|
the idea. We do see room for further improvement as well. Struct types should be generally possible to `with`, and in
|
||
|
particular tuples should feel first class here. Some other ideas for future improvements that we'll need to keep in mind
|
||
|
when designing anonymous types is an ability to specify a `withable` constraint: perhaps that's a thing we could do via
|
||
|
typeclasses, but if that's a thing that should be specifiable then we'll want to make sure that whatever we do for structs
|
||
|
and anonymous types works well with it.
|
||
|
|
||
|
##### Conclusion
|
||
|
|
||
|
Triaged into C# 10 for discussion with the other `with` enhancements
|
||
|
|
||
|
#### Required properties
|
||
|
|
||
|
https://github.com/dotnet/csharplang/issues/3630
|
||
|
|
||
|
A smaller group is currently fleshing this proposal out in the direction of initializer debt, and is looking to talk more
|
||
|
about it in the next few months.
|
||
|
|
||
|
##### Conclusion
|
||
|
|
||
|
Triaged for C# 10.
|
||
|
|
||
|
#### Shebang support
|
||
|
|
||
|
https://github.com/dotnet/csharplang/issues/3507
|
||
|
|
||
|
This is part of the next step in the C# scripting discussion. In particular, this proposal details just one, very small
|
||
|
piece of the puzzle here, namely the ability have a C# file startup an environment. There is significantly more work to
|
||
|
be done in the language and tooling to effectively modernize the loose-files support for C#. Today, C# code has a core
|
||
|
concept that cs files themselves do not contain information about the runtime environment. They don't specify the target
|
||
|
runtime, nuget dependencies, where tools can be found, or anything else similar (beyond some `#ifdef` blocks). Supporting
|
||
|
this would be intentionally eroding this aspect, which we need to make sure we're doing with intention and design. There
|
||
|
is support among LDT members for this scenario, so we'll continue to look at.
|
||
|
|
||
|
##### Conclusion
|
||
|
|
||
|
Triaged into C# 10 for discussion. We acknowledge that we may well not ship anything in this space as part of C# 10, but
|
||
|
we want to start discussing possible futures here in the coming X months, not X years.
|
||
|
|
||
|
### Private fields in structs with `SkipLocalsInit`
|
||
|
|
||
|
https://github.com/dotnet/csharplang/issues/3431
|
||
|
|
||
|
Proposal 1: https://github.com/dotnet/roslyn/issues/30194#issuecomment-657858716
|
||
|
Proposal 2: https://github.com/dotnet/roslyn/issues/30194#issuecomment-657900257
|
||
|
|
||
|
This topic was brought up last week when we realized there was a potential hole in `SkipLocalsInit` with definite
|
||
|
assignment, where we realized it's possible to observe uninitialized memory via private fields. When importing metadata,
|
||
|
the native compiler ignored private fields, including private fields in structs, and did not require them to be considered
|
||
|
definitely assigned before usage. This behavior was preserved when we implemented Roslyn, as attempting to break it was
|
||
|
too large of a change for organizations to adopt. Both of these proposals ensure that, with `SkipLocalsInit` on a method,
|
||
|
it's considered an error to not definitely assign here, which was fine with LDM as this is a new feature and cannot break
|
||
|
anyone. We then looked at the differences between the two proposals, namely whether the definite assignment diagnostic
|
||
|
should be a warning or an error when users opt into to a new warning wave. We found the arguments around incremental
|
||
|
adoption compelling: we don't want users to be blocked off from adopting new warning waves and making their code at least
|
||
|
a little safer by issuing errors that cannot be ignored. If users want to ensure that these warnings are fixed in their
|
||
|
code, they can use `warnAsError` to turn these specific warnings or all warnings into errors, as you can today.
|
||
|
|
||
|
#### Conclusion
|
||
|
|
||
|
Proposal 1 has been chosen:
|
||
|
|
||
|
1. If a method has the [SkipLocalsInit] attribute, or the compilation has the "strict" feature enabled, we use the strong
|
||
|
version of analysis for its body. Otherwise
|
||
|
2. If a sufficiently high /warnversion (>= 5) is enabled, we run the strong version of analysis, and
|
||
|
a. If it reports no diagnostics, we are done.
|
||
|
b. If it reports diagnostics, we run the weak version of analysis. Errors that are common to the two runs are reported
|
||
|
as errors, and errors only reported by the strong version are downgraded to a warning.
|
||
|
3. Otherwise we run the weak version of analysis.
|
||
|
|
||
|
### Future record direction
|
||
|
|
||
|
See https://github.com/dotnet/csharplang/issues/3707 for the full list. We briefly went through the list here to gauge
|
||
|
support from LDT members on the various proposals. We didn't get particularly in depth on any one part, but some
|
||
|
highlights:
|
||
|
|
||
|
* `init` fields and methods - We rejected these in 9, deciding to wait for community feedback. We believe this is still
|
||
|
the right decision, and want to hear user scenarios before proceeding further.
|
||
|
* Final initializers - We briefly entertained the idea of having an `init { }` syntax to guarantee that a block is called
|
||
|
after a method. This was later rejected as too complicated after design review. Like `init`, we need to get a better
|
||
|
handle on the user scenarios.
|
||
|
* Required members - We have broad support for doing something in this space.
|
||
|
* Factores - We have broad support for doing something in this space.
|
||
|
* User-defined cloning - Will likely need to be designed hand-in-hand with factories
|
||
|
* Cross-inheritance between records and non-records - part of the initial record goal was that `record` is pure syntactic
|
||
|
sugar. If that's still a goal, then we need to do more work here.
|
||
|
* Generalized primary constructors - Mixed support here. We need to do more design work.
|
||
|
* Primary constructor bodies - Might be done for the former. We need to flesh this out so we can determine how to apply
|
||
|
attributes to record constructors.
|
||
|
* Discriminated unions - We need to determine whether this will be a simple syntactic shorthand for a general sealed type
|
||
|
hierarchy feature, or if this will be the only way to declare such hierarchies.
|