
# 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<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 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.
