# C# Language Design Meeting for October 13th, 2021

## Agenda

1. [Revisiting DoesNotReturn](#revisiting-doesnotreturn)
2. [Warning on lowercase type names](#warning-on-lowercase-type-names)
3. [Length pattern backcompat](#length-pattern-backcompat)

## Quote of the Day

- "You're opinionated against opinionated features" "I see the irony, but..."

## Discussion

### Revisiting DoesNotReturn

https://github.com/dotnet/csharplang/issues/5231

We wanted to revisit this design decision after a few years and some reports of customer confusion around this attribute.
While it's not an overwhelming amount of confusion, it's non-zero. When last this attribute was
[discussed](../2019/LDM-2019-07-10.md#doesnotreturn), we decided that we couldn't use it to broadly enforce the concept of
a method that does not return: instead, it could only influence nullable analysis. Much like the rest of the features
nullable analysis added, it cannot make strong guarantees. Changing this behavior now wouldn't really solve any of the
issues with it, as code exists today that is attributed with `DoesNotReturn` that cannot be statically-proven to never
return.

Instead, we think that https://github.com/dotnet/csharplang/issues/538 would be needed to make progress here: once we have
a `never` type, these guarantees can be statically proven, the runtime can abort if an instance of `never` is ever created,
and we can introduce a warning wave at that point to suggest that methods attributed with `DoesNotReturn` should have a
return type of `never`. This would prevent us from introducing another loose generalized analysis that can't be statically
relied upon before later adding a more strict version that can be relied upon.

#### Conclusion

No changes.

### Warning on lowercase type names

https://github.com/dotnet/roslyn/issues/56653

This is an issue that we've been kicking around for a long time to try and protect language design space, and we've recently
started to make more breaks in this space. For example, C# 9 introduced `record` as a type specifier, and made it illegal
to declare a type named `record` without escaping it. We've heard no complaints about this change, and this has given us
more confidence to go ahead with a warning in this area.

And important point is that this change is _not_ motivated by style. C# as a language tries hard not to be opinionated on
coding styles; we have defaults for formatting that are part of VS and `dotnet new editorconfig`, but these are highly
customizable and we try not to punish users for taking advantage of that customizability. Instead, this warning is about
trying to ensure that C# has design space to work with that doesn't break users who upgrade to new C# versions. This goal
means we're trying to help 2 sets of customers:

1. People who author types with lowercase names. These authors should be informed that they could be causing issues for their
users by using a lowercase name.
2. People who use types with lowercase names. These users should be informed that, if a future version of C# adds the type
they're using as a keyword, their code could change meaning or no longer compile.

Some other points of consideration we brought up:

* Should we do this for just public types?
    * Answer: we are trying to protect users from both themselves and others. This means we want to warn everywhere.
* Should we have codefixers to prepend `@` in front of identifiers?
    * Ultimately this will be up to the IDE team, but we think that each set of customers above should have a different answer
    here. For set 1, we don't want to encourage this type of naming, even when escaped, so we would not want to see a fixer on
    type definitions. However, for set 2, they're just using a type someone else defined. We don't want to unreasonably punish
    them, so a fixer to prepend `@` for these users seems appropriate.

#### Conclusion

The compiler will issue a diagnostic for types named all lowercase letters. We may simplify that to be just types named all
ASCII lowercase characters, to avoid worrying about lowercase characters in other encodings and because we don't believe C#
will be interested in adding non-ASCII keywords.

### Length pattern backcompat

https://github.com/dotnet/csharplang/issues/5226

There are user tradeoffs here. In our previous discussion, we expressed a desire to have a similar ability to nullable, whereby
a missing negative Length test would not count against exhaustive matching, but if one was present it would then cause negative
values to need to be fully matched against. However, describing these rules and implementing them is quite complex, to the point
that we are concerned both about the code complexity and the explanation of the rules to users. We therefore think that the
simpler implementation, where we just consider the domain of `Count`/`Length` for indexable and countable types to be non-negative
integers, to be the better approach.

While we were discussing this, we also brought up the inherent flaw of structural typing, where types that do not satisfy the contract
of indexable and countable but still have the correct shape end up having incorrect behavior. For example, the BCL recently approved
a `Vector2<T>` type. That type has an indexer, and it has a property called `Length` that returns an integer. This `Length` property
is not the length of the Vector: that's always 2. Instead, this is the euclidean length of the vector, ie the distance from (0, 0).
Our knowledge of `Length` and combining subsumption with list patterns will behave incorrectly here. However, we note that this type
is _already_ broken with structural typing in C# today. For example, `vector[^1]` would work on the type, but it wouldn't have the
expected behavior. Instead of trying to solve something here, we instead think we should see what other uses customers have for opting
out of structural typing, and started a discussion about that [here](https://github.com/dotnet/csharplang/discussions/5278).

#### Conclusion

We will accept the existing breaking change on subsumption for indexable and countable types, and treat Length/Count on types that are
both indexable and countable as if they can _only_ have non-negative values. We would like to get this change in preview sooner
rather than later so that we can receive feedback on the change.
