csharplang/meetings/2020/LDM-2020-11-11.md
2021-02-03 17:47:44 -08:00

7.1 KiB

C# Language Design Meeting for November 11th, 2020

Agenda

  1. IsRecord in metadata
  2. Triage
    1. AsyncMethodBuilder
    2. Variable declarations under disjunctive patterns
    3. Direct constructor parameters
    4. Always available extension methods
    5. Allow nameof to access instance members from static contexts
    6. Add await as a dotted postfix operator

Quote of the Day

  • "Alright, I'm going to make an analogy to social security here."

Discussion

IsRecord in metadata

https://github.com/dotnet/csharplang/issues/4121

We discussed a few different ways to tackle this issue, which relates to customers depending on the presence of the <Clone>$ method as a way of determining if a type is a record or not. First, there are theoretically some ways we could retrofit this method to work as an identifying characteristic, such as by marking <Clone>$ methods on non-record types, instead of marking the record types in some manner. However, this approach would have to square with struct records, which may or may not have that special method. We also need to understand some of the dependent scenarios better: we understand the IDE scenario pretty well, we want to be able to have QuickInfo and metadata-as-source reflect the way the type was declared. However, we don't have an understanding of the EF scenario, and what it would want to do for, say, a non-record class that inherits from a record type. Finally, we considered time frames, and came to the conclusion that the proposed solution would work fine if we wait until C# next to introduce it, and does not require being rushed out the door to be retconned into C# 9: the proposed solution is backwards compatible, as long as it is introduced at the same time as class/record cross inheritance.

Conclusion

Into the Working Set, we'll consider this issue in conjunction with class/record cross-inheritance.

Triage

AsyncMethodBuilder

https://github.com/dotnet/csharplang/issues/1407

We generally like this proposal, as it solves a real need in the framework while creating a generalized feature that can be plugged into more libraries. We did have a couple of questions come up:

  1. Should we allow this on just the method, or also the type/module level? This seems to be similar to SkipLocalsInit, and could be tedious to rep-specify everywhere.
  2. Can this solve ConfigureAwait? We don't think so: this controls the method builder, not the meaning of awaits inside the method, so while it could potentially change whether a method call returns a task that synchronizes to the thread context by default, it could only do that for methods defined in your assembly, which would just lead to confusing behavior.
Conclusion

Triaged into the Working Set, we'll work through the proposal in a full LDM session soon.

Variable declarations under disjunctive patterns

https://github.com/dotnet/csharplang/issues/4018

We like this proposal. There are a couple of open issues/questions that need to be addressed:

  1. We need a rule that says when you are allowed to redeclare existing variables. It needs to cover multiple switch case labels, while also not permitting things declared outside the switch label to be redeclared.
  2. How identical do the types need to be? Are nullability differences permitted? ie, are (object?, object) and (object, object?) the same for the purposes of this feature? It seems like they may have to be.
Conclusion

Triaged into the Working Set. We'll take some time and consider these questions, and we should also consider alternatives at the same time, such as an into pattern that would allow a previously-declared variable to be assigned in a pattern, including ones declared outside a pattern.

Direct constructor parameters

https://github.com/dotnet/csharplang/issues/4024

We discussed this feature during our last look at primary constructors, and our conclusion is that we need to explore the space more fully with both features in mind. There are concerns about abstraction leaks, particularly with property casing.

Conclusion

Triaged into the Working Set, to be considered in conjunction with primary constructors.

Always available extension methods

https://github.com/dotnet/csharplang/issues/4029

There was some strong negative reaction to this proposal. However, presented another way it's more interesting: users who use var need to include usings they otherwise do not need in order to access these types of extension methods, whereas users who do not use var will already have the relevant using in scope, and will thus see these extension methods. These types of methods are also often ways of working around various C# limitations, such as lack of specialization, and would naturally be defined on the type itself if it was possible.

We are concerned with doing anything in this space with extension everything/roles/type classes on the horizon, as we don't want to change extension methods in a way that we'd regret with those features.

Conclusion

Triaged into the backlog. We'll consider this in conjunction with extension everything.

Allow nameof to access instance members from static contexts

https://github.com/dotnet/csharplang/issues/4037

There is some feeling that this is basically just a bug in the spec (or is just an area where it's not super clear, and it's a bug in the implementation). We do think this is generally good: yes, the scenario could just use string.Length, but that is not really what the user intended. They wanted the Length property on P, and if P changes to a different type that no longer has Length, there should be an error there. Without this, the cliff that nameof tries to solve is just moved further, not removed.

Conclusion

Triaged into Any Time. We'd accept a community contribution here: it needs to only permit exactly this scenario, not allow any new types of expressions in nameof.

Add await as a dotted postfix operator

https://github.com/dotnet/csharplang/issues/4076

The LDT has very mixed reactions on this. While we are sympathetic to the desire to make awaits more chainable, and the . can be viewed as the pipeline operator of the OO world, we don't think this solves enough to make it worth it. Chainability of await expressions isn't the largest issue on our minds with async code today: that honor goes to ConfigureAwait, which this does not solve. We could go a step further with this form by making it a general function that would allow true/false parameters to control the thread context behavior, but given our mixed reaction to the syntax form as a whole we're not optimistic about the approach. A more general approach that simplified chaining generally for prefix operators would be more interesting.

Conclusion

Rejected. We do like the space of improving await, but we don't think this is the way.