Back to Csharplang

C# Language Design Meeting for March 24th, 2025

meetings/2025/LDM-2025-03-24.md

latest7.1 KB
Original Source

C# Language Design Meeting for March 24th, 2025

Agenda

Quote(s) of the Day

  • "A syntax question with no hands? That's impossible" ... "I'm going to mis-spell whichever one we choose anyways"
  • "What is snoisnestringsxEg?" "Something happened in liveshare" "Oh, that's not the syntax suggestion?"

Discussion

Dictionary Expressions

Champion issue: https://github.com/dotnet/csharplang/issues/8659
Specification: https://github.com/dotnet/csharplang/blob/bcc689fafe8c2d226b8a3034eb7f66f48495e3aa/proposals/dictionary-expressions.md

Support dictionary types as params type

Question: https://github.com/dotnet/csharplang/blob/bcc689fafe8c2d226b8a3034eb7f66f48495e3aa/proposals/dictionary-expressions.md#support-dictionary-types-as-params-type

Our first topic today is about whether we should support params parameters of dictionary types. This is really a breaking change, as it means that we would potentially use an indexer for a dictionary-like type, where we currently use an Add method. That would likely result in a change from throwing semantics to overwrite semantics, so anyone depending on potential exception behavior will see a behavioral difference. However, that's nothing specific to params, as the same is true for any other collection expression targeted to a dictionary-like type, so we're not concerned about the potential for breaks in this specific corner.

We like this change overall, as it keeps the language simpler, even if the compiler is more complex. The goal we had with expanding params was that anything you could use a collection expression for, you could params. Rather than re-adding the decoder ring of "what can be params'd vs collection expression'ed", we keep the correspondence simple, though at the expense of more compiler developer work.

Conclusion

We will allow use of params on dictionary-like types that can be targeted with a collection expression, and constructing those types will prefer using indexers when available, just like when using a collection expression to create that same type.

Type inference for KeyValuePair<K, V> collections

Question: https://github.com/dotnet/csharplang/blob/bcc689fafe8c2d226b8a3034eb7f66f48495e3aa/proposals/dictionary-expressions.md#type-inference-for-keyvaluepairk-v-collections

We like these proposed rules, as they honor the goal of making KVP as transparent as tuples for these types of targets. There is a minor breaking change here as well, in that type inference can now succeed where it previously failed, meaning that overload resolution may find a nearer applicable method (for example, not going out to extensions because there's now an applicable instance method). We're ok with this type of break, so we'll accept these rules as written.

Conclusion

Rules accepted as written.

Overload resolution for KeyValuePair<K, V> collections

Question: https://github.com/dotnet/csharplang/blob/bcc689fafe8c2d226b8a3034eb7f66f48495e3aa/proposals/dictionary-expressions.md#overload-resolution-for-keyvaluepairk-v-collections

Again, we like the analogy with tuple behavior that is happening here. If we ever run into a scenario where these rules behave differently than tuples would in this same area, we should bring that back for discussion. Otherwise, this is approved.

Conclusion

Rules are accepted as written

Extensions

Champion issue: https://github.com/dotnet/csharplang/issues/8697
Specification: https://github.com/dotnet/csharplang/blob/bcc689fafe8c2d226b8a3034eb7f66f48495e3aa/proposals/extensions.md

Signature conflict rules

Question: https://github.com/dotnet/csharplang/blob/bcc689fafe8c2d226b8a3034eb7f66f48495e3aa/proposals/extensions.md#extension-declaration-validation

The current conflict rules are:

  1. check no conflict within similar extensions using class/struct rules,
  2. check no conflict between implementation methods across various extensions declarations.

Do we stil need the first part of the rules?

First up in extensions, we looked at whether we still need/want both parts of the extension validation rules. The 2 rules serve different purposes. The second rule covers our ability to actually emit method signatures; this is the rule that prevents two extension blocks on different types from having the same static method. The first rule is more about preserving class experience; this is the rule that prevents having a static and instance method with the same name and parameters on the same type. We're hesitant to remove this rule without further examples of where it would be useful, and more exploration of where it would be problematic. This rule also protects things like being unable to declare both int Prop { get; } and void set_P(int i) { } in the same type, and is intended to help prevent concerning consumption scenarios. For example:

cs
class C
{
    static Color Color { get; }

    static void Main()
    {
        Color.M(); // What M is called?
    }
}

class Color
{
    public static void M() {}
    public void M() {}
}

We don't want to mess with validation of so-called Color/Color scenarios now, so absent further evidence, we will keep the rules as is.

Conclusion

Both rules are retained.

extension vs extensions

Question: https://github.com/dotnet/csharplang/blob/bcc689fafe8c2d226b8a3034eb7f66f48495e3aa/proposals/extensions.md#open-issues

Finally today, we have a syntax bikeshed; do we prefer extension or extensions as the keyword? After some debate, we boiled this down to whether we think of the entire block as a true group of items or not. Or, in other words, can we think of moving the parameter down to the individual methods involved and have everything still be exactly the same? We have repeatedly concluded that yes, we do not think of the block as a construct with true meaning; writing out 10 extension blocks on the same underlying type, or grouping them together into a single block, has the same meaning. Therefore, we will continue with the name extension.

We also had a small discussion on what to name the grouping of extension methods itself; we'd like to have a consistent name to use in documentation, in compiler API names, etc. We spitballed a number of options:

  • extension declaration
  • extension block
  • extension body
  • extensions
  • extension group
  • extension container

Only "extension group" and "extension block" attracted any support, and of them "extension block" was heavily preferred, and not disliked by anyone. Therefore, we will call this grouping an "extension block".

Conclusion

The keyword is extension, and the term for the entire set of extension methods is an "extension block".