Skip to content

Latest commit

 

History

History
64 lines (48 loc) · 4.45 KB

LDM-2024-10-14.md

File metadata and controls

64 lines (48 loc) · 4.45 KB

C# Language Design Meeting for October 14th, 2024

Agenda

Quote of the Day

  • "I know I might be jinxing myself by saying this"
  • "That is not the quote of the day"
  • "I think it would be a little narcissistic if I was my favorite person." "Oh, I would totally say that though. That's why I shouldn't be anybody's favorite, because I'm my favorite person. I'm just a terrible narcissist."
  • "That is also not the quote of the day"

Discussion

Extensions

Champion issue: #5497
Related: https://github.com/dotnet/csharplang/blob/d5b8e7808998024e4aa6b380acdccac30aa03b60/proposals/extensions_v2.md, https://github.com/dotnet/csharplang/blob/1e8255a438517bc3ad067c726c28cfa20cb60f1e/meetings/working-groups/extensions/Compatibility%20through%20coexistence%20between%20extension%20types%20and%20extension%20methods.md

We started today by making sure that everyone has clarity on the different approaches here, devoting the first section of the meeting to that. To help with that, we did an exercise on "converting" LINQ to the respective new forms. The fully compatible version is here, and the least compatible version is here. One thing that this revealed is that there's a difference in philosophy between the two approaches that can be expressed with one letter. The fully compatible version is extensions, where it's a collection of different extensions for various types. The least compatible version is extension, where the user is writing an extension to a given type, extending with a bunch of new members.

One of the things that was brought up in response to this exploration is some concern that maybe the smaller, special cases for slightly different receivers aren't all that uncommon. In a type first approach, each of these small special cases would need its own container name; is it that uncommon that someone might want to have a series of extensions on a generic type, and then also one or two extensions on a specific substitution of that generic type? Should those latter two need their own container to be declared? A member first approach would not require this, but a type first approach would.

We also discussed a bit about generic properties and operators. Adding generics in these locations would be new, and require its own set of designs; what if we avoided this by saying that, if a user wants to put a generic in a place it can't go today, would they need to use a type-centric approach? IE, this would ensure that if a user wanted to want an extension property on List<T>, they would need to use a type extension, and couldn't use a member extension. This was pushed back on as a bad place to put the cliff; the underlying type being generic is a rather arbitrary place to put the line, and it would mean that LINQ couldn't use the member centric approach.

We also looked at possible other forms of syntax. One possibility is a grouping syntax like:

extension E
{
    for IEnumerable<T> where T
    {
        public void M1() { ... }
    }

    for IList<T> where T
    {
        public void M2() { ... }
    }
}

We're unsure what this would imply: would people think that it adds a local type parameter to the methods, or to the containing type, or to some other nebulous area? One of the reasons we're so cautious here is that C# has, to this point, not really messed with the basic metadata of signatures. Type parameters appear in IL exactly where they appear in syntax, parameters appear in IL where they appear in syntax, and so on. The only times we violate this are areas that cannot be part of any public API, such as lambdas and local functions. This would be a new type of modification, so we're wary to start down the path.

Another point we thought about is human compatibility, not just source/binary compatibility. Our users know what modifiers on a parameter mean. They know what method type parameters are. They know how to say that a nullable value is accepted for a given parameter. A type based approach that still allowed adjusting these things would require a new set of syntax to do the same thing that users already know how to do, which isn't great for overall language cohesiveness.

The LDM currently has a slight leaning towards the member based approach here, but plenty of us are still unsure and need more time to think about this. So once again, we will come back to this again in a future meeting.