Back to Csharplang

C# Language Design Meeting for May 1st, 2024

meetings/2024/LDM-2024-05-01.md

latest2.9 KB
Original Source

C# Language Design Meeting for May 1st, 2024

Agenda

Quote of the Day

  • "I'm going to release you all early. I know your parents aren't here to pick you up yet." "So we should all go to the playground and stay there?" ... "Or if we're older we go to the library."

Discussion

Adjust binding rules in the presence of a single candidate

https://github.com/dotnet/csharplang/pull/8027

Last time, we looked at an adjustment to the rules of dynamic binding that would see the compiler issue more errors for cases where dynamic operations could be resolved as never possible to work at compile-time. The new proposal suggests that, for assignments, we can statically bind during compile and issue errors for scenarios where no valid assignment is possible. For example, we'd error for this scenario:

cs
var c2 = new C2();
c2.M(0, 1);

public class C2
{
    public void M(dynamic d, object o)
    {
        this[d] += o; // Would error, += cannot be applied to operands of type Base and object
    }

    Base this[int x]
    {
        get => new Base();
        set {}
    }
}

class Base { }

It was hoped that this narrow restriction, only affecting assignments and not affecting invocations, would be small enough to provide meaningful compile-time errors while avoiding runtime breaks. However, we were able to come up with several counterexamples for this scenario. One such example:

cs
// Succeeds and prints 1
var c2 = new C2();
c2.M(0, 1);

public class C2
{
    public void M(dynamic d, object o)
    {
        this[d] += o; // Succeeds today because `Derived.operator +` is found at runtime by dynamic
    }

    Base this[int x]
    {
        get => new Derived();
        set {}
    }
}

class Base { }

class Derived
{
    public static Derived operator+(Derived x, object y)
    {
        System.Console.Write(1);
        return x;
    }
}

The proposed rules would break this scenario, because Base has no + operator; at runtime, though, the dynamic binder would see that the return of this[d] is a Derived, and find the operator it defines. We're also concerned about interactions with IDynamicMetaObjectProvider, as those can also break in similar fashions with this scheme. Given these issues, we don't think that we're comfortable with even this narrow set of errors. Ultimately, use of dynamic in these scenarios intentionally moves errors from compile-time to runtime, and we don't think that the potential for breaking existing code is worth the additional validation here. We'll shelve this change for now, and revisit in the future if we have a better idea for how to avoid potential breaks.

Conclusion

Proposal is rejected.