csharplang/meetings/2019/LDM-2019-03-27.md
2019-04-03 23:03:48 -07:00

3.8 KiB

C# LDM Notes for Mar 27, 2019

Agenda

  1. Switch expression syntax

  2. Default interface implementations

    1. Reabstraction

    2. Explicit interface abstract overrides in classes

    3. object.MemberwiseClone()

    4. static int P {get; set} semantics

    5. partial on interface methods

  3. ? on unconstrained generic param T

Discussion

Switch expression syntax

Confirmed that we like

e switch
{
    a => b,
    c => d,
}

Default interface methods

Reabstraction

Implement the interface method with an abstract in an interface, forcing re-implementation of deriving interfaces.

We previously wanted to see a cost for handling it in the runtime and we know have a proposal for that: https://github.com/dotnet/coreclr/pull/23313

Given that, do we want to allow reabstraction?

Conclusion

Assuming the proposed approach, it seems cheap enough. The only question is if the metadata approach is one we want to add to metadata. Right now we're going to say yes to the feature, assuming that the runtime teams can produce the feature. We also want to put this under the runtime feature flag to prevent exposure to older compilers. We should also do the same for features like static members in interfaces.

Explicit interface abstract overrides in classes

Allow abstract interface implementions in a class as well? Not an abstract class method implementing an interface method.

Conclusion

No, we don't see any great use cases.

Is object.MemberwiseClone() accessible in an interface?

In principle, maybe yes, but this member seems particularly problematic. Let's say protected members of object are not accessible.

Is static int P { get; set; } is an auto-property with a compiler-generated backing field?

This seems consistent with the idea that static means sealed by default, but a little strange given that the same syntax without static implies virtual for instance members.

The main problem will be if we allow static virtual/abstract members to be declared in future versions of the language, where this rule doesn't necessarily make sense.

Conclusion

Let's keep the current semantics for now static int P {get; set;} -- this declares a static auto-property. The same goes for static field-like events.

We may revisit this entire area in the future.

Confirm that partial implies private and no access modifier is permitted?

Conclusion

Confirmed.

Nullable reference types

Right now we don't allow the ? annotation for type parameters that we don't know to be non-nullable. There are numerous customer scenarios where people want to do this and are prohibited.

Proposal: T? is similar to the constraint object?, where T remains essentially unconstrained.

class C<T>
{
    T? M(T p1, T? p2)
    {
        if (p2 != null)
            M(p1, null); // error on the `null` because T may be `int`
        if (p2 != null)
            M(p1, default); // OK, because if T is `int`, default is valid
    }
}

The goal is to provide value to the consumer that they must deal with null.

A use case would be

IEnumerable<T> FilterNull<T>(IEnumerable<T?> e)
{
    foreach (var i in e)
    {
        if (i != null)
        {
            yield return e;
        }
    }
}

This would make T? a replacement for the MaybeNullAttribute and would provide value for places you could not use the MaybeNullAttribute, like nested inside generic types. Moreover, attributes are not required to be propagated for overrides or interface implementations, so it's very possible for implementations to drop requirements of their abstract specification.

Conclusion

It does seem like our current approach has significant limitations. We want to look more closely at the customer scenarios, especially around overriding and interface implementation to decide what more we want to do.