Add notes for July 7th, 2020, update readme.
This commit is contained in:
parent
2cbd8db612
commit
d96d221393
126
meetings/2020/LDM-2020-07-06.md
Normal file
126
meetings/2020/LDM-2020-07-06.md
Normal file
|
@ -0,0 +1,126 @@
|
|||
|
||||
# C# Language Design Meeting for July 6th, 2020
|
||||
|
||||
## Agenda
|
||||
|
||||
1. [Repeated attributes on `partial` members](#repeated-attributes-on-partial-members)
|
||||
2. [`sealed` on `data` members](#sealed-on-data-members)
|
||||
3. [Required properties](#required-properties)
|
||||
|
||||
## Quote of the Day
|
||||
|
||||
"Is there a rubber stamp icon I can use here?"
|
||||
|
||||
## Discussion
|
||||
|
||||
### Repeated attributes on `partial` members
|
||||
|
||||
https://github.com/dotnet/csharplang/pull/3646
|
||||
|
||||
Today, when we encounter attribute definitions among partial member definitions, we merge these attributes, applying attributes multiple
|
||||
times if there are duplicates across the definitions. However, if there are duplicated attributes that do not allow multiples, this merging
|
||||
results in an error that might not be resolvable by the user. For example, a source generator might copy over the nullable-related
|
||||
attributes from the stub side to the implementation side. This is further exacerbated by the new partial method model: previously, the
|
||||
primary generator of partial stubs was the code generator itself. WPF or other code generators would generate the partial stub, which the
|
||||
user could then implement to actually create the implementation. These generators generally wouldn't add any attributes, and the user could
|
||||
add whatever attributes they wanted. However, the model is flipped for the newer source generators. Users will put attributes on the stub in
|
||||
order to hint to the generator how to actually implement the method, so either the generator will have never copy attributes over (possibly
|
||||
complicating implementation), or it will have to be smart about only copying over attributes that matter. It would further hurt debugability
|
||||
as well; presumably tooling will want to show the actual implementation of the method when debugging, and it's likely that the tooling won't
|
||||
want to try and compute the merged set of attributes from the stub and the implementation to show in debugging.
|
||||
|
||||
What emerged from this discussion is a clear divide in how members of the LDT view the stub and the implementation of a partial member: some
|
||||
members view the stub as a hint that something like this method exists, and the implementation provides the final source of truth. This group
|
||||
would expect that, if we were designing again, all attributes would need to be copied to the implementation and attributes on the stub would
|
||||
effectively be ignored. The other segment of the LDT viewed partial methods in exactly the opposite way: the stub is the source of truth, and
|
||||
the implementation had better conform to the stub. This reflects these two worlds of previous source generators vs current generators: for the
|
||||
previous uses of partial, the user would actually be creating the implementation, so that's the source of truth. For the new uses, the user is
|
||||
creating the stubs, so that's the source of truth.
|
||||
|
||||
We also briefly considered a few ways of enabling the attribute that keys the generator to be removed from the compiled binary, so that it
|
||||
does not bloat the metadata. However, we feel that that's a broader feature that's been on the backlog for a while, source-only attributes. We
|
||||
don't see anything in this feature conflicting with source-only attributes. We also don't see anything in this feature conflicting with
|
||||
future expansions to partial members, such as partial properties.
|
||||
|
||||
#### Conclusion
|
||||
|
||||
The proposal is accepted. For the two open questions:
|
||||
|
||||
1. We will deduplicate across partial types as well as partial methods if `AllowMultiple` is false. This is considered lower priority if a
|
||||
feature needs to be cut from the C# 9 timeframe.
|
||||
2. We don't have a good use-case for enabling `AllowMultiple = true` attributes to opt into deduplication. If we encounter scenarios where
|
||||
this is needed, we can take it up again at that point.
|
||||
|
||||
### `sealed` on `data` members
|
||||
|
||||
In a [previous LDM](LDM-2020-06-22.md#data-properties), we allowed an explicit set of attributes on `data` members, but did not include
|
||||
`sealed` in that list, despite allowing `new`, `override`, `virtual`, and `abstract`. `sealed` feels like it's missing, as it's also
|
||||
pertaining to inheritance.
|
||||
|
||||
#### Conclusion
|
||||
|
||||
`sealed` will be allowed on `data` properties.
|
||||
|
||||
### Required properties
|
||||
|
||||
https://github.com/dotnet/csharplang/issues/3630
|
||||
|
||||
In C# 9, we'll be shipping a set of improvements to nominal construction scenarios. These will allow creation of immutable objects via
|
||||
object initializers, which has some advantages over positional object creation, such as not requiring exponential constructor growth
|
||||
over object hierarchies and the ability to add a property to a base class without breaking all derived types. However, we're still
|
||||
missing one major feature that positional constructors and methods have: requiredness. In C# today, there is no way to express that a
|
||||
property must be set by a consumer, rather than by the class creator. In fact, there is no requirement that all fields of a class type
|
||||
need to be initialized during object creation: any that aren't initialized are defaulted today. The nullable feature will issue warnings
|
||||
for initialized fields inside the declaration of a class, but there is no way to indicate to the feature that this field must be initialized
|
||||
by the consumer of the class. This goes further than just the newly added `init`: mutable properties should be able to participate in this
|
||||
feature as well. In order for staged initialization to feel like a true first-class citizen in the language, we need to support requiredness
|
||||
in the contract of creating a class via the feature.
|
||||
|
||||
The LDM has seemingly universal support of making improvements here. In particular, the proposed concept of "initialization debt" resonated
|
||||
strongly with members. It allows for a general purpose mechanism that seems like it will extend natural to differing initialization modes.
|
||||
We categorized the two extreme ends of object initialization, both of which can easily be present in a single nominal record: Nothing is
|
||||
initialized in the constructor (the default constructor), and everything is initialized in the constructor (the copy constructor). The next
|
||||
question is how are these initialization contracts created: there's some tension here with the initial goal of nominal construction.
|
||||
|
||||
Fundamentally, initialization contracts can be derived in one of two ways: implicitly, or explicitly. Implicit contracts are attractive at
|
||||
first glance: they require little typing, and importantly they're not brittle to the addition of new properties on a base class, which was
|
||||
an important goal of nominal creation in the first place. However, they also have some serious downsides: In C# today, public contracts for
|
||||
consumers are always explicit. We don't have inferred field types or public-facing parameter/return types on methods/properties. This means
|
||||
that any changes to the public contract of an object are obvious when reviewing changes to that type. Implicit contracts change that. It
|
||||
would be very possible for a manually-implemented copy constructor on a derived type to miss adding a copy when a property is added to its
|
||||
base type, and suddenly all uses of `with` on that type are now broken.
|
||||
|
||||
We further observe that this shouldn't just be limited to auto-properties: a non-autoprop should be able to be marked as required, and then
|
||||
any fields that the initer or setter for that property initializes can be considered part of the "constructor body" for the purposes of
|
||||
determining if a field has been initialized. Fields should be able to be required as well. This could extend well to structs: currently,
|
||||
struct constructors are required to set all fields. If they can instead mark a field or property as required then the constructor wouldn't
|
||||
have to initialize it all.
|
||||
|
||||
One way of implementing initialization debt would be to tie it to nullable: it already warns about lack of initialization for not null
|
||||
fields when the feature is turned on. We're still in the nullable adoption phase where we have more leeway on changing warnings, so we
|
||||
could actually change the warning to warn on _all_ fields, nullable or not. This would effectively be an expansion of definite assignment:
|
||||
locals must be assigned a value before use, even if that value is the default. By extending that requirement to all fields in a class, we
|
||||
could essentially make all fields required when nullable is enabled, regardless of their type. Then, C# 10 could add a feature to enable
|
||||
skipping the initialization of some members based on whether the consumer must initialize them. This is also not really a breaking change
|
||||
for structs: they're already required to initialize all fields in the constructor. However, it would be a breaking change for classes, and
|
||||
we worry it would be a significantly painful one, especially with no ability to ship another preview before C# 9 releases. `= null!;` is
|
||||
already a significant pain point in the community, and this would only make it worse.
|
||||
|
||||
We came up with a few different ways to mark a property as being required:
|
||||
* A keyword, as in the initial proposal, on individual properties.
|
||||
* Assigning some invalid value to the field/property. This could work well as a way to be explicit about what fields a particular
|
||||
constructor would require, but does leave the issue about inherited brittleness.
|
||||
* Attributes or other syntax on constructor bodies to indicate required properties.
|
||||
|
||||
We like the idea of some indication on a property itself dictating the requiredness. This puts all important parts of a declaration together,
|
||||
enhancing readability. We think this can be combined with a defaulting mechanism: the property sets whether it is required, and then a
|
||||
constructor can have a set of levers to override individual properties. These levers could go in multiple ways: a copy constructor could
|
||||
say that it initializes _all_ members, without having to name individual members, whereas a constructor that initializes one or two specific
|
||||
members could say it only initializes those specific members, and inherits the property defaults from their declarations. There's still
|
||||
open questions in this proposal, but it's a promising first start.
|
||||
|
||||
#### Conclusion
|
||||
|
||||
We have unified consensus that in order for staged initialization to truly feel first-class in the language, we need a solution to this issue,
|
||||
but we don't have anything concrete enough yet to make real decisions. A small group will move forward with brainstorming and come back to
|
||||
LDM with a fully-fleshed-out proposal for consideration.
|
|
@ -21,26 +21,6 @@
|
|||
|
||||
## Jul 13, 2020
|
||||
|
||||
## Jul 6, 2020
|
||||
|
||||
- [Repeat Attributes in Partial Members](https://github.com/RikkiGibson/csharplang/blob/repeated-attributes/proposals/repeat-attributes.md) (Rikki)
|
||||
- [Required properties](https://github.com/dotnet/csharplang/issues/3630) (Fred)
|
||||
|
||||
## Jul 1, 2020
|
||||
|
||||
- [Non-defaultable struct types](https://github.com/dotnet/csharplang/issues/99#issuecomment-601792573) (Sam, Chuck)
|
||||
- Confirm unspeakable `Clone` method and long-term implications (Jared/Julien)
|
||||
|
||||
## Jun 29, 2020
|
||||
|
||||
- [Static interface members](https://github.com/Partydonk/partydonk/issues/1) (Miguel, Aaron, Mads, Carol)
|
||||
|
||||
## Jun 24, 2020
|
||||
|
||||
- Parameter null checking: finalize syntax
|
||||
- https://github.com/dotnet/csharplang/issues/3275 Variance on static interface members (Aleksey)
|
||||
- [Function pointer question](https://github.com/dotnet/roslyn/issues/39865#issuecomment-647692516) (Fred)
|
||||
|
||||
## Jun 3, 2020
|
||||
|
||||
- allow suppression on `return someBoolValue!;` (issue https://github.com/dotnet/roslyn/issues/44080, Julien)
|
||||
|
@ -54,11 +34,6 @@
|
|||
|
||||
- Record Monday (Andy, Jared, Mads)
|
||||
|
||||
## May 11, 2020
|
||||
|
||||
- Record Monday (Andy, Jared, Mads)
|
||||
- https://gist.github.com/MadsTorgersen/3fb6b7461e211c8458044ad5115f2117 Primary constructors and records (Mads)
|
||||
|
||||
## April 29, 2020
|
||||
|
||||
- Design review
|
||||
|
@ -71,10 +46,6 @@
|
|||
|
||||
- https://github.com/jaredpar/csharplang/blob/record/proposals/recordsv3.md clone-style records (Jared)
|
||||
|
||||
## Jan 29, 2020
|
||||
|
||||
- Records: drilling in to individual features (Mads)
|
||||
|
||||
## Jan 13, 2020
|
||||
|
||||
- Records: Paging back in the previous proposal (Andy)
|
||||
|
@ -83,6 +54,37 @@
|
|||
|
||||
Overview of meetings and agendas for 2020
|
||||
|
||||
## Jul 6, 2020
|
||||
|
||||
[C# Language Design Notes for July 1, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-07-06.md)
|
||||
|
||||
- [Repeat Attributes in Partial Members](https://github.com/RikkiGibson/csharplang/blob/repeated-attributes/proposals/repeat-attributes.md) (Rikki)
|
||||
- `sealed` on `data` members
|
||||
- [Required properties](https://github.com/dotnet/csharplang/issues/3630) (Fred)
|
||||
|
||||
|
||||
## Jul 1, 2020
|
||||
|
||||
[C# Language Design Notes for July 1, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-07-01.md)
|
||||
|
||||
- [Non-defaultable struct types](https://github.com/dotnet/csharplang/issues/99#issuecomment-601792573) (Sam, Chuck)
|
||||
- Confirm unspeakable `Clone` method and long-term implications (Jared/Julien)
|
||||
|
||||
## Jun 29, 2020
|
||||
|
||||
[C# Language Design Notes for June 29, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-06-29.md)
|
||||
|
||||
- [Static interface members](https://github.com/Partydonk/partydonk/issues/1) (Miguel, Aaron, Mads, Carol)
|
||||
|
||||
## Jun 24, 2020
|
||||
|
||||
[C# Language Design Notes for June 24, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-06-22.md)
|
||||
|
||||
- Parameter null checking: finalize syntax
|
||||
- https://github.com/dotnet/csharplang/issues/3275 Variance on static interface members (Aleksey)
|
||||
- [Function pointer question](https://github.com/dotnet/roslyn/issues/39865#issuecomment-647692516) (Fred)
|
||||
|
||||
|
||||
## Jun 22, 2020
|
||||
|
||||
[C# Language Design Notes for June 22, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-06-22.md)
|
||||
|
@ -97,6 +99,8 @@ Overview of meetings and agendas for 2020
|
|||
|
||||
## Jun 17, 2020
|
||||
|
||||
[C# Language Design Notes for June 17, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-06-17.md)
|
||||
|
||||
1. Null-suppression & null-conditional operator
|
||||
1. `parameter!` syntax
|
||||
1. `T??`
|
||||
|
@ -143,7 +147,7 @@ Record syntax
|
|||
2. Record syntax/keyword
|
||||
3. Details on property shorthand syntax
|
||||
|
||||
## March 11, 2020
|
||||
## May 11, 2020
|
||||
|
||||
[C# Language Design Notes for May 11, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-05-11.md)
|
||||
|
||||
|
|
Loading…
Reference in a new issue