Compare commits

...

807 commits

Author SHA1 Message Date
Rikki Gibson 4df3296a0f
Update param-nullchecking proposal (#5397) 2021-11-10 15:17:49 -08:00
Mads Torgersen 9b15547365
Update LDM agenda 2021-11-10 07:15:16 -08:00
Charles Stoner 87b42f24ad
Update lambda-improvements.md to match language design decisions (#5388)
* Include anonymous methods for function types and conversions

* Remove Direct invocation section

* 'var' cannot be used as explicit return type

* No inferred type for discard

* Function type conversions are ignored for user-defined conversions

* Update better function member and better conversion from expression

* Warning converting method group to object

* Move open issues to dedicated section

* Function types are used in a few specific contexts

* Removed design meeting links (moved to championed issue)
2021-11-09 12:02:49 -08:00
Charles Stoner df1a9276ff
Fix relative links in params-span.md (#5389) 2021-11-08 11:01:59 -08:00
Bernd Baumanns 3369227509
Fix linq (#5390)
* missing curly brace
2021-11-08 10:57:20 -08:00
Charles Stoner 73077e88ca
Add proposal for params Span<T> (#5382) 2021-11-05 17:43:34 -07:00
AlekseyTs 28efe56136
Explicitly specify the order of evaluation for implicit Index/Range support (#5380)
This is a follow up on an LDM decision, see https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-11-01.md for more information.
2021-11-05 06:40:36 -07:00
CyrusNajmabadi 338b5908b6
Update LDM-2021-11-03.md 2021-11-03 17:22:19 -07:00
Fredric Silberberg e51570659f
Added LDM notes for November 3rd, 2021. 2021-11-03 17:12:26 -07:00
Nigel Bess 1f7a1340e1
Update LDM-2021-04-14.md (#5383)
Fixed typo
2021-11-03 10:12:12 -07:00
Fredric Silberberg b7f3a6653c
Corrected notes on Index and Range. 2021-11-02 09:44:28 -07:00
Fredric Silberberg d0176fe491
Correct ordering 2021-11-01 17:05:43 -07:00
Fredric Silberberg 3514aabe7c
Added LDM Notes for November 1st, 2021 2021-11-01 16:47:12 -07:00
Mads Torgersen 2246988f5d
Update LDM agenda 2021-11-01 10:28:22 -07:00
Charles Stoner 26ccd64e79
Update README.md 2021-10-31 00:04:48 -07:00
Fred Silberberg 43d9ed40c1
Update the interpolated string handler spec (#5365)
Updates the spec with the changes implemented in https://github.com/dotnet/roslyn/pull/57456, after discussion with LDM.
2021-10-29 21:02:04 -07:00
Alireza Habibi cb5871f620
Update list-patterns.md (#5364) 2021-10-29 13:44:15 -07:00
Charles Stoner 6a76c1cf68
Update README.md 2021-10-29 11:30:49 -07:00
Mads Torgersen 7bdf60f57a
Update LDM agenda 2021-10-28 17:54:44 -07:00
Charles Stoner 87137e67cc
Update README.md 2021-10-28 17:31:03 -07:00
Fredric Silberberg 81f2670ec5
Added LDM notes for September 27th, 2021 2021-10-27 17:50:30 -07:00
Mads Torgersen 2e10a1b56d
Update LDM agenda 2021-10-27 09:56:17 -07:00
Fred Silberberg 42b18c5d20
Fixup utf8 string proposal (#5355) 2021-10-27 09:50:16 -07:00
CyrusNajmabadi 0f09d0ffdd
Update README.md 2021-10-27 09:46:06 -07:00
Jared Parsons 5e25bf6e3a
Utf8 string literal proposal (#5349)
* Have to start somewhere

* Progress

* Progress

* Initial draft complete

* Apply suggestions from code review

Co-authored-by: Stephen Toub <stoub@microsoft.com>

* Suggestions

Co-authored-by: Stephen Toub <stoub@microsoft.com>
2021-10-27 08:49:24 -07:00
Mads Torgersen 8f13ded863
Update LDM agenda 2021-10-26 11:03:14 -07:00
Fredric Silberberg 2802e29f4c
Added LDM Notes for October 25th, 2021 2021-10-25 15:43:12 -07:00
Mads Torgersen ec01d26c47
Update LDM agenda 2021-10-22 14:50:59 -07:00
Mads Torgersen 2ba7e98c33
Add Nov and Dec dates to LDM agenda 2021-10-21 17:02:41 -07:00
Fredric Silberberg 9f54c9673f
Added LDM Notes for October 20th, 2021. 2021-10-20 16:27:56 -07:00
Julien Couvreur e8ddd37721
Remove value type restriction on nullable suppressions
A recent issue prompted me to double-check this: https://github.com/dotnet/roslyn/issues/57142
Original design decision: https://github.com/dotnet/roslyn/issues/29907
2021-10-19 16:57:48 -07:00
Mads Torgersen f20dd3076e
Update primary constructors proposal 2021-10-19 16:57:31 -07:00
Mads Torgersen 95ffad807f
Merge pull request #5306 from dotnet/madst
Create non-record-primary-constructors.md
2021-10-19 16:55:33 -07:00
Mads Torgersen ce40037cbf Update non-record-primary-constructors.md
React to @jaredpar comments about fields vs parameters
2021-10-19 16:47:39 -07:00
Mads Torgersen b6f2fb7598
Update proposals/non-record-primary-constructors.md
Co-authored-by: Jared Parsons <jaredpparsons@gmail.com>
2021-10-19 16:25:33 -07:00
Mads Torgersen 8265129d86 Create non-record-primary-constructors.md
Rewrite proposal from primary_constructors.md in light of the primary constructors already available on records.
2021-10-19 15:18:58 -07:00
Charles Stoner 90f617d0a7
Remove separate lambda-attributes.md proposal (#5301) 2021-10-18 18:11:39 -07:00
Mads Torgersen dd9c089e9e
Update LDM agenda 2021-10-15 13:33:54 -07:00
CyrusNajmabadi 762f5da1d2
Update semi-auto-properties.md 2021-10-15 12:53:13 -07:00
CyrusNajmabadi e4ffa88c9f
Update semi-auto-properties.md 2021-10-15 12:52:44 -07:00
CyrusNajmabadi b8fa5f0689
Update semi-auto-properties.md 2021-10-15 12:51:37 -07:00
CyrusNajmabadi d91984fe41
Update semi-auto-properties.md 2021-10-15 12:49:17 -07:00
CyrusNajmabadi cf102bcbb2
Create semi-auto-properties.md 2021-10-15 12:47:27 -07:00
CyrusNajmabadi a7aa8230e6
Update new-line-in-interpolation.md 2021-10-15 10:27:05 -07:00
CyrusNajmabadi f548a2fea8
Rename new-line-in-interpolation to new-line-in-interpolation.md 2021-10-14 14:05:11 -07:00
CyrusNajmabadi 0130349385
Create new-line-in-interpolation 2021-10-14 14:04:57 -07:00
Fredric Silberberg 7e2455955c
Added LDM notes for October 13th, 2021. 2021-10-13 15:34:01 -07:00
Mads Torgersen 6934787776
Update LDM agenda 2021-10-12 10:51:53 -07:00
Julien Couvreur 5675cc01cd
Update README.md 2021-10-08 16:55:36 -07:00
Charles Stoner a6737cff25
Several corrections to task-types.md (#5253) 2021-10-06 21:41:54 -07:00
Bill Wagner 1bbea06217
fix typos (#5250)
find / replace mistake, where I had // instead of /
2021-10-05 20:20:18 -04:00
AlekseyTs eedd69b8f9
Update "Unresolved questions" in static-abstracts-in-interfaces.md (#5249) 2021-10-05 14:49:13 -07:00
Bill Wagner f5daa3c480
Update links to spec (#5248)
Making the links to the spec relative links, so they'll resolve correctly both in this repo, and when published on docs.microsoft.com

(The latest change doesn't have the folder as part of it.)
2021-10-05 17:40:03 -04:00
Alireza Habibi 6e57bef953
Add pattern-variables.md (#4592) 2021-10-04 13:02:43 -07:00
Mads Torgersen 5a4d8a5903
Add LDM dates 2021-10-03 15:33:52 -07:00
Julien Couvreur a012a07b58
Update README.md 2021-10-01 14:42:07 -07:00
Fred Silberberg 0eb5952478
Fix the intro sections of the spec. (#5239) 2021-10-01 13:50:34 -07:00
Petr Onderka 41f962b156
Deleted confusing task lists from proposals (#5232) 2021-09-28 12:51:58 -07:00
Julien Couvreur 5c70a7acac
Update README.md 2021-09-28 10:56:55 -07:00
Julien Couvreur 40e8483671
Update README.md 2021-09-27 10:43:16 -07:00
CyrusNajmabadi 0ea5665946
Merge pull request #5174 from dotnet/CyrusNajmabadi-patch-1
Create using-alias-types.md
2021-09-24 17:50:00 -05:00
Charles Stoner d52e29f186
Lambda improvements: include 'Explicit return type inference' spec section (#5217) 2021-09-24 10:38:05 -07:00
Fred Silberberg c33a21734e
Fix example 2021-09-23 11:20:38 -07:00
Alireza Habibi 138765d6b0
Fix code example in notes (#5215) 2021-09-23 08:31:23 -07:00
Fredric Silberberg 38794f2c5b
Add missing notes link. 2021-09-22 17:39:46 -07:00
Fredric Silberberg 17d51b5875
Remove brackets 2021-09-22 17:37:42 -07:00
Fredric Silberberg 10f366592c
Added LDM notes fo rSeptember 22nd, 2021 2021-09-22 17:36:26 -07:00
Julien Couvreur 33e3bfe31f
Update README.md 2021-09-22 12:01:08 -07:00
Joseph Musser 088f20b6f9
Fix typos (#5210) 2021-09-21 09:53:30 -07:00
Charles Stoner fab06e432c
Correct formatting of generic type name in LDM notes (#5209) 2021-09-21 08:41:19 -07:00
Fredric Silberberg 4109c3d3de
Added LDM Notes for September 15th and 20th. 2021-09-20 18:21:14 -07:00
Mads Torgersen c1ccfd0d6a
Update LDM agenda 2021-09-19 09:54:00 -07:00
Charles Stoner 6f9ae4dccd
Update README.md 2021-09-17 15:52:13 -07:00
Mads Torgersen 5d5688cdac
Update LDM agenda 2021-09-17 15:45:48 -07:00
Mads Torgersen 794e7fa1d9
Update LDM agenda 2021-09-16 14:13:42 -07:00
Jared Parsons e99dae65fc
Fix a couple of issues (#5188)
Feedback on discord pointed out that there were a few mistakes in the
doc:

- Use `ref field = ref value` instead of `field = ref value`j`. The
latter is correct here because it mimics how `ref` locals work
- Use `readonly ref` to describe `ref` fields that can't be reassigned
instead of `ref readonly`
2021-09-14 12:21:06 -07:00
Bill Wagner 1ea4383736
Clarify matching members prevents synthesized members (#5187)
Fixes #5186
2021-09-14 14:08:44 -04:00
Fredric Silberberg c117a50a14
Added LDM notes for September 13th, 2021. 2021-09-13 15:33:26 -07:00
Rikki Gibson 73dc536d4d
Remove new handling of nullable value types in method type argument inference (#5138) 2021-09-13 11:25:30 -07:00
CyrusNajmabadi 076e25b596
Update using-alias-types.md 2021-09-10 14:56:54 -07:00
CyrusNajmabadi ad321d2aac
Update using-alias-types.md 2021-09-10 13:21:23 -07:00
CyrusNajmabadi 611b638273
Create using-alias-types.md 2021-09-10 11:00:07 -07:00
Julien Couvreur 8aaf7240da
Update README.md 2021-09-10 10:23:53 -07:00
Mads Torgersen 7c9a4c1946
Update LDM agenda 2021-09-10 09:59:26 -07:00
Mads Torgersen cf4d452be2
Update LDM agenda 2021-09-10 09:58:35 -07:00
Bill Wagner f63f70960c
Add missing semicolon (#5165)
See dotnet/docs#26006

Also fixed in dotnet/csharpstandard#371
2021-09-08 09:05:25 -07:00
Yanis Batura 8df1e5d5a7
Update required-members.md (#5147)
fix a typo
2021-09-04 23:29:26 -07:00
Mads Torgersen fc125168ea
Update LDM agenda 2021-09-03 15:39:14 -07:00
Fredric Silberberg fbbdf86e8a
Added field keyword. 2021-09-02 17:46:30 -07:00
Fredric Silberberg c0536b57c7
Add links to the README 2021-09-02 13:56:06 -07:00
Fredric Silberberg dcd6bda4b8
Added notes for August 30th and September 1st 2021-09-02 13:54:25 -07:00
Mads Torgersen 2f9862c8e6
Update LDM agenda 2021-09-02 11:20:37 -07:00
Mads Torgersen 93c42cf98b
Update LDM agenda 2021-09-02 10:58:16 -07:00
Mads Torgersen c8544ccc29
Update LDM agenda 2021-09-02 10:22:35 -07:00
Julien Couvreur ff7e5f04d3
Update README.md 2021-08-30 13:12:11 -07:00
Julien Couvreur f9e8476c97
Update low-level-struct-improvements.md 2021-08-30 11:20:28 -07:00
Mads Torgersen 015894956e
Update LDM agenda 2021-08-29 16:42:53 -07:00
Fredric Silberberg e85356bb95
Added notes for August 25th, 2021. 2021-08-25 14:35:33 -07:00
Fred Silberberg b89d4c9340
Update schedule. 2021-08-24 15:24:59 -07:00
Fredric Silberberg e664481942
Added public issue note. 2021-08-24 15:02:26 -07:00
Fredric Silberberg 7fd92296bc
Added LDM notes for August 23rd, 2021. 2021-08-24 15:00:55 -07:00
Julien Couvreur 86c641d4d5
Update README.md 2021-08-23 11:39:55 -07:00
Bill Wagner a4c9db9a69
Address docs build warnings (#5102)
* fix docs suggestions

There are two different types of changes in this PR:

- H1s should use ATX headers (`#`)
- tables should have a header row that is not empty.

* replace docs links with source

This addresses another docs build warning. The docs build system flags absolute links to the pages on docs.microsoft.com as warnings, which should be replaced with relative links. This fix changes the link to the source doc on GitHub. I'm currently looking for a better solution.

* Revert "replace docs links with source"

This reverts commit b40cfc9632.
2021-08-23 14:33:02 -04:00
CyrusNajmabadi 88825dd480
Merge pull request #5094 from dotnet/Update-raw-string-literal-examples
Update raw-string-literal.md
2021-08-21 10:11:19 -04:00
Mads Torgersen 1d95494330
Update LDM agenda 2021-08-20 12:31:41 -07:00
Charles Stoner 73af544295
Update README.md 2021-08-20 12:17:25 -07:00
CyrusNajmabadi 8255f7d434
Update raw-string-literal.md 2021-08-20 12:09:52 -07:00
Charles Stoner 341d5184ba
Update README.md 2021-08-19 20:50:47 -07:00
Jared Parsons 085024139e
Clarify span safety rules for readonly receivers (#5083)
* Clarify span safety rules for readonly receivers

The compiler excludes receivers from the "Must Arguments Must Match"
rules when the type is a `readonly struct`. This exclusion was not
covered in the rules.

* Apply suggestions from code review

Co-authored-by: Fred Silberberg <fred@silberberg.xyz>

Co-authored-by: Fred Silberberg <fred@silberberg.xyz>
2021-08-19 12:10:53 -07:00
Ruslan Batkaev 9a18b64732
fix typo 'of' -> 'or' (#3026) 2021-08-18 11:23:29 -07:00
Julien Couvreur 6b0f5be210
Update README.md 2021-08-17 22:16:55 -07:00
Fred Silberberg cf9794dbb5
Added another ASAP issue for discussion. 2021-08-17 13:24:11 -07:00
Rikki Gibson 2329ddd55f
Add partial base type nullability differences agenda item (#5069) 2021-08-17 10:17:41 -07:00
Bill Wagner 134702a58a
fix missing links (#5025)
A few links to the standard did not include the folder path.
2021-08-11 10:19:59 -04:00
Rikki Gibson 815cb6903b
Specify when record struct synthesized members are 'readonly' (#4890) 2021-08-10 14:52:53 -07:00
Bill Wagner 0e4b7363ec
fix build warnings in docs (#5018)
Most of the fixes are updating links to sections of the spec so that they work correctly.

Other fixes include semantic markdown:
- exactly 1 H1 heading in each file.
- ATX style headers.
2021-08-10 17:27:10 -04:00
Bernd Baumanns 1714a1ef92
pattern-match-span-of-char-on-string.md is not part of csharp 10 (#5001) 2021-08-05 10:19:29 -07:00
Julien Couvreur 5b473bcf77
Add C# 10 to language history (#4996) 2021-08-04 22:08:23 -07:00
Charles Stoner 4907038e8e
Update lambda / method group natural type to use "function type" (#4728) 2021-08-04 12:15:52 -07:00
Alireza Habibi 2c0481fb22
Update list-patterns.md (#4982) 2021-08-03 10:43:48 -07:00
Fred Silberberg 9a6e23e589
Add topic for when LDM is back. 2021-08-02 13:54:22 -07:00
Julien Couvreur 614edd88d7
Create raw-string-literal.md 2021-07-30 20:59:16 -07:00
Fred Silberberg 1dbcfb485c
Remove no longer needed proposal status checkboxes. (#4977) 2021-07-28 16:14:48 -07:00
Julien Couvreur dcbaa81525
Fix some links (#4976) 2021-07-27 12:34:38 -07:00
Julien Couvreur 1788bfd3ad
Move shipped proposals to csharp-10.0 folder (#4973) 2021-07-27 11:35:55 -07:00
Joseph Musser 9df76ef6c6
Fix typos (#4970) 2021-07-26 19:57:19 -07:00
Fred Silberberg 9f5c1d13c0 Added notes for July 19th and 26th, 2021 2021-07-26 17:46:50 -07:00
Julien Couvreur f4d1c13a6a
Update README.md 2021-07-23 11:46:03 -07:00
Mads Torgersen d3c31779a1
Add dates to LDM agenda 2021-07-22 16:33:38 -07:00
Mads Torgersen f2fe67e0ef
Update LDM agenda 2021-07-22 16:21:33 -07:00
CyrusNajmabadi 31f07a1839
Update README.md 2021-07-22 10:37:59 -07:00
Rikki Gibson fe65068f74
Call EnsureSufficientExecutionStack in PrintMembers (#4951) 2021-07-20 16:47:57 -07:00
Rikki Gibson 9c2ac8391c
Add generic attributes proposal (#4936) 2021-07-20 10:21:17 -07:00
Mads Torgersen f05a7cd15f
Update LDM agenda 2021-07-16 14:58:37 -07:00
WhiteBlackGoose 96e23022d4
A meeting with lambda improvements mentioned (#4931) 2021-07-16 09:19:09 -07:00
Fredric Silberberg 1296da8e31
Fix link 2021-07-13 17:05:27 -07:00
Fredric Silberberg 733f9611aa
Added notes for July 12th, 2021. 2021-07-13 17:04:24 -07:00
Fred Silberberg 4f938f7595
Specify unescaping rules for interpolated strings (#4910)
Co-authored-by: Stephen Toub <stoub@microsoft.com>
2021-07-09 16:42:54 -07:00
Mads Torgersen 136320cab1
Update LDM agenda 2021-07-09 14:37:01 -07:00
Mads Torgersen 7dc4311c7b
update LDM agenda 2021-07-09 13:33:52 -07:00
Julien Couvreur 7e863bee4a
Update async-method-builders.md (#4903) 2021-07-06 10:31:24 -07:00
Fredric Silberberg 70fc3eb703
Clarify that all variance is disallowed on explicit lambda return types. Add email decision on global using warnings. 2021-06-25 10:25:24 -07:00
Fredric Silberberg d91eab3660
Added LDM Notes for June 21st, 2021. 2021-06-23 17:12:18 -07:00
Alireza Habibi e4edc94d14
Use separate list-pattern with square brackets (#4860) 2021-06-22 12:28:33 -07:00
Julien Couvreur a11816a462
Update spec to reflect LDM 2021/06/21 decisions (#4859) 2021-06-21 19:33:30 -07:00
Mads Torgersen 6662672a2b
Update LDM agenda 2021-06-19 01:31:18 +02:00
Charles Stoner b9ea94262d
Update README.md 2021-06-18 07:12:16 -07:00
Mads Torgersen f4265f4899
Update LDM agenda 2021-06-18 15:33:39 +02:00
Meowtimer 22962db0e9
pattern 404 link (#4834)
Should probably link to [csharp-7.0/pattern-matching.md](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-7.0/pattern-matching.md)
2021-06-16 07:52:19 -07:00
Charles Stoner ef10c625c3
Update README.md 2021-06-15 23:17:49 -07:00
Charles Stoner b518743c6f
Update README.md 2021-06-15 23:17:17 -07:00
Fred Silberberg fb6af9155a
Clarify wording of list patterns conclusion. 2021-06-15 17:04:12 -07:00
Joseph Musser 592da35424
Fix typo (#4831) 2021-06-15 13:43:52 -07:00
Fred Silberberg 258cc959fd
Fix numbering. 2021-06-15 13:27:20 -07:00
Fred Silberberg 36b666765e
Fix default value. 2021-06-15 13:25:35 -07:00
Fred Silberberg 3462d9cd28
Fixed a missing word 2021-06-15 13:12:54 -07:00
Fredric Silberberg ed6ad44e00
Added notes for June 14th, 2021 2021-06-15 11:50:33 -07:00
Julien Couvreur 15c2bca0be
Update README.md 2021-06-15 09:45:42 -07:00
Bernd Baumanns 3ca20d7107
fix: special type implementation for array (#4829) 2021-06-15 08:30:08 -07:00
Julien Couvreur 85ed4b0785
Update README.md 2021-06-11 21:40:13 -07:00
Julien Couvreur 95d0b48db5
Update README.md 2021-06-11 21:31:52 -07:00
Mads Torgersen 20a57a9a6d
Update LDM agenda 2021-06-11 17:24:03 +02:00
Fred Silberberg b282f51ab9
Update the interpolated string handler spec (#4795)
* Update the interpolated string handler spec

Updates the spec to reflect the naming changes, the change in Create vs ctor, and the other open questions that have since been resolved.
2021-06-10 15:11:10 -07:00
Fred Silberberg c618b06a36
Fix parameterless struct constructor example. 2021-06-07 16:57:32 -07:00
Fred Silberberg 900e997f0b
Correct sub-bullets 2021-06-07 15:03:19 -07:00
Fredric Silberberg 9cd6a7d4f7
Added LDM notes for June 7th, 2021. 2021-06-07 15:02:20 -07:00
Julien Couvreur cefa73b371
Update README.md 2021-06-07 12:29:29 -07:00
Mads Torgersen 38845c5639
Update README.md 2021-06-07 12:28:33 +02:00
Julien Couvreur ecd0620606
Relax commitment around single evaluation 2021-06-03 11:06:57 -07:00
AlekseyTs 2a17f2b214
Update "Unresolved questions" section in static-abstracts-in-interfaces.md (#4794) 2021-06-02 18:31:53 -07:00
Fredric Silberberg 4d2b699d44
Added LDM notes for June 2nd, 2021. 2021-06-02 15:01:44 -07:00
Julien Couvreur c4debafa0c
Update README.md 2021-06-02 14:49:29 -07:00
Mads Torgersen 5a1112a255
Update LDM agenda 2021-06-02 07:24:14 -07:00
Julien Couvreur 5cb472d6b4
Split list patterns on enumerables (#4793) 2021-05-30 22:02:01 -07:00
Alireza Habibi bcd1ace777
Update list-patterns.md (#4790) 2021-05-28 15:44:06 -07:00
Fredric Silberberg 32f886de6b
Add missing proposal link 2021-05-27 21:38:37 -07:00
Yair Halberstadt 95d5ea7254
Fix typo (#4788) 2021-05-27 21:36:10 -07:00
Fredric Silberberg 6c911c2b8b
Add LDM notes for May 26th, 2021. 2021-05-27 17:01:07 -07:00
Fred Silberberg 04cb45a8cb
Add open questions for CallerArgumentExpression to the backlong. 2021-05-27 14:46:05 -07:00
Rikki Gibson 74a4b1da81
Adjust 'is' spec (#4785) 2021-05-27 14:18:40 -07:00
Charles Stoner 69be01c864
Update README.md 2021-05-27 11:03:07 -07:00
AlekseyTs bb6eca3925
Propose rules for consuming user-defined conversion operators declared in interfaces. (#4773) 2021-05-27 09:32:52 -07:00
Charles Stoner 6137557e7e
Clarify struct field initialization with default constructor initializer (#4778) 2021-05-26 08:25:23 -07:00
Mads Torgersen c2dfc38cbf
Update LDM agenda 2021-05-24 13:41:52 -07:00
Julien Couvreur b352c17312
Update README.md 2021-05-24 09:31:22 -07:00
Fred Silberberg e178fbbc93
Fix the date 2021-05-20 11:07:02 -07:00
Fredric Silberberg a11db0a6d5
Added LDM notes for May 19th, 2021. 2021-05-20 11:05:20 -07:00
Joseph Musser f751454623
Typo and rendering fixes (#4761) 2021-05-18 16:27:15 -07:00
Fredric Silberberg f817e1f3db
Added notes for May 17th, 2021. 2021-05-18 15:27:11 -07:00
Mads Torgersen 38c9773f13
Add LDM dates 2021-05-14 15:48:14 -07:00
Mads Torgersen 46a2bcff0b
Update LDM agenda 2021-05-14 10:44:15 -07:00
Fredric Silberberg 76538e5e13
Added notes for May 12th, 2021 2021-05-12 16:03:06 -07:00
Mads Torgersen caf3fd7385
Update LDM agenda 2021-05-12 14:11:18 -07:00
Youssef Victor fb699c0c6d
Fix variable name (#4742) 2021-05-11 11:38:16 -07:00
Fredric Silberberg 1a0e4bc758
Update notes branch link. 2021-05-10 15:46:44 -07:00
Fredric Silberberg 3137df7cf4
Added LDM Notes for May 10th, 2021. 2021-05-10 15:45:59 -07:00
Charles Stoner 03aedc0516
Update README.md 2021-05-07 11:21:48 -07:00
Julien Couvreur e6122ed487
Update list-patterns.md 2021-05-05 23:14:57 -07:00
Rikki Gibson e619b20e50
Rename statics-in-interfaces.md to static-abstracts-in-interfaces.md (#4719) 2021-05-04 12:48:39 -07:00
Fredric Silberberg a3ff206420
Added notes for May 3rd, 2021. 2021-05-04 11:45:34 -07:00
CyrusNajmabadi 555704e008
Update README.md 2021-05-04 09:27:36 -07:00
Julien Couvreur 107d8df70d
Update README.md 2021-05-03 14:55:18 -07:00
Julien Couvreur 3c526ee195
Update README.md 2021-05-03 14:54:05 -07:00
Mads Torgersen fd0dc4f157
Update LDM agenda 2021-05-03 09:54:45 -07:00
Charles Stoner 91752413d6
Update README.md 2021-04-30 15:19:35 -07:00
Mads Torgersen 15c507ecc5
Update LDM agenda 2021-04-29 17:58:54 -07:00
Charles Stoner 8777a189c7
Update parameterless struct constructor proposal (#4521) 2021-04-29 11:55:17 -07:00
Fred Silberberg eb30fa570e
Rework improved interpolated string builder proposal with LDM feedback. (#4703)
* Rework improved interpolated string builder proposal with LDM feedback.
2021-04-29 10:40:39 -07:00
Fred Silberberg c4ee96110e
Clarify warning wave on new StructType() 2021-04-29 09:57:31 -07:00
Joseph Musser ed8610b290
Typos (#4712) 2021-04-29 09:14:30 -07:00
Fredric Silberberg 2b70bbed59
Added notes for April 28th, 2021. 2021-04-28 17:09:50 -07:00
Mads Torgersen 97ea12ccd5
Remove Apr 26 LDM 2021-04-23 11:48:35 -07:00
Fredric Silberberg bf7ce619e6
Added LDM notes for April 21st, 2021. 2021-04-23 11:08:15 -07:00
Mads Torgersen 1f655b145c
Add May dates to LDM agenda 2021-04-23 10:45:43 -07:00
Mads Torgersen a4af8a0f8a
Update C# LDM agenda 2021-04-23 10:42:49 -07:00
Julien Couvreur cbc7d18430
Update docs for positional fields and hidden positional members (#4673) 2021-04-23 10:13:05 -07:00
Petr Kulikov f99f391ad9
Fix example: static struct members cannot be readonly (#3354) 2021-04-22 13:14:39 -04:00
AlekseyTs b6f3504bc7
Add Variance safety section to statics-in-interfaces.md (#4610) 2021-04-22 06:59:08 -07:00
Charles Stoner cc6cba159a
Clarify description of inferred type for method group (#4678) 2021-04-20 21:32:43 -07:00
Fredric Silberberg e8b27ef36f
Added LDM notes for April 19th, 2021. 2021-04-20 15:17:38 -07:00
Mads Torgersen 99ee2e877f
Update LDM agenda 2021-04-20 13:05:50 -07:00
Carl Erik Patrik Iwarson 22a8d8976e
Update ranges.md: length -> Length (#4675)
Extremely small fix to get the example code under "Implicit Range support" to run
2021-04-20 09:46:35 -07:00
Charles Stoner 5484a151f7
Update README.md 2021-04-19 21:39:12 -07:00
Charles Stoner f58bfd7a0a
Update lambda improvements proposal (#4642) 2021-04-19 14:39:15 -07:00
Charles Stoner 2ea0826865
Update README.md 2021-04-17 17:25:55 -07:00
Charles Stoner e1e8404fd8
Update README.md 2021-04-17 15:48:02 -07:00
Rikki Gibson 2a35c5b299
Merge pull request #4664 from dotnet/dev/rigibson/is-pattern-bool 2021-04-16 14:42:52 -07:00
Fred Silberberg 2610effb3d
Fix notes title. 2021-04-16 12:44:57 -07:00
Rikki Gibson 9852346063
Accept more bool patterns 2021-04-16 12:12:30 -07:00
Fredric Silberberg d8430957be
Fix typo. 2021-04-16 11:28:16 -07:00
Fredric Silberberg f894bac818
Reword to reduce confusion. 2021-04-16 11:24:07 -07:00
Fredric Silberberg 5da3f4e8bf
Added LDM notes for April 14th, 2021 2021-04-16 10:54:19 -07:00
Fred Silberberg 4e333cf6dc
Update interpolated string proposal (#4649)
* Update interpolated string proposal

Updates the proposal with feedback from API review and previous LDM sessions.

Co-authored-by: Stephen Toub <stoub@microsoft.com>
2021-04-16 10:40:08 -07:00
Rikki Gibson 4cbfe08276
Merge pull request #4656 from alrz/patch-6
Fix indentation
2021-04-15 10:44:33 -07:00
Alireza Habibi 4f848c4496
Update variables.md 2021-04-15 12:22:19 +04:30
Mads Torgersen 9d8d98e61e
Update LDM agenda 2021-04-14 12:19:36 -07:00
Fredric Silberberg 8cb45218b0
Added LDM notes for April 7th, 2021 2021-04-13 14:33:21 -07:00
Julien Couvreur e3e07b999b
Update README.md 2021-04-13 12:30:56 -07:00
Fredric Silberberg b40826529e
Added LDM notes for April 12th, 2021 2021-04-12 16:08:33 -07:00
Julien Couvreur 0093f12358
Update list-patterns.md 2021-04-12 12:24:26 -07:00
Julien Couvreur a05ef31c01
Record decisions from LDM 4/12/2021 2021-04-12 12:21:36 -07:00
Charles Stoner b25408365a
Update README.md 2021-04-11 12:21:03 -07:00
Gérald Barré 1ff26b634d
Fix readonly property samples (#4640) 2021-04-10 23:34:30 -07:00
Mads Torgersen 3c8559f186
Update LDM agenda 2021-04-08 15:02:45 -07:00
Alireza Habibi 98d4638aaf
Update extended-property-patterns.md (#4631) 2021-04-08 07:16:26 -07:00
CyrusNajmabadi e8f99b0bc3
Merge pull request #4581 from CyrusNajmabadi/features/file-scoped-namespaces
Initial specification for file-scoped-namespaces
2021-04-06 21:40:50 -07:00
Fredric Silberberg 5930dfb0d3
Remove links in the readme 2021-04-06 15:36:52 -07:00
Fredric Silberberg e01b11a71e
Added LDM notes for April 5th, 2021. 2021-04-06 15:36:07 -07:00
Mads Torgersen 1d59a69eff
Merge pull request #4611 from dotnet/madst
Add equality and conversion operators to static abstract members in interfaces
2021-04-06 13:51:11 -07:00
Mads Torgersen f6208cbf3f Update section on default implementations 2021-04-06 13:46:09 -07:00
Mads Torgersen 554b51929f Revert "Add default implementations to static virtual members in interfaces"
This reverts commit d80953e14d.
2021-04-06 13:26:06 -07:00
CyrusNajmabadi ae52d973cd
Update record-structs.md 2021-04-05 22:08:12 -07:00
Julien Couvreur f1cbd4c9eb
Update record-structs.md 2021-04-05 22:05:50 -07:00
Deepu Madhusoodanan d41fcd0377
Update improved-interpolated-strings.md (#4617)
Fix typo in "Return" keyword. 

Changed to return instead of "Return"
2021-04-02 13:32:12 -07:00
Julien Couvreur 0e036c9129
Use AsyncMethodBuilder and remove scoped scenarios (#4603) 2021-03-31 16:37:25 -07:00
Mads Torgersen d80953e14d Add default implementations to static virtual members in interfaces 2021-03-31 14:13:38 -07:00
Mads Torgersen d5434955d0 Add equality and conversion operators 2021-03-31 12:28:02 -07:00
Fred Silberberg 30fc08bc1e
Update interpolated string proposal with feedback (#4588)
Update interpolated string proposal with feedback

* Split the TryFormat methods into TryFormatBaseString and TryFormatInterpolationHole. Naming is definitely subject to review, but hopefully the concept is clear.
* Added new open questions for logging scenarios after review with the ILogger folks.
* Added leeway for async rules in using the interpolated string builder for string types.
* Added open question for disposal of builder types.
* Swap the out param and return type in the proposals, make the bool optional.

Co-authored-by: Chris Sienkiewicz <chsienki@microsoft.com>
Co-authored-by: Chris Sienkiewicz <chsienki@microsoft.com>
2021-03-31 11:42:00 -07:00
CyrusNajmabadi 62cfaf1501
Update README.md 2021-03-30 14:50:16 -07:00
goyzhang 50d39a0057
Update ranges.md (#4606) 2021-03-30 09:47:56 -07:00
Fredric Silberberg b7091bad97
Added LDM Notes for March 29th, 2021 2021-03-29 16:14:18 -07:00
Cyrus Najmabadi 89724a1098 Spelling 2021-03-29 15:13:03 -07:00
Charles Stoner 4865d92cfa
Update README.md 2021-03-29 14:55:50 -07:00
Charles Stoner cbfdc35dc8
Update README.md 2021-03-28 13:11:08 -07:00
Julien Couvreur 6aeb218adc
Update async-method-builders.md 2021-03-26 15:15:23 -07:00
Julien Couvreur a8585351ff
Update list-patterns.md 2021-03-26 15:11:31 -07:00
Joseph Musser 37885565fc
Help to set expectations for issues up front (#4513) 2021-03-26 14:44:23 -07:00
Mads Torgersen 9a0dddbf06
Update statics-in-interfaces.md 2021-03-26 11:21:42 -07:00
Mads Torgersen 5d4ba55102
Create statics-in-interfaces.md 2021-03-26 11:10:21 -07:00
Mads Torgersen a01626f3de
Update LDM agenda 2021-03-26 10:01:14 -07:00
Alireza Habibi 01fd6d3edf
Add extended-property-patterns.md (#4585) 2021-03-25 16:08:26 -07:00
Julien Couvreur 47143d1935
Spec list-pattern on enumerable collections (#4575) 2021-03-25 16:02:11 -07:00
Fredric Silberberg 7d1157b445
Added LDM Notes for March 24th, 2021. 2021-03-25 10:49:29 -07:00
Fred Silberberg 56cbb1ed9a
Add improved interpolated strings spec (#4486)
Co-authored-by: Stephen Toub <stoub@microsoft.com>
Co-authored-by: Yaakov <yaakov-h@users.noreply.github.com>
2021-03-25 09:22:00 -07:00
CyrusNajmabadi d194a55d68
Update file-scoped-namespaces.md 2021-03-24 14:28:39 -07:00
CyrusNajmabadi 9eb5a43bb4
Update file-scoped-namespaces.md 2021-03-24 14:20:43 -07:00
CyrusNajmabadi 0c48d101ae
Update file-scoped-namespaces.md 2021-03-24 14:18:44 -07:00
Cyrus Najmabadi 287db71b53 Merge branch 'features/file-scoped-namespaces' of https://github.com/CyrusNajmabadi/csharplang into features/file-scoped-namespaces 2021-03-24 14:17:18 -07:00
CyrusNajmabadi 3dd985908e
Update file-scoped-namespaces.md 2021-03-24 14:15:23 -07:00
Cyrus Najmabadi e374854c2c eremove 2021-03-24 14:13:31 -07:00
CyrusNajmabadi e3d4e5974d
Update file-scoped-namespaces.md 2021-03-24 14:12:53 -07:00
CyrusNajmabadi c80d21eab2
Update file-scoped-namespaces.md 2021-03-24 14:12:30 -07:00
Cyrus Najmabadi 735692bbf2 Add initial draft specification. 2021-03-24 14:10:37 -07:00
Cyrus Najmabadi 5502b2bf7b Merge remote-tracking branch 'upstream/main' 2021-03-24 13:54:14 -07:00
Julien Couvreur 790f2e01bc
Update README.md 2021-03-24 13:36:48 -07:00
Julien Couvreur 08fc429e4b
Update README.md 2021-03-24 13:35:27 -07:00
Rikki Gibson a4c82ef11c
Address conversions of conditional accesses in IDA (#4554) 2021-03-23 13:11:00 -07:00
Julien Couvreur dfd082f696
Add open question to record-structs.md (#4564) 2021-03-19 23:23:01 -07:00
C-xC-c 38c6ed3b57
Rename record equality parameters to 'left' and 'right' (#4555)
Co-authored-by: Jack Tyrer <jack@tyrer.dev>
2021-03-19 10:32:09 -07:00
Julien Couvreur 9df5261be0
Update async-method-builders.md 2021-03-19 10:22:22 -07:00
Julien Couvreur 937a7130d6
Update README.md 2021-03-19 10:18:14 -07:00
Alireza Habibi b864efcce0
Add list patterns proposal (#3245) 2021-03-19 10:08:35 -07:00
Julien Couvreur c3aa294baf
Move CODEOWNERS file to correct folder (#4558) 2021-03-18 17:15:09 -07:00
Mads Torgersen 72beb72f56
Update LDM agenda 2021-03-18 11:51:02 -07:00
Charles Stoner fffb1bfabe
Update README.md 2021-03-17 20:40:56 -07:00
Fredric Silberberg 3ffbddf8e9
Added LDM notes for March 15th, 2021. 2021-03-16 13:51:13 -07:00
Alex Buck d910cfa1f4
Fix misspelled word in init.cs (#4542) 2021-03-16 08:08:09 -07:00
AlekseyTs 8bddff3b2f
Reflect LDM decision about scope of Global Using directive in the spec. (#4539) 2021-03-15 16:43:48 -07:00
AlekseyTs 95b26c4cb5
Add a link 2021-03-15 08:56:24 -07:00
Julien Couvreur e4c820c211
Determination of async method builder type from override attribute (#4512) 2021-03-12 20:05:56 -08:00
AlekseyTs 3b89009e2c
Clarify scoping and name lookup rules around Global Using directives. (#4499) 2021-03-12 17:54:29 -08:00
Mads Torgersen 7f674675ab
Update LDM agenda 2021-03-12 13:46:37 -08:00
Fredric Silberberg 1b4f6ac09f
Add LDM Notes for March 10th, 2021. 2021-03-11 14:01:54 -08:00
Youssef Victor ae69a53cf0
Fix dead links (#4525) 2021-03-11 10:10:25 -08:00
Mads Torgersen 26827be206
Update LDM agenda 2021-03-11 09:18:03 -08:00
Charles Stoner 5b6f535bee
Minor clarifications to parameterless struct constructor proposal (#4516) 2021-03-10 14:23:11 -08:00
Charles Stoner 6fec6567a5
Update README.md 2021-03-10 08:50:18 -08:00
Julien Couvreur 003c0606c3
Remove mention of "copy constructor" (#4515) 2021-03-09 14:57:28 -08:00
CyrusNajmabadi 5917736d40
Update README.md 2021-03-09 14:39:04 -08:00
AlekseyTs 6a48b62c9b
Update README.md 2021-03-09 11:56:57 -08:00
Julien Couvreur b72a3c2bd2
Create CODEOWNERS (#4502) 2021-03-09 11:45:30 -08:00
Fred Silberberg 8a5955168e
Add initial required properties proposal (#4493) 2021-03-08 10:42:06 -08:00
Charles Stoner 00b0f04deb
Move lambda improvements proposal and update links (#4498) 2021-03-05 16:43:07 -08:00
Charles Stoner 7397714ff4
Add proposal for lambda improvements (#4451) 2021-03-05 16:09:36 -08:00
Mads Torgersen b84678cf2c
Update C# LDM agenda 2021-03-05 15:12:31 -08:00
Fredric Silberberg 547b1d0991
Added notes for March 3rd, 2021. 2021-03-05 11:43:28 -08:00
Charles Stoner 14c7c290e9
Add proposal for explicit parameterless struct constructors (#4459) 2021-03-02 14:31:49 -08:00
Leandro Fernandes 0d06813349
Update Language-Version-History.md (#4396) 2021-03-02 10:47:00 -08:00
Petr Onderka f921de697a
Fixed links in spec (#3273) 2021-03-01 18:58:12 -08:00
Fredric Silberberg 3f8f57e294
Remove bad links. 2021-03-01 16:40:09 -08:00
Fredric Silberberg 9196a30129
Added LDM Notes for March 1st, 2021 2021-03-01 16:39:04 -08:00
Rikki Gibson 5a537b3d3d
Update conditional expression section of IDA (#4472) 2021-03-01 15:06:41 -08:00
Andrew Dashkov 835828da4e
Add the missing letter (#3334)
"The type parameters can the be used" -> "The type parameters can then be used"
2021-03-01 15:05:41 -08:00
Mads Torgersen f0590512a5
Update LDM agenda 2021-02-26 12:51:36 -08:00
Rikki Gibson 7d97a3f373
Add improved-definite-assignment.md (#4468) 2021-02-25 17:03:15 -08:00
Fredric Silberberg 1a7ae36a02
Add LDM Notes for February 24th, 2021. 2021-02-25 14:12:27 -08:00
Fredric Silberberg 8b3d79f62b
Add proposal links 2021-02-25 13:23:39 -08:00
Youssef Victor 93404fdb73
Fix PrintMembers return type (#4464) 2021-02-24 12:27:05 -08:00
Charles Stoner 42c3677c51
Update README.md 2021-02-24 10:27:10 -08:00
AlekseyTs 834bcec4d5
Update syntax for Global Using Directive based on LDM decision. 2021-02-23 14:01:39 -08:00
Fred Silberberg 6a3999caca
Add list pattern open questions to the backlog 2021-02-22 21:31:15 -08:00
Fredric Silberberg 0c0df35e90
Added LDM notes for February 22nd, 2021 2021-02-22 16:36:44 -08:00
AlekseyTs 00256069ad
Update README.md 2021-02-20 12:23:00 -08:00
Charles Stoner 04d8e5c4d5
Update README.md 2021-02-19 16:33:21 -08:00
Julien Couvreur 224a2ffa41
Update record-structs.md 2021-02-18 16:52:01 -08:00
Julien Couvreur 1f5b1dc19d
Record decisions for record structs (#4437) 2021-02-18 10:12:23 -08:00
Fred Silberberg 766e12d62c
Remove static delegates proposal (#4448) 2021-02-18 09:55:02 -08:00
AlekseyTs 5de77d1ea3
Add proposal for Global Using Directive (#4449) 2021-02-18 08:33:44 -08:00
Hugo Protsch 660f5a2e1c
Fix Typo (#4438) 2021-02-12 15:59:31 -08:00
Julien Couvreur 8afe00686b
Update README.md 2021-02-12 13:00:15 -08:00
Mads Torgersen 65fc81c8ed
Update LDM agenda 2021-02-12 12:08:13 -08:00
Mads Torgersen 0156250878
Update C# LDM agenda 2021-02-12 11:08:27 -08:00
Fredric Silberberg e698abcbf0
Added LDM Notes for February 10th, 2021. 2021-02-10 17:35:31 -08:00
Joseph Musser 1774292e88
Fix typo (#4404) 2021-02-08 20:13:46 -08:00
Julien Couvreur ec31c2771e
Update async-method-builders.md (#4351) 2021-02-08 17:27:45 -08:00
Fredric Silberberg e7fd82ec95
Added LDM notes for February 8th, 2021 2021-02-08 17:09:24 -08:00
Mads Torgersen 6f3b971e45
Update LDM agenda 2021-02-04 16:42:09 -08:00
AlekseyTs efc800ced7
Update README.md 2021-02-04 11:14:55 -08:00
Fred Silberberg c968dc13da
prefix->postfix 2021-02-03 17:47:44 -08:00
Fredric Silberberg 34da56b1df
Added LDM notes for February 3rd, 2021 2021-02-03 15:27:11 -08:00
Mads Torgersen c449de91e9
Update README.md 2021-02-03 10:00:16 -08:00
Mads Torgersen 1f038d2067
Update LDM agenda 2021-02-01 07:36:53 -08:00
Fredric Silberberg 1741c519d2
Added LDM notes for January 27th, 2020 2021-01-29 18:22:59 -08:00
Mads Torgersen 2328664170
Update LDM agenda 2021-01-27 09:54:32 -08:00
Julien Couvreur 775dc37c18
Update README.md 2021-01-26 10:32:14 -08:00
Fred Silberberg 6ab8409a32
Function pointer type inference (#4310) 2021-01-25 11:08:11 -08:00
Mads Torgersen 6497983e4b
Update LDM agenda 2021-01-21 13:46:32 -08:00
Julien Couvreur a9b70c6ee1
Spec for record structs (#4307) 2021-01-16 16:11:06 -08:00
Julien Couvreur 4170bf5304
Update README.md 2021-01-15 12:06:43 -08:00
Youssef Victor ebe33d5bfe
Fix broken link (#4329) 2021-01-15 11:42:23 -08:00
Julien Couvreur 0470255b81
Update README.md 2021-01-15 11:04:58 -08:00
Fredric Silberberg f80973d27c
Reverse a word 2021-01-14 16:46:40 -08:00
Fredric Silberberg 6d6166fab1
Added notes for January 13th, 2021. 2021-01-14 16:41:27 -08:00
Fredric Silberberg 0d1d5f2efe
Added LDM notes for January 11th, 2021. 2021-01-11 15:10:24 -08:00
Mads Torgersen 6aee98ef1f
Update LDM agenda 2021-01-08 14:00:37 -08:00
Fredric Silberberg b7a4f850cb
Correct folder link, actually add the notes page. 2021-01-06 13:56:34 -08:00
Fredric Silberberg 7199337452
Rename file to 2021 2021-01-06 13:55:17 -08:00
Fredric Silberberg a6ef4e93e4
Added notes for January 5th, 2020 2021-01-06 13:54:15 -08:00
Mads Torgersen aed221e8c3
Update LDM agenda 2021-01-05 15:31:30 -08:00
CyrusNajmabadi e8a7683e85
Update LDM-2020-12-16.md 2020-12-17 16:51:11 -08:00
Fredric Silberberg b2d64b1570
Added LDM notes for December 16th, 2020. 2020-12-17 11:14:24 -08:00
Zhenwei Wu 6c631c0f39
Fix minor error in proposal that affects docs (#4239)
dotnet/docs#21969.
2020-12-16 08:29:22 -08:00
Mads Torgersen 06290c2f91
Update LDM agenda 2020-12-15 16:05:32 -08:00
Joseph Musser efac0d1e90
Fix typo 'retconn' (#4233) 2020-12-14 20:33:50 -08:00
Fredric Silberberg f2aaf44b9c
Added LDM notes for December 14th, 2020. 2020-12-14 15:44:32 -08:00
Mads Torgersen 388aae30b2 Create 2021 LDM agenda 2020-12-11 14:53:07 -08:00
Mads Torgersen a0a6be9894
Update LDM agenda 2020-12-11 14:42:44 -08:00
Mads Torgersen 5c1dccd80e
Update LDM agenda 2020-12-11 14:42:09 -08:00
Fredric Silberberg 21d94ea8c2
Added notes for December 7th, 2020. 2020-12-09 11:54:03 -08:00
Mads Torgersen cdce61573d
Update LDM agenda 2020-12-04 14:47:49 -08:00
Fredric Silberberg 73aec17c03
Added notes for December 2nd, 2020 2020-12-04 10:07:08 -08:00
Jared Parsons 8cf85e8021
Parameter does not escape annotation (#3961)
* Parameter does not escape annotation

This updates the low level struct proposal section on annotations for
parameters that do not escape. This is intended to remove low level
friction points that result from using `ref struct` as arguments to
instance methods on `ref struct`.

* Update proposals/low-level-struct-improvements.md

Co-authored-by: Fred Silberberg <fred@silberberg.xyz>

* Apply suggestions from code review

Co-authored-by: Jan Kotas <jkotas@microsoft.com>

Co-authored-by: Fred Silberberg <fred@silberberg.xyz>
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
2020-12-03 20:36:26 -08:00
Fred Silberberg 7d600fa568
Add required properties to the agenda 2020-11-19 14:57:49 -08:00
Mads Torgersen 3d2315ca49
Update LDM agenda 2020-11-17 13:57:30 -08:00
Mads Torgersen 41054950ef
Update LDM agenda 2020-11-17 13:56:50 -08:00
Jared Parsons 1eef8e0f64
NRT spec updates (#4126)
* NRT spec updates

This makes the following updates to the NRT spec

- Examples for scenarios that commonly trip up customers
- Clarification on when expressions have the null state "maybe default"
  vs. "maybe null"
- Minor langauge cleanup

* PR feedback

* PR feedback
2020-11-17 12:32:02 -08:00
Fredric Silberberg 05dacb663a
Added notes for November 16th, 2020. 2020-11-16 15:14:04 -08:00
Mads Torgersen 59449140af
Update README.md 2020-11-13 15:35:00 -08:00
Mads Torgersen 1df9b32fd7
Update LDM dates 2020-11-13 15:34:45 -08:00
Fred Silberberg 7c519e291f
Fix AsyncMethodBuilder link 2020-11-11 15:27:30 -08:00
Fred Silberberg fd50ce8311
Fix AsyncMethodBuilder link 2020-11-11 15:26:54 -08:00
Fredric Silberberg f5dd4c9e6a
Added notes for November 11th, 2020 2020-11-11 14:23:26 -08:00
Stephen Toub 1fccd6246b
Add comments on localized pooling 2020-11-11 09:39:38 -05:00
Yair Halberstadt 38908f71e5
Add proposal for pattern matching Span<char> on a constant string (#4068) 2020-11-10 15:10:17 -08:00
Julien Couvreur 00d9d791b6
Refresh NRT spec (#4104) 2020-11-09 21:26:43 -08:00
Mads Torgersen d636ada06f
Update README.md 2020-11-09 10:54:38 -08:00
Fred Silberberg ed13b83b47
Add IsRecord to agenda 2020-11-09 10:12:04 -08:00
Stephen Toub 796742db0d
Fix tabs instead of spaces in async method builders proposal 2020-11-08 15:22:18 -05:00
Stephen Toub 4650fd6202
Remove erroneous [Pool] portion of async method builders proposal 2020-11-08 15:21:17 -05:00
Mads Torgersen 1cec9651fd
Update LMD agenda 2020-11-06 14:16:18 -08:00
Rikki Gibson 29b0f41953
Add nullable parameter default proposal (#4101) 2020-11-06 09:57:45 -08:00
Stephen Toub 4c8b0a1c81
Add proposal for per-method AsyncMethodBuilders (#4105)
* Add async methods proposal

* Address PR feedback
2020-11-05 17:58:17 -05:00
Jared Parsons 475c75bfab
Move task like proposal to csharplang (#4107)
Moving the task-like proposal from roslyn to csharplang

https://github.com/dotnet/roslyn/blob/master/docs/features/task-types.md
2020-11-05 14:23:43 -08:00
Fredric Silberberg 1458643eab
Added notes for November 11th, 2020 2020-11-04 16:00:41 -08:00
Julien Couvreur 29df547564
Fork NRT speclet (#4100) 2020-11-04 12:05:09 -08:00
Fred Silberberg 22ab7021c3
Add init accessors in readonly structs and readonly properties (#3915) 2020-11-02 12:55:26 -08:00
Fred Silberberg 87c087f410
Add list patterns to schedule when convenient. 2020-11-02 11:05:37 -08:00
Mads Torgersen 7712303fc6
Update LDM agenda 2020-11-01 16:38:48 -08:00
Youssef Victor 7125a8428a
Fix typo (is -> if) (#4091) 2020-10-31 11:56:08 -07:00
Julien Couvreur b2b83eed29
Disallow unsafe types for record parameters (#4077) 2020-10-29 22:17:22 -07:00
Mads Torgersen a4c37c2d68
Add to the LDM agenda 2020-10-29 17:28:46 -07:00
Yair Halberstadt 75ea1d741f
Allow trailing comma after subpatterns (#4069) 2020-10-27 10:39:10 -07:00
Fred Silberberg ddbd1e2505
Fix bullets 2020-10-26 14:18:25 -07:00
Fredric Silberberg 211d49a34f
Add notes for October 26th, 2020 2020-10-26 14:17:17 -07:00
Charles Stoner 9807f9b2e2
Add proposals/csharp-9.0/unconstrained-type-parameter-annotations.md (#4043) 2020-10-26 13:19:24 -07:00
Julien Couvreur 4fc7fcf83b
Update README.md 2020-10-24 22:20:25 -07:00
Julien Couvreur 0d9762aa9f
Allow semi-colon after block body for record declarations (#4060)
Since we allow `class C { };`
2020-10-23 10:52:39 -07:00
Fredric Silberberg 346d2d2125
Added notes for October 21st, 2020 2020-10-21 14:56:54 -07:00
Mads Torgersen 1042196165
Add LDM dates 2020-10-21 09:33:44 -07:00
Mads Torgersen dc5830cd93
Update C# LDM 2020-10-21 09:16:18 -07:00
Petr Kulikov 94b8189f4a
Covariant returns - typo fixes (#4045) 2020-10-21 10:30:43 -04:00
Fred Silberberg e4b0ade065
Add info about the milestones to the README. (#4011) 2020-10-20 15:02:12 -07:00
Charles Stoner a0b59a6768
Add proposals/csharp-8.0/shadowing-in-nested-functions.md (#4036)
* Add proposals/csharp-8.0/shadowing-in-nested-functions.md

* Use enclosing method rather than scope

* Misc.
2020-10-19 12:56:27 -07:00
Mads Torgersen 8e7d390f6d
Update LDM agenda 2020-10-16 17:36:37 -07:00
Mrxx99 f6a4820041
Updated records in proposal "discriminated-unions" (#4014)
Changed "data class" in examples to "record" and some other adjustments to conform more with records.
Also swapped position of "partial" and "abstract" because apparently the compiler only likes it the other way.
To get the examples to compile the classes that contain the records ("Shape", "Binary" and "Expr") should also be changed to record but I left that out for now.
2020-10-15 10:51:54 -07:00
Fredric Silberberg 843230d5c0
Added notes for October 14th, 2020 2020-10-14 14:57:31 -07:00
Fred Silberberg 87adc18115
Fix links 2020-10-13 11:59:07 -07:00
Fred Silberberg 2878f42415
Fix list formatting 2020-10-13 11:55:19 -07:00
Fredric Silberberg c2b4f93666
Added notes for October 12th, 2020. 2020-10-12 16:00:42 -07:00
Eamon Nerbonne 88ef4b0056
revist => revisit (#3995) 2020-10-11 09:45:46 -07:00
Mads Torgersen d5d2f87c23
Update LDM agenda 2020-10-09 14:30:22 -07:00
Fred Silberberg 1efe320de3
Fix ToC 2020-10-07 16:01:51 -07:00
Fredric Silberberg 41828d6f50
Added notes for October 7th, 2020 2020-10-07 15:58:39 -07:00
Mads Torgersen 57ab7dca0d
Add next design review to agenda 2020-10-07 12:31:12 -07:00
Mads Torgersen b22cb4c657
Update README.md
Remove obsolete agendas
2020-10-07 12:29:53 -07:00
Fredric Silberberg 7cbb29465b
Added notes for October 5th, 2020 2020-10-06 14:58:21 -07:00
WhiteBlackGoose 7014365bd8
System.StringBuilder -> System.Text.StringBuilder (#3976) 2020-10-06 07:59:50 -07:00
Damien Guard 23c9e13493
Add missing , to record_base rule (#3972) 2020-10-05 09:49:56 -07:00
Damien Guard 6bfe301e79
Update records to correct pubic to public (#3971) 2020-10-05 08:04:38 -07:00
Mads Torgersen a2cd3c4947
Update LDM agenda 2020-10-02 13:37:25 -07:00
Fred Silberberg 201a8cb7fe
Remove missing link 2020-10-01 13:29:06 -07:00
Fred Silberberg b5ff2efa01
Fix nested list. 2020-10-01 13:28:42 -07:00
Fredric Silberberg a3d67d1415
Added notes for September 30th, 2020 2020-10-01 13:21:55 -07:00
Jared Parsons 77b2ab88a0
Proposal: Low level struct improvements (#3936)
* Proposal: Low level struct improvements

This design covers adding the following features to C# for low level
struct performance improvements:

- Allowing `ref struct` to contain `ref` fields.
- Allowing `struct` and `ref struct` to return `ref` to their fields.
- Allowing safe fixed buffers for unmanaged and managed types.

Note: the section on providing parameter escape notations is incomplete
at this time. I will send a PR in the future once I finalize this
portion. Feel free to still leave comments though.

Iterations

* Rename to ThisRefEscapes

The name `[RefEscapes]` was causing a lot of confusion in the
discussions. People were mis-interpretting it as a general feature that
could apply to other constructs when in reality it's a very specific and
targetted feature. Renaming to `[ThisRefEscapes]` to make it clear this
is a very targetted feature.

* Allow heap inputs

Based on feedback from several people I've decided that we need to make
the rules for `ref` fields more flexible when the values being passed
around are known to refer to the heap. In those cases there is simply no
reason to restrict the created `ref struct` as it is always
*ref-safe-to-escape* to the enclosing method as well as not requiring
any adjustment to the method invocation rules.

This does mean that we need to add the notion of "refers to the heap" to
the span safety document. That doesn't change any assumptions there.
It's just that before this change the notion of "refers to the heap"
wasn't necessary to describe our safety rules.


Co-authored-by: Ruikuan <liruikuan@outlook.com>
Co-authored-by: Joseph Musser <me@jnm2.com>
2020-09-29 08:31:01 -07:00
Fredric Silberberg cd13c1328c
Added notes for September 28th, 2020 2020-09-28 14:46:57 -07:00
Andrew Hill 3f6a61b29b
We should Inform people about appropriate use of analyzers (#3934)
* We should Inform people about appropriate use of analyzers

as per #3925

* Update README.md

Co-authored-by: Fred Silberberg <fred@silberberg.xyz>
2020-09-27 11:14:17 -07:00
Fred Silberberg 8bcdc05af8
Corrected the date 2020-09-26 21:10:52 -07:00
Mads Torgersen f11bd0833f
Update LDM agenda 2020-09-25 13:57:51 -07:00
Fredric Silberberg 74861d2aaf
Added notes for September 23rd, 2020. 2020-09-25 10:15:08 -07:00
Youssef Victor b2699bff42
Update native integers conversions (#3941) 2020-09-25 09:45:17 -07:00
Julien Couvreur 3f901fa303
Exclude static fields and setter-only properties from PrintMembers (#3919) 2020-09-21 10:19:52 -07:00
Youssef Victor ad94ce8053
Update records spec (#3918) 2020-09-21 09:56:09 -07:00
AlekseyTs d6109bf586
Clarify that a copy constructor doesn't prevent an automatic addition of a default instance constructor for a record. (#3913) 2020-09-21 05:31:23 -07:00
Mads Torgersen b06bc10585
Update README.md 2020-09-18 15:55:32 -07:00
Mads Torgersen b6a06dae21
Update LDM agenda 2020-09-18 15:52:06 -07:00
AlekseyTs a87af899c0
Allow record's parameter_list to be empty. (#3900)
* Allow record's `parameter_list` to be empty.

Based on https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-08-24.md#base-calls-on-parameterless-records
2020-09-18 10:13:26 -07:00
Fredric Silberberg 3882702804
Add notes for September 16th, 2020 2020-09-17 11:28:00 -07:00
Neal Gafter 2661a4b395
Change to 7.5.4.2 Grammar Ambiguities in patterns spec to support type pattern. 2020-09-16 11:32:32 -07:00
Neal Gafter fcf884f7f8
Update pattern spec for narrowed type of ITuple pattern (#3891)
Fixes https://github.com/dotnet/roslyn/issues/44102
2020-09-16 09:27:34 -07:00
Petr Kulikov 8203726f00
Minor grammar and typo fixes (#3370) 2020-09-16 09:18:49 -07:00
Fredric Silberberg addae801a3
Add notes for September 14th, 2020 2020-09-14 15:39:39 -07:00
Fred Silberberg f20eb250f6
Add warning wave to future discussion 2020-09-14 13:34:38 -07:00
Youssef Victor ca09fc178f
Update records spec with new warning (#3883)
* Update records spec with new warning

* Update proposals/csharp-9.0/records.md

Co-authored-by: Fred Silberberg <fred@silberberg.xyz>

Co-authored-by: Fred Silberberg <fred@silberberg.xyz>
2020-09-11 16:07:40 -07:00
Mads Torgersen b4b5b530da
Update C# LDM agenda 2020-09-11 15:44:04 -07:00
Julien Couvreur 1333a5bcd3
Update README.md 2020-09-11 15:10:04 -07:00
Charles Stoner 2241fc9083
Update README.md 2020-09-11 15:07:18 -07:00
Julien Couvreur 8032d0c7c3
Update README.md 2020-09-11 14:09:51 -07:00
Julien Couvreur 1a6e8ca4e4
Update README.md 2020-09-11 14:05:07 -07:00
NetMage 8cb28ad560
Update LDM-2020-05-27.md (#3875)
Replaced incorrect structs with classes in: "less far behind" than structs in record features
2020-09-10 18:56:10 -07:00
Mads Torgersen 1b48340ac8
Update LDM agenda 2020-09-10 18:21:24 -07:00
Julien Couvreur 04ab4562e9
Update README.md 2020-09-10 17:47:46 -07:00
Mads Torgersen b3a10fc9ab
Update LDM agenda 2020-09-10 17:47:24 -07:00
Fred Silberberg 622f4ea4ff
Add missing we 2020-09-10 16:40:02 -07:00
Youssef Victor 9fb76a990c
Grammar fixes (#3827)
Co-authored-by: Fred Silberberg <fred@silberberg.xyz>
2020-09-10 09:57:50 -07:00
Fred Silberberg 09aecc2f74
Add issue templates (#3872) 2020-09-10 09:54:59 -07:00
Fredric Silberberg 41a28555bf
Add README link for notes. 2020-09-09 16:59:30 -07:00
Fredric Silberberg 38c2e48ada
Added LDM notes for September 9th, 2020. 2020-09-09 16:57:46 -07:00
Bill Wagner 8df4f29c1c
fix broken link (#3865)
The path is needed for the spec link
2020-09-09 09:36:14 -07:00
Youssef Victor d52960a47b
Fix broken link (#3861) 2020-09-09 09:35:31 -07:00
Mads Torgersen b61ecce72b
Update LDM agenda 2020-09-08 16:33:27 -07:00
Julien Couvreur c3df20406f
Document features shipping in C# 9.0 (#3850) 2020-09-08 11:17:39 -07:00
Mads Torgersen b23ef78ab5
Add Discussions guidance 2020-09-08 10:17:00 -07:00
Christopher Watford 7cf8d52977
Restore missing code example (#3862)
Follow on to eade6b9#diff-c5d292723e1e43121acb1f8360545e53
2020-09-08 09:25:42 -07:00
Charles Stoner cc11a3bb7a
Recent updates for native integers (#3856) 2020-09-08 09:18:46 -07:00
Youssef Victor 3a6c79012a
Add missing commas (#3855) 2020-09-06 10:00:20 -07:00
Youssef Victor 95adf054b9
Add H1 to convariant returns (#3846) 2020-09-04 11:14:13 -07:00
Neal Gafter ac14d87c16
Update spec for covariant returns. (#3843) 2020-09-03 16:57:07 -07:00
Neal Gafter dd40959c46
Create empty-params-array.md 2020-09-03 14:44:12 -07:00
Fred Silberberg 31289a8255
Merge pull request #3823 from 333fred/update-unmanagedcallesonly 2020-08-26 10:18:52 -07:00
Fredric Silberberg 3213aa0993
Update incorrect examples. 2020-08-26 10:18:18 -07:00
Fredric Silberberg 3e179c04d4
Address PR feedback:
1. Simplify the parameter/return requirements.
2. Clarify the intent around invalid imported metadata.
2020-08-25 17:10:34 -07:00
Fredric Silberberg 55df4c7f82
Update with feedback 2020-08-25 16:44:57 -07:00
Fredric Silberberg 7ff6cb3bb7
Clarify the rules on UnmanagedCallersOnly 2020-08-25 15:48:55 -07:00
Yaakov 94b0500e97
Update LDM-2020-08-24.md (#3819)
Fix spelling
2020-08-25 08:04:19 -07:00
Fredric Silberberg fc840b53c5
Added notes for August 24th, 2020. 2020-08-24 16:16:55 -07:00
Julien Couvreur f38867ee6e
Avoid boxing and extra space when printing records 2020-08-24 13:34:27 -07:00
Mads Torgersen e95770c463
Update README.md 2020-08-24 16:31:54 +02:00
Mads Torgersen d0fde6692c
Update README.md 2020-08-24 16:30:17 +02:00
Fred Silberberg 5d40e91f04
Use clearer terminology 2020-08-21 13:30:51 -07:00
Genevieve Warren 06ee75e6e3
Fix/remove broken links (#3801)
* Fix broken link

* Update module-initializers.md

* Update module-initializers.md

* Update target-typed-new.md

* Make link relative

Co-authored-by: Youssef Victor <31348972+Youssef1313@users.noreply.github.com>

* Update proposals/csharp-9.0/module-initializers.md

Co-authored-by: Bill Wagner <wiwagn@microsoft.com>

Co-authored-by: Youssef Victor <31348972+Youssef1313@users.noreply.github.com>
Co-authored-by: Bill Wagner <wiwagn@microsoft.com>
2020-08-21 11:08:25 -04:00
Bill Wagner cc02cda55f
Markdig syntax fix
Markdig requires a blank line before the start of a table.
2020-08-18 21:17:40 -04:00
Rikki Gibson a69376ba67
Update nullable-constructor-analysis.md (#3794) 2020-08-13 16:29:11 -07:00
Rolf Bjarne Kvinge a7b84ea928
Fix typo. (#3792) 2020-08-12 08:03:52 -07:00
Fred Silberberg eade6b9b55
Remove bad void* example. 2020-08-10 17:50:13 -07:00
Fred Silberberg db3bb77338
Add missing semicolon in calling conventions 2020-08-10 17:40:29 -07:00
Fredric Silberberg 4f801a3b72
Update communities and readme with links to the dotnet evolution discord. 2020-08-10 10:02:21 -07:00
Julien Couvreur 7d3c77ee79
Add ToString and PrintMembers to records (#3762) 2020-08-07 10:37:56 -07:00
Bill Wagner f222935330
Fix table rendering (#3773)
The previous table style worked for GFM, but was not valid for markdig.
2020-08-05 10:12:15 -04:00
Hadrian Tang 4f02d029d1
Remove erroneous backtick (#3769) 2020-08-03 10:37:30 -07:00
AlekseyTs cd3c18237b
Specify equality operators for records (#3754)
See https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-07-27.md#conclusion-1
2020-07-31 10:49:11 -07:00
Julien Couvreur a4a9e017df
Clarify some restrictions on records (#3759) 2020-07-30 23:58:06 -07:00
Bill Wagner a88d56e313
fix a number of broken links (#3750)
These were found building dotnet/docs#19736

- Add correct folders for several spec references.
- Correct casing of one anchor tag.
- Replace absolute links with relative links.
2020-07-30 14:39:47 -04:00
Rikki Gibson 29c08a3460
Update LDM-2020-07-27.md 2020-07-30 10:57:04 -07:00
Rikki Gibson 5bde862ee7
Add nullable-constructor-analysis.md (#3742) 2020-07-30 10:56:00 -07:00
Neal Gafter 89bbdd101f
Move C# 9 proposals for integrated features. (#3751) 2020-07-29 14:09:31 -07:00
Fred Silberberg 71813f1643
Merge pull request #3747 from Youssef1313/patch-3 2020-07-29 09:47:28 -07:00
Fred Silberberg c92ac50c37
Merge pull request #3721 from leandromoh/patch-4 2020-07-29 09:46:13 -07:00
Youssef Victor eca37476cc
Update function-pointers.md 2020-07-29 18:07:34 +02:00
Youssef Victor 94ed97a268
Fix href 2020-07-29 18:02:19 +02:00
Fredric Silberberg c92018c46b
Add extra newline. 2020-07-28 11:11:40 -07:00
Fredric Silberberg 98a98559a8
Add notes for August 27th, 2020. 2020-07-28 11:10:50 -07:00
Julien Couvreur dba9200990
Update README.md 2020-07-28 10:15:58 -07:00
Julien Couvreur 0c25406d8a
Move C# 9 specs to sub-folder (#3731) 2020-07-27 22:59:33 -07:00
Julien Couvreur cede56944c
Update README.md 2020-07-27 15:59:24 -07:00
Mads Torgersen 3bdc3355b8
Update README.md 2020-07-27 10:36:29 -07:00
Mads Torgersen 45bc98cca5
Update README.md 2020-07-25 15:33:35 -07:00
Leandro Fernandes 3f91ebca93
remove pt-br from url 2020-07-25 14:37:16 -03:00
Leandro Fernandes 1d383e70d4
Update Language-Version-History.md
Co-authored-by: Fred Silberberg <fred@silberberg.xyz>
2020-07-25 14:36:28 -03:00
Mads Torgersen ea449ed112
Update README.md 2020-07-24 16:30:59 -07:00
Rikki Gibson 28eb378734
Delete nullable-constructor-analysis.md
This file wasn't intended to be added to `master` yet
2020-07-24 13:19:48 -07:00
Rikki Gibson 1dd5317c8b Add nullable-constructor-analysis.md 2020-07-24 13:18:54 -07:00
Mads Torgersen 2dda3cdd75
Update README.md 2020-07-24 12:49:11 -07:00
Leandro Fernandes 384dc3b466
adds few features 2020-07-24 14:23:14 -03:00
Fred Silberberg c25bf006cd
Merge pull request #3710 from 333fred/public-conventions
Only support public calling convention types.
2020-07-22 09:37:37 -07:00
Fredric Silberberg ebaabf6ca3
Only support public calling convention types. 2020-07-21 14:52:22 -07:00
Julien Couvreur c11b561232
Update README.md 2020-07-21 13:56:08 -07:00
Fred Silberberg de1645446e
Add equality operators in records to the agenda 2020-07-21 10:56:33 -07:00
Fredric Silberberg c6f4a217a6
Added LDM notes for 2020-07-20. 2020-07-20 15:52:41 -07:00
Julien Couvreur 32bfa55d19
Update README.md 2020-07-20 12:02:35 -07:00
Julien Couvreur 9a99808082
Update README.md 2020-07-20 12:01:29 -07:00
Julien Couvreur 731b371161
Update README.md 2020-07-20 11:52:03 -07:00
AlekseyTs 84c16c14e0
Rename Variance-safety-for-static-interface-members.md to variance-safety-for-static-interface-members.md 2020-07-19 09:26:18 -07:00
AlekseyTs 1052c8855f
Create Variance-safety-for-static-interface-members.md 2020-07-19 09:25:24 -07:00
Mads Torgersen 994c41586e
Update LDM Agenda 2020-07-17 15:42:13 -07:00
Fred Silberberg 8087d27db1
Merge pull request #3696 from anurmatov/patch-1
Update unsafe-code.md
2020-07-17 09:39:32 -07:00
AlekseyTs a5899d45d1
Clarify expected accessibility of an EqualityContract property in a record directly inheriting from object. (#3700) 2020-07-16 14:49:17 -07:00
Michael Ketting 6b9a732aa3
Fixed typo in Readme.md (#3694)
The link to the Design Notes for June 24th was set to June 22nd.
2020-07-16 08:15:53 -07:00
anurmatov 7d4c75a2da
Update unsafe-code.md
It should be specified comparison operator `>=` (greater than or equal) instead of lambda `=>`
2020-07-16 14:14:04 +06:00
AlekseyTs 3402ccd0e0
Clarify semantics of with expression. (#3690) 2020-07-15 16:02:56 -07:00
AlekseyTs 66fd2ffbda
Clarify accessibility of a synthesized record copy constructor. (#3686) 2020-07-15 13:20:16 -07:00
Fred Silberberg 1124abb051
Merge pull request #3688 from slang25/patch-2
Correct LDM date
2020-07-15 12:58:21 -07:00
Stuart Lang fe73722354
Correct date 2020-07-15 20:55:02 +01:00
AlekseyTs e149d1e9c0
Clarify accessibility requirements for explicitly declared record copy constructor. (#3678) 2020-07-15 09:55:25 -07:00
AlekseyTs 5a09cc1726
Add clarifications for instance "clone" method (#3683) 2020-07-15 09:32:46 -07:00
Neal Gafter f1533732b0
Missing ':' in format part of interpolation (#3679) 2020-07-15 09:23:26 -07:00
Mads Torgersen c46030b7fd
Update README.md 2020-07-14 12:42:46 -07:00
Julien Couvreur e874c6d46e
Disallow certain modifiers in record parameters (#3672) 2020-07-14 12:06:46 -07:00
AlekseyTs db9bca1e5c
Document ability to explicitly declare Deconstruct method. (#3670) 2020-07-14 10:15:08 -07:00
AlekseyTs c6c9e199ad
Applying attributes to properties and fields that are created to back primary constructor parameters (#3667) 2020-07-14 10:14:32 -07:00
Julien Couvreur 09c67fbf78
Local functions and lambdas are outside init phase (#3674) 2020-07-13 22:24:09 -07:00
Fredric Silberberg ee1ba85e54
Add missing triage decision to the notes. 2020-07-13 15:01:16 -07:00
Fredric Silberberg dfedf00f3c
Fix link in 2020 readme 2020-07-13 14:55:43 -07:00
Fredric Silberberg e4429f399f
Add notes for July 17th, 2020 2020-07-13 14:53:05 -07:00
Mads Torgersen 9cf2f66647
Update LDM agenda 2020-07-09 13:55:15 -07:00
Rikki Gibson 4e69e5cde3
Update repeated-attributes.md (#3661) 2020-07-09 13:48:23 -07:00
Julien Couvreur 78a7c37efe
Disallow "Clone" members (#3652) 2020-07-09 10:11:13 -07:00
Rikki Gibson cc68af0b2a
Repeated attributes across partial declarations (#3646)
* Create repeat-attributes.md

* Update repeat-attributes.md

* Update repeat-attributes.md

* Update repeat-attributes.md

* Fix filename

* Update repeated-attributes.md
2020-07-08 17:07:10 -07:00
Rikki Gibson d0deb2f61b
Update and rename static-lambdas.md to static-anonymous-functions.md (#3651) 2020-07-08 17:06:50 -07:00
Rikki Gibson b50c5ee1d9
Update repeated-attributes.md 2020-07-08 14:25:29 -07:00
Fredric Silberberg d96d221393
Add notes for July 7th, 2020, update readme. 2020-07-08 13:26:15 -07:00
AlekseyTs 2cbd8db612
Additional clarifications around Equality members (#3641) 2020-07-08 11:22:31 -07:00
Fred Silberberg 1aaa2ce941
Merge pull request #3647 from Jay-Madden/master 2020-07-07 15:46:50 -07:00
David Pine 9b736b5b73
Update the ranges.md file to correctly represent the actual impl. (#3645) 2020-07-07 10:51:45 -04:00
Jay c4f7854f1c Added mention ??= rules 2020-07-07 09:48:49 -04:00
Jay 0d8b6b6596 Added Pointer-null-coalescing.md 2020-07-06 17:42:09 -04:00
Rikki Gibson 9ae50fad18 Fix filename 2020-07-06 13:01:17 -07:00
Rikki Gibson ad8e804774
Update repeat-attributes.md 2020-07-06 12:54:09 -07:00
Mads Torgersen 43966001af
Update README.md 2020-07-02 16:10:49 -07:00
Mads Torgersen 5f42632905
Update README.md 2020-07-02 16:04:51 -07:00
AlekseyTs ce26928a60
Clarify some aspects of inheritance and equality for records (#3634) 2020-07-02 14:16:03 -07:00
Rikki Gibson ec49f96cb7
Update repeat-attributes.md 2020-07-02 13:53:22 -07:00
Rikki Gibson 0cab9c586a
Update repeat-attributes.md 2020-07-02 13:52:17 -07:00
Fredric Silberberg 464e8d16e3
Add notes for 7/1/2020 2020-07-02 12:36:07 -07:00
Fred Silberberg 1bb454804d
Update the calling convention and UnmanagedCallersOnly attribute. (#3441)
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
2020-07-01 15:02:01 -07:00
Fredric Silberberg 2ca2a15434
Fix typo. 2020-07-01 15:01:18 -07:00
Fredric Silberberg 07582155a4
Update the calling convention sections with feedback from internal design, LDM decisions, and PR feedback. 2020-06-30 16:05:25 -07:00
Fred Silberberg dd3261cfde
Add required properties to the schedule. 2020-06-30 11:44:45 -07:00
Charles Stoner 413c55fe88
Override abstract property get and init accessors (#3626) 2020-06-30 10:53:26 -07:00
Mads Torgersen 510a72d2fc
Update README.md 2020-06-29 17:17:44 -07:00
Fredric Silberberg 6d8cee6e4a
Added notes for 6/29/2020 2020-06-29 17:16:32 -07:00
Andy Gocke 7460aa357e Adjust agenda 2020-06-28 22:22:19 -07:00
Andy Gocke 7058cc815e Add LDM notes for June 22, 2020 2020-06-28 22:20:41 -07:00
Mads Torgersen 607706fbf5
Update README.md 2020-06-26 10:52:29 -07:00
Mads Torgersen 6d43eec15c
Update README.md 2020-06-25 16:55:04 -07:00
Julien Couvreur 8498f4963c
Update README.md 2020-06-25 14:59:16 -07:00
Petr Kulikov 6f244db799
Fix typo in tuple equality proposal (#3614) 2020-06-25 11:42:58 -07:00
Fredric Silberberg 3b8500a93f
Added notes for 6/24/2020 2020-06-25 11:21:37 -07:00
Leandro Fernandes f4b1117610
Add features in Language-Version-History.md (#3371)
* Update Language-Version-History.md

* remove en-us from links

* `params` arrays

* removed "Statement" bullet

* specify yield and lock statements

* adjust links section

* adds more links

* adds few more links

* added Covariance and contravariance in c#

reference https://docs.microsoft.com/pt-br/dotnet/csharp/whats-new/csharp-version-history
2020-06-25 08:34:14 -04:00
Julien Couvreur b901db48de
Update static-lambdas.md 2020-06-24 14:00:36 -07:00
Rikki Gibson aa2d828c82
Update module-initializers.md (#3604) 2020-06-23 15:23:17 -07:00
Andy Gocke 7c44a62f9a
Add nullable spec for nested functions 2020-06-22 15:07:55 -07:00
Fred Silberberg 26966202e8
Add function pointer link for Wednesday. 2020-06-22 11:16:48 -07:00
Mads Torgersen 0df3446c36
Update README.md 2020-06-22 08:24:00 -07:00
Charles Stoner d48f35e584
Records: update "Equality members" spec section (#3583) 2020-06-19 14:20:47 -07:00
Andy Gocke 0e365431d7 Add LDM notes for 2020-06-17 2020-06-18 16:31:16 -07:00
Andy Gocke a05203115d Add LDM notes for 2020-06-15 2020-06-18 16:23:32 -07:00
Kevin Sun eb00bb077e
Add constant interpolated strings (#3581)
* Create constant_interpolated_strings.md

* Update constant_interpolated_strings.md

* Update constant_interpolated_strings.md

* Update constant_interpolated_strings.md

* Update constant_interpolated_strings.md

* Update constant_interpolated_strings.md
2020-06-18 09:43:38 -07:00
Fred Silberberg aa2ff4d18a
Add spec for extension GetEnumerator (#3576)
* Add extension GetEnumerator spec.

* Add await foreach note
2020-06-17 16:40:02 -07:00
Mads Torgersen 9ca3758397
Update README.md 2020-06-17 10:33:28 -07:00
Hiroshi Yoshioka 538df2e3c3
Typo "***" (#3405)
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/nullable-reference-types-specification
2020-06-17 08:30:02 -07:00
Mads Torgersen 7efb8212e5
Update README.md 2020-06-15 13:56:27 -07:00
Charles Stoner 4c158751bb
Update README.md 2020-06-15 09:03:57 -07:00
Mads Torgersen f84503e651
Update README.md 2020-06-15 08:58:56 -07:00
Mads Torgersen 1a38cbd5b1
Update README.md 2020-06-15 07:34:57 -07:00
Rikki Gibson c90824ed24
Create repeat-attributes.md 2020-06-12 16:59:32 -07:00
Mads Torgersen 82c4d68bb8
Update README.md 2020-06-11 12:02:05 -07:00
Andy Gocke 0f56445e25 Add LDM notes for June 10, 2020 2020-06-10 12:22:54 -07:00
Charles Stoner 3bfb6f875a
Update record equality specification (#3552) 2020-06-10 12:16:37 -07:00
AlekseyTs 0e42c53aa5
Clarify some aspects for record constructors (#3548) 2020-06-10 08:46:46 -07:00
Mads Torgersen 348d1c74a9
Update README.md 2020-06-09 11:12:16 -07:00
Mads Torgersen ab0c24d125
Update README.md 2020-06-09 11:10:06 -07:00
Andy Gocke 5c9b8f27bd
Update records.md (#3547) 2020-06-08 14:01:34 -07:00
Mads Torgersen 956d7e8ece
Update LDM agenda 2020-06-05 15:50:17 -07:00
Andy Gocke 100d3f7f04
Bring records proposal up to date (#3527)
Try to bring the proposal in line with LDM decisions. Inheritance is somewhat described, but there
have been no affirmative decisions by LDM so this is still in flux
2020-06-04 12:18:43 -07:00
Mads Torgersen 14f32ea1f1
Update README.md 2020-06-04 09:25:44 -07:00
Andy Gocke 6c404867b9
Add spec for nominal records (#3520) 2020-06-02 14:21:18 -07:00
Andy Gocke 2b2452802a Add LDM notes for June 1, 2020 2020-06-01 14:33:26 -07:00
Andy Gocke 85263bfff8 Add LDM notes for May 27, 2020 2020-05-31 15:23:16 -07:00
Neal Gafter 41e377c7fa
Update target-typed conditional expression spec. (#3503) 2020-05-31 14:29:44 -07:00
Andy Gocke ae11413106 Move old records proposals to rejected/ and rename current proposal 2020-05-30 12:24:13 -07:00
Andy Gocke 04f998e2f9
Update records-wip.md (#3505) 2020-05-30 12:21:00 -07:00
Mads Torgersen 7f02ff0a8b
Update LDM agenda 2020-05-29 15:49:55 -07:00
Mads Torgersen e1f35d1569
Update LDM agenda 2020-05-29 11:09:47 -07:00
Mads Torgersen 35c14f7c15
Update LDM agenda 2020-05-26 11:51:35 -07:00
Andy Gocke 300226c009
Update spec for record value equality (#3396) 2020-05-24 12:25:51 -07:00
Neal Gafter e355841daa
Update target-typed-conditional-expression.md
Adjust specification.
2020-05-21 14:53:19 -07:00
Andy Gocke 751ebd4669 Add LDM notes for 2020-05-11 2020-05-19 00:54:16 -07:00
Neal Gafter 125539b88d
Add doc for C# 6.0 struct autoprop initialization (#3459) 2020-05-18 16:36:57 -07:00
Jaliya Udagedara c2df2ee72f
Update constructor parameters (#3466) 2020-05-17 10:12:44 -07:00
JesperTreetop 9c3fde1e45
Correct March to April (#3461) 2020-05-15 08:24:07 -07:00
Matt Styles c2fe8f1d15
Updated status of null coalescing assignment from proposed to implementation completed (#3451)
* Updated status of null coalescing assignment from proposed to implementation completed

The feature is available in C# 8. I can't see guidance on what should be updated in these docs to reflect that, so not sure if what I've changed is what should be changed!

* Update null-coalescing-assignment.md

Marking all stages of null coalescing assignment proposal as completed with checkbox filling
2020-05-12 14:41:23 -07:00
Mads Torgersen 97eaba738e
Update README.md 2020-05-12 08:56:49 -07:00
Julien Couvreur 1466a8ae9e
Update README.md 2020-05-12 07:31:40 -07:00
Julien Couvreur 91b25c73a8
Update README.md 2020-05-11 14:07:05 -07:00
Julien Couvreur 76631d3a84
Update README.md 2020-05-11 14:06:24 -07:00
Julien Couvreur 9face9a8ec
Update README.md 2020-05-11 14:05:46 -07:00
AlekseyTs dccd6f151a
Merge pull request #3442 from AlekseyTs/SimplePrograms_04
Providing access to command line arguments within top-level statements
2020-05-11 10:34:04 -07:00
Andy Gocke ac0b1302b1 Fix file name for 2020-05-04 notes 2020-05-09 17:09:46 -07:00
Andy Gocke 45d49ec640 Add LDM notes for May 6, 2020 2020-05-09 17:06:58 -07:00
Andy Gocke a2d15ae55b Add LDM notes for May 4, 2020 2020-05-09 17:02:06 -07:00
AlekseyTs c657de69f5
Providing access to command line arguments within top-level statements 2020-05-09 09:43:55 -07:00
Fred Silberberg d073319400
Update proposals/function-pointers.md
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
2020-05-08 23:16:08 -07:00
Fredric Silberberg fc347a5739
Update the calling convention and UnamangedCallersOnly attribute. 2020-05-08 16:14:30 -07:00
AlekseyTs f7f8935d16
Merge from dotnet/csharplang
Merge from dotnet/csharplang
2020-05-08 10:45:45 -07:00
Julien Couvreur 36bf39178d
Update README.md 2020-05-07 14:26:53 -07:00
Julien Couvreur 21a249d0d0
Update README.md 2020-05-07 08:25:20 -07:00
Julien Couvreur da3b99a86d
Update README.md 2020-05-07 08:24:48 -07:00
Neal Gafter a17f4c8ba8
constant pattern is a constant expression. 2020-05-06 14:13:20 -07:00
Neal Gafter c9ae01e03b
Update target-typed-conditional-expression.md 2020-05-05 16:16:39 -07:00
Neal Gafter 347c6665f7
Update target-typed-conditional-expression.md 2020-05-05 16:15:36 -07:00
Mads Torgersen c583233dd8
Update README.md 2020-05-05 15:43:36 -07:00
Alireza Habibi e006b4808d
Permit init-only initialization in attribute usages (#3425) 2020-05-05 12:47:03 -07:00
Mads Torgersen 7c75acb30b
Update README.md 2020-05-01 14:47:14 -07:00
Mads Torgersen 5ee18e113a
Update README.md 2020-05-01 14:39:05 -07:00
Mads Torgersen 8ca39632ed
Update README.md 2020-05-01 14:11:54 -07:00
Andy Gocke c30039481e
Update records-wip.md (#3353)
Add info for the `with` expression
2020-04-30 10:28:24 -07:00
Rikki Gibson 0cec4e00c3
Module initializers (#3392)
Co-authored-by: Fred Silberberg <fred@silberberg.xyz>
2020-04-30 10:03:12 -07:00
Mads Torgersen d77deaccf3
Update LDM-2020-04-15.md 2020-04-28 13:10:24 -07:00
Mads Torgersen 161e9facb5
Update README.md 2020-04-28 13:10:01 -07:00
Mads Torgersen b272718c5f
Update README.md 2020-04-28 13:09:24 -07:00
Mads Torgersen af0265255f
Add files via upload 2020-04-28 13:04:15 -07:00
Andy Gocke 3159656400
Update LDM-2020-04-27.md 2020-04-28 10:26:27 -07:00
Andy Gocke 124dabcb01 Add LDM notes for 2020-04-27 2020-04-27 16:02:34 -07:00
Julien Couvreur ab0873759f
Update init.md 2020-04-26 08:55:22 -07:00
Julien Couvreur cbf73854a6
Tweaks to init-only speclet (#3398) 2020-04-26 08:28:51 -07:00
Neal Gafter f1d43aade5
Move specification from #2844 to proposals. (#3394) 2020-04-24 16:58:39 -07:00
Mads Torgersen 1281700df3
Update README.md 2020-04-24 16:28:49 -07:00
Rikki Gibson 64566a1688
Update extending-partial-methods.md (#3386) 2020-04-23 13:06:39 -07:00
Julien Couvreur fea3e4f374
Update modreq type name 2020-04-22 15:34:43 -07:00
Julien Couvreur 356ee04506
Rename simple programs (#3382) 2020-04-22 10:38:05 -07:00
David Pine 7f1c2a6fe4
Added details and examples for null guard guidance (#3381)
* Added details and examples for null guard guidance

* Update proposals/csharp-8.0/nullable-reference-types.md

Co-Authored-By: Bill Wagner <wiwagn@microsoft.com>

Co-authored-by: Bill Wagner <wiwagn@microsoft.com>
2020-04-22 13:11:13 -04:00
Jared Parsons 5c7cc61921
Extending partial methods (#3379)
* Copy from LDM proposal

* Partial Methods

* Put document in right directory

* Cleanup

* Typo

* Apply suggestions from code review

Co-Authored-By: Joseph Musser <me@jnm2.com>

Co-authored-by: Joseph Musser <me@jnm2.com>
2020-04-22 09:39:24 -07:00
Jared Parsons 3f177e90b1
Init only proposal document (#3367)
* Really rough draft

* modreq vs. attributes

Finished up the section detailing using attributes vs. modreq. Decided
to make it an open question for now vs. a consideration. I felt less
strongly about it after writing it. I still do feel quite passionate
though about this with validators.

* Summary and motivation added

Got the basic summary and motivation added. Feeling good about the
premise here.

* Detailed design section

This ended up persuading me that `init` should be on the `set` method,
not the property itself. There is just too much in common with the
`readonly` modifier here. Plus if we ever decide to include the concept
of `init` members as a general feature then `init` would be required to
be on the `set`.

* Encoding discussions written

* Almost there

* Initial draft completed

* Remove init type modifier

After discussion in LDM we've decide against this as a feature. Reasons
captured in the document.

* Updated all notes

* Respond to LDM decisions

This updates to the following two LDM decisions:
1. Disallow `init` on fields
1. Use `init` instead of `init set`

* Cleaned up emit scenarios

* Apply suggestions from code review

Co-Authored-By: Fred Silberberg <fred@silberberg.xyz>

* Addressed some feedback

* Finish up PR feedback

Finish up the PR feedback on the proposal

* Typo

* PR feedback

* Apply suggestions from code review

Lots of typos 😄

Co-Authored-By: Tiago César Oliveira <4922781+tiagocesar@users.noreply.github.com>
Co-Authored-By: Patrick Westerhoff <PatrickWesterhoff@gmail.com>
Co-Authored-By: Steve Ognibene <steve.ognibene@namely.com>
Co-Authored-By: Viacheslav Ivanov <viacheslav.ivanov@gmail.com>

* Apply suggestions from code review

Co-Authored-By: Julien Couvreur <jcouv@users.noreply.github.com>
Co-Authored-By: Fred Silberberg <fred@silberberg.xyz>

Co-authored-by: Fred Silberberg <fred@silberberg.xyz>
Co-authored-by: Tiago César Oliveira <4922781+tiagocesar@users.noreply.github.com>
Co-authored-by: Patrick Westerhoff <PatrickWesterhoff@gmail.com>
Co-authored-by: Steve Ognibene <steve.ognibene@namely.com>
Co-authored-by: Viacheslav Ivanov <viacheslav.ivanov@gmail.com>
Co-authored-by: Julien Couvreur <jcouv@users.noreply.github.com>
2020-04-20 20:52:29 -07:00
Andy Gocke 95f5f86ba2 Add LDM notes for April 20, 2020 2020-04-20 15:37:31 -07:00
Fred Silberberg 71a1696e3a
Add metadata representation section for in and out (#3368) 2020-04-20 13:56:28 -07:00
Neal Gafter a993c653f5
Add proposal for target-typed conditional expression. (#3363) 2020-04-20 11:46:15 -07:00
Mads Torgersen 46a8659f06
Update README.md 2020-04-20 09:52:34 -07:00
Mads Torgersen 6b14a23b9a
Update README.md 2020-04-20 08:23:29 -07:00
Mads Torgersen 2836e29605
Update README.md 2020-04-20 08:14:21 -07:00
CyrusNajmabadi da18b947b1
Update README.md 2020-04-17 19:30:24 -07:00
Neal Gafter 6901635c38
Add draft spec for C# pattern-matching changes. (#3361) 2020-04-17 16:03:52 -07:00
AlekseyTs 1ecebc412f
Allow returning an integer from a Simple Program (#3342) 2020-04-17 10:20:23 -07:00
CyrusNajmabadi bddb733d59
Update README.md 2020-04-16 18:11:39 -07:00
Mads Torgersen d414836632
Update README.md 2020-04-15 12:03:46 -07:00
Charles Stoner 583bdd220f
Native-sized integers proposal (#2833) 2020-04-14 12:39:37 -07:00
Mads Torgersen 47856e2351
Update README.md 2020-04-13 14:32:41 -07:00
Mads Torgersen 0a75a38f7e
Update README.md 2020-04-13 14:01:13 -07:00
Mads Torgersen 907c155f09
Update README.md 2020-04-13 14:00:25 -07:00
Mads Torgersen c5428f507f
Create LDM-2020-04-13.md 2020-04-13 13:57:21 -07:00
Andy Gocke 88202acd40
Update with expression in records-wip 2020-04-10 12:34:23 -07:00
Fred Silberberg 52624f54c0
Update function pointers proposal for binary operators. (#3348)
* Update function pointers proposal for binary operators.

* Update wording per feedback.
2020-04-09 14:33:18 -07:00
Andy Gocke ff18bac738 Add LDM notes for April 6, 2020 2020-04-08 14:54:50 -07:00
Andy Gocke 017870d59c Add LDM notes for April 8, 2020 2020-04-08 14:47:59 -07:00
Fred Silberberg 14cd563c27
Update schedule
Add open issues in extension GetEnumerator to the to-be-scheduled list.
2020-04-08 14:23:51 -07:00
Mads Torgersen 7b3d402ade
Update README.md 2020-04-08 13:31:12 -07:00
Mads Torgersen 1873ddee96
Update README.md 2020-04-08 10:29:33 -07:00
Andy Gocke 7f0c8e4eac
Keep parameterless record struct constructors 2020-04-07 17:29:48 -07:00
AlekseyTs 897bc11882
Merge from dotnet/csharplang
Merge from dotnet/csharplang
2020-04-07 14:49:00 -07:00
Andy Gocke 9143a30162
Update records-wip.md 2020-04-06 16:57:07 -07:00
Andy Gocke 1cca522b9b
Update records-wip.md 2020-04-06 16:56:29 -07:00
Mads Torgersen 18c41f4cea
Update README.md 2020-04-06 11:53:37 -07:00
Mads Torgersen 8003c3fe73
Update README.md 2020-04-03 13:47:38 -07:00
Jared Parsons 3d424e1a79
Merge pull request #3327 from terrajobst/code-of-conduct
Link Code of Conduct
2020-04-03 12:05:47 -07:00
Andy Gocke 9b256c2906 Added LDM notes for 2020-04-01 2020-04-02 15:29:33 -07:00
Immo Landwerth 59e3f278b9 Link Code of Conduct 2020-04-02 13:42:06 -07:00
Fred Silberberg 7964497b5f
Update function pointer agenda link 2020-03-31 17:23:58 -07:00
Mads Torgersen d2cabfddb0
Update C# LDM agenda 2020-03-31 15:17:29 -07:00
Andy Gocke 0286170d01 Add LDM notes for March 30, 2020 2020-03-30 14:29:33 -07:00
Neal Gafter 26342db77a
Update README.md 2020-03-28 07:28:29 -07:00
Mads Torgersen 21093514a3
Update C# LDM Agenda 2020-03-27 16:43:46 -07:00
Andy Gocke 1e1c7c72b1
Fix spelling 2020-03-25 17:46:24 -07:00
AlekseyTs 75ddc88a40
Limit top-level statements to a single compilation unit within a program (#3292)
Reflect LDM decision made on 2020-03-09 to limit top-level statements to a single compilation unit within a program.
2020-03-25 16:28:26 -07:00
Neal Gafter 64da1dcf00
target-typed new: reflect LDM decisions 2020-03-25 (#3311) 2020-03-25 15:40:49 -07:00
Andy Gocke 23172a7c6d
Add 'with' expression to the spec (#3282) 2020-03-25 15:36:47 -07:00
Andy Gocke 6e748b19f1 Add notes for March 23, 2020 2020-03-25 15:18:45 -07:00
Andy Gocke dee0aaf7b5 Add LDM notes for March 25, 2020 2020-03-25 14:47:17 -07:00
Fred Silberberg 2fef08d7e0
Add function pointers to schedule ASAP 2020-03-25 12:07:50 -07:00
Neal Gafter 74c38d2950
Clean up the specification portion of target-typed new (#3310) 2020-03-25 10:06:34 -07:00
Julien Couvreur 7ea0b8e328
Update target-typed-new.md 2020-03-25 07:13:54 -07:00
Julien Couvreur 1f45494dec
Throw new() is allowed 2020-03-25 07:11:57 -07:00
Mads Torgersen 194a043db7
Update README.md 2020-03-24 09:22:17 -07:00
Julien Couvreur 40bf00abdf
Update target-typed-new.md 2020-03-24 08:48:10 -07:00
Mads Torgersen 19eca6008a
Update LDM agenda 2020-03-24 08:40:08 -07:00
Andy Gocke 6ea9877330 Add LDM notes for March 9, 2020 2020-03-24 00:33:54 -07:00
Andy Gocke 1dbb8e82be Add LDM notes for Feb 26, 2020 2020-03-24 00:19:58 -07:00
Petr Kulikov cf22e016c7
Ranges proposal: fix typos (#2836) 2020-03-23 08:42:41 -07:00
Joseph Musser 636f053f74
'conceit' → 'concept' (#3280) 2020-03-23 08:40:03 -07:00
Mads Torgersen c124903b80
Update LDM agenda 2020-03-23 08:36:41 -07:00
Mads Torgersen 9aa177443b
Update README.md 2020-03-20 13:48:34 -07:00
AlekseyTs d6718accc5
Merge from dotnet/csharplang
Merge from dotnet/csharplang
2020-03-20 13:03:33 -07:00
Neal Gafter 3fa28e4b54
Update shadowing-in-nested-functions.md 2020-03-19 17:39:49 -07:00
Fred Silberberg 45a1455732
Only allow static methods for applicable members (#3281)
* Only allow static methods for applicable members

This fixes a very similar problem to https://github.com/dotnet/csharplang/issues/3277, where this code is unable to be resolved:
```cs
interface I1{}
interface I2{}

public unsafe class C : I1, I2 {
    void M(I1 i) {}
    static void M(I2 i) {}
    public void M1() {
        delegate*<C, void> a = M; // Ambiguous because both M's are applicable
    }
}
```
With this change, the instance method M is not applicable, so there is no ambiguity.
2020-03-19 12:56:34 -07:00
Julien Couvreur a6c38525c2
Update target-typed-new.md (#1989) 2020-03-19 11:44:21 -07:00
Andy Gocke cc9cb6eae6 Add design notes for Feb. 24, 2020 2020-03-18 16:54:17 -07:00
Andy Gocke a847159ec3 Fix typo 2020-03-18 16:07:01 -07:00
Andy Gocke c9be90873a Adjust agenda with new notes 2020-03-18 15:58:44 -07:00
Andy Gocke 82e330685f Add meeting notes for Feb. 19, 2020 2020-03-18 15:56:26 -07:00
Mads Torgersen 33a60a1db1
Update C# LDM Agenda 2020-03-18 09:20:07 -07:00
Mads Torgersen 59ad46e78c
Update LDM Agenda 2020-03-17 14:22:04 -07:00
Rikki Gibson 51e8d545c7
Add draft spec for local function attributes (#3198) 2020-03-17 13:58:50 -07:00
Neal Gafter 70a7286fac
Add placeholder specs for two features from C# 7.0 (#3270) 2020-03-16 18:23:28 -07:00
Bill Wagner 5688b13e66
clarify readonly set (#3266)
Fixes dotnet/docs#13841

I added a note (first recommendation) but did not make any additions for the second. That's covered in more of the tutorials and conceptual docs.
2020-03-13 09:48:25 -04:00
CyrusNajmabadi cdbfdc555b
Update README.md 2020-03-12 08:37:39 -07:00
Fred Silberberg f3170512e7
Add conversions spec for function pointers (#3263)
* Add conversions spec for function pointers.

* Fix typo

Co-Authored-By: Jan Kotas <jkotas@microsoft.com>
2020-03-11 14:33:34 -07:00
Neal Gafter 21b0400850
Add placeholder documents for missing specifications. (#3261) 2020-03-11 11:48:23 -07:00
Eyal Solnik 5745c18024
Reverse the order (#3064)
Recent features/changes should appear first as opposed to last.
2020-03-10 15:05:44 -07:00
LouisFr81 5278336b61
Update tuple-equality.md (#2204) 2020-03-10 12:09:55 -07:00
Zhiliang Xu 3cb286fe1d
Fix a grammar issue (#3176) 2020-03-10 12:08:19 -07:00
Neal Gafter dfed65d105
Update README.md 2020-03-09 12:05:31 -07:00
Mads Torgersen 9d90ddf5f6
Update LDM agenda 2020-03-09 07:26:46 -07:00
Mads Torgersen 9ab097ede9
Update LDM agenda 2020-03-03 10:48:18 -08:00
Alexander Köplinger f530e937c5
Fix typos in function pointers proposal (#3238)
- Preventing -> Presenting
- Fix markdown link
2020-03-02 15:46:09 -08:00
Mads Torgersen 1922535987
Update LDM Agenda 2020-03-02 10:23:20 -08:00
Andy Gocke 2a6dffb607
Add spec for equality (#3189) 2020-02-29 14:21:55 -08:00
Neal Gafter 86a6067e0e
Update README.md 2020-02-26 18:56:11 -08:00
Neal Gafter fdd049e944
Update README.md 2020-02-26 18:55:55 -08:00
Mads Torgersen 526489cd5c
Update LDM Agenda 2020-02-24 11:42:24 -08:00
Neal Gafter fb5c260489
Update README.md 2020-02-22 11:23:01 -08:00
Mads Torgersen 712ce8e53b
Update LDM agenda 2020-02-21 20:57:43 -08:00
Neal Gafter 5b388eb941
Update README.md 2020-02-21 11:59:41 -08:00
Andy Gocke 99094464ff Add LDM notes for Feb. 12, 2020 2020-02-19 20:37:27 -08:00
Andy Gocke b090ab8413 Add LDM notes for Feb. 10, 2020 2020-02-19 20:28:52 -08:00
Mads Torgersen 22c6fd0da6
Update LDM agenda 2020-02-18 13:40:54 -08:00
AlekseyTs 36b028f4d6
Clarify implicit nature of an async context within top-level statements 2020-02-14 15:24:47 -08:00
Neal Gafter 8a0371d784
Update README.md 2020-02-10 16:33:06 -08:00
Andy Gocke e5a56c4ff1 Add LDM notes for Feb. 3, 2020 2020-02-07 19:19:46 -08:00
Andy Gocke 4914e41489 Add meeting notes for Jan. 29, 2020 2020-02-07 19:12:05 -08:00
Andy Gocke 013d92093d Add meeting notes for Feb 5, 2020 2020-02-07 18:47:32 -08:00
Mads Torgersen 73e2a7595b
Update LDM agenda 2020-02-07 12:53:17 -08:00
AlekseyTs e0031c5139
Add proposal for "Simple programs" feature (#3159) 2020-02-06 10:33:11 -08:00
Andy Gocke 21845d37fc Add LDM notes for Jan 22, 2020 2020-02-03 21:57:15 -08:00
Andy Gocke 2d521548ec Add LDM notes for Jan. 15, 2020 2020-02-03 20:58:18 -08:00
Mads Torgersen 3bbad41c9c
Update LDM Agenda 2020-01-31 16:51:15 -08:00
Mads Torgersen f7fdb7cd7e
Update LDM Agenda 2020-01-28 16:14:48 -08:00
Andy Gocke 19bc0f521e
Update records-wip.md (#3106) 2020-01-27 12:58:42 -08:00
Leandro Fernandes 0b9e64a3c3 foreach loop of variables been changed c# (#3022)
https://stackoverflow.com/questions/12112881/has-foreachs-use-of-variables-been-changed-in-c-sharp-5
2020-01-26 23:15:00 -08:00
Maher Jendoubi 02b535d712 Contributing: fix typos (#3125) 2020-01-24 18:22:11 -05:00
Julien Couvreur 6f24703c82
var infers a nullable type (#3097) 2020-01-21 22:49:40 -08:00
Mads Torgersen d832b361bb
Update LDM agenda 2020-01-21 13:19:39 -08:00
Andy Gocke e134bb7058
Add spec work for record ctor (#3076)
* Add spec work for record ctor

* Add more detail about constructor implementation
2020-01-15 16:40:26 -08:00
Mads Torgersen 581270dfd2
Update LDM Agenda 2020-01-14 10:48:56 -08:00
Maira Wenzel f61a06970f
Fix broken links (#3091)
* Fix broken link

* update/fix links

* fix broken link
2020-01-13 16:31:13 -08:00
Neal Gafter 1b98900380
Update README.md 2020-01-13 15:44:41 -08:00
Yair Halberstadt b750272482 Fix example in LDM-2020-01-06.md (#3090) 2020-01-13 14:08:58 -08:00
Andy Gocke 064e3b810a Add notes for Jan 8th, 2020 2020-01-13 14:06:20 -08:00
Mads Torgersen 0513712252
Update LDM agenda 2020-01-12 19:38:23 -08:00
Mads Torgersen 6b335814c4
Update LDM agenda 2020-01-12 19:35:20 -08:00
Mads Torgersen 19d3d4ec87
Update LDM agenda 2020-01-12 19:34:14 -08:00
Andy Gocke 919a3f22a0 Add LDM notes for Jan. 6th, 2020 2020-01-09 21:13:20 -08:00
Neal Gafter c7c89c2e7b
Update README.md 2020-01-08 09:58:43 -08:00
Neal Gafter b2e7ad465c
Update README.md 2020-01-07 17:01:19 -08:00
Neal Gafter 3843844601
Update README.md 2020-01-07 16:20:48 -08:00
Andy Gocke 162ba7ba85
Update records-wip.md 2020-01-02 22:40:04 -05:00
Andy Gocke 0546ee1a16
Update records-wip.md 2020-01-02 22:36:27 -05:00
Andy Gocke 2b894dc9aa
Add draft spec for records, as approved 2020-01-02 22:35:04 -05:00
CyrusNajmabadi a378a5f066 Update const-var.md 2017-07-26 13:19:45 -07:00
CyrusNajmabadi 61967db208 Create const-var.md 2017-07-26 13:18:10 -07:00
231 changed files with 24072 additions and 1106 deletions

1
.github/CODEOWNERS vendored Normal file
View file

@ -0,0 +1 @@
* @dotnet/roslyn-compiler

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View file

@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Propose a language idea or ask a question
url: https://github.com/dotnet/csharplang/discussions/new
about: Starting with discussion is the way to create a new proposal.

View file

@ -0,0 +1,50 @@
---
name: Create a language specification
about: For proposals that have been invited by a team member.
title: "[Proposal]: [FEATURE_NAME]"
---
<!--
Hello, and thanks for your interest in contributing to C#! If you haven't been invited by a team member to open an issue, please instead open a discussion marked [draft issue] at https://github.com/dotnet/csharplang/discussions/new and we'll try to give you feedback on how to get to an issue-ready proposal.
New language feature proposals should fully fill out this template. This should include a complete detailed design, which describes the syntax of the feature, what that syntax means, and how it affects current parts of the spec. Please make sure to point out specific spec sections that need to be updated for this feature.
-->
# FEATURE_NAME
* [x] Proposed
* [ ] Prototype: Not Started
* [ ] Implementation: Not Started
* [ ] Specification: Not Started
## Summary
[summary]: #summary
<!-- One paragraph explanation of the feature. -->
## Motivation
[motivation]: #motivation
<!-- Why are we doing this? What use cases does it support? What is the expected outcome? -->
## Detailed design
[design]: #detailed-design
<!-- This is the bulk of the proposal. Explain the design in enough detail for somebody familiar with the language to understand, and for somebody familiar with the compiler to implement, and include examples of how the feature is used. Please include syntax and desired semantics for the change, including linking to the relevant parts of the existing C# spec to describe the changes necessary to implement this feature. An initial proposal does not need to cover all cases, but it should have enough detail to enable a language team member to bring this proposal to design if they so choose. -->
## Drawbacks
[drawbacks]: #drawbacks
<!-- Why should we *not* do this? -->
## Alternatives
[alternatives]: #alternatives
<!-- What other designs have been considered? What is the impact of not doing this? -->
## Unresolved questions
[unresolved]: #unresolved-questions
<!-- What parts of the design are still undecided? -->
## Design meetings
<!-- Link to design notes that affect this proposal, and describe in one sentence for each what changes they led to. -->

6
CODE-OF-CONDUCT.md Normal file
View file

@ -0,0 +1,6 @@
# Code of Conduct
This project has adopted the code of conduct defined by the Contributor Covenant
to clarify expected behavior in our community.
For more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct).

View file

@ -6,9 +6,13 @@
[![Join the chat at https://gitter.im/dotnet/csharplang](https://badges.gitter.im/dotnet/csharplang.svg)](https://gitter.im/dotnet/csharplang?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
- [Discord](https://aka.ms/csharp-discord) - Any discussion related to the C# language up to the application level.
- [Dotnet Discord](https://aka.ms/dotnet-discord-csharp) - github.com/dotnet discord for discussing dotnet repositories (including csharplang).
[![Join the chat at https://aka.ms/csharp-discord](https://img.shields.io/discord/102860784329052160.svg)](https://aka.ms/csharp-discord)
[![Chat on Discord](https://discordapp.com/api/guilds/143867839282020352/widget.png)](https://aka.ms/dotnet-discord-csharp)
- [C# Discord](https://aka.ms/csharp-discord) - General C# discussion not limited to the dotnet repositories.
[![Chat on Discord](https://discordapp.com/api/guilds/102860784329052160/widget.png)](https://aka.ms/csharp-discord)
- IRC - Any discussion related to the C# language up to the application level.

View file

@ -1,109 +1,42 @@
Features Added in C# Language Versions
====================
# [C# 1.0](https://en.wikipedia.org/wiki/Microsoft_Visual_Studio#.NET_.282002.29) - Visual Studio .NET 2002
# C# 10.0 - .NET 6 and Visual Studio 2022 version 17.0
- Classes
- Structs
- Interfaces
- Events
- Properties
- Delegates
- Expressions
- Statements
- Attributes
- Literals
- [Record structs](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-10.0/record-structs.md) and `with` expressions on structs (`record struct Point(int X, int Y);`, `var newPoint = point with { X = 100 };`).
- [Global using directives](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-10.0/GlobalUsingDirective.md): `global using` directives avoid repeating the same `using` directives across many files in your program.
- [Improved definite assignment](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/improved-definite-assignment.md): definite assignment and nullability analysis better handle common patterns such as `dictionary?.TryGetValue(key, out value) == true`.
- [Constant interpolated strings](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/constant_interpolated_strings.md): interpolated strings composed of constants are themselves constants.
- [Extended property patterns](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/extended-property-patterns.md): property patterns allow accessing nested members (`if (e is MethodCallExpression { Method.Name: "MethodName" })`).
- [Sealed record ToString](https://github.com/dotnet/csharplang/issues/4174): a record can inherit a base record with a sealed `ToString`.
- [Incremental source generators](https://github.com/dotnet/roslyn/blob/main/docs/features/incremental-generators.md): improve the source generation experience in large projects by breaking down the source generation pipeline and caching intermediate results.
- [Mixed deconstructions](https://github.com/dotnet/csharplang/issues/125): deconstruction-assignments and deconstruction-declarations can be blended together (`(existingLocal, var declaredLocal) = expression`).
- [Method-level AsyncMethodBuilder](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/async-method-builders.md): the AsyncMethodBuilder used to compile an `async` method can be overridden locally.
- [#line span directive](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/enhanced-line-directives.md): allow source generators like Razor fine-grained control of the line mapping with `#line` directives that specify the destination span (`#line (startLine, startChar) - (endLine, endChar) charOffset "fileName"`).
- [Lambda improvements](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/lambda-improvements.md): attributes and return types are allowed on lambdas; lambdas and method groups have a natural delegate type (`var f = short () => 1;`).
- [Interpolated string handlers](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/improved-interpolated-strings.md): interpolated string handler types allow efficient formatting of interpolated strings in assignments and invocations.
- [File-scoped namespaces](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/file-scoped-namespaces.md): files with a single namespace don't need extra braces or indentation (`namespace X.Y.Z;`).
- [Parameterless struct constructors](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/parameterless-struct-constructors.md): support parameterless constructors and instance field initializers for struct types.
- [CallerArgumentExpression](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/caller-argument-expression.md): this attribute allows capturing the expressions passed to a method as strings.
# [C# 1.2](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-version-history#c-version-12) - Visual Studio .NET 2003
- Dispose in foreach
- foreach over string specialization
# [C# 2](https://msdn.microsoft.com/en-us/library/7cz8t42e(v=vs.80).aspx) - Visual Studio 2005
- Generics
- Partial types
- Anonymous methods
- Iterators
- Nullable types
- Getter/setter separate accessibility
- Method group conversions (delegates)
- Static classes
- Delegate inference
# [C# 3](https://msdn.microsoft.com/en-us/library/bb308966.aspx) - Visual Studio 2008
- Implicitly typed local variables
- Object and collection initializers
- Auto-Implemented properties
- Anonymous types
- Extension methods
- Query expressions
- Lambda expression
- Expression trees
- Partial methods
# [C# 4](https://msdn.microsoft.com/en-us/magazine/ff796223.aspx) - Visual Studio 2010
- Dynamic binding
- Named and optional arguments
- Co- and Contra-variance for generic delegates and interfaces
- Embedded interop types ("NoPIA")
# [C# 5](https://blogs.msdn.microsoft.com/mvpawardprogram/2012/03/26/an-introduction-to-new-features-in-c-5-0/) - Visual Studio 2012
- Asynchronous methods
- Caller info attributes
# [C# 6](https://github.com/dotnet/roslyn/wiki/New-Language-Features-in-C%23-6) - Visual Studio 2015
- [Draft Specification online](https://github.com/dotnet/csharplang/blob/master/spec/README.md)
- Compiler-as-a-service (Roslyn)
- Import of static type members into namespace
- Exception filters
- Await in catch/finally blocks
- Auto property initializers
- Default values for getter-only properties
- Expression-bodied members
- Null propagator (null-conditional operator, succinct null checking)
- String interpolation
- nameof operator
- Dictionary initializer
# [C# 7.0](https://blogs.msdn.microsoft.com/dotnet/2017/03/09/new-features-in-c-7-0/) - Visual Studio 2017
- [Out variables](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/out-var.md)
- [Pattern matching](https://github.com/dotnet/csharplang/blob/master/proposals/patterns.md)
- [Tuples](https://github.com/dotnet/roslyn/blob/master/docs/features/tuples.md)
- [Deconstruction](https://github.com/dotnet/roslyn/blob/master/docs/features/deconstruction.md)
- [Discards](https://github.com/dotnet/roslyn/blob/master/docs/features/discards.md)
- [Local Functions](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/local-functions.md)
- [Binary Literals](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/binary-literals.md)
- [Digit Separators](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/digit-separators.md)
- Ref returns and locals
- [Generalized async return types](https://github.com/dotnet/roslyn/blob/master/docs/features/task-types.md)
- More expression-bodied members
- [Throw expressions](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/throw-expression.md)
# [C# 7.1](https://blogs.msdn.microsoft.com/dotnet/2017/10/31/welcome-to-c-7-1/) - Visual Studio 2017 version 15.3
- [Async main](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/async-main.md)
- [Default expressions](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/target-typed-default.md)
- [Reference assemblies](https://github.com/dotnet/roslyn/blob/master/docs/features/refout.md)
- [Inferred tuple element names](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/infer-tuple-names.md)
- [Pattern-matching with generics](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/generics-pattern-match.md)
# [C# 7.2](https://blogs.msdn.microsoft.com/dotnet/2017/11/15/welcome-to-c-7-2-and-span/) - Visual Studio 2017 version 15.5
- [Span and ref-like types](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/span-safety.md)
- [In parameters and readonly references](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/readonly-ref.md)
- [Ref conditional](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/conditional-ref.md)
- [Non-trailing named arguments](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/non-trailing-named-arguments.md)
- [Private protected accessibility](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/private-protected.md)
- [Digit separator after base specifier](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/leading-separator.md)
# C# 7.3 - Visual Studio 2017 version 15.7
- `System.Enum`, `System.Delegate` and [`unmanaged`](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.3/blittable.md) constraints.
- [Ref local re-assignment](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.3/ref-local-reassignment.md): Ref locals and ref parameters can now be reassigned with the ref assignment operator (`= ref`).
- [Stackalloc initializers](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.3/stackalloc-array-initializers.md): Stack-allocated arrays can now be initialized, e.g. `Span<int> x = stackalloc[] { 1, 2, 3 };`.
- [Indexing movable fixed buffers](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.3/indexing-movable-fixed-fields.md): Fixed buffers can be indexed into without first being pinned.
- [Custom `fixed` statement](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.3/pattern-based-fixed.md): Types that implement a suitable `GetPinnableReference` can be used in a `fixed` statement.
- [Improved overload candidates](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.3/improved-overload-candidates.md): Some overload resolution candidates can be ruled out early, thus reducing ambiguities.
- [Expression variables in initializers and queries](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.3/expression-variables-in-initializers.md): Expression variables like `out var` and pattern variables are allowed in field initializers, constructor initializers and LINQ queries.
- [Tuple comparison](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.3/tuple-equality.md): Tuples can now be compared with `==` and `!=`.
- [Attributes on backing fields](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.3/auto-prop-field-attrs.md): Allows `[field: …]` attributes on an auto-implemented property to target its backing field.
# C# 9.0 - .NET 5 and Visual Studio 2019 version 16.8
- [Records](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/records.md) and `with` expressions: succinctly declare reference types with value semantics (`record Point(int X, int Y);`, `var newPoint = point with { X = 100 };`).
- [Init-only setters](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/init.md): init-only properties can be set during object creation (`int Property { get; init; }`).
- [Top-level statements](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/top-level-statements.md): the entry point logic of a program can be written without declaring an explicit type or `Main` method.
- [Pattern matching enhancements](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/patterns3.md): relational patterns (`is < 30`), combinator patterns (`is >= 0 and <= 100`, `case 3 or 4:`, `is not null`), parenthesized patterns (`is int and (< 0 or > 100)`), type patterns (`case Type:`).
- [Native sized integers](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/native-integers.md): the numeric types `nint` and `nuint` match the platform memory size.
- [Function pointers](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/function-pointers.md): enable high-performance code leveraging IL instructions `ldftn` and `calli` (`delegate* <int, void> local;`)
- [Suppress emitting `localsinit` flag](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/skip-localsinit.md): attributing a method with `[SkipLocalsInit]` will suppress emitting the `localsinit` flag to reduce cost of zero-initialization.
- [Target-typed new expressions](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/target-typed-new.md): `Point p = new(42, 43);`.
- [Static anonymous functions](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/static-anonymous-functions.md): ensure that anonymous functions don't capture `this` or local variables (`static () => { ... };`).
- [Target-typed conditional expressions](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/target-typed-conditional-expression.md): conditional expressions which lack a natural type can be target-typed (`int? x = b ? 1 : null;`).
- [Covariant return types](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/covariant-returns.md): a method override on reference types can declare a more derived return type.
- [Lambda discard parameters](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/lambda-discard-parameters.md): multiple parameters `_` appearing in a lambda are allowed and are discards.
- [Attributes on local functions](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/local-function-attributes.md).
- [Module initializers](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/module-initializers.md): a method attributed with `[ModuleInitializer]` will be executed before any other code in the assembly.
- [Extension `GetEnumerator`](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/extension-getenumerator.md): an extension `GetEnumerator` method can be used in a `foreach`.
- [Partial methods with returned values](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/extending-partial-methods.md): partial methods can have any accessibility, return a type other than `void` and use `out` parameters, but must be implemented.
- [Source Generators](https://devblogs.microsoft.com/dotnet/introducing-c-source-generators/)
# C# 8.0 - .NET Core 3.0 and Visual Studio 2019 version 16.3
- [Nullable reference types](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-8.0/nullable-reference-types-specification.md): express nullability intent on reference types with `?`, `notnull` constraint and annotations attributes in APIs, the compiler will use those to try and detect possible `null` values being dereferenced or passed to unsuitable APIs.
@ -120,3 +53,121 @@ Features Added in C# Language Versions
- [Alternative interpolated verbatim strings](https://github.com/dotnet/csharplang/issues/1630): `@$"..."` strings are recognized as interpolated verbatim strings just like `$@"..."`.
- [Obsolete on property accessors](https://github.com/dotnet/csharplang/issues/2152): property accessors can now be individually marked as obsolete.
- [Permit `t is null` on unconstrained type parameter](https://github.com/dotnet/csharplang/issues/1284)
# C# 7.3 - Visual Studio 2017 version 15.7
- `System.Enum`, `System.Delegate` and [`unmanaged`](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.3/blittable.md) constraints.
- [Ref local re-assignment](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.3/ref-local-reassignment.md): Ref locals and ref parameters can now be reassigned with the ref assignment operator (`= ref`).
- [Stackalloc initializers](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.3/stackalloc-array-initializers.md): Stack-allocated arrays can now be initialized, e.g. `Span<int> x = stackalloc[] { 1, 2, 3 };`.
- [Indexing movable fixed buffers](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.3/indexing-movable-fixed-fields.md): Fixed buffers can be indexed into without first being pinned.
- [Custom `fixed` statement](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.3/pattern-based-fixed.md): Types that implement a suitable `GetPinnableReference` can be used in a `fixed` statement.
- [Improved overload candidates](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.3/improved-overload-candidates.md): Some overload resolution candidates can be ruled out early, thus reducing ambiguities.
- [Expression variables in initializers and queries](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.3/expression-variables-in-initializers.md): Expression variables like `out var` and pattern variables are allowed in field initializers, constructor initializers and LINQ queries.
- [Tuple comparison](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.3/tuple-equality.md): Tuples can now be compared with `==` and `!=`.
- [Attributes on backing fields](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.3/auto-prop-field-attrs.md): Allows `[field: …]` attributes on an auto-implemented property to target its backing field.
# [C# 7.2](https://blogs.msdn.microsoft.com/dotnet/2017/11/15/welcome-to-c-7-2-and-span/) - Visual Studio 2017 version 15.5
- [Span and ref-like types](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/span-safety.md)
- [In parameters and readonly references](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/readonly-ref.md)
- [Ref conditional](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/conditional-ref.md)
- [Non-trailing named arguments](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/non-trailing-named-arguments.md)
- [Private protected accessibility](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/private-protected.md)
- [Digit separator after base specifier](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/leading-separator.md)
# [C# 7.1](https://blogs.msdn.microsoft.com/dotnet/2017/10/31/welcome-to-c-7-1/) - Visual Studio 2017 version 15.3
- [Async main](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/async-main.md)
- [Default expressions](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/target-typed-default.md)
- [Reference assemblies](https://github.com/dotnet/roslyn/blob/master/docs/features/refout.md)
- [Inferred tuple element names](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/infer-tuple-names.md)
- [Pattern-matching with generics](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/generics-pattern-match.md)
# [C# 7.0](https://blogs.msdn.microsoft.com/dotnet/2017/03/09/new-features-in-c-7-0/) - Visual Studio 2017
- [Out variables](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/out-var.md)
- [Pattern matching](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-7.0/pattern-matching.md)
- [Tuples](https://github.com/dotnet/roslyn/blob/master/docs/features/tuples.md)
- [Deconstruction](https://github.com/dotnet/roslyn/blob/master/docs/features/deconstruction.md)
- [Discards](https://github.com/dotnet/roslyn/blob/master/docs/features/discards.md)
- [Local Functions](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/local-functions.md)
- [Binary Literals](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/binary-literals.md)
- [Digit Separators](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/digit-separators.md)
- [Ref returns and locals](https://docs.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/ref-returns)
- [Generalized async return types](https://github.com/dotnet/roslyn/blob/master/docs/features/task-types.md)
- [More expression-bodied members](https://docs.microsoft.com/dotnet/csharp/programming-guide/statements-expressions-operators/expression-bodied-members)
- [Throw expressions](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/throw-expression.md)
# [C# 6](https://github.com/dotnet/roslyn/blob/master/docs/wiki/New-Language-Features-in-C%23-6.md) - Visual Studio 2015
- [Draft Specification online](https://github.com/dotnet/csharplang/blob/master/spec/README.md)
- Compiler-as-a-service (Roslyn)
- [Import of static type members into namespace](https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/using-static)
- [Exception filters](https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/when)
- Await in catch/finally blocks
- Auto property initializers
- Default values for getter-only properties
- [Expression-bodied members](https://docs.microsoft.com/dotnet/csharp/programming-guide/statements-expressions-operators/expression-bodied-members)
- Null propagator (null-conditional operator, succinct null checking)
- [String interpolation](https://docs.microsoft.com/dotnet/csharp/language-reference/tokens/interpolated)
- [nameof operator](https://docs.microsoft.com/dotnet/csharp/language-reference/operators/nameof)
- Dictionary initializer
# [C# 5](https://blogs.msdn.microsoft.com/mvpawardprogram/2012/03/26/an-introduction-to-new-features-in-c-5-0/) - Visual Studio 2012
- [Asynchronous methods](https://docs.microsoft.com/dotnet/csharp/programming-guide/concepts/async/)
- [Caller info attributes](https://docs.microsoft.com/dotnet/csharp/language-reference/attributes/caller-information)
- foreach loop was changed to generates a new loop variable rather than closing over the same variable every time
# [C# 4](https://msdn.microsoft.com/magazine/ff796223.aspx) - Visual Studio 2010
- [Dynamic binding](https://docs.microsoft.com/dotnet/csharp/programming-guide/types/using-type-dynamic)
- [Named and optional arguments](https://docs.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments)
- [Co- and Contra-variance for generic delegates and interfaces](https://docs.microsoft.com/dotnet/standard/generics/covariance-and-contravariance)
- [Embedded interop types ("NoPIA")](https://docs.microsoft.com/dotnet/framework/interop/type-equivalence-and-embedded-interop-types)
# [C# 3](https://msdn.microsoft.com/library/bb308966.aspx) - Visual Studio 2008
- [Implicitly typed local variables](https://docs.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/implicitly-typed-local-variables)
- [Object and collection initializers](https://docs.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/object-and-collection-initializers)
- [Auto-Implemented properties](https://docs.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/auto-implemented-properties)
- [Anonymous types](https://docs.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/anonymous-types)
- [Extension methods](https://docs.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/extension-methods)
- [Query expressions, a.k.a LINQ (Language Integrated Query)](https://docs.microsoft.com/dotnet/csharp/linq/query-expression-basics)
- [Lambda expression](https://docs.microsoft.com/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions)
- [Expression trees](https://docs.microsoft.com/dotnet/csharp/programming-guide/concepts/expression-trees/)
- [Partial methods](https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/partial-method)
- [Lock statement](https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/lock-statement)
# [C# 2](https://msdn.microsoft.com/library/7cz8t42e(v=vs.80).aspx) - Visual Studio 2005
- [Generics](https://docs.microsoft.com/dotnet/csharp/programming-guide/generics/)
- [Partial types](https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/partial-type)
- [Anonymous methods](https://docs.microsoft.com/dotnet/csharp/programming-guide/statements-expressions-operators/anonymous-functions)
- [Iterators, a.k.a yield statement](https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/yield)
- [Nullable types](https://docs.microsoft.com/dotnet/csharp/language-reference/builtin-types/nullable-value-types)
- Getter/setter separate accessibility
- Method group conversions (delegates)
- [Static classes](https://docs.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/static-classes-and-static-class-members)
- Delegate inference
- Type and namespace aliases
- [Covariance and contravariance](https://docs.microsoft.com/dotnet/csharp/programming-guide/concepts/covariance-contravariance/)
# [C# 1.2](https://docs.microsoft.com/dotnet/csharp/whats-new/csharp-version-history#c-version-12) - Visual Studio .NET 2003
- Dispose in foreach
- foreach over string specialization
# [C# 1.0](https://en.wikipedia.org/wiki/Microsoft_Visual_Studio#.NET_.282002.29) - Visual Studio .NET 2002
- [Classes](https://docs.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/classes)
- [Structs](https://docs.microsoft.com/dotnet/csharp/language-reference/builtin-types/struct)
- [Enums](https://docs.microsoft.com/dotnet/csharp/language-reference/builtin-types/enum)
- [Interfaces](https://docs.microsoft.com/dotnet/csharp/programming-guide/interfaces/)
- [Events](https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/event)
- [Operator overloading](https://docs.microsoft.com/dotnet/csharp/language-reference/operators/operator-overloading)
- [User-defined conversion operators](https://docs.microsoft.com/dotnet/csharp/language-reference/operators/user-defined-conversion-operators)
- [Properties](https://docs.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/properties)
- [Indexers](https://docs.microsoft.com/dotnet/csharp/programming-guide/indexers/)
- Output parameters ([out](https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/out) and [ref](https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/ref))
- [`params` arrays](https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/params)
- [Delegates](https://docs.microsoft.com/dotnet/csharp/programming-guide/delegates/)
- Expressions
- [using statement](https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/using-statement)
- [goto statement](https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/goto)
- [Preprocessor directives](https://docs.microsoft.com/dotnet/csharp/language-reference/preprocessor-directives/)
- [Unsafe code and pointers](https://docs.microsoft.com/dotnet/csharp/programming-guide/unsafe-code-pointers/)
- [Attributes](https://docs.microsoft.com/dotnet/csharp/programming-guide/concepts/attributes/)
- Literals
- [Verbatim identifier](https://docs.microsoft.com/dotnet/csharp/language-reference/tokens/verbatim)
- Unsigned integer types
- [Boxing and unboxing](https://docs.microsoft.com/dotnet/csharp/programming-guide/types/boxing-and-unboxing)

View file

@ -1,6 +1,6 @@
# C# Language Design
[![Join the chat at https://gitter.im/dotnet/csharplang](https://badges.gitter.im/dotnet/csharplang.svg)](https://gitter.im/dotnet/csharplang?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Join the chat at https://gitter.im/dotnet/csharplang](https://badges.gitter.im/dotnet/csharplang.svg)](https://gitter.im/dotnet/csharplang?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Chat on Discord](https://discordapp.com/api/guilds/143867839282020352/widget.png)](https://aka.ms/dotnet-discord-csharp)
Welcome to the official repo for C# language design. This is where new C# language features are developed, adopted and specified.
@ -17,23 +17,29 @@ If you discover bugs or deficiencies in the above, please leave an issue to rais
For *new feature proposals*, however, please raise them for [discussion](https://github.com/dotnet/csharplang/labels/Discussion), and *only* submit a proposal as a pull request if invited to do so by a member of the Language Design Team (a "champion").
## Discussion
## Discussions
Discussion pertaining to language features takes place in the form of issues in this repo, under the [Discussion label](https://github.com/dotnet/csharplang/labels/Discussion).
Debate pertaining to language features takes place in the form of [Discussions](https://github.com/dotnet/csharplang/discussions) in this repo.
If you want to suggest a feature, discuss current design notes or proposals, etc., please [open a new issue](https://github.com/dotnet/csharplang/issues/new), and it will be tagged Discussion.
If you want to suggest a feature, discuss current design notes or proposals, etc., please [open a new Discussion topic](https://github.com/dotnet/csharplang/discussions/new).
GitHub is not ideal for discussions, but it is beneficial to have language features discussed nearby to where the design artifacts are. Comment threads that are short and stay on topic are much more likely to be read. If you leave comment number fifty, chances are that only a few people will read it. To make discussions easier to navigate and benefit from, please observe a few rules of thumb:
Discussions that are short and stay on topic are much more likely to be read. If you leave comment number fifty, chances are that only a few people will read it. To make discussions easier to navigate and benefit from, please observe a few rules of thumb:
- Discussion should be relevant to C# language design. Issues that are not will be summarily closed.
- Choose a descriptive title for the issue, that clearly communicates the scope of discussion.
- Stick to the topic of the issue title. If a comment is tangential, start a new issue and link back.
- If a comment goes into detail on a subtopic, also consider starting a new issue and linking back.
- Discussion should be relevant to C# language design. If they are not, they will be summarily closed.
- Choose a descriptive topic that clearly communicates the scope of discussion.
- Stick to the topic of the discussion. If a comment is tangential, or goes into detail on a subtopic, start a new discussion and link back.
- Is your comment useful for others to read, or can it be adequately expressed with an emoji reaction to an existing comment?
Language proposals which prevent specific syntax from occurring can be achieved with [a Roslyn analyzer](https://docs.microsoft.com/en-us/visualstudio/extensibility/getting-started-with-roslyn-analyzers). Proposals that only make existing syntax optionally illegal will be rejected by the language design committee to prevent increased language complexity.
## Proposals
Once you have a fully fleshed out proposal describing a new language feature in syntactic and semantic detail, please [open an issue for it](https://github.com/dotnet/csharplang/issues/new/choose), and it will be labeled as a [Proposal](https://github.com/dotnet/csharplang/issues?q=is%3Aopen+is%3Aissue+label%3AProposal). The comment thread on the issue can be used to hash out or briefly discuss details of the proposal, as well as pros and cons of adopting it into C#. If an issue does not meet the bar of being a full proposal, we may move it to a discussion, so that it can be "baked" further. Specific open issues or more expansive discussion with a proposal will often warrant opening a side discussion rather than cluttering the comment section on the issue.
When a member of the C# LDM finds that a proposal merits discussion, they can [Champion](https://github.com/dotnet/csharplang/issues?q=is%3Aopen+is%3Aissue+label%3A%22Proposal+champion%22) it, which means that they will bring it to the C# Language Design Meeting. If the LDM decides to work on adopting the feature, the proposer, the champion and others can collaborate on adding it as a document to the [Proposals](proposals) folder, where its evolution can be tracked over time.
## Design Process
[Proposals](proposals) are raised by, or on invitation from, "champions" on the LDT. They evolve as a result of decisions in [Language Design Meetings](meetings), which are informed by [discussion](https://github.com/dotnet/csharplang/labels/Discussion), experiments, and offline design work.
[Proposals](proposals) evolve as a result of decisions in [Language Design Meetings](meetings), which are informed by [discussions](https://github.com/dotnet/csharplang/discussions), experiments, and offline design work.
In many cases it will be necessary to implement and share a prototype of a feature in order to land on the right design, and ultimately decide whether to adopt the feature. Prototypes help discover both implementation and usability issues of a feature. A prototype should be implemented in a fork of the [Roslyn repo](https://github.com/dotnet/roslyn) and meet the following bar:
@ -45,6 +51,15 @@ Once approved, a feature should be fully implemented in [Roslyn](https://github.
**DISCLAIMER**: An active proposal is under active consideration for inclusion into a future version of the C# programming language but is not in any way guaranteed to ultimately be included in the next or any version of the language. A proposal may be postponed or rejected at any time during any phase of the above process based on feedback from the design team, community, code reviewers, or testing.
### Milestones
We have a few different milestones for issues on the repo:
* [Working Set](https://github.com/dotnet/csharplang/milestone/19) is the set of championed proposals that are currently being actively worked on. Not everything in this milestone will make the next version of C#, but it will get design time during the upcoming release.
* [Backlog](https://github.com/dotnet/csharplang/milestone/10) is the set of championed proposals that have been triaged, but are not being actively worked on. While discussion and ideas from the community are welcomed on these proposals, the cost of the design work and implementation review on these features are too high for us to consider community implementation until we are ready for it.
* [Any Time](https://github.com/dotnet/csharplang/milestone/14) is the set of championed proposals that have been triaged, but are not being actively worked on and are open to community implementation. Issues in this can be in one of 2 states: needs approved specification, and needs implementation. Those that need a specification still need to be presented during LDM for approval of the spec, but we are willing to take the time to do so at our earliest convenience.
* [Likely Never](https://github.com/dotnet/csharplang/milestone/13) is the set of proposals that the LDM has rejected from the language. Without strong need or community feedback, these proposals will not be considered in the future.
* Numbered milestones are the set of features that have been implemented for that particular language version. For closed milestones, these are the set of things that shipped with that release. For open milestones, features can be potentially pulled later if we discover compatability or other issues as we near release.
## Language Design Meetings
Language Design Meetings (LDMs) are held by the LDT and occasional invited guests, and are documented in Design Meeting Notes in the [meetings](meetings) folder, organized in folders by year. The lifetime of a design meeting note is described in [meetings/README.md](meetings/README.md). LDMs are where decisions about future C# versions are made, including which proposals to work on, how to evolve the proposals, and whether and when to adopt them.

View file

@ -274,7 +274,7 @@ A value-semantics class like the above would be automatically generated by a "re
class Point(int X, int Y);
```
By default, this would generate all of the above, except parameter names would be upper case. If you want to supercede default behavior, you can give it a body and do that explicitly. For instance, you could make X mutable:
By default, this would generate all of the above, except parameter names would be upper case. If you want to supersede default behavior, you can give it a body and do that explicitly. For instance, you could make X mutable:
``` c#
class Point(int X, int Y)

View file

@ -112,7 +112,7 @@ We should allow expression variables in queries, but keep them scoped to the ind
[csharplang/issues/287](https://github.com/dotnet/csharplang/issues/287)
The [proposal](https://github.com/dotnet/csharplang/blob/master/proposals/caller-argument-expression.md) calls for an extra parameter with a default value (which is then replaced by the expression passed as an argument for the parameter designated in the attribute). This means that in a tie breaker situation, existing methods would match better than new ones that differ only by having this extra argument.
The [proposal](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-10.0/caller-argument-expression.md) calls for an extra parameter with a default value (which is then replaced by the expression passed as an argument for the parameter designated in the attribute). This means that in a tie breaker situation, existing methods would match better than new ones that differ only by having this extra argument.
There are solutions to that for API owners:

View file

@ -13,7 +13,7 @@
The way `base.` works in classes, if the base implementation that was present at compile
time is removed at rune time, the CLR will search for the next implementation in the
heirarchy and use that instead. For example,
hierarchy and use that instead. For example,
```C#
class A

View file

@ -25,7 +25,7 @@ This is the next major release (as C# 8.0 is a done deal at this point). Putting
## #146
There's something to this, but instead of marking seperately, we think it is paired with allowing nullary constructors on structs . For those we would warn on uses of `default(S)` that we can detect, similar to nullability.
There's something to this, but instead of marking separately, we think it is paired with allowing nullary constructors on structs . For those we would warn on uses of `default(S)` that we can detect, similar to nullability.
## #812

View file

@ -0,0 +1,128 @@
# C# Language Design Meeting for Jan. 6, 2020
## Agenda
1. Use attribute info inside method bodies
1. Making Task-like types covariant for nullability
1. Casting to non-nullable reference type
1. Triage
## Discussion
### Use attribute info inside method bodies
Examples:
1.
```C#
bool TryGetValue<T>([MaybeNullWhen(false)]out T t)
{
return other.TryGetValue(out t); // currently warns
}
```
2.
```C#
[return: MaybeNull]
T GetFirstOrDefault<T>()
{
return null; // currently warns
}
```
3.
Overriding/implementation
```C#
class A<T>
{
[return: MaybeNull]
virtual T M();
}
class B : A<string>
{
override string? M(); // warns about no [MaybeNull]
}
```
We don't have a complete design here, but some cases have an intuition about the correct
behavior. In overriding, specifically, we need a specification for what it means for an
annotation to be "compatible" with each of the attributes. On the other hand, it's not clear what
the behavior of `MaybeNullWhenTrue` should be in all cases.
**Conclusion**
We'd like to do this if the return on investment seems worth it, but to fully evaluate
we need a proposal of the work.
### Making Task-like objects nullable covariant
This is a pretty common pain-point, and it's not the first time we special-cased variance,
specifically `IEquatable<T>` is treated as nullable contravariant. It's unfortunate that the CLR
doesn't have capability to make `Task<T>` full covariant, but handling even nullable alone would
be useful. Moreover, if we later get the capability to mark `Task<T>` covariant, this would not
harm the effort.
We also think that there may be some special cases introduced for overload resolution where we
consider `Task<T>` as covariant already. If we could reuse that knowledge, that would be useful.
**Conclusion**
Let's see if we can dig up the overload resolution changes for Task-like types and try to adapt
the same rule for making Task-like types nullable covariant.
### Casting to non-nullable reference type
Example:
```C#
BoundNode? node = ...;
if (node.Kind == BoundKind.Expression)
{
var x = (BoundExpression)node; // warning if node is nullable
}
```
The question is if this warning is valuable, or annoying. We've hit this most often in Roslyn
when using the pattern `(object)x == null` to do a null check while avoiding the user-defined
equality check. This is annoying in the Roslyn codebase, but not very common outside it. On the
other hand, there's feeling that when doing the BoundNode to BoundExpression check, which is less
common in Roslyn but more common generally, there's agreement that the warning is useful in
making the type annotated with the most accurate representation of the null state.
**Conclusion**
Keep the warning, no change. We think the warning is valuable for the non-null-check cases. Newer
version of C# have features that address the null check problem and Roslyn should move to use `x
is null` or similar.
## Triage
Three related proposals: #3037, #3038, #377.
These all deal with the general problem of statements in expressions, especially statements in
switch expressions, and switch expression form in statements.
They don't necessarily require each other, but they fit a lot of the same syntax and semantic
space, so we should consider them all together.
There's also a sketch for how we could unify the syntax forms of all of three proposals, with
potential syntax changes.
**Conclusion**
We agree that all of these proposals are addressing important scenarios, and some improvement
here is valuable. We're not sure where we want to go with generalized statements-in-expressions
vs. adding special syntax forms for switch expression/statement.
We're mainly concerned that if we do switch expression blocks, we want to make sure that the we
don't block a future generalization to all expressions. We need to find a generalization that we
like, reject a generalization and accept this syntax, or put these improvements on the
back-burner if we think that a generalization is possible, we just haven't found it.
Accepted for C# 9.0 investigation.

View file

@ -0,0 +1,188 @@
# C# Language Design Meeting for Jan. 8, 2020
## Agenda
1. Unconstrained type parameter annotation
2. Covariant returns
## Discussion
### Unconstrained type parameter annotation T??
You can only use `T?` when is constrained to be a reference type or a value type. On the other
hand, you can only use `T??` when `T` is unconstrained.
The question is what to use for the following:
```C#
abstract class A<T>
{
internal abstract void F<U>(ref U?? u) where U : T;
}
class B1 : A<string>
{
internal override void F<U>(ref U?? u) => default; // Is ?? allowed or required?
}
class B2 : A<int>
{
internal override void F<U>(ref U?? u) => default; // Is ?? allowed or required?
}
class B3 : A<int?>
{
internal override void F<U>(ref U?? u) => default; // Is ?? allowed or required?
}
```
Our understanding is that this would be:
```C#
abstract class A<T>
{
internal abstract void F<U>(ref U?? u) where U : T;
}
class B1 : A<string>
{
internal override void F<U>(ref U?? u) => default;
// We think the correct annotation is
// void F<U>(ref U? u) where U : class
// because the type parameter is no longer unconstrained. The `where U : class`
// constraint is required, as U? would otherwise mean U : struct
}
// We may want to allow U?? even in the above case, so
class B1 : A<string>
{
internal override void F<U>(ref U?? u) => default; // allowed?
// This would not require the `where U : class` constraint because `U??` cannot
// be confused with `Nullable<U>`
}
class B2 : A<int>
{
internal override void F<U>(ref U?? u) => default;
// The correct annotation is
// void F<U>(ref U u)
// We could allow
// void F<U>(ref U?? u)
// although it would be redundant
}
class B3 : A<int?>
{
internal override void F<U>(ref U?? u) => default;
// The correct annotation is
// void F<U>(ref U u)
// We could allow
// void F<U>(ref U?? u)
// although it would be redundant
```
In the above, we're wondering whether we should allow `??` without warning even in cases where
there's existing syntax to represent the semantics. One benefit is that you could write
```C#
abstract class A<T>
{
internal abstract F<U>(ref U?? u) where U : T;
}
class B1 : A<string>
{
internal override F<U>(ref U?? u) { }
}
```
Since the override cannot be confused with `U?`, there's no need for the `where U : class`. On the
other hand, the benefit seems marginal and it's not needed to represent the semantics. It could
also be added later.
**Conclusion**
We like the syntax `??` to represent the "maybe default" semantics. We think that `??` should be
allowed in the cases where we have other syntax to represent the semantics. A warning will be
provided and hopefully a code fix to move the code to the "more canonical" form. The syntax `??`
is only legal on type parameters in a nullable-enabled context.
We considered using the `?` syntax the represent the same semantics, but ruled it out for a couple reasons:
1. It's technically difficult to achieve. There are two technical limitations in the compiler.
The first is design history where a type parameter ending in `?` is assumed to be a struct. This
has been true in the compiler all the way until nullable reference types in the last release. The
second problem is that many pieces of C# binding are very sensitive to being asked if a type is a
value or reference type and asking the question can often lead to cycles if asked before the answer
is absolutely necessary. However, `T?` means different things if `T` is a struct or unconstrained, so
finding the safe place to ask is difficult.
2. Unresolved design problems. In overriding `T?` means `where T : struct`, going back to the beginning of
`Nullable<T>`. This already caused problems with `T? where T : class` in C# 8, which is why we introduced
a feature where you could specify `T? where T : class` in an override, contrary to past C# design where
constraints are not allowed to be re-specified in overrides. To accommodate overloads for unconstrained
`T?` we would have to introduce a new type of explicit constraint meaning *unconstrained*. We don't have
a syntax for that, and don't particularly want one.
3. Confusion with a different feature. If we use the `T?` syntax, the following would be legal:
```C#
class C
{
public T? M<T>() where T : notnull { ... }
}
```
what you may think is that `M` returns a nullable reference type if `T` is a reference type, and a nullable
value type if `T` is a value type (i.e., `Nullable<T>`). However, that's *not* what this feature is. This
feature is essentially *maybe default*, meaning that `T?` may contain the value `default(T)`. For a reference
type this would be `null`, but for a value type this would be the zero value, not `null`.
Moreover, this seems like a useful feature, that would be ruled out if we used the syntax for something else.
Consider a method similar to `FirstOrDefault`, `FirstOrNull`:
```C#
public static T? FirstOrNull<T>(this IEnumerable<T> e) where T : notnull
```
The benefit is that there is a single sentinel value, `null`, and that the full set of values in a struct
could be represented. In `FirstOrDefault`, if the input is `IEnumerable<int>` there is no way to distinguish
a non-empty enumerable with first value of `0`, or an empty enumerable. With `FirstOrNull` you can distinguish
these cases in a single call, as long as `null` is not a valid value in the type.
Due to CLR restrictions it is not possible to implement this feature in the obvious way, so this feature may
never be implemented, but we would like to prevent confusion and keep the syntax available in case we ever
figure out how we'd like to implement it.
### Covariant returns
We looked at the proposal in #2844.
There's a proposal that for the following
```C#
interface I1
{
object M();
}
interface I2 : I1
{
string M() => null;
}
```
`I2.M` would be illegal as it is, because this is an interface *implementation*, not an
*override*. Interface implementation would not change return types, while overriding would. Thus
we would allow
```C#
interface I1
{
object M();
}
interface I2 : I1
{
override string M() => null;
}
```
which would allow the return type to change. However, it would override *all* `M`s, since
explicit implementation is not allowed.
**Conclusion**
We like it in principle and would like to move forward. There may be some details around
interface implementation vs. overriding to work out.

View file

@ -0,0 +1,159 @@
# C# Language Design Meeting for Jan. 15th, 2020
## Agenda
1. Working with data
2. Record feature breakdown
## Discussion
### Working with data
As we discuss records, we want to go over a design document we produced a number of years ago
called "working with data." This document lays out how, when we design features, we inherently
express a "path of least resistance," which consists of the features that seem easiest or
shortest to use to accomplish a given problem.
Link: https://github.com/dotnet/csharplang/issues/3107
The document argues that, as we find particular patterns to be more effective at building
software, we should make the forms we find to be more effective simpler or shorter to express in
the language. We should not "change" our opinions, meaning make old syntax illegal, but we should
"level the playing field" by making other forms simpler.
The conclusion of the design document is that we should favor
1. Immutable members in records by default
1. Any features from records that we separate should not make the simple syntax longer
### Record feature breakdown
We've also been working on breaking down the individual features
of records and determining how independent they can or should be.
Notes: https://github.com/dotnet/csharplang/issues/3137
There seem to be the following somewhat separable parts of records
1. Value-based equality
2. Construction boilerplate
3. Object initializers
4. Nondestructive mutation
5. Data-friendly defaults
#### Value equality
It's been proposed that a `key` modifier could be applied to signal that value-based equality is
being generated based on the members which have it. This works in many cases,
but if the absence of the `key` modifier means inherited equality, we're not sure
that's the semantics we want. It would also not allow value-based equality to be
"specified" in the base class in some sense, enforcing value equality for the deriving
type. Whether this is valuable or blocking is an open question.
#### Construction boilerplate
Creating a constructor to assign members of a container is one of the largest sources
of repetitive boilerplate, e.g.
```C#
public class Point
{
public int X { get; }
public int Y { get; }
public Point(int x, int y)
{
X = x;
Y = y;
}
}
```
You can imagine various points on this spectrum to simplify the boilerplate,
```C#
public class Point
{
public key int X { get; }
public key int Y { get; }
public Point(X, Y); // name matching and type absence implies initialization
}
```
Which removes the duplication of naming the same elements multiple times or,
```C#
public class Point(X, Y)
{
public key int X { get; }
public key int Y { get; }
}
```
Which removes the constructor name duplication and we could go further to remove
property name duplication,
```C#
public class Point(
public key int X { get; }
public key int Y { get; }
);
```
Going all the way to the original position deconstruction
```C#
public class Point(int X, int Y);
```
Where we pick a point in this space seems to correspond to the perceived benefits
of the orthogonality of the feature. If the construction shorthand is useful for
many scenarios outside of the record scenarios, it's practical to expand it.
### Object initializers
One benefit to object initializers is that they don't refer to a constructor directly,
only to the properties. This sidesteps a weakness in C#, where constructor initialization in inheritance requires repetition. Without constructors the simple
relation
```C#
public abstract class Person
{
public string Name { get; }
}
public class Student : Person
{
public string ID { get;}
}
```
has no repetition. Each class states only the properties that are essential, and
for derived classes all the base properties are inherited without repetition.
Once you add constructors this breaks down
```C#
public abstract class Person
{
public string Name { get; }
public Person(string name)
{
Name = name;
}
}
public class Student : Person
{
public string ID { get; }
public Student(string id, string name)
: base(name)
{
Id = id;
}
}
```
Now the derived classes have to repeat everything from the base, causing brittleness
along the boundary. If we were to imagine some improvement to object initializers,
then defining a constructor would not be required.
On the other hand, this also removes one of the main benefits for having a constructor,
namely that you can validate the whole state of the object before producing it.

View file

@ -0,0 +1,108 @@
# C# Language Design Notes for Jan. 22, 2020
## Agenda
1. Top-level statements and functions
2. Expression Blocks
## Discussion
### Top-level statements and functions
https://github.com/dotnet/csharplang/issues/3117
Three main scenarios:
1. Simple programs are simple -- remove the boilerplate for Main
2. Top-level functions. Members outside of a class.
3. Scripting/interactive. Submission system allows state preservation across evaluations.
Unfortunately, some of these proposals interact in difficult ways.
If you write
```C#
int x = ...;
```
is `x` now a global mutable variable for the entire program? Or is it a
local variable in a generated Main method?
#### Proposal: Simple programs
The proposal is to prioritize (1) and (3) and remove boilerplate, while
enabling use in scripting/interactive scenarios.
To address (1), we would allow a single file in the compilation to contain top-level statements,
and any file to contain top-level local functions, which would be in scope in all files, but it
would be an error to refer to them.
There's wide consensus that (1) is very useful. There's the case of small programs, where you
really just want to write a few statements and not have to write the boilerplate of classes and
Main. It's also a very large learning burden in that just to write "Hello, World" requires
explaining methods, classes, static, etc.
(3) is also important partly because there are a number of products and scenarios
currently using the scripting system. We should keep that in mind to make sure that
we don't prevent a large number of use cases from ever using the new system.
We think (2) is interesting and worth considering. It may not be the highest priority,
but we need to make sure we don't rule it out entirely. We also think that if we add
(1) it seems likely that some people would want (2) much sooner.
If we do want to make space for (2) we should make sure to look at lookup rules very carefully.
The C# lookup rules are very complicated and including new ones for top-level members could
include subtle ways that change new code.
When we designed scripting we had experience that copying back-and-forth from interactive and the
main program is very useful and important. Because the syntax used here is similar to local
functions and it's not currently proposed that accessibility modifiers are legal, this would
create a difference when copying code between standard C# and the interactive dialect, since
presumably those declarations would now be illegal.
#### Block expressions
https://github.com/dotnet/csharplang/issues/3137
We're revisiting the earlier discussions and there is a proposal for how we could
make blocks legal as expressions. The proposed precedence would be the lowest
possible, so many ambiguities or breaking changes would be avoided.
Examples:
```C#
var x = { ; 3 }; // int x = 3
var x = { {} 3 }; // int x = 3
```
Note that a final expression is required, so the `'` or `{}` are necessary as "starting
statements".
The most notable restrictions are that you cannot branch out, meaning that `return`, `yield break`, and `yield return`, and `goto` would be illegal in this proposal.
Something which was brought up before is whether to use a "trailing expression" to
produce a value, or introduce some sort of statement to produce the evaluation
expression. If we used a `break e;` syntax, the above could look like
```C#
var x = { break 3; };
```
One problem is turning the block into a lambda, where `break` would have to be changed to
`return`. On the other hand, if this code were introduced directly into the method, `return`
would actually produce different, valid semantics. `break e;` would be an error in both contexts,
instead of producing different code.
The precedence doesn't have agreement. Some people think that the precedence is
still too high and that we should almost always require a parenthesized wrapper
expression, except in specific cases where we think it's clear. Other people think
that this is too low and they want to use them in more places.
**Conclusion**
We don't think we have enough information about the restrictions we're working under. One way to
make progress would be to construct a list of the potential ambiguities in using the `{}` as an
expression term.

View file

@ -0,0 +1,106 @@
# C# Language Design for Jan. 29, 2020
## Agenda
Record -- With'ers
## Discussion
In this meeting we'd like to talk about Mads's write-up of the "With-ers" feature, as it relates
to records. Multiple variations have been proposed, but the suggestion generally takes the form
of a `with` expression that can return a copy of a data type, with selective elements changed.
Write-up: https://github.com/dotnet/csharplang/issues/3137
The first thing we learned is that the fundamental problem we're trying to solve is
"non-destructive mutation."
There are two approaches we've thought of: direct copy and then direct modification, and creation of a new type based on the values of the old type.
1. Direct copy. We might call this "copy-and-update" because we copy the new data type exactly,
then update the new type with required changes. The basic implementation would be to use
MemberwiseClone, and then overwrite select properties.
2. Create a new type. we call this "constructing through virtual factories." If the type supports
a constructor, this approach would call the constructor using the new values, or the existing
ones if nothing new is given. The construction would be virtual so that derived types would not
lose state when called through the base type.
There are advantages and disadvantages to each proposal.
(1) is simple but seemingly dangerous. There are often internal constraints to a type which must
be preserved for correctness. Usually this is enforced through the type constructor and
visibility of modification. That would not necessarily be available here.
(2) does construction similar to conventional construction today, so it doesn't introduce as many
safety concerns. On the other hand, the contract looks a lot more complicated. To make the
feature seem simple on the surface, it looks like we imply a lot of implicit dependency. For
example,
```C#
public data class Point(int X, int Y);
var p2 = p1 with { Y = 2 };
```
Would generate
```C#
public class Point(int X, int Y)
{
public virtual Point With(int X, int Y) => new Point(X, Y);
}
var p2 = p1.With(p1.X, 2);
```
The first requirement is that an auto-generated `With` method must have a primary constructor, in
order to know which constructor to call. Alternatively, we could have a `With` method generated
for every constructor, although that would require a syntax to signal that `With` methods should
be generated in the absence of a primary constructor.
The compiler also needs to know that the `X` and `Y` parameters of the `With` method correspond
to particular properties, so it can fill in the defaults in the `with` expression. Otherwise we
would need some way of signifying which of the parameters are meant to be "defaults":
```C#
public class Point(int X, int Y)
{
public virtual Point With(bool[] provided, int X, int Y)
{
return new Point(provided[0] ? X : this.X, provided[1] ? Y : this.Y);
}
}
var p2 = p1.With(new bool { false, true}, default, 2);
```
We also need to figure out which `With` method to call at a particular call site. One way is to
construct an equivalent call and perform overload resolution. Another way would be to pick a
particular `With` method as primary, and always use that one in overload resolution.
This also has some of the same compatibility challenges that we've seen in other areas.
Particularly, if you add members to the record, there will be a new `With` method with a new
signature. This would break existing binaries referencing the old `With` method. In addition, if
you add a new `With` method, the old one would still be chosen by overload resolution, if
overload resolution is performed, as long as unspecified properties in the `with` expression are
default values.
On the other hand, this is also a general problem with backwards compatibility overloads. We'll
need to investigate whether we want to add a general purpose mechanism for handling backwards
compatibility and if we want to introduce a special case for With-ers specifically.
What all of the above interdependency implies is that we need a significant amount of syntax or
"hints" about what to do during autogeneration. We previously expressed interest in providing
orthogonality for as many of the "record" features as possible. A conclusion is that
auto-generated With-ers require or suggest many of syntactic and semantic components of records
themselves. When we try to separate the feature entirely, we require user opt-in to specify the
"backing" state of the With-er. This seems to imply that auto-generation should
not be a general, orthogonal feature, but a specific property of records.
However, we don't have to give up orthogonality entirely. The requirements for auto-generated
With-ers doesn't imply anything about manually written With-ers. Auto-generation seems possible
in records because the syntax ties the state to the public interface. Manual specification looks
just like the components of records that can be written explicitly in regular classes, like
constructors themselves. If we do want to pursue this avenue, we should try to limit
the complexity of the pattern as much as possible. It's not too bad if it's fully
generated by the compiler, but it can't be very complicated if we want users to write
it themselves.

View file

@ -0,0 +1,61 @@
# C# LDM for Feb. 3, 2020
## Agenda
Value equality
## Discussion
We split our discussion between two proposals, which end up being very
similar.
### 'key' equality proposal
https://github.com/dotnet/csharplang/pull/3127
Q: Is comparing `System.Type`s slow? Does it require reflection?
A: `typeof` does not require reflection and comparing `Type`s is fast.
Q: Why use a KeyEquals method?
A: To signify that value equals is used and delegate to the base equality,
when the base opts-in to value equality. By having a well-known signature
in metadata, no special attributes are required for derived types to discover
the pattern.
Q: Is KeyEquals necessary? Can we use `EqualityContractOrigin` to figure
out that the type implements value equality?
A: Yes, that seems like it should work.
*Discussion*
There's some concern that modifying the public surface area of the type
itself without any type of modifier is too much magic. If we have some
sort of modifier that goes on the type, in addition to the "key" members,
it would be clear that the type implements value equality from the type
declaration, in addition to the member declarations.
This dovetails into records as a whole in that it would allow the feature sets to be separable.
If a type could have value equality or be a record, the features could be combined to produce a
value record, or the value equality could be left off to allow a record with reference equality.
There's some disagreement on whether this is a positive or a negative. If you view a record as
appropriately having value equality, this is a negative, or vice versa.
### 'value' equality proposal
https://github.com/dotnet/csharplang/issues/3137
The most visible difference here is that `value` is the name of the modifier, instead of `key`.
This more accurately reflects the term "value equality", but it's unfortunate that we already
have the term "value type" which has a completely different meaning in the language.
At the moment the proposal also doesn't include the "extra" members, like a strongly
typed Equals, the `==`/`!=` operators, and `IEquatable` interface implementation.
There's an open question as to whether this feature is preferred for a discriminated
union scenario or not. We have two examples in Roslyn of discriminated unions, our
symbol tree and our bound tree, and they have almost completely different equality
contracts.

View file

@ -0,0 +1,133 @@
# C# LDM for Feb. 5, 2020
## Agenda
1. Dependent nullability attribute
2. Null checking in unconstrained generics
## Discussion
### Nullability
Dependent calls:
We'd like to be able to support patterns like:
```C#
if (x.HasValue)
{
x.Value // should not warn when HasValue is true
}
```
We would add attributes to support these use cases: `EnsuresNotNull` and `EnsuresNotNullWhen` (to parallel the existing `NotNull` attributes). The
proposal as stands is to name the fields or properties and that would be
the inputs and outputs for the flow analysis. We propose that the lookup
rules for resolving the names in these instances would be similar to the
rules for the `DefaultMemberAttribute`.
This could also be used for helpers in constructor initialization, where today constructors which
only call `base` are required to initialize all members, even if a helper initializes some of the
members.
There's a follow-up question: should you be able to specify that members of the parameter are
not-null after the call? For example,
```C#
class Point
{
public object? X;
}
static void M([EnsuresNotNull(nameof(Point.X))]Point p) { ... }
```
We could also allow it for nested annotation
```C#
class Point
{
public object? X;
}
class Line
{
public Point P1;
public Point P2;
}
static void M([EnsuresNotNull("P1.X", "P1.Y")]Line l) { ... }
static bool M([EnsuresNotNullWhen(true, "P1.X", "P1.Y")]Line l) { ... }
```
The nested names could also be used for return annotations.
However, we're not sure this is worth it. We see the usefulness in theory,
but we're not sure how often it would actually be used. If we want to leave
the space for later, we could produce an error when writing an attribute with
an unsupported string form.
Similarly, if we don't want to support referring to members of types through
the parameters, as in the first example, we can also provide an error for these
scenarios. Or, we could say that the initial proposal is qualitatively different
from all these scenarios:
```C#
[MemberNotNull(nameof(X))]
void M() { }
```
For the situations in parameters and return types we are referring to the target the attribute is
being applied to, while the original proposal is returning to the containing type, somewhat
unrelated to the location of the attribute.
We're also not sure exactly what the name or shape of these attributes would
look like. We think this could be valuable, but we'd like to decide with
the full context of other attributes we're considering.
**Conclusion**
We see the usefulness of the original scenario, but the broadening we're not sure
on the return on investment. Let's support the original scenario through a new
attribute, `MemberNotNull`, that only has members as valid attribute targets to start.
If we find users still hit significant limitations without the parameter and return
type support, we can consider broadening in a future release.
### Pure non-null check in generic
```C#
public T Id<T>(T t)
{
if (t is null) Console.WriteLine();
return t; // warn?
}
```
The question here is whether we should consider `T` to move to `MaybeDefault` after
checking for `null`. We never do this today.
The scenario where a "pure" null check would come into play is:
```C#
public T Id<T>(T t) where T : notnull
{
if (t is null) Console.WriteLine();
return t;
}
```
It appears that this does not warn today, which looks like a bug. The analogous
scenario for `T??` is
```C#
public T ID<T>(T t)
{
if (t is default) Console.WriteLine();
return t;
}
```
However, this is illegal as there is no way to check if `T` is `default(T)`.
**Conclusion**
The original scenario should not warn.

View file

@ -0,0 +1,48 @@
# C# Language Design for Feb. 10, 2020
# Agenda
Records
# Discussion
We're continuing our attempt to draw out the dependencies and individual features inside records.
When going through the list, what stands out is:
- Looking at `with`, we need to figure out what's mentionable in the `with` expression.
- We need to figure out exactly what we want for how primary constructors fit into records
There are a number of positives and negatives of primary constructors. On the negative side,
a non-record primary constructor seems to consume syntactic space that could be used for
records. If we think that records are the overwhelmingly common scenario, then it seems like
using the shortest syntax for the most common feature is useful. On the positive side, primary
constructors alone seem to support a simpler way of writing private implementation details.
Separate from the value as a whole, there's some desire to have a special keyword just for
records. That is, even if we didn't do primary constructors, it could be valuable to have
an explicit modifier, like `data` to signify that this type has special behavior.
One possible pivot is to eliminate some composition syntax entirely, by creating a new type
of declaration, `record`, e.g.
```C#
record Point(int X, int Y);
```
This would be equivalent to the syntax that we've been discussing with `data`, namely
```C#
data class Point(int X, int Y);
```
but since the `class` keyword is implied by default, the most common scenario would be
just about as short as the shorter `class Point(int X, int Y)` form.
**Conclusion**
After taking everything into account, we think having an new keyword for records is good both for
leaving space for non-record primary constructors, and also to serve as a clear signifier of
record semantics.

View file

@ -0,0 +1,116 @@
# C# Language Design for Feb 12, 2020
## Agenda
Records
## Discussion
### Value equality
Proposal: use the `key` keyword previously mentioned, but also
require it on the type declaration as well, e.g.
```C#
key class HasValueEquality
{
public key int X { get; }
}
```
There are a number of things we could pivot on
```C#
key class HasValueEquality1 { public key int X { get; } }
class HasValueEquality2 { public key int X { get; } }
key class HasValueEquality3 { public key X { get; } }
class HasValueEquality4 : IEquatable<HasValueEquality4> { public int X { get; } }
```
----
```C#
record Point1(int X); // Implies value equality over X
record Point2a(int X); // Implies inherited equality
key record Point2b1(int X); // Implies value equality over X
key record Point2b2a(int X); // Implies "empty" value equality
key record Point2b2b(key int X); // Implies value equality over X
key class Point3a(int X); // implies record + value equality over X
data class Point3b(int X); // implies record with inherited equality
```
#### Equality default
We originally considered adding value equality on records both because it's difficult to
implement yourself and it fits the semantics we built for records in general. We want to validate
that these things are still true, and new considerations, namely whether it is the appropriate
default for records and whether it should be available to other types, like regular classes.
We left off in the previous discussion asking whether value equality is not just
an inconvenient default, but actively harmful for key scenarios for records. Some examples
we came up with are either classes with large numbers of members, where value equality may
be unnecessary and slow, and circular graphs, where using value equality could cause
infinite recursion.
These do seem bad, but it's not obvious that these scenarios either fit perfectly with the
canonical record, or if the consequences are necessarily worse than default reference equality.
Certainly producing infinite recursion in object graphs is bad, but silently incorrect behavior
due to inaccurate reference equality is also harmful, in the same sense. It's also easier
to switch from value equality to reference equality than it is to switch from reference equality
to value equality, due to the complex requirements in a value equality contract.
**Conclusion**
Value equality seems a reasonable default, as long as they are immutable by default, and that
there is a reasonable way to opt-in to a different equality.
#### Separable value equality
Given that we like value equality as a default, we have to decide if we want a separable equality
feature as well. This is important for the scenario:
```C#
record Point1(int X)
{
public int X { get; }
}
```
if there's a separate `key` feature, we need to decide if the substituted property should
require, allow, or disallow the `key` modifier, e.g.
```C#
record Point1(int X)
{
public key int X { get; }
}
```
We also need to decide what such a "separable" equality feature would look like, and if it has a
difference between records and other classes. We could add a `key` feature for non-records, and
disallow `key` entirely in records. The members of a record equality would then not be
customizable.
The individual `key` modifiers on non-records seem deceptively complicated.
A common case is "opt-in everything". `key` modifiers wouldn't improve much on this, as they
would be necessary on every element. On the other hand, there are often computed properties that
may be seen as part of "everything", but not part of the equality inputs. The plus of record
primary constructors is that they identify the "core" inputs to the type.
Individual `key` modifiers also do not help with the large custom classes that are written today
where it's easy to forget to add new members to equality. With a `key` modifier you can still
forget to add the modifier to a new member.
These decisions play into records as a whole because they affect the uniformity of record and
non-record behavior. If records are defined by their "parameters", namely in this syntax the
primary constructor parameters and identically named properties, then no other members should
be a part of the equality. However, that would imply members in the body are not automatically
included. For regular classes, it seems backwards. Members are not generally included, they have
to be added specifically.
On the other hand, if we prioritize uniformity, general members in record bodies would be included
in equality, which would harm a view of records as consisting primarily of the "record inputs."

View file

@ -0,0 +1,82 @@
# C# Language Design for Feb. 19, 2020
## Agenda
State-based Value Equality
## Discussion
Proposal: https://github.com/dotnet/csharplang/issues/3213
* We haven't decided (yet) to add support for value equality on all
classes (separate from records)
* The behavior is actually that all fields _declared_ in the class are
members in the value equality, not all fields in the class (since inherited fields are not
included)
* Inheritance would be implemented using the previously described
proposals using the `EqualityContract` property
* Records wouldn't behave differently, except that they have `value` by
default
* The main difference with how records work in other places is that the semantics
of a record is otherwise decided by the members of the primary constructor, while in this
proposal the members of the record primary constructor have no special contribution to the value
equality semantics
* There's an evolution risk where we want to provide more complex things, like deep
equality, but these features don't support enough complexity to add it. Instead, we end up just
adding more keywords or more attributes. Consider array fields. The default equality is reference
equality, but sequence equality isn't particularly rare. How would users customize that?
A new keyword? Attribute? Writing Equals manually?
* Turns out we're finding a lot of customization pivots. String comparison is another one.
If we want to support all these scenarios attributes could be better. If we could use
attributes to supply an EqualityComparer that would be almost completely customizable.
* If equality is this complicated, should we only support simple generated equality for
records? Can we leave more complicated scenarios to tooling, like source generators?
Record equality: use the "primary" members or use all fields?
* Using all the fields is consistent with how structs work
* Using the "primary" members mirrors how the generation of `With` or other things
generated by a record with a primary constructor
* There does seem to be a possibility that after you get to a certain size, positional
records are less useful. In that case we want a path to the nominal record. If we do want the
nominal path, it's generally desirable that we want as little "record" syntax as possible.
If we choose the struct "use all the fields" approach, then we could use exactly the
same mechanism for both the "nominal" and the "positional" records.
* The nominal record syntax that has been floated is
```C#
record Point { int X; int Y; }
```
which generates
```C#
record Point
{
public int X { get; init; }
public int Y { get; init; }
}
```
Aside from the shorthand for properties, this generates Equals, GetHashCode and some form
of "With", which doesn't seem much different from proposals for a separable value equality. Is
there really much point in separating these proposals?
* One completely opposite possibility: bypass the question by prohibiting private members in the
positional record entirely
**Conclusion**
No hard decisions yet. Leaning slightly towards using "all declared fields" as the metric for
value equality. There's some support for the "no private fields approach."

View file

@ -0,0 +1,41 @@
# C# Language Design for Feb. 24, 2020
## Agenda
1. Nominal records proposal
## Discussion
### Nominal records
https://github.com/dotnet/csharplang/issues/3226
We've been trying to leave space open for something we're calling "nominal records" where the
concept is that we establish some new system for constructing types based on names, instead of
the order of parameters in a constructor.
Here we have a refreshed nominal records proposal to examine and consider.
The proposal says:
> The main thing you lose out on with nominal construction is a centralized place - the
constructor body - for validation. Property setters can have member-wise validation, but
cross-member holistic validation is not possible. However, for a feature such as records that is
for data not behaviors, that seems to be a particularly small sacrifice.
We don't necessarily agree that this is a small restriction, and there may be some way to add
support for it.
When it comes to the `With` we do need to decide what members are copied over in non-destructive
mutation. One strategy is to use the "surface area" of the object, which is defined as the
constructor parameters, along with the public fields and properties that have some sort of
"setter".
Alternatively, we could copy over the state of the object. This would be equivalent to the use
of the `MemberwiseClone` approach as we discussed in previous design meetings.
**Conclusion**
There are many details to work out, but there's consensus that we want to investigate adding
nominal records in the future.

View file

@ -0,0 +1,123 @@
# C# Language Design Meeting for Feb. 26, 2020
## Agenda
Design Review
## Discussion
Today is a design review, where we collect the design team, selected emeritus
members, and a number of broad ecosystem experts to provide some "in-the-moment"
feedback to our current designs and their directions.
Today we presented more of our thoughts on the top-level statements/"simple programs"
features and records.
### Simple Programs
We have a prototype of simple programs. As per the existing spec, you can have
top-level functions among all files, and other statements in a single file.
Collected feedback, not in any particular order:
* Supporting local functions in files other than the top-level statement file doesn't
seem useful and could cause confusion. If there's a local function defined in a file
only with classes, it would appear that that function would be in scope for the
classes, according to C# lexical scoping conventions. However, since these are defined
as *local functions*, not top-level methods, it would be an error to use them inside
the class. Moreover, even if that confusion is resolved, there doesn't seem to be a
compelling reason to allow it in the first place. Because these functions are not
accessible from anything except the main statement file, it would be most likely to
want to put the functions in that file, next to the uses. The only benefit from allowing
local functions in separate file may be as a helper file that is linked into other
compilations. However, wrapping these utility functions in a class so they can be used
in more places seems like a small burden with big benefits. Once wrapped in a class,
these functions are simply methods like in C# today.
* Mixing classes and statements in the same file could generate some confusion. The existing
design is that classes can see the variables created by statements, but it would be illegal
to reference them. This keeps the option open to allow access later. However, this could be
a confusing middle ground. To simplify the situation we could require only statements in the
top-level in one file (forcing all types to be declared in separate files). However, there is
interest in using utility classes in the top-level statements, perhaps especially with a
forthcoming records feature that provides simple, short syntax for declaring new types.
* Many of these features mirror what we already have in CSX. It's good that our
current designs are similar and allow these constructs in more places, but since the semantics of
this design have subtle differences from CSX this would effectively create a third dialect of C#.
There's some desire to unify these worlds, but it's difficult. CSX is designed to allow all
values to be persisted, which is important for the scripting "submission" system, but this makes
a number of types of statements illegal that we have support for in the current design, like
ref locals. It also creates a burden for new designs, where statements need to be explicitly
designed for both CSX and C#. For example, the new `using var` declaration form is nonsensical
under the CSX design and probably should be illegal. Since the current 'simple programs' design
effectively treats statements like they are part of a method body, there's a cleaner semantic
parallel with C#, meaning less special-casing.
### Records
Here we presented a variety of different pieces of designs we have been thinking about.
#### Nominal Record
Feedback:
* One of the biggest drawbacks of the current writeable-property style in C#, where types are
declared with public mutable properties that are then initialized using object initializers,
is that author can't enforce that certain properties are always initialized. It would be a
big disappointment if any "nominal records" feature that we built couldn't support this feature.
* With the design as-is there's no way to validate the whole state of the object. However, that's
also true of the object-initializer style currently in use, and this doesn't seem to be as a big
of a problem for current users.
#### Value Equality
* Positive feelings on generating `.Equals(T)` and implementing `IEquatable<T>`, mixed feelings
on generating the `==` and `!=` operators.
* If we opt-in the whole class using `value class`, we also need an opt-out for individual members.
Regular classes also often have somewhat specialized equality requirements, like wanting to compare
certain lists as sequence-equal, or compare strings ignoring case. This observation points to a
lot more customization points for value equality on general classes than value equality on records.
* Using value equality on mutable state is seems dangerous if the type is used in a dictionary,
but despite the danger, other languages (Java, Go) have value equality for common types, like
lists, that can be easily added to a dictionary.
* We don't currently have a robust mental model for what it means to be a "value class." Is "value
class" a separable concept from "implementing value equality," which people often do today? Or
is it not a different type of class, but simply a modifier signaling an implementation detail,
namely that the compiler generates value equality automatically. If we think of value equality
as a public contract, how does that change our view of existing code? Classes can currently
override Equals, but we don't distinguish what *kind* of Equals they provide. That isn't a
language concept, in a sense, but a part of the documentation.
### Nominal Records
* When using the `with` expression on nominal records, the generated parameter-less `With` method
looks a lot like `Clone`. It does little aside from return a new object with a shallow copy of
the state. If `With` is essentially Clone, why not use one of the existing forms of Clone that we
already have?
* ICloneable is deprecated and MemberwiseClone is protected. Maybe we should just call the method
Clone(), but not override or implement any of the other framework uses.
* This feature looks a lot like structural typing from other languages, like Javascript's "spread"
operator, but that is not the feature we're currently trying to build. This is feature is still
about declaring new types, not providing some compatibility between existing types.
* We spent a lot of time talking about validation and "validators", a very recent concept that was
floated as an alternative to constructors, executing after the `with` expression.
* There's some general concern about having no capability of validation, but no consensus on
exactly how validators should work.
* If validators work against the copied fields of the object, that seems to imply that the
fields are the state being operated on. On the other hand, only certain members can be
mentioned in the `with` expression. Why wouldn't those be the things that are copied? Instead
of all the state?

View file

@ -0,0 +1,80 @@
# C# Language Design for March 9, 2020
## Agenda
1. Design review
2. Records
## Discussion
### Simple Programs
In the design review we covered the "simple programs" feature. A big piece of feedback is that
they didn't like the "middle ground" we had carved out with local functions. Right now we have
local functions that can exist both in the top-level statement "file" and also across other
files. Because the design allows only local functions at the top level, those functions are only
accessible from and can only access the statements in the "top-level statement file."
The feedback was that this would be an unfortunate design point. Organizing local functions in
other files, when they can't be accessed by other files, is a big problem. There are two places
we could go with this. We could either pull back and allow many of these forms only in the
"top-level statement file." Or we could go the other way and allow more functionality at the top
level, like allowing truly top-level members, including functions and variables, that can be
declared and referenced from everything in the program.
Allowing full top-level members is attractive but opens a lot of questions. The most important is
top-level variables. By allowing top-level variables and giving them the C# default of
mutability, we would effectively be enabling mutable global variables. There is collective
agreement that in everything but the smallest programs this is a bad programming practice and we
shouldn't encourage it.
We could try to pivot on syntactic differences. One major difference between local variables and
functions and member-level variables and functions is that members allow accessibility modifiers.
Top-level statements could be, by default, local variables. Accessibility modifiers, `public`,
`private`, `internal`, et al., could differentiate between top-level and local variables.
However, this feels like it may be too subtle a design point, relying too much on minor syntactic
decisions to decide things like scoping.
The biggest takeaway is that this is a complex topic with a lot possibilities. Maybe we could try
to carve out a small portion to make some progress, without committing to a narrow design for the
entire space of "top-level members." We generally like this approach, but CSX makes things
difficult. Since the existing design focuses on local variables and local functions,
compatibility with any sort of submission system is a problem. Fundamentally, we would need to
decide which pieces of state in a C# program are "transient," in that they cannot be referenced
from a new submission, and which are "preserved."
The value still seems important enough to move forward. There's general agreement that top-level
statements are useful. Some people think they are useful in the simple form already presented,
while other people want to see this as the starting point for a full feature, and these views are
roughly compatible.
If we move forward with our subset, we need to flesh out the mental model for how it works.
Specifically, it's important to note why top-level variables and functions would be inaccessible
from inside classes. One way to think about this is the difference between instance and static.
When you're in a static context, all the instance variables are visible, but not accessible. You
could also model it as the statements are directly inserted into Main (which is true).
**Conclusion**
We'd like to move forward with the prototype with the modification that top-level statements can
only appear in one file. Symbols declared in these statements would be visible, but an error to
access inside classes. All the top-level statements are treated as if they were inside an async
Main method.
### Value equality
When we discussed records in the design meeting we brought up value equality for records and a
proposal for extending to regular classes. A big shift was that records should have an easy
global automatic value equality, while general classes should never have a global opt-in.
This seems contradictory, but if records have a set of default semantics that naturally fit value
equality, then having it enabled by default is suitable. Value equality plays particularly well
with immutability. Since records strongly support immutable programming, supporting value
equality is natural. For arbitrary classes, however, it's not clear at all how value equality
should behave. Opt-ing in either all or only some members seems to have downsides for many class
examples.
We're not ruling out value equality for regular classes, but for the future we'd like to examine
specifically how we'd like value equality to work for records. This could impact how and when we
bring generated value equality to conventional user classes.

View file

@ -0,0 +1,103 @@
# C# Language Design Meeting for March 23rd, 2020
## Agenda
1. Triage
2. Builder-based records
## Discussion
### Triage
#### Generic constraint `where T : ref struct`
Proposal: #1148
This is a very complicated area. It's probably not good enough to add this generic constraint,
because things like default interface methods create a boxed `this` parameter. It's likely that
we would need runtime support to make this safe.
This is somwewhat related to the designs in the shapes/roles proposal in that it's about using
the "shape" of an interface, possibly with more restrictions than interfaces themselves. Since
both proposals may require runtime changes it would be valuable to batch up those changes
together.
##### Conclusion
Push to at least C# 10.0. Should be considered in concert with the shapes/roles proposals.
#### Improve overload resolution for delegate compatibility
Proposal: #3277
This is a parallel to changes we previously made to betterness where we remove overloads
that will later be considered invalid, to be removed from the overload resolution candidate
list in the beginning. This functionally will cause more overload resolution calls to succeed,
since invalid candidates will be removed and this will prevent overload resolution ambiguitiy.
##### Conclusion
Tentatively added to C# 9.0. We'd like this proposal for function pointers, so if we were to
implement this for function pointers and correct overload resolution for delegates at the same
time, that would be desirable.
#### Allow GetEnumerator from extension methods
Proposal: #600
First thing is to confirm that there's no compat concern. When we tried to extend the behavior
for `IDisposable` we ran into a problem because `foreach` *conditionally* disposes things which
match the `IDisposable` pattern. This means that if anything starts satisfying the pattern which
didn't before, an existing method may be newly called. If we ever conditionally use the `foreach`
pattern this would probably also be a breaking change.
##### Conclusion
Willing to accept it any time, as long as we confirm that it's not a breaking change.
### Builder-based records
When discussing records we've had various
designs that focus on "nominal" scenarios, where the members of the record are set by name, instead of lowering into method parameters. One proposed implementation strategy is a new series of rules around initialization that we've sometimes called "initonly." We've also looked at using struct "builders" in the past for a similar purpose, and would like to revisit some of these discussions.
We have a proposal from a community member, @HaloFour, that lays out another example implementation strategy that we're using for discussion.
https://gist.github.com/HaloFour/bccd57c5e4f3261862e04404ce45909e
There are certainly some advantages to this structure:
* Uses existing valid C# to implement the pattern, making it compatible with existing compilers. If
we avoid usage of features like `ref struct` and `in`, it could be compatible for even older
consumers, since this would be binary compatible with C# 2.0 metadata.
* Allows the type being built to always see the whole set of property values being initialized,
meaning that the author of the type can validate the new state of the object.
* No new runtime support for any features (e.g., does not require covariant returns)
There are also some disadvantages.
Performance could be a problem. For classes, the biggest concern is stack size. Currently,
initializing a class with an object initializer only requires a single pointer on the class and
then each member is initialized separately, the initializer values don't all need to be on the
stack simultaneously. If we use a struct builder, the entire builder needs to be on the stack
before initialization.
For structs, there is the extra stack space cost, but having a builder also effectively doubles
the metadata size of the every struct. It's also potentially harder for the CLR to optimize the
initialization and remove dead stores through the double-struct passing. If we go forward with
this approach we should consult the JIT for their perspective.
We're also not sure that this approach fully eliminates all brittleness in adding/changing fields
and properties across inheritance, especially if the inheritance is split across assemblies and
only one author is recompiled, or they are recompiled in a different order. If we can find a way
to close those holes, or limit the feature to prevent these situations, that could be an
important mitigating factor.
#### Conclusion
There's a difficult balance here. Some members are focused on about performance, some prioritize
ecosystem compat, and others prioritize "cleanliness" of design, in different directions. Almost
everyone has a different priority and prefers different approaches for different reasons. We need
to discuss things more and reduce some of the unknowns.

View file

@ -0,0 +1,117 @@
# C# Language Design Meeting for March 25, 2020
## Agenda
1. Questions around the new `nint` type
2. Target-typed new
## Discussion
Issue #3259
### LangVersion
THe question is what the behavior of the compiler should be when seeing an `nint`
type in `langversion` C# 8. Our convention is that the compiler never preserves
old *behavior* for older language versions. For instance, we do not preserve the
code for older code generation strategies and switch to that with the language
version flag. Instead, `langversion` is meant to be guard rails, providing
diagnostics when features are used that aren't available in older versions of the
language.
There are a few options we could take.
1. Make an exception for `nint`, allowing them to be seen and compiled like an
`IntPtr` in `langversion` C# 8.
2. Make a wider divergence between `nint` and `IntPtr`. Adding a `modreq` to
the emitted `IntPtr` type would make them effectively unusable by older language
versions and other languages.
3. Preserve the behavior, as long as no new semantics are used. For instance,
using the arithmetic operators on `nint` and on `IntPtr` have different semantics.
It would be an error to use any of these operators in older language versions.
**Conclusion**
We think (3) is the best balance.
### `IntPtr` and `nint` operators
We have two proposals:
1. Remove built-in identity conversions between native integers and underlying types and add explicit conversions.
2. Remove `nint` operators when using the `IntPtr` type
**Conclusion**
(1) is a little too harsh. Let's do (2).
### Behavior of constant folding
The concern is platform dependence.
In the following example
```C#
const nint m = int.MaxValue;
const nint u1 = unchecked(m + 1);
nint u2 = unchecked(m + 1);
```
if the machine is 32-bit, then the result overflows. If the machine is 64-bit, it does not.
While it's possible in the existing language to produce constant-folded values which are
undefined, we don't think that behavior is desirable for nint.
The main contention is what to do in a `checked` context if we know the value will overflow
32-bits. We could either produce an error, saying that this will overflow on some platforms,
or produce a warning and push the calculation to runtime, warning that the calculation may
overflow at runtime (and produce an exception).
**Conclusion**
Whenever we can safely produce a constant value under 32-bits, we do constant folding. Otherwise,
the result is non-constant, and under `checked`, the code produces a warning and the result
is non-constant.
### Interfaces on `nint`?
Should interfaces on `IntPtr` and `nint` match? Or should `nint` only accept a certain set of
compiler-validated interfaces on `IntPtr`?
**Conclusion**
We trust that interfaces will only be added to `IntPtr` with recognition that those interfaces
also affect `nint`. We'll make all interfaces on `IntPtr` available on `nint`, with `IntPtr`
occurrences substituted for `nint`.
## Target-typed `new`
https://github.com/dotnet/csharplang/blob/master/proposals/target-typed-new.md
Clarification about library evolution: if a user uses `new()`, adding a constructor to a type
can produce an ambiguity. Similarly, if a method is called with `new()` that can produce an
ambiguity if more overloads of that method is added. This is analogous with `null` or `default`,
which can convert to many different types and can produce ambiguity.
The spec currently specifies that there are a list of types where target-typed new is allowed. To
simplify, we propose that we specify that target-typed new should produce a fully-typed `new` and
the legality of that expression is defined elsewhere. This does make `new()` work on enums, which
is currently proposed as illegal because it may be confusing. However, `new Enum()` is legal
today, so we think that it should be allowed for target-typed `new` simply because of
consistency.
There's some debate on what it should do for nullable value types. On the one hand, the rule
"new() is just shorthand for writing out the type on the left," implies that the result should be
`null`. On the other hand, the nullable lifting rules would imply that the base type of the
target should be the underlying type, not the nullable type. Overall, we think that `new`ing the
underlying type makes the most sense, both because it's the most useful (we already have a
shorthand for `null`) and because it's likely what the user intended.
For `dynamic`, we will not permit it simply because `new dynamic()` is also illegal.
Final thought: many thanks to @alrz for the great contribution!

View file

@ -0,0 +1,112 @@
# C# Language Design Meeting for March 30, 2020
## Agenda
Records
1. Builders vs init-only
2. Possible conflicts with discriminated unions
3. Value equality
## Discussion
### Builders vs. init-only
We discussed more of the tradeoffs of using builders vs using an "init-only" feature for records,
and looked into requirements for other languages, including VB and F#. Based on our current
designs, the work needed to consume the new features for "init-only" seem fairly small.
Recognizing the `modreq` and allowing access to init-only members, and calling any necessary
"validator" on construction, are pretty simple features for VB. VB already has the syntactic
requirements for the feature (object initializers), and we'd like to keep it possible for VB to
consume major changes in the API surface, if not write those new features. F# is undergoing
active development and changes are certainly viable there. Because the scope of changes is more
open-ended in F#, it's possible it could feature more implementation work.
Notably, most of the features associated with "init-only" and "validators" do not require a new
runtime, only a new compiler version. The new compiler version is necessary to recognize safety
rules (validators must always be called after constructors, if they exist), but they don't use
any new features in the CLR. The only feature potentially requiring runtime features is
overriding a record with another record, which could potentially require covariant returns.
The remaining differences seem to come down to whether you can "see" the whole object during
initial construction (as opposed to validation). If you can see the whole object immediately,
that makes writing a `With` method that avoids a copy if all the values are identical very
straightforward. However, this could be done for "init-only" as well, by moving this semantic to
the `with` expression, optionally comparing the arguments to the `With` expression with the
values on the receiver object and avoiding calling With if they are identical. Therefore we don't
think we're actually ruling anything out by going down the "init-only" route.
There are advantages in going down the "init-only" route instead. The performance for structs
is probably better and more optimizable, and the IL pattern seems clearer and less bloated.
**Conclusion**
We like the "init-only" IL better. Given the path forward for other languages and compatibility
with many runtimes, we think it's a better future as an IL pattern.
### Conflicts with discriminated unions
There was a general question if these decisions could impact a future discriminated unions feature.
We don't have a lot in mind, but if we do end up building a discriminated union made of the records
feature, there is one component we may want to reserve. Discriminated unions often have a set of simple
data members. For instance, if we wrote a Color enum as a discriminated union, it could look like.
```C#
enum class Color
{
Red,
Green,
Blue
}
```
If we reduce these to records, it may look like:
```C#
abstract class Color
{
public class Red() : Color;
public class Green() : Color;
public class Blue() : Color;
}
```
The problem is: since those classes are effectively singletons, we'd like for the instances to be
cached by the compiler, to avoid allocations. However, we don't currently have a syntax in C# that
means "singleton." Scala uses the "empty record" syntax to mean singleton. We need to decide if we'd
like to reserve that syntax ourselves, or find some other solution.
### Value equality
We've decided that we want value equality by default for records. We need to settle on what that
means. The primary proposal on the table is shallow-field-equality, namely comparing all fields
in the type via EqualityComparer. This would match the semantic we have decided on for "Withers,"
where the shallow state of the object is copied, similar to MemberwiseClone.
There's a large segment of the LDM that thinks doing anything except for field comparison is
problematic because it introduces far too many customization points for the record feature.
Almost all custom equality would have to deal with sequence equality and string equality, which
are already very different mechanisms. There's a proposal that we could provide further
customization via source generators, which could allow almost any customization.
A follow-up to that is: why have value equality by default at all? Why not use source generators
for all value equality? One problem with that is that we want the simplest records to be very
short. The other problem is that we effectively have to pick an equality (C# will inherit one if
you don't). We previously decided that value equality is a non-controversial default -- if it's
wrong it's probably not worse than when reference equality is wrong, and it's often better.
Struct-like field-based equality is a simple and familiar version of value equality.
We also need to decide on value-equality as a separable feature for regular classes. Some people
like the idea of a separate feature and would be fine even with the constrained version that only
compares fields. Others don't think this feature meets the hurdles for a new language feature. If
we don't have customization options, it may be rarely used, and it seems possible that a source
generator version could be the much more popular version. It's also worth noting that, as a
separable feature, we don't need to add separable equality now.
**Conclusion**
No separable value equality for non-records, right now. Default record equality is defined as
field-based shallow equality.

View file

@ -0,0 +1,119 @@
# C# Language Design Meeting for April 1, 2020
## Agenda
1. Function pointer calling conventions
2. `field` keyword in properties
## Discussion
### Function Pointers
There are a few open issues and proposals for generalization of function pointers based on
new runtime features.
https://github.com/dotnet/csharplang/issues/3324
#### NativeCallableAttribute
The attribute already exists in the CLR, and allows for specifying a calling convention other than
`managed` (which means that it can't be called from C#, but could be used from function pointers).
The question is what level of support we want to provide in the language for this attribute.
Since the runtime behavior is to crash if the method is called incorrectly (meaning, invoked at
all from C# if not through a function pointer), we almost certainly want to recognize the
attribute's existence and provide errors for incorrect usage.
We considered more restrictions than the ones mentioned in the issue (only usable in function
pointers, parameters must be blittable, must be static) like restricted accessibility or special
syntax. The consensus is that is too much work for a small feature.
**Conclusion**
`NativeCallableAttribute` should be recognized and the restrictions are accepted, with the
addition that generics are also prohibited in the method and all containing types, recursively,
and delegate conversion is also prohibited.
#### Supporting extra calling conventions
The existing proposal mandates that the only the existing calling conventions are supported. We
previously said we'd consider new calling conventions when they were proposed by the runtime. We now
have proposals about some likely new calling convention from the runtime.
The proposal is that the "calling convention" syntax in function pointers could be a general identifier, and legal values for the runtime would be determined by name matching against type names
starting with `CallConv` in a particular namespace, and passing through Unicode lower-case mapping.
**Conclusion**
Accepted.
#### Attributes on function pointer types
The syntax is getting a bit verbose, but allowing an extra axis for customization seems like the
simplest extension of function pointers that provides the level support that the runtime may need
in the future.
Currently our favored syntax is:
```C#
delegate* cdecl[SuppressGCTransition, MyFuncAttr]<void> ptr;
```
The attribute-like syntax would be turned into the `modreq`s on the function pointer type that
would be used by the runtime to encode special calling behavior. These would also effectively be
different types at the C# level and would not have implicit conversions between them.
**Conclusion**
Accepted, assuming there are no problems in implementation.
### `field` keyword in properties
Over the years there have been many requests for similar features, e.g.
https://github.com/dotnet/csharplang/issues/140
Maybe the simplest version is that there is a contextual identifier, e.g. `field`, which refers
to an implicit backing field of the property. This seems useful, but a big limitation is that the
backing field of the property must have the same type as the property. If lazy initialization is
a common case, that seems likely to require differing property types, as the backing field would
often be nullable, but the initialized field would be not nullable.
On the other hand, biting off too much in a single feature may delay simple scenarios
unnecessarily. Should we try to address the simplest scenarios first, and leave more complex
scenarios for later? In this case we probably need to find what scenarios are served by that
design. Two things that are recognized are simple validation, e.g.
```C#
public int PositiveValue
{
get => field;
set
{
if (value < 0)
throw new ArgumentException("Cannot be negative")
field = value;
}
}
```
and registration like `INotifyPropertyChanged`
```C#
public int P
{
get => field;
set
{
PropertyChanged();
field = value;
}
}
```
Let's confirm that these scenarios are the ones most commonly requested and that they aren't
addressed or modified by any of the other scheduled language features, e.g. source generators for
INotifyPropertyChanged. From there we can discuss the specific proposal with a better
understanding of the problem and solution space.

View file

@ -0,0 +1,86 @@
# 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.

View file

@ -0,0 +1,154 @@
# C# Language Design for April 8, 2020
## Agenda
1. `e is dynamic` pure null check
2. Target typing `?:`
3. Inferred type of an `or` pattern
4. Module initializers
## Discussion
### `e is dynamic` pure null check
We warn that doing `e is dynamic` is equivalent to `e is object`, but `e is object` is a pure
null check, while `e is dynamic` is not. Should we make `is dynamic` a pure null check for
consistency?
**Conclusion**
Yes.
### Target-typing `?:`
The simplest example where we have a breaking change is
```C#
void M(short)
void M(long)
M(b ? 1 : 2)
```
Previously this would choose `long`, because the expressions are effectively typed separately,
and when inferring `1 : 2` we would choose `int`, and then rule out `short` during overload
resolution as invalid.
Target-typing converts each arm in turn to find the best possible type, selecting `short` instead
of `long`. That means the first overload is selected instead with target-typing.
It's hard to easily avoid this breaking change. The obvious mechanism, running overload
resolution twice, is problematic because having multiple arguments with `conditional` expressions
produces exponential growth in the number of passes of overload resolution.
**Conclusion**
Let's talk about this again in a separate meeting. Since whatever we choose here will probably
be the final decision (any further changes will be breaking), we want to be sure we're making the
best choice.
### Inferred type of an `or` pattern is the common type of two inferred types
```C#
object o = 1;
if (o is (1 or 3L) and var x)
// what is the type of `x`?
```
The problem here is that the existing common type algorithm allows conversion that are forbidden
in pattern matching. In the above case we would choose `long`, because `3L` is a long, and `1`
can be converted to `long`. However, in pattern matching the widening conversion from `int` to
`long` is illegal.
The proposal is to narrow the set of conversions only to implicit reference conversions or
boxing conversions. Why this could be useful is the example
```C#
class B { }
class C : B { }
if (o is (B or C) and var x)
// x is `B`
```
A follow-up question is about ordering. The proposed rules only infer types mentioned in
the checks, meaning that the following
```C#
if (o is (Derived1 or Derived2 or Base { ... }) and var x)
```
looks like this today
```C#
((Derived1 or Derived2) or Base)
-> ((object) or Base)
-> (object)
```
On the other hand, if the example were parameterized in the opposite way,
```C#
(Derived1 or (Derived2 or Base))
-> (Derived1 or (Base))
-> (Base)
```
So the ordering seemingly matters if the `or` pattern is a simple binary expression.
The first question is if
```C#
if (o is (Derived1 or Derived2 or Base { ... }))
```
should produce `Base`, and the second question is if parenthesizing affects this, e.g. explicitly saying
```C#
if (o is ((Derived1 or Derived2) or Base { ... }))
```
produces `object`.
**Conclusion**
We're not seeing a lot of scenarios that depend on these features, but not doing it feels like
leaving information on the table. Functionally, the compiler can infer a stronger type, so why
not do so? The proposed modified common type algorithm is accepted.
We also think that type narrowing for the `or` operation should use all the `or` operations
in a series as the arguments to the common type algorithm.
### Module Initializers
Proposal: https://github.com/RikkiGibson/csharplang/blob/module-initializers/proposals/module-initializers.md
There are a few places where module initializers today. The most common is a shared resource
that is used by multiple types, but the program would like to initialize the shared resource
before the static constructors of the types are run.
The question for the implementation is to how to indicate where the code for the module
initializer will go, and how the compiler will recognize it.
The proposal provides a mechanism to identify the module initializer via an attribute on the module
that points to a type, and type contains a static constructor that acts as the module initializer.
From a conceptual level, this seems more complicated than necessary. Can we put the attribute on the
type or, even the method, that holds the code for the module initializer?
If we go that route, why require the code be in the static constructor at all? Can any static method
be a target? One reason why we may prefer a static constructor is that if the emitted module initializer
calls the target static constructor method, it's easy to insert code before that method is invoked
by writing a static constructor for the containing type. On the other hand, even static constructor
can have code inserted before them, for example with static field initializers.
The last question is whether to allow only one module initializer method, or allow multiple and specify
that the compiler will call them in a stable, but implementation-defined order.
**Conclusion**
Let's let any static method be a module initializer, and mark that method using a well-known attribute.
We'll also allow multiple module initializer methods, and they will each be called in a reserved, but
deterministic order.

View file

@ -0,0 +1,77 @@
# C# Language Design for April 13, 2020
## Agenda
1. Roadmap for records
2. Init-only properties
# Roadmap for records
We want to break down the records feature in a way that gets incremental steps out to partner teams and users sooner, and lets us iterate based on feedback. So what order should we do things in?
Two demanding aspects of records that are certainly important but can probably be done later are:
1. Primary constructors (allowing positional parameters directly on record types)
2. Inheritance to and from record types
So a proposal is to split those off in the first iteration of implementation.
## Decision
We do need to get those right to ultimately ship the feature! However, we want to start by building a version of records that:
* Is nominal only (no primary constructor)
* Inherits from object and can't be inherited from
* Special-cases `with` expressions to `With` methods rather than rely on a "Factory" feature
* Fully implements value equality
For this to be useful we need the init-only property feature at the same time as well, so that there is *some* way to create and initialize immutable records.
In subsequent iterations we will
* Add support for inheritance to records
* Add primary constructors to records
* Generalize the `With` implementation to use factories
* Decide on and embrace defaults (`public` by default?) and abbreviations
On parallel tracks we will work on:
* Factory methods
* Validators?
* Mandatory properties?
* Primary constructors as a general feature?
# Init-only members
Init-only properties are the most urgent separate feature to nail down, as the experience of even the first iteration of records depends on them. There are a couple of design decisions still left open; we address them here.
## Should we have init-only fields?
Readonly fields today can only be assigned during construction, and only through a `this` access within the body of the class that declares the field. As we extend the concept of "initialization time" to cover execution of init-only setters (by object initializers in client code) as well as validators (if we add those to the language), it makes sense that `readonly` fields should be assignable from within those kinds of members as well.
We would *not* allow readonly fields to be directly assigned in an object initializer, however, as that would undermine the expectation that the class author has full control over how and when they are assigned.
Allowing init-only properties to assign readonly fields would address most of the init-only scenario: An object initializer can be used to set immutable state on the newly created object. A dedicated init-only form of fields is not needed for that. It probably *does* have valid scenarios (in programming styles where immutable fields are themselves public), but those seem less central. We could wait see if that rises to the importance of a seperate, subsequent feature.
### Decision
Let's allow init-only property setters (and validators, if and when we add them) to assign to `readonly` fields of the same object.
Let's not add init-only fields now. We can consider a new kind of field that can be initialized directly in object initializers later, as a separate feature, if we become convinced that it's worthwhile.
## Syntax
Should the setters of init-only properties be called `init` or `init set`? In other words, is `init` a modifier on the `set` accessor, or does it replace it completely?
Shorter is generally nicer. However, we do foresee a (near?) future where `init` as a modifier could be applied to other members and accessors, to mean that they can only run during initialization (and in return would get privileges such as assigning to readonly members).
### Decision
`init` it is. `init` as a modifier is an interesting feature, but we can discuss it separately. If we do, we can consider allowing `init set` as a long form of an init-only setter for regularity when code has `init` modifiers in multiple places. But for now, let's just allow `init` instead of `set`.
## Init-only indexers
Indexers also have `set` accessors. Should they also be allowed to declare an `init` accessor instead?
### Decision
It makes perfect sense, is somewhat useful, would be more regular in the language, and has straightforward semantics. Let's do it.

View file

@ -0,0 +1,74 @@
# C# Language Design Notes for Apr 15, 2020
## Agenda
1. Non-void and non-private partial methods
2. Top-level programs
# Non-void, non-private partial methods
Proposal: https://github.com/dotnet/csharplang/issues/3301.
Currently, partial methods are required to return void. They are implicitly private, and cannot have an explicit accessibility. In return for that, calls to a partial method that has a *declaration* but no *definition* can be safely elided by the compiler. Thus, partial methods serve as optional "hooks" or points of extension for generated code, code that is conditionally included based on compilation target, etc.
With the expected advent of source generators in the C# 9.0 timeframe, there are likely to many scenarios where these restrictions are too limiting. The proposal suggests a different trade-off for partial methods, where they *can* have return values, and *can* have broader accessibility, but in exchange the definition is *mandatory*: An implementation *must* be provided, since calls can't be elided.
The mandatory aspect can in fact be viewed as a feature. It is a way for one part of the code to *require* another part to be specified, even as they are separated across files and authorship.
Main concern is that we would need to preserve the "old" semantics for compatibility in cases that are already allowed in C#, and developers may accidentally fall into that case, failing to compel another part to produce an implementation, and having calls elided without wanting to.
One mitigating factor is that the existing feature doesn't allow you to explicitly say `private` - it has to be implied. So we could say that if `private` is explicitly supplied we are in the new semantics, and the method implementation is required. It's a subtle an non-obvious distinction, but at least it is there.
Another question is whether we would allow other members to be partial. We would need to work out the syntax in each case: E.g. how do you distinguish a partial property definition from a declaration that implements it as an auto-property?
## Decision
Despite the weirdness of distinguishing between implicit and explicit private (the latter requires an implementation, the former does not), we are ok with accepting this wart in the language. The feature extension is valuable, and alternative solutions are distinctly less appetizing.
On the other hand we are not ready to allow `partial` on other kinds of members. If future scenario bear out a strong need, we will do the design work to hash it out, but we think methods are able to address the vast majority of what's needed.
# Top-level statements
Proposal: https://github.com/dotnet/csharplang/blob/master/proposals/Simple-programs.md
We took a look at the currently implemented semantics to make sure we are happy with them. A couple of questions came up:
## Expressions at the end
Part of the motivation for the feature was to decrease the syntactic distance between C# (.cs) and its scripting dialect (.csx). However, unlike script we still don't allow expressions at the end. For the scripting dialect this is mostly for producing a result in an interactive setting.
### Decision
We are ok with this remaining distance, and would prefer not to have a notion of "expression at the end produces result" in C#.
## Shadow and error
The proposal puts top-level local variables and functions in scope inside type declarations in the program. However, if they are are used in those places, and error is given.
### Decision
This is deliberately there to allow us to do a more general form of top-level functions in the future. We do believe that it protects likely future designs for this.
## Args
Currently there is no way to access the `args` array optionally given as input to an explicit `Main` method. Instead you have to make use of existing APIs that have a slightly different behavior (they include the name of the program as the first element), and certainly look different.
For anyone who uses the APIs in a top level program, they can still trivially move it into an explicit `Main` method at a later point, but going the other way with a `Main` body that uses `args` is not so easy.
There are ideas to:
- add a new API that looks more like `args` (e.g. `Something.Args`) and behaves the same way
- add `args` as a magic variable in top level programs (similar to `value` in property setters), on the assumption that 99.9% of `Main` methods use `args` as the parameter name.
### Decision
We think this is important to pursue further, but aren't going to hold up the feature for it.
## Await triggers a different signature
In the current implementation, the signature of the `Main`-like method generated from the top level program will be different, depending on whether `await` is used or not. If it is, then the signature will include `async Task<...>`, otherwise it won't.
An alternative would be to always generate a `Task`-based signature, and just suppress the usual warning when no `await`s occur in the body. The choice doesn't affect the user much. The main difference is that with the current design there is no need to reference the `Task` types, and any limitations imposed by the language inside async methods are not in force, unless `await` is used.
### Decision
We stick with the current design.

View file

@ -0,0 +1,64 @@
# 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.

View file

@ -0,0 +1,180 @@
# C# Language Design Meeting for April 27, 2020
## Agenda
1. Records: positional
## Discussion
The starting point for positional records is how it fits in with potential
"primary constructor" syntax. The original proposal for primary constructors
allowed the parameters for primary constructors to be visible inside the class:
```C#
class MyClass(int x, int y)
{
public int P => x + y;
}
```
When referenced, `x` and `y` would be like lambda captures. They would be in
scope, and if they are captured outside of a constructor, a private backing
field would be generated.
One consequence of this design is that the primary constructor must *always*
run. Since the parameters are in scope throughout the entire class, the primary
constructor must run to provide the parameters. The proposed way of resolving
this is to require all user constructors to call the primary constructor, instead
of allowing calls to `base`. The primary constructor itself would be the only
constructor allowed (and required) to call `base`.
This does present a conundrum for positional records. If positional records support
the `with` expression, as we intended for all records, they must generate two constructors:
a primary constructor and a copy constructor. We previously specified that the copy
constructor works off of fields, and is generated as follows
```C#
class C
{
protected C(C other)
{
field1 = other.field1;
...
fieldN = other.fieldN;
}
}
```
This generated code violates the previous rule: it doesn't call the primary constructors.
One way to resolve this would be to change the codegen to delegate to the primary constructor:
```C#
record class Point(int X, int Y)
{
protected Point(Point other) : Point(other.X, other.Y) { }
}
```
This is almost identical, except that the primary constructor may have side-effects, or the
property accessors may have side-effects, if user-defined. We had strong opinions against using
the accessors before because of this -- we couldn't know if the properties were even
auto-properties and whether we were duplicating or even overwriting previous work.
However, we note that violating the rule for our generated code shouldn't be a problem in
practice. Since the new object is a field-wise duplicate of the previous object, if we assume
that the previous object is valid, the new object must be as well. All fields which were
initialized by the primary constructor _must already be initialized_. Thus, for our code
generation it's both correct and safer to keep our old strategy. For user-written constructors
we can require that they call the primary constructor, but because the user owns the type, they
should be able to provide safe codegen. In contrast, because the compiler doesn't know the full
semantics of the user type, we have to be more cautious in our code generation.
This doesn't really contradict with our goal of making a record representable as a regular class.
A mostly-identical version can be constructed via chaining as described above. The only
difference is in property side effects, which the compiler itself cant promise is identical, but
if it were written in source then the user could author their constructor to behave similarly.
Property side-effects have an established history of being flexible in the language and the
tooling. Property pattern matching doesn't define the order in which property side effects are
evaluated, doesn't promise that they even will be evaluated if theyre not necessary to determine
whether the pattern matches, and doesn't promise that the ordering will be stable. Similarly, the
debugger auto-evaluates properties in the watch window, regardless of side effects, and the
default behavior is to step over them when single stepping. The .NET design guidelines also
specifically recommend to not have observable side effects in property evaluation.
We now have a general proposal for both how positional records work, and how primary constructors
work.
Primary constructors work like capturing. The parameters from the primary constructor are visible
in the body of the class. In field initializers and possibly a primary constructor body, they are
non-capturing, namely that use of the parameter does not capture to any fields. Everywhere else
in the class, the parameters are captured and create a private backing field.
Positional records work like primary constructors, except that they also generate public
init-only properties for each positional record parameter, if a member with the same signature
does not already exist. This means that in field initializers and the primary constructor body,
the parameter name is in scope and shadows the properties, while in other methods the parameter
name is not in scope. In addition, the generated constructor will initialize all properties with
the same names as the positional record parameters to the parameter values, unless the
corresponding members are not writeable.
#### Conclusion
The above proposals are accepted. Both positional records and primary constructors are accepted
with the above restrictions. In source, all non-primary constructors in a type with a primary
constructor must call the primary constructor. The generated copy constructor will not be
required to follow this rule, instead doing a field-wise copy. The exact details of the scoping
rules, including whether primary constructors have parameters that are in scope everywhere, or
simply generate a field that is in scope and shadows the parameter, is an open issue.
### Primary constructor bodies and validators
We do have a problem with some syntactic overlap. We previously proposed that our original
syntax for primary constructor bodies could be the syntax for a validator. However, there
are reasons why you may want to write both. For instance, constructors are a good way to
provide default values for init-only properties that may be overwritten later. Validators
are still useful for ensuring that the state of the object is legal after the init-only.
In that case we need two syntaxes that can be composed. The proposal is
```C#
class TypeName(int X, int Y)
{
public TypeName
{
// constructor
}
init
{
// validator
}
}
```
To mirror the keyword used for init-only properties, we could use the `init` keyword
instead. This would also hint that validators aren't *only* for validating the state,
they can also set init-only properties themselves. To that end, we have a tentative name:
final initializers.
#### Conclusion
Accepted. `type-name '{' ... '}'` will refer to a primary-constructor-body and `init '{' ... '}'` is
the new "validator"/"final initializer" syntax. No decisions on semantics.
### Primary constructor base calls
Given that we have accepted the following syntax for primary constructors and primary constructor bodies,
```C#
class TypeName(int X, int Y)
{
public TypeName
{
}
}
```
how should we express the mandatory base call? We have two clear options:
```C#
class TypeName(int X, int Y) : BaseType(X, Y);
class TypeName(int X, int Y) : BaseType
{
public TypeName : base(X, Y) { }
}
```
We mostly like both. The first syntax feels very simple and it effectively moves the "entire"
constructor signature up to the type declaration, instead of just the parameter list. However,
we don't think that class members would be in scope in the argument list for this base call
and there are some rare cases where arguments to base calls may involve calls to static private
helper methods in the class. Because of that we think the second syntax is more versatile and
reflects the full spectrum of options available in classes today.
#### Conclusion
Both syntaxes are accepted. If prioritization is needed, the base specification on the primary
constructor body is preferred.

View file

@ -0,0 +1,95 @@
# C# Language Design for May 4, 2020
## Agenda
Design review feedback
## Discussion
We had a design review on 2020-04-29 to bring our latest designs to the full review team and get
feedback. Today we went over the feedback and how it would affect our design.
### Final initializers
- Design review said it was very complicated, when do I use an initializer vs a constructor?
A possible fix would be to try to run initializers *before* constructors, instead of after. The
main problem is that this is not where object initializers (using setters) run today. It would be
very distasteful to have `init-only` setters run at a different time from regular setters, and
worse to subtly run the setters at a different time just because of the presence of a different
`init-only` field.
This is a difficult piece of feedback to reconcile, because it doesn't present a clear direction.
However, we're not sure we need to finish the design for final initializers now. We still think
the scenarios are useful, but there are many scenarios which don't rely on those semantics. One
of the most important scenarios that we were worried about was how to copy a type that had
private fields that should not be copied. One proposal was to write a final initializer which
either resets certain fields, or `throw`s if the state is invalid. Our proposed alternative for
this situation is to write your own copy constructor, which sets up the appropriate state for the
copy.
However, final initializers do address a significant shortfall in existing scenarios, namely that
there's no way to validate a whole object in a property setter (or initter). In that sense we do
have many existing issues, separate from our records designs, which would be addressable with the
feature. There is also no way to validate an object after a `with` expression since necessarily.
### Factory methods
The review team agreed about the necessity of "factory" semantics in the `with` expression, namely
that the with expression essentially requires a `virtual` Clone method to work correctly through
inheritance, but was not convinced that the feature was generally useful.
We're also not convinced that it's generally useful, but limiting `with` to only be usable on a
record is a significant change from where we were before, where records are currently fully
representable as regular classes.
We need to consider if we are willing to live with this limitation, or need a way of specifying
the appropriate `Clone` method in source.
### Structs as records
Can every struct be a record automatically? We don't need a `Clone` method, because structs
already copy themselves and they already implement value equality (albeit sometimes
inefficiently). If we take this stance, would we want to explicitly design records as "struct
behavior for classes?" If that's true, we would seek to use the behavior of structs as a template
for records.
### Positional records
The feedback was negative about making a primary constructor parameters different from positional
record parameters. The proposal during the design meeting was that primary constructors would see
parameters as "captured" in the scope of the class, while records would generate public
properties for each parameter. This is a big semantic divergence, as expressions like
`this.parameter` would be legal in the body of a positional record, but illegal in the body of a
class with a primary constructor. One way of shrinking the semantic gap would be to always
generate members based on primary constructor parameters, but in regular classes those members
would be private fields, while in records they would be public init-only properties. Even this
semantic difference was perceived as too inconsistent.
We have two proposals to unify the behavior inside and outside of records. On one end, we could
try to view primary constructors as a syntactic space to contain more elements. By default,
primary constructors would be simple parameters, which could be closed over in the class body. By
allowing member syntax in the parameter list, the user would have more control over the
declaration. For instance,
```C#
public class Person(
public string Name { get; init; }
);
```
would generate a public property named `Name` instead of simply a parameter and the property
would be implicitly assigned in the constructor.
On the other hand, we could _always_ make public properties, abandoning the idea of
primary-constructor-parameters-as-closures. In this formulation,
```C#
class C(int X, int Y);
```
would generate two properties, X and Y. If this is made into a record e.g., `data class C(int X,
int Y)`, then the same record members would be synthesized as in a nominal record.
We did not settle on a conclusion, but have a rough sense that having a primary constructor
always generate properties is preferred.

View file

@ -0,0 +1,79 @@
# C# LDM for May 6, 2020
## Agenda
1. `if (e is not int i)`
2. Target-typed conditional
3. Extension GetEnumerator
4. `args` in top-level programs
## Discussion
### `if (e is not int i)`
https://github.com/dotnet/csharplang/issues/3369
There are broader features that we'd to consider here as well, for instance allowing
some declarations below `or` patterns. However, this should be compatible with broader
changes and is easy to implement right now.
#### Conclusion
Accepted for C# 9. Further elaborations will be considered, assuming the schedule could
accept it.
### Target-typed conditional
We still unfortunately have a breaking change here with
```C#
M(b ? 1 : 2, 1); // calls M(long, long) without this feature; ambiguous without this feature
M(short, short);
M(long, long);
```
As always, breaking changes are very worrying, unless we are confident that almost no real-world
code would be broken. If the breaking change results in an ambiguity instead of silent different
codegen, that is substantially better, as people would at least know that the compiler changed
behavior. At the moment, we only think that this change could result in new ambiguities, not
different behavior.
#### Conclusion
We'll do some more investigation, try to find code that would be broken, and see if we can accept
the change.
### Extension GetEnumerator
https://github.com/dotnet/roslyn/issues/43147
Conclusions:
No objections to the proposals as written.
### `args` in Top-Level programs
If the top-level statements are logically inside a `Main` method, it would be very useful to have
access to the command line arguments for the program. You can access these via
`Environment.GetCommandLineArgs()`, but it's unfortunate that this is both different from the
APIs in Main, and `Environment.GetCommandLineArgs()` includes the program name, and `args` in
Main does not.
If we want to do something, we could have a magic variable named `args` (similar to `value` in
setters) or a property in the framework called `Args` (e.g. `Environment.Args`).
In favor of the property, fewer language-level changes means fewer things that people have to
learn.
In favor of the `args` magic variable, it's simpler to use than a property (since the property
would either have to qualified with a type name, or a `using static` would have to be added) and
a language feature for the inputs (command line args) mirrors the language feature for the output
(returning an `int` that turns into the process exit code).
#### Conclusion
We'll go with the `args` magic variable. We still need to decide on the scope: either equivalent
to top-level locals, which are visible in all files but inaccessible, or only in scope in
top-level statements. If we make it visible in all files we would only add the variable if there
is at least one top-level statement in the program.

View file

@ -0,0 +1,107 @@
# C# Language Design Meeting for May 11, 2020
## Agenda
Records
## Discussion
Today we tried to resolve some of the biggest questions about records,
namely how to unify the semantics of nominal records and positional
records, and what are the key scenarios that we are trying to resolve
with records.
The main inconsistency is that the members `record class Person(string FirstName, string
LastName)` are very different from the members in `class Person(string firstName, string
lastName)`. One way of resolving this is to unify the meaning of the declaration in the direction
of primary constructors. In this variant, the parameters of a primary constructor always capture
items by default.
To produce public init-only properties like we were exploring, we would require an extra
keyword, `data`, that could be generalizable. So a record which has two public init-only
members would be written
```C#
record Person(data string FirstName, data string LastName);
```
This would allow a generalizable `data` keyword that could be applied even in regular
classes, e.g.
```C#
class Person
{
data string FirstName;
data string LastName;
public Person(string first, string last)
{
}
}
```
The worry here is that we're harming an essential motivation for records, namely a short syntax
for immutable data types. In the above syntax, `record` alone does not mean immutable data type,
but instead only value equality and non-destructive mutation. A problem with this is that value
equality is dangerous for mutable classes, since the hash code can change after being added to a
dictionary. This was why we were previously cautious about adding a general feature for value
equality. One option to discourage misuse would be to provide a warning for any non-immutable
member in a record class.
The other problem is, frankly, it's not that short. Aside from some duplication of intent by
requiring both `record` and `data` modifiers, it also requires applying the `data` modifier to
each member, so the overhead grows larger as the type does.
Alternatively, we could go in the complete opposite direction: limit customizability by making
records all about public immutable data.
For instance, nominal records could also have syntax abbreviation
```C#
record Person { string FirstName; string LastName; }
```
and we could avoid confusion by prohibiting other members entirely.
This would look at lot more like positional records, e.g.
```C#
record Person(string FirstName, string LastName);
```
and we could introduce further restrictions on those by also disallowing other members
in the body, or even disallowing primary constructors entirely.
Disallowing all members inside of records is draconian, but not entirely without precedence.
Enums work the same way in C# and members are added via extensions methods. That's not a ringing
endorsement since we've considered proposals for allowing members in enums before, but it also
doesn't put it outside the realm of possibility for C#, especially in earlier forms.
The main drawback of the simplest form is the risk that we might have trouble evolving the
feature to fit all circumstances. If we wanted to allow a user to define private fields, the
syntax with no accessibility modifier now means "public init-only property" so we might not
be able to add support for private fields at all, or we might have to use a syntactic distinction
that requires a `private` accessibility, which is a subtle change.
### Conclusion
We largely prefer the short syntax for records. A nominal record would look like
```C#
record class Person { string FirstName; string LastName; }
```
This would create a class with public `init-only` properties named `FirstName`
and `LastName`, along with equality and non-destructive mutation methods.
Similarly,
```C#
record class Person(string FirstName, string LastName);
```
would create a class with all of the above, but also a constructor and Deconstruct.
We have yet to confirm whether `record` disallows private fields entirely, or if it
just changes the default accessibility.

View file

@ -0,0 +1,147 @@
# C# Language Design Meeting for May 27, 2020
## Agenda
1. Records -- syntax
## Discussion
### Syntax Questions
We got significant feedback that `record` is a better name than `data` for indicating
a `record`. There are two syntaxes we've been considering here:
1. `record class Person { ... }`
2. `record Person { ... }`
The main difference here is that (2) has less obvious space for a `struct` token, which
raises the question of whether "record structs" are a feature we want to enable.
There are a couple arguments for why records would be useful for structs. The first is
that "value behavior" is a general feature that could be useful for both structs and classes.
Value equality exists for structs today, but it is potentially slow in the runtime implementation.
The second is that the syntax provided for classes is also useful for structs. The positional
syntax specifically seems attractive because it has a lot of similarity to tuples and allows a
form of "named tuple."
```C#
record struct Point(int X, int Y);
```
On the other hand, we could improve the performance of equality, completely separate from records.
For instance, the compiler could add equality methods if they are not present. We also do not necessarily
need to address structs first. Since structs already have many features of records they are, in a sense,
"less far behind" than classes in record features. It makes sense to concentrate first on classes and
consider augmentations for structs in a future update.
So to return to the original question, we have to decide if we want to move forward with option (2), which
is a new form of declaration. Notably, this is a breaking change for certain scenarios e.g.,
```C#
record M(int X, int Y) { ... }
class C
{
record M(int X, int Y) { ... }
partial record M(int X, int Y);
}
```
All of these are currently method declaration syntax. In C# 9 this would be a record declaration
with a positional constructor and a body. Normally we would never consider this kind of change,
but since we started shipping with .NET Core we do not automatically upgrade language version
unless the target framework is the newest one (i.e., NET 5).
#### Conclusion
Do not support structs for now. They already support many features of records and we can add
more, time permitting.
The accepted proposal is that the syntax, `<modifiers> <attributes> 'record'` followed by
`identifier` and either '(', '{', or '<' would be contextually parsed as a record declaration
only if the language version is C# 9.
### Short-property syntax
We previously agreed that, to unify the syntax forms in the positional and nominal declaration, we
would allow fields in nominal records with no modifiers to instead be interpreted as public auto-properties.
After looking at feedback and exploring some of the related issues, we've decided that's not the best approach.
There are a few proposals on the table:
1. Leave positional records the same, do not provide special syntax for nominal records.
```C#
public record Point(int X, int Y);
public record Point
{
public int X { get; init; }
public int Y { get; init; }
}
```
2. Unify the declaration forms in favor of nominal records, allowing property declarations in the
record parameter list
```C#
public record Point(
public int X { get; init; },
public int Y { get; init; }
)
public record Point
{
public int X { get; init; },
public int Y { get; init; }
}
```
3. Keep positional records the same, provide a new modifier (e.g., `data` or `init`) for members
which means "public init-only property"
```C#
public record Point(int X, int Y);
public record Point
{
data int X;
data int Y;
}
```
4. Provide the new modifier from (3), and require it in both types of records
```C#
public record Point(data int X, data int Y);
public record Point
{
data int X;
data int Y;
}
```
After discussion, we prefer (3). Positional records already seem to have enough syntactic distinction and
the `data` keywords seem superfluous in this position. It also makes the shortest syntax form match up
with the most common use case.
However, we do think some further keyword is necessary for nominal records. Looking too much like existing
fields seems like it would be too confusing, especially if we want to also allow fields in records.
Instead, we're considering leaving positional records to generate public auto-properties by default, partly
because they are already a significantly different syntax that cannot be confused with existing language
constructs, and providing a new mechanism for positional records.
#### Conclusion
Keep positional records the same, provide a `data` modifier for fields which means "public
init-only property"
```C#
public record Point(int X, int Y);
public record Point
{
data int X;
data int Y;
}
```

View file

@ -0,0 +1,163 @@
# C# Language Design for June 1, 2020
## Agenda
Records:
1. Base call syntax
2. Synthesizing positional record members and assignments
3. Record equality through inheritance
## Discussion
### Record base call syntax
We'd like to reconsider adding a base call syntax to a record declaration, i.e.
```antlr
record_base
: ':' class_type argument_list?
| ':' interface_type_list
| ':' class_type argument_list? interface_type_list
;
```
The main question is how the scoping of the parameters from the record positional
constructor interact with the base call syntax and the record body.
We would definitely like the parameters to be in scope inside the base call. For the record body,
it's proposed that the parameters of the primary constructor are in scope for initializers, and
the primary constructor body (if we later accept a proposal for such syntax). The parameters
shadow any members of the same name. The parameters are not in scope outside of these locations.
To unify the scoping behavior between the base call and the body, we propose that members of the
body are also in scope in the base call syntax. Instance members would be an error in these locations
(similar to how instance members are in scope in initializers today, but an error to use), but
the parameters of the positional record constructor would be in scope and useable. Static members
would also be useable, similar to how base calls work in ordinary constructors today.
**Conclusion**
The above proposals are accepted.
### Synthesized positional record members
A follow-up question is how to do generation for auto-generated positional properties. We need
to decide both 1) when we want to synthesize positional members and 2) when we want to initialize
the corresponding members. The affect is most clearly visible in the example below, where the
initialization order will affect what values are visible at various times during construction,
namely whether the synthesized properties are initialized before or after the `base` call.
```C#
record Person(string FirstName, string LastName)
{
public string Fullname => $"{FirstName} {LastName}";
public override string ToString() => $"{FirstName} {LastName}";
}
record Student(string FirstName, string LastName, int Id)
: Person(FirstName, LastName)
{
public override string ToString() => $"{FirstName} {LastName} ({ID})";
}
```
First we discussed when to synthesize members, namely when an "existing" member will prevent
synthesis. A simple rule is that we synthesize members when there is no accessible, concrete
(non-abstract) matching member in the type already, either because it was inherited or because it
was declared. The rule for matching is that if the member would be considered identical in signature,
or if it would require the `new` keyword in an inheritance scenario, those members would "match." This
rule allows us to avoid generating duplicate members for record-record inheritance and also produces the
intuition that we should err on the side of not synthesizing members when they could be confused with
an existing member.
Second, we discussed when and in what order assignments were synthesized from positional record
parameters to "matching" members. A starting principle is that in record-record inheritance we don't
want to duplicate assignment -- the base record will already assign its members. In that case, we could
choose to assign only members synthesized or declared in the current record. That would mean
```C#
record R(int X)
{
public int X { get; init; }
}
```
would initialize the `X` property to the value of the constructor parameter even though the property
is not compiler synthesized. However, we would have to decide if it is synthesized before or after
the `base` call. In essence, the question is how we de-sugar the assignments. Is `record Point(int X, int Y);`
equivalent to
```C#
record Point(int X, int Y) : Base
{
public int X { get; init; } = X;
public int Y { get; init; } = Y;
}
```
or
```C#
record Point(int X, int Y) : Base
{
public int X { get; init; }
public int Y { get; init; }
public Point
{
this.X = X;
this.Y = Y;
}
}
```
Note that today property and field initializers are always executed before the `base` call, while
statements in the constructor body are executed afterwards and we are disinclined to change that
for record initializers.
Looking at the examples as a whole, we think using the initializer behavior is good -- it's easy
to understand and more likely to be correct in the presence of a virtual call in the base class,
but it makes things significantly more complicated if we synthesize it even for user-written
properties. Is the initializer synthesized even if there's already an initializer on the property?
What if the user-written property isn't an auto-property?
**Conclusion**
We think it's much clearer if we simplify the rules to only initialize synthesized properties.
Effectively, if you replace the synthesized record property, you also have to write the initialization,
if you want it. In the case that the property is not already declared, e.g. `record Point(int X, int Y);`
the equivalent code is
```C#
record Point(int X, int Y)
{
public int X { get; init; } = X;
public int Y { get; init; } = Y;
}
```
### Equality through inheritance
We have a number of small and large questions about how records work with inheritance.
Q: What should we do if one of the members which we intend to override, like object.Equals and
object.GetHashCode, are sealed?
A: Error. This is effectively outside of the scope of automatic generation.
Q: Should we generate a strongly-typed Equals (i.e., `bool Equals(T)`) for each record declaration? What
about implementing `IEquatable<T>`?
A: Yes. Implementing `IEquatable<T>` is very useful and would require a strongly-typed equals method. We
could explicitly implement the method, but we also think this is useful surface area. If we broaden
support to structs, this would prevent a boxing conversion, which has a significant performance impact.
Even for classes this could avoid extra type checks and dispatch.
Q: Should each record declaration re-implement equality from scratch? Or should we attempt to dispatch
to base implementations of equality?
A: For the first record in a type hierarchy, we should define equality based on all the accessible fields,
including inherited ones, in the record. For records inheriting from a class with an existing
`EqualityContract`, we should assume that it implements our contract appropriately, and delegate comparing
the EqualityContract itself and the base fields to the base class.

View file

@ -0,0 +1,41 @@
# C# LDM for June 10, 2020
## Agenda
1. "Roles"
## Discussion
Exploration of previous proposal: #1711
This is a topic that we've explored before which we're reviving for further consideration and discussion.
We have a "role" proposal, but it's more of a starting point for a final design. There are a number of
different problems we can presumably solve here, but it seems like we have some intersecting features that
might address multiple problems simultaneously.
There are many tradeoffs to consider in these designs. One of the most well-known is sometimes called
"incoherence," where the ability to implement an interface in two ways on the same type effectively causes
the two implementations to "cross" each other in ways that can be hard to predict. For instance, if two
people implemented `IEquatable<T>` on the same third-party type, and both added it to a dictionary, if they
used different `GetHashCode` implementations then the same member could be added twice, and each consumer
wouldn't see the implementation used by other consumers.
Another tradeoff is the ability to use the role as a type, namely refer to it in a type position. This
is often desirable, but has some tradeoffs in type equivalence (see SML modules for alternative notions
of type equivalence through functors).
The Roles proposal as a whole seems very powerful, but there are many big questions here. The biggest,
most pressing question is: what problems do we think are the most important and how big a feature do
we need to address them? Providing a way to abstract over different numeric abstractions is a concrete
scenario, but it may not need the fully generalized mechanism. Allowing existing types to conform
to an abstract after definition is also powerful and has many possible use cases, but how flexible
do we need to make that mechanism? Can it only be used in generics? Can you implement abstractions
defined in other compilations on types defined in other compilations?
The performance concerns are also very real. We have a few mechanisms for abstraction in the language
today, but a lot of those mechanisms come with performance costs like allocation that make them
unusable in performance-sensitive scenarios. We would like more zero-cost abstractions if possible,
but we're not sure what functionality we could provide in those circumstances and whether the features
would fit well into the existing ecosystem.

View file

@ -0,0 +1,197 @@
# C# Language Design Meeting for June 15, 2020
## Agenda
1. `modreq` for init accessors
1. Initializing `readonly` fields in same type
1. `init` methods
1. Equality dispatch
1. Confirming some previous design decisions
1. `IEnumerable.Current`
## Discussion
### `modreq` for init accessors
We've confirmed that the modreq design for `init` accessors:
- The modreq type `IsExternalInit` will be present in .NET 5.0, and will be recognized if
defined in source
- The feature will only be fully supported in .NET 5.0
- Usage of the property (including the getter) will not be possible on older compilers, but
if the compiler is upgraded (even if an older framework is being used), the getter will be
usable
### Initializing `readonly` fields in same type
We previously removed `init` fields from the design proposal because we didn't think it was
necessary for the records feature and because we didn't want to allow fields which were
declared `readonly` before records to suddenly be settable externally in C# 9, contrary to
the author's intent.
One extension would be to allow `readonly` fields to be set in an object initializer only inside
the type. In this case you could still use object initializers to set readonly fields in
static factories, but because they would be a part of your type you would always know the intent
of the `readonly` modifier. For instance,
```C#
class C
{
public readonly string? ReadonlyField;
public static C Create()
=> new C() { ReadonlyField = null; };
}
```
On the other hand, we may not need a new feature for many of these scenarios. An init-only
property with a private `init` accessor behaves similarly.
```C#
class C
{
public string? ReadonlyProp { get; private init; }
public static C Create()
=> new C() { ReadonlyProp = null; };
}
```
**Conclusion**
We still think `readonly` fields are interesting, but we're not sure of the scenarios yet.
Let's keep this on the table, but leave it for a later design meeting.
### `init` methods
We previously considered having `init` methods which could modify `readonly` members just
like `init` accessors. This could enable scenarios like "immutable collection initializers",
where members can be added via an `init` Add method.
The problem is that the vast majority of immutable collections in the framework today would be
unable to adopt this pattern. Collection initializers are hardcoded to use the name `Add` today
and almost all the immutable collections already have `Add` methods that are meant for a different
purpose -- they return a copy of the collection with the added item.
If we naively extend `init` to collection initializers most immutable collections wouldn't be able
to adopt them because they couldn't make their `Add` methods `init`-only, and no other method name
is allowed in a collection initializer. In addition, some types, like ImmutableArrays, would be
forced to implement init-only collection initializers very inefficiently, by declaring a new array
and copying each item every time `Add` is called.
**Conclusion**
We're still very interested in the feature, but we need to determine how we can add it in a way
that provides a path forward for our existing collections.
### Equality dispatch
We have an equality implementation that we think is functional, but we're not sure it's the most
efficient implementation. Consider the following chain of types:
```C#
class R1
{
public override bool Equals(object other)
=> Equals(other as R1);
public virtual bool Equals(R1 other)
=> !(other is null) &&
this.EqualityContract == other.EqualityContract
/* && compare fields */;
}
class R2 : R1
{
public override bool Equals(object other)
=> Equals(other as R2);
public override bool Equals(R1 other)
=> Equals(other as R2);
public virtual bool Equals(R2 other)
=> base.Equals((R1)other)
/* && compare fields */;
}
class R3 : R2
{
public override bool Equals(object other)
=> Equals(other as R3);
public override bool Equals(R1 other)
=> Equals(other as R3);
public override bool Equals(R2 other)
=> Equals(other as R3);
public virtual bool Equals(R2 other)
=> base.Equals((R1)other)
/* && compare fields */;
}
```
The benefit of the above strategy is that each virtual call goes directly
to the appropriate implementation method for the runtime type. The drawback
is that we're effectively generating a quadratic number of methods and overrides
based on the number of derived records.
One alternative is that we could not override the Equals methods of anything
except our `base`. This would cause more virtual calls to reach the implementation,
but reduce the number of overrides.
**Conclusion**
We need to do a deep dive on this issue and explore all the scenarios. We'll come
back once we've outlined all the options and come up with a recommendation.
### Affirming some previous decisions
Proposals for copy constructors
- Do not include initializers (including for user-written copy constructors)
- Require delegation to a base copy constructor or `object` constructor
- If the implementation is synthesized, this behavior is synthesized
Proposal for Deconstruct:
- Doesn't delegate to a base Deconstruct method
- Synthesized body is equivalent to a sequence of assignments of member
accesses. If any of these assignments would be an error, an error is produced.
It's also proposed that any members which are either dispatched to in a derived record
or expected to be overridden in a derived record will produce an error for synthesized
implementations if the required base member is not found. This includes if the base
member was not present in the immediate base, but was inherited instead. For some situations
this may mean that the user can write a substituted implementation for that synthesized
member, but for the copy constructor this effectively forbids record inheritance, since
the valid base member must be present even in a user-defined implementation.
**Conclusion**
All of the above decisions are upheld.
### Non-generic IEnumerable
Currently in the framework `IEnumerable.Current` (the non-generic interface) is annotated to
return `object?`. This produces a lot of warnings in legacy code that `foreach` over the result
with types like `string`, which is non-nullable. We have two proposals to resolve this:
- Un-annotate `IEnumerable.Current`. This will keep the member nullable-oblivious and no warnings
will be generated, even if the property is called directly
- Special-case the compiler behavior for `foreach` on `IEnumerable` to suppress nullable warnings
when calling `IEnumerable.Current`
**Conclusion**
Overall, we prefer un-annotation. Since this interface is essentially legacy, we feel that
providing nullable analysis is potentially harmful and rarely beneficial.

View file

@ -0,0 +1,122 @@
# C# Language Design Meeting for June 17, 2020
## Agenda
1. Null-suppression & null-conditional operator
1. `parameter!` syntax
1. `T??`
## Discussion
### Null-suppression & null-conditional operator
Issue #3393
We generally agree that this is uninintended and unfortunate, essentially a spec bug. The
only question is whether to allow `!` at the end of a `?.`, as well as in the "middle". In
some sense
### `parameter!` syntax
This has been delayed because we haven't been able to agree on the syntax. The main contenders
are
```C#
void M(string param!)
void M(string param!!)
void M(string! param)
void M(string !param)
void M(checked string param)
void M(string param ?? throw)
void M(string param is not null)
void M(notnull string param)
void M(null checked string param)
void M(bikeshed string param)
void M([NullChecked("Helper")] string param)
/* contract precondition forms */
void M(string param) Requires.NotNull(param)
void M(string param) when param is not null
```
The simplest form, `void M(string param!)` is attractive, but looks very similar to the null
suppression operator. The biggest problem is that you can see them as having very different
meanings -- `!` in an expression silences nullable warnings, while `!` on a parameter does the
opposite, it actually produces an exception on nulls. However, the result of both forms is a
value which is treated by the compiler as not-null, so there is a way of seeing them as similar.
Moving it to the other side of the parameter name, `!param`, would resolve some of the similarity
with the null suppression operator, but it also looks a lot like the `not` prefix operator. There's
slightly less contradiction in these operators, but it still features a bit of syntactic overloading.
`string!` has a couple problems, including a suggestion that it's a part of the type (which it would not
be), and that sometimes you may want to use the operator on nullable types, like `AssertNotNull` methods.
It also wouldn't be usable in simple lambdas without types.
`checked` suggests integer over/underflow more than nullability.
`param!!` has some usefulness that we could provide a corresponding expression form -- `!`
suppresses null warnings, while `!!` actually checks for null and throws if it is found. On the
other hand, it also reads a bit strangely, especially since we're adding a new syntax form
instead of trying to reuse some forms we already have. On the other hand, the fact that it's
different enough to look different, while also short enough to be used commonly has a lot in
favor of it. In general we historically have a bias towards making new things strongly
distinguished from existing code, but shortly after introducing the feature we tend to wish that
things were less verbose and didn't draw as much attention in the code. On the other hand, the
nullable feature has a rule that it should not affect code semantics, while the purpose of this
feature is to affect code semantics. `param!!` could be seen as being too similar to other things
in the nullable feature, but to some people it also stands out because of the multiple operators.
We did a brief ranked choice vote and came up with the following ranking, not as definitive, just to
measure our current preferences:
1. `void M(string param!!)`
2. `void M(nullcheck string param)`
3. `void M([NullChecked(Helper)] string param)`
Many people don't have strong opinions, so we don't have a clear winner coming out.
**Conclusion**
We're getting closer to consensus, but we need to discuss this more and consider some of the
long-term consequences, as well as impact on other pieces of the language design.
### `T??`
Unfortunately there are multiple parsing ambiguities with `T??`:
```C#
(X??, Y?? y) t;
using (T?? t = u) { }
F((T?? t) => t);
```
This has left us looking back to the original syntax: `T?`. The original reason we rejected this
was that there could be confusion that `T?` means "maybe default," so that the type is nullable
if it's a reference type, but not nullable if it's a value type.
If we want to allow the `T?` syntax anyway, we need some syntax to specify that, for overrides,
we want the method with no constraints (unconstrained). This is because constraints cannot
generally be specified in overrides or explicit implementations, so previously `T?` always meant
`Nullable<T>`, but now it may not. We added the `class` constraint for nullable reference types,
but neither `T : class` nor `T : struct` help if the `T` is unconstrained. In essence, we need a
constraint that means unconstrained. Some options include:
```C#
override void M1<[Unconstrained]T,U>(T? x) // a
override void M1<T,U>(T? x) where T: object? // b
override void M1<T,U>(T? x) where T: unconstrained // c
override void M1<T,U>(T? x) where T: // d
override void M1<T,U>(T? x) where T: ? // e
override void M1<T,U>(T? x) where T: null // f
override void M1<T,U>(T? x) where T: class|struct // g
override void M1<T,U>(T? x) where T: class or struct // h
override void M1<T,U>(T? x) where T: cluct // joke
override void M1<T,U>(T? x) where T: default // i
```
**Conclusion**
The `default` constraint seems most reasonable. It would only be allowed in overrides and
explicit interface implementations, purely for the purpose of differentiating which method
is being overridden or implemented. Let's see if there are other problems.

View file

@ -0,0 +1,104 @@
# C# Language Design Meeting for June 22, 2020
## Agenda
1. Data properties
1. Clarifying what's supported in records for C# 9
- Structs
- Inheritance with records and classes
## Discussion
### `data` properties
We've been working on an implementation for data properties and have some questions about
modifiers, which are currently not allowed.
There are some modifiers that could be legal, like `new`, `abstract`, `virtual`, and `override`.
Some of these, especially `new` and `override` would probably prevent `data` properties from
being used at all, since a warning would be generated if there's a matching member in the base
that requires either `override` or `new`.
However, the point of data properties was to be brief. Adding modifiers would potentially cloud
the purpose of the feature. The syntactical abbreviation isn't strictly required because the
equivalent property can always be written explicitly:
```C#
data int X;
// versus
public int X { get; init; }
```
**Conclusion**
Based on where we are in the schedule for C# 9, we probably will not have time to respond to feedback.
Therefore, we're planning on putting this feature into preview and not shipping it with C# 9. For now,
let's allow the following modifiers: `public`, `new`, `abstract`, `virtual`, and `override`. This will
provide an option for allowing `data` properties to interact more smoothly with other constructs in C#,
while maintaining some of the simplicity. We'll see how it feels in prototypes to gauge whether we went
too far, or not far enough.
### Struct records
We're not sure how much space we have for structs in C# 9, but we do think structs are an
interesting design point. We previously proposed that structs could support a variety of record
behaviors without being a record. One idea would be to automatically implement `IEquatable<T>`
for all structs, but this has a lot of potential negative impact for the runtime and the
ecosystem: effectively every struct would add a large number of members which could seriously
bloat metadata.
An alternative would be to work with the runtime to try to provide a runtime-generated form of
`IEquatable<T>`. If it's cheap enough, we may be able to provide `IEquatable<T>` for structs as
a as-necessary addition to all structs. However, this is a potentially very large change. Even
small costs could add up, and even small semantic changes could impact someone.
Overall, the modification of arbitrary struct semantics just seems too risky. Something as simple
as testing a struct for an implementation of `IEquatable<T>` could be a breaking change, and with
a change this big, it's almost certain to be breaking for someone.
**Conclusion**
Altering the semantics of all structs as-is is out. We're leaning towards a real "record struct"
declaration.
### Inheritance between records and classes
We currently have a restriction that records cannot inherit from classes and classes cannot
inherit from records. We should confirm that this restriction is acceptable for C# 9.
**Conclusion**
We definitely see scenarios for expanding this, but we think the restriction is fine for the
first version of records. Based on feedback and example scenarios, we can reconsider these
restrictions and also the expected semantics.
### `with` expressions on non-records
This encompasses:
1. Finding some way to define a compatible `Clone` for user-defined classes
1. Anonymous types
1. Tuples
Compatibility for `Clone` in user-defined classes is the most difficult of these items because it
relies on a new language feature for requiring that a new object is returned from the Clone
method.
Anonymous types are very simple, we can retroactively define them as record types.
Tuples would be simple to special-case in the language, but it's probably more consistent to
decide the semantics for struct records first, and then update the definition of
System.ValueTuple to support them.
**Conclusion**
Anonymous types can be updated at any time, everything else should wait until after C# 9.

View file

@ -0,0 +1,188 @@
# C# Language Design Meeting for June 24th, 2020
## Agenda
1. [Confirming Function Pointer Decisions](#Confirming-Function-Pointer-Decisions)
1. [Parameter Null Checking](#Parameter-Null-Checking)
1. [Interface `static` Member Variance](#Interface-`static`-Member-Variance)
1. [Property Enhancements](#Property-Enhancements)
## Quote of the Day
"It feels a little bit like we're playing code golf here"
## Discussion
### Confirming Function Pointer Decisions
https://github.com/dotnet/roslyn/issues/39865#issuecomment-647692516
There are a few open questions from a previous [LDM](LDM-2020-04-01.md) and a followup email chain
that need to be confirmed before they can be implemented. These questions center around calling
convention type lookup and how identifiers need to be written in source. The grammar we had roughly
proposed after the previous meeting is:
```antlr
func_ptr_calling_convention
: 'managed'
| 'unmanaged' ('[' func_ptr_callkind ']')?
func_ptr_callkind
: 'CallConvCdecl'
| 'CallConvStdcall'
| 'CallConvThiscall'
| 'CallConvFastcall'
| identifier (',' identifier)*
```
##### Calling Convention Lookup
When attempting to bind the `identifier` used in an unmanaged calling convention, should this follow
standard lookup rules, such that the type must be in scope at the current location, or is using a
form of special lookup that disregards the types in scope at the current location? The types valid
in this location are a very specific set: they must come from the `System.Runtime.CompilerServices`
namespace, and the types must have been defined in the same assembly that defines `System.Object`,
regardless of the binding strategy used here, so it's really a question of whether the user has to
include this namespace in their current scope, adding a bunch of types that they are generally not
advised to use directly, and whether they can get an error because they defined their own calling
convention.
##### Conclusion
Given the specificness required here, we will use special name lookup.
##### Required identifiers
The previous LDM did not specify the required syntax for the identifiers quite explicitly enough for
implementation, and specified that identifiers should be lowercase while also having upper case
identifiers in some later examples. The following rules are proposed as the steps the compiler will
take to match the identifier to a type:
1. Prepend `CallConv` onto the identifier. No casemapping is performed.
2. Perform special name lookup with that typename in the `System.Runtime.CompilerServices` namespace
only considering types that are defined in the core library of the program (the library that defines
`System.Object` and has no dependencies itself).
We also reconsidered the decision from the previous LDM on using lowercase mapping for the identifier
names. There is convention for this in other languages: C/C++, for example, use `__cdecl` or similar
as their calling convention specifiers, and given that this feature will be used for native interop
with libraries doing this it would be nice to have some parity. However, this would introduce several
issues with name lookup: existing special name lookup allows us to modify the `identifier` specified
in source, but it does not allow us to modify the names of the types we're matching against, which
we would need to do here. There is certainly an algorithm that could be specified here, but we overall
felt that this was too complicated for what was a split aesthetic preference among members.
##### Conclusion
The proposed rules are accepted. As a consquence, the identifier specified in source cannot start
with `CallConv` in the name, unless the runtime were to add a type like `CallConvCallConv`.
### Parameter Null Checking
We ended the [previous meeting](LDM-2020-06-17.md) on this with two broad camps: support for the `!!`
syntax, and support for some kind of keyword. Email discussion over the remainder of the week and
polling showed that a clear majority supported the `!!` syntax.
#### Conclusion
We will be moving forward with `!!` as the syntax for parameter null checking:
```cs
public void M(Chitty chitty!!)
```
### Interface `static` Member Variance
https://github.com/dotnet/csharplang/issues/3275
We considered variance in `static` interface members. Today, for co/contravariant type parameters
used in these members, they must follow the full standard rules of variance, leading to some
inconsistency with the way that `static` fields are treated vs `static` properties or methods:
```cs
public interface I<out T>
{
static Task<T> F = Task.FromResult(default(T)); // No problem
static Task<T> P => Task.FromResult(default(T)); //CS1961
static Task<T> M() => Task.FromResult(default(T)); //CS1961
static event EventHandler<T> E; // CS1961
}
```
Because these members are `static` and non-virtual, there aren't any safety issues here: you can't
derive a looser/more restricted member in some fashion by subtyping the interface and overriding
the member. We also considered whether this could potentially interfere with some of the other
enhancements we hope to make regarding roles, type classes, and extensions. These should all be
fine: we won't be able to retcon the existing static members to be virtual-by-default for interfaces,
as that would end up being a breaking change on multiple levels, even without changing the variance
behavior here.
We also considered whether this change could be considered a bug fix on top of C# 8, meaning that
users would not have to opt into C# 9 in order to see this behavior. While the change is small and
likely very rarely needed, we would still prefer to avoid breaking downlevel compilers.
#### Conclusion
We will allow `static`, non-virtual members in interfaces to treat type parameters as invariant,
regardless of their declared variance, and will ship this change in C# 9.
### Property Enhancements
In a [previous LDM](#LDM-2020-04-01.md) we started to look at various enhancements we could make
to properties in response to customer feedback. Broadly, we feel that these can be addressed by
one or more of the following ideas:
1. Introduce a `field` contextual keyword that allows the user to refer to the backing storage of
the property in the getter/setter of that property.
* In this proposal, we can consider all properties today as having this `field` keyword. As
an optimization, if the user does not refer to the backing field in the property body, we
elide emitting of the field, which happens to be the behavior of all full properties today.
* Of the proposals, this allows the most brevity for simple scenarios, allowing some lazily-fetched
properties to be one-liners.
* This proposal does not move the cliff far: if you need to have a type differing from the
type of the property, or multiple fields in a single property, then you must fall back to a full
property and expose the backing field to the entire class.
* There are also questions about the nullability of these backing properties: must they be
initialized? Or should we provide a way to declare them as nullable, despite the property
itself not being nullable?
* There was also concern that this is adding conceptual overhead for not enough gain: education
would be needed on when backing fields are elided and when they are not, complicated by the
additional backcompat overhead of ensuring that `field` isn't treated as a keyword when it
can bind to an existing name.
2. Allow field declarations in properties.
* Conveniently for this proposal, a scoping set of braces for properties already exists.
* This addresses the issue of properties backed by a different storage type: if you have a
property that uses a `Lazy<T>` to initialize itself on first access, for example.
* This also allows users to declare multiple backing fields, if they want to lock access
to the property or combine multiple pieces of information into a single type in the public
surface area.
* In terms of user education, this is the simplest proposal. Since a set of braces already
exists, the education is just "There's a new scope you can put fields in."
3. Introduce a delegated property pattern into the language.
* There have been a few proposals for this, such as #2657. Other languages have also adopted
this type of feature, including Kotlin and Swift.
* This is by far the most complex of the proposals, adding new patterns to the language and
requiring declaration of a whole new type in order to remove one or possibly 2 fields from
a general class scope.
* By that same token, however, this is the most broad of the proposals, allowing users to
write reusable property implementations that could be abstracted out.
The LDM broadly viewed these proposals as increasing in scope: the `field` keyword allows the most
brief syntax, but forces users off the cliff back to full class-scoped fields immediately if their
use case is not having a single backing field of the same type. Meanwhile, property-scoped fields
don't allow for and encourage creating reusable helpers, like delegated properties would.
We also recognize that regardless of what decisions we make today, we're not done in this space.
None of these proposals are mutually exclusive, and we can "turn the crank" by introducing one, and
then adding more in a future release. There is interest among multiple LDM members in adding some
form of reusable delegated properties or property wrappers, and adding one of either the `field`
keyword or property-scoped fields does not preclude adding the other in a later release. Further,
all of these proposals are early enough that we still have a bunch of design space to work through
with them, while designing ahead enough to ensure that we don't add a wart on the language that we
will regret in the future.
#### Conclusion
A majority of the LDM members would like to start by exploring the property-scoped locals space.
We'll start by expanding that proposal with intent to include in C# 10, but will keep the other
proposals in mind as we do so.

View file

@ -0,0 +1,80 @@
# C# Language Design Meeting for June 29th, 2020
## Agenda
1. [Static interface members](https://github.com/Partydonk/partydonk/issues/1)
## Procedural Note
For the past few years, the LDM notes have been compiled by the wonderful Andy Gocke (@agocke).
Andy is taking the next step in his career and moving to be the lead of the CLR App Model team
as of today, and as such will be moving to LDT emeritus status, joining the ranks of our other
former LDT members who form our advisory council. We thank him for all his hard work during his
time as notetaker, collating the sometimes inane rambling of the LDM in a set of readable
arguments and decisions.
At this point Fred Silberberg (@333fred) will be the new LDM notetaker. While I'll try to keep
up much of the same spirit as Andy, I am not going to try to match his exact style or formatting,
so there could be some changes in the exact formatting of the notes. I'll additionally apologize
in advance as the notes inevitably end up delayed in the first few weeks as I settle in. And now,
on to the meeting notes!
## Quote of the Day
"So we spent these last 10 years making it so we can come back to this. We actually never forgot,
[.NET Core] has all been a ploy to get statics into interfaces."
## Discussion
Today @abock and @migueldeicaza presented their work on Partydonk over the past year, bringing
abstract interface members to C# and the Mono runtime in a proof of concept. I did not take notes
on the specific slides: all of that material is available publicly on the partydonk repo
[here](https://github.com/Partydonk/partydonk/blob/master/Generic%20Math/Generic%20Math%20in%20.NET%20-%20Contractual%20Static%20Interface%20Members%20in%20CSharp.pdf).
Overall, the LDT members had a very positive reception to this work: in particular, they arrived
at many of the same conclusions @CarolEidt had in her exploration of this space 10 years ago:
much of the runtime work falls out from allowing `abstract static` in CIL and emitting constrained
calls to such members during compilation. From a language perspective, there's still a bit of work
to do. `override` on `abstract` static members defined in interfaces isn't particularly nice from
a regularity with instance members perspective. We will also have to do design work around explicit
implementations: it could all fall out from existing rules, but will need a critical eye to make
sure that the consequences of explicitly implementing an abstract member, and what that really means.
The existing code uses a `TSelf` generic parameter in what could be considered kind of an unfortunate
syntax:
```cs
interface INumeric<TSelf> where TSelf : INumeric<TSelf>
{
abstract static TSelf Zero { get; }
abstract static TSelf operator +(TSelf a, TSelf b);
}
```
The `TSelf : where TSelf : INumeric<TSelf>` was suggested in the past to help the prototype make
progress without blocking on associated types, but it's ugly and proliferates through the entire
type hierarchy if left unchecked. A much better solution would be to formally introduce associated
types into the language, something that we've discussed in LDM before and has some support. We should
take those into account here: if we introduce this entire type hierarchy, then in the next C# release
introduce a `TSelf` associated type it would leave an annoying blemish on the language. In particular,
we need to make sure we have a good roadmap for all components involved here: the compiler, the runtime,
and the core libraries. Nonvirtual static members in interfaces have already shipped with C# 8, so we
can't get that back and declared them virtual members of the interface.
We do still have a few language questions: today, you cannot create user-defined operators that involve
interfaces, because doing so would subvert the type system. However, some numeric applications seem
like they would want to be able to do this for constants (see `IExpressibleByIntegerLiteral` and
`IExpressibleByFloatLiteral` in the presentation). If we allow this for the `TSelf` parameter, it seems
like these concerns should be obviated: you're not converting to an interface type, you're converting to
a concrete type and specifying that said conversion must be available for any implementations of the
interface. Additionally there's an interesting correspondance issue: today, any members that are part
of the interface contract are available on an instance of the interface. However, with static methods,
the interface itself doesn't provide them: types that implement the interface provide them, but not the
interface itself. We can certainly come up with new rules to cover this, but we will need to do so.
Some other miscellaneous topics that came up:
* We could use this system to specify constructors with multiple parameters of a specific type. Static
interface members could be implemented by a type calling `new`, which would allow us to improve on the
simple `new()` that we have today.
* Existing language built-in operators would need to be considered to satisfy the constraints of the
numeric interfaces.

View file

@ -0,0 +1,129 @@
# C# Language Design Meeting for July 1st, 2020
## Agenda
1. [Non-defaultable struct types and parameterless struct constructors](#Non-defaultable-struct-types-and-parameterless-struct-constructors)
2. [Confirming unspeakable `Clone` method implications](#Confirming-unspeakable-Clone-method-implications)
## Quote of the Day
"I did not say implications, I said machinations [pronounced as in British English]. I used a big word."
"You mispronounced machinations [pronounced as in American English], which is why I'm just ignoring you."
## Discussion
### Non-defaultable struct types and parameterless struct constructors
Proposal: https://github.com/dotnet/csharplang/issues/99#issuecomment-601792573
#### Parameterless struct constructors
We discussed both proposals for allowing default struct constructors and for having a feature to allow differentiating between
`struct` types that have a valid `default` value, and types that do not.
First, we looked at parameterless constructors. Today, `struct`s cannot define their own custom parameterless constructors, and
a previous attempt to ship this feature in C# 6 failed due to a framework bug that we could not fix.
```cs
public struct S
{
public readonly int Field = 1; // Field is set by the default constructor
}
public void M<T>()
{
var s = (S)Activator.CreateInstance(typeof(T));
Console.WriteLine(s.Field);
}
```
In .NET Framework and .NET Core prior to 2.0, a call to `M` will print `0`. However, .NET Core fixed this API in 2.0 to correctly
call the parameterless constructor of a struct if one is present, and since we now tie language version to the target platform
there will be no supported scenario with this bug.
While there was general support for this scenario in the LDM, we spent most of the time on the second part of the proposal and
did not come away with a conclusion for parameterless constructors. We will need to revisit this in context of a reworked defaultable
types proposal and make a yes/no conclusion on this feature.
#### Non-defaultable struct types
The crux of this proposal is that we would extend the tracking we introduced in C# 8 with nullable reference types, and extend it
to value types that opt-in, holes and all. From a type theory perspective, the idea is that by applying a specific attribute, a
struct type can indicate that `default` and `new()` are _not_ the same value in the domain of its type. In fact, if the struct does
not provide a parameterless constructor, `new()` wouldn't be in the domain of the struct at all. This attribute would further opt the
struct's `default` value into participating in "invalid" scenarios in the same way that `null` is part of the domain of a reference
type, but is considered invalid for accessing members directly on that instance. This played well with our previous design of `T??`,
if we were to allow the `??` moniker on types constrained to `struct` as well as unconstrained type parameters. However, as `??`
has been removed from C# 9 due to syntactic ambiguities (notes [here](LDM-2020-06-17.md#T??)), that part of the proposal will have
to be reworked. Not having `??` makes the feature much harder to explain to users, and we'll run into issues with representation in
non-generic scenarios.
One thing that is clear from discussion is that non-defaultable struct types will need to have some standardized form of checking
whether they are the default instance. `ImmutableArray<T>`, for example, has an `IsDefault` property, as do most of the existing
struct types in Roslyn that cannot be used when `default`. We would want to be able to recognize this pattern in nullable analysis,
just like we do today with the `is null` pattern. Since the attribute and pattern would be new, we could declare it to be whatever
we desire, and the libraries will standardize around that if they want to participate.
Generics also present an interesting challenge for non-defaultable value types. Today, the `struct` constraint implies new:
```cs
public void M<T>() where T : struct
{
var y = new T(); // Perfectly valid
}
```
If we were to enable non-defaultable struct types, this would change: `new()` is not necessarily valid on all struct types because
non-defaultable struct types have explicitly opted to separate `default` and `new()` in their domain, and might not have provided
a value for `new()`, meaning that it would return `default`. From an emit perspective, this is further complicated: for the above
code, the C# compiler _already_ emits a `new()` constraint. C# code cannot actually specify both the `struct` constraint and the
`new()` constraint at the same time today, but in order to actually emit the combination of these constraints for this feature
we would have to introduce a new annotation on the type parameter to describe that it is required to have a parameterless `new()`
that provides a valid instance of the type.
`ref` fields in structs also came up in discussion. This is a feature that we've been asked for by the runtime team and a few other
performance-focussed areas, but is very hard to represent in C# because it would require a hard guarantee that a struct with a
`ref` field is truly never defaulted, by anything. `ref`s do not have a "default", so a struct that contained on in a field would
need to not be possible to default in any fashion. This proposal could overlap with that feature: the guarantees provided here are
no stronger than the guarantees given with nullable reference types, which is to say easy to break: arrays of these structs would
still be filled with `default` on creation, for example, even if the type wasn't annotated with a `??` or hypothetical other sigil.
We need to be sure that, if that's the case and we do want to add `ref` fields, we're comfortable having both a "soft" and "hard"
defaultness guarantee in the language.
Finally, there was some recognition and discussion around how this issue is very similar to another long standing request from
libraries like Unity: custom nullability. The idea is that with C#, among the entire value domain of a type we recognize and have
built language support for one _particular_ invalid value: `null`. However, this isn't the only invalid value that a value domain
may have. Unity objects have backing C++ instances, and they override the `==` operator to allow comparison with `null` to also
return true if the backing field has not yet been instantiated. While the C# object itself is not `null` in this case, it _is_
invalid, and should be treated as such. However, this doesn't play well with other operators in C#, such as `?.`, `??`, and
`is null`. These all special-case a particular invalid value, `null`, and don't play well with other invalid values, leading
libraries like Unity to encourage users to write code that does not take advantage of modern idiomatic C# features. This issue is
very similar to the non-defaultable structs issue: we'd like to recognize a particular value in the domain of a struct type as
invalid. It might be better to implement this as a general invalid value pattern that any type, struct or class, can opt into.
#### Conclusion
For both of these issues, we need to take more time and rethink them again, especially in light of the removal of `??`, which
the non-defaultable struct type proposal relied on heavily. A small group will explore the space more, particularly the more
general invalid object pattern, and come back with a rethought proposal. The guiding principle that this group should keep in
mind from the current proposal is "Users should be able to change something from a class to a struct for performance without
significant redesign due to having to handle an invalid `default` struct value."
### Confirming unspeakable `Clone` method implications
Before we ship unspeakable `Clone` methods for `with` expressions, we wanted to make sure that we've worked through the
consequences of doing so, and are sure that the language will be able to continue to evolve without breaking scenarios that
we are enabling with this feature. In particular, in the face of a general factory pattern that users can use to extend record
types, or even potentially expand what is today a record type into a full blown type without breaking their customers, we
might need to emit both the unspeakable `Clone` method and a factory method in the future. A guiding principle for record design
has been that whether something is a record is an implementation detail. Therefore whatever future method we add that will allow
a regular class type to participate in a `with` expression will likely have to emit this method as well.
We also considered whether we should take any measures right now to try and keep our design space open in records for adding a
user-overridable `Clone` method. We could try emitting the method now, and modreq it so that it cannot be directly called from
C# code, or we could just block users from creating a `Clone` method in a record entirely.
#### Conclusion
We're fine with the unspeakable name being a feature of records forever going forward. We will also reserve `Clone` as a member
name in records to ensure that our future selves will be able to design in this space.

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

View file

@ -0,0 +1,213 @@
# C# Language Design Meeting for July 13th, 2020
## Agenda
1. [Generics and generic type parameters in aliases](#Generics-and-generic-type-parameters-in-aliases)
2. ["closed" enum types](#"closed"-enum-types)
3. [Allow `ref` assignment for switch expressions](#Allow-`ref`-assignment-for-switch-expressions)
4. [Null suppressions nested under propagation operators](#Null-suppressions-nested-under-propagation-operators)
5. [Relax rules for trailing whitespaces in format specifier](#Relax-rules-for-trailing-whitespaces-in-format-specifier)
6. [Private field consideration in structs during definite assignment analysis](#Private-field-consideration-in-structs-during-definite-assignment-analysis)
7. [List patterns](#list-patterns)
8. [Property-scoped fields and the `field` keyword](#Property-scoped-fields-and-the-field-keyword)
9. [File-scoped namespaces](#file-scoped-namespaces)
10. [Allowing `ref`/`out` on lambda parameters without explicit type](#Allowing-ref/out-on-lambda-parameters-without-explicit-type)
11. [Using declarations with a discard](#Using-declarations-with-a-discard)
12. [Allow null-conditional operator on the left hand side of an assignment](#Allow-null-conditional-operator-on-the-left-hand-side-of-an-assignment)
12. [Top level statements and functions](#Top-level-statements-and-functions)
13. [Implicit usings](#implicit-usings)
## Quote of the day
"It does actually seem like this pattern is the 98% case..."
"I just want to disagree with something [redacted] said... [they] said [they] thought it was the 98% case that this would apply to, and I think it's 99..."
"Not fair, I was going to say that."
## Discussion
This meeting was issue triage. There will not be much detail on any particular issue, just a general summary
of the LDM's feeling and the milestone that we triaged to.
### Generics and generic type parameters in aliases
https://github.com/dotnet/csharplang/issues/1239
In general, we want to make improvements in this area. We should also be open to making other enhancements
in this space, such as allowing tuple syntax on the right side, or allowing C# keywords like `int`. There's
also a set of features that we should investigate in parallel, such as globally-visible aliases or publicly-
exported aliases.
#### Conclusion
Triaged for C# 10 for now so that we can look at the space hollistically in the near term.
### "closed" enum types
https://github.com/dotnet/csharplang/issues/3179
This is a solution to the very common complaints around enum usage, particularly in switch expressions and other
exhaustiveness scenarios. It will also work well with DUs, and we should make sure that whatever syntax we use
there works well with closed or sealed enum types as well.
#### Conclusion
Triaged for C# 10 to look at in coordination with DUs.
### Allow `ref` assignment for switch expressions
https://github.com/dotnet/csharplang/issues/3326
We like this proposal. You can already do this with ternaries, and it's odd that you can't do this with switch
expressions as well. It's not high priority, but we'd be happy to see it in the language. Like ternaries, the
ref version would not be target-typed.
#### Conclusion
Triaged for Any Time.
### Null suppressions nested under propagation operators
https://github.com/dotnet/csharplang/issues/3393
This will be a breaking change, so we need to get it in as soon as possible.
#### Conclusion
C# 9 timeframe. We need to make a syntax proposal and approve it.
### Relax rules for trailing whitespaces in format specifier
https://github.com/dotnet/csharplang/issues/3414
In reading this proposal, we're unsure whether the request was for _ignoring_ trailing spaces in format specifiers,
or allowing them and including them in the format specifier. We think that either way this is interpreted, it will
be confusing: trailing spaces are allowed in front of an interpolated expression and mean nothing, but for things
like `DateTime`, spaces are valid parts of a format specifier and will be respected in the output. We think that
either behavior here would be confusing, with no clear indication on which the user wants.
#### Conclusion
Rejected.
### Private field consideration in structs during definite assignment analysis
https://github.com/dotnet/csharplang/issues/3431
This is a bug from the native compiler that had to be reimplemented in Roslyn for compat, but it's always been
one of the prime candidates for a warning wave (and is already supported as an error in the compiler via the strict
feature flag). There is some contention whether it should be a warning or an error in this wave. There is also a
concern that this will combine with the `SkipLocalsInit` feature in C# 9 to expose an uninitialized memory hole in
C# with no use of `unsafe` or `System.Unsafe` required.
#### Conclusion
We need to look at this ASAP to make sure that we don't unintentionally expose unsafety in the language without
user intention. We'll schedule this for next week.
### Remove restriction that optional parameters must be trailing
https://github.com/dotnet/csharplang/issues/3434
It's possible to define such methods in metadata with the correct attribute usage _and_ call them from C# today.
This would just be about removing the restriction from _defining_ them in C#.
#### Conclusion
Triaged for Any Time.
### List patterns
https://github.com/dotnet/csharplang/issues/3435
We have an open proposal that with a prototype. We like the general direction it takes, but we need to have more
detailed design review of it and possibly make a few different decisions. This is a direction we want to take
pattern matching in future releases, so we'll continue iterating on this.
#### Conclusion
Triaged into C# 10 for design work.
### Property-scoped fields and the `field` keyword
* https://github.com/dotnet/csharplang/issues/133
* https://github.com/dotnet/csharplang/issues/140
We've started doing design work around both of these issues. We should continue doing that.
#### Conclusion
Triaged into C# 10.
### File-scoped namespaces
https://github.com/dotnet/csharplang/issues/137
This has been a large request for a long time that reflects the default of almost every single C# file written.
There's still some design work to do, particularly in how that will affect `using` statements, but it's work
that we should take on.
#### Conclusion
Triaged into C# 10.
### Allowing `ref`/`out` on lambda parameters without explicit type
https://github.com/dotnet/csharplang/issues/338
We've heard this request a few times, and while we don't see any particular issue with this, it's not a priority
for the team at this point. If a spec/implementation was provided we'd likely accept it but won't go out of our
way to add it unless something else changes here.
#### Conclusion
Triaged to Any Time.
### Using declarations with a discard
https://github.com/dotnet/csharplang/issues/2235
There's still some open design questions here, particularly around possibly ambiguous syntaxes. We need to keep
iterating on this to find a design that we like.
#### Conclusion
Triaged for X.X, pending a new proposal.
### Allow null-conditional operator on the left hand side of an assignment
https://github.com/dotnet/csharplang/issues/2883
Initial discussion shows a big LDT split on whether `?.` should be able to effectively a conditional ref. We
would need to discuss further, but aren't ready to outright approve or reject the feature.
#### Conclusion
Triage to X.X for future discussion.
### Top level statements and functions
https://github.com/dotnet/csharplang/issues/3117
This is part 2 of the work we started in C# 9 with top-level statements: designing free-floating functions that
can sit on the top level without any containing type. We need to continue examining this context of scripting
unification, which we plan to continue doing on an ongoing basis.
#### Conclusion
Triage into C# 10 for ongoing discussion.
### Implicit usings
https://github.com/dotnet/csharplang/issues/3428
This is another issue arising of discussions on top-level statements and using C# as a scripting language:
attempting to make the language more brief by specifying common imports on the command line or as part of
the project file is certainly one way to remove boilerplate. However, it's a controversial feature that often
draws visceral reactions. We need to discuss this more and figure out if it's a feature we want to have in C#,
taking into account our increased focus on scripting-like scenarios. It's worth noting that CSX has a limited
form of this support already, and implementing this in C# proper would bring us one step closer to unifying the
two dialects.
#### Conclusion
Triage to C# 10 for discussion.

View file

@ -0,0 +1,113 @@
# C# Language Design Meeting for July 20th, 2020
## Agenda
1. [Finishing Triage](#finishing-triage)
a. [Extend with expression to anonymous type](#Extend-with-expression-to-anonymous-type)
b. [Required properties](#Required-properties)
c. [Shebang support](#shebang-support)
2. [Private reference fields in structs with `SkipLocalsInit`](#Private-reference-fields-in-structs-with-`SkipLocalsInit`)
## Quote of the Day
"If you go get a beer from the fridge or wherever you keep them and drink it right now, I'll refund you."
## Discussion
### Finishing Triage
#### Extend with expression to anonymous type
https://github.com/dotnet/csharplang/issues/3530
We don't see any reason why we couldn't extend `with` expressions to handle anonymous types, and we universally support
the idea. We do see room for further improvement as well. Struct types should be generally possible to `with`, and in
particular tuples should feel first class here. Some other ideas for future improvements that we'll need to keep in mind
when designing anonymous types is an ability to specify a `withable` constraint: perhaps that's a thing we could do via
typeclasses, but if that's a thing that should be specifiable then we'll want to make sure that whatever we do for structs
and anonymous types works well with it.
##### Conclusion
Triaged into C# 10 for discussion with the other `with` enhancements
#### Required properties
https://github.com/dotnet/csharplang/issues/3630
A smaller group is currently fleshing this proposal out in the direction of initializer debt, and is looking to talk more
about it in the next few months.
##### Conclusion
Triaged for C# 10.
#### Shebang support
https://github.com/dotnet/csharplang/issues/3507
This is part of the next step in the C# scripting discussion. In particular, this proposal details just one, very small
piece of the puzzle here, namely the ability have a C# file startup an environment. There is significantly more work to
be done in the language and tooling to effectively modernize the loose-files support for C#. Today, C# code has a core
concept that cs files themselves do not contain information about the runtime environment. They don't specify the target
runtime, nuget dependencies, where tools can be found, or anything else similar (beyond some `#ifdef` blocks). Supporting
this would be intentionally eroding this aspect, which we need to make sure we're doing with intention and design. There
is support among LDT members for this scenario, so we'll continue to look at.
##### Conclusion
Triaged into C# 10 for discussion. We acknowledge that we may well not ship anything in this space as part of C# 10, but
we want to start discussing possible futures here in the coming X months, not X years.
### Private fields in structs with `SkipLocalsInit`
https://github.com/dotnet/csharplang/issues/3431
Proposal 1: https://github.com/dotnet/roslyn/issues/30194#issuecomment-657858716
Proposal 2: https://github.com/dotnet/roslyn/issues/30194#issuecomment-657900257
This topic was brought up last week when we realized there was a potential hole in `SkipLocalsInit` with definite
assignment, where we realized it's possible to observe uninitialized memory via private fields. When importing metadata,
the native compiler ignored private fields, including private fields in structs, and did not require them to be considered
definitely assigned before usage. This behavior was preserved when we implemented Roslyn, as attempting to break it was
too large of a change for organizations to adopt. Both of these proposals ensure that, with `SkipLocalsInit` on a method,
it's considered an error to not definitely assign here, which was fine with LDM as this is a new feature and cannot break
anyone. We then looked at the differences between the two proposals, namely whether the definite assignment diagnostic
should be a warning or an error when users opt into to a new warning wave. We found the arguments around incremental
adoption compelling: we don't want users to be blocked off from adopting new warning waves and making their code at least
a little safer by issuing errors that cannot be ignored. If users want to ensure that these warnings are fixed in their
code, they can use `warnAsError` to turn these specific warnings or all warnings into errors, as you can today.
#### Conclusion
Proposal 1 has been chosen:
1. If a method has the [SkipLocalsInit] attribute, or the compilation has the "strict" feature enabled, we use the strong
version of analysis for its body. Otherwise
2. If a sufficiently high /warnversion (>= 5) is enabled, we run the strong version of analysis, and
a. If it reports no diagnostics, we are done.
b. If it reports diagnostics, we run the weak version of analysis. Errors that are common to the two runs are reported
as errors, and errors only reported by the strong version are downgraded to a warning.
3. Otherwise we run the weak version of analysis.
### Future record direction
See https://github.com/dotnet/csharplang/issues/3707 for the full list. We briefly went through the list here to gauge
support from LDT members on the various proposals. We didn't get particularly in depth on any one part, but some
highlights:
* `init` fields and methods - We rejected these in 9, deciding to wait for community feedback. We believe this is still
the right decision, and want to hear user scenarios before proceeding further.
* Final initializers - We briefly entertained the idea of having an `init { }` syntax to guarantee that a block is called
after a method. This was later rejected as too complicated after design review. Like `init`, we need to get a better
handle on the user scenarios.
* Required members - We have broad support for doing something in this space.
* Factores - We have broad support for doing something in this space.
* User-defined cloning - Will likely need to be designed hand-in-hand with factories
* Cross-inheritance between records and non-records - part of the initial record goal was that `record` is pure syntactic
sugar. If that's still a goal, then we need to do more work here.
* Generalized primary constructors - Mixed support here. We need to do more design work.
* Primary constructor bodies - Might be done for the former. We need to flesh this out so we can determine how to apply
attributes to record constructors.
* Discriminated unions - We need to determine whether this will be a simple syntactic shorthand for a general sealed type
hierarchy feature, or if this will be the only way to declare such hierarchies.

View file

@ -0,0 +1,186 @@
# C# Language Design Meeting for July 27th, 2020
## Agenda
- [Improved nullable analysis in constructors](#Improved-nullable-analysis-in-constructors)
- [Equality operators in records](#Equality-operators-in-records)
- [`.ToString()` or `GetDebuggerDisplay()` on records](#ToString-or-DebuggerDisplay-on-record-types)
- [W-warnings for `T t = default;`](#W-warnings-for-`T-t-=-default;`)
## Quote of the Day
"We should pick our poison: one is arsenic, and will kill us. The other is a sweet champagne, and will give us a headache tomorrow."
![Delectable Tea or Deadly Poison](delectable_tea_2020_07_27.png)
## Procedural Note
LDM is going on August hiatus as various members will be out. We'll meet next on August 24th, 2020.
## Discussion
### Improved nullable analysis in constructors
https://github.com/dotnet/csharplang/blob/master/proposals/nullable-constructor-analysis.md
This proposal is a tweak to the nullable warnings we emit today in constructors that would bring these warnings more in line with
behavior for `MemberNotNull`, as well as addressing a few surprising cases where you do not get a deserved nullable warning today.
This code, for example, has no warnings today:
```cs
public class C
{
public string Prop { get; set; }
public C() // we get no "uninitialized member" warning, as expected
{
Prop.ToString(); // unexpectedly, there is no "possible null receiver" warning here
Prop = "";
}
}
```
We consider this to be possible to retrofit into the nullable feature, as we're still within the nullable adoption phase. After
C# 9 is released, however, this would be a breaking change, so we will need to either do it now, or do it in a warning wave
(which would heavily complicate the implementation). Additionally, even though we're still within the nullable adoption phase,
this is a relatively big change in warnings that could result in lots of new errors in codebases that have heavily adopted nullable.
We also considered whether there could be any interference here with C# 10 plans around required properties or initialization debt.
There does not appear to be, as this would effectively be the initialization debt world where a constructor is required to set all
properties in the body, and any relaxation of this by requiring properties to be initialized at construction site will play well.
#### Conclusion:
We should implement the change and smoke test it on roslyn, the runtime repo, and on VS. If there is large churn, we'll re-evaluate
at that point.
### Equality operators in records
https://github.com/dotnet/csharplang/issues/3707#issuecomment-661800278
We've talked briefly about equality operators in records prior to now, but we never ended up making any firm decisions, so now we
need to make an intentional decision about records before we ship as doing so after would be a breaking change. The concern is that,
because class types inherit a default equality operator from simply being a class, we'll get into a scenario where a record's `Equals`
method could return `true`, and the `==` operator returns false. Most standard .NET "values" behave in this fashion as well: `string`
being the most common example.
There are some interesting niggles, however, particularly with `float` and `double` values. For example,
this code:
```cs
var a = (float.NaN, double.NaN);
System.Console.WriteLine(a == a); // Prints false
System.Console.WriteLine(a.Equals(a)); // Prints true
```
This happens because the `==` operator and the `Equals` method for floats and doubles behave differently. The `==` operator uses IEEE
equality, which does not consider `NaN` equal to itself, while `Equals` uses the CLR definition of equality, which does. When combined
with `ValueTuple`, this makes for an interesting set of behaviors, as `ValueTuple` doesn't have its own definition of the `==` operator.
Rather, the compiler synthesizes the set of `==` operators on the component elements of the tuple. This means that for generic cases,
such as `public void M<T>((T, T) tuple) { _ = tuple == tuple; }`, you get an error when attempting to use `==` on the tuple, since `==`
is not defined on generic type parameters. `ValueTuple` is a particularly special case here though. The compiler special cases knowledge
of the implementation, which is not generalizable across inheritance hierarchies with record types. In order for an implementation to do
memberwise `==` across all levels of a record type, there will have to be hidden virtual methods to take care of this, and it gets more
complicated when you consider that a derived record type could introduce a generic type parameter field that can't be `==`'d. We feel
that attempting to get too clever here would end up being unexplainable, so if we want to implement the operators, it should just
delegate to the virtual `Equals` methods we already set up.
Next, we considered whether we should implement `==` operators on all levels of a record inheritance hierarchy, or just the top level.
With records as they're shipping in C# 9, we don't believe that there's a scenario you can get into that would break this. However, the
eventual goal is to enable records and classes to inherit from each other, and that point if every level didn't provide its own
implementation it could end up being possible to break assumptions. Further, attempting to trim implementations of `==` and `!=` would
end up resulting in complicated rules that don't feel necessary: adding the operators isn't going to bloat metadata size, will potentially
allow eliminating of some levels of equality method calls, and future proofs ourselves.
Finally, we looked at whether the user will be able to provide their own implementation of `==` and `!=` operators, and if we'd error
on this or allow it and not generate the operators ourselves in this case. We feel that allowing this would complicate records: there
are existing extension points into record equality that can be overridden as needed, and we want to have a stronger concept of `Equals`
and `==` being the same. If there are good user scenarios around allowing this, we can consider it at a later point.
#### Conclusion
We will generate the `==` and `!=` operators on every level of a record hierarchy. These implementations will not be user-overridable,
and they will delegate to `.Equals`. The implementation will have this semantic meaning:
```cs
pubic static bool operator==(R? one, R? other)
=> (object)one == other || (one?.Equals(other) ?? false);
public static bool operator!=(R? one, R? other)
=> !(one == other);
```
### `ToString` or `DebuggerDisplay` on record types
#### Initial proposal
1. `record` generates a ToString that prints out its type name followed by a positional syntax: Point(X: 1, Y: 2).
(issue: disfavors nominal records)
2. `record` generates a ToString that does the above and also appends nominal properties by calling ToStringNominal:
`FirstName: First, LastName: Last`, and assembles the parts into `Person { FirstName: First, LastName: Last, ID: 42 }`.
#### Discussion
The initial proposal here is to add a `ToString` method that would format a record type by their positional properties, and have a
separate method for creating a string from nominal properties named something like `ToStringNominal`. The initial reaction was that
this seemed overly complicated: there should just be one method that does "the right thing<sup>tm</sup>". There's further question
about whether having a `ToString` or `DebuggerDisplay` would be useful: depending on the properties of the record type, it could end
up doing more harm than good (if the properties were lazy, for example). Additionally, when a `ToString` is provided it's often domain
specific, and nothing we do in the compiler would be able to predict what shape that should be. We ended up coming up with a list of
common scenarios in which a `ToString` would be useful:
* Viewing in the debugger. This could be done with just a `DebuggerDisplay` attribute, or users can just expand the object to view the
properties of it as you can today.
* Viewing in test output. Using an equality test, for example, will usually print the objects if they were not equal to each other,
and it would be useful if that was actually meaningful, particularly for these value-like class types.
* Logging output. This is a very similar case to the previous.
We also considered whether we should implement this via source generators. However, it feels very similar to equality: we have a
sensible default there, and anyone who wants to customize (this field should be excluded, this one should use sequence equality)
can either write it manually or use a source generator. The same arguments apply here: we can provide a sensible default that will
enable short syntax, and anyone who wants to get custom behavior can override this.
After considering _whether_ to do this feature, we looked at what properties would be included in such a feature. How, would they
be formatted, and which ones are considered? The initial proposal was for positional only, with a separate method for nominal
properties. We felt that this was too complicated and likely not to be the right defaults: it totally disadvantages nominal records
and makes the implementation more complicated. The options we considered are:
* The same members as .Equals. This means all fields of a class, translating auto-generated backing fields to their properties for
display names. This would make explaining what appears in the `ToString` simple: it's the equality members, full stop.
* The positional members and `data` members of a record. We feel that this is too restrictive, especially since `data` members will
not be shipping in final form with C# 9: they'll still be under the preview language version.
* The fields and properties of a record type with some accessibility, accessibility to be determined next. We believe that it's very
unusual for a `ToString` to display `private` fields, which the other proposal would do.
We leaned towards just doing the fields and properties of a type, with some accessibility. Finally, we looked at what accessibility
to use by default for these:
* All members not marked `private`. This means that things that not relevant to a consumer of the type, such as `protected` fields,
show up in the `ToString`, and violates encapsulation principles.
* All `public` and `internal` members. This propsal has some of the same issues as the previous one: you could making an `internal`
type that implements a `public` interface, and it would be odd if the final user sees that internal state.
* At least as accessible as the record itself. This would mean that if the `record` was `internal`, then internal members would be
shown. If the record was `public`, then only `public` members would be shown. This doesn't solve any of our issues with the previous
proposal, and adds a behavioral difference between making a type `public` or `internal`.
* Only `public` members. This is what the positional constructor will generate by default, and it feels like the most natural state
to choose. This ensures that encapsulation isn't violated, and records with lots of `internal` or `private` state that want to
display these in a `ToString` are likely not really records anyway. If the user really wants to change this, they can customize it
as they choose.
Conclusion:
We'll have a generated `ToString`, that will display the public properties and fields of a `record` type. We'll come back with a
specific proposal on how this will be implemented at a later point.
### W-warnings for `T t = default;`
Just after we initially shipped C# 8, we made a change to warn whenever `default` was assigned to a local or property of type `T`,
or when a default was cast to that type. There was no way to silence this warning without using a `!`, so we reverted the change.
However, now that we are shipping `T?`, there is an actual syntax that users can write in order to express "this location might
be assigned default". We know from experience that this is something that users already do a lot, so making a change here would be
pretty breaking, even for the nullable rollout phase of the first year. Further, as we know that if the `!` is the only way to get
rid of this warning then we'll get lots of feedback from users, we believe that we can't unconditionally warn here: you can only
get rid of the warning in C# 9, so at a minimum it should only be reported in C# 9. We could also put this in a warning wave, and
you would only get it when you opt into the warning wave. An important thing to consider with doing this as a warning wave implies
that it should be separate error code from 8600: we've previously told people that if they don't want to annotate all their local
variables with `?`s, then they should disable that warning and all the rest of the warnings will be actual safety warnings. This
would add another warning to that list to disable. We could make it memorable as well, but one of the key aspects in warning waves
is that you should be able to opt out of individual warnings if necessary, so users will need to be able to opt out of this new
warning without turning off all the existing 8600 warnings. All that being said, there's also a serious backcompat concern here,
as introducing the warning when upgrading to C# 9 under the existing error code could cause people to hold off on upgrading at all.
#### Conclusion
We'll add a new warning here, under a warning wave.

View file

@ -0,0 +1,196 @@
# C# Language Design Meeting for July 27th, 2020
## Agenda
- [Warnings on types named `record`](#warnings-on-types-named-record)
- [`base` calls on parameterless `record`s](#base-calls-on-parameterless-records)
- [Omitting unnecessary synthesized `record` members](#omitting-unnecessary-synthesized-record-members)
- [`record` `ToString` behavior review](#record-tostring-behavior-review)
- [Behavior of trailing commas](#behavior-of-trailing-commas)
- [Handling stack overflows](#handling-stack-overflows)
- [Should we omit the implementation of `ToString` on `abstract` records](#should-we-omit-the-implementation-of-tostring-on-abstract-records)
- [Should we call `ToString` prior to `StringBuilder.Append` on value types](#should-we-call-tostring-prior-to-stringbuilder.append-on-value-types)
- [Should we try and avoid the double-space in an empty record](#should-we-try-and-avoid-the-double-space-in-an-empty-record)
- [Should we try and make the typename header print more economic](#should-we-try-and-make-the-typename-header-print-more-economic)
- [Reference equality short circuiting](#reference-equality-short-circuiting)
## Quote of the Day
"He was hung up on his principles!"
"I painted my tower all ivory."
## Discussion
### Warnings on types named `record`
We previously discussed warning in C# 9 when a type is named `record`, as it will need to be escaped in field
definitions in order to parse correctly. This is a breaking change being made in C# 9, but we didn't explicitly
record the outcome of the warning discussion. We also discussed going further here: we could make lower-cased
type names a warning with the next warning wave, under the assumption that lowercase names make good keywords.
For example, we could start warning on types named `async` or `var`. Those who want to forbid usage of those
features in their codebase have a solution in analyzers.
#### Conclusion
We will warn on types named `record` in C# 9. Further discussion will need to happen for lowercase type names
in general, as there are globalization considerations, and we feel that disallowing `record` might be a good
smoke test for reception to the idea in general.
### `base` calls on parameterless `record`s
We have a small hole in records today where this is not legal, and there is no workaround to making it legal:
```cs
record Base(int a);
record Derived : Base(1);
```
The spec as written today explicitly forbids this: "It is an error for a record to provide a `record_base`
`argument_list` if the `record_declaration` does not contain a `parameter_list`." However, there is good
reason to allow this, and while this design may have fallen out of the principles that were set out given
that a default constructor for a nominal record is not recognized as a primary constructor, this seems to
violate principles around generally making record types smaller. Further, with the spec as written today
it's not possible to work around this issue by giving `Derived` an empty parameter list, as parameter lists
are not permitted to be empty.
A solution to this problem is relatively straightforward: we make the default constructor of a nominal record
the primary constructor, if no other constructor was provided. This seems to mesh well with the existing rules,
and seems to work well with future plans for generalized primary constructors. We could consider 2 variants of
this: requiring empty parens on the type declaration in all cases, or only requiring them in cases where the
default constructor would otherwise be omitted (if another constructor was added in the `record` definition).
#### Conclusion
We'll allow empty parens as a constructor in C# 9. We're also interested in allowing the parens to be omitted
when a default constructor would otherwise be emitted, but if this doesn't make it in C# 9 due to time
constraints it should be fine to push back to v next.
### Omitting unnecessary synthesized `record` members
Some record members might be able to be omitted in certain scenarios if they're unneeded. For example, a
`sealed` `record` that derives from `System.Object` would not need an `EqualityContract` property, as it
can only have the one contract. We could also simplify the implementation of `ToString` if we know there
will be no child-types that need to call `PrintMembers`.
However, despite leading to simplified emitted code for these types, we're concerned that this will cause
other code to become more complicated. We'll need to have more complicated logic in the compiler to handle
these cases. Further, source generators and other tools that interact with records programmatically will
have to duplicate this logic if they need to interact with record equality or any other portion of code that
"simplified" by this mechanism. We further don't see a real concern for metadata bloat in this scenario,
as we aren't omitted fields from the record declaration.
#### Conclusion
There are likely more downsides than upsides to doing something different here. We'll continue to have this
be regular.
### `record` `ToString` behavior review
Now that we have a proposal and implementation for `ToString` on record types, we'll go over some standing
questions from initial implementation review. Prior art for this area in C# that we found relevant was
`ToString` on both tuples and anonymous types.
#### Behavior of trailing commas
There is a proposal to simplify the implementation of `ToString` by always printing trailing commas after
properties. This would remove the need for some bool tracking flags for whether a comma was printed as
part of a parent's `ToString` call. However, no prior art (in either C# or other languages) that we could
find does this. Further, it provokes a visceral reaction among team members as feeling unfinished, and that
it would be the first bug report we get after shipping it.
##### Conclusion
No trailing commas.
#### Handling stack overflows
There is some concern that `ToString` could overflow if a record type is recursive. While this is also true
of equality and hashcode methods on records, there is some concern that `ToString` might be a bit special
here, as it's the tool that a developer would use to get a print-out of the record to find the cyclic element
in the first place. There's examples in the javascript world of this being a pain point. However, any
solution that we come up with for records will have limitations: it wouldn't be able to protect against
indirect cycles through properties that are records but not records of the same type, or against cycles
in properties that are not records at all. In general, if a user makes a record type with a cyclic data
structure, this is a problem they're going to have to confront already in equality and hashcode.
##### Conclusion
We will not attempt any special handling here. We could consider adding a `DebuggerDisplay` with more special,
reflective handling at a later point in time if this proves to be a pain point, but we don't think it's
worth the cost in regular `ToString` calls.
#### Quoting/escaping values
Today, records do not attempt to escape `string`s when printing, which could result in potentially confusing
printing. However, we do have concerns here. First, none of our prior art in C# does this escaping. Second,
the framework also does not escape `ToString()` like this. Third, there's a question of what _type_ of
escaping we should do here. Would we want to print a newlines as the C# version, `\n`, or the VB version?
Further, we already have some handling the expression evaluator and debugger for regular strings and
anonymous types, to ensure that the display looks good there. Given that this is mainly about ensuring
that records appear well-formatted in the debugger, it seems like the correct and language-agnostic approach
is to ensure the expression evaluator knows about record types as well.
##### Conclusion
We won't do any quoting or escaping of string record members. We should make the debugger better here.
#### Should we omit the implementation of `ToString` on `abstract` records
We could theoretically omit providing an implementation of this method on `abstract` record types as it
will never be called by the derived `ToString` implementation. On the face of it, we cannot think of a
scenario that would be particularly helped by including the `ToString`, however we also cannot think of
a scenario that would be harmed by including it, and doing so would make the compiler implementation simpler.
##### Conclusion
Keep it.
#### Should we call `ToString` prior to `StringBuilder.Append` on value types
The concern with directly calling `Append` without `ToString` on the value being passed is that for
non-primitive struct types, this will cause the struct to be boxed, and the behavior of `Append` is
to immediately call `ToString` and pass to the `string` overload.
##### Conclusion
Do it.
#### Should we try and avoid the double-space in an empty record
The implementation currently prints `Person { }` for an empty record. This provokes immediate "unfinished"
reactions in the LDT, similar to the trailing commas above.
##### Conclusion
Should we remove it? YES! YES! YES! YES!
#### Should we try and make the typename header print more economic
Today, we call `StringBuilder.Append(nameof(type))` and `StringBuilder.Append("{")` immediately after
as 2 separate calls, which is another method call we could drop if we did it all in one. We feel that this
is sufficiently outside the language spec as to be a thing a compiler could do if it feels it appropriate.
From the compiler perspective, however, it could actually be bad change, as it would increase the size of
the string table, which is known to be an issue in some programs, while getting rid of one extra method call
in a method not particularly designed to be as fast as possible in the first place.
##### Conclusion
Up to implementors. However, we don't believe it to be a good idea or worth any effort.
### Reference equality short circuiting
Today, we have a slight difference between the equality operators `==`/`!=` and the implementation of the
`Equals(record)` instance method, in that the former compare reference equality first, before delegating
to the `Equals` method. This ensures that `null` is equal to `null` as a very quick check, and ensures we
only have to compare one operand to `null` explicitly in the implementation of the operators. The `Equals`
instance member then does not check this condition. However, this means that the performance characteristics
of these two members can be very different, with the operators being an order of magnitude faster on even
small record types since it has to do potentially many more comparisons. The proposal, therefore, is to
check reference equality in the `Equals` instance member as well, as the first element.
#### Conclusion
We will do this. We'll keep the reference equality check in the operators as well to ensure that `null == null`,
and add one at the start of the instance method. It does mean that the `==` operators will check reference
equality twice, but this is an exceptionally quick check so we don't believe it's a big concern.

View file

@ -0,0 +1,190 @@
# C# Language Design Meeting for September 9th, 2020
## Agenda
1. [Triage issues still in C# 9.0 candidate](#triage-issues-still-in-C#-9.0-candidate)
2. [Triage issues in C# 10.0 candidate](#Triage-issues-in-C#-10.0-candidate)
# Quote(s) of the Day
"Don't even mention I was here."
"I have lots of strong opinions, I'm just judicious with how I distribute them."
# Discussion
## Triage issues still in C# 9.0 candidate
To start, we updated https://github.com/dotnet/csharplang/blob/master/Language-Version-History.md with the features that have been merged into the compiler for C# 9 at
this point, and moved their corresponding issues to the [9.0 milestone](https://github.com/dotnet/csharplang/milestone/18).
### Null propagation expression does not allow `!` as a nested operator form
https://github.com/dotnet/csharplang/issues/3393
We did not adequately prioritize this given the urgency of the breaking change. We need to attempt to get this into C# 9 or we may end up being stuck with this behavior
given that the nullable rollout period is ending, or we'd need to consider taking what could be a large breaking change. We'll attempt to throw and catch this hail mary,
and it will stay in C# 9.0 candidate for now.
### [Proposal] Improve overload resolution for delegate compatibility
https://github.com/dotnet/csharplang/issues/3277
We had hoped to get this done as a refactoring while implementing function pointers, but did not end up getting it in. This is a good candidate for community contribution
as it can be implemented and tested in a single PR, so we'll move this to any time.
### Interface static method, properties and event should ignore variance
https://github.com/dotnet/csharplang/issues/3275
This is implemented, just waiting on infrastructure to move forward to a runtime where it can be tested. Will be in C# 9 as soon as that happens, and is staying in 9.0
candidate.
### Records-related issues
https://github.com/dotnet/csharplang/issues/3226
https://github.com/dotnet/csharplang/issues/3213
https://github.com/dotnet/csharplang/issues/3137
These are all records related issues. We didn't get all of what we want to accomplish in this space in C# 9, so we need to break the still-to-be-done parts of these
proposals out into separate issues for 10 or later and close/move these.
### Primary Constructors
https://github.com/dotnet/csharplang/issues/2691
We didn't managed to break this out of records in a satisfactory manner for 9, but we would like to get this in for 10. Retriaged to 10.0 Candidate.
### Proposal: Target typed null coalescing (`??`) expression
https://github.com/dotnet/csharplang/issues/2473
When attempting to spec and implement this, we found that it doesn't actually work well in practice, as `??` has a number of complicated rules around type resolution
already and what part should be target-typed is confusing. We believe that, given the investigation, we won't be moving this one forward, and it moves to the Likely
Never milestone.
### Champion: Simplified parameter null validation code
https://github.com/dotnet/csharplang/issues/2145
We didn't quite get the code gen for this one finished up. Moving to 10.0 candidate.
### Champion: relax ordering constraints around `ref` and `partial` modifiers on type declarations
https://github.com/dotnet/csharplang/issues/946
We had put this in 9.0 because we thought it would be required for `data` classes. That did not end up being the case, and we don't have high priority for it otherwise.
We'd accept a contribution if a community member wanted to loosen the restriction, thus moved to Any Time.
### Champion "Nullable-enhanced common type"
https://github.com/dotnet/csharplang/issues/33
https://github.com/dotnet/csharplang/issues/881
We said when doing additional target-typing work that we either had to do these now, or it would be very complicated to implement later without avoiding breaking changes.
Given that the target-typing we added more generally addresses this in most scenarios, we don't believe that the additional "break glass in case of emergency" bar is
met with these, and they are moved to Likely Never.
### Proposal: improvements to nullable reference types
https://github.com/dotnet/csharplang/issues/3297
This is part of the ongoing nullable improvements list. We will split the parts that have not been implemented out into a separate list, and then move this to 9.0 with
just the things actually implemented for this release.
## Triage issues in C# 10.0 candidate
We will be moving issues from the 10.0 candidate bucket to the 10.0 Working Set bucket during triage. Issues in the 10.0 Working Set bucket are issues that we have decided
to devote some design time towards during the upcoming 10.0 timeframe, but not all of the issues triaged into this working set will actually make it into the 10.0 release.
### Proposal: Exponentiation operator
https://github.com/dotnet/csharplang/issues/2585
We don't feel that this is a major priority for the language currently. It is a relatively small amount of work, however. If a community member wants to add a proposal
for a specific symbol to use for the operator and a precedence for that symbol, we'd be happy to consider it at that point. Moved to Any Time.
### Champion "Type Classes (aka Concepts, Structural Generic Constraints)"
https://github.com/dotnet/csharplang/issues/110
We feel that issues in improving the type system, such as type classes, roles, statics in interfaces, etc, are the next big area of investment for the language. While
we may not end up seeing the results of these investments in the 10.0 timeframe, we need to start designing them now or we'll never see them at all. As such, we are
labeling this issue as "Long lead" to indicate that there is a lot of design work to come before and implementation can even start to happen. Moved to 10.0 Working Set.
### generic constraint: where T : ref struct
https://github.com/dotnet/csharplang/issues/1148
This is related to a forthcoming proposal on ref fields, as well as to the aforementioned type system improvements we want to make. To really be useful beyond allowing
`Span<Span<T>>`, ref structs need to be able to implement interfaces, and so this will be considered in tandem with them. Moved to 10.0 Working Set.
### Champion "CallerArgumentExpression"
https://github.com/dotnet/csharplang/issues/287
While this could be considered Any Time, we already have most of an implementation and would like to get it in for C# 10, so we are moving it to 10.0 Working Set.
### Champion "Allow Generic Attributes"
https://github.com/dotnet/csharplang/issues/124
A community member is contributing this feature, and while we don't think there is any design work left to do from the language side there's still a bit of work on the
implementation itself. We'll move this to 10.0 Working Set, as opposed to Any Time, to ensure that we give priority if there does end up being any language work to do.
### C# Feature Request: Allow value tuple deconstruction with default keyword
https://github.com/dotnet/csharplang/issues/1358
This is a small quality of life change that we already have a PR for. Let's get it merged, and move this issue to 10.0 Working Set.
### Expression Blocks/Switch Expression and Statement Enhancements
https://github.com/dotnet/csharplang/issues/3086
https://github.com/dotnet/csharplang/issues/3038
https://github.com/dotnet/csharplang/issues/3087
https://github.com/dotnet/csharplang/issues/2632
We know that we want to make some improvements here. We need to narrow down on a concrete proposal as we have a lot of different scopes/syntaxes currently, and then we
can proceed with implementation. Move to 10.0 Working Set.
### Champion: Name lookup for simple name when target type known
https://github.com/dotnet/csharplang/issues/2926
We consider this a somewhat essential necessary feature for discriminated unions, so this should be considered in concert with that. Move to 10.0 Working Set.
### Proposal: "Closed" type hierarchies
https://github.com/dotnet/csharplang/issues/485
This needs to be designed in concert with discriminated unions, so we'll move it to 10.0 Working Set.
### Championed: Target-typed implicit array creation expression `new[]`
https://github.com/dotnet/csharplang/issues/2701
This needs some design work around either making it a generalized feature for type parameter-based inference or if it specializes for the interfaces that array implements
specifically. We don't feel that this particularly pressing, so we're moving it to X.0 unless we hear a need to add it to align with other .NET priorities.
### Champion: `base(T)` phase two
https://github.com/dotnet/csharplang/issues/2337
While this was part of the initial feature set for DIMs, we don't hear any particular customer complaints for this feature. We'll move it to X.0 until such time as we
hear customer asks for it.
### Champion "defer statement"
https://github.com/dotnet/csharplang/issues/1398
LDM was somewhat negative on this feature. There are times when you'd want to pair code to run at the end of a block/method return, but defer has invisible consequences
here because it would have to use try/finally. This give defer a penalty that would prevent it from being used in many of the places we'd otherwise want to use it ourselves.
Additionally, there is significant negative community sentiment about this feature, much more than we usually get for participation on any particular csharplang issue. As a
result, we are moving this feature to Likely Never, and if we see similar significant outcry to the rejection we can reconsider this.
### Five ideas for improving working with fixed buffers
https://github.com/dotnet/csharplang/issues/1502
This will be part of the previously-mentioned forthcoming ref fields proposal. Move it to 10.0 Working Set.

View file

@ -0,0 +1,111 @@
# C# Language Design Meeting for September 14th, 2020
## Agenda
1. [Partial method signature matching](#partial-method-signature-matching)
2. [Null-conditional handling of the nullable suppression operator](#null-conditional-handling-of-the-nullable-suppression-operator)
3. [Annotating IEnumerable.Cast](#annotating-ienumerable.cast)
4. [Nullability warnings in user-written record code](#nullability-warnings-in-user-written-record-code)
5. [Tuple deconstruction mixed assignment and declaration](#tuple-deconstruction-mixed-assignment-and-declaration)
## Quote of the Day
- "Now with warning waves it's a foam-covered baseball bat to hit people with"
## Discussion
### Partial method signature matching
https://github.com/dotnet/roslyn/issues/45519
There is a question about what amount of signature matching is required for method signatures, both as part of the expanded partial methods in C# 9
and for the new `nint` feature in C# 9. Currently, our rules around what has to match and what does not are confusing: tuple names must match,
`dynamic`/`object` do not have to match, we warn when there are unsafe nullability conversions, and other differences are allowed (including parameter
names). We could lean on a warning wave here and make our implementation more consistent with the following general rules:
1. If there are differences in the CLR signature, we error (as we cannot emit code at all!)
2. If there are differences in the syntactic signature, we warn (even for safe nullability changes).
While we like this proposal in general, we have a couple of concerns around compatibility. Tuple names erroring is existing behavior, and if we loosen
that to a general warning that would need to be gated behind language version, as you could write code with a newer compiler in C# 8 mode that does not
compile with the C# 8 compiler. This complicates implementation, and to make it simple we lean towards just leaving tuple name differences as an error.
We also want to make sure that nullability is able to differ by obliviousness: a common case for generators is that either the original signature or the
implementation will be unaware of nullable, and we don't want to break this scenario such that either both the user and generator must be nullable aware,
or the must both be nullable unaware.
We also considered an extension to these rules where we make the new rules always apply to the new enhanced partial methods, regardless of warning level.
However, we believe that this would result in a complicated user experience and would make the mental model harder to understand.
#### Conclusion
1. We will keep the existing error that tuple names must match.
2. We will keep the existing warnings about unsafe nullability differences.
3. We will add a new warning wave warning for all other syntactic differences between partial method implementations.
a. This includes differences like parameter names and `dynamic`/`object`
b. This includes nullability differences where both contexts are nullable enabled, even if the difference is supposedly "safe" (accepting `null`
where it is not accepted today).
c. If nullability differs by enabled state (one part is enabled, the other part is disabled), this will be allowed without warning.
### Null-conditional handling of the nullable suppression operator
https://github.com/dotnet/csharplang/issues/3393
This is a spec bug that shipped with C# 8, where the `!` operator does not behave as a user would expect. Members of the LDT believe that this is broken
on the same level as the `for` iterator variable behavior that was changed in C# 5, and we believe that we should take a similar breaking change to fix
the behavior here. We have made a grammatical proposal for adjusting how null-conditional statements are parsed, and there was general agreement that this
proposal is where we want to go. The only comment is that `null_conditional_operations_no_suppression` should be renamed to avoid confusion, as there can
be a null suppression inside the term, just not at the end. A better name would be `null_conditional_operations_no_final_suppression`.
#### Conclusion
Accepted, with the above rename. Will get a compiler developer assigned to implement this ASAP.
### Annotating IEnumerable.Cast
https://github.com/dotnet/runtime/issues/40518
In .NET 5, the `Cast<TResult>` method was annotated on the return to return `IEnumerable<TResult?>`, which means that regardless of whether the input
enumerable can contain `null` elements, the returned enumerable would be considered to contain `null`s. This resulted in some spurious warnings when
upgrading roslyn to use a newer version of .NET 5. However, the C# in general lacks the ability to properly annotate this method for a combination of
reasons:
1. There is no way to express that the nullability of one type parameter depends on the nullability of another type parameter.
2. Even if there was a way to express 1, `Cast` is an extension method on `IEnumerable`, not `IEnumerable<T>`, because C# does not have partial type
inference to make writing code in this scenario better.
Given this, we have a few options:
1. Leave the method as is, and possibly enhance the compiler/language to know about this particular method. This is analogous to the changes we're
considering with `Where`, but it feels like a bad solution as it's not generalizable.
2. Make the method return `TResult`, unannotated. The issue with this is that it effectively means the method might actually lie: there is no way to
ensure that the method actually returns a non-null result if a non-null `TResult` is provided as a type, given that nullability is erased in the
implementation. We're concerned that this could make the docs appear to lie, which we think would also give a bad experience.
3. Convert `Cast` back to being unannotated. This seems to be compromise that both sides can agree on: analyzers can flag use of the unannotated API
to help users, and spurious warnings get suppressed. It also matches the behavior of `IEnumerator.Current`, and means that the behavior of `foreach`
loops over such a list behave in a consistent manner.
#### Conclusion
The BCL will make `Cast` and a few related APIs an oblivious API.
### Nullability warnings in user-written record code
The question here is on whether we should warn users when manually-implemented methods and properties for well-known members in a `record` should warn
when nullability is different. For example, if their `Equals(R other)` does not accept `null`. There was no debate on this.
#### Conclusion
we'll check user-defined `EqualityContract`, `Equals`, `Deconstruct`, ... methods on records for nullability safety issues in their declaration. For
example, `EqualityContract` should not return Type?.
### Tuple deconstruction mixed assignment and declaration
https://github.com/dotnet/csharplang/issues/125
We've discussed this feature in the past (https://github.com/dotnet/csharplang/blob/master/meetings/2016/LDM-2016-11-30.md#mixed-deconstruction), and
we liked it then but didn't think it would fit into C# 7. It's been in Any Time since, and now we have a community PR. We have no concerns with
moving forward with the feature.
#### Conclusion
Let's try and get this into C# 10.

View file

@ -0,0 +1,66 @@
# C# Language Design Meeting for September 14th, 2020
## Agenda
1. [Required Properties](#required-properties)
2. [Triage](#triage)
## Quote of the day
- "It's my version of thanks Obama, thanks C#"
## Discussion
### Required Properties
https://github.com/dotnet/csharplang/issues/3630
[Presentation](./Required_Properties_2020_09_16.pdf)
Most of the time today was used hearing a presentation about a proposal for required properties. This presentation was intended
as a high-level overview of the issue required properties are attempting to solve, and to illustrate a few approaches that could
be taken for implementing these. Notes were not taken to the slide content itself, as the slides are linked above.
Overall, the LDM is a bit leary about the implementation complexity of runtime-verification methods. One approach that wasn't on
the slides, but is a possible approach, is introducing validators and letting type authors do the verification themselves. This
may end up resulting in type authors conflating nullability and requiredness for most simple implementations, but for the common
scenarios this may be just fine. We were unable to find just one implementation strategy that stuck out as "this is the right thing
to do." Instead, each implementation strategy had a set of tradeoffs, particularly around the implementation complexity of tracking
whether a property has been initialized.
One thing that we noted from the presentation is that any method of introducing required properties is going to mean that types with
these contracts on their empty constructors will not be able to be used in generic scenarios `where T : new()`, as the empty constructor
is required to set some amount of properties. The presentation also did not cover how to do additive or subtractive contracts: ie, a
future factory method `MakeAMads` might want to specify "Everything from the normal `Person` constructor except `FirstName`", whereas
a copy constructor would want to specify "You don't have to initialize anything". Some work has started on designing this scenario,
but it needs some more work before it's in a state to get meaningful feedback.
A read of the room found that most of the LDM was leaning towards compile-time only validation of required properties. It does mean
that upgrading binary versions without recompiling can leave things in an invalid state, but the implementation strategies for
getting actual runtime breaks are very complex and we're not sure they're worth the tradeoff. The next step in design will be to
come back with a more concrete syntax proposal for how required properties will be stated, and how constructors will declare their
contracts.
### Triage
We only had time left to triage 1 issue:
#### Proposal: Permit trailing commas in method signatures and invocations
https://github.com/dotnet/csharplang/issues/391
This is a longstanding friction point in the language that has mostly positive sentiment on csharplang. We're also fairly confident
that it wouldn't break any possible language features other than omitted arguments, which the LDM is not particularly interested
in pursuing. That being said, the general gut reaction of most LDM members is something along the lines of "This looks wrong." We
certainly acknowledge that, despite some syntactic misgivings, this can be a very useful feature, particularly for source generators
and refactorings, as well as for just simply reordering parameters in a method call or definition. There are a couple of open issues
we'd need to resolve as well:
* What would happen with param arrays?
* Would tuple declarations be allowed to have trailing commas? This proposal actually seems like a natural way to allow oneples into
the language, in a similar style to Python, where the oneple must have a trailing comma.
##### Conclusion
Triage in X.0. We think this feature has a place in C#, but we don't think it will make the bar for what we're interested in with C# 10.

View file

@ -0,0 +1,37 @@
# C# Language Design Meeting for September 23rd, 2020
## Agenda
1. General improvements to the `struct` experience
## Quote of the day
- "This makes C# developers queasy. Refs can never be null! The runtime says that's not true, the C# type system is a lie."
## Discussion
Most of this session was dedicated to explaining the proposal itself, which can be found [here](https://github.com/dotnet/csharplang/blob/master/proposals/low-level-struct-improvements.md).
We covered the section `Provide ref fields` in full, but did not get beyond that in this session. What follows are some noted comments on the
proposal, as we did not have long discussions about the merits of the feature itself.
* The general driving principles of this proposal are to ease friction points in the language around structs. Today we have `Span<T>`, which is
a very useful type, but it uses a magic BCL-internal type called `ByReference<T>`. Span uses it to great effect, but because there are no compile
rules around its safety we can't expose it publicly. This leads to 3rd parties using reflection to get it, which just results in badness all
around. We'd like to allow the semantics to be fully specifiable in C# and enable it not just for the BCL, but for all types of structs. The LDM
generally agrees with this goal.
* There will need to be some metadata tool updates. In order for safe-to-escape analysis to work, we will have to ensure that all `ref` fields,
even private fields, appear in reference assemblies and similar locations to ensure that the compiler can correctly determine lifetimes.
* The rules around returning a ref to a ref parameter are not especially intuitive. We acknowledge that they are necessary given the lifetime
rules today with methods returning a `Span`, but we could introduce a `CapturesAttribute` or something similar to indicate that a `ref` parameter
is captured by the method, and thus allow passing it directly as a `ref` to `new Span<T>`.
* There is a workaround for this behavior: instead of taking a `ref T` in the constructor, take a `Span<T>`, which will ensure that all the
lifetimes line up. While this workaround is viable, we're somewhat worried it won't be straightforward enough of a solution.
* Allowing `ref` assignment after the fact could be done in a later version of C#. It's a good deal of work in the compiler (likely an entirely
new flow analysis pass) to correctly update the lifetimes, and we're not yet certain that the scenario is worth the effort. If this proves to be
a friction point for users, we can revisit.
* One scenario this spec does not consider is `ref` assignment in an object initializer, which is still part of the object construction phase.
This should be allowable, and we need to update the draft specification to address this case.
* `ref null` is going to be an annoying problem. Given that you can `default` structs in any of a number of ways, at some point it will be possible
to observe a `default` ref struct that has a `null` `ref`. While the runtime does have an `Unsafe.IsNullRef` helper method, it feels unnatural that
code that is entirely safe C# should have to use a method from the `Unsafe` class. Further, these newly-observable `null` `ref`s will will end up
everywhere, in much the same way that `null` ends up everywhere. We may need to think more about this problem.

View file

@ -0,0 +1,207 @@
# C# Language Design Meeting for September 28th, 2020
## Agenda
1. [Warning on `double.NaN`](#warning-on-double.nan)
2. [Triage](#triage)
1. [Proposal: more improvements to nullable reference types](#proposal-more-improvements-to-nullable-reference-types)
2. [Proposal: Required Properties](#proposal-required-properties)
3. [Proposal: Extend with expression to anonymous type](#proposal-extend-with-expression-to-anonymous-type)
4. [Proposal: Shebang (#!) Support](#proposal-shebang--support)
5. [Proposal: List Patterns](#proposal-list-patterns)
6. [Proposal: Add ability to declare global usings for namespaces, types and aliases by using a command line switch](#proposal-add-ability-to-declare-global-usings-for-namespaces-types-and-aliases-by-using-a-command-line-switch)
7. [Proposal: "Closed" enum types](#proposal-closed-enum-types)
8. [Top-level functions](#top-level-functions)
9. [Primary Constructors](#primary-constructors)
10. [Champion: Simplified parameter null validation code](#champion-simplified-parameter-null-validation-code)
11. [Proposal: Support generics and generic type parameters in aliases](#proposal-support-generics-and-generic-type-parameters-in-aliases)
12. [Support for method parameter names in nameof](#support-for-method-parameter-names-in-nameof)
## Quote of the day
- "On a rational basis I have nothing against this"
## Discussion
### Warning on `double.NaN`
https://github.com/dotnet/roslyn/issues/15936
We have an existing FxCop warning (CA2242) for invalid comparisons to `double.NaN`. We could consider bringing
that warning into the compiler itself as in a warning wave. However, as this analyzer is now shipped with the
.NET 5 SDK, is on by default, and deals more with API usage than with the language itself, it would also be fine
to leave it where it is.
#### Conclusion
Rejected. Leave the warning where it exists today.
### Triage
Today, we got through half the remaining issues in the C# 10.0 Candidate milestone
#### Proposal: more improvements to nullable reference types
https://github.com/dotnet/csharplang/issues/3868
We have a few open topics in improvements to nullable reference types for the C# 10.0 timeframe. We're currently
tracking LINQ improvements, Task-like type covariance, and uninitialized fields and constructors. This last point
will likely be handled in conjunction with the proposals for required properties and initialization debt. The
first two can be broken out to specific issues for the 10.0 timeframe.
##### Conclusion
File separate issues for the first two bullets, and triage into the 10.0 working set.
#### Proposal: Required Properties
https://github.com/dotnet/csharplang/issues/3630
We've already started talking about this one.
##### Conclusion
Triage into the 10.0 working set.
#### Proposal: Extend with expression to anonymous type
https://github.com/dotnet/csharplang/issues/3530
This proposal extends anonymous types to allow `with` expressions to change them, which we like a lot. In a way,
this extension makes anonymous types practically just anonymous _record_ types, as they have the rest of the properties
of a record already: value equality, ToString, etc. It also fits in well with the idea of generally extending `with`
expressions to be more broadly applicable. Since anonymous types cannot be exposed as types in a public API, generating
new `init` members and the `with` clone method is a non-breaking change. New compilations can take advantage of the
features, and old compilations don't get affected by them.
As part of discussing this issue, we hit upon the idea of additionally allowing `new { }` to be target-typed. If a `new`
expression that did not have `()` is assigned to something that matches its shape (such as a record with the correct)
property names, we could just allow that new expression to be treated as the target-type constructor, rather than as
creating a new anonymous type. If the target-type is `object` or `dynamic`, it will still result in an anonymous object
being created, and there may be some tricks to figuring out generic inference, but we think it might be a path forward
towards making target-typed new more regular with the rest of the language (a complaint we have already heard). A future
proposal for that will be filed.
##### Conclusion
Triage into C# 10.0 working set for consideration with the rest of the `with` extensions.
#### Proposal: Shebang (#!) Support
https://github.com/dotnet/csharplang/issues/3507
While could eventually be an interesting proposal, the tooling is not there currently, and we feel the discussion around
developer ergonomics in .NET 6 will shape our discussions in this area.
##### Conclusion
Triaged into X.0, and if the .NET tooling looks to add `dotnet run csfile`, we can consider again at that point.
#### Proposal: List Patterns
https://github.com/dotnet/csharplang/issues/3435
We like continuing to enhance the pattern support in C#, and are in general positive about this proposal. However, the
somewhat-fractured nature of .NET here works to our detriment, not just in the `Count` vs `Length` property names, but
in the general collection type sense. It would be nice to support `IEnumerable`, for example, which does not meet the
definitions set out in the proposal. Another consideration would be dictionary types: we don't have support for a
dictionary initializers specifically today, so having a decomposition step without a composition step would be odd, but
they would be a useful pattern nontheless. We also would like to see if we can find a way to make the syntax use braces
rather than square brackets to mirror collection initializers, though that will be difficult due to the empty property
pattern.
##### Conclusion
We'll spend design time on this in the C# 10 timeframe, though it may not make the 10.0 release itself. Triaged into the
10.0 working set.
#### Proposal: Add ability to declare global usings for namespaces, types and aliases by using a command line switch
https://github.com/dotnet/csharplang/issues/3428
This is, in many ways, a language-defining issue. The proposal itself is small, but it reflects the LDT's thinking of
future C# directions as a whole. It is also very divisive, both in the LDT and in the greater community, with a small
majority (both in the LDT and in the csharplang community) in favor of the feature. It introduces a level of magic to
the language that has been somewhat resisted in the past. Additionally, there is concern that there is no one set of
"base usings" that should be automatically included in files: a console app might only want to include `System`, while
an ASP.NET app might want to include a bunch of namespaces for various routing properties, controllers, and the like.
##### Conclusion
We'll discuss this more in the 10.0 timeframe. There could be interactions around the theme of developer QoL in the .NET
6 timeframe.
#### Proposal: "Closed" enum types
https://github.com/dotnet/csharplang/issues/3179
This proposal is linked to discriminated unions, in that it's a another type of closed hierarchy that C# does not support
today.
##### Conclusion
Triage into 10.0 working set, to be discussed with DU's and closed type hierarchies in general.
#### Top-level functions
https://github.com/dotnet/csharplang/issues/3117
This is the follow-up work from C# 9 that we did not conclude in the initial push for top-level statements in C#,
namely in allowing globally-accessible functions in C# to float at the top level without a containing class. One
concern with generalizing this feature is that we have 20 years of BCL design that does not account for top-level
functions, in addition to other well-known and used libraries. For consistency, these libraries would likely not
use this new feature, which would relegate this feature to minimal usage. While many LDT members like the feature
in general, and would likely introduce it if we were redesigning C# from the ground up, we don't believe that the
feature belong in the C# we have today. We will continue to investigate whether top-level functions defined today
(which are local functions to the implicit `Main` method) should be callable from within the current file, in order
to have better compat with CSX. However, the overall feature is rejected.
##### Conclusion
Rejected.
#### Primary constructors
https://github.com/dotnet/csharplang/issues/2691
We have a proposal for this, and we are mostly in agreement that we should see this through.
##### Conclusion
Triage into 10.0 working set.
#### Champion: Simplified parameter null validation code
https://github.com/dotnet/csharplang/issues/2145
We have an implementation of this mostly ready. It was done in such as way as to be usable by the BCL, and will
potentially save 7K+ lines of code there. Let's get it in.
##### Conclusion
Triage into 10.0 working set.
#### Proposal: Support generics and generic type parameters in aliases
https://github.com/dotnet/csharplang/issues/1239
We like the idea of improving aliases in general, and this could come into play when we talk about the previously-mentioned
global usings. There are multiple possible flavors here though: there's simple aliases like we have today, that are
freely convertible back to the underlying type, and then there are true opaque aliases that are not freely convertible
back to the underlying type. Ideally, these latter aliases would be zero cost, which will likely require some work in
conjunction with the runtime. Additionally, while we like the idea of making improvements here, we have a lot on the C# 10
plate currently, and think it would fit in better with the type enhancements we hope to make after 10.
##### Conclusion
Triaged into X.0.
#### Support for method parameter names in nameof
https://github.com/dotnet/csharplang/issues/373
We like this, and have the start of an implementation.
##### Conclusion
Triaged into 10.0 working set.

View file

@ -0,0 +1,134 @@
# C# Language Design Meeting for September 30th, 2020
## Agenda
1. `record structs`
1. [`struct` equality](#struct-equality)
2. [`with` expressions](#with-expressions)
3. [Primary constructors and `data` properties](#primary-constructors-and-data-properties)
## Quote of the Day
- "... our plan of record"
- "haha badum-tish"
## Discussion
Our conversation today focused on bringing records features to structs, and specifically what parts should apply
to _all_ structs, what should apply to theoretical `record` structs (if that's even a concept we should have), and
what should not apply to structs at all, regardless of whether it's a `record` or not. The table we looked at is
below, followed by detailed summaries of our conversations on each area. We did not come to a confirmed conclusion
on primary constructors/data properties this meeting, but we do have a general room lean, which has been recorded.
|Feature |All structs |Record structs|No structs|
|----------------------------------|--------------|--------------|----------|
|Equality |--------------|--------------|----------|
|- basic value equality | X (existing) | | |
|- == and strongly-typed `Equals()`| | X | |
|- `IEquatable<T>` | | X | |
|- Customized value equality | X | | |
|`with` |--------------|--------------|----------|
|- General support | X | | |
|- Customized copy | |explicit error| X |
|- `with`ability abstraction | | ? | |
|Primary constructors |--------------|--------------|----------|
|- Mutability by default | | | leaning |
|- Public properties | | leaning | |
|- Deconstruction | | leaning | |
|Data properties |--------------|--------------|----------|
|- Mutability by default | | | leaning |
|- Public properties | | leaning | |
### `struct` equality
`record`s in C# 9 are very `struct` inspired in their value equality: all fields in `record` a and b are compared
for equality, and if they are all equal, then a and b are also equal. This is the default behavior for all `struct`
types in C# today, if an `Equals` implementation is not provided. However, this default implementation is somewhat
slow, as it uses reflection. We've talked in the past about potentially generating an `Equals` implementation for
all struct types that would have better performance. However, we are definitely very concerned about potential size
bloat for doing this, particularly around interop types. Given those concerns, we don't think we can generate such
methods for all struct types. We then considered whether hypothetical `record` structs should get this implementation.
However, generating a good implementation of equality for structs almost seems like it's not a C# language issue at
all. More than just C# runs on the CLR, and it would be a shame if there was incentive to use a particular language
because it generates a better equality method. Further, since we can't do this for all `struct` types, it means we
would inevitably have to educate users that "`record struct`s generate better code for equality, so you may just
want to make your `struct` a `record` for that reason alone", which isn't great either. Given that, we'd rather work
with the runtime team to make the automatic `Equals` method better, which will benefit not just all C# structs,
but all `struct` types from all languages that run on the CLR.
Next, we looked at whether we should expose new equality operators and strongly-typed `Equals` methods on `struct`
types, as well as implementing `IEquatable<T>`. We again came to the conclusion that, for all existing `struct`
types, it would be too costly in metadata (and a potential breaking change for exposing a strongly-typed `Equals`
method or `IEquatable<T>`) to do this for all types. However, we do think that a gesture for opting into this
generation would be useful. Given that, we considered whether it was useful to have these be more granular gestures,
ie if a type could just opt-in to generating `IEquatable<T>` without the equality features. For these scenarios, we
feel that the need just isn't there, and that it should be an all-or-nothing opt-in.
Finally on this topic, we considered customized `Equals` implementations. This is a fairly simple topic: all structs
support customizing their definition of `Equals` today, and will continue to do so in the future.
#### Conclusion
All structs will continue to use the runtime-generated `Equals` method if none is provided. Making a `struct` a
`record` will be a way to opt-in to new surface area that uses this functionality. We will work with the runtime
team to hopefully improve the implementation of the generated `Equals` methods in future versions of .NET.
### `with` expressions
We considered whether all structs should be copyable via a `with` expression, or just some subset of them. On the
surface, this seems a simple question: all structs are copyable today, and we even have a dedicated CIL instruction
for this: `dup`. It seems trivial to enable this for any location where we know the type is a `struct` type, and
just emit the `dup` instruction. Where this becomes a more interesting question, though, is in the intersection
between all structs and any potential for customization of the copy behavior. We have plans to enable `with`
as a general pattern that any class can implement through some mechanism, and if structs can customize that behavior
it means that a struct substituted for a generic type `where T : struct` will behave incorrectly if that behavior
was customized. Additionally, if we extend `with`ability as a pattern and allow it to be expressed via some kind of
interface method, would structs be able to implement that method? Or would it get an automatic implementation of
that method?
An important note for structs is that, no matter what we do here with respect to `with`, structs are fundamentally
different than classes as they're _already_ copied all the time. Unless someone is ensuring that they always pass
a struct around via `ref`, the compiler is going to be emitting `dup`s all the time. While we could design a new
runtime intrinsic to call either `dup` or the struct's clone method if it exists, struct cloning behavior has long-
established semantics that we think users will continue to expect.
#### Conclusion
All `struct` types should be implicitly `with`able. No `struct` types should be able to customize their `with`
behavior. Depending on how we implement general `with` abstractions, `record` structs might be able to opt-in to them,
but will still be unable to customize the behavior of that abstraction.
### Primary constructors and `data` properties
Finally today, we considered the interactions of primary constructors, data properties, and structs. There are two
general ideas here:
1. `struct` primary constructors should mean the same thing as `class` primary constructors (with whatever behavior
we define later in this design cycle), and `record struct` primary constructors should mean the same thing as
`record` primary constructors (public init-only properties), or
2. `record struct` primary constructors should mean public, mutable fields.
Option 1 would provide a symmetry between record structs and record class types, while option 2 would provide a
symmetry between record structs and tuple types. In a sense, a record struct would just become a strongly-named tuple
type, and have all the same behaviors as a standard tuple type. You could then opt a record struct into being
immutable by declaring the whole type `readonly`, or declaring the individual parameters `readonly`. For example:
```cs
// Public, mutable fields named A and B
record struct R1(int A, int B);
// Public, readonly fields named A and B
readonly record struct R2(int A, int B);
```
A key point in the mutability question for structs is that mutability in a struct type is nowhere near as bad as
mutability in a reference type. It can't be mutated when it's the key of a dictionary, for example, and unless
refs to the struct are being passed around the user is always in control of the struct. Further, if a ref is passed
and it is saved elsewhere, that's a copy, and mutation to that copy doesn't affect the original. As always, we also
have easy syntax to make something readonly in C#, while not having an easy syntax for making it mutable. On the other
hand, the shortest syntax in a class record type is to create an immutable property, and it might be confusing if
we had differing behaviors between record classes and record structs.
We did not come to a conclusion on this topic today. A general read of the room has a _slight_ lean towards keeping
the behavior consistent with record classes, but a number of members are undecided as there are good arguments in
both directions. We will revisit this topic in a future meeting after having some time to mull over the options here.

View file

@ -0,0 +1,71 @@
# C# Language Design Meeting for October 5th, 2020
## Agenda
1. [`record struct` primary constructor defaults](#record-struct-primary-constructor-defaults)
2. [Changing the member type of a primary constructor parameter](#changing-the-member-type-of-a-primary-constructor-parameter)
3. [`data` members](#data-members)
## Quote of the Day
- "The problem with people who voted for immutable by default is that they can't change their opinion. #bad_dad_jokes"
## Discussion
### `record struct` primary constructor defaults
We picked up today where we left off [last time](LDM-2020-09-30.md#primary-constructors-and-data-properties), looking at what
primary constructors should generate in `record struct`s. We have 2 general axes to debate: whether we should generate mutable
or immutable members, and whether those members should be properties or fields. All 4 combinations of these options are valid
places that we could land, with various pros and cons, so we started by examing the mutable vs immutable axis. In C# 9, `record`
primary constructors mean that the properties are generated as immutable, and consistency is a strong argument for preferring
immutable in structs. However, we also have another analogous feature in C#: tuples. We decided on mutability there because it's
more convenient, and struct mutability does not carry the same level of concern as class mutability does. A struct as a
dictionary key does not risk getting lost in the dictionary unless it itself references mutable class state, which is just as
much of a concern for class types as it is for struct types. Even if we had `with` expressions at the time of tuples, it's
likely that we still would have had the fields be mutable. A number of C# 7 features centered around reducing unnecessary struct
copying, such as `readonly` members and ref struct improvements, and reducing copies in large structs by `with` is still a
useful goal. Finally, we have a better story for making a `struct` fully-`readonly` with 1 keyword, while we don't have a similar
story for making a `struct` fully-mutable with a similar gesture.
Next, we examined the question of properties vs fields. We again looked to our previous art in tuples. `ValueTuple` can be viewed
as an anonymous struct record type: it has value equality and is used as a pure data holder. However, `ValueTuple` is a type
defined in the framework, and its implementation details are public concern. As a framework-defined pure data holder, it has no
extra behavior to encapsulate. A `record struct`, on the other hand, is not a public framework type. Much like any other user-
defined `class` or `struct`, the implementation details are not public concern, but the concern of the creator. We have real
examples in the framework (such as around the mathematics types) where exposing fields instead of properties was later regretted
because it limits the future flexibility of the type, and we feel the same level of concern applies here.
#### Conclusion
Primary constructors in `record struct`s will generate mutable properties by default. Like with `record` `class`es, users will
be able to provide a definition for the property if they do not like the defaults.
### Changing the member type of a primary constructor parameter
In C# 9, we allow `record` types to redefine the property generated by a primary constructor parameter, changing the accessibility
or the accessors. However, we did not allow them to change whether the member is a field or property. This is an oversight, and
we should allow changing whether the member is a field or property in C# 10. This will allow overriding of the default decision
in the first section, giving an ability for a "grow-up" story for tuples into named `record struct`s with mutable fields if the
user wishes.
### `data` members
Finally today, we took another look at `data` members, and what behavior they should have in `record struct`s as opposed to
`record` `classes`. We had previously decided that `data` members should generate `public` `init` properties in `record` types;
therefore, the crucial thing to decide is if `data` should mean the same thing as `record` would in that type, or if the `data`
keyword should be separated from `record` entirely. In C# today, we have very few keywords that change the code they generate
based on containing type context, and making `data` be dependent on whether the member is in a `struct` or `class` could end up
being quite confusing. On the other hand, if `data` is "the short way to create a nominal record type", then having different
behavior between positional parameters and `data` members in a `struct` could also be confusing.
#### Conclusion
We did not reach a decision on this today. There are 3 proposals on the table:
1. A `data` member is `public string FirstName { get; set; }` in `struct` types, and `public string FirstName { get; init; }` in
`class` types.
2. A `data` member is `public string FirstName { get; init; }` in all types.
3. We cut `data` entirely.
We'll come back to this in a future LDM.

View file

@ -0,0 +1,103 @@
# C# Language Design Meeting for October 7th, 2020
## Agenda
1. [`record struct` syntax](#record-struct-syntax)
2. [`data` members redux](#data-members-redux)
3. [`ReadOnlySpan<char>` patterns](#readonlyspanchar-patterns)
## Quote of the Day
- "And we're almost there (famous last words, I'll knock on something)"
- "What about `record delegate`... does `record interface` make sense... I'll go away now"
## Discussion
### `record struct` syntax
First, we looked at what syntax we would use to specify `struct` types that are records. There are two possibilities:
```cs
record struct Person;
struct record Person;
```
In the former, `record` is the modifier on a `struct` type. In the latter, `struct` is the modifier on `record` types.
We also considered whether to allow `record class`.
#### Conclusion
By unanimous agreement, `record struct` is the preferred syntax, and `record class` is allowed. `record class` is
synonymous with just `record`.
### `data` members redux
With `data`, we come back to the same question we had at the end of [Monday](LDM-2020-10-05.md#data-members): should we have
`data` members, and if we do, what should they mean. `data` can be viewed as a strategy to try and get nominal records in a
single line, much like positional records. This is not a goal of brevity just for brevity's sake: in discriminated unions,
listing many variants as nominal records is a design goal, and single-line declarations are particularly useful for this case.
Many languages with discriminated unions based on inheritance introduce short class-declaration syntax for use in union
declarations, and that was a defining goal for where `record` types would be useful.
Another area worth examining is the original proposal for the `data` keyword. In the original proposal, primary constructors
would have meant the same thing in `record` types as well non-`record` types, and `data` would have been used as a modifier
on the primary constructor parameter to make it a public get/init property. `data` applied to a member, then, would have been
a natural extension and reuse of that keyword. With the original scenario gone, there are a few concrete scenarios we think
are highly related to, and will influence, the `data` keyword:
1. Use as a single-line in a discriminated union. While this is motivating, it's worth considering that, at least to some LDT
members, anything more than 2 properties as `data` members doesn't look great, and would perhaps work better as a multi-line
construct, which will line up visually. This seems a reasonable concern, so `data` may not be the solution we're looking for.
2. Use in required properties, as it seems likely that we will need some keyword to indicate that a property is a required
member in a type. While `data` could be orthogonal to some other required property keyword, it's likely there will be at least
some interaction as we'd likely want `data` to additionally imply required. It's also possible that we could have just a single
keyword to mark a property required, and it gives you what we believe are the useful defaults for such a property.
3. Use in general primary constructors as a way to say "give me the same thing a `record` would have for this parameter". This
would be somewhat resurrecting the original use case for the keyword, as we could then retcon `record` primary constructors
as implying `data` on all parameters for you, but you can then opt-in to them in regular primary constructors as well. `data`
members in a class, then, would again become a natural reuse and extension of the keyword on a primary constructor parameter.
#### Conclusion
We'll leave `data` out of the language for now. Our remaining motivating scenarios are things that will be worked on more in
C# 10 cycle, and absent clearer designs in those spaces the need and design factors for `data` are too abstract. Once we work
more on these 3 scenarios, we'll revisit `data` and see if a need for it has emerged.
### `ReadOnlySpan<char>` patterns
https://github.com/dotnet/csharplang/issues/1881
We have a community PR to implement the Any Time feature of allowing constant strings to be used to pattern match against
a `ReadOnlySpan<char>`. This would be acknowledging special behavior for `ReadOnlySpan<char>` with respect to constant strings,
but we already have acknowledged special behavior for `Span` and `ReadOnlySpan` in the language, around `foreach`. We also
considered whether this could be a breaking change, but we determined it could not be one: `ReadOnlySpan` cannot be converted
to `object` or to an interface as it is a ref struct, so if there exists a pattern today operating on one today the input type
of that pattern match must be `ReadOnlySpan<char>`. There were two open questions:
#### Should we allow `Span<char>`
The question is if `Span<char>` should also be allowed as well as `ReadOnlySpan<char>`. All of the same arguments about
compat apply to `Span<char>`. We also considered whether `Memory`/`ReadOnlyMemory` should be allowed inputs. Unlike `Span`/`ReadOnlySpan`,
though, there are backcompat concerns with `Memory` that cannot be overlooked, as they are not ref structs. It is very
easy to obtain a `Span`/`ReadOnlySpan` from a `Memory`/`ReadOnlyMemory`, however, so the need isn't as great.
##### Conclusion
`Span<char>` is allowed. `Memory<char>`/`ReadOnlyMemory<char>` are not.
#### Is this specific to `switch`, or can it be any pattern context
The original proposal here just mentioned `switch`. However, the implementation allows it to be used in any pattern context,
such as `is`.
##### Conclusion
Allowed in all pattern contexts.
#### Final Notes
We also discussed making sure that switching on a `Span`/`ReadOnlySpan` is as efficient for large switch statements as switching
on a string is. Over 6 cases, the compiler will take the hashcode of the string and use it to implement a jump table to reduce the
number of string comparisons necessary. This method is added to the `PrivateImplementationDetails` class in an assembly, and we
should make sure to do the same thing for `Span<char>` and `ReadOnlySpan<char>` here as well so the cost to using one isn't higher
than allocations would be from just doing a substring and matching with that.

View file

@ -0,0 +1,57 @@
# C# Language Design Meeting for October 12th, 2020
## Agenda
1. General improvements to the `struct` experience (continued)
## Quote of the Day
- "Only 5 people are going to use it..."
- "We said that about function pointers too."
## C# Community Ambassadors
We have been taking a look at https://github.com/dotnet/csharplang/discussions/3878, which is around how to help community
proposals into better shape to be looked at by LDM. We largely agree with the points raised, which is that most community
issues are in a state that isn't quite good enough to be sponsored by an LDT member, but also not controversial or generally
discouraged enough to be outright rejected. Our move to enabling discussions on the repo itself was the first step in this
direction: discussions are more free-form, allow multiple branching conversations, and we view them as having less requirements
towards creating one. The next step we're taking today is nominating a few community members to become ambassadors to the
community: @jnm2, @YairHalberstadt, and @svick. This role will be focussed around helping triage incoming issues and
discussions, helping community members get their proposals into a state that can realistically be looked at by LDT members
and potentially championed, and helping with deduplication as it is noticed. We're starting very small with this experiment:
if it proves successful, we can consider expanding the list to more members of the csharplang community, of which there are
several deserving candidates. As part of this, we're tentatively hoping to review promising community proposals at a more
regular cadence, hopefully monthly.
Community ambassadors are not members of the LDT and do not have the ability to champion issues. They will help us look at
deserving community proposals, and we value their input, as we value the input of the general community here.
## Discussion
Today, we finished going through the fixed fields proposal, found [here](https://github.com/dotnet/csharplang/blob/master/proposals/low-level-struct-improvements.md).
[Previously](LDM-2020-09-23.md), we made it through the `Provide ref fields` section of the specification. Today, we
finished going through the rest. Again, most the conversation was dedicated to the specification itself, but there were
a few points brought up that will be updated in the specification later:
* `ThisRefEscapes` is defined very narrowly in this proposal, not allowed on any virtual methods (including methods from
interfaces). In our initial investigations, we don't see a huge need for allowing it on interface methods. We can consider
this in the future if it ends up being a friction point, but will need a good amount of work around ensuring that OHI is
correctly respected.
* We considered the issue of whether we should use syntax for `ThisRefEscapes` and `DoesNotEscape`, and nearly-unanimously
decided on using attributes. Attributes allow us to have a more descriptive name that users are less likely to accidentally
use. Further, all this attribute is controlling is a `modreq`, not the actual implementation of the method. We have existing
attributes such as `SpecialNameAttribute` that control emit flags like this, so it's not unprecedented.
* The syntax for fixed buffer locals is actually quite generally attractive: it would be nice if we could remove the requirement
for specifying `fixed` in fields. It would further simplify the language: we even have parser code that parses this form today
so that we can give nicer errors to people coming from C/C++. It would further resolve an ambiguity: in the proposal today, old-
style fixed-size buffers are differentiated from new-style by whether or not the field is in an unsafe context: by omitting the
fixed, we have a completely different syntax that is unambiguous.
* We don't believe there is any real motivating scenario for either fixed multi-dimensional arrays or fixed jagged arrays of a
specific inner length. Jagged arrays of this form would work: `int[] array[10]`, where you have a fixed buffer of array references,
but allocating the inner array as part of the containing structure itself isn't currently seen as an important scenario.
Multidimensional arrays today need to call into CLR helper methods today and are generally slower. We can think about this later
if a scenario comes up.
* We might want to make "inline array" a first-class type in the CLR. This would allow for things such as substituting in type
parameters. This will largely be driven by the CLR design here.

View file

@ -0,0 +1,138 @@
# C# Language Design Meeting for October 14th, 2020
## Agenda
1. [Triage](#triage)
1. [Repeated Attributes in Partial Members](#repeated-attributes-in-partial-members)
2. [Permit a fixed field to be declared inside a readonly struct](#permit-a-fixed-field-to-be-declared-inside-a-readonly-struct)
3. [Do not require fixing a fixed field of a ref struct](#do-not-require-fixing-a-fixed-field-of-a-ref-struct)
4. [params Span<T>](#params-spant)
5. [Sequence Expressions](#sequence-expressions)
6. [utf8 string literals](#utf8-string-literals)
7. [pattern-based `with` expressions](#pattern-based-with-expressions)
8. [Property improvements](#property-improvements)
9. [File scoped namespaces](#file-scoped-namespaces)
10. [Discriminated Unions](#discriminated-unions)
11. [Efficient params and string formatting](#efficient-params-and-string-formatting)
12. [Allow omitting unused parameters](#allow-omitting-unused-parameters)
2. [Milestone Simplification](#milestone-simplification)
## Quote of the Day
- "I used to have a fidget cube, but then [redacted] took away my fidget cube because it was apparently a very annoying device for everyone else"
## Discussion
### Triage
#### Repeated Attributes in Partial Members
https://github.com/dotnet/csharplang/issues/3658
We discussed this briefly at the tail-end of C# 9 work, and came to the conclusion this is an issue for source generator authors and that we wanted
to make it work. Triaged into the working set.
#### Permit a fixed field to be declared inside a readonly struct
https://github.com/dotnet/csharplang/issues/1793
This is part of the feature we discussed Monday. Triage into the working set.
#### Do not require fixing a fixed field of a ref struct
https://github.com/dotnet/csharplang/issues/1792
We generally like the idea of this feature: language-wise it's small, makes sense, and is an annoyance for users of ref structs. However, the
implementation of `fixed` in Roslyn has historically been an issue with a long bug trail coming every time we need to make a change. We think
this makes sense the next time we need to a larger feature around fixed that would force us to refactor the handling of `fixed` in the compiler.
Until then, we don't think the implementation cost is worth it. Triaged to the backlog.
#### params Span<T>
https://github.com/dotnet/csharplang/issues/1757
We like this feature. We'll need to carefully design the overload resolution rules such that it wins out over existing params arrays. Libraries
can then intentionally opt-in by introducing `Span<T>` overloads, just like they can introduce any new overload today that causes a change in
behavior when recompiled. Triaged into the working set.
#### Sequence Expressions
https://github.com/dotnet/csharplang/issues/377
Related to #3038, #3037, and #3086, which are all in the working set. We'll be taking a look at the whole scenario in the upcoming design period,
so this is triaged into the working set with the others.
#### utf8 string literals
https://github.com/dotnet/csharplang/issues/184
We need the runtime to make progress here. While we could consider ways to make it easier to declare constant utf-8 byte arrays, we feel that
would likely box us in when the runtime wants to move forward in this area. When they're ready, we can put this back on the agenda. Triaged
into the backlog.
#### pattern-based `with` expressions
https://github.com/dotnet/csharplang/issues/162
This is part of the next round of record work, so into the working set it goes. We may need to think about how general object might be able to
do object reuse as part of a `with` (Roslyn would not be able use it to replace `BoundNode.Update` as spec'd for records, for example), so that
is a scenario we need to keep in mind as we generalize.
#### Property improvements
https://github.com/dotnet/csharplang/issues/133
https://github.com/dotnet/csharplang/issues/140
We've discussed these recently in LDM. We're moving forward with design, starting with #133. Triaged into the working set.
#### File scoped namespaces
https://github.com/dotnet/csharplang/issues/137
Triaged into the working set. We'll need to come up with a more complete proposal than we have currently, particularly considering how it will
interact with top-level statements, but it doesn't seem too difficult.
#### Discriminated Unions
https://github.com/dotnet/csharplang/issues/113
This is one of the next big C# tent poles we're looking to address, and we're working on an updated proposal after having some time to ruminate
on the previous proposals in the area and post initial records. We have lots of design work to do, so into the working set it goes.
#### Efficient params and string formatting
https://github.com/dotnet/csharplang/issues/2302
Interpolated strings are a pit of failure in certain scenarios, such as logging, where formatting costs are incurred up front even if they're
not needed. We'll keep this in the working set to keep iterating on proposals. We know we want to do some work here, but we're not sure exactly
how it will function yet.
#### Allow omitting unused parameters
https://github.com/dotnet/csharplang/issues/2180
We had some initial questions around the metadata representation of discards: should the be nameless, for example? We generally like proposals
that put discards in more places, and we're willing to look at a complete proposal if one is presented. Triaged to any time.
### Milestone Simplification
Today, we have quite a few milestones that mean various things at various points in time, and it's hard for outsiders to keep track of what is
on track for what. This is further complicated by the fact that sometimes things are just not known: we could be working on a feature with every
intention to put it in the next version of C#, but fully acknowledging it might not make it. Or we may be doing design work for a feature that
we know _definitely_ will not make it into the next version of C#, but needs to have work done or we'll never get it at all. For this reason,
we're simplifying our milestones to be more clear about what the state of things is:
* Working Set is the set of proposals that the LDT is currently actively working on. Not everything in this milestone will make the next version
of C#, but it will get design time during the upcoming release.
* Backlog is the set of proposals that members of the LDT have championed, but are not actively working on. While discussion and ideas from the
community are welcomed on these proposals, the cost of the design work and implementation review on these features is too high for us to consider
community implementation until we are ready for it.
* Any Time is the set of proposals that members of the LDT have championed, but are not being actively worked on and are open to community
implementation. We'll go through these shortly and label the ones that need to have a specification added vs the ones that have an approved spec
and just need implementation work. Those that need a specification still need to be presented during LDM for approval of the spec, but we are
willing to take the time to do so at our earliest convenience.
* Likely Never is the set of proposals that the LDM has reject from the language. Without strong need or community feedback, these proposals will
not be considered in the future.
* Numbered milestones are the set of features that have been implemented for that particular language version. For closed milestones, these are
the set of things that shipped with that release. For open milestones, features can be potentially pulled later if we discover compatability or
other issues as we near release.

View file

@ -0,0 +1,132 @@
# C# Language Design Meeting for October 21st, 2020
## Agenda
1. [Primary Constructors](#primary-constructors)
2. [Direct Parameter Constructors](#direct-parameter-constructors)
## Quote of the Day
- "Hopefully Seattle doesn't wash into the ocean"
## Discussion
### Primary Constructors
https://github.com/dotnet/csharplang/discussions/4025
We started today by examining the latest proposal around primary constructors, and attempting to tease out the possible
behaviors of what a primary constructor could mean. Given this sample code:
```cs
public class C(int i, string s) : B(s)
{
...
}
```
there are a few possible behaviors for what those parameters mean:
1. Parameter references are only allowed in initialization contexts. This means you could assign them to a property, but
you couldn't use them in a method that runs after the class has been initialized.
2. Parameter references are allowed throughout the class, and if they're referenced from a non-initialization context then
they are captured in the type, but are not considered fields from a language perspective. This is the proposed behavior in
the linked discussion.
3. Parameter references are automatically captured to fields of the same name.
We additionally had a proposal in conjunction with behavior 1: You can opt in to having a member generated by adding an
accessibility to the parameter. So `public class C(private int i)` would generate a private field `i`, in addition to having
a constructor parameter. This is conceivably not tied to behavior 1 however, as it could also apply to behavior 2 as well.
It would additionally need some design work around what type of member is generated: would `public` generate a field or a
property? Would it be mutable or immutable by default?
To try and come up with a perferred behavior here, we started by taking a step back and examining the motivation behind
primary constructors. Our primary (pun kinda intended) motivation is that declaring a property and initializing it from
a constructor is a boring, repetitive, boilerplate-filled process. You have to repeat the type twice, and repeat the name
of the member 4 times. Various IDE tools can help with generating these constructors and assignments, but it's still a lot
of boilerplate code to read, which obscures the actually-interesting bits of the code (such as validation). However, it is
_not_ a goal of primary constructors to get to 1-line classes: we feel that this need is served by `record` types, and that
actual classes are going to have some behavior. Rather, we are simply trying to reduce the overhead of describing the simple
stuff to let the real behavior show through more strongly.
With that in mind, we examined some of the merits and disadvantages of each of these:
1. We like that parameters look like parameters, and adding an accessibility makes it no longer look like a parameter. There's
definitely a lot to debate on what that accessibility should actually do though. There are some concerns that having the
parameter not be visible is non-obvious to users: to solve this, we could make then visible throughout the type, but have it
be an error to reference in a location that is not an initialization context (and a codefix to add an accessibility to make
it very easy to fix). This allows users to be very explicit about the lifetime of variables.
2. This variation of the proposal might feel more natural to users, as the variable exists in an outer "scope" and is therefore
visible to all inner scopes. There is some concern, however, that silent captures could mean that the state of a class is no
longer visible: you'll have to examine all methods to determine if a constructor parameter is captured, which could be suboptimal.
3. This the least flexible of the proposals, and wasn't heavily discussed. It would need some amount of work to fit in with the
common autoprop case, where the others could work without much work (either via generation or by simple assignment in an
initializer for the autoprop).
In discussing this, we brought another potential design: we're considering primary constructors to eliminate constructor boilerplate.
What if we flipped the default, and instead generated a constructor based on the members, rather than generating potential members
based on a constructor. A potential strawman syntax would be something like this:
```cs
// generate constructor and assignments for A and B, because they are marked default
public class C
{
default public int A { get; }
default public string B { get; }
}
```
There are a bunch of immediate questions around this: how does ordering work? What if the user has a partial class? Does this
actually solve the common scenario? While we think the answer to this is no, it does bring up another proposal that we
considered in the C# 9 timeframe while considering records: Direct Parameter Constructors.
## Direct Parameter Constructors
https://github.com/dotnet/csharplang/issues/4024
This proposal would allow constructors to reference members defined in a class, and the constructor would then generate a matching
parameter and initialization for that member in the body of the constructor. This has some benefits, particularly for class types:
* Many class types have more than one constructor. It's not briefer than primary constructors declaring members for a class with
just one constructor, but it does get briefer as you start adding more constructors.
* We believe, at least from our initial reactions, that this form would be easier to understand than accessibility modifiers on the
parameters.
There are still some open questions though. You'd like to be able to use this feature in old code, but if we don't allow for customizing
the name of the parameter, then old code won't be able to adopt this for properties, as properties will almost certainly have different
casing than the parameters in languages with casing. This isn't something we can just special case for the first letter either: there
are many examples (even in Roslyn) of identifiers that have the first two letters capitalized in a property and have them both lowercase
in a parameter (such as `csharp` vs `CSharp`). We briefly entertained the idea of making parameter names match in a case-insensitive
manner, but quickly backed away from this as case matters in C#, working with casing in a culture-sensitive way is a particularly hard
challenge, and wouldn't solve all cases (for example, if a parameter name is shortened compared to the property).
We also examined how this feature might interact with the accessibility-on-parameter proposal in the previous section. While they are
not mutually exclusive, several members of the LDT were concerned that having both of these would add too much confusion, giving too
many ways to accomplish the same goal. A read of the room found that we were unanimously in favor of this proposal over the accessibility
proposal, and there were no proponents of adding both proposals to the language.
Finally, we started looking at how initialization would work with constructor chaining. Some example code:
```cs
public class Base {
public object Prop1 { get; set; }
public virtual object Prop2 { get; set; }
public Base(Prop1, Prop2) { Prop2 = 1; }
}
public class Derived : Base
{
public new string Prop1 { get; set; }
public override object Prop2 { get; set; }
public Derived(Prop1, Prop2) : base(Prop1, Prop2) { }
}
```
Given this, the question is whether the body of `Derived` should initialize `Prop1` or `Prop2`, or just one of them, or neither of them.
The simple proposal would be that passing the parameter to the base type always means the initialization is skipped, but that would
mean that the `Derived` constructor has no way to initialize the `Prop1` property, as it can no longer refer to the constructor parameter
in the body, and `Base` certainly couldn't have initialized it (since it is not visible there). There are a few questions like this that
we'll need to work out.
## Conclusions
Our conclusions today are that we should pursue #4024 in ernest, and come back to primary constructors with that in mind. Several members
are not convinced that we need primary constructors in any form, given that our goal is not around making regular `class` types have only
one line. Once we've ironed out the questions around member references as parameters, we can come back to primary constructors in general.

View file

@ -0,0 +1,109 @@
# C# Language Design Meeting for October 26st, 2020
## Agenda
1. [Pointer types in records](#pointer-types-in-records)
2. [Triage](#triage)
1. [readonly classes and records](#readonly-classes-and-records)
2. [Target typed anonymous type initializers](#target-typed-anonymous-type-initializers)
3. [Static local functions in base calls](#static-local-functions-in-base-calls)
## Quote of the Day
- "And I specialize in taking facetious questions and answering them literally"
## Discussion
### Pointer types in records
Today, you cannot use pointer types in records, because our lowering will use `EqualityComparer<T>.Default`, and pointer
types are not allowed as generic type arguments in general. We could specially recognize pointer types here, and use a
different equality when comparing fields of that type. We have a similar issue with anonymous types, where pointers are
not permitted for the same reason (and indeed, Roslyn's code for generating the equality implementation is shared between
these constructs). We would also need consider every place record types can be used if we enabled this: for example, what
would the experience be when attempting to pattern deconstruct on a record type, as pointer types are not allowed in patterns
today? It also might not be a good idea to introduce value equality based on pointer types to class types, as this is not
well-defined for all pointer types (function pointers, for example). Finally, the runtime has talked several times about
enabling pointer types as generic type parameters, and if they were to do so then the rules for this might fall out at that
time.
#### Conclusion
Triaged to the Backlog. We're not convinced this needs to be something that we enable right now, and may end up being resolved
by fallout from other changes.
### Triage
#### readonly classes and records
https://github.com/dotnet/csharplang/issues/3885
This proposal would allow marking a class type `readonly`, ensuring that all fields and properties on the type must be `readonly`
as well. Several familiar questions were immediately raised, namely around the benefit. `readonly` has a very specific benefit
for struct types, around allowing the compiler to avoid defensive copies where they would otherwise be necessary. For
`readonly` classes, there is no clear similar advantage. We might not even emit such information to metadata, and the main
benefit would be for type authors, not for type consumers. There is also some concern about whether this would be confusing to
users, particularly if this does not apply to an entire hierarchy. If you depend on a non-Object base type that has mutable,
then the benefits of using `readonly` are not as clear, even for a type author. Similarly, if a non-`readonly` type can inherit
from a `readonly` type, that means that any guarantees on the current type aren't very strong, as mutation can occur under the
hood anyway. `readonly` in C# today always means shallow immutability, so there is an argument to be made that this level of
hierarchy-mutability is not too different.
We also looked at the question of whether this feature should just be analyzer. There is certainly argument for that: particularly
if there is no hierarchy impact, it seems a perfect use case for an analyzer. However, this is a case where we allow the keyword
on one set of types, while not allowing it on a different set of types. Further, unlike many such proposals, we already have a
C# keyword that is perfect for the scenario.
##### Conclusion
Triaged into the Working Set. We'll look at this with low priority, and particularly try to see what the scenarios around
hierarchical enforcement look like, as those were more generally palatable to LDT members.
#### Target typed anonymous type initializers
https://github.com/dotnet/csharplang/issues/3957
This is a proposal to address some cognitive dissonance we have with object creation in C#: you can leave off the parens if you
have an object initializer, but only if you specify the type. While it does save 2 characters, that is not a primary motivation
of this proposal. There are grow-up stories for other areas we could explore in this space as well: we could allow F#-style
object expressions, for example, or borrow from Java and allow anonymous types to actually inherit from existing types/interfaces.
However, we have a number of concerns about the compat aspects of doing this, where adding a new `object` overload can silently
change consumer code to call a different overload and create an anonymous type. In these types of scenarios, it might even be
impossible to determine if the user made an error: if they typed a wrong letter in the property name, for example, we might be
forced to create an anonymous type silently, instead of erroring on the invalid object initializer.
We also briefly considered more radical changes to the syntax: for example, could we allow TS/JS-style object creation, with
just the brackets? However, this idea was not very well received by the LDM.
##### Conclusion
Triaged into the Backlog. While we're open to new proposals in this space that significantly shift the bar (such as around new
ways of creating anonymous types that inherit from existing types), we think that this proposal could end up conflicting with
any such future proposals and should be considered then.
#### Static local functions in base calls
https://github.com/dotnet/csharplang/issues/3980
This is a proposal that, depending on the exact specification, would either be a breaking change or have complicated lookup rules
designed to avoid the breaking change. It also requires some deep thought into how the exact scoping rules would work. Today,
locals introduced in the `base` call are visible throughout the constructor, so we would have to retcon the scoping rules to
work something like this:
1. Outermost scope, contains static local functions
2. Middle scope, contains the base clause and any variables declared there
3. Inner scope, contains the method body locals and regular local functions.
This also raises the question of whether we should stop here. For example, it might be nice if `const` locals could be used as
parameter default values, or if attributes could use names from inside a method body. We've had a few proposals for creating
various parts of a "method header" scope (such as https://github.com/dotnet/csharplang/issues/373), we could consider extending
that generally to allow this type of thing. Another question would be: why stop at `static` local functions? We could allow
regular local functions in the base clause, and leverage definite assignment to continue doing the same things it does today to
make sure that things aren't used before assignment. This might work well with a general "method header" scope, instead of the
scheme proposed above. Finally, we considered simply allowing the `base` call to be done in the body of the constructor instead,
a la Visual Basic. This has some support, and would allow us to avoid the question of a method header scope by simply allowing
users to move the base call to where the local function is visible.
##### Conclusion
Triaged into the Working Set. We like the idea, and have a few avenues to explore around method header scopes or allowing the
base call to be moved.

View file

@ -0,0 +1,60 @@
# C# Language Design Meeting for November 4th, 2020
## Agenda
1. [Nullable parameter defaults](#nullable-parameter-defaults)
2. [Argument state after call for AllowNull parameters](#argument-state-after-call-for-allownull-parameters)
## Quote of the Day
No particularly amusing quotes were said during this meeting, sorry.
## Discussion
### Nullable parameter defaults
https://github.com/dotnet/csharplang/pull/4101
We started today by examining some declaration cases around nullable that we special cased in our our initial implementation, but
felt that we should re-examine in light of `T?`. In particular, today we do not warn when you create a method signature that assigns
`default` to `T` as a default value. This means that it's possible for generic substitution to cause bad method signatures to be
created, where a `null` is assigned to a non-nullable reference type. The proposal, then, is to start warning about these cases, in
both C# 8 and 9. In C# 8, the workaround is to use `AllowNull` on that parameter, and C# 9 would allow `T?` for that parameter. There
was no pushback to this proposal.
As part of this, we also considered the other locations in this example. For example, we could issue a warning at the callsite of such
a method. The proposal would be to expand the warnings on nullable mismatches in parameters to implicit parameters as well. This could
end up causing double warning, if both the method and the callsite get a warning here, but it might be able to help users who are using
otherwise unannotated methods, or libraries compiled with an older version of the compiler that did not warn here. There is some
concern, though, that putting a warning at the callsite is the wrong location. It was the method author that created this invalid
signature, and we'd be punishing users with additional warnings. Presumably, if the author allows `null`, they're appropriately
handling it, even if the code is still oblivious or in an older version of C#.
#### Conclusion
The original proposal is approved. We'll continue looking at the callsite proposal as an orthogonal feature and come back when we have
a complete proposal to review.
### Argument state after call for AllowNull parameters
https://github.com/dotnet/csharplang/discussions/4102
https://github.com/dotnet/roslyn/issues/48605
Next, we looked at fallout over a previous decision to update the state of variables passed as parameters to a method. This allowed us
to bring the behavior of `void M([NotNull] string s)` and `void M(string s)` in line, which caused issues for the BCL (as it meant
that any change to add `NotNull` to a parameter would be a good change to make, and they were not interested in updating thousands of
methods to do this). However, it caused an unfortunate side effect: `void M([AllowNull] string s)` would have no warnings, and would
silently update the parameter state to not null, even though there was absolutely no way `M` could have affected the input argument as
it was not passed by ref. We considered 2 arguments for this:
1. Perhaps the method isn't annotated correctly? The real-world example here is `JsonConvert.WriteJson`, and there is an argument to be
made that in C# 9, this parameter would just be declared as `T?`, solving the issue. However, it does feel somewhat obvious that this
method shouldn't update the state of the parameter.
2. We loosen the "effective" resulting type of the parameter based on the precondition, if the parameter is by-value. `[AllowNull]` would
loosen the effective resulting type to `T?`, which would not make any changes to the current state of the argument. We might also do the
inverse for `DisallowNull`.
#### Conclusion
We ran out of time today, but are interested in approach 2 above. We'll come back with a complete proposal for a future LDM and examine it
again.

View file

@ -0,0 +1,127 @@
# C# Language Design Meeting for November 11th, 2020
## Agenda
1. [IsRecord in metadata](#isrecord-in-metadata)
2. [Triage](#triage)
1. [AsyncMethodBuilder](#asyncmethodbuilder)
2. [Variable declarations under disjunctive patterns](#variable-declarations-under-disjunctive-patterns)
3. [Direct constructor parameters](#direct-constructor-parameters)
4. [Always available extension methods](#always-available-extension-methods)
5. [Allow `nameof` to access instance members from static contexts](#allow-nameof-to-access-instance-members-from-static-contexts)
6. [Add `await` as a dotted postfix operator](#add-await-as-a-dotted-postfix-operator)
## Quote of the Day
- "Alright, I'm going to make an analogy to social security here."
## Discussion
### IsRecord in metadata
https://github.com/dotnet/csharplang/issues/4121
We discussed a few different ways to tackle this issue, which relates to customers depending on the presence of the `<Clone>$` method
as a way of determining if a type is a `record` or not. First, there are theoretically some ways we could retrofit this method to work
as an identifying characteristic, such as by marking `<Clone>$` methods on non-record types, instead of marking the record types in
some manner. However, this approach would have to square with `struct` records, which may or may not have that special method. We also need
to understand some of the dependent scenarios better: we understand the IDE scenario pretty well, we want to be able to have QuickInfo
and metadata-as-source reflect the way the type was declared. However, we don't have an understanding of the EF scenario, and what it
would want to do for, say, a non-record class that inherits from a record type. Finally, we considered time frames, and came to the
conclusion that the proposed solution would work fine if we wait until C# next to introduce it, and does not require being rushed out the
door to be retconned into C# 9: the proposed solution is backwards compatible, as long as it is introduced at the same time as
class/record cross inheritance.
#### Conclusion
Into the Working Set, we'll consider this issue in conjunction with class/record cross-inheritance.
### Triage
#### AsyncMethodBuilder
https://github.com/dotnet/csharplang/issues/1407
We generally like this proposal, as it solves a real need in the framework while creating a generalized feature that can be plugged into
more libraries. We did have a couple of questions come up:
1. Should we allow this on just the method, or also the type/module level? This seems to be similar to `SkipLocalsInit`, and could be
tedious to rep-specify everywhere.
2. Can this solve `ConfigureAwait`? We don't think so: this controls the method builder, not the meaning of `await`s inside the method,
so while it could potentially change whether a method call returns a task that synchronizes to the thread context by default, it could
only do that for methods defined in your assembly, which would just lead to confusing behavior.
##### Conclusion
Triaged into the Working Set, we'll work through the proposal in a full LDM session soon.
#### Variable declarations under disjunctive patterns
https://github.com/dotnet/csharplang/issues/4018
We like this proposal. There are a couple of open issues/questions that need to be addressed:
1. We need a rule that says when you are allowed to redeclare existing variables. It needs to cover multiple switch case labels, while
also not permitting things declared outside the switch label to be redeclared.
2. How identical do the types need to be? Are nullability differences permitted? ie, are `(object?, object)` and `(object, object?)` the
same for the purposes of this feature? It seems like they may have to be.
##### Conclusion
Triaged into the Working Set. We'll take some time and consider these questions, and we should also consider alternatives at the same time,
such as an `into` pattern that would allow a previously-declared variable to be assigned in a pattern, including ones declared outside a
pattern.
#### Direct constructor parameters
https://github.com/dotnet/csharplang/issues/4024
We discussed this feature during our last look at primary constructors, and our conclusion is that we need to explore the space more fully
with both features in mind. There are concerns about abstraction leaks, particularly with property casing.
##### Conclusion
Triaged into the Working Set, to be considered in conjunction with primary constructors.
#### Always available extension methods
https://github.com/dotnet/csharplang/issues/4029
There was some strong negative reaction to this proposal. However, presented another way it's more interesting: users who use `var` need
to include `using`s they otherwise do not need in order to access these types of extension methods, whereas users who do not use `var`
will already have the relevant `using` in scope, and will thus see these extension methods. These types of methods are also often ways of
working around various C# limitations, such as lack of specialization, and would naturally be defined on the type itself if it was possible.
We are concerned with doing anything in this space with extension everything/roles/type classes on the horizon, as we don't want to change
extension methods in a way that we'd regret with those features.
##### Conclusion
Triaged into the backlog. We'll consider this in conjunction with extension everything.
#### Allow `nameof` to access instance members from static contexts
https://github.com/dotnet/csharplang/issues/4037
There is some feeling that this is basically just a bug in the spec (or is just an area where it's not super clear, and it's a bug in the
implementation). We do think this is generally good: yes, the scenario could just use `string.Length`, but that is not really what the user
intended. They wanted the `Length` property on `P`, and if `P` changes to a different type that no longer has `Length`, there should be an
error there. Without this, the cliff that `nameof` tries to solve is just moved further, not removed.
##### Conclusion
Triaged into Any Time. We'd accept a community contribution here: it needs to only permit exactly this scenario, not allow any new types of
expressions in `nameof`.
#### Add `await` as a dotted postfix operator
https://github.com/dotnet/csharplang/issues/4076
The LDT has very mixed reactions on this. While we are sympathetic to the desire to make awaits more chainable, and the `.` can be viewed
as the pipeline operator of the OO world, we don't think this solves enough to make it worth it. Chainability of `await` expressions
isn't the largest issue on our minds with `async` code today: that honor goes to `ConfigureAwait`, which this does not solve. We could go
a step further with this form by making it a general function that would allow `true`/`false` parameters to control the thread context
behavior, but given our mixed reaction to the syntax form as a whole we're not optimistic about the approach. A more general approach that
simplified chaining generally for prefix operators would be more interesting.
##### Conclusion
Rejected. We do like the space of improving `await`, but we don't think this is the way.

View file

@ -0,0 +1,81 @@
# C# Language Design Meeting for November 16th, 2020
## Agenda
1. [Ternary comparison operator](#ternary-comparison-operator)
2. [Nominal and collection deconstruction](#nominal-and-collection-deconstruction)
3. [IgnoreAccessChecksToAttribute](#ignoreaccesscheckstoattribute)
## Quote of the Day
- "If it turns out to be really hard, give it to a smarter compiler dev"
- "The name is not good: It should be the BreakTermsOfServiceAttribute"
## Discussion
### Ternary comparison operator
https://github.com/dotnet/csharplang/issues/4108
This proposal centers around add a bit of syntax sugar to simply binary comparisons, where a user might want to compare 3 objects
for ascending or descending order. Today, the user would have to write `a < b && b < c`, but with this proposal they would just
write `a < b < c`. In order to deal with the potential ambiguities, we'd have to first attempt to bind these scenarios as we would
today, and if that fails then attempt to bind them as this new "relational chaining" form. This feature would need to have a very
specific pattern: if we were to allow `a < b > c`, for example, that could be syntactically ambiguous with a generic, and would need
to keep binding to that as it would today. We therefore are only interested in strictly-ordered comparisons: all comparisons in a
chain should be less-than/less-than-or-equal, or greater-than/greater-than-or-equal, without mixing between the 2 orders. We are
also worried about the compile-time cost of double-binding here, particularly since the most-likely binding will have to be done second,
in order to preserve backwards compatability. We also considered allowing more than 3 objects in such a chain: we like the idea, but
it will require some spec work as it does not just fall out of the current specification.
#### Conclusion
Triaged into Any Time. This needs some specification work to allow the 4 or more operators, which would likely be similar in form to
the null-conditional operator. Additionally, any implementation will have to take steps to address potential perf issues and demonstrate
that it does not adversely affect compilation perf on real codebases.
### Nominal and collection deconstruction
https://github.com/dotnet/csharplang/issues/4082
This feature provides unity between patterns and deconstruction assignment. Today, we have tuple deconstruction assignment, and tuple
patterns. They evolved in the opposite direction: we started with tuple deconstruction assignment, then added general patterns to the
language. We now consider adding nominal deconstruction assignment, to complete the symmetry between the feature sets.
One thing we want to be careful of here is to not go to far down the path of replicating patterns in assignment. A pattern in an `is`
or `switch` forces the user to deal with the case that the pattern did not match, which is not present here. For nominal deconstruction,
we can leverage nullable reference types: the user will get a warning if they attempt to deconstruct an element that could be null. For
list patterns, though, there is no similar level of warning, and we want to be careful of creating a pit of failure that will result in
exceptions at runtime. We are also concerned about some of the aspects of allowing names to be given to outer structures, such as allowing
`var { Range: { Column: column } range } = GetRange();`. This could mix badly with allowing existing variable reuse: in patterns today,
the `{ ... } identifier` syntax always introduces a new variable, which we think would end up being confusing. We very wary of allowing
patterns to match into existing variables because it would introduce side-effects to patterns, which is very concerning. Finally, given
that we haven't yet designed regular list patterns, we think we should hold off on list deconstruction assignment until those are complete,
at which point we should have a discussion around whether we should have them at all.
#### Conclusion
Nominal deconstruction assignment is accepted into the working set. Let's split list deconstruction assignment into a separate issue, which
will be followed up on after list patterns are designed. Open questions exist on whether we should allow names on patterns themselves.
### IgnoreAccessChecksToAttribute
We had a very spirited discussion around this attribute, which is essentially the inverse of `InternalsVisibleToAttribute`. Where IVT
allows an author to grant access to a specific other dll, this allows a specific other dll to grant themselves access to an author. There
are many challenges around this scheme that fundamentally affect the entire ecosystem, and those discussions need to happen at a .NET
ecosystem level, rather than at a language level, even though most of the implementation work will fall on the compiler. Ref assemblies,
for example, do not have internal members today. There also needs to be discussions on how we would enforce the "use at your own risk"
aspect of this feature. We can say that all we want, but at the end of the day if VS were to take a dependency on an internal Roslyn
API that we need to change, it could block shipping until either Roslyn readded the API or the dependency was removed. Given our
experiences with `InternalsVisibleToAttribute` already, we're not certain that this burden of risk will be correctly shouldered by the
ones actually taking on the risk.
#### Conclusion
Tabled for now. Discussion needs to happen at a higher level.
## Working Set Themes
With our discussions today, we have finished working through our current triage backlog! We've collected the various issues and themes
in our working set and created a meta-issue to track them all: https://github.com/dotnet/csharplang/issues/4144. We've locked the issue
to ensure that it stays a clean space. For discussion on a particular topic, please see the topic issue, or create a new discussion.

View file

@ -0,0 +1,75 @@
# C# Language Design Meeting for December 2nd, 2020
## Agenda
1. [Partner scenarios in roles and extensions](#partner-scenarios-in-roles-and-extensions)
## Quote(s) of the Day
- "Have you noticed how similar what you just said is to function pointers?"
- "This is a modern version of COM aggregation." "But in a good way."
## Discussion
### Partner scenarios in roles and extensions
Today, we heard from partner teams on the Azure SDK and on ASP.NET, talking about friction they currently encounter
with some scenarios that might be addressable through roles, extension everything, or potentially some other solution.
#### ASP.NET Feature Collections
ASP.NET models contexts through an aggregation system that allows different services to be composed onto a single `HttpContext`.
For example, adding TLS to a session involves creating a TLS connection, wrapping the existing connection, and adding it
as an available feature to the context. This underlying connection could be one of several types connections: it could be
routed through a socket, or it could be in-process, or any of a number of other connection mechanisms, each with its own set
of properties. It is possible to retrieve each of these sets of features from a `Get` method on the context, but this is
cumbersome and not generally extensible: for their users, it would be nice to be able to expose a view over a context or
connection that exposed the underlying properties.
This scenario seems like a clear-cut use case for roles and extension-everything as we last discussed them. A role could be
used to expose a grouping of properties on an upper layer from a lower layer. In fact, the ASP.NET architecture was designed
with the eventual intention of using extension properties to remove a number of extension methods that they have in place
today to expose these underlying properties from a decorated type. Of the 3 scenarios we discussed today, this seems the
most obviously-addressed by the existing proposal.
#### Azure SDKs
The Azure SDK scenario presents a more interesting challenge. Feature collections were designed with C# in mind, meaning
that both types and type names were thoughtfully designed when creating the API. The Azure SDK (and by extension many
web APIs), by comparison, are designed in a web-first manner. In this context, property _names_ are important, and general
structures of an API are important, but names of these structures are _not_ important. These APIs are often described and
generated using Swagger, which uses JSON to describe the structure of a response. JSON structures can be strongly typed,
of course: the structure itself is the type. But the nested properties of a JSON object, which can be nested objects
themselves, are described entirely in a structural manner, not in a nominal manner as we do in C#. Here, C#'s paradigms
break down, and the SDK teams run into trouble when creating a C# API to wrap this structure. All of these nested structures
need to be named, so that C# can talk about them. This leads to an explosion of types, which can be made even more difficult
when you consider identical structures developed by different teams (perhaps even different companies). By necessity, each
team will need to create their own "named" data structure to give C# an ability to talk about the object, but these names
are really meaningless. The JSON didn't have this name, and the structures cannot unify. There are also scenarios with
very similar objects (perhaps one object has an extra field that the former does not have). This necessitates an entirely
new object to be created, and users often end up needing to write boilerplate methods that just translate objects from
representation A to B, changing nothing about the data other than making sure the type's name lines up.
This set of scenarios is not addressed by roles and extension methods, as they currently stand. We theorized that teams
might be able to a combination of `dynamic` and a custom completion provider/analyzer, to give users help in writing and
validating code that is, in essence, a set of dynamic calls to nested properties of unnamed types that does have a structure,
but this is a complicated solution to the scenario that is likely not generally-leverageable. There are more IDEs than just
VS, and more IDE scenarios than just completion: what would go-to-def do on these, or quick info on hover?
#### Data Processing
Finally, we took a look at a small proof-of-concept library exploring what replicating parts of the popular Python library
Pandas could be like in C#, with stronger typing around the data generated from a given input. This scenario is very
reminiscent of F# type providers, allowing users to simply dot into a data structure. However, it suffers from the same
set of issues that affect the Azure SDK scenarios above. In order to talk about nested data structures, they have to be
named. And while the Azure examples entirely focus on the types of structures representable in JSON, Pandas is far more
flexible. Additionally, Pandas allows you create new objects as they flow through a pipeline, adding or removing properties
as they are manipulated.
Looking at these last two examples, it seems that there are some scenarios not served well by C# today, involving JSON or
other structured but unnamed data. These scenarios care deeply about the names of properties, and the structure attached to
each property name, but the domains these scenarios interact with do not care about naming these structures. Further, adding
names to these structures in C# can be harmful, because it locks out scenarios that can be accomplished in the original
domain and forces a naming structure where none was intended, which can result in confusing or badly-named types that can
then never be changed because of backwards compatibility concerns. As we continue to evolve the roles and extension
everything proposals, we should look at these scenarios and see if there are ways to improve the experience for them.

View file

@ -0,0 +1,30 @@
# C# Language Design Meeting for December 7th, 2020
## Agenda
1. [Required Properties](#required-properties)
## Quote(s) of the Day
- "I also can't see anyone's video, so raise your hand [in Teams] if you're not here."
- "If you can't solve required properties, you're not making a time machine."
## Discussion
### Required Properties
https://github.com/dotnet/csharplang/discussions/4209
Today, we took a look at the next revision of the required properties proposal, after a few months of design work from a smaller
team to flesh out the design. We had a small questions coming out of the meeting:
* Could assignments in the nominal parameter list always imply `base.`? It would make it easier for automatically considering
hidden properties being initialized.
* We could make it more user friendly by possibly adding warning when a property that is required by the constructor is definitely
assigned in the constructor?
* There's still some debate as to this should only be a source-breaking change.
* Is `init` the right word? Maybe `requires` would be better?
More generally, the reaction to this in the LDM was mixed. While we believe that this is the best proposal we've seen to date, it's
very complicated and introduces a bunch of new concepts. We may need to start looking at simplifying scenarios and seeing whether that
allows us to cut this proposal down a bit.

View file

@ -0,0 +1,94 @@
# C# Language Design Meeting for December 14th, 2020
## Agenda
- [List Patterns](#list-patterns)
## Quote of the Day
- "My Monday is your Friday... you're going to get unadulterated truth here"
## Discussion
### List Patterns
https://github.com/dotnet/csharplang/pull/3245
Today, we took our first in-depth look at list patterns, which will be the next big turn of the crank in generalized pattern
support in C#. The intent of this type of pattern is to allow matching on arbitrary collection types, matching against both
the length and the content of the collection in a single, simple-to-understand fashion, much like our other pattern forms enable
for positional and nominal content. To bring context to the discussion around our general goals and principles for pattern
matching in C#, we again brought up the table from discussion [3107](https://github.com/dotnet/csharplang/discussions/3107):
| Type | Declaration | Creation | Decomposition | Dispatch (pattern) |
|-|:-:|:-:|:-:|:-:|
|`int`|`int x`|`3`|`int x`|`int x` or `3`
|class with mutable fields|`class Point { public int X, Y; }`|`new Point { X = 3, Y = 4 }`|`p.X`|`Point { X: int x, Y: int y }` or `Point { X: 3, Y: 4 }`
|anonymous type|-|`new { X = 3, Y = 4 }`|`p.X`|`{ X: int x, Y: int y }` or `{ X: 3, Y: 4 }`
|record class|`class Point(int X, int Y);` (proposed)|`Point(3, 4)` (proposed)|`(int x, int y) = p`|`Point(int x, int y)` or `Point(3, 4)`
|tuple|`(int x, int y)`|`(3, 4)`|`(int x, int y) = p`|`(int x, int y)` or `(3, 4)`
|List|`List<int>`|`new List<int> { 3, 4 }`| ? | **List patterns fit in here**
|Dictionary|`Dictionary<K,V>`|`new Dictionary<K,V> { { K, V } }`| ? | ?
While we are not looking at list decomposition with this proposal, we should keep it in mind, as we will want whatever form
we use for pattern dispatch to be used for decomposition as well. In this table, we can see a correspondence between the different
syntactic forms of creation and destructuring: object initializers correspond with recursive object patterns, tuple literals
correspond with tuple patterns, etc. By this principle, our initial instinct is to make the collection pattern correspond with
the collection initializer syntax, which uses curly braces. However, this runs into an immediate issue: `{ }` is already a
valid pattern today, the empty object pattern. This means it cannot serve as the empty collection pattern, as that pattern
must specifically check that the collection is actually empty. The current proposal instead takes the approach of using square
brackets `[]` to represent a collection pattern, instead of using the curlies. We're pretty divided on this approach: C# has
not used square brackets to represent a list or array in the past. Even C# 1.0 used the curly brackets for array initializers,
reserving the brackets for array size or index access. This would make the proposed syntax a really big break with C# tradition.
We could "retcon" this by enabling new types of collection literals using square brackets, but that's an issue that LDM has
not intensely looked at beyond previously rejecting https://github.com/dotnet/csharplang/issues/414 and related issues. After
some discussion, we've come to the realization that the empty collection (ie, the base case for recursive algorithms) is the
most important pattern to design for, and the rest of the syntax falls out from that design. We've come up with a few different
syntactic proposals:
1. The existing proposal as is. Notably, this pattern form is _not_ part of a recursive pattern, and that means that you can't
specify a pattern like this: `int[] [1, 2, 3]`. Indeed, such a pattern is potentially ambiguous, as `int[] []` already means
a type test against a jagged `int` array today. Instead, such a pattern would have to be expressed as `int[] and []`. The
first part narrows the type to `int[]`, and the second part specifies that the array must be empty. We're not huge fans of needing
the `and` combinator for a base case (when the input type to the pattern is not narrowed enough to use a collection pattern)
given that one is not needed for tuple deconstruction patterns or property patterns, but it is elegant in its simplicity.
2. A similar version to 1, except that it allows nesting the square brackets inside the curly braces of the property pattern.
This would allow `int[] { [1, 2, 3] }` for the case where you need to both narrow the input type and test the array content.
There are some concerns with this syntax: we've also envisioned a dictionary pattern, that would match content using a form
like this: `{ [1]: { /* some nested pattern */ } }`. This would mean that the colon at the end of the brackets would determine
whether the contents of the brackets are used as arguments to an indexer or the patterns the collection is being tested against.
3. Using curlies to match the list contents. There are a couple of sub proposals in this section, separated by the way they
enable testing for the empty collection case. They share the content tests, which look like `{ 1, 2, 3 }`.
1. No empty case. Instead, use a property pattern on `Length` or `Count` to check for the empty case. This has issues
with our previously-desired support for `IEnumerable` and general `foreach`-able type support, as they do not have any
such property to check.
2. Empty case represented by a single comma: `{,}` would represent an array with `Length == 0`. This was suggested, but
no one argued in favor.
3. Square brackets for `Length` tests. This proposal would look something like this: `int[] [0]`. The interesting angle
with this version is that it allows for succinct length tests that could be composed of patterns itself. For example, the
BCL has some cases where they need to check to see whether an array has some content and Length between two cases, and that
could be expressed as `[>= 0 and < 256] { 1, 2, .. }`. This would also allow a general length check to be expressed for
`foreach`-able types, though there are some concerns that it would become a perf pitfall if enumerating the entire sequence
was necessary to check a non-zero length. The length or count of the collection could also be extracted with a declaration
pattern, which could turn into a nice shorthand for not having to know whether this collection uses `Length` or `Count`,
something we didn't standardize and now can't. How this version combines with other property tests on the same object would
still need to be discussed: could you do `MyType { Property: a } [10] { 1, 2, 3, .. }`, for example, or would the property and
collection patterns need to be combined with an `and`?
4. Add a new combinator keyword to make the transition to a collection pattern explicit. This is similar to how VB uses
`From` to indicate collection initializers. Such a pattern might look something like `int[] with { }` for the empty case.
(`with` was the word we spitballed here, but likely wouldn't end up being the final word for confusion with `with` expressions).
We came to no solid conclusions on the syntax topic today, as we were mostly generating ideas and need some time to mull over the
various forms. We'll come back to this at a later date.
We also took a brief look at the slice pattern and whether it could be extended to `foreach`-able types. A trailing `..` in a
`foreach` match would be easy to implement and not have any hidden costs, as it would just skip a check to `MoveNext()` after
the leading bits of the pattern match. However, a leading `..` would be much more concerning. Depending on implementation
strategy, we'd have emit a much larger state machine or keep track of a potentially large number of previous values as we
iterate the enumerable, so that when we get to the end we can ensure that the previous slots matched correctly. We're not
sure if this difference will be obvious enough to users, and will need to think more about whether we should enable the trailing
slice, or enable both slice patterns and let the codegen be what it will. In all likelihood, if the user needs this pattern
they're going to code it by hand if they can't do it with a pattern, and we can make it less likely to introduce a bug for it
if we generate the states programmatically instead of the user doing it by hand.
Again, we came to no solid conclusions here, as we spent most of our time on the syntax aspects.

View file

@ -0,0 +1,87 @@
# C# Language Design Meeting for December 14th, 2020
## Agenda
1. [List patterns](#list-patterns)
2. [Definite assignment changes](#definite-assignment-changes)
## Quote of the Day
- "They are syntax forms you little devil. No amount pedanticism is too much in C#."
## Discussion
### List patterns
https://github.com/dotnet/csharplang/pull/3245
Coming out of [Monday's meeting](LDM-2020-12-14.md), we had a few different competing proposals for syntax. As a quick recap:
1. The original proposal as is.
2. Put the brackets from 1 inside the braces on the top level.
3. Use braces for the list pattern, with the empty case being:
1. No empty case.
2. `{,}`
3. Add a `[pattern]` form that allows testing and potentially extracting the length of a collection.
4. Add a new combinator to make the braces explicitly a list pattern, which would allow `{ }` to be the base case.
After the notes were published, we took the list and had an email discussion to narrow in on the specifics of each of these cases.
Cases 2, 3.i, 3.ii, and 3.iv were not defended in this email chain, and coming into today's meeting there were 4 different main syntax
proposals, the final 3 being variations of 3.iii from the original list (in psuedo-antlr):
1. The original proposal. This introduces a new `pattern`, which uses `'[' (pattern (',' pattern)* ']')` as the syntax of that
new pattern. This cannot be expressed as a top-level concept in a `positional_pattern` or a `property_pattern` because the braces
can be ambiguous with the `type` component of these patterns.
2. `type? ('(' subpatterns? ')')? ('[' pattern ']')? ('{' property_subpatterns_or_list_element_patterns '}')?`.
This form modifies the `positional_pattern` syntax introduced in C# 8 to add a length pattern section, defined by the middle
`[pattern]` section, and modifies the final braces to contain either a set of positional subpatterns, or a set of list element
patterns, but not both. To test both property elements and list elements, a conjunctive pattern needs to be used.
3. `type? ('(' subpatterns? ')')? ('[' pattern ']')? ('{' property_subpatterns '}')? ('{' list_subpatterns '}')?`.
This is very similar to 2, except that it allows both property and list subpatterns at the same time.
4. `type? ('(' subpatterns? ')')? ('[' pattern ']')? ('{' property_subpatterns_and_list_element_patterns '}')?`.
This is very similar to 2, except that it allows both property subpatterns and list subpatterns in the same set of braces. Consider
subproposals of this version to require properties first, list elements first, or no ordering requirements.
The very important goal for the language team here is to follow the correspondence principle. That means that if you construct using one
syntax construct, you should use the same construct to deconstruct. For collection types, this means that we strongly want to prefer
using curly braces as the deconstruction syntax, rather than square brackets, because collection initializers use the braces. It is
possible that at some point in the future, we could add a collection literal syntax that uses square brackets, but there is strong
history in C# to avoid using the brackets in this fashion. Up to this point, the brackets have always contained indexes or lengths
in the language, and lists of things to initialize have always been inside braces. Changing that at this point, even if we later seek
to add conformance by introducing a new collection literal, would be asking C# users to unlearn a concept that has been unchanged
since C# 1.0, which is very concerning to us. Given this desire, option 1 deviates too much from existing C#, and we will instead
focus on one of the latter options.
Of these latter options, option 2 can be viewed as a strict subset of both 3 and 4, as either will allow using conjunctive patterns
to separate out the list and property patterns if users feel that the combination is unreadable. Additionally, we again turn to the
correspondence principle: today, you cannot combine both collection initializers and object initializers. By the correspondence
principle, then, you should not be able to combine them in the same pattern during deconstruction. We're not necessarily opposed to
allowing collection and object initializers to be combined in the future, but that is out of scope for the collection pattern changes.
Finally, in discussions Monday and over email, we also took a brief look at indexer patterns as possible `property_subpatterns`. These
would look something like this: `{ [1]: pattern, [2..^4]: var slice }`. This form seems like a good next step after list patterns to
allow deconstructioning objects with indexers. These indexer arguments could allow non-integer constants as well as multiple arguments,
giving a deconstruction mechanism for dictionaries that corresponds to object initializers in this area.
#### Conclusion
We'll move forward with the general syntax proposed in option 2, with a length subpattern and allowing either property subpatterns or
list subpatterns in the same "recursive pattern" section. We still need to translate the psuedo-spec above into a formal specification.
We also did not address the open questions around whether the length pattern should be applicable to types of `IEnumerable`, and if so
whether `[0]` is the only allowed pattern or if any pattern is allowable.
### Definite assignment changes
https://github.com/dotnet/csharplang/discussions/4240
This is an area of longstanding pain for C# users: any time conditional evaluation and comparison to constants mix, definite assignment
cannot figure out what is going on and variables that the user can see are obviously assigned are not considered assigned. We're highly
in support of this idea in general, as everyone has run into this at some point or another in their C# careers. The definite assignment
rules are written in a very syntax-driven form, and thus this proposal is written in a very syntax-driven form to update the relevant
constructs. Despite that, we do wonder whether we can make these rules more holistic and systematic, such that we don't need to make
them syntax-specific like they need to be today. We're also less enthused about the conditional expression version. If it fell out of
more general rules it would be nice, but it's not highly important like the null conditional and coalescing changes seem to be.
#### Conclusion
The general idea is approved. We'll work to see if we can generalize the rules a bit, and submit a proposal for review on github.

View file

@ -1,35 +1,452 @@
# Upcoming meetings for 2020
# C# Language Design Notes for 2020
## Schedule ASAP
Overview of meetings and agendas for 2020
## Schedule when convenient
## Dec 16, 2020
## Recurring topics
[C# Language Design Notes for December 16th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-12-16.md)
- *Triage championed features*
- *Triage milestones*
- *Design review*
- List patterns
- Definite assignment changes
## Dec 14, 2020
[C# Language Design Notes for December 14th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-12-14.md)
- List patterns
## Dec 7, 2020
[C# Language Design Notes for December 7th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-12-07.md)
- Required Properties
## Dec 2, 2020
[C# Language Design Notes for December 2nd, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-12-02.md)
- Partner scenarios in roles and extensions
## Nov 16, 2020
[C# Language Design Notes for November 16th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-11-16.md)
- Triage
## Nov 11, 2020
[C# Language Design Notes for November 11th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-11-11.md)
- IsRecord in metadata
- Triage
## Nov 4, 2020
[C# Language Design Notes for November 4th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-11-04.md)
- Nullable parameter defaults
- Argument state after call for AllowNull parameters
## Oct 26, 2020
[C# Language Design Notes for October 26st, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-10-26.md)
- Pointer types in records
- Triage
## Oct 21, 2020
[C# Language Design Notes for October 21st, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-10-21.md)
- Primary Constructors
- Direct Parameter Constructors
## Oct 14, 2020
[C# Language Design Notes for October 14th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-10-14.md)
- Triage
- Milestone Simplification
## Oct 12, 2020
[C# Language Design Notes for October 12th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-10-12.md)
- General improvements to the `struct` experience (continued)
## Oct 7, 2020
[C# Language Design Notes for October 7th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-10-07.md)
- `record struct` syntax
- `data` members redux
- `ReadOnlySpan<char>` patterns
## Oct 5, 2020
[C# Language Design Notes for October 5th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-10-05.md)
- `record struct` primary constructor defaults
- Changing the member type of a primary constructor parameter
- `data` members
## Sep 30, 2020
[C# Language Design Notes for September 30th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-09-30.md)
- `record structs`
- `struct` equality
- `with` expressions
- Primary constructors and `data` properties
## Sep 28, 2020
[C# Language Design Notes for September 28th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-09-28.md)
- Warning on `double.NaN`
- Triage
## Sep 23, 2020
[C# Language Design Notes for September 23rd, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-09-23.md)
- General improvements to the `struct` experience
## Sep 16, 2020
[C# Language Design Notes for September 16th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-09-16.md)
- Required Properties
- Triage
## Sep 14, 2020
[C# Language Design Notes for September 14th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-09-14.md)
- Partial method signature matching
- Null-conditional handling of the nullable suppression operator
- Annotating IEnumerable.Cast
- Nullability warnings in user-written record code
- Tuple deconstruction mixed assignment and declaration
## Sep 9, 2020
[C# Language Design Notes for September 9th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-09-09.md)
- Triage issues still in C# 9.0 candidate
- Triage issues in C# 10.0 candidate
## Aug 24, 2020
[C# Language Design Notes for August 24th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-08-24.md)
- Warnings on types named `record`
- `base` calls on parameterless `record`s
- Omitting unnecessary synthesized `record` members
- [`record` `ToString` behavior review](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/records.md#printing-members-printmembers-and-tostring-methods)
- Behavior of trailing commas
- Handling stack overflows
- Should we omit the implementation of `ToString` on `abstract` records
- Should we call `ToString` prior to `StringBuilder.Append` on value types
- Should we try and avoid the double-space in an empty record
- Should we try and make the typename header print more economic
- Reference equality short circuiting
## Jul 27, 2020
[C# Language Design Notes for July 27th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-07-27.md)
- [Improved nullable analysis in constructors](https://github.com/RikkiGibson/csharplang/blob/nullable-ctor/proposals/nullable-constructor-analysis.md) (Rikki)
- [Equality operators (`==` and `!=`) in records](https://github.com/dotnet/csharplang/issues/3707#issuecomment-661800278) (Fred)
- `.ToString()` or `GetDebuggerDisplay()` on records? (Julien)
- Restore W-warning to `T t = default;` for generic `T`, now you can write `T?`? (Julien)
## Jul 20, 2020
[C# Language Design Notes for July 20th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-07-20.md)
- [struct private fields in definite assignment](https://github.com/dotnet/csharplang/issues/3431) (Neal/Julien)
- [Proposal 1](https://github.com/dotnet/roslyn/issues/30194#issuecomment-657858716)
- [Proposal 2](https://github.com/dotnet/roslyn/issues/30194#issuecomment-657900257)
- Finish [Triage](https://github.com/dotnet/csharplang/issues?q=is%3Aopen+is%3Aissue+label%3A%22Proposal+champion%22+no%3Amilestone)
- Records-related features to pick up in the next version of C# (Mads)
## Jul 13, 2020
[C# Language Design Notes for July 13th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-07-13.md)
- Triage open issues
## Jul 6, 2020
[C# Language Design Notes for July 6, 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-24.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)
1. Data properties
1. Clarifying what's supported in records for C# 9
- Structs
- Inheritance with records and classes
## 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??`
## Jun 15, 2020
[C# Language Design Notes for June 15, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-06-15.md)
Record:
1. `modreq` for init accessors
1. Initializing `readonly` fields in same type
1. `init` methods
1. Equality dispatch
1. Confirming some previous design decisions
1. `IEnumerable.Current`
## Jun 10, 2020
[C# Language Design Notes for June 10, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-06-10.md)
- https://github.com/dotnet/csharplang/issues/1711 Roles and extensions
## Jun 1, 2020
[C# Language Design Notes for June 1, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-06-01.md)
Records:
1. Base call syntax
2. Synthesizing positional record members and assignments
3. Record equality through inheritance
## May 27, 2020
[C# Language Design Notes for May 27, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-05-27.md)
Record syntax
1. Record structs?
2. Record syntax/keyword
3. Details on property shorthand syntax
## 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)
Records
## May 6, 2020
[C# Language Design Notes for May 6, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-05-06.md)
1. Target-typing ?: when the natural type isn't convertible to the target type.
1. Allow `if (x is not string y)` pattern.
1. Open issues in extension `GetEnumerator`
1. Args in top-level programs
## May 4, 2020
[C# Language Design Notes for May 4, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-05-04.md)
1. Reviewing design review feedback
## April 27, 2020
[C# Language Design Notes for April 27, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-04-27.md)
Records: positional & primary constructors
## April 20, 2020
[C# Language Design Notes for April 20, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-04-20.md)
Records: Factories
## April 15, 2020
[C# Language Design Notes for April 15, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-04-15.md)
1. Non-void and non-private partial methods
2. Top-level programs
## April 13. 2020
[C# Language Design Notes for April 13, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-04-13.md)
1. Roadmap for records
2. Init-only properties
## April 8, 2020
[C# Language Design Notes for April 8, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-04-08.md)
1. `e is dynamic` pure null check
2. Target typing `?:`
3. Inferred type of an `or` pattern
4. Module initializers
## April 6, 2020
[C# Language Design Notes for April 6, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-04-06.md)
1. Record Monday: Init-only members
## April 1, 2020
[C# Language Design Notes for April 1, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-04-01.md)
1. Function pointer design adjustments
2. `field` keyword in properties
## March 30, 2020
1. Record Monday
[C# Language Design Notes for March 30, 2020](LDM-2020-03-30.md)
## March 25, 2020
[C# Language Design Notes for March 25, 2020](LDM-2020-03-25.md)
1. Open issues with native int
2. Open issues with target-typed new
## March 23, 2020
[C# Language Design Notes for March 23, 2020](LDM-2020-03-23.md)
1. Triage
2. Builder-based records
## March 9, 2020
[C# Language Design Notes for March 9, 2020](LDM-2020-03-09.md)
1. Simple programs
2. Records
## Feb 26, 2020
[C# Language Design Notes for Feb. 26, 2020](LDM-2020-02-26.md)
Design Review
## Feb 24
[C# Language Design Notes for Feb. 24, 2020](LDM-2020-02-24.md)
Taking another look at "nominal" records
## Feb 19
[C# Language Design Notes for Feb. 19, 2020](LDM-2020-02-19.md)
State-based value equality
## Feb 12
[C# Language Design Notes for Feb. 12, 2020](LDM-2020-02-12.md)
Records
## Feb 10
[C# Language Design Notes for Feb. 10, 2020](LDM-2020-02-10.md)
Records
## Feb 5
[C# Language Design Notes for Feb. 5, 2020](LDM-2020-02-05.md)
- Nullability of dependent calls (Chuck, Julien)
- https://github.com/dotnet/csharplang/issues/3137 Records as individual features (Mads)
## Feb 3
[C# Language Design Notes for Feb. 3, 2020](LDM-2020-02-03.md)
Value Equality
## Jan 29, 2020
[C# Language Design Notes for Jan. 29, 2020](LDM-2020-01-29.md)
Records: "With-ers"
## Jan 22, 2020
[C# Language Design Notes for Jan 22, 2020](LDM-2020-01-22.md)
1. Top-level statements and functions
2. Expression Blocks
## Jan 15, 2020
## Jan 13, 2020
[C# Language Design Notes for Jan 15, 2020](LDM-2020-01-15.md)
Records
1. "programming with data"
1. Decomposing subfeatures of records
## Jan 8, 2020
- https://github.com/dotnet/csharplang/pull/3035 Unconstrained type parameter annotation: `T??` (Chuck)
- https://github.com/dotnet/csharplang/issues/2608 module initializers (Neal)
- https://github.com/dotnet/csharplang/issues/2910 base(T) (Neal)
[C# Language Design Notes for Jan 8, 2020](LDM-2020-01-08.md)
1. Unconstrained type parameter annotation
2. Covariant returns
## Jan 6, 2020
- Irksome nullable issues to revisit (Jared)
- heed attribute info inside method bodies
- consider special-casing `Task<T>` and `ValueTask<T>` for null covariance
- https://github.com/dotnet/csharplang/projects/4#column-4649189 Triage recently championed features
- https://github.com/dotnet/csharplang/issues/2844 Covariant Return Types (Neal)
[C# Language Design Notes for Jan 6, 2020](LDM-2020-01-06.md)
# C# Language Design Notes for 2020
Overview of meetings and agendas for 2020
1. Use attribute info inside method bodies
1. Making Task-like types covariant for nullability
1. Casting to non-nullable reference type
1. Triage

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 MiB

View file

@ -0,0 +1,48 @@
# C# Language Design Meeting for Jan. 5th, 2021
## Agenda
1. [File-scoped namespaces](#file-scoped-namespaces)
## Quote of the Day:
- "I see a big tropical void where [redacted's] face was... It's so annoying"
- "It's so cold here, it's 70 [F]"
## Discussion
### File-scoped namespaces
https://github.com/dotnet/csharplang/issues/137
Today, we looked at some of the details around this feature, specifically what should be supported before or after a top-level
namespace declaration. The proposal as written allows only extern aliases, using directives, and global attributes. The proposal
also does not allow multiple top-level namespaces: you can only have one in the file, and all following type declarations are
considered to be part of that namespace. The debate, therefore, centers on whether we allow multiple of these declarations in a
file, what they would mean in that case, and whether we allow a top-level namespace at the same file as top-level statements.
In many ways, this seems like a style question. Syntactically, regardless of whether allow these concepts to be mixed/duplicated
in a single file in the formal grammar, the compiler will have to implement rules for what this means in order to provide a good
IDE experience. There is potential value is allowing this to be flexible, as we generally do not take strong stances on syntax
formatting guidelines beyond the default rules shipped with Roslyn, and those are very customizable to allow users to decide
whether to allow them or not (`var` vs explicit type has 3 major doctrines, for example). By allowing all forms here, we would
let users decide what is preferred to them and what is not.
That being said, however, we have concerns that we even understand what code like this would do:
```cs
namespace X;
class A {}
namespace Y;
class B {}
```
For this scenario, some people would expect these types to be `X.A` and `Y.B`, while others would expect them to be `X.A` and
`X.Y.B`. We have additional concerns around how this type of code would read in the presence of top-level statements, and
whether there would be enough visual contrast between the end of the top-level statements, the namespace, and then types under
the namespace, or whether that would be confusing to read. If we restrict the usage now, nothing would stop us from loosening
restrictions in a later language version if we discover that we were too restrictive initially, but if we let the genie out of
the bottle now, we can never put it back in.
#### Conclusion
No conclusion today. We're largely split between these two extremes, allowing everything or allowing nothing. We'll take this
back up again soon to finish debate and settle on a conclusion.

View file

@ -0,0 +1,65 @@
# C# Language Design Meeting for Jan. 11th, 2021
## Agenda
1. [Required properties simple form](#required-properties-simple-form)
## Quote of the Day
- "You didn't want to hear me say um anyway... So, um"
## Discussion
### Required properties simple form
https://github.com/dotnet/csharplang/discussions/4209#discussioncomment-275575
Today, we took a look at an extension to the existing required properties proposal, that proposed a syntax form
that simplifies the base case of the proposal to remove complexity for what we believe is the 80% use case. This
form adds a `require` modifier on a property definition. These requirements and then automatically added to the
implicit parameterless constructor of a type, if present, and can be added to explicit constructors with
`require default`, in the same place as the `init` lists of the last proposal.
First, we discussed the syntax in the proposal, and potential alternatives. We like the move to put a modifier
on properties and fields as it makes implicit constructor scenarios much simpler, but something still feels off
about the full-blown form of this syntax, with `require { Property, List }`. We could draw on type parameter
constraint clauses, and a rough first attempt looks promising:
```cs
public Person() require FirstName, LastName
{
}
public Student() require ID
: base()
{
}
```
The proposed ability to assign to properties in the require list might be either odd or outright impossible here,
depending on potential syntactic ambiguities we haven't thought of yet, but the syntax immediately feels more
like C# than the previous curly-brace version.
Where we spent the bulk of meeting, however, was on how implicit we can make the default parameter list. We
had immediate pushback on `require default` even being necessary on constructors: why can't we just infer that
for all constructors in a type, and then have a syntax for removing all requirements? There's a feeling that
`require default` is just busywork, and the compiler should just infer the defaults from the properties and
fields in the type that are marked `require`. Some proposals for the ability to remove all requirements are
`require none` and `require default = _`. We also considered a version of the proposal that goes even further,
that doesn't allow constructors to `require` additional items: you mark a property or field as required, then
remove requirements in the constructor itself. In this model, constructors would be unable to add new requirements,
which does remove some potential scenarios, but could simplify the feature significantly. Roughly speaking, the
three versions of the proposal can be summarized as follows:
1. Only implicit constructors get implicit require lists.
2. All constructors get implicit require lists, and can add requirements of their own:
1. If the constructor calls base in some manner (including implicit calls to the `object` constructor), that
list is all the fields and properties in the type that are marked require.
2. If the constructor calls another constructor on `this`, then it simply advertises chaining to that
constructor, potentially removing some requirements if it takes care of them in its body.
3. All constructors get implicit require lists, and cannot add to them. They can only remove them, and there
is no `require` syntax. This version will need a new syntax for removing requirements, but that will likely
be much simpler than the full `require` clause and need less user education.
After a read of the room, we're interested in seeing where proposal 3 goes. We'll work on fleshing that out
with examples and bring it back to LDM soon.

View file

@ -0,0 +1,84 @@
# C# Language Design Meeting for Jan. 13th, 2021
## Agenda
1. [Global usings](#global-usings)
2. [File-scoped namespaces](#file-scoped-namespaces)
## Quote(s) of the Day
- "You're not yelling at me. You're just wrong."
- "All language rules are arbitrary. Some are just more arbitrary than others."
## Discussion
### Global usings
https://github.com/dotnet/csharplang/issues/3428
Today, we started by looking at a long-standing request in various forms: the ability to create using directives that apply
to an entire project. This is of particular importance now as we solidify our work in relation to the .NET 6 themes, especially
around both beginner scenarios and general ease-of-use. A well-studied problem in teaching a programming language is avoiding
cognitive load, and usings are an ever-present cognitive load in C#, even in simple "Hello, World!" style applications. Either
the teacher says "Ignore the `using` thing for now" or they say "Ignore what the `.`s mean for now", with no ability to hold
off on introducing them. That's not to say teaching `using` isn't necessary, and necessary early in the teaching process; merely
that delaying that introduction from the first second of seeing C# to a day or week into the curriculum can be very helpful in
avoiding overloading newcomers and scaring them off.
While it's an important scenario, beginners aren't the only driving motivation here. .NET 6 is looking at making both beginner
and general scenarios better, and there's an argument that this will help general scenarios as well. Large-sized projects such
as dotnet/roslyn are the exception, not the rule; most .NET projects are smaller and don't have nearly so many moving and
interacting pieces. `using` boilerplate has a bigger impact on these projects, particularly as they tend to use many frameworks
and a custom project SDK (such as ASP.NET). That custom SDK, combined with a feature to allow the SDK to specify global usings
in some manner, can help ease these scenarios and remove unnecessary lines from most files in such solutions. Larger projects
like Roslyn may never use this feature, but Roslyn and projects like it are not the projects that much of our users are actually
writing.
Broadly, there are two possible approaches to this type of feature: CLI flags, specifiable for actual users via the project file,
and a syntax form that allows a user to specify a using should apply to all files. We have an existing proposal for the former
approach, 3428 (linked above), and some spitball ideas for what the latter could look like (perhaps something like
`global using System;`). Both have advantages:
* If these are specified via command line flags, then there is one place to go looking for them: the project file. A syntax form
would be potentially able to be spread out among multiple files. It is would be possible to spread these out across multiple
props files if users wanted to, but the types of projects that use these features are likely rarer than the types of projects
that use multiple C# files. Tooling could certainly help here, such as creating a new node in the project explorer to list all
the global usings for a project, but we do still need to consider cases where code is not viewed in an IDE such as on GitHub.
* We have a number of long-standing requests for having global using aliases. While these can be accomplished via the CLI flag
proposal, it would be significantly easier and more accessible to users if they had a syntax form of doing so.
* A syntax form would allow participation from source generators. We're somewhat split on whether that's a good thing or not.
* A syntax form might be a barrier to potential abilities to do things like `dotnet run csfile` in the future: where would the
syntax form live? An ethereal temp file, or a hardcoded part of the SDK?
#### Conclusion
We seem to have unanimous agreement here that the design space is interesting, and we would like a feature to address the issues
discussed above. We're much more split on the potential approaches, however, and need to explore the space more in depth.
### File-scoped namespaces
https://github.com/dotnet/csharplang/issues/137
We're picking back up on the discussion from [last week](LDM-2021-01-05.md#file-scoped-namespaces), which is around how
restrictive we should be in permitted mixing and matching of multiple namespace statements and combination with traditional
namespace directives. An important point to acknowledge is that, regardless of what decision we make here, Roslyn is going to
have to do something to understand what multiple namespace directives in a file means because it will encounter that code at
some point, regardless of whether it's valid or not, and will have to do its level best to make a guess as to what the user
meant. There is a big difference between a compiler trying to make as much sense as it can of invalid code and the language
having actual rules for the scenario, though. The scenario we're targeting specifically is files with one namespace in them
(and most often, one type as well), and these scenarios make up roughly 99.8% of C# syntax files that lived on one LDT-member's
computer. This includes the Roslyn codebase, which has several of these types of files specifically for the purposes of
testing that we handle the scenario correctly. Measuring an even broader set of millions of C# files on GitHub shows literally
99.99% of files have just one namespace in them.
We also briefly discussed the interaction with top-level statements. On the one hand, we're concerned about the readability of
combining these things, and that the namespace statement would be too easily missed. On the other hand, having just finished
talking about beginner scenarios, it seems like it might be annoying that beginners couldn't be introduced to the simple form
until they start splitting things apart into multiple classes. Users will likely police themselves here if it doesn't read well,
and maybe restricting it is just adding an arbitrary restriction.
#### Conclusion
We allow one and only one file-scoped namespace per file. You cannot combine a file-scoped namespace with a traditional
namespace directive in the same file. We did not reach a conclusion on the combination with top-level statements and will
pick that up again soon.

View file

@ -0,0 +1,117 @@
# C# Language Design Meeting for Jan. 27th, 2021
## Agenda
1. [Init-only access on conversion on `this`](#init-only-access-on-conversion-on-this)
2. [Record structs](#record-structs)
1. [Copy constructors and Clone methods](#copy-constructors-and-clone)
2. [`PrintMembers`](#printmembers)
3. [Implemented equality algorithms](#implemented-equality-algorithms)
4. [Field initializers](#field-initializers)
5. [GetHashcode determinism](#gethashcode-determinism)
## Quote of the Day
- "You don't see the gazillion tabs I have in my other window... It's actually mostly stackoverflow posts on how to use System.IO.Pipelines."
## Discussion
### Init-only access on conversion on `this`
https://github.com/dotnet/roslyn/issues/50053
We have 3 options on this issue, centered around how whether we want to make a change and, if so, how far do we want to take it.
1. Change nothing. The scenario remains an error.
2. Allow unconditional casts.
3. Allow `as` casts as well.
We feel that this case is pretty pathological, and we have trouble coming up with real-world examples of APIs that would need to
both hide a public member from a base type and initialize it in the constructor to some value. It would also be odd to allow it
in the constructor while not having a form of initializing the property from an object initializer, which is the new thing that
`init` enables over `set` methods. If we continue seeing a need to name hidden members, perhaps we can come up with a feature that
generally allows that, as opposed to solving one particular case in constructors.
#### Conclusion
We'll go with 1. The proposal is rejected.
### Record structs
https://github.com/dotnet/csharplang/issues/4334
#### Copy constructors and Clone methods
We're revisiting the decision made the last time we talked about record structs. In that meeting, we decided to disallow record
structs from defining customized `with` semantics, due to concerns over how such structs would behave in generic contexts when
constrained to `where T : struct`. If we do disallow this customization, do we need to disallow methods named Clone as well?
And should we also disallow copy constructors? In looking at the questions here, we spitballed some potential ways that we could
allow customized copies and still allow record structs to be used in generics constrained to `where T : struct`, potentially by
introducing a new interface in the BCL. A `with` on a struct type param would check for an implementation of that interface and
call that, rather than blindly emitting a `dup` instruction as our original intention was. We think it's an interesting idea and
want to pull it into a complete proposal, so we're holding off on making any decisions about allowed and disallowed members in
record structs related to copying for now.
##### Conclusion
On hold.
#### `PrintMembers`
A question was raised during initial review of the specification for record structs on whether we need to keep `PrintMembers`.
Struct types don't have inheritance, so we could theoretically simplify that to just `ToString()` for this case. However, we
think that there is value in minimizing the differences between record structs and record classes, so conversion between them
is as painless as possible. Since users can provide their own `PrintMembers` method with their own semantics, removing it
potentially introduces friction in making such a change.
##### Conclusion
Keep `PrintMembers`. The behavior will be the same as in record classes.
#### Implemented equality algorithms
During review, a question was raised about our original decision here with respect to generating the actual equality implementation
for record structs. Originally, we had decided to not generate a new `Equals(object)` method, and have making a struct a record
be solely about adding new surface area for the same functionality. Instead, we'd work with the runtime to make the equality
generation better for all struct types. While we still want to pursue this angle as well, after discussion we decided that this
would be another friction point between record classes and record structs, and could potentially have negative consequences if
we don't have time to ship better runtime equality for structs in .NET 6, as many scenarios would then just need to turn around
and implement equality themselves. In the future, if we do get the better runtime-generated equality, that could be added as a
feature flag to `System.Runtime.CompilerServices.RuntimeFeature`, and we can inform the generation of equality based on the
presence of the flag.
##### Conclusion
We will generate equality methods in the same manner as proposed in the record struct specification proposal.
#### Field initializers
The question here is whether we can allow field initializers in structs that have a primary constructor with more than zero
parameters. The immediate followup to that question, of course, is can we just finally allow parameterless constructors for
structs in general, and then field initializers just work for all of them? We're still interested in doing this: the
`Activator.CreateInstance` bug was in a version of the framework that is long out of support at this point, and we have universal
agreement behind the idea. The last time we talked about the feature we took a look at non-defaultable value types in general,
and while there are interesting ideas in there, we don't think we need to block parameterless constructors on it.
##### Conclusion
Let's dig up the proposal from when we did parameterless struct constructors last and get it done, then this question becomes
moot.
#### GetHashcode Determinism in `Combine`
The record class specification, and the record struct specification, states:
> The synthesized override of `GetHashCode()` returns an `int` result of a deterministic function combining the values of
> `System.Collections.Generic.EqualityComparer<TN>.Default.GetHashCode(fieldN)` for each instance field `fieldN` with `TN` being
> the type of `fieldN`.
We're not precise on the semantics of "a deterministic function combining the values" here, and the question is whether we should
be more precise about the semantics of that. After discussion, we believe we're fine with the wording. It does not promise
determinism across boundaries such as different executions of the same program or running the same program on different versions
of the runtime, which are not guarantees we want to make.
##### Conclusion
Fine as is.

View file

@ -0,0 +1,78 @@
# C# Language Design Meeting for Feb 3rd, 2021
## Agenda
1. [List patterns on `IEnumerable`](#list-patterns-on-ienumerable)
2. [Global usings](#global-usings)
## Quote of the Day
- "If the teacher doesn't show up, class is dismissed, right?" "Who is the teacher in this scenario?"
## Discussion
### List patterns on `IEnumerable`
https://github.com/alrz/csharplang/blob/list-patterns/proposals/list-patterns.md
Today, we discussed what the behavior of list patterns should be for `IEnumerable`, and specifically how much of list patterns
should be able to operate on enumerables. There are multiple competing factors here that we need to take into consideration.
1. `IEnumerable`s can be infinite. If a user were to attempt to match the count of such an enumerable, their code hangs.
2. `IEnumerable`s can be expensive. Likely more common than the infinite case, enumerable can be a DB query that needs to run
off to some data server in the cloud when queried. We absolutely do not want to enumerate these multiple times.
3. We do not want to introduce a new pitfall of "Oh, you're in a hot loop, remove that pattern match because it'll be slower
than checking the pattern by hand".
All of that said, we do think that list patterns on enumerables are useful. While this can be domain specific, efficient enumeration
of enumerables is relatively boilerplate code and with some smart dependence on framework APIs, we think there is a path forward.
For example, the runtime just approved a new API for [`TryGetNonEnumeratedCount`](https://github.com/dotnet/runtime/issues/27183),
and in order to make the pattern fast we could attempt to use it, then fall back to a state-machine-based approach if the collection
must be iterated. This would give us the best of both worlds: If the enumerable is actually backed by a concrete list type, we don't
need to do any enumeration of the enumerable to check the length pattern. If it's not, we can fall back to the state machine, which
can do a more efficient enumeration while checking subpatterns than we could expose as an API from the BCL.
For the state machine fallback, we want to be as efficient as possible. This means not enumerating twice, and bailing out as soon
as possible. So, the pattern `enumerable [< 6] { 1, 2, 3, .., 10 }` can immediately return false if it gets to more than 6 elements,
or if any of the first 3 elements don't match the supplied patterns.
Finally, on the topic of potentially infinite or expensive enumerations, they are an existing problem today. The BCL exposes a `Count`
API, and if you call it on a Fibonacci sequence generator, your program will hang. Enumerating db calls is expensive, regardless
of whether we provide a new, more succinct form or not. In these cases, users generally know what they're working with: it's not a
surprise that they have an infinite enumerable, they've very likely already done a `Take` or some other subsequence mechanism if they're
looking for "the last element from the end". By having these patterns, we simply allow these users to take advantage of a generation
strategy that's as efficient as they could write by hand, with much clearer intent. As long as the enumeration has a specific pattern
that users can reason about, it's an overall win.
#### Conclusion
We'll proceed with making a detailed specification on how `IEnumerable` will be pattern matched against. We're ok with taking advantage
of BCL APIs here, including `TryGetNonEnumeratedCount`, and are comfortable working with the BCL team to add new APIs if existing ones
don't prove complete enough for our purposes.
### Global usings
We started this by looking at a prototype of how ASP.NET is looking to reduce ceremony in their templates with a framework called
Feather, which can be seen [here](https://github.com/featherhttp/framework). The hello world for this code is 12 lines long: 6 lines
of actual code, 3 newlines, and 3 lines of usings. As apps get more complicated, these usings tend to grow quite quickly, and they're
all for the types of things that often boil down to "I want to use the async feature from C# 5, LINQ from C# 3, generic collections
from C# 2, and I want to build an ASP.NET application". This hints at a related, but orthogonal, using feature: recursive usings. For
example, `using System.*` would bring in all namespaces under `System`, or `using Microsoft.AspNetCore.*` would bring in all namespaces
under `Microsoft.AspNetCore`. However, such a feature wouldn't really solve the issue in question here, which is "how can specifying
the SDK in use ensure that I get the ability to use the features of that SDK by default?"
We have 2 general approaches here: use the project file as the place where implicit usings go, or allow a source file to include them.
Both approaches have several pros and cons. In a project file works more natively for an SDK, as they can just define a property. The
SDK does define an AssemblyVersion.cs today, but this feature is potentially more complicated than that. The project file is also
where we tend to put these types of global controls, like nullable or checked. On the other hand, project files are very hard to tool,
as MSBuild is a complicated beast that can do arbitrary things. Artificial restrictions on the feature, like requiring that it appear
directly in the project file and not in some other targets file, severely limits the usefulness of the feature across solutions. Source
files as the solution provide an easily-toolable experience that feels more C#-native, but potentially encourages these usings to be
spread out in many locations. Razor has a `_ViewImports.cshtml` file that handles this problem for Razor files, but we don't think this
maps well to the solutions we're discussing for C#: it only allows the one file, and is in some ways the "project file" for the rest
of the cshtml files in the solution as it provides things like the namespace of the rest of the pages.
#### Conclusion
We're split right down the middle here between project file and C# files. We'll revisit this again very shortly to try and make
progress on the feature.

View file

@ -0,0 +1,118 @@
# C# Language Design Meeting for Feb 8th, 2021
## Agenda
1. Virtual statics in interfaces
1. [Syntax Clashes](#syntax-clashes)
2. [Self-applicability as a constraint](#self-applicability-as-a-constraint)
3. [Relaxed operator operand types](#relaxed-operator-operand-types)
4. [Constructors](#constructor)
## Quote(s) of the Day
- "If you need to kick yourself I see that [redacted] has a foot in the chat you can kick yourself with"
- "Are we at the point where we derail your meeting with other proposals?"
- "It's the classic, noble art of retconning"
## Discussion
Today, we want to take a look at a few top-level design decisions for virtual statics in interfaces that will drive further design and implementation
decisions for this feature.
### Syntax Clashes
C# 8 brought 2 new features to interfaces: default members, and non-virtual static members. This sets up a clash between static virtual members and
static non-virtual members. In pre-C# 8, `interface` members were always virtual and abstract. C# 8 blurred the line here: private and static members
in interfaces are non-virtual. For private members, this makes perfect sense, as the concept of a virtual private method is an oxymoron: if you can't
see it, you can't override it. For statics, it's a bit more unfortunate because we now have inconsistency in the default-virtualness of members in
the interface. We have a few options for addressing this inconsistency:
1. Accept life as it is. We'd require `abstract` and/or `virtual` on static members to mark them as such. There is some benefit here: `static` has
meant something for 21 years in C#, and that is not `virtual`. Requiring a modifier means this does not change.
2. Break the world. Make static members in interfaces mean static virtual by default. This gets us consistency, but breaks consumers in some fashion
and/or introduces multiple dialects of C# to support.
3. We could introduce a bifurcation in interfaces with a `virtual` modifier on the `interface` declaration itself. When marked with `virtual`, `static`
members of the interface are automatically `virtual` by default. This is very not C#-like: we require `static` on all members of `static class`es, why
would `virtual interface`s be any different here? And how would you define the existing non-`virtual` members in such an interface?
Options 2 and 3 also have a question of how they will apply to class members. Due to the size of the changes required we may have to split virtual
static members, shipping with just interfaces in the first iteration and adding class types at a later point. However, we need to make sure that we
design the language side of these changes together, so when class virtual statics are added they don't feel like an afterthought. The second and third
proposals would likely need to have the first proposal for the class version of the feature anyway. While it would be consistent with instance members,
neither of them would totally eliminate the needs to apply the modifiers to interface members.
#### Conclusion
We will require `abstract` or `virtual` be applied to a virtual static member. We will also look at allowing these modifiers for instance interface
methods, even though they are redundant, much like we allow `public` on members today.
### Self-applicability as a constraint
`abstract` static members introduce an interesting scenario in which an interface is no longer valid as a substitute for a type parameter constrained
to that interface type. Consider this scenario:
```cs
interface IHasStatics
{
abstract static int GetValue(); // No implementation of GetValue here
}
class C : IHasStatics
{
static int GetValue() => 0;
}
void UseStatics<T>() where T : IHasStatics
{
int v = T.GetValue();
}
UseStatics<C>(); // C satisfies constraint
UseStatics<IHasStatics>(); // Error: IHasStatics doesn't satisfy constraint
```
The main question here is what do we do about this? We have 2 paths:
1. Forbid interfaces with an abstract static from satisfying a constraint on itself.
2. Forbid access to static virtuals with a type parameter unless you have an additional constraint like `concrete`.
Option 2 seems weird here. Why would a user have constrained to a type that implements an interface, rather than just taking the interface, unless
they wanted to use these methods? Yes, adding an `abstract static` method to an interface where one does not exist today would be a breaking change
for consumers, but that's nothing new: that's why we added DIMs in the first place, and it would continue to be possible to avoid the break by providing
a default method body for the virtual method, instead of making it abstract.
#### Conclusion
We choose option 1.
### Relaxed operator operand types
Today, C# requires that at least one of the operand-types of a user-defined operator be the current type. This breaks down with user-defined virtual
operators in interfaces, however, as the type in the operator won't be the current type, it will be some type derived from the current type. Here,
we naturally look at self types as a possible option. We are concerned with the amount of work that self-types will require, however, and aren't sure
that we want to tie the shipping of virtual statics to the need for self types (and any other associated-type feature). We also need to make sure that
we relax operators enough, and define BCL-native interfaces in a way, such that asymmetric types are representable. For example, a matrix type would
want to be able to add a matrix and a numeric type, and return a matrix. Or `byte`'s `+` operator, which does not return a `byte` today. Given that,
we think it is alright to ship this feature and define a set of operator interfaces without the self type, as we would likely be forced to not use it
in the general interfaces anyway to keep them flexible enough for all our use cases.
#### Conclusion
We're ok with relaxing the constraints as much as we need to here. We won't block on self types being in the language.
### Constructors
Finally, we looked at allowing or disallowing constructors as virtual in interfaces. This is an interesting area: either derived types would be required
to provide a constructor that matches the interface, or derived types would be allowed to not implement interfaces that their base types do. The feature
itself is a parallel to regular static methods; in order to properly describe it in terms of static methods, you'd need to have a self type, which is
what makes it hard to describe in today's C# terms in the first place. Adding this also brings in the question of what do we do about `new()`? This may
be an area where we should prefer a structural approach over a nominal approach, or add a form of type classes to the language: if we were to effectively
deprecate `new()`, that would mean that every type that has a parameterless constructor would need to implement an `IHasConstructor` interface instead.
And we would need to have infinite variations of that interface, and add them to every type in the BCL. This would be a serious issue, both in terms of
sheer surface area required and in terms of effect on type loads and runtime performance penalties for thousands and thousands of new types.
#### Conclusion
We will not have virtual constructors for now. We think that if we add type classes (and allow implementing a type class on a type the user doesn't own),
that will be a better place for them. If we want to improve the `new()` constraint in the mean time, we can look at a more structural form, and users
can work around the lack of additional constraints for now by using a static virtual.

View file

@ -0,0 +1,168 @@
# C# Language Design Meeting for Feb 10th, 2021
## Agenda
1. [Follow up on record equality](#follow-up-on-record-equality)
2. [Namespace directives in top-level programs](#namespace-directives-in-top-level-programs)
3. [Global usings](#global-usings)
4. [Triage](#triage)
1. [Nominal And Collection Deconstruction](#nominal-and-collection-deconstruction)
2. [Sealed record ToString](#sealed-record-ToString)
3. [`using` aliases for tuple syntax](#using-aliases-for-tuple-syntax)
4. [Raw string literals](#raw-string-literals)
5. [Allow `var` variables to be used in a `nameof` in their initializers](#allow-var-variables-to-be-used-in-a-nameof-in-their-initializers)
6. [First-class native integer support](#first-class-native-integer-support)
7. [Extended property patterns](#extended-property-patterns)
## Quote of the Day
- "That's 3 issues in 8 minutes." "That's an LDM record!"
- "Back to serious stuff. Raw string literals. Because raw is better for digestion"
## Discussion
### Follow up on record equality
https://github.com/dotnet/csharplang/issues/39#issuecomment-678097433
https://github.com/dotnet/csharplang/discussions/4411
Back when the linked comment on #39 was raised, we had an internal email chain discussing changing the implementation of `==` to move the
reference equality short-circuit down to the strongly-typed `Equals` implementation. We came to the conclusion that instead of moving the
check we should duplicate it, to ensure that `==` still behaves correctly for `null`, but we never followed up on that conclusion. Today,
we confirmed that we do indeed want to do that, and update the C# compiler to generate this better version of equality.
#### Conclusion
We'll do this. https://github.com/dotnet/roslyn/issues/51136 tracks following up on that work.
### Namespace directives in top-level programs
Our last discussion on the namespace directive had one open question left: should we allow them in combination with top-level statements?
We had an internal email chain on this topic since then, and came to the conclusion that we should disallow this combination. There's a
couple reasons for this:
1. We think the namespace directive is confusing here. It looks like a statement, but the rest of the statements on the top-level don't
introduce a new scope.
2. It is easier to remove an error later if we decide that it's too restrictive. If we allow it, we'd have to support it forever.
3. Users might expect to be able to put a namespace _before_ those top-level statements and change the namespace the implicit `Main` is
generated into.
#### Conclusion
Decision upheld. Top-level statements are not allowed in combination with file-scoped namespace directives.
### Global usings
Our last discussion on global usings had us split right down the middle on whether to make global usings a C# syntax feature, or a
command-line switch to the compiler, with a razor-thin majority leaning to C# syntax. In order to make progress here to begin
implementation, we again took an internal email chain to discuss this further. This conversation drew a few conclusions:
* Neither a a command-line switch nor C# syntax would prevent a source-generator from providing their own set of usings, but the switch
would prevent the source-generator from _dynamically_ providing this, it would have to be predefined in props/targets file in the
generator nuget package.
* We really need to be considering the experience when using `dotnet`, not `csc`. The SDK passes 182 parameters to a build of a simple
hello world application today. It's very unrealistic to base scenarios on calling `csc` directly.
* For the base templates, such as as a console app or a default ASP.NET application, this choice doesn't really affect the files the
templates drop down. In either case, the usings will be hidden. For more complicated templates, this choice changes whether the template
drops a `GlobalUsings.cs` file, or fills in a property in the template csproj. In either case, the template has really moved beyond a
single-file program, so the difference isn't huge.
* We've had a number of requests over the years for global aliases, and a C# syntax will fit in nicely with such a feature.
#### Conclusion
Given the need to start implementing here and the thin majority that prefer C# syntax, we will start investigation and implementation
on the C# syntax version, with a speclet forthcoming later this week.
### Triage
#### Nominal and Collection Deconstruction
https://github.com/dotnet/csharplang/issues/4082
This feature will add symmetry with tuple patterns/deconstruction, which is desirable. There is some potential parsing challenges, as
several of the examples look like a block with a labelled statement inside it and will need some tricky work to ensure disambiguation
works.
##### Conclusion
To the backlog. We like the idea and think there's a way to get it into a form we like, but can't commit to it right now.
#### Sealed record ToString
https://github.com/dotnet/csharplang/issues/4174
This is a simple enough change and we've had a few complaints about the behavior and inability to seal. As an alternative, we could
design a parallel ToString implementation for records that the base type in a hierarchy will call into, which would be a minor behavior
change from C# 9 as released. However, this would be complicated, and `sealed` is the keyword to tell consumers "No really, this is the
final version of this behavior, you can't change it."
##### Conclusion
We'll put this in Any Time to promote community contributions for this small feature, but if no one picks it up we will likely put in a
bit of effort to get it into C# 10.
#### `using` aliases for tuple syntax
https://github.com/dotnet/csharplang/issues/4284
The title of this issue is a bit of a misnomer, as the proposal actually extends to all types, not just tuples. We've also looked at a
broader proposal recently in conjunction with the global using statement feature, which would allow things like
`global using MyDictionary<TValue> = System.Collections.Generic.Dictionary<int, TValue>` and other similar work. It seems like we want
to make some improvements in the alias and using area, and we should consider doing a subset of that larger proposal now in the same
fashion that we've continuously shipped incremental updates for patterns.
##### Conclusion
Triaged into the working set. We want to make a general using improvement push in 10, and have a goal of at least doing this much for
alias improvements in this release.
#### Raw string literals
https://github.com/dotnet/csharplang/issues/4304
There are a number of potentially contentious design decisions in this area, but we intentionally tried to steer away from them today
and limit to just the general concept. There are many scenarios for embedding other languages into C#: XML, JSON/Javascript, C#, and
more. In many of these languages, " and ' are not interchangeable, so anything with a " in it is painful in C# today. We also thing that
interpolation in these strings is important, as these embedded code scenarios are often used for templating. There is potential work around
a way to specify what character sequence defines the interpolation holes, but we did not go into details or specifics here.
##### Conclusion
Into the Working Set. There's a bunch of design questions that we'll need to spend some time working on.
#### Allow `var` variables to be used in a `nameof` in their initializers
https://github.com/dotnet/csharplang/issues/4384
This is a minor convenience issue that has come up a few times for users, but has potential implementation nastiness with disambiguating
whether `nameof` is a method or a `nameof_expression`. Given the minor benefit and the potential implementation concerns, we're concerned
about doing this unless we decide to make `nameof` a non-conditional keyword.
##### Conclusion
Rejected. If we ever make the change to make `nameof` not a conditional keyword and can simplify the binding here, then we can bring this
back, but until that point we will leave this as is.
#### First-class native integer support
https://github.com/dotnet/csharplang/issues/4385
As the language is specified today, compliant C# compilers have to emit certain overflow conversions and then roundtrip those conversions
back to the original representation. This is inefficient and a small spec change will produce no observable semantic difference, while
allowing the compiler to emit better code.
##### Conclusion
Accepted into the working set.
#### Extended property patterns
https://github.com/dotnet/csharplang/issues/4394
This is something that patterns are very verbose about today, and it's a syntax we've previously discussed as a potential shorthand to
reduce the boilerplate. We could also potentially extend this idea to object initializers, but don't want to tie that to this proposal.
##### Conclusion
Accepted into the working set.

View file

@ -0,0 +1,86 @@
# C# Language Design Meeting for Feb 22nd, 2021
## Agenda
1. [Global `using`s](#global-usings)
2. [`using` alias improvements](#using-alias-improvements)
## Quote of the Day
* "You're muted" "I wanted to be muted"
## Discussion
### Global `using`s
https://github.com/dotnet/csharplang/blob/master/proposals/csharp-10.0/GlobalUsingDirective.md
Today we discussed the proposed syntax and restrictions on the current feature specification. As checked in today, the proposal
puts `global` after the `using` directive, which could be potentially ambiguous and require complicated parsing logic, as `global`
is a valid namespace identifier today. For example, this is valid code:
```cs
// Is this a global using alias, or a top-level using variable declaration?
using global myVar = Test.AGlobal;
class Test
{
public static global AGlobal = new global();
}
class global : IDisposable { public void Dispose() {} }
```
We could potentially resolve this in the same way we did for the `record` keyword, which is to forbid types be named `global` in
C# 10. We haven't gotten pushback on this approach for `record` as a type name so far, which is positive. However, aside from the
ambiguity, there are other reasons to view `global`-first as a good thing. `global` here is a modifier on the `using`, which C#
generally puts before the declaration, not after. We also considered 2 separate but related questions:
1. Is `static` a similar modifier? Should it be allowed to come before the `using` as well?
* After discussion, we don't believe so. `static` isn't a modifier on the `using`, it fundamentally changes what the meaning
of the using is about.
2. We already have existing modifiers for C# scopes: should we use `internal` as the keyword here?
* Using `internal` begs the followup question: what does `public` on one of these `using`s mean? What about `private`? We're
uncomfortable with the idea of treating these more like types than like macros. This starts to get into a very slippery slope
of how we export aliases publicly, can additional constraints be added to aliases, and how does that interact with roles?
Finally, we discussed the proposed restrictions on the feature. We like them overall: if `global` and non-`global` `using`s can
be interspersed, it could lead to user confusion as to whether regular `using` directives can affect `global` ones. It also helps
set up a clearly-defined set of scopes. We add a new `global` scope that comes before all top-level `using` statements today, and
their interactions mirror the interactions of regular `using`s statements with those nested in a namespace.
#### Conclusion
We put `global` before `using`, but the proposal is otherwise accepted as is.
### `using` alias improvements
https://github.com/dotnet/csharplang/pull/4452
Continuing with the theme of `using` improvements, we also discussed generalized improvements to `using` aliases to address a
number of reoccuring complaints over the years with limitations in today's approach. Specifically, `using` directives today
cannot reference predefined names like `string`, they can't have generic type arguments, they can't use tuple syntax, or use
pointer types (including the C# 9 function pointer syntax). The current proposal allows all of these things, including aliases
for partially-bound type parameters such as `using MyDictionary<T> = System.Collections.Generic.Dictionary<int, T>;`. When
combined with the previous `global using` feature, enabling this would allow compilation-unit type aliases. Our remaining open
questions here focus again on how we want to push `using`s forward in the future:
1. If we want to push `using` aliases as real types, then they need to have the ability to expression the same things all other
types can, including constraints and variance. If we go this route, we could potentially have a future where you can introduce
an alias that adds a _new_ constraint onto an existing type, such as an invariant `IEnumerable<T>` alias, or a dictionary that
is constrained to only `struct`-type values.
2. If we want to push `using` aliases as more macro-expansion, then the ability to expression constraints and variance is a
confusing detriment. The type parameter will be substituted at expansion site and we'll error at that point if an illegal
substitution is made.
Approach 1 has many followup questions that quickly start to slide into roles territory. Aliases can be used in public API, for
example, so how would we advertise them publicly if the alias has added new constraints? Is it possible for users to introduce
an opaque alias, such as aliasing `int` to `CustomerId` in such a way as there's no implicit conversion between them? Ultimately,
we think that these problems are better solved by a discrete language feature such as roles, rather than as an expansion on
`using` aliases.
#### Conclusion
`using` aliases will be treated more as macro expansions than as real types. We'll check substitutions for concrete types where
we can (such as erroring in the alias itself for `using MyList = System.Collections.Generic.List<int*>;`), but for things we
cannot check at the declaration site, we will error at the use site. There is no way to add constraints to a `using` alias.

View file

@ -0,0 +1,55 @@
# C# Language Design Meeting for Feb 24th, 2021
## Agenda
1. [Static abstract members in interfaces](#static-abstract-members-in-interfaces)
## Quote of the Day
- "I'm not using the monoid word, I'm trying to make it relatable"
## Discussion
### Static abstract members in interfaces
https://github.com/dotnet/csharplang/issues/4436
Today we went over the proposed specification for `static` abstract members. In order to scope the initial implementation, this proposal
intentionally limits such members to _only_ `abstract` members, not `virtual` members. This is due to complexity in passing along the
"instance" that the static is operating on. Consider this example:
```cs
interface I
{
virtual static void I1() { I2(); }
abstract static I2();
}
class C : I
{
public static void I2() {}
}
C.I1();
// How does the runtime pass along the information that the type here is C,
// and I.M1() should invoke C.I2()?
```
Given the complexity of implementation of this scenario and the lack of current motivating examples, we will push this out for a later
version unless our investigations of representing generic math end up needing it.
#### `==` and `!=` operators
These are restricted in interfaces today because interface types cannot implement `object.Equals(object other)` and `object.GetHashcode()`,
which are integral to implementing the operators correctly. We can lift that restriction for `abstract static` members, as the implementing
concrete type will then be required to provide implementations of `Equals(object other)` and `GetHashcode()`.
#### `sealed` on non-abstract members
We don't have any strong feelings on allowing `sealed` on non-virtual `static` interface members. It's fine to include in the proposal.
#### Conversion restrictions
As we implement a set of math interfaces, we'll come across parts of the current restrictions that make it impossible. We should be cautious
here and only lift restrictions as much as is necessary to implement the target scenarios. We can review the rules in depth when they have
been proven out by final usage.

View file

@ -0,0 +1,93 @@
# C# Language Design Meeting for March 1st, 2021
## Agenda
1. [Async method builder override](#async-method-builder-override)
2. [Async exception filters](#async-exception-filters)
3. [Interpolated string improvements](#interpolated-string-improvements)
## Quote of the Day
- "I checked my math twice before I spoke." "Well I did not."
## Discussion
### Async method builder override
https://github.com/dotnet/csharplang/issues/1407
We first looked at a proposal to enable customization of the async state machine generated by the compiler to allow for additional
customizability. Today, there is no way to customize the builder that the compiler emits for an async method except by introducing
a new task-like type. This is a leaky abstraction that limits the ability of the BCL and other libraries to adopt pooling and other
customizations where appropriate because they don't want to leak the implementation detail of the pooling to users of a method, but
don't have another way to customize the builder.
This proposal has simple core, with multiple possible addendums that add more complexity but also more customizability to usages.
After review, we believe the initial proposal is enough to cover our needs here, as additional arguments to a builder can be achieved
by using additional builder types that have their own `Create` methods. This could be somewhat ugly for deeply-variable scenarios,
but we believe this is enough of a corner case that we don't need to support it in the language, at least initially. If the need
comes up for it in a future version, we can look at adding more customization then.
We also looked at ways to simplify the type/module level constructor. The proposal today suggests having a constructor that takes
both the builder type and the task-like type, that would inform the compiler of when to apply the customized builder. This seems
like mandated busy-work for the developer: the builder type returns an instance of this task-like type from a well-defined method,
and we'd need to verify that the specified task-like type is compatible with the return of that method, so it seems like it would
be easier for the user to just infer the applicable task-like type from the builder. There are some interesting scenarios around
open generics here: how does the compiler perform substitution to arrive at the final builder type, and verify that the task-like
return is correct? Some spec work will be needed to achieve this, but it should be possible, and should be overall worth it.
Another question is whether it's possible to go back to the default builder on a method if an attribute has been applied at a
type/module level. This should be doable: all the standard builder types are public API, so all the user needs to know is what the
default builder for a type actually is. This is also a fairly niche corner in an already niche scenario, so we don't think any
additional sugar or "default" constructors are necessary.
Diagnostics will need to be reported on the use-site for issues involving generic substitutions. Builder generics will be able add
new constraints on type parameters that the underlying task-like type doesn't have, so invalid uses need to be carefully handled
and diagnostics reported to ensure a good user experience.
#### Conclusion
We unanimously like looking at a type inference-based approach and seeing if we can make it work.
### Async exception filters
https://github.com/dotnet/csharplang/issues/4485
This is a proposal to address a pain-point in async contexts, where the state machine can catch exceptions and unwind the exception
stack before user-code can catch the exception, which leads to bug reports and heap dumps that are missing the actual stack trace
where an exception is thrown. Roslyn is a prime example of this, with lots of try/catch handlers sprinkled over the codebase in
async contexts to be able to report heap dumps before the async machine catches and unwinds the stack. However, this is often a
error-prone process: Roslyn receives a bug report with a missing stack, adds a new try/catch to ensure it gets a good bug report,
then waits for a user to encounter the problem again. This proposal would allow the user to define a handler that gets called when
the async state machine gets called back for an exception, allowing Roslyn and similar async applications to report take telemetry
and other similar actions before stack unwinding. Similar to the first proposal today, it in many ways represents an aspect-oriented
feature of customizing the async state machine emit in some way.
#### Conclusion
We like the idea of the proposal, but it needs to be fleshed out more. We'll look at a more complete proposal when it's ready.
### Interpolated string improvements
https://github.com/dotnet/csharplang/issues/4487
Finally today, we looked at a proposal on improving code gen and usage for interpolated string expressions. Most of this section of
the meeting was spent going through the proposal itself, with not a lot of discussion on the individual points or open questions.
Observations we made:
* We should consider making the `GetInterpolatedString` and `TryFormat` methods public only. This ensures that, like instance
GetEnumerator() methods, there isn't potential confusion when one method is preferred in project A but another method is preferred
in project B, even when all the types involved are otherwise identical.
* We'll need to carefully consider how the `out` parameter affects local lifetime rules for `ref struct` builder types, which we expect
to be the majority. Most of this should end up falling out, but careful verification will be needed.
* The more likely compat issue is that a library introduces a public API that exposes one of these builder types, and an older compiler
is fed that API and picks a different method. We don't see any real way to avoid this, nor do we think it's a deal breaker.
* Even intentional, measured changes to better conversion from expression are scary, and this needs very careful review to ensure
we're doing exactly what we want, and no more.
* `TryFormat` short-circuiting can be quite powerful. There are plenty of logging scenarios where the user would not want to evaluate
some expensive computation that we get around today by creating `Func`s and lazily-evaluating. This would solve that, but we need
to make sure we're not creating an easy pitfall for users.
#### Conclusion
We like the direction of this proposal. We did not address the open questions in depth today, will need to come back to them soon.

View file

@ -0,0 +1,170 @@
# C# Language Design Meeting for March 3rd, 2021
## Agenda
1. [Natural type for lambdas](#natural-type-for-lambdas)
1. [Attributes](#attributes)
2. [Return types](#return-types)
3. [Natural delegate types](#natural-delegate-types)
2. [Required members](#required-members)
3. [Appendix: ASP.NET examples](#appendix-aspnet-examples)
## Quote of the Day
- "I specifically avoided using the word to avoid settling on a pronunciation for everyone to get annoyed at."
## Discussion
### Natural type for lambdas
https://github.com/dotnet/csharplang/blob/master/proposals/csharp-10.0/lambda-improvements.md
Today we looked at a proposal around enhancing lambda expressions and method groups with a "natural type", which is helpful for several
ASP.NET scenarios. Overall, the LDM has general support for making enhancements here: explaining how lambdas and method groups don't have
natural types and why that means you can't use `var` or other similar scenarios has always been a pain point. Examples that show the
ASP.NET scenarios are at the bottom of these notes in [Appendix: ASP.NET examples](#appendix-aspnet-examples).
#### Attributes
There are some important details around how exactly these attributes are emitted to the final assembly that need to be ironed out, and this
likely will mean that we need to specify more about how lambdas themselves are emitted. This is not something we do today, so we need to make
sure that we are cautious enough about this specification that we don't box ourselves out of future lambda optimizations we can make today.
Syntax-wise, there's a couple of potential issues. We need to make sure that a leading `[Attribute]` is never ambiguous as an indexer on a
previous expression. If we require that the lambda is entirely parenthesized when an attribute is used it shouldn't be ambiguous, but
parenthesizing lambdas can be a pain and isn't the prettiest thing in the world. There's an additional question of whether we should always
require the arguments to a lambda to be parenthesized if there is a leading attribute. This code is visually ambiguous if unparenthesized,
for example:
```cs
[MyAttribute] x => x; // Does MyAttribute apply to the parameter or the entire lambda?
```
Another syntax question is around the requirement to specify the parameter type when attributing a parameter. We have an open proposal to
remove the requirement to specify the type when using `ref` or other parameter modifiers, so why add the requirement here? The main issue
is around making sure that we can parse the lambda. We added the requirement for modifiers previously because we weren't sure if we could
always parse the lambda. If we want to remove the requirement here as well, we need to make sure that we've done the work to ensure there
are no parsing issues.
#### Return types
Parsing issues abound here as well. `:` is _very_ dangerous from a parsing perspective, potentially requiring a large amount of lookahead and
recovery to figure out whether we're in a ternary or a lambda expression. Even if it does prove to always be unambiguous, we're not fans of
the amount of effort that disambiguation will require. Some potential alternatives we discussed:
```
() -> int { ... } // Potentially ambiguous with pointer derefs, but should be easier to disambiguate than the :
(-> int) { ... } // Also possibly ambiguous, but again easier to disambiguate than :
(return: int) { ... }
```
We could also look into forms that put the return type on the left side of the lambda, which fits more into existing method declaration
syntax today. However, lambdas are closer to `Func<T>` and function pointer types, and today both of those use the right-hand side for the
return type, so using a right-hand return type here would fit.
#### Natural delegate types
Our main potential concerns with introducing a natural type for lambdas and method groups comes from conversion scenarios. By introducing
a natural type and allowing it to convert to `Delegate` and making no other changes, it could potentially change resolution for `Expression<T>`
or other complicated inference scenarios. For most cases the more specific type in the better conversion would win, but we need to verify
that. A potential workaround is to define a specific type of conversion for delegate natural type to System.Delegate, and adjust better
conversion to always consider this conversion to be worse. We also should consider whether delegate natural types should be natively
convertible to `Expression<T>` as well.
Another important note is that by allowing single-method method groups to have a natural type, we'll be taking a step we explicitly avoided
in the function pointer feature from C# 9. By making single-method method groups have a type, we'll be introducing a new type of breaking
change to C#, as adding a new overload to a previously-not-overloaded will _always_ be a potential breaking change, even if no parameter
types are ambiguous.
Finally, we looked at whether we should avoid synthesizing delegate types, and just restrict natural types to those that can be expressed
as an `Action/Func`. While this would simplify implementation, it makes understanding the feature dramatically more complex, and prevents
using either ref parameters/returns or ref struct parameters/returns.
### Required members
https://github.com/dotnet/csharplang/issues/3630
Finally today, we took a broad look at another revision of the required members proposal, following up on feedback from the
[last](LDM-2021-01-11.md#required-properties-simple-form) time it was presented to the LDM. The LDT overall likes the current form of the
proposal. There are still some open questions to resolve, but unlike previous iterations these are refinements to the proposal in its
current form, not total rewrites. Some questions raised today and recorded in the proposal are:
* What is the scope of the init clause? Does it introduce a new scope like the base clause does, or does it exist at the same scope as
the constructor? This affects whether it can use local functions defined in the constructor and whether the constructor body can shadow
locals.
* How many diagnostics do we want to have for silly scenarios, such as a required property that is never required from a constructor?
* What is the severity of diagnostics we are looking to have? Namely, warnings or errors?
* Are we using the right keywords?
### Appendix: ASP.NET examples
These are example ASP.NET programs we looked at when considering natural types, originally taken from https://github.com/halter73/HoudiniPlayground.
#### As written in C# 9
```cs
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
var app = WebApplication.Create(args);
[HttpGet("/")]
Todo GetTodo() => new(Id: 0, Name: "Play more!", IsComplete: false);
app.MapAction((Func<Todo>)GetTodo);
[HttpPost("/")]
Todo EchoTodo([FromBody] Todo todo) => todo;
app.MapAction((Func<Todo, Todo>)EchoTodo);
[HttpGet("/id/{id?}")]
IResult GetTodoFromId([FromRoute] int? id) =>
id is null ?
new StatusCodeResult(404) :
new JsonResult(new Todo(Id: id.Value, Name: "From id!", IsComplete: false));
app.MapAction((Func<int?, IResult>)GetTodoFromId);
await app.RunAsync();
record Todo(int Id, string Name, bool IsComplete);
```
#### Simple proposal with natural types
```cs
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc;
var app = WebApplication.Create(args);
app.MapAction([HttpGet("/")] () => new(Id: 0, Name: "Play more!", IsComplete: false));
app.MapAction([HttpPost("/")] ([FromBody] Todo todo) => todo);
await app.RunAsync();
record Todo(int Id, string Name, bool IsComplete);
```
#### A version that uses a lambda return type
```cs
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc;
var app = WebApplication.Create(args);
app.MapAction([HttpPost("/")] ([FromBody] Todo todo) : Todo => todo);
app.MapAction([HttpGet("/")] () : Todo => new(Id: 0, Name: "Play more!", IsComplete: false));
app.MapAction([HttpGet("/id/{id?}")] ([FromRoute] int? id) : IResult =>
id is null ?
new StatusCodeResult(404) :
new JsonResult(new Todo(Id: id.Value, Name: "From id!", IsComplete: false)));
await app.RunAsync();
record Todo(int Id, string Name, bool IsComplete);
```

View file

@ -0,0 +1,123 @@
# C# Language Design Meeting for March 10th, 2021
## Agenda
1. [Property improvements](#property-improvements)
1. [`field` keyword](#field-keyword)
2. [Property scoped fields](#property-scoped-fields)
2. [Parameterless struct constructors](#parameterless-struct-constructors)
## Quote of the Day
- "I have a request for the second part of this meeting... more funny quotes!" "I'm here, don't worry." "If nothing
else happens I'll take it I guess."
## Discussion
### Property improvements
https://github.com/dotnet/csharplang/issues/140
https://github.com/dotnet/csharplang/issues/133
We started today by looking at these proposals again, examining the whole space to determine a priority for which to start implementing
first. [Last time](../2020/LDM-2020-06-24.md#property-enhancements) we looked at this was 6 months ago, with mild preference for doing 133
first, and these issues remain the issues with the largest general support on the csharplang repo.
Broadly speaking, C# today has 2 types of properties, each lying on the extreme end of a spectrum of flexibility:
* Auto-props. These have no flexibility: a backing field of the exact same type as the property is declared, and can be read from/assigned
to only via the property getter and setter.
* Manual props. These are maximally flexible, but have a lot of boilerplate involved and any needed backing fields are exposed to the entire
class.
We also see 2 broad classes of problems that users would like to be addressed:
* Users would like to decorate the property. They still want a backing field of the same type as the property, but want to do some action on
`get` or `set`. This includes things like INotifyPropertyChanged and logging. 140 has a solution for this, the `field` keyword.
* Users would like to have either multiple pieces of state for one property, or have state that has a different type than the property itself.
Today, these pieces of state must be exposed to the entire type, which results in naming conventions like `_value_doNotUseOutsideOfProperty`.
133 solves this by allowing fields to be scoped to properties.
One important distinction we see between these problems is that the first one, solved by the `field` keyword, tends to be _much_ more pervasive
than the second. This is true both within a single codebase (if the user is using INPC, that kills all autoprops in every view model), and in
number of requests for the feature in general.
#### `field` keyword
The field keyword, while seemingly simple, has some interesting design decisions that we will need to settle on:
* What should the nullability of these backing fields be? An obvious answer is "should match the property", but this likely precludes the
ability to do any kind of lazy init in such properties. Rather, this scenario seems similar to `var`, where we allow `null` to be assigned
to the local, but warn when it is used unsafely. It seems possible that we could devise rules that work similarly for the `field` keyword
here.
* There are some concerns about how the compiler will know whether the property is a partial auto-prop or not. Just using the `field`
keyword can lead to some complicated scenarios, particularly if the user wants to have both custom getters and setters. We could look at a
modifier like `auto` to enable usage of the `field` keyword in the property body, or put a requirement that such properties must have either
an auto-implemented `get` or `set`, but both of those feel like limitations we're not fans of. Investigation will be needed into how much
complexity this will introduce for the compiler.
* Another important concern here is that it's not just the compiler that will need to understand this: users reading will need to do the
same determination.
#### Property scoped fields
Property scoped fields are similarly simple on first glance, but have some questions to resolve:
* Are these _truly_ only visible in the property? Or can they be seen from the constructor? If they're not visible in the constructor, then
it seems like that restriction would mean `Lazy<T>` would be unusable, since it likely needs access to `this`. Related questions:
* If they are visible, how can they be accessed? Just by name? Dotted off the property somehow?
* Can names conflict with each other?
* Can these property-scoped fields be seen by overrides? What are the valid accessibilities for them?
* How do these fields influence nullable analysis?
We also considered whether to think of this proposal "property scoped locals", instead of as fields. However, thinking of these as locals
raises confusing questions about lifetimes of these members, whether attributes can be applied to them, and still leaves the above questions
unresolved.
Finally on this topic, we looked at whether we should expand the set of property-scoped things to methods, classes, and other definitions.
Currently, we don't see a huge need for this, but we can revisit later if the need presents itself.
#### Conclusions
In a switch up from the last time we looked at this, we lean heavily towards looking at the `field` keyword first. It's probably more work,
but resolves more cases and provides more benefit to the users who want it, as it actually reduces boilerplate rather than just moving
boilerplate.
We do like both of these proposals and want them both in the language, but will start by creating a detailed spec for LDM to review on 140.
### Parameterless struct constructors
https://github.com/dotnet/csharplang/blob/master/proposals/csharp-10.0/parameterless-struct-constructors.md
Finally today, we looked at the proposal for parameterless constructors. This proposal needs to make sure that it can handle what the general
.NET ecosystem can do with struct constructors today, including private struct constructors.
Initialization behavior is one major open question. Today, constructors must initialize all fields in a struct, but they can delegate to the
parameterless constructor to zero-initialize all fields if they choose to. If the user is defining the parameterless constructor themselves,
they can no longer do this. We could consider making the zero-initialization an implicit part of the parameterless constructor if not all fields
were definitely assigned, but this would create an inconsistency with how structs work in general. A related question arises with field
initializers when no parameterless constructor is present: if one field initializer is present, do all fields have to be initialized, or can
we infer zeroing them? We should also consider a warning for `this = default` in a parameterless constructor that has field initializers, as
that will overwrite the field initializers.
We also looked at warnings around when parameterless constructors are not called, namely everywhere that `default` is used instead of `new`.
This includes arrays, uninitialized fields, and others. One immediate comparison is to the compromises we made around nullable: we don't
warn when an array of a non-nullable reference type is created and then immediately dereferenced, so it seems contradictory that we'd add
warnings here. While non-defaultable structs are an interesting idea that LDM has looked at in the past, it is orthogonal to this feature
and will need a bunch more rules than we can put in here.
Next, we considered scenarios where `new StructType()` does not actually mean calling the constructor, such as default parameter values. This
is allowed today, but if we add parameterless constructors it will not actually call that constructor. Warning or erroring on such things is
a breaking change, but the potential harm from developers thinking a constructor is being called when it's not is likely greater than any
harm to users that would need to specify `default` instead of `new`. We should consider erroring when a parameterless constructor exists for
these cases, and having a warning wave to cover the cases when there isn't a parameterless constructor to help guide users to idiomatic patterns.
Finally, we looked at interactions with generic type arguments. The `new()` constraint required a _public_ constructor, internal and private
do not work for this. We can block direct substitution for such type parameters, but indirect substitution would be possible as `where T : struct`
already implies `new()` today. We don't think that we can realistically block all `where T : struct` substitutions for structs with non-public
constructors, and we think that a warning for these cases is likely to produce far too many false positives to be useful. This may be a case
where we have to simply hold our noses and compromise on letting the runtime exception happen.
#### Conclusions
Overall, the spec is in good shape, and we'll get started on implementation. As it comes up in the implementation work, we'll work through
open questions.

View file

@ -0,0 +1,76 @@
# C# Language Design Meeting for March 15th, 2021
## Agenda
1. [Interpolated string improvements](#interpolated-string-improvements)
2. [Global usings](#global-usings)
## Quote of the Day
- "Need is a strong word... I'm just teasing, I'm just lobbing in a joke"
## Discussion
### Interpolated string improvements
https://github.com/dotnet/csharplang/issues/4487
We looked at the open question around argument passing today. In the current form, the proposal treats the receiver specially, even
for reduced extension methods where the receiver is just sugar for the first argument. This special treatment of the receiver is
very limiting, as many API patterns exist today where destinations are conveyed as arguments to a method, not as the receiver of the
method, and we would like APIs to be able to continue having their same shapes. It's also inconsistent with how we treat extension
methods in the rest of the language: they're a sugar, and there is no semantic difference between calling them in reduced form or not.
To address this, we looked at a couple of possible solutions:
1. Don't pass anything. No receiver, no arguments. This is clean, but is not really an improvement on how it works today. It means that
the builder type would need to support storage of an arbitrary number of arguments of arbitrary types, and would preclude working with
ref structs and other types that can't be in generics today.
2. Require methods to have a `PrepFormat` or similar signature that is isomorphic to the original signature, with the builder parameters
as `out` variables instead. This would allow us to simply call that signature, and there would be no fancy mapping to consider. However,
this is pretty messy from a public API standpoint. We can apply `EditorDisplay` to such methods, but they'll still exist, need to be
documented, and generally get in the way. It also means that every method will need to have a second method, which possibly limits code
sharing abilities.
3. Put an attribute on either individual parameters or on the builder type, specifying that these parameters should be passed to the
builder creation method. The former version was proposed in the open questions section, but the latter came up in discussion and seems
like a better approach. It gives a central location, handles multiple potential builders in a method signature, and allows including the
receiver type as either a magic name like `this` or as a boolean flag.
#### Conclusion
We'll look at the attribute on the builder type solution. The next question we need to answer is around out-of-order execution for
arguments passed to builders.
### Global usings
https://github.com/dotnet/csharplang/issues/3428
Next, we looked at 2 open issues in global usings: the scope of the global using statements, and how name lookup treats these usings
with respect to regular using directives. Both of these questions really hinge on the overall view we want to take on how global usings
are represented. There are 2 views here:
1. Global usings are effectively copy/pasted into the top of every file. They're just like regular `using` directives, and all the same
rules that apply to regular `using` directives at the top level apply to global usings as well.
* This has the advantage that, at the top level, a regular `using` directive will _never_ be changed by a global using directive.
Users can't introduce namespace ambiguities at the top level by introducing a global using directive that has a nested namespace with
the same name as a top-level namespace.
* It aligns with our prior art: both CSX and VB.NET work this way.
* This version has the disadvantage that, at the top level, global aliases could not be reused in a file-scoped using alias. They could
be used in an alias nested inside a namespace declaration, but not at the top level. While this is a niche scenario, it is likely that
someone will hit it at some point.
* If a name is imported in both a global `using` directive and a file-scoped `using` directive, that name is ambiguous.
2. Global usings are a new scope, that exists _above_ regular `using` directives at the top of a file. They are to file-scoped `using`
directives what file-scoped `using` directives are to `using` directives nested in a namespace.
* This would allow globally-defined aliases to be used in file-scoped directives.
* We would need to rationalize how these rules work for CSX. Do global using directives imported from a `#load` directive change the
meaning of `using` directives in the current file, or files that are subsequently `#load`ed?
* Name lookup would prefer the file-scoped `using` directives, only going to global directives if a name wasn't found.
* Has a bigger implementation cost: some PDB changes might be required in order to ensure that names mean the correct things and diverges
heavily from existing implementations.
We think both worldviews here are consistent and reasonable, and would be fine with either mental model as an explanation to consumers of how
the feature works. However, worldview 1 is more consistent with past decisions and has less implementation concerns.
#### Conclusion
We'll go with worldview 1. The decisions for scoping and name lookup fall out from this.

View file

@ -0,0 +1,70 @@
# C# Language Design Meeting for March 24th, 2021
## Agenda
1. [Improved interpolated strings](#improved-interpolated-strings)
2. [`field` keyword](#field-keyword)
## Quote of the Day
- "We all want to be happy"
## Discussion
### Improved interpolated strings
https://github.com/dotnet/csharplang/issues/4487
Today, we looked at one of the open questions in improved interpolated strings, conditional evaluation of the interpolated
string holes. The proposal today allows the interpolated string builder to return `false` from creation or from any `TryFormat`
methods, which short-circuits evaluation of any of the following interpolation holes. This has some pros and cons:
* Pro: Interpolation holes can be expensive, and if they don't need to be executed it gives an easy way to achieve semantics
that people often do with lambdas currently.
* Con: This is "invisible" to the user. There isn't a way, looking at an interpolated string expression as an argument to a
method, to tell whether the holes in this string will be conditionally-evaluated or not.
This conditional evaluation can have visible impacts when the interpolated string expression has side-effects. For example,
a conditionally-evaluated string won't have its holes impact definite assignment, because we can't be sure that the expressions
were evaluated. Further, due to the way the proposal is written, upgrading to a new version of a library could change the
semantics of existing code, as the library author could introduce a new overload that the interpolated string prefers, introducing
conditional evaluation of what used to be unconditionally-evaluated code. While library upgrades can always introduce behavior
changes in a user's code (introducing a new instance method that is preferred over an extension method, for example), this would
be expanding such concerns.
We considered whether to have some syntax marker to indicate that "the interpolated string expression holes will be conditionally
evaluated", such as putting a `?` in the hole (like `$"{?name}"`). While this syntax calls out that conditional evaluation is
occurring, we're concerned that it leans too far into making new language features obvious. We'd need to start shipping analyzers
that ensure that users are using this syntax where possible, and it could become another pitfall of "make sure you add this syntax
for maximum performance."
Finally, we looked at whether we could investigate a broader feature around lazily-evaluated arguments. Today, users often use
lambdas to defer this type computation. We're concerned by building a feature like this on lambdas, however, because of the
implicit allocation cost here. If we make advances in this space later, we can look at incorporating those advances at that point,
but we feel that we can move forward with conditional evaluation at this point.
#### Conclusion
We will have conditional evaluation of interpolated string holes without a special syntax for calling this out.
### `field` keyword
https://github.com/dotnet/csharplang/issues/140
We looked at how the `field` identifier will be resolved inside a property, and what exactly will indicate to the compiler that the
property should have a backing field generated for it. The proposal calls for resolving `field` to the backing field when there is
no other identifier named that in scope. We thought about a few alternatives:
* Could we make `field` _always_ a contextual keyword in property bodies, gated by target language version? We made a bigger break
with `record` type names, but it was a very different break. `record` was used as a type name, which are by-convention PascalCase
in C# programs. Here, we'd be breaking `field` as an identifier, which is much more common and fits in with standard C# naming
practices.
* Could we use a `__` name? Identifiers with a `__` are reserved by C#, so we can use one without breaking anyone. However, `__`
names are not common, only used for things that aren't common practice in C# (such as `__makeref` or `__arglist`).
* Could we take a page from VB's book, and introduce a `_PropName` identifier? While it still has a potential conflict with class
fields, the conflict should be much smaller, and theoretically resolving the ambiguity could be as easy as deleting the class field
(provided we get the naming right), whereas a class `field` identifier could be entirely unrelated to the current property.
#### Conclusion
We'd like to explore the last 2 proposals a bit, and come back to the LDM with a fleshed out proposal after some thinking about it.

View file

@ -0,0 +1,100 @@
# C# Language Design Meeting for March 29th, 2021
## Agenda
1. [Parameterless struct constructors](#parameterless-struct-constructors)
2. [AsyncMethodBuilder](#asyncmethodbuilder)
## Quote of the Day
- "I told people to question my vague memory and now I'm upset that you did"
## Discussion
### Parameterless struct constructors
https://github.com/dotnet/csharplang/blob/struct-ctor-more/proposals/csharp-10.0/parameterless-struct-constructors.md
Today, we took a look at open questions in this proposal.
#### Field initializers and implicit constructors
The main question on our mind here is, what does this code print?
```cs
// Is this `default(S)`, or does `Field` have a value of 42?
var s = new S();
System.Console.WriteLine(s.Field);
public struct S {
public int Field = 42;
public S(int i)
{
// C# executes:
// Field = 42
}
}
```
There are a few possibilities for what this can imply:
1. There is an implicit parameterless constructor that runs the field initializer. The code sample would print 42.
2. No implicit parameterless constructors are synthesized. We warn on the field initializer if an explicit parameterless constructor
is not provided. The code sample would print 0.
3. An implicit parameterless constructor is synthesized _when no other explicit constructors are provided_. The code sample would
print 0.
The complication here comes from the fact that `new S()` was and will continue to be legal, even when there is no parameterless
constructor. This differs from class types, which do not have an implicit parameterless constructor that would run such a field
initializer. Therefore, one way that we could look at the problem is under the lens of "We've always had this constructor, it's
just been omitted as an optimization". By that rule, option 1 should be the tack we take. However, we are also concerned that some
users will have taken a dependency on that parameterless constructor meaning a 0-initialized struct.
Another complication was raised in conjunction with record struct primary constructors. In record classes today, we require that if
the record has a primary constructor, all other constructors must chain to it. This would mean that the parameterless constructor
needs to chain to the primary constructor, which wouldn't work for an implicit parameterless constructor. We could require that record
structs with field initializers and a primary constructor provide a parameterless constructor that chains, but that also brings up
concerns about nullable annotations of parameters. In C# today, we generally advise struct authors to annotate for typical use, not
for all the technical possibilities. That means that if users shouldn't be using a default struct, we advise that a reference field
could be annotated not null. That would interact poorly with a requirement to define the primary constructor here, as there could
very well be _no_ valid default to specify.
##### Conclusion
The points raised today around interactions with primary constructors need more thought. We'll take this back for more workshopping,
and bring it to LDM again later.
#### Other conclusions
We also came to a couple other conclusions this session, affirming the proposed behavior of:
* Definite assignment simplification: the proposed rules are accepted. Further general relaxation of definite assignment might be
interesting, but require a separate proposal.
* Some of the language around how the C# compiler handles private and internal constructors today needs to be modified a bit to
reflect more nuances, but we approve of the general goal: keep behavior unchanged.
### AsyncMethodBuilder
https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/async-method-builders.md
We started today by questioning whether we can simplify this proposal a bit. Today, the proposal covers both a scoped version and
a single-method version. The scoped version is complicated, and has a number of downsides:
* Diagnostic story is unclear. If the user thought they were applying the builder to all methods with a specific return type but
did it incorrectly for a subset of the locations, we have no good way to let them know they made an error.
* Relatedly, a scoped version would need a good amount of IDE work to help users understand what builder type this method was actually
using.
When we look at our use cases for this attribute, we generally believe that there are a couple of main ones. First, and the use case
the runtime is interested in, is pooling. This usecase is unlikely to want module-wide application because pooling is potentially
harmful for infrequently-used APIs, and so users would want to be more precise about which specific methods in a type are high
usage and which are not. The other big use case we can see is builders that responsible for tracing. These builders could potentially
be wanted module-wide so that tracing could be added everywhere, but we are again worried about the diagnostic and user-info story
for this.
#### Conclusion
We will remove the scoped version of this proposal for now, and use the existing `AsyncMethodBuilder` attribute on an individual method,
local function, or lambda, to control the builder type for that function. If we hear demand for a module-scoped version in the future,
we can use a new attribute designed for that case and think about the diagnostic situation at that point.

View file

@ -0,0 +1,151 @@
# C# Language Design Meeting for April 5th, 2021
## Agenda
1. [Interpolated string improvements](#interpolated-string-improvements)
2. [Abstract statics in interfaces](#abstract-statics-in-interfaces)
## Quote of the Day
- "Every time someone tells me they have a printer that works, I believe they're part of the conspiracy"...
"So what I'm getting from this is that you've given up on your printer and are now printing at the office?"
NB: This is, to my knowledge, the largest amount of time between parts 1 and 2 of an LDM quote (approximately 1 hour and 10 minutes,
in this instance).
## Discussion
### Interpolated string improvements
https://github.com/dotnet/csharplang/issues/4487
Our focus today was in getting enough of the open questions in this proposal completed for the [dotnet/runtime API proposal](https://github.com/dotnet/runtime/issues/50601)
to move forward.
#### Create method shape
We adjusted the shape of the `Create` method from the initial proposal to facilitate some improvements:
* In some cases, `out`ing a parameter with a reference type field can cause the GC to introduce a write barrier.
* For the non-`bool` case, `Create` feels more natural.
This may be a micro-optimization, but given that this pattern is not intended to be user-written, but instead lowered to by the compiler,
we feel that it's worth it.
##### Conclusion
Approved.
#### TryFormatX method shape
The proposal suggests that we should allow `TryFormatX` calls to either return `bool` or `void`, as some builders will want to stop formatting
after a certain point if they run out of space, or if they know that their output will not be used. While a `void`-returning method named `TryX`
isn't necessarily in-keeping with C# style, we will keep the single name for a few reasons:
* Again, this pattern isn't intended to be directly consumed by the end user, they'll be writing interpolated strings that lower to this.
* It's harder for API authors to mess up and mix `void`-returning and `bool`-returning `TryFormatX` methods, because you can't overload on
return type.
* It's easier to implement.
We do want to allow mixing of a `Create` method that has an `out bool` parameter, as some builder are never going to fail after the first create
method. A logger, for example, would return `false` from `Create` if the log level wasn't enabled, but the actual format calls will always succeed.
We also looked at ensuring that a single `TryFormatInterpolationHole` method with optional parameters for both alignment and format components can
be used with this pattern. As specified today, these parameters are not named so overload resolution can only look for signatures by parameter type.
This means there's no single signature that handle just a format or just an alignment. To resolve this, we will specify the parameter names we use
for the alignment and format components (their names will be `alignment` and `format`, respectively). The first parameter will still be unnamed.
Another discussion point was on whether we should require builders to _always_ support all possible combinations of a format or alignment component
being present. For some types (such as `ReadOnlySpan<T>`), we're imagining that such components would be just ignored by the builder, and it would
be interesting to just have that be a compile error instead of just being silently ignored at runtime. However, the ship on invalid format specifiers
sailed a long time ago, and there is potential difficulty in making a good compile-time error experience for these scenarios. Thus, our recommendation
is to always include overloads that support these specifiers, even when ignored at runtime.
##### Conclusion
API shape is approved. We will use named parameters for `alignment` and `format` parameters, as appropriate.
#### Disposal
Finally in interpolated string improvements, we looked at supporting disposal of builder types. Our decision that we will have conditional execution
of interpolated string holes means that user code will be running the middle of builder code. This means that an exception can be thrown, and if the
builder acquired resources (such as renting from the `ArrayPool`), it has the potential to be lost if we do not wrap the builder (and potentially
larger method call that consumes the builder for non-`string` arguments) in a try/finally that calls dispose on the builder. There's also an additional
complication to the disposal scenario, which is whether we trust the compile-time type of the builder. If the builder is a non-sealed reference type
or a type parameter constrained to an interface type that has an `abstract static Create` method, the actual runtime type could implement `IDisposable`
that we do not know about at runtime. In the language, we're not hugely consistent on this. In some cases we trust that the compile-time type is correct
(such as when determining if a sealed/struct type is disposable), and in some cases we emit a runtime check for `IDisposable` (such as if the enumerator
type is a non-sealed type or interface). We also need to consider whether to do pattern-based `Dispose` for all types (as we do in `await foreach`) or
just for `ref struct`s (as we do for regular `foreach`).
Even the concept of disposal for these builder types might not be needed. The runtime is a bit leary of having `InterpolatedStringBuilder` be disposable,
because it means that every interpolated string will introduce a `try/finally` in a method. We really don't want to see people create performance analyzers
that tell users to avoid interpolated strings in methods because it will affect inlining decisions. We have some ideas on avoiding this for interpolated
strings converted to strings specifically, but a general pattern is concerning. If the main builder type won't be disposable, are we concerned that we're
trying to engineer a solution to a problem that doesn't actually exist?
##### Conclusion
No conclusion on this point today. A small group will examine this in more detail and make recommendations to the LDM based on evaluation.
### Abstract statics in interfaces
https://github.com/dotnet/csharplang/issues/4436
We looked at 2 major changes to the proposal today: allowing default implementations and changes to operator restrictions.
#### Default implementations
The existing proposal specifically scopes default implementations of virtual statics in interfaces out because of concerns about runtime implementation
costs. In particular, in order to make default implementations work and be able to call other virtual static members, there must be a hidden "self" type
parameter so that the runtime knows what type to call the virtual static method on. That work is still too complicated to bring into C# 10, but a simple
change of scope can make a subset of these cases work: we could require that all static virtual members _must_ be called on a type parameter. This takes
that hidden "self" parameter and makes it no longer hidden, because there must always be a thing that the user calls that actually contains the type. It's
not always necessary to write `T` itself: for example, `t1 + t2` would reference the static virtual `+` operator on `T`, so it's being accessed on the
type parameter, not on the interface.
However, there are some serious usability concerns for this approach. A default implementation of a virtual static member cannot be inherited by any
concrete types that inherit from that interface. This is true for instance methods as well, but that method (or a more derived type's implementation of
the method) can be accessed by casting that instance to the interface type in question. For a DIM of a virtual static member, there is no instance that
can be cast to the base interface to access the member, so a concrete type must always reimplement the virtual static member or it will be truly inaccessible.
For example:
```cs
interface I<T> where T : I<T>
{
public static abstract bool operator ==(T t1, T t2);
public static virtual bool operator !=(T t1, T t2) => !(t1 == t2);
public void M() {}
}
class C : I<C>
{
public static bool operator ==(C c1, C c2) => ...;
}
C c = new C();
c.M(); // M is not accessible
((I)c).M(); // This works, however
_ = c == c; // Fine: C implements ==
_ = c != c; // Not fine: I.!= is a default implementation that C does not inherit. This method cannot be called.
```
There are 2 workarounds a user could use for this problem: make a generic method that takes a type parameter constrained to I and invoking the member there,
or reimplementing the operator on C, thereby removing the benefit of the default implementation in the first place. Neither of these are particularly appealing.
##### Conclusion
A smaller group will revisit this and decide whether it is useful. We are skeptical of it based on the above problems currently.
#### Operator restrictions
Today, interfaces are prohibited from implementing `==` or `!=`, and from appearing in user-defined conversion operators. We have a long history of this, mainly
because with interfaces there is always the change that the underlying type actually implements the interface at runtime, and the language should always prefer
built-in conversions to user-defined conversions. However, these operators cannot actually be accessed when the user only has an instance of the interface, they
can only be accessed when using a concrete derived type or a type parameter constrained to the interface type. This addresses our concerns about interface
implementation at runtime, and conversions from types defined in interfaces is particularly useful for numeric contexts such as being able to allow `T t = 1;`
because `T` is constrained to an interface that has a user-defined conversion from integers.
##### Conclusion
Lifting these restrictions is approved.

View file

@ -0,0 +1,95 @@
# C# Language Design Meeting for April 7th, 2021
## Agenda
MVP-nominated session agenda
1. [Abstract statics methods](#abstract-statics-methods)
2. [Making other language literals easier](#making-other-language-literals-easier)
3. [Expression trees](#expression-trees)
4. [Metaprogramming](#metaprogramming)
5. [Cost-free delegates and LINQ](#cost-free-delegates-and-linq)
6. [Readonly locals and parameters](#readonly-locals-and-parameters)
7. [Global usings](#global-usings)
8. [Mixed-language projects](#mixed-language-projects)
9. [Discriminated unions](#discriminated-unions)
## Quote of the Day
- "Cats are the superior pet" - followed by a lot of discussion that isn't relevant, as your note taker is a cat person
## Discussion
Today we held a more informal LDM session with Microsoft MVPs, where we selected an agenda from their suggestions and a brief discussion
on our thoughts around the topic, as well as getting their impressions and potential concerns on the topic.
### Abstract statics method
One thing we heard today was that there are definite use cases for this feature, not just in interfaces, but also in class types. This will
particularly help with abstracting construction scenarios. There are also likely cases in Objective-C and Swift interop code that will be
made simpler with this feature, which we hadn't yet looked at as a possible application for this. We also briefly discussed the issue of
multiple inheritance with default implementations of abstract methods, but no new problems arise from abstract statics that did not already
exist with default implementations of instance interface members.
### Making other language literals easier
A common complaint in C# is when users need to include literals from other languages such as XML or JSON, or even C# itself (particularly
evident in source generators). While we aren't looking for language-specific literal types, we are looking at a more general "raw string"
proposal that will allow more customization of escapes inside the string, which will address the problems around copying and pasting text
that includes quote marks in it.
### Expression trees
Some questions were raised on why we haven't updated expression trees since initial release. Our concerns here are around expression tree
consumers: any update we make to start including new things in the tree will likely break consumers of expression trees. This starts to get
particularly gnarly when we consider libraries that users want to ship and support on older target frameworks, or when newer code wants to
depend on older code that hasn't been updated for handling of new expression tree constructs. We need a good proposal around how to handle the
guardrails in these tricky scenarios to move this forward, and we don't have one yet.
### Metaprogramming
Questions here centered around 2 points. First was ease of use, such as being able to define a source generator in the same project that
consumes it. We are currently focussed on the V2 of the source generator API, but after that is shipped we'll be turning to focus on more
general ergonomics, and this will be one of the areas we'll investigate. There are some particularly hard questions around running a source
generator when the project doesn't compile.
The second point is in source replacement. We are very unsure about this feature: in particular, the IDE experience isn't great. We've
already received occasional bugs from users about IDE experiences with existing code-rewriting solutions such as Fody (such as debuggers
appearing to misbehave), and we have additional concerns about the perf implications of such generators.
### Cost-free delegates and LINQ
A number of scenarios would like lambdas to be more efficient. In particular, some applications of LINQ should be able to be cost-free, as
the results are immediately used and don't need to allocate closures. However, we don't have the language facilities to do this today. If
we add the ability for ref structs to implement interfaces and be used in generics, we could get this feature, but usage would be extremely
unergonomic due to the inability to infer generics parameters for some of the cases involved. To really make a feature like this usable, we
would also want associated/existential types to remove those uninferrable generic parameters.
### Readonly locals and parameters
This has been one of the ultimate examples of bikeshedding. We have an obvious syntax in `readonly`, but we are concerned that the effort
the user would put into putting `readonly` everywhere doesn't match the actual benefit they would derive from doing so. C#'s past a
mutable-first language is definitely a liability with this issue.
### Global usings
We revisited why we are looking at this feature as C# syntax, and not as a project file switch. There are 2 reasons for this: we think we
can do a better tooling experience in source, and we think that it will compose well with using aliases to enable other much-requested
features. It does make multiple-project aliases a bit more difficult, as the user will have to include the file from multiple projects,
but we think it's a worthwhile tradeoff. We also looked at global usings nested inside a namespace. We're concerned about the user experience
for such constructs, and that the use case isn't there currently. If we see a need for this in the future, we can look at it then.
### Mixed-language projects
While this is an interesting idea, the compiler support here is somewhat scary. Additionally, VB.NET and C# have a number of very subtle
differences that could very easily lead to developer confusion. Overall, we're not pursuing this area.
### Discriminated unions
While we wanted to look at discriminated unions for C# 10, we don't think we're going to be able to. In particular, there are some big questions
left around type inference to be solved. `Option<T>.None` won't be particularly ergonomic until we do so. We also took a brief survey to see
what the MVPs are looking to get out of the feature:
* Exhaustiveness in pattern matching
* Brevity in declaration
* Either-or parameters to methods

View file

@ -0,0 +1,102 @@
# C# Language Design Meeting for April 12th, 2021
## Agenda
1. [List patterns](#list-patterns)
2. [Lambda improvements](#lambda-improvements)
## Quote(s) of the Day
- "If the runtime team jumped off a bridge, would you [redacted]?" "If it would make my code faster"
- "Quote of the day may need to involve corn fields"
## Discussion
### List patterns
https://github.com/dotnet/csharplang/issues/3435
Today we looked over the changes around supporting `IEnumerable` types in list patterns, and how slice patterns will affect them. While
we overall like the lowering that has been proposed, we would like to continue to look at possible optimizations around using framework
apis such as `TryGetNonEnumeratedCount`. This will allow the framework to do all the grungy bookkeeping to make this quick for cases when
the `IEnumerable` is actually a countable type, or one of a certain type of LINQ expression that is countable under the hood (such as a
`Select` over an array). The runtime is also planning on adding a `Take` method that does similar bookkeeping with index and range, falling
back to buffering if it has to.
We also considered to what extent we should allow sub-patterns under a slice pattern. The obvious use case is a declaration pattern for the
slice, but as worded today the syntax will allow any arbitrary sub-pattern on the slice. After discussion, while we think that the main use
case is just declaration patterns, we see no reason to disallow other nested sub-patterns. It should compose well, and while 99% of users
will never need it, it could be helpful for that 1%.
The other question with slice patterns is whether to allow nested sub-patterns for `IEnumerable` as well as for sliceable types. If we do
allow this, it would mean treating `IEnumerable` specially here, while indexers and slicers cannot be used in the general case. Given
this, we think it will be a better experience if we only allow sub-patterns under a slice if the type is actually sliceable. Separately, we
can look at considering extension methods as a part of general sliceability, which, if combined with renaming that `Take` method from the
framework to `Slice` before it ships, would enable the feature in a much more general fashion.
#### Conclusions
* Lowering is generally approved.
* Slice sub-patterns will allow any pattern, so long as the input type to the list pattern is sliceable.
* Making `IEnumerable` sliceable is orthogonal.
### Lambda improvements
https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/lambda-improvements.md
After some implementation work, this proposal is back to look at some more changes. One of the big ones is moving the return type to the left
side of the parameter list. This makes the syntax analogous to our other signature declarations in C#, looking like an unnamed version of a
local function. This fits in well with the types of changes we've been making to C# in recent versions, such as tuples/record structs, anonymous
classes/record classes, and declaration forms/pattern forms. While we do have `Func` and `delegate*` as types that put the return last, we are
at least consistent within type forms and within signature declaration forms. At this point, the only parity we are missing between lambdas
and local functions is the ability to declare generic type parameters, but those won't be useful on lambda expressions unless we add
higher-kinded types to the language.
We also looked at requirements around return type specification: do we want to require that, if a return type is specified, parameter types must
be specified too? On the one hand, we require that, if any parameter types are specified, the others must be specified as well. On the other,
we can't make it required to specify the return type when a parameter type is specified because C# hasn't had such an ability until now, so
requiring this would lack symmetry. It's also very possible that the return type of a lambda could be uninferrable, while the parameter types
are, and it would be unfortunate if you had to specify everything in order to just get the return type. Given this, we will allow the return
type to be specified without parameter types.
We considered the case of `async async (async async) => async`. We could make it required to escape `async` used as a type name here: if the user
wants to specify the return type of the lambda is the type named `async` and the lambda is _not_ an async lambda, they'll have to escape it anyway
to disambiguate between making the lambda `async`. Given this, we support making it required to escape the type name in the return type.
The changes around attributes in the proposal raised no concerns. These changes were requiring that, if an attribute is used, parentheses must
be used for the parameter list, and the rules around how the compiler will disambiguate conditional array accesses and dictionary initializers.
Finally, we noted the possibility for a breaking change if single-method method groups are given a natural type with the following code:
```cs
using System;
var c = new C();
D.M(c.MyMethod);
// Outputs "Extension" today, would print Instance if c.MyMethod had a natural type.
class C
{
public void MyMethod() { Console.WriteLine("Instance"); }
}
static class CExt
{
public static void MyMethod(this C c, string s) { Console.WriteLine("Extension"); }
}
class D
{
public static void M(Delegate d) { d.DynamicInvoke(); }
public static void M(Action<string> a) { a(""); }
}
```
We'll need to investigate to see if we can avoid this change, or if we're ok with the potential break.
#### Conclusions
* Return type before the parameter list is approved, does not require parameter types to be specified.
* `async` as a return type name should require escapes.
* Attribute changes are approved.

View file

@ -0,0 +1,90 @@
# C# Language Design Meeting for April 14th, 2021
## Agenda
1. [Shadowing in record types](#shadowing-in-record-types)
2. [`field` keyword](#field-keyword)
3. [Improved interpolated strings](#improved-interpolated-strings)
## Quote of the Day
- "We're taking my sarcastic suggestion"
## Discussion
### Shadowing in record types
In C# 10, we want to allow the user to change whether a record primary constructor parameter is a property or a field. However, we run into an
issue with currently-legal C# 9 code like this:
```cs
using System;
var c = new C(2);
c.Deconstruct(out var x);
Console.WriteLine(x); // Prints 1
public record Base
{
public int X { get; set; } = 1;
}
public record C(int X) : Base
{
public new int X = X;
}
```
In this example, what will deconstruct refer to? In C# 9, it will be `Base.X`, but if we allow changing whether `X` is a property or not then
C# 10 will consider that to be `C.X`, and the code will print 2. We consider this to a pathological case and not something we intended to enable
in C# 9, so we will take a hard-line approach and patch C# 9 to make shadowing a base record property like this an error.
#### Conclusion
Make this code an error in C# 9. In C# 10, `Deconstruct` will refer to `C.X`.
### `field` keyword
https://github.com/dotnet/csharplang/issues/140
After our [last](LDM-2021-03-24.md#field-keyword) meeting on partially-implemented auto-properties, we had decided to look more deeply at a
few alternate syntaxes to see if we could avoid the need to make `field` a contextual keyword. While some of the suggestions would take less
compiler work, our ultimate conclusion here is that we'd prefer to do the work needed to make `field` a contextual keyword over taking what we
feel is an inferior syntax. As part of this work, we can consider making the public Roslyn APIs around backing fields more consistent. Today,
there are differences between what `GetMembers()` will return for auto-properties vs field-like events, and in order to implement the `field`
keyword we will likely need to take the same strategy as we did with field-like events to avoid circularities. We will also consider standardizing
the behavior here as it has also been a source of Roslyn-API consumer confusion in the past. We will also consider a .NET 6 warning wave to prefix
`field` identifiers in properties that do not correspond to a backing field with either `@` or `this.`, as appropriate.
#### Conclusions
We will proceed with `field` as the keyword, and would like to have .NET 6 warning wave to nudge users to write code that has no chance of being
ambiguous.
### Improved interpolated strings
https://github.com/dotnet/csharplang/issues/4487
Today, we took a look at two questions. First, should we allow interpolated string builders to be passed by ref? And if so, what, if any, is
syntax needed on the builder? We think this will be important for both safety and optimal performance in some framework builders: if the builder
is a struct type and is passed by reference and it captures any reference types as fields, then those fields can be cleared by the called method,
which will help ensure things aren't unnecessarily rooted. We already have a good precedent for this in extension methods: struct types are allowed
to be passed by `ref` as the `this` parameter, and no `ref` is required at the call site. We think the same rules will work here as well.
We also took a look at out-of-order parameter evaluation. Our current proposal is that a builder can be annotated with an
`InterpolatedStringBuilderArgument` attribute, and that the compiler will look at the names in the attribute to determine which parameters to pass
to the `Create` method call of the builder. However, we have a question of what to do if the named parameter is _after_ the interpolated string
literal and the interpolated string is being lowered using the `bool`-returning `Append` methods, as we will have to evaluate the trailing parameter
before the contents of the interpolated string. This would break lexical ordering, which is likely to be extremely confusing and have detrimental
effects on definite assignment, as well as user understanding. However, in order for maximum compatibility with existing API signatures, this would
have to be supported, as there existing API shapes (such as `Utf8Formatter`) that put the location the interpolated string would go before some of
the arguments that the builder will need (in the case of `Utf8Formatter`, their signatures are the value to be formatted, then the destination span).
We could potentially make this dependent on the `Append` calls used the by the builder: `void`-returning `Append`s would allow arguments after the
builder, and `bool`-returning `Append`s would not. This would allow the compiler to evaluate the interpolation holes ahead of time and preserve
lexical ordering. However, it has its own downsides of adding confusion to the builder pattern, and might be more difficult to tool. Further discussion
on this topic revealed that we need to revisit the whole question of conditional execution in order to make a decision here.
#### Conclusion
* Ref parameters are approved, using the same rules as extension method `this` parameters.
* We will take the Monday LDM to resolve the questions around conditional execution and out-of-order parameter execution (and hopefully all other
open questions on this proposal).

View file

@ -0,0 +1,52 @@
# C# Language Design Meeting for April 19th, 2021
## Agenda
1. [Improved interpolated strings](#improved-interpolated-strings)
## Quote of the Day
- "I'm glad you had a stomachache here so I don't have to"
## Discussion
### Improved interpolated strings
https://github.com/dotnet/csharplang/issues/4487
Today, we spent the full meeting digging into the pros and cons of conditional evaluation of interpolation holes, to ensure that we feel
comfortable with the changes doing so will bring. The real challenge here is that conditional evaluation of interpolation holes will break
with current mental models of interpolated strings: today, interpolated string holes are unconditionally evaluated in lexical order, and
the way the proposal is designed makes it possible for a library update to change whether the expressions in an interpolation hole is
evaluated or not. While library updates can always bring changes in behavior, this is the type of change that is currently only possible
by a library adding the `Conditional` attribute onto a method or changing the type of an exception being thrown, causing a catch handler
to no longer be hit. Adding a new instance method that is preferred over an extension method is similar, but except in rare cases involving
user-defined conversions this can't actually affect the expressions in the method body itself.
If we proceed with conditional evaluation, user education will be a key component. The proposal does not involve conditional evaluation when
the interpolated string literal is used directly as a `string`, but other types can introduce this. If a user is confused by this behavior,
we need a clear thing we can point out to say "this is why you're seeing the current behavior." One potential way to do this is by introducing
a specific syntax to enable conditional interpolation hole evaluation, something like `$?"{ConditionallyEvaluated()}"`. With such a syntax,
we would never conditionally evaluate the holes unless the string were marked with `$?` or `@$?`. However, this immediately becomes a concern
for libraries that want to introduce conditional evaluation: presumably they were making that decision for a good reason. A logging library
would want this to just work, and every library that uses the feature would presumably then also need to make an analyzer to go along with the
feature to ensure their customers are actually using it.
We also considered the benefits that partial evaluation gives the user. An important goal for C# features is that users don't adopt the
feature then immediately switch to something else because it introduces performance issues. Patterns are a good example of doing this right:
the compiler generates code that is usually as good, if not better, than the code the user would write by hand to match a pattern. Today's
interpolated strings, on the other hand, do _not_ do this today. They box value types, don't work with spans, and generate array garbage that
can't be elided. We want interpolated strings to be better: using the language feature should generate code that is just as performant as
you can get manually today. Conditional evaluation is a big part of this: both with the up front check, and with the intervening checks on
each `Append` call, we can ensure that a simple line of C# generates code that is as good as manual checks.
A good analogy to think about for concerns about conditional evaluation is in `struct`s: if C# were to introduce value types today, would
we be concerned that we need to call out the copies everywhere they can occur? Or would we simply accept that, yes, struct copies can happen
and that it's fine. Yes, behavior could change inside method bodies on upgrading a library, but that can happen in a number of ways with any
library upgrade today. New instance methods can be introduced that cause extension methods to longer be chosen, libraries can introduce new
conversions, new exceptions can be thrown/existing exceptions can be no longer thrown. While is another change that can happen, we don't think
it's substantially different enough to warrant concern.
#### Conclusion
We accept conditional evaluation of interpolation holes as written in the spec.

View file

@ -0,0 +1,77 @@
# C# Language Design Meeting for April 21st, 2021
## Agenda
1. [Inferred types for lambdas and method groups](#inferred-types-for-lambdas-and-method-groups)
2. [Improved interpolated strings](#improved-interpolated-strings)
## Quote of the Day
- "And then we will open Pandora's box"
## Discussion
### Inferred types for lambdas and method groups
https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/lambda-improvements.md
https://github.com/dotnet/csharplang/issues/4674
Further implementation work has revealed a few potential breaking changes in giving lambdas and method groups a natural type (linked in the issue
above). It is possible to run into these breaks with or without extension methods involved, and while these are the same types of breaks that can
be observed in extension method resolution (adding new ones in a closer scope or adding an instance method that is preferred), these would be a
case of the language actually changing the results of overload resolution for the same inputs. We have a few ideas for how to approach this:
1. Accept the break. This would be one of the bigger breaks that C# has ever taken, on par with the `foreach`-scoping changes in C# 5.
2. Always prefer a target-type for method groups and lambda expressions. This idea, while sounding simple, is quite complex implementation-wise.
The C# type inference and overload resolution algorithms are very much tied to having a natural type for an expression, and flowing that information
through the process. To prefer target-typing here, we would have to first try to target-type, then fall back to a natural type and try the whole
process again. This would add a significant cost complexity to an already-expensive part of the compilation process, and while it might work it
will be an exponentially harder problem every time we want to do something else like this.
3. Make natural types for lambdas and method groups opt-in. This would be through some sort of syntax gesture, such as:
1. A cast like `(_)` to indicate "I would like the natural type for this but I don't want to state it". This would lock in a specific syntax
that would forever need to be explained to users to "use C# 10 please".
2. Only lambdas with return types (indicating new feature uptake) would have a natural type. This would severely hamper the scenarios our
partner teams are interested in: most of the time, their return types should be inferred, and it will not support method groups.
4. Only infer a natural type when converting to `System.Delegate` or `System.MulticastDelegate`. This technically still does have the chance of
breaking scenarios, but the breaks are significantly smaller. However, this would result in the unfortunate consequence that only non-generic
delegate types can cause natural types to be inferred, which feels like a pre-generics solution to the problem.
While accepting a break here could potentially be big, it's important to note that this particular scenario is actually quite fragile today. In
either of the code samples, simply extracting the lambda or method group to a local variable will cause overload resolution to pick the same
overload that giving the lambda a natural type would. This is because the local variable will have a natural type itself. It seems relatively
likely that the only users intentionally taking advantage of this "feature" are creating extension methods that just call the original method
with the delegate, using the extension method as a source of a target-type for the lambda expression.
We also have a decent amount of runway for previewing changes here. We're not planning on shipping this feature in a non-preview version of either
VS or the runtime until it's time to actually release C# 10, so we can make an aggressive version of this change now and see if we need to dial
it back. The preview will have a warning reported whenever the natural type of a lambda or method group is used, which will hopefully give us
enough of a signal during this preview to know just how aggressive we can be here.
#### Conclusion
We will tentatively accept the breaking change to overload resolution. Previews will be used to determine if we need to revisit this decision.
### Improved interpolated strings
https://github.com/dotnet/csharplang/issues/4487
We took a look at a couple of outstanding issues in interpolated strings today. First, we looked at the order of arguments to the builder from the
current context. There is potential here to break lexical ordering of expressions if we allow arguments to the builder's `Create` method to come
after the builder itself in the argument list. While a possible model for thinking of interpolation holes is lambda expressions, where the holes
are either not evaluated or evaluated at a later point from where they were written, these holes can potentially have definite assignment impacts
on the current method body. This is entirely different from other forms of deferred execution in C#, and we're concerned with the implication.
After discussion, we agreed on requiring lexical ordering to be respected: if a parameter is an argument to the `Create` method of the builder type,
it must come before the interpolated string. That error will be reported at the invocation site, and it should be affected by the true lexical
order of the invocation. Named parameters can be used to reorder evaluation, so we should error if named parameter use results in an argument being
evaluated after the interpolated string that needs it. We will implement a warning at the method declaration if the signature of the method requires
named parameters to need to be used at the call site.
We also looked at the proposal around allowing interpolated strings to be "seen" through conversion expressions and through binary addition expressions.
Binary addition being proposed resulted from prototyping work in the runtime to use the builder, while the conversion proposal was a logical next step.
After discussion, we don't think that the use case of needing to disambiguate between two overloads with different builder types and otherwise identical
signatures is realistic. We accept the use case for binary addition, but we will only do it for conversions to interpolated builder types as we don't
have an ask for `IFormattable` or `FormattableString` here.
#### Conclusions
Lexical ordering should be respected, and seeing interpolated strings through binary addition expressions will be supported.

View file

@ -0,0 +1,125 @@
# C# Language Design Meeting for April 28th, 2021
## Agenda
1. [Open questions in record and parameterless structs](#open-questions-in-record-and-parameterless-structs)
2. [Improved interpolated strings](#improved-interpolated-strings)
## Quote of the Day
- "I was kinda hoping you'd fight me on this"
## Discussion
### Open questions in record and parameterless structs
https://github.com/dotnet/csharplang/blob/struct-ctor-more/proposals/csharp-10.0/parameterless-struct-constructors.md
https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/record-structs.md
#### Initializers with explicit constructors
The first thing we need to resolve today is a question around our handling of field initializers, both in the presence of an
explicitly-declared constructor(s), and when no constructors are present. There's two parts to this question:
1. Should we synthesize a constructor to run the field initializer? and
2. If we don't, should we warn the user that their field initializer won't be run?
We feel that a simple rule here would be to mirror the observed behavior with reference types: if there is no explicit constructor
for a struct type, we will synthesize that constructor. If that constructor happens to be empty (as it would be today in a
constructorless struct type because field initializers aren't yet supported) we optimize that constructor away. If a constructor
is explicitly declared, we will not synthesize any constructor for the type, and field initializers will not be run by `new S()`
unless the parameterless constructor is also explicitly declared. This does have a potential pit of failure where users would
expect the parameterless constructor to run the field initializers, but synthesizing a parameterless constructor would have bad
knock-on effects for record structs with a primary constructor: what would the parameterless constructor do there? It doesn't
have anything it can call the primary constructor with, and would result in confusing semantics. To address this potential issue,
we think there is room for a warning wave dedicated to using `new S()`, when `S` does not have a parameterless constructor. There
will be some holes in this, particularly around generics: `struct` today implies `new()`, and we're concerned about how breaking
the change would be if we tried to make the warning apply to everywhere that a parameterless struct was substituted for a type
parameter constrained to `struct`. We would also have to take another language feature to enable `where T : struct, new()`, which
isn't allowed today. If there is future appetite for introducing another warning wave to cover the generic hole, we can look at
it at that point.
##### Conclusion
We will only synthesize a constructor when the user does not explicitly declare one. We will consider a warning wave when using
`new` on a struct that does not have a parameterless constructor and also has an explicit constructor with parameters.
#### Record struct primary constructors
Next, we looked at how the parameterless struct constructor feature will interact with record primary constructors. The rule we
decided for the first question ends up making the decisions very simple here:
1. Parameterless primary constructors are allowed on struct types.
2. The rules for whether an explicit constructor needs to call the primary constructor are the same as in record class types. This
applies to an explicit primary constructor too, just like in record class types.
##### Conclusion
Use the above rules.
#### Generating the Equals method with `in`
We looked at a potential optimization around the `Equals` method, where we could generate it with an `in` parameter, instead of
with a by-value parameter. This could help scenarios with large struct types get better codegen. However, when we would want to do
this is a very complicated heuristic. For structs smaller than machine pointer size, it is usually faster to pass by value. This
gets even more complex when considering types that are passed in non-standard registers, such as vectorized code. We don't think
there's a generalized way to do this heuristic. Instead, we just need to make sure that the user can perform this optimization, if
they want to.
##### Conclusion
We won't attempt to be smart here. Users can provider their more customized equality implementation if they so choose.
#### `readonly` Equality and GetHashCode
Finally in record structs, we looked at automatically marking the `Equals` and `GetHashCode` methods as `readonly`, if the all the
fields they use for the calculation are also all `readonly`. While this would be technically feasible, we're not sure what the
scenario for this is, beyond just marking the entire struct `readonly`. At that point, every method would be readonly, including
the ones we synthesize.
##### Conclusion
We don't do anything smart here. Users can just mark the struct as `readonly`.
### Improved interpolated strings
https://github.com/dotnet/csharplang/issues/4487
We're getting close the end of open questions in this proposal. We looked at 2 today:
#### Confirming `InterpolatedStringBuilderAttribute`
An internal discussion on simplifying the conversion rules resulted in a proposal that we only look for the presence of a specific
attribute on a type to determine if there exists a conversion from an interpolated string literal to the type. This simplification
results in much cleaner semantics: the presence of various methods on the builder type no longer plays into whether the conversion
exists, only whether conversion is valid. This will help users get understandable errors that don't silently fall back to
string-based overloads when a builder doesn't have the right set of `Append` methods to lower the interpolated string.
We also looked at whether we should control the final codegen based on a property on the attribute: we initially proposed conditional
evaluation could be controlled by the attribute. This would potentially let the compiler change the behavior of when expressions in
interpolation holes are evaluated: up front, or in line the `Append` calls. However, the logic for determining the codegen is not
as simple as one property: the `Append` calls can potentially return `bool`s to stop evaluation, and the `Create` method can
potentially `out` a parameter to control this as well. There are valid scenarios for all 4 possibilities here, so a switch that only
allows either all conditional or no conditional isn't a good option. It's also complex because this would be a library author making
a lowering decision for user code. We also note that, if we decide that this is important at a later date, we can extend the pattern
then.
##### Conclusion
Using the attribute is accepted. The `Append` and `Create` method signatures will drive the lowering process.
#### Specific extensions for structured logging
Finally today, we looked at a question around including specific syntax to support structured logging. [Message templates](https://messagetemplates.org/)
are a well-known structured logging format that most of the biggest .NET logging frameworks support, and as we want these libraries
to consider using the improved interpolated strings feature, we looked to see if we can include specific syntax to help encourage
this. After some initial discussion, our general sentiment is that this feels too narrow. An example syntax we considered is
`$"{myExpression#structureName,alignment:format}"`, and while this would work for the scenario, it wouldn't be a meaningful improvement
over simply using a tuple expression: `$"{("structureName", myExpression),alignment:format}"`. It is possible to construct interpolated
string builders that only accept tuples of `string` and `T` in their interpolation holes, and with the other adjustments we made today
there should be good diagnostics for such cases. Further restrictions can be imposed via analyzers, as is possible today. While a more
general string templating system could be interesting, we think that this is a bit too narrow of a focus for a language feature today.
##### Conclusion
We won't pursue specific structured syntax at this time.

View file

@ -0,0 +1,94 @@
# C# Language Design Meeting for May 3rd, 2021
## Agenda
1. [Improved interpolated strings](#improved-interpolated-strings)
2. [Open questions in record structs](#open-questions-in-record-structs)
## Quote of the Day
- "You all have a special way of working"
## Discussion
### Improved interpolated strings
https://github.com/dotnet/csharplang/issues/4487
Today, we got through the last of the open questions around the improved interpolated strings feature proposal.
#### `Create` vs `.ctor`
The first open question is around using the `Create` method instead of a constructor call. The spec today uses a static `Create` method as
an abstraction, to allow a hypothetical builder type to pool reference types in a static context, rather than being forced to return a `new`
instance on every builder creation. However, while this is a nice abstraction, we don't know of any proposed builder types that would take
advantage of this feature, and there are real codegen benefits to using a constructor instead. If we later come across a use case that would
like a static `Create` method instead, we can also add it later by using a switch on the attribute.
##### Conclusion
For better codegen, we will go with a single method of creation, a constructor, not a `Create` method.
#### Converting regular strings to builder types
We could consider any `string` value as being convertible to a builder type automatically via the builder pattern, which is the trivial case
of `value.Length` number of characters with zero interpolation holes. If we were to do this, it would be in the interest of consistency: a
user could more readily reason about how all string types will interact with an API. However, we do already have a mechanism in the language
to enable this: implicit user-defined conversions. Pushing a string through the standard builder pattern will likely be worse for performance
than what an API-author would write in an implicit conversion, and user-defined conversions already have well-defined semantics and impacts
on overload resolution.
##### Conclusion
Rejected. If an API author wants string to be convertible to their builders, they can use a user-defined conversion.
#### `ref struct` builder types in `async` contexts
Today, `ref struct` types are generally forbbiden in `async` contexts. This is because `await` expressions can occur in any subexpression, and
we have not formalized rules around ensuring that a `ref struct` variable does not cross an `await` boundary. In order to enable `ref struct`
builder types in `async` methods, we'd need to do essentially that same work in order to make usage safe. We're not introducing any new tradeoffs
by avoiding this: already today, developers need to choose between using a `ref struct`, and allowing usage in `async` contexts. While we would
be interested in general rules here, we don't think we should do anything special with regard to interpolated strings builder types. If we enable
it in general, interpolated string builders will naturally come along for the ride.
##### Conclusion
We will treat interpolated string builder usage as any other usage of a `ref struct` in `async` methods (today, that means disallowed).
### Open questions in record structs
#### Implementing `ISpanFormattable`
The BCL is adding a new interface for .NET 6, `ISpanFormattable`, which allows types to be formatted directly into a span, rather than having to
create a separate string instance. One immediate thought we have is why are records (struct or class) special here? We often think of records as
being named versions of anonymous types/tuples, so if we were to do this for records we would likely want to do this for those types as well.
This is important because it does impact public API: new overloads of `PrintMembers` will need to be implemented, and how this will interact with
the existing `PrintMembers` method that takes a `StringBuilder` is unclear. We also don't have a clear scenario here: `ToString()` in records is
mainly focused around debugging and logging scenarios. While performance is a nice to have here, it's not an overridding concern, and users who
want to actually use `ToString()` to do more important work can provide their own implementation, and `ISpanFormattable` with it. They can handle
the problems around interop with existing APIs by simply not using those APIs, which will keep the considerations simpler for them.
##### Conclusion
Rejected.
#### Using `InterpolatedStringBuilder` in record formatting
We could potentially optimize the implementation of `ToString()` by using `InterpolatedStringBuilder` as the string-building mechanism, rather
than `StringBuilder`. Unfortunately, this again runs into the problem of needing to interop with existing code, which unfortunately limits our
options here. Without a clear scenario to try and solve, we don't think this is worth it.
##### Conclusion
Rejected.
#### Passing an `IFormatProvider`
We could potentially generate an overload of `ToString` that takes an `IFormatProvider` and passes it to nested contexts. This again runs the
question of lacking a clear scenario and interop with existing code. We additionally don't have a clear idea of when we'd pass the format
provider to a nested type, as there is no standardized `ToString(IFormatProvider)` method on all types. If a user wants to have formatted
strings in their records, they presumably are providing their own implementation anyway, so we don't feel this is appropriate.
##### Conclusion
Rejected.

View file

@ -0,0 +1,95 @@
# C# Language Design Meeting for May 10th, 2021
## Agenda
1. [Lambda improvements](#lambda-improvements)
## Quote of the Day
- "I'll allow it"
## Discussion
### Lambda improvements
#### Lambda natural types in unconstrained scenarios
There are a few related open questions around how we handle lambda expressions and method groups in unconstrained scenarios. These
are scenarios such as:
```cs
var a = (int x) => x; // What is the type of A?
void M1<T>(T t);
M1((int x) => x); // What is the type of T?
void M2(object o);
M2((int x) => x); // What is the type of the expression? ie, o.GetType() returns what?
```
These scenarios are all related to how much we want to define a "default" function type in C#, and how much we think doing so could
stifle later development around value delegates (if we even do such a feature). In C# today, we have 3 function types:
* Delegate types that inherit from `System.Delegate`.
* Expression tree types that inherit from `System.Linq.Expressions.**Expression`.
* Function pointer types.
All of these types support conversions from some subset of method groups or lambdas, and none is currently privileged above another.
Overloads between these types are considered ambiguous, and users must explicitly include information that tells the compiler what
type of function type to use, such as by giving a target type. If we allow `var`, conversions to `object`, and/or unconstrained generic
type inference to work, we would be setting in stone what the "default" function type in C# is. This would be particularly noticeable
if our future selves introduced a form of lightweight delegate types and wanted to make them the default in various forms of overload
resolution. We are doing analogous work with interpolated strings currently, but interpolated strings are a much smaller section of
the language than lambda expressions, and lambda irregularities are potentially much more noticeable.
We could protect our future selves here by making the spec more restrictive: Do not allow lambdas/method groups to be converted to
unconstrained contexts. This would mean no `var`, no unconstrained type parameters, and no conversion to `object`. We would only infer
when there was information that we could use to inform the compiler as to which type of function type to use: conversion to just
`System.Delegate` would be fine, for example, because we know that the delegate type version was being chosen. While this would protect
the ability to introduce a value delegate type later and make it the default, we see some potential usability concerns with making
such a delegate type the default. At this point, we believe such a delegate type would be based on ref structs, and making `var`
declare these types would be minefield for async and other existing scenarios. Using such types by default in generic inference would
have similar issues around ref struct safety rules. And finally, if such a type were converted to `object`, it would by necessity need
to be boxed somewhere, obviating the point of using a lightweight value delegate type in the first place. Given these concerns, we
believe that we would just be protecting our ability to make the same decision later, and that another function type would not be a
good "default".
##### Conclusion
We allow inferring a natural type for a lambda or method group in unconstrained scenarios, inferring Action/Func/synthesized delegate
type, as appropriate.
#### Type inference
We went over the rules as specified in the proposal. The only missing bit is that, at final usage, a function type needs to look at
constraints to determine whether it should be inferred to be a Delegate or an Expression.
##### Conclusion
Accepted, with the additional step around constraints.
#### Direct invocation
Finally today, we looked at supporting direct invocation of lambda expressions. This is somewhat related to the
[first topic](#lambda-natural-types-in-unconstrained-scenarios), but could be implemented even if we chose to do the restrictive version
of that issue because this feature would not require us to actually choose a final function type for the lambda expression. We could
just emit it as a method and call it directly, without creating a delegate instance behind the scenes at all. However, we don't have an
important driving scenario behind this feature: technically it could be used as a form of statement expression, but it doesn't feel like
a good solution to that problem. The main thing we want to make sure works is regularity with other inferred contexts:
```cs
// If this works
var zeroF = (int x) => x;
var zero = zeroF(0);
// This should also work
var zero = ((int x) => x)(0);
// But this wouldn't work with var, so is it fine to have not work here?
var zero = (x => x)(0);
```
##### Conclusion
We generally support the idea, even the final example. It may take more work however, and thus may not make C# 10. We'll create a
more formal specification for approval.

View file

@ -0,0 +1,95 @@
# C# Language Design Meeting for May 12th, 2021
## Agenda
1. [Experimental attribute](#experimental-attribute)
2. [Simple C# programs](#simple-c-programs)
## Quote of the Day
- "I've always felt the shotput with the Rubik's Cube should be part of the Olympics"
## Discussion
Today we took a look at a couple of broader .NET designs that will impact C#, to get an idea of how we feel C# fits into these designs.
### Experimental attribute
https://github.com/dotnet/designs/blob/main/accepted/2021/preview-features/preview-features.md
The first proposal we looked at is the design the runtime team has been working on around preview features. The C# compiler has shipped
preview features in the compiler ahead of language releases before, but this hasn't been very granular, and we've never shipped a version
of the runtime (particularly not an LTS!) where some parts of the runtime and language features built on top are actually still experimental.
Support stories get complicated, particularly when you start mixing installations of LTS versions of .NET 6 and .NET 7 on the same machine.
For example, we'll be shipping a preview of abstract static members in interfaces in .NET 6, but this implementation will _always_ be a
preview. It's possible that, for .NET 7, we'll move the feature out of preview, and the version of the C# compiler in VS installed at that
point would no longer consider abstract statics to be a preview language feature, even if the project itself is targetting .NET 6. To solve
this, the runtime will introduce a new attribute, detailed in the preview feature proposal, which marks APIs and elements of RuntimeFeature
that should be considered preview in this version of the runtime, and then require that the consuming library be marked preview itself.
Where this requirement comes from is one of the open questions in this meeting: should it come from an analyzer or from the compiler itself?
The analyzer approach is initially attractive because it is easier to implement. Roslyn's analyzer infrastructure, particularly with the
investments around both the symbol analyzer model and IOperation, means that it is possible to implement this analyzer almost entirely
language-independently, while a compiler feature would have be implemented in each compiler separately. It is also significantly easier to
maintain an analyzer: turning off analyzer errors is possible for false-positives while bugs are patched, while compiler errors are impossible
to disable. However, this flexibility does come with downsides: it's possible to disable the analyzer for _real_ positives and ship in an
unsupported state, and potentially cause downstream dependencies to take advantage of preview features unintentionally. There's also no
guarantees that users actually enable the analyzer, as they might just disable analyzers for any particular reason. Despite these concerns,
we think that an analyzer is a good path forward, at least initially. We can use an analyzer in .NET 6 to iron out the semantics of how the
feature works, and look at putting the logic into the compiler itself in a future version.
In particular, there are some interesting semantics that still need to be worked out. Should APIs be allowed to introduce or remove previewness
when overriding or implementing a member? For example, `System.Decimal` already has a `+` operator today, and it will be implementing the
preview numeric interfaces that define the `+` abstract static operator. The `+` on System.Decimal is not preview today, nor should it be in
.NET 6, but it _will_ be implementing the preview `+` operator. Explicit implementation is also not always possible for these operators, as
we will have asymmetric operator support in the math interfaces that get unified with a symmetric operator later in the hierarchy, so we
can't rely on enforcing explicit implementation to solve this problem. On the opposite side of this problem, allowing adding of previewness
at more derived API level is problematic, because the user could be calling a less-derived method and therefore accidentally taking advantage
of a preview feature.
Finally, there is some IDE-experience work to think through. While we do want these APIs to show up in places like completion and refactorings,
we would also like to make sure we're not accidentally opting users into preview features that then break their build totally unexpectedly. We
think there is design space similar to our handling of `Obsolete`, such as marking things preview in completion lists.
#### Conclusion
We will proceed with an analyzer for now and look to move that logic into the compiler at a later point, if we think it makes sense. More
design is needed on some parts of the feature, but it doesn't require direct involvement of the LDM.
### Simple C# programs
https://github.com/dotnet/designs/pull/213
Finally today, we looked at "simple" C# programs. We take simple here to mean programs that don't have a lot of complex build logic, and are
possibly on the smaller side code-wise. Simple does _not_ necessarily mean "Hello, World!" and nothing else. While we are interested in the
intro experience, we additionally think there is opportunity to expand to address a market that has traditionally had a bunch of friction to
use C# in today.
C# has historically had a focus on very enterprise scenarios: professional developers working on larger projects using a dedicated IDE. Our
user studies have shown that this workflow isn't what many newer users are expecting, particularly if they're coming from scripting languages
like Go, Javascript, or Python. These users instead expect to be able to simple make a `.cs` file and run it, with potentially more ceremony
as they start adding more complex dependencies or other scenarios. Other expectations exist (such as repls), but our studies have shown that
this is the most popular. An important part of our task here will be figuring out where that "more ceremony" step lies, what that additional
ceremony will look like, and how it will interact with any additions we make to the language (how project-file based projects interact with
`#r` directives, for example).
Investing in tooling that puts NuGet directives in C#, as well as potentially `#load` or other similar file-based directives, is going to
necessitate that we reconcile file structure and project structure in C#. Today, the contents of C# files are very intentionally independent
of their locations on disk: file structure is handled by the project file, and project structure is handled by `using` directives and
namespace declarations. `#r` to local NuGet packages or `#load` to add other `.cs` files would blur the line here.
Another important consideration of these directives is how complex we want to let them get. At the extreme end, these directives could be
nested inside `#if` directives, which starts to necessitate a true preprocessing step that the SDK tooling will need to understand and perform.
Today, preprocessor directives in C# don't have massive effects, and they can be processed in line with lexing. There are restrictions we can
look at for where to allow `#r` and similar directives, and deciding on those restrictions will help inform where exactly that additional
ceremony will land. For example, we could require that all of these directives must be the first things in a file, with nothing preceding
them. This would ensure that conditional NuGet references are that cliff of complexity that requires a project file.
Finally, how much of the project settings do we think is reasonable to control in a .CS file? Is it reasonable to set language version or TFM
in a file? What about output settings such as dll vs exe, or single-file and trimming settings? We don't have answers for these today, and
some of these answers will be driven by discussions with the SDK teams, but they're all part of determining where the cliff of complexity
will land.
#### Conclusion
Overall, we're extremely excited to take this challenge on, and look forward to working through this design to find the edges.

View file

@ -0,0 +1,125 @@
# C# Language Design Meeting for May 17th, 2021
## Agenda
1. [Raw string literals](#raw-string-literals)
## Quote(s) of the Day
- "You have a mongolian vowel separator"
"Dear god"
- "I was expecting [redacted] to flip the table and say I'm out of here"
"When you flip the table at home, how do you clean that up?"
"Exactly, I don't want to have to clean that up"
"Wait wait, that sounds like a new teams feature"
- "Pretty easy to interpolate those results"
"Is that a correct use of the word interpolate?"
"No"
## Discussion
https://github.com/dotnet/csharplang/issues/4304
Today we took a look through the proposal for raw string literals. This would add a new type of string literal to C#, specifically
for working with embedded language scenarios that are difficult to work with in C# today. A number of other languages have added
similar features, though our colleagues on Java are perhaps the most direct inspiration for this proposal (particularly with the
whitespace trimming feature).
Overall, the LDM is universally in favor of the feature. Some details still remain to be worked out, but we believe this is a feature
that will benefit C#, despite the complexity in adding yet another string literal format.
### Single-line vs multi-line
The proposal suggests both single-line and multi-line forms for this new literal format. While multi-line literals are the obvious
headline feature here, we do think there's a use-case for a single-line form: embedded languages like regex are often single-line,
used inline in a method call or similar. They suffer from all the same problems as other embedded languages today (frequent need
for quotes, but using quotes is both hard and results in hard-to-read code).
#### Conclusion
We would like a single-line version.
### Whitespace trimming
Verbatim string literals today have behavior that make them somewhat unpleasant for multiline strings because, if whitespace is not
desired at the start of the line, the literal content has to be fully start-aligned in the file. This leads to a zig-zag code pattern
in the file which breaks up the flow of the file and can make subsequent indentation hard to judge. Trimming solves this by removing
whitespace from the start of every line, determined by the whitespace preceding the final quotes. This feature has a couple of levers
we can tune to increase or decrease the requirements on the user, namely around handling blank lines. The proposal currently says
that blank lines must have a _prefix_ of the removed whitespace on the line. That means that, if the whitespace to be removed is
`<tab> <tab> <space>`, a completely empty line is fine, as is a blank line with `<tab> <tab>`. Both are prefixes of the whitespace to
be removed. However, a line with `<tab> <space>` is _not_ fine, because that is not a prefix of the whitespace to be removed. We
could make this more strict by saying that a blank line must either have the full whitespace to be removed, or no content at all.
While this is more strict, it could end up being a better user experience: whitespace is, by nature, hard to visualize, and providing
a good diagnostic experience around "this whitespace isn't a prefix of that whitespace" is not something we're eager to tackle. On the
other hand, trailing whitespace is pretty easy to accidentally insert today, and we don't make that a compile error by default anywhere
else.
#### Conclusion
We'll go with the stricter behavior for now: blank lines must either contain the entire whitespace being removed, or no text at all.
We can relax this later if it makes the experience better.
### Language fences
We also looked at allowing a language fence in literals, similar to how markdown works. In multiline markdown strings, ```` ```identifier ````
marks the code block as having a specific language, which the markdown renderer can use to render the text inline. In C# string literals
today, there's fragmented support for this implemented in a number of tools: VS, for example, detects when a string is being passed
directly to a regex API, and also has support for a comment syntax to turn on highlighting for different locations. We could standardize
this for C# raw string literals: the proposal is specifically worded such that text is _required_ to start on the line after the open
quotes to allow us to include this feature in the future. One immediate question, however, is how would we support this for single-line
literals. Our existing syntax highlighting support is specifically for regex, which is the exact use case for the single-line version,
but the language specifier doesn't work there. We could potentially support a trailing language specifier for this case, such as
`""".*"?"""regex`, but it would limit the number of things that can be put in the space.
#### Conclusion
We're mixed on language fences, leaning against supporting them for now. More debate is needed.
### Interpolation
This proposal didn't originally have interpolation, but after a large pushback from the community, interpolation was added. Because the
goal of the proposal is to represent all strings without escaping, the immediate next question is how we represent interpolation holes
without requiring escaping of braces. The proposal suggests we use the number of `$`s in front of the raw string to represent the number
of braces required to trigger an interpolation hole: `$$"""{}"""` would be the string `{}`, because `{{}}` is needed to be counted as an
interpolation hole. IDE experience is going to be very important here: context-sensitive interpolation holes are going to be somewhat
harder to keep track of, and refactorings to add additional braces to an existing string if needed will be very helpful for users to avoid
tedious and potentially error-prone manual changes when suddenly the user needs to use the existing number of braces as an actual string
component.
We also considered a slightly different form, `$"""{{`, where the number of braces after the triple quotes controls how interpolations work.
This form, while providing a more direct representation of the number of curlies required, doesn't work for single-line strings and cannot
be applied to all interpolated strings. We further thought about using the number of quotes to control both the number of braces required
for interpolation holes and the number of quotes required to close the string; while this would work for the single-line form, it would
require that all interpolation holes are a minimum of 3 braces, but most scenarios we can think of either don't need braces, or only need
to represent a single open/close brace. It also cannot be extended to all interpolated strings.
#### Conclusion
We want interpolation, and we're ok with using the number of `$`s to control the number of braces.
### Alternative Quotes
We considered whether to use ```` ``` ```` or `'''` instead of or in addition to `"""`. The `` ` `` symbol is concerning because it can
be hard for non-English keyboard layouts to hit; while there are symbols in C# today that are already difficult for these layouts to hit,
we don't want to deliberately introduce more pain for these users. We also don't like the complexity of either having multiple symbols
that can start strings in C#: this proposal is already adding an axis of complexity (for gain we feel is worth it), but we don't think
the additional axes of complexity is worth the tradeoff here. It does mean that the single-line version cannot represent a string that
starts with a `"`, but we think this is an OK tradeoff.
#### Conclusion
Quotes are the only way to start strings. Users that need to start a string with a quote must use the multi-line version.
### Miscellaneous conclusions
Even though we could support parsing long strings of quotes on a non-blank line inside a raw string literal, we will require that if a
user wants to use 4 quotes in a string, the raw string delimiters must be at least 5 quotes long.
Strings like this are supported:
```cs
var z = $$"""
{{{1 + 1}}}
""";
```
The innermost braces are the interpolation holes, the resulting value here would be `{2}`.

View file

@ -0,0 +1,121 @@
# C# Language Design Meeting for May 19th, 2021
## Agenda
1. [Triage](#triage)
1. [Checked operators](#checked-operators)
2. [Relaxing shift operator requirements](#relaxing-shift-operator-requirements)
3. [Unsigned right shift operator](#unsigned-right-shift-operator)
4. [Opaque parameters](#opaque-parameters)
5. [Column mapping directive](#column-mapping-directive)
6. [Only allow lexical keywords](#only-allow-lexical-keywords)
7. [Allow nullable types in declaration patterns](#allow-nullable-types-in-declaration-patterns)
2. [Protected interface methods](#protected-interface-methods)
## Quote of the Day
- "I feel like I've known this before and then I packed it away in some chamber of horrors in my brain"
## Discussion
### Triage
#### Checked operators
https://github.com/dotnet/csharplang/issues/4665
There are some complexities to this proposal (such as betterness rules between checked and unchecked operators), how it will affect VB, and some
potential clunkiness in the interface definitions (`int` shift doesn't overflow today even in checked contexts, but would need to expose both?),
but we think that this is pretty essential to a well-formed generic math interface structure.
##### Conclusion
Triaged into the working set.
#### Relaxing shift operator requirements
https://github.com/dotnet/csharplang/issues/4666
We have some immediate visceral reactions to this, but it's been 21+ years of BCL and other library design and we don't see huge abuse of other
operators. It might be time to lift the restriction here.
##### Conclusion
Triaged into the working set.
#### Unsigned right shift operator
https://github.com/dotnet/csharplang/issues/4682
This is an odd missing operator in general, and a hole in our design for generic math that similar libraries in other languages have filled.
##### Conclusion
Triaged into the working set.
#### Opaque parameters
https://github.com/dotnet/csharplang/issues/4629
We're not a huge fan of how this silently munges with the method signature, and the number of cliffs there are: what happens when a user wants
2 of these parameters with the same type, or wants to add multiple constraints to a type parameter?
##### Conclusion
Rejected. It's possible we could revisit flavors of this with associated types at a later point, but as is this is rejected.
#### Column mapping directive
https://github.com/dotnet/csharplang/issues/4747
We have a few open questions, such as whether we need an end offset as well. However, overall this looks good. These directives are basically
never human-written or read, and it helps solve problems for partner teams using C# as a DSL.
##### Conclusion
Triaged into the working set.
#### Only allow lexical keywords
https://github.com/dotnet/csharplang/issues/4460
This is a discussion that has been building in the LDM for years, particularly around older contextual keywords such as `var` and `dynamic`
used in a type position. We think there are two broad categories of contextual keywords here: keywords that we think are "safe" to reserve,
such as the aforementioned `var`, that are used in positions where standard C# conventions wouldn't allow things to be named in a conflicting
manner: types, for example, are PascalCase by convention in C#, and `var` starts with a lowercase character. Making a break here helps _both_
the compiler team and the average language user, as it simplifies the language and isn't likely to break code that isn't intentionally trying
to avoid the feature. There are other keywords though, such as `yield`, that we think are good to keep as contextual keywords. It makes the
compiler team's life more difficult, but it helps users, and we don't want to make changes here just to make the compiler's job a bit easier.
We think there's opportunity to do work here in the first set, particularly if we take a phased approach where we warn about a keyword in C#
X and then totally deprecate in Y.
##### Conclusion
Triaged into the working set. We'll revisit soon to think about the phased strategy and see what we want to do for C# 10.
#### Allow nullable types in declaration patterns
https://github.com/dotnet/csharplang/issues/4724
There are some really gnarly parsing ambiguities here, but even if we could solve the compiler parsing problem, the human parsing problem will
remain. We don't think those problems are really solveable, and that the gain isn't worth the complexity.
##### Conclusion
Rejected.
### Protected interface methods
https://github.com/dotnet/csharplang/discussions/4718
When DIMs were initially implemented, we were concerned about a `public` member in a type named the same as a `protected` member in an interface
that type is implementing being confused for an implicit implementation of that `protected` member. However, this ends up somewhat hindering the
goal of DIMs in the first place, which was making adding new methods to an interface not be a breaking change. Given this, and given that the
future option for _having_ implicit `protected` interface member implementation was already removed in V1 of DIMs, we'd like to remove this
restriction. We don't think we can treat this as a bugfix, despite the low impact nature, as it was intentional and C# 8 has been out for a year
and a half now. The hardest part will be coming up with a name for the compiler error message: perhaps "Relaxed DIM requirements for non-public
members".
#### Conclusion
We'll relax this restriction as a new language feature.

Some files were not shown because too many files have changed in this diff Show more