65 lines
3.4 KiB
Markdown
65 lines
3.4 KiB
Markdown
|
|
||
|
# C# Language Design Meeting for March 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.
|