csharplang/meetings/2020/LDM-2020-04-06.md
2020-04-08 14:54:50 -07:00

3.8 KiB

C# Language Design Notes for April 6th, 2020

Agenda

Init-only members

Discussion

We have a proposal to dive into: https://github.com/jaredpar/csharplang/blob/init/proposals/init.md

  • The proposal notes that you can set init fields of the base type during construction, similar to readonly. This is not how readonly works today, only the declaring type can set readonly fields

  • The proposal allows init on class and struct declarations as a shorthand for init on types. This is different from how readonly struct works today, where there is no syntactic shorthand, readonly simply adds the additional requirement that all instance fields are marked readonly.

  • For the runtime: does this feature prohibit runtime restrictions on setting readonly instance fields in the future? Put simply: yes. To avoid breaking C#, the runtime would be required to either respect the proposed InitOnlyAttribute, or restrict optimizations to not alter the code for these features.

  • Use in interfaces: the proposal prohibits it, but the following example seems useful:

    interface I
    {
        int Prop { get; init set; }
    }
    
    public void MyMethod<T>() where T : I, new()
    {
        var t = new T() {
            Prop = 1
        };
    }
    
  • Signature compatibility: should init properties be compatible with mutable ones? That is, should removing init in favor of a bare set be binary-compatible? This impacts our decisions for how we think about safety in older compilers:

    • If we use a modreq to prevent other compilers from unsafely using a setter, that affects the signature of the method, and would make the above a breaking change

    • If we want accept that older compilers are not a problem (C#, VB, and F# will all be updated), perhaps we don't need to specially guard this at all

    • We could use attributes to mark and guard, by using the Obsolete attribute. ref structs use this guard by having an Obsolete attribute with a reserved message, that is ignored by compatible compilers.

Accessors

Should we allow three accessors: get, set, init? A big problem here is that you can end up calling instance members in a constructor that invoke the setter, not the initter, for a property. This means that there are few, if any, invariants that hold for init vs. set, and weakens the feature significantly.

Syntax

init vs. initonly for syntax. On the one hand, init is inconsistent with readonly (vs. initonly), but on the other hand we're pretty sad that readonly is such a long keyword. It also has few analogies with properties, where readonly isn't allowed at all, and the shorter init keyword seems more similar to get and set

  • Usage of init as a modifier: there are a number of different meanings here, and similarities between readonly and init is separating the more places we use it. For instance, if init is allowed as a member modifier, it seems similar to readonly on members, but they actually do different things. Moreover, readonly on types means that all instance fields and methods are readonly, while init on types would only mean init on fields, not on methods.

  • What are the uses for init methods, aside from helper methods? Could they be used in collection initializers?

Required Initialization

The proposal in this doc is that required initialization is also an important feature for setters. We're going to leave that discussion for a future meeting. As proposed, nullable warnings are not modified for init members.

Conclusions

No init on types. No agreement on syntax. We probably have to talk about more of the use cases. We've decided that having three different accessors is not helpful. Settled that we will place a modreq on all init setters.