87 lines
3.8 KiB
Markdown
87 lines
3.8 KiB
Markdown
|
|
||
|
# 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.
|