Back to Csharplang

C# Language Design Meeting for April 16th, 2025

meetings/2025/LDM-2025-04-16.md

latest5.4 KB
Original Source

C# Language Design Meeting for April 16th, 2025

Agenda

Discussion

Extensions-open issues

Champion issue: https://github.com/dotnet/csharplang/issues/8697
Specification: https://github.com/dotnet/csharplang/blob/feb7a075739e81393def6c28ab12eb7b8fdc3bb6/proposals/extensions.md#open-issues

Nullability attributes

Nullability attributes there are some scenarios where the attributes can be placed on the receiver parameter but may feel odd or be inappropriate. For example, if an attribute refers to a method parameter name, like NotNullIfNull, nameof cannot be used. The name of the parameter has to be used.

These attributes can be placed on extension methods with the traditional syntax.

If the attribute includes a name, and the name does not exist on one of the extension methods in the block, it will be ignored. This is consistent with existing behavior for nullability attributes.

Conclusion

We will copy these attributes to the lowered version of the extension method, in the same way we copy any other attribute. We will do no special work for these cases. This avoids breaking changes for people moving from the traditional syntax to the new syntax, except in the case where they used nameof on a parameter other than the receiver parameter.

Should skeleton methods throw NotSupportedException or null?

These methods should not be called, and are marked as special methods. However, NotSupportedException better explains the intent.

Conclusion

NotSupportedException is preferred.

Should we accept more than one parameter in marker method in metadata?

A future version might add more parameters.

Conclusion

This is an implementation detail the team can choose. We do not have scenarios where we would need a second parameter.

Should the extension marker of speakable implementation methods br marked with special name flag?

This is a discussion of the compiler special name. It's up to the compiler to decide what is appropriate.

The implementation method also are currently marked with special name. This may not be appropriate since the implementation has switched to speakable names.

Conclusion

The extension method will be marked with special name.

The implementations method will not be marked with special name.

How should ORPA apply to new extension methods?

Overload resolution priority attribute (ORPA) is meant to differentiate overloads within the same type. For the new extension syntax, what does the notion of the containing type mean?

Using the containing static class, rather than the extension block is compatible with traditional extension methods, and supports the case where extensions with the same receiver parameter appear in different extension blocks. Given:

csharp
public static class Extensions
{
    extension(Type1)
    {
        [OverloadResolutionPriority(1)]
        public void Overload(...)
    }
    extension(Type2)
    {
        public void Overload(...)
    }

    // same bucket/ same "containing type"
    public static void Overload(this Type3, ...)
}

If the containing type is the static Extensions class, all three overloads considered together.

Conclusion

The containing type is the static class. The extension block is not considered.

Should we apply the "inconsistent accessibility" check on the receiver parameter even for static members?

csharp
public static class Extensions
{
    extension(PrivateType p)
    {
        // We report inconsistent accessibility error, 
        //   because we generate a `public static void M(PrivateType p)` implementation in enclosing type
        public void M() { } 

        public static void M2() { } // should we also report here, even though not technically necessary?
    }

    private class PrivateType { }
}

We don't strictly need the to give an error here, but it is not a helpful since the underlying type is inaccessible.

Providing the error would be consistent with the general behavior of accessing private types within public methods.

Conclusion

Apply the "inconsistent accessibility" check on the receiver parameter.

Confirm whether init-only accessors should be allowed in extensions

init accessors are intended for use during object creation and limited to that timeframe.

If we do not do this now, we could do this later. We could consider it in relation to other enhancements to object creation.

Conclusion

We will not allow init accessors on extension properties.

Extension static member lookup on generic types does not work

This is a discussion of Extension static member lookup on generic types does not work.

csharp
static void Test<T>()
{
    T.Hello(); // error CS0704: Cannot do non-virtual member lookup in 'T' because it is a type parameter
}

static class Ext
{
    extension<T>(T)
    {
        public static void Hello()
        {
            Console.WriteLine("Hello");
        }
    }
}

You cannot currently call static members on type parameters in non-extension code. A constraint is available and the static method can be called on the constraint.

Calling static extension members with type parameters may be more useful than non-extensions.

Design work would be needed to support this.

Conclusion

This may be a valuable scenario, but we are going to wait for feedback.