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