Added LDM notes for February 3rd, 2021
This commit is contained in:
parent
c449de91e9
commit
34da56b1df
78
meetings/2021/LDM-2021-02-03.md
Normal file
78
meetings/2021/LDM-2021-02-03.md
Normal file
|
@ -0,0 +1,78 @@
|
|||
# C# Language Design Meeting for Feb 3rd, 2021
|
||||
|
||||
## Agenda
|
||||
|
||||
1. [List patterns on `IEnumerable`](#list-patterns-on-ienumerable)
|
||||
2. [Global usings](#global-usings)
|
||||
|
||||
## Quote of the Day
|
||||
|
||||
- "If the teacher doesn't show up, class is dismissed, right?" "Who is the teacher in this scenario?"
|
||||
|
||||
## Discussion
|
||||
|
||||
### List patterns on `IEnumerable`
|
||||
|
||||
https://github.com/alrz/csharplang/blob/list-patterns/proposals/list-patterns.md
|
||||
|
||||
Today, we discussed what the behavior of list patterns should be for `IEnumerable`, and specifically how much of list patterns
|
||||
should be able to operate on enumerables. There are multiple competing factors here that we need to take into consideration.
|
||||
|
||||
1. `IEnumerable`s can be infinite. If a user were to attempt to match the count of such an enumerable, their code hangs.
|
||||
2. `IEnumerable`s can be expensive. Likely more common than the infinite case, enumerable can be a DB query that needs to run
|
||||
off to some data server in the cloud when queried. We absolutely do not want to enumerate these multiple times.
|
||||
3. We do not want to introduce a new pitfall of "Oh, you're in a hot loop, remove that pattern match because it'll be slower
|
||||
than checking the pattern by hand".
|
||||
|
||||
All of that said, we do think that list patterns on enumerables are useful. While this can be domain specific, efficient enumeration
|
||||
of enumerables is relatively boilerplate code and with some smart dependence on framework APIs, we think there is a path forward.
|
||||
For example, the runtime just approved a new API for [`TryGetNonEnumeratedCount`](https://github.com/dotnet/runtime/issues/27183),
|
||||
and in order to make the pattern fast we could attempt to use it, then fall back to a state-machine-based approach if the collection
|
||||
must be iterated. This would give us the best of both worlds: If the enumerable is actually backed by a concrete list type, we don't
|
||||
need to do any enumeration of the enumerable to check the length pattern. If it's not, we can fall back to the state machine, which
|
||||
can do a more efficient enumeration while checking subpatterns than we could expose as an API from the BCL.
|
||||
|
||||
For the state machine fallback, we want to be as efficient as possible. This means not enumerating twice, and bailing out as soon
|
||||
as possible. So, the pattern `enumerable [< 6] { 1, 2, 3, .., 10 }` can immediately return false if it gets to more than 6 elements,
|
||||
or if any of the first 3 elements don't match the supplied patterns.
|
||||
|
||||
Finally, on the topic of potentially infinite or expensive enumerations, they are an existing problem today. The BCL exposes a `Count`
|
||||
API, and if you call it on a Fibonacci sequence generator, your program will hang. Enumerating db calls is expensive, regardless
|
||||
of whether we provide a new, more succinct form or not. In these cases, users generally know what they're working with: it's not a
|
||||
surprise that they have an infinite enumerable, they've very likely already done a `Take` or some other subsequence mechanism if they're
|
||||
looking for "the last element from the end". By having these patterns, we simply allow these users to take advantage of a generation
|
||||
strategy that's as efficient as they could write by hand, with much clearer intent. As long as the enumeration has a specific pattern
|
||||
that users can reason about, it's an overall win.
|
||||
|
||||
#### Conclusion
|
||||
|
||||
We'll proceed with making a detailed specification on how `IEnumerable` will be pattern matched against. We're ok with taking advantage
|
||||
of BCL APIs here, including `TryGetNonEnumeratedCount`, and are comfortable working with the BCL team to add new APIs if existing ones
|
||||
don't prove complete enough for our purposes.
|
||||
|
||||
### Global usings
|
||||
|
||||
We started this by looking at a prototype of how ASP.NET is looking to reduce ceremony in their templates with a framework called
|
||||
Feather, which can be seen [here](https://github.com/featherhttp/framework). The hello world for this code is 12 lines long: 6 lines
|
||||
of actual code, 3 newlines, and 3 lines of usings. As apps get more complicated, these usings tend to grow quite quickly, and they're
|
||||
all for the types of things that often boil down to "I want to use the async feature from C# 5, LINQ from C# 3, generic collections
|
||||
from C# 2, and I want to build an ASP.NET application". This hints at a related, but orthogonal, using feature: recursive usings. For
|
||||
example, `using System.*` would bring in all namespaces under `System`, or `using Microsoft.AspNetCore.*` would bring in all namespaces
|
||||
under `Microsoft.AspNetCore`. However, such a feature wouldn't really solve the issue in question here, which is "how can specifying
|
||||
the SDK in use ensure that I get the ability to use the features of that SDK by default?"
|
||||
|
||||
We have 2 general approaches here: use the project file as the place where implicit usings go, or allow a source file to include them.
|
||||
Both approaches have several pros and cons. In a project file works more natively for an SDK, as they can just define a property. The
|
||||
SDK does define an AssemblyVersion.cs today, but this feature is potentially more complicated than that. The project file is also
|
||||
where we tend to put these types of global controls, like nullable or checked. On the other hand, project files are very hard to tool,
|
||||
as MSBuild is a complicated beast that can do arbitrary things. Artificial restrictions on the feature, like requiring that it appear
|
||||
directly in the project file and not in some other targets file, severely limits the usefulness of the feature across solutions. Source
|
||||
files as the solution provide an easily-toolable experience that feels more C#-native, but potentially encourages these usings to be
|
||||
spread out in many locations. Razor has a `_ViewImports.cshtml` file that handles this problem for Razor files, but we don't think this
|
||||
maps well to the solutions we're discussing for C#: it only allows the one file, and is in some ways the "project file" for the rest
|
||||
of the cshtml files in the solution as it provides things like the namespace of the rest of the pages.
|
||||
|
||||
#### Conclusion
|
||||
|
||||
We're split right down the middle here between project file and C# files. We'll revisit this again very shortly to try and make
|
||||
progress on the feature.
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
## Schedule when convenient
|
||||
|
||||
- Namespace directives
|
||||
|
||||
## Recurring topics
|
||||
|
||||
- *Triage championed features and milestones*
|
||||
|
@ -19,16 +21,17 @@
|
|||
|
||||
- Statics in interfaces
|
||||
|
||||
## Feb 3, 2021
|
||||
|
||||
- Global usings
|
||||
- Namespace directives
|
||||
- IEnumerable and Length patterns - (Fred)
|
||||
|
||||
# C# Language Design Notes for 2021
|
||||
|
||||
Overview of meetings and agendas for 2021
|
||||
|
||||
## Feb 3, 2021
|
||||
|
||||
[C# Language Design Notes for February 3rd, 2021](https://github.com/dotnet/csharplang/blob/master/meetings/2021/LDM-2021-02-03.md)
|
||||
|
||||
1. List patterns on `IEnumerable`
|
||||
2. Global usings
|
||||
|
||||
## Jan 27, 2021
|
||||
|
||||
[C# Language Design Notes for January 27th, 2021](https://github.com/dotnet/csharplang/blob/master/meetings/2021/LDM-2021-01-27.md)
|
||||
|
|
Loading…
Reference in a new issue