# 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: ```C# interface I { int Prop { get; init set; } } public void MyMethod() 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 struct`s 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.