csharplang/meetings/2020/LDM-2020-04-13.md
2020-04-13 13:57:21 -07:00

4.2 KiB

C# Language Design for April 13, 2020

Agenda

  1. Roadmap for records
  2. Init-only properties

Roadmap for records

We want to break down the records feature in a way that gets incremental steps out to partner teams and users sooner, and lets us iterate based on feedback. So what order should we do things in?

Two demanding aspects of records that are certainly important but can probably be done later are:

  1. Primary constructors (allowing positional parameters directly on record types)
  2. Inheritance to and from record types

So a proposal is to split those off in the first iteration of implementation.

Decision

We do need to get those right to ultimately ship the feature! However, we want to start by building a version of records that:

  • Is nominal only (no primary constructor)
  • Inherits from object and can't be inherited from
  • Special-cases with expressions to With methods rather than rely on a "Factory" feature
  • Fully implements value equality

For this to be useful we need the init-only property feature at the same time as well, so that there is some way to create and initialize immutable records.

In subsequent iterations we will

  • Add support for inheritance to records
  • Add primary constructors to records
  • Generalize the With implementation to use factories
  • Decide on and embrace defaults (public by default?) and abbreviations

On parallel tracks we will work on:

  • Factory methods
  • Validators?
  • Mandatory properties?
  • Primary constructors as a general feature?

Init-only members

Init-only properties are the most urgent separate feature to nail down, as the experience of even the first iteration of records depends on them. There are a couple of design decisions still left open; we address them here.

Should we have init-only fields?

Readonly fields today can only be assigned during construction, and only through a this access within the body of the class that declares the field. As we extend the concept of "initialization time" to cover execution of init-only setters (by object initializers in client code) as well as validators (if we add those to the language), it makes sense that readonly fields should be assignable from within those kinds of members as well.

We would not allow readonly fields to be directly assigned in an object initializer, however, as that would undermine the expectation that the class author has full control over how and when they are assigned.

Allowing init-only properties to assign readonly fields would address most of the init-only scenario: An object initializer can be used to set immutable state on the newly created object. A dedicated init-only form of fields is not needed for that. It probably does have valid scenarios (in programming styles where immutable fields are themselves public), but those seem less central. We could wait see if that rises to the importance of a seperate, subsequent feature.

Decision

Let's allow init-only property setters (and validators, if and when we add them) to assign to readonly fields of the same object.

Let's not add init-only fields now. We can consider a new kind of field that can be initialized directly in object initializers later, as a separate feature, if we become convinced that it's worthwhile.

Syntax

Should the setters of init-only properties be called init or init set? In other words, is init a modifier on the set accessor, or does it replace it completely?

Shorter is generally nicer. However, we do foresee a (near?) future where init as a modifier could be applied to other members and accessors, to mean that they can only run during initialization (and in return would get privileges such as assigning to readonly members).

Decision

init it is. init as a modifier is an interesting feature, but we can discuss it separately. If we do, we can consider allowing init set as a long form of an init-only setter for regularity when code has init modifiers in multiple places. But for now, let's just allow init instead of set.

Init-only indexers

Indexers also have set accessors. Should they also be allowed to declare an init accessor instead?

Decision

It makes perfect sense, is somewhat useful, would be more regular in the language, and has straightforward semantics. Let's do it.