csharplang/meetings/2020/LDM-2020-04-20.md
2020-05-15 08:24:07 -07:00

65 lines
3.4 KiB
Markdown

# C# Language Design Meeting for April 20, 2020
## Agenda
Records:
1. Factory methods
## Discussion
The proposal at its core is to allow certain methods to opt-in to certain language semantics
that are only currently valid at construction, namely object initializers, collection
initializers, and the new `with` expression (although that expression is legal on only certain
factory methods).
Possible extension of the feature: allow initializer forms everywhere, but only allow `init`
properties to be initialized when the method is marked with `Factory`. However, almost all uses
of this syntax would be a mutation of the receiver, and it may not be clear that the initializer
syntax produces a mutation.
As to whether `null` should be a valid return: most people think no. Since almost all initializer
forms dereference the receiver, this is essentially creating a very obscure way of producing
exceptions. In addition, all struct values should be permitted, as they are all safe. `default`
should be legal if the target type is known to be a struct. We have not considered what the
behavior should be for unconstrained generics.
There also some concerns about the syntactic extensions. First in that this would make `identifier {
... }` a valid syntactic form in most situations. This may not be syntactically ambiguous today,
but we have a lot of different features, like `block expressions`, which share some syntactic
similarity. Even if there is no syntactic ambiguity, some people are still concerned that the feature
will be too opaque. One way to remedy this would be to require the `new` keyword for this form as well.
So the new syntax would be:
```C#
var s = new Create() { Name = "Andy" };
```
There could be some naming ambiguity here because `Create` could be either a factory method or a
type name. We would have to preserve the interpretation as a type here for compatibility.
There's a broader question of how or if we'd like a general initializer feature. There's some
question of whether the feature is useful enough to deserve the complexity at all, using any
additional syntax. Alternatively, we could embrace the syntax requiring the `new` keyword.
One important piece of history is that initializers are not meant for mutating existing state,
only for mutating new objects. This doesn't necessarily conflict with allowing initializers on
any object, but the reason here is not that the language is suggesting using object initializers
for arbitrary mutation, but that convention alone is good enough to promote use on "new" objects
only.
Regardless of the extensions of the feature, we certainly need to implement something for
records. The core feature requirement here is for the `with` expression, which needs to assign to
`init` fields. We can head two directions: special case the `Clone` method, or build a more general
feature. This is a spectrum, where one end may be a new syntactic form specific to just the Clone
method, and the other end could be a `Factory` attribute that could be applied to any method.
### Conclusion
Right now we're more concerned with what to do for records. In the meantime, let's not support
user-written Clone methods. A Clone method will be generated for a record with an unspeakable type
and the SpecialName flag. The `with` expression will look for exactly that method name. We intend
to decide for C# 9 how that method will be written in source. We'll consider broader `Factory`
scenarios later.