96 lines
7.9 KiB
Markdown
96 lines
7.9 KiB
Markdown
# C# Language Design Meeting for May 12th, 2021
|
|
|
|
## Agenda
|
|
|
|
1. [Experimental attribute](#experimental-attribute)
|
|
2. [Simple C# programs](#simple-c-programs)
|
|
|
|
## Quote of the Day
|
|
|
|
- "I've always felt the shotput with the Rubik's Cube should be part of the Olympics"
|
|
|
|
## Discussion
|
|
|
|
Today we took a look at a couple of broader .NET designs that will impact C#, to get an idea of how we feel C# fits into these designs.
|
|
|
|
### Experimental attribute
|
|
|
|
https://github.com/dotnet/designs/blob/main/accepted/2021/preview-features/preview-features.md
|
|
|
|
The first proposal we looked at is the design the runtime team has been working on around preview features. The C# compiler has shipped
|
|
preview features in the compiler ahead of language releases before, but this hasn't been very granular, and we've never shipped a version
|
|
of the runtime (particularly not an LTS!) where some parts of the runtime and language features built on top are actually still experimental.
|
|
Support stories get complicated, particularly when you start mixing installations of LTS versions of .NET 6 and .NET 7 on the same machine.
|
|
For example, we'll be shipping a preview of abstract static members in interfaces in .NET 6, but this implementation will _always_ be a
|
|
preview. It's possible that, for .NET 7, we'll move the feature out of preview, and the version of the C# compiler in VS installed at that
|
|
point would no longer consider abstract statics to be a preview language feature, even if the project itself is targetting .NET 6. To solve
|
|
this, the runtime will introduce a new attribute, detailed in the preview feature proposal, which marks APIs and elements of RuntimeFeature
|
|
that should be considered preview in this version of the runtime, and then require that the consuming library be marked preview itself.
|
|
Where this requirement comes from is one of the open questions in this meeting: should it come from an analyzer or from the compiler itself?
|
|
|
|
The analyzer approach is initially attractive because it is easier to implement. Roslyn's analyzer infrastructure, particularly with the
|
|
investments around both the symbol analyzer model and IOperation, means that it is possible to implement this analyzer almost entirely
|
|
language-independently, while a compiler feature would have be implemented in each compiler separately. It is also significantly easier to
|
|
maintain an analyzer: turning off analyzer errors is possible for false-positives while bugs are patched, while compiler errors are impossible
|
|
to disable. However, this flexibility does come with downsides: it's possible to disable the analyzer for _real_ positives and ship in an
|
|
unsupported state, and potentially cause downstream dependencies to take advantage of preview features unintentionally. There's also no
|
|
guarantees that users actually enable the analyzer, as they might just disable analyzers for any particular reason. Despite these concerns,
|
|
we think that an analyzer is a good path forward, at least initially. We can use an analyzer in .NET 6 to iron out the semantics of how the
|
|
feature works, and look at putting the logic into the compiler itself in a future version.
|
|
|
|
In particular, there are some interesting semantics that still need to be worked out. Should APIs be allowed to introduce or remove previewness
|
|
when overriding or implementing a member? For example, `System.Decimal` already has a `+` operator today, and it will be implementing the
|
|
preview numeric interfaces that define the `+` abstract static operator. The `+` on System.Decimal is not preview today, nor should it be in
|
|
.NET 6, but it _will_ be implementing the preview `+` operator. Explicit implementation is also not always possible for these operators, as
|
|
we will have asymmetric operator support in the math interfaces that get unified with a symmetric operator later in the hierarchy, so we
|
|
can't rely on enforcing explicit implementation to solve this problem. On the opposite side of this problem, allowing adding of previewness
|
|
at more derived API level is problematic, because the user could be calling a less-derived method and therefore accidentally taking advantage
|
|
of a preview feature.
|
|
|
|
Finally, there is some IDE-experience work to think through. While we do want these APIs to show up in places like completion and refactorings,
|
|
we would also like to make sure we're not accidentally opting users into preview features that then break their build totally unexpectedly. We
|
|
think there is design space similar to our handling of `Obsolete`, such as marking things preview in completion lists.
|
|
|
|
#### Conclusion
|
|
|
|
We will proceed with an analyzer for now and look to move that logic into the compiler at a later point, if we think it makes sense. More
|
|
design is needed on some parts of the feature, but it doesn't require direct involvement of the LDM.
|
|
|
|
### Simple C# programs
|
|
|
|
https://github.com/dotnet/designs/pull/213
|
|
|
|
Finally today, we looked at "simple" C# programs. We take simple here to mean programs that don't have a lot of complex build logic, and are
|
|
possibly on the smaller side code-wise. Simple does _not_ necessarily mean "Hello, World!" and nothing else. While we are interested in the
|
|
intro experience, we additionally think there is opportunity to expand to address a market that has traditionally had a bunch of friction to
|
|
use C# in today.
|
|
|
|
C# has historically had a focus on very enterprise scenarios: professional developers working on larger projects using a dedicated IDE. Our
|
|
user studies have shown that this workflow isn't what many newer users are expecting, particularly if they're coming from scripting languages
|
|
like Go, Javascript, or Python. These users instead expect to be able to simple make a `.cs` file and run it, with potentially more ceremony
|
|
as they start adding more complex dependencies or other scenarios. Other expectations exist (such as repls), but our studies have shown that
|
|
this is the most popular. An important part of our task here will be figuring out where that "more ceremony" step lies, what that additional
|
|
ceremony will look like, and how it will interact with any additions we make to the language (how project-file based projects interact with
|
|
`#r` directives, for example).
|
|
|
|
Investing in tooling that puts NuGet directives in C#, as well as potentially `#load` or other similar file-based directives, is going to
|
|
necessitate that we reconcile file structure and project structure in C#. Today, the contents of C# files are very intentionally independent
|
|
of their locations on disk: file structure is handled by the project file, and project structure is handled by `using` directives and
|
|
namespace declarations. `#r` to local NuGet packages or `#load` to add other `.cs` files would blur the line here.
|
|
|
|
Another important consideration of these directives is how complex we want to let them get. At the extreme end, these directives could be
|
|
nested inside `#if` directives, which starts to necessitate a true preprocessing step that the SDK tooling will need to understand and perform.
|
|
Today, preprocessor directives in C# don't have massive effects, and they can be processed in line with lexing. There are restrictions we can
|
|
look at for where to allow `#r` and similar directives, and deciding on those restrictions will help inform where exactly that additional
|
|
ceremony will land. For example, we could require that all of these directives must be the first things in a file, with nothing preceding
|
|
them. This would ensure that conditional NuGet references are that cliff of complexity that requires a project file.
|
|
|
|
Finally, how much of the project settings do we think is reasonable to control in a .CS file? Is it reasonable to set language version or TFM
|
|
in a file? What about output settings such as dll vs exe, or single-file and trimming settings? We don't have answers for these today, and
|
|
some of these answers will be driven by discussions with the SDK teams, but they're all part of determining where the cliff of complexity
|
|
will land.
|
|
|
|
#### Conclusion
|
|
|
|
Overall, we're extremely excited to take this challenge on, and look forward to working through this design to find the edges.
|