[
  {
    "path": ".gitattributes",
    "content": "* text=auto\n"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "*       @dotnet/roslyn-compiler\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Propose a language idea or ask a question\n    url: https://github.com/dotnet/csharplang/discussions/new/choose\n    about: Starting with discussion is the way to create a new proposal.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/docs-feedback.yml",
    "content": "name: Learn feedback control.\ndescription: |\n  ⛔ This template is hooked into the feedback control on the bottom of every page on the learn.microsoft.com site. It automatically fills in several fields for you. Don't use for other purposes. ⛔\nassignees:\n  - BillWagner\nlabels:\n  - Area-Speclets\n  - untriaged\nbody:\n  - type: markdown\n    attributes:\n      value: \"## Issue information\"\n  - type: markdown\n    attributes:\n      value: Select the issue type, and describe the issue in the text box below. Add as much detail as needed to help us resolve the issue.\n  - type: dropdown\n    id: issue-type\n    attributes:\n      label: Type of issue\n      options:\n        - Typo\n        - Spec incorrect\n        - Spec incomplete\n        - Other (describe below)\n    validations:\n      required: true\n  - type: textarea\n    id: feedback\n    validations:\n      required: true\n    attributes:\n      label: Description\n  - type: markdown\n    attributes:\n      value: \"## 🚧 Article information 🚧\"\n  - type: markdown\n    attributes:\n      value: \"*Don't modify the following fields*. They are automatically filled in for you. Doing so will disconnect your issue from the affected article. *Don't edit them*.\"\n  - type: input\n    id: pageUrl\n    validations:\n      required: true\n    attributes:\n      label: Page URL\n  - type: input\n    id: contentSourceUrl\n    validations:\n      required: true\n    attributes:\n      label: Content source URL\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/proposal_template.md",
    "content": "---\nname: Create a language specification\nabout: For proposals that have been invited by a team member.\ntitle: \"[Proposal]: [FEATURE_NAME]\"\n---\n<!--\nHello, and thanks for your interest in contributing to C#! If you haven't been invited by a language design 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.\n\nThis issue should give a very brief description of the feature, with the more complete description and design being contained in the proposal specification. This issue will be used for tracking purposes, and should have enough information to make it obvious what the feature is about for a casual reader.\n-->\n# FEATURE_NAME\n\n* Specification: Link to a filled out [proposal template](../../proposals/proposal-template.md). If not yet available, link to the PR adding the specification.\n* Discussion: Link to the discussion topic for this feature.\n\n## Summary\n[summary]: #summary\n\n<!-- Short summary of the feature; the full explanation should be in the checked-in specification. -->\n\n## Design meetings\n\n<!-- Link to design notes that affect this proposal, and describe in one sentence for each what changes they led to. -->\n"
  },
  {
    "path": ".gitignore",
    "content": ".vscode/*\n\n# Ignore temporary files\n~$*\n*~\n"
  },
  {
    "path": "CODE-OF-CONDUCT.md",
    "content": "# Code of Conduct\n\nThis project has adopted the code of conduct defined by the Contributor Covenant\nto clarify expected behavior in our community.\n\nFor more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct).\n"
  },
  {
    "path": "Communities.md",
    "content": "**Disclaimer**: This document is maintained by the C# community and not the responsibility of the C# Language Design Team (LDT). Please do not contact the LDT for any errors in this document; however, PRs are welcome. \n\n**Channels:**\n\n- [Dotnet Discord](https://aka.ms/dotnet-discord-csharp) - github.com/dotnet discord for discussing dotnet repositories (including csharplang).\n\n    [![Chat on Discord](https://discordapp.com/api/guilds/143867839282020352/widget.png)](https://aka.ms/dotnet-discord-csharp)\n\n- [C# Discord](https://aka.ms/csharp-discord) - General C# discussion not limited to the dotnet repositories.\n\n    [![Chat on Discord](https://discordapp.com/api/guilds/102860784329052160/widget.png)](https://aka.ms/csharp-discord)\n\n- IRC - Any discussion related to the C# language up to the application level.\n\n    [![Join the chat at https://www.irccloud.com/invite?channel=%23%23csharp&amp;hostname=irc.freenode.net&amp;port=6697&amp;ssl=1](https://img.shields.io/badge/IRC-%23%23csharp-1e72ff.svg?style=flat)](https://www.irccloud.com/invite?channel=%23%23csharp&amp;hostname=irc.freenode.net&amp;port=6697&amp;ssl=1) \n\n    Servers: irc.freenode.net, chat.freenode.net\n    \n    Channel: ##csharp\n\n    [![Join the chat at https://www.irccloud.com/invite?channel=%23c%23&amp;hostname=irc.quakenet.org&amp;port=6697&amp;ssl=1](https://img.shields.io/badge/IRC-%23c%23-1e72ff.svg?style=flat)](https://www.irccloud.com/invite?channel=%23c%23&amp;hostname=irc.quakenet.org&amp;port=6697&amp;ssl=1) \n\n    Servers: irc.quakenet.org\n    \n    Channel: #c#\n\n    Recommended IRC Clients: HexChat, mIRC.\n\n**Forums:**\n\n- [Stack Overflow](https://stackoverflow.com)\n\n    Please read [this](https://stackoverflow.com/help/dont-ask) before posting.\n\n- [Reddit](https://www.reddit.com/r/csharp/)\n\n    Please read [this](https://www.reddit.com/r/csharp/comments/3xn6sm/welcome_to_rcsharp_read_this_post_before) before posting.\n"
  },
  {
    "path": "Design-Process.md",
    "content": "# Language Design Process\n\nThe language design process is the steps that a proposal takes throughout its life, going from an initial seed of an idea, to a championed proposal that is being considered\nfor inclusion in the language, all the way to the final specification representing a feature that has been shipped as part of a .NET release. It is very important to the\nlanguage design team that we have a clear process and organization for this, for multiple reasons:\n\n* Our community is very active and vocal on this repo, and we want to make sure that feedback can be heard and impact the design and direction of the language, as well as\n  ensuring that the community can follow the state of designs.\n* We want to make sure that we are using our design energy effectively, and that we can see the status of previous meetings as we drive a feature to completion.\n* We want to be able to look back historically to use previous design decisions to inform new language features, as well as to ensure that when a feature is incorporated into\n  the ECMA spec, it captures the full nuances of what was designed.\n\nTo achieve these goals, this repository covers the actual proposed text for new language features (often called speclets), notes from language design meetings (called LDM),\nintermediate documents being worked on as part of the development of proposals, issues tracking features that we want to include in the C# language (champion issues), and\ndiscussion topics for those features. In order to keep things organized, we keep discussion of proposals to actual discussions; issues are for tracking purposes only. This\npolicy is changed from previous history in the csharplang repo, so many (most) issues will have some historical discussion in them. However, threaded discussion topics are\nbetter for the types of branching conversations that language features have, so all new discussion will happen in the Discussion forum, rather than on issues.\n\n## Steps of the process\n\nThere are a few steps along the path from the seed of an idea all the way to an implemented language feature that is in an official ECMA specification. While much of that\nprocess takes place outside of this repository (https://github.com/dotnet/roslyn for the language feature implementation, https://github.com/dotnet/runtime for supporting\nBCL APIs and runtime changes, https://github.com/dotnet/csharpstandard/ for the specification changes, just to name a few), we track the overall implementation of the feature\nin this repository, and take the following steps to make understanding the current status easier.\n\n### Proposed feature\n\nNew ideas are submitted as [discussions](https://github.com/dotnet/csharplang/discussions). These ideas can be very freeform, though we ask that you search for duplicates\nbefore opening a new discussion, as the most common first comment on new discussions is one or more links to existing discussions that cover the idea. While ideas are welcome,\nthere is no guarantee that an idea will be adopted into the language; even among things that have been triaged for eventual inclusion in the language, there is more work\nthan can be done in a single lifetime. In order to move forward, a member of the language design team (LDT) has to decide to \"champion\" the idea. This is effectively the\nLDT member deciding to sponsor the idea, and to bring it forward at a future LDM. Most features do not make it out of this stage.\n\nIn order to move to the next stage, there needs to be enough detail to fill out the [proposal template](proposals/proposal-template.md) with at least some amount of detail.\nWhile we do not need exact spec language at this point, there should be enough information that other LDT members can get a general idea of the feature, what areas of the\nlanguage it will impact, and where the complicated aspects are likely to be. In order to be triaged as part of an LDM, this template will need to be checked into the repo.\n\n#### Stage Lifecycle\n\n* Starts when a new discussion is opened\n* Moves to [Championed feature](#championed-feature) when an LDT member decides to champion\n    * For LDT members, see [these instructions](#steps-to-move-a-discussion-to-a-champion-feature) for how to move to the next stage.\n\n### Championed feature\n\nA championed feature is an idea for a C# language feature that an LDT member has decided to sponsor, or \"champion\", for possible inclusion into C#. You can identify issues\nin this category by looking for issues with\n[this query](https://github.com/dotnet/csharplang/issues?q=is%3Aissue%20state%3Aopen%20no%3Amilestone%20label%3A%22Proposal%20champion%22), issues with the `Proposal Champion`\nlabel and no milestone. For these issues, one or more LDT members have indicated that they are interested in the idea, but the entire LDM has not met to discuss the idea and\ngive an official blessing. We try to triage these every few months, though when we start wrapping up a particular release and design time is needed for active questions on\nfeatures currently under development, we can lag behind here.\n\n#### Stage Lifecycle\n\n* Starts when an LDT member decides to champion a [proposed feature](#proposed-feature)\n* Moves to [rejected feature](#rejected-feature) if rejected at LDM\n* Moves to [triaged feature](#triaged-feature) if approved at LDM and assigned to a development milestone\n\n### Triaged feature\n\nA triaged feature is a championed issue that has been approved at LDM for inclusion in a future release of C#. We have quite a few issues in this bucket; they are visible\nby looking at any issues labeled `Proposal Champion` that have been assigned to one of the development milestones, `Any Time`, `Backlog`, `Needs More Work`, or `Working Set`.\n[This query](https://github.com/dotnet/csharplang/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22Proposal%20champion%22%20(milestone%3ABacklog%20OR%20milestone%3A%22Any%20Time%22%20OR%20milestone%3A%22Needs%20More%20Work%22%20OR%20milestone%3A%22Working%20Set%22%20))\nshows these issues. The development milestones mean the following:\n\n* `Working Set` - These are features that are being actively worked on by LDT and/or Roslyn compiler members in some form; whether that's design work behind the scenes,\n  active LDMs discussing the topics, or other actions.\n* `Backlog` - These are features that have been approved for inclusion in C# at some LDM in the past, but are not currently being actively worked on. These are not open to\n  community implementation; they are usually too large or involved to devote LDM time to unless we're willing to make an active effort to get them into the language.\n* `Needs More Work` - These are features that have been approved for inclusion in C# at some LDM in the past, but there are currently design aspects or blocking issues that\n  prevent active work from proceeding at this point.\n* `Any Time` - These are features that have been approved for inclusion in C# at some LDM in the past that are open for community members to contribute to C#. Please do keep\n  in mind that the C# compiler team is constrained by resource limits, and will need to devote significant time to helping get even the simplest of features into the language;\n  please ask _before_ starting to work on one of these features to make sure the team is currently able to devote that time. Features in this category can be in one of two states,\n  denoted by labels on the issue:\n    * `Needs Approved Specification` - LDT has approved this in theory, but has not been presented with a precise specification for how the feature will work. Before implementation\n      can proceed, a complete specification needs to be created and approved at an LDM.\n    * `Needs Implementation` - A specification for this feature has been approved at a previous LDM, and needs to be implemented in the C# compiler.\n\nThis state is the one that will consume most of an approved feature's lifecycle, on average. It is not uncommon for a feature that is approved in theory to spend years in the\nbacklog and/or working set before being implemented.\n\n#### Stage Lifecycle\n\n* Starts when a [championed feature](#championed-feature) is approved at LDM and assigned to a development milestone\n* Ends when the feature is [implemented](#implemented-feature) as part of a C# release\n    * For LDT members, see [these instructions](#steps-to-move-a-triaged-feature-to-an-implemented-feature) for steps to take when shipping a feature.\n* Ends if the feature is reconsidered at an LDM and then [rejected](#rejected-feature)\n\n### Implemented feature\n\nOnce a feature has been implemented in the [Roslyn](https://github.com/dotnet/roslyn) C# compiler and been released as part of an official C# release, it is considered implemented.\nAt this point, it will have a complete speclet available in the [proposals/csharp-\\<release version\\>](proposals) folder (note that some older C# features, particularly the C# 7.X\nand prior features, did not follow this, and have incomplete or non-existent speclets). At this point, the issue will be labeled `Implemented Needs ECMA Specification`, but it will\nnot be closed until the ECMA-334 specification is updated with the feature. This can take some time; the ECMA-334 committee is working on catching up as fast as they can, but is\nseveral years behind the language implementation.\n\n#### Stage Lifecycle\n\n* Starts when a [triaged feature](#triaged-feature) is shipped as part of a C# release\n* Ends when the feature is fully incorporated into a version of the ECMA-334 specification\n\n### ECMA-specified feature\n\nAt this point, the feature has been fully incorporated by ECMA-TC49-TG2, the C# standards committee, into the\n[official C# ECMA specification](https://github.com/dotnet/csharpstandard/). When this happens, we close the issue as completed, and all development work on the feature is\ncomplete.\n\n#### Stage Lifecycle\n\n* Starts when an [implemented feature](#implemented-feature) is shipped as part of a C# release\n* This is the final state for a feature that is included in C#, no further state changes occur\n\n### Rejected feature\n\nWhen a feature is explicitly considered during an LDM, and the LDT decides as a group to reject it, it moves to this state. At this point, close the champion issue as not planned\nand set the milestone to `Likely Never`. It's not impossible for an issue to be pulled back out of this state and included in the language in the future, but generally, this state\nmeans that the feature will never be part of C#.\n\n#### Stage Lifecycle\n\n* Starts when a [championed feature](#championed-feature) is considered at LDM and rejected\n* While it is possible that some rejected features end up getting reconsidered, this is generally the final state for language features that are explicitly considered and\n  rejected during LDM\n\n## Language Design Team processes\n\nThese are various processes and actions taken by LDT members during the development of a feature. Community members should not perform these actions unless invited to do so\nby an LDT member.\n\n### Steps to move a [Discussion](#proposed-feature) to a [Champion feature](#championed-feature)\n\nWhen an LDT member decides to champion a discussion, they take the following steps:\n\n1. Create a new proposal champion issue.\n    * If preferred, the LDT member can ask the original proposer to create this issue.\n    * Note: it can be easier to create the PR for step 6 first, get that into a ready-to-merge state, and then create the champion issue at that point, depending on the complexity\n      of the feature.\n    * The champion issue should have a short summary of the feature, but not the full proposal; there should be enough detail to jog the memory and/or get someone interested in reading the full\n      specification, but should not have detail that will end up needing to be edited often as a proposal evolves.\n2. Assign themselves to the champion issue.\n3. Apply the `Proposal Champion` label to the new issue, as well as to the original discussion.\n4. Link to the original discussion from the champion issue.\n5. Lock the proposal champion issue for comments to ensure that discussion continues in the discussion area, rather than on the champion issue.\n6. Fill out and check in a [proposal template](proposals/proposal-template.md) for the feature. Exact spec language is not required, but there should be enough detail to have a\n   meaningful triage session.\n    * This is also something the LDT member can ask a community member to open a PR for, if they are willing.\n    * The filled out proposal should include a link to the champion issue for easy navigation.\n\n### Bringing open questions to LDM\n\nDuring the course of development of a feature, there are several different types of questions that need to get brought to LDM for answers. The most important overriding factor\nfor any question is that there is a checked-in commit that contains the question. The document and commit will be linked as part of the notes so that future readers of the notes\ncan understand the full context in which the question was asked.\n\n#### Alternative proposals, supplemental documentation\n\nAs part of the initial design of a feature, a number of different proposals may be brought as part of the design process, either as alternatives to an initial design, or as\nsupplemental materials to an existing design to help drive conversation in LDM. We want to keep these \"supplemental\" materials in one place, rather than scattered throughout\nthe repo as different issues, discussions, and other documents. For such material, they should go in the [working group folder](meetings/working-groups/) for that feature. Not\nall features will have such a folder; indeed, most will not. For these documents, please check them in _before_ bringing them to an LDM. The LDM organizer should be able to\nlink to an exact document, not to a PR. In the event the proposer wants to solicit input before LDM, they can leave the PR open until a day or two before LDM; in such a case the\nLDM organizer may decide to link to the PR in the schedule instead of a specific document. However, the PR must be merged before LDM.\n\n#### Specific implementation questions\n\nDuring the implementation process, we will often come up with specific scenarios that need to be brought to an LDM and discussed. These questions should be placed in the proposal\nspecification, in an `Open Questions` section below the main specification text. Each question should have a _linkable_ header, such that the notes that go over the question can\nlink to the exact question being asked. For these questions, please check them in _before_ bringing them to an LDM. The LDM organizer should be able to link to a specific heading\nin a specific document, not to a PR. In the event the questioner wants to solicit input before LDM, they can leave the PR open until a day or two before LDM; in such a case the\nLDM organizer may decide to link to the PR in the schedule instead of a specific document. However, the PR must be merged before LDM.\n\nOnce a question has been answered, the specification should be updated to include any changes required, and the question should be removed. We link to exact commits in the notes\nto ensure that questions can still be found, while keep speclets neat and free of potentially confusing syntax examples that may be rejected at LDM.\n\n#### Proposed specification updates\n\nSometimes during implementation, a specification needs to be updated. These updates are often best viewed by looking at a PR diff; however, PRs present a problem for historical\nrecording keeping. While GitHub does keep around commits that were only ever part of a PR (either because the PR was closed, or because it was squashed/rebased), reusing a PR\nacross multiple LDM sessions can make it difficult to understand the exact state of the PR when it was reviewed by LDM. Whenever possible, do not reuse PRs between multiple LDM\nsessions. When a PR is reviewed by LDM, either close or merge it, and make a new PR for the next LDM to pick up where it left off. This is a guideline, not a rule; there will be\ntimes this cannot happen for whatever reason. But the following rules _must_ be followed:\n\n1. Do not force push over commits that have been reviewed by LDM.\n2. When scheduling your topic for LDM, please use GitHub commit URL or commit range URL. The PR link can be included as well, but the commit (range) is required for inclusion in\n   the notes. The LDM organizer should be able to link to exactly what will be reviewed in the LDM session.\n\n### Steps to move a [triaged feature](#triaged-feature) to an [implemented feature](#implemented-feature)\n\nOnce a feature has been implemented and has or soon will be shipped, take the following steps (these are usually done in bulk when a release nears):\n\n1. If a folder for the C# release does not exist yet, create it.\n2. Move the specification for the feature into that folder and review relative links it contains.\n3. Update the champion issue as follows:\n   1. Update the specification link to point at the new location.\n   2. Update the milestone of the issue to be the C# release it has shipped/will ship in, creating it if it doesn't exist.\n   3. Add the version of .NET and VS it will/did ship in to the issue title.\n        * As an example, `[Proposal]: Params Collections` became `[Proposal]: Params Collections (VS 17.10, .NET 9)`\n   4. Add the `Implemented Needs ECMA Spec` label to the issue.\n4. Add the feature to the [language version history](Language-Version-History.md) document.\n\n### Publishing notes (for the LDM notetaker)\n\nWhen publishing a set of notes, take the following steps:\n\n1. Put the notes in the appropriate `meetings/<year>` folder. Notes should follow the `LDM-<year>-<month>-<date>.md` format.\n   1. Any supplemental documents for the meeting are also included here with the same prefix to ensure good sorting.\n   2. Include an agenda at the top with document-relative links to each section corresponding to the topics discussed during LDM.\n   3. Include both the champion issue and the reviewed specification for a given topic.\n   4. Ensure there are two spaces at the end of lines that do not have an extra line break (such as between entries for the champion issue and specification).\n   5. All links should be permalinks (rather than branch links). If you press \"y\" on the page, the URL in the browser will update to the permalink.\n2. Update the `meetings/<year>/README.md` to:\n   1. Move the date into the `C# Language Design Notes for <year>` section\n   2. Update the agenda to match what is in the meeting notes, with the document-relative links removed.\n   3. Include a link to the notes. This format is usually `[C# Language Design Meeting for <month> <day>, <year>](absolute-note-link)` (use the branch link here).\n   4. When entering the questions discussed, use the question rather than the outcome.\n   5. If a topic was not discussed during LDM, or not fully finished, move the topic line back to `Schedule ASAP`.\n3. Commit the updates. Prefer using spelled out dates (ie, January 1st, 1970), rather than abbreviations, to avoid confusion.\n4. Update the champion issues of discussed topics with a link to the notes. Prefer using an exact link to the heading for that set of notes.\n5. Create a discussion for the new notes. The title format is `LDM Notes for <month> <day>, <year>`. Set the category to `LDM Notes`.\n   1. The discussion should link to the full notes, and copy the agenda from the README.\n6. Post the discussion to various communities to let people know the notes are up; at a minimum, to the C# LDM teams chat. We often post to\n   discord as well, but that is dependent on people being who are on discord not being on vacation.\n"
  },
  {
    "path": "Language-Version-History.md",
    "content": "Features Added in C# Language Versions\n====================\n\n# C# 14.0 - .NET 10 and Visual Studio 2026 version 18.0\n- [Extension methods and properties](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-14.0/extensions.md): allows extending an existing type with instance or static methods and properties.\n- [Extension operators](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-14.0/extension-operators.md): allows extending an existing type with operators.\n- [`field` keyword in properties](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-14.0/field-keyword.md): `field` allows access to the property's backing field without having to declare it.\n- [Partial events and constructors](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-14.0/partial-events-and-constructors.md): allows the partial modifier on events and constructors to separate declaration and implementation parts.\n- [User-defined compound assignment operators](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-14.0/user-defined-compound-assignment.md): allow user types to customize behavior of compound assignment operators in a way that the target of the assignment is modified in-place (`public void operator +=(int x)`).\n- [First-class `Span` types](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-14.0/first-class-span-types.md): streamlines usage of `Span`-based APIs by improving type inference and overload resolution.\n- [Null-conditional assignment](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-14.0/null-conditional-assignment.md): permits assignment to occur conditionally within a `a?.b` or `a?[b]` expression (`a?.b = c`).\n- [Unbound generic types in `nameof`](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-14.0/unbound-generic-types-in-nameof.md): relaxes some restrictions on usage of generic types inside `nameof` (`nameof(List<>)`).\n- [Simple lambda parameters with modifiers](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-14.0/simple-lambda-parameters-with-modifiers.md): allows lambda parameters to be declared with modifiers without requiring their types (`(ref entry) => ...`).\n- [Ignored directives](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-14.0/ignored-directives.md): add `#:` directive prefix to be used by `dotnet run app.cs` tooling but ignored by the language.\n- [Optional and named arguments in `Expression` trees](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-14.0/optional-and-named-parameters-in-expression-trees.md): relaxes some restrictions on `Expression` trees (`Expression<...> e = (a, i) => a.Contains(i, comparer: null);`).\n\n# C# 13.0 - .NET 9 and Visual Studio 2022 version 17.12\n- [ESC escape sequence](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-13.0/esc-escape-sequence.md): introduces the `\\e` escape sequence to represent the ESCAPE/ESC character (U+001B).\n- [Method group natural type improvements](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-13.0/method-group-natural-type-improvements.md): look scope-by-scope and prune inapplicable candidates early when determining the natural type of a method group.\n- [`Lock` object](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-13.0/lock-object.md): allow performing a `lock` on `System.Threading.Lock` instances.\n- Implicit indexer access in object initializers: allows indexers in object initializers to use implicit Index/Range indexers (`new C { [^1] = 2 }`).\n- [`params` collections](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-13.0/params-collections.md): extends `params` support to collection types (`void M(params ReadOnlySpan<int> s)`).\n- [`ref`/`unsafe` in iterators/async](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-13.0/ref-unsafe-in-iterators-async.md): allows using `ref`/`ref struct` locals and `unsafe` blocks in iterators and async methods between suspension points.\n- [`ref struct` interfaces](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-13.0/ref-struct-interfaces.md): allows `ref struct` types to implement interfaces and introduces the `allows ref struct` constraint.\n- [Overload resolution priority](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-13.0/overload-resolution-priority.md): allows API authors to adjust the relative priority of overloads within a type using `System.Runtime.CompilerServices.OverloadResolutionPriority`.\n- [Partial properties](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-13.0/partial-properties.md): allows splitting a property into multiple parts using the `partial` modifier.\n- [Better conversion from collection expression element](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-13.0/collection-expressions-better-conversion.md): improves overload resolution to account for the element type of collection expressions.\n\n# C# 12.0 - .NET 8 and Visual Studio 2022 version 17.8\n\n- [Collection expressions](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md): provides a uniform and efficient way of creating collections using collection-like types (`List<int> list = [1, 2, 3];`)\n- [Primary Constructors](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/primary-constructors.md): helps reduce field and constructor boilerplate (`class Point(int x, int y);`)\n- [Inline Arrays](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/inline-arrays.md): provides a general-purpose and safe mechanism for declaring arrays using the `[InlineArray(size)]` attribute.\n- [Using aliases for any type](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/using-alias-types.md): relaxes many restrictions on `using` alias declarations, allowing built-in types, tuple types, pointer types, array types (`using Point = (int x, int y);`)\n- [Ref readonly parameters](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/ref-readonly-parameters.md): `ref readonly` parameters mandate that arguments are passed by reference instead of potentially copied, can’t be modified, and warn if a temporary variable must be created.\n- [Nameof accessing instance members](https://github.com/dotnet/csharplang/issues/4037): relaxes some restrictions on usage of instance members inside `nameof` (`nameof(field.ToString)`)\n- [Lambda optional parameters](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/lambda-method-group-defaults.md): allows lambda parameters to declare default values (`(int i = 42) => { }`)\n\n# C# 11.0 - .NET 7 and Visual Studio 2022 version 17.4\n\n- [Raw string literals](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/raw-string-literal.md): introduces a string literal where the content never needs escaping (`var json = \"\"\"{ \"summary\": \"text\" }\"\"\";` or `var json = $$\"\"\"{ \"summary\": \"text\", \"length\": {{length}} }\"\"\";`).\n- [UTF-8 string literals](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/utf8-string-literals.md): UTF-8 string literals with the `u8` suffix (`ReadOnlySpan<byte> s = \"hello\"u8;`)\n- [Pattern match `Span<char>` on a constant string](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/pattern-match-span-of-char-on-string.md): an input value of type `Span<char>` or `ReadonlySpan<char>` can be matched with a constant string pattern (`span is \"123\"`).\n- [Newlines in interpolations](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/new-line-in-interpolation.md): allows newline characters in single-line interpolated strings.\n- [List patterns](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/list-patterns.md): allows matching indexable types (`list is [1, 2, ..]`).\n- [File-local types](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/file-local-types.md): introduces the `file` type modifier (`file class C { ... }`).\n- [Ref fields](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/low-level-struct-improvements.md): allows `ref` field declarations in a `ref struct` (`ref struct S { ref int field; ... }`), introduces `scoped` modifier and `[UnscopedRef]` attribute.\n- [Required members](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/required-members.md): introduces the `required` field and property modifier and `[SetsRequiredMembers]` attribute.\n- [Static abstract members in interfaces](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/static-abstracts-in-interfaces.md): allows an interface to specify abstract static members.\n- [Unsigned right-shift operator](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/unsigned-right-shift-operator.md): introduces the `>>>` operator and `>>>=`.\n- [`checked` user-defined operators](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/checked-user-defined-operators.md): numeric and conversion operators support defining `checked` variants (`public static Int128 operator checked +(Int128 lhs, Int128 rhs) { ... }`).\n- [Relaxing shift operator requirements](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/relaxing_shift_operator_requirements.md): the right-hand-side operand of a shift operator is no longer restricted to only be `int`\n- [Numeric IntPtr](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/numeric-intptr.md): `nint`/`nuint` become simple types aliasing `System.IntPtr`/`System.UIntPtr`.\n- [Auto-default structs](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/auto-default-structs.md): struct constructors automatically default fields that are not explicitly assigned.\n- [Generic attributes](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/generic-attributes.md): allows attributes to be generic (`[MyAttribute<int>]`).\n- [Extended `nameof` scope in attributes](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/extended-nameof-scope.md): allows `nameof(parameter)` inside an attribute on a method or parameter (`[MyAttribute(nameof(parameter))] void M(int parameter) { }`).\n\n# C# 10.0 - .NET 6 and Visual Studio 2022 version 17.0\n\n- [Record structs](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-10.0/record-structs.md) (`record struct Point(int X, int Y);`, `var newPoint = point with { X = 100 };`).\n- [With expression](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/record-structs.md#allow-with-expression-on-structs) on structs and anonymous types.\n- [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.\n- [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`.\n- [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.\n- [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\" })`).\n- [Sealed record ToString](https://github.com/dotnet/csharplang/issues/4174): a record can inherit a base record with a sealed `ToString`.\n- [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.\n- [Mixed deconstructions](https://github.com/dotnet/csharplang/issues/125): deconstruction-assignments and deconstruction-declarations can be blended together (`(existingLocal, var declaredLocal) = expression`).\n- [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.\n- [#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\"`).\n- [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;`).\n- [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.\n- [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;`).\n- [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.\n- [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.\n\n# C# 9.0 - .NET 5 and Visual Studio 2019 version 16.8 \n- [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 };`).\n- [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; }`).\n- [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.\n- [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:`).\n- [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.\n- [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;`)\n- [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.\n- [Target-typed new expressions](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/target-typed-new.md): `Point p = new(42, 43);`.\n- [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 () => { ... };`).\n- [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;`).\n- [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.\n- [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.\n- [Attributes on local functions](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/local-function-attributes.md).\n- [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.\n- [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`.\n- [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.\n- [Source Generators](https://devblogs.microsoft.com/dotnet/introducing-c-source-generators/)\n\n# C# 8.0 - .NET Core 3.0 and Visual Studio 2019 version 16.3 \n- [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.\n- [Default interface members](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-8.0/default-interface-methods.md): interfaces can now have members with default implementations, as well as static/private/protected/internal members except for state (ie. no fields).\n- [Recursive patterns](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-8.0/patterns.md): positional and property patterns allow testing deeper into an object, and switch expressions allow for testing multiple patterns and producing corresponding results in a compact fashion.\n- [Async streams](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-8.0/async-streams.md): `await foreach` and `await using` allow for asynchronous enumeration and disposal of `IAsyncEnumerable<T>` collections and `IAsyncDisposable` resources, and async-iterator methods allow convenient implementation of such asynchronous streams.\n- [Enhanced using](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-8.0/using.md): a `using` declaration is added with an implicit scope and `using` statements and declarations allow disposal of `ref` structs using a pattern.\n- [Ranges and indexes](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-8.0/ranges.md): the `i..j` syntax allows constructing `System.Range` instances, the `^k` syntax allows constructing `System.Index` instances, and those can be used to index/slice collections.\n- [Null-coalescing assignment](https://github.com/dotnet/csharplang/issues/34): `??=` allows conditionally assigning when the value is null.\n- [Static local functions](https://github.com/dotnet/csharplang/issues/1565): local functions modified with `static` cannot capture `this` or local variables, and local function parameters now shadow locals in parent scopes.\n- [Unmanaged generic structs](https://github.com/dotnet/csharplang/issues/1744): generic struct types that only have unmanaged fields are now considered unmanaged (ie. they satisfy the `unmanaged` constraint).\n- [Readonly members](https://github.com/dotnet/csharplang/issues/1710): individual members can now be marked as `readonly` to indicate and enforce that they do not modify instance state.\n- [Stackalloc in nested contexts](https://github.com/dotnet/csharplang/issues/1412): `stackalloc` expressions are now allowed in more expression contexts.\n- [Alternative interpolated verbatim strings](https://github.com/dotnet/csharplang/issues/1630): `@$\"...\"` strings are recognized as interpolated verbatim strings just like `$@\"...\"`.\n- [Obsolete on property accessors](https://github.com/dotnet/csharplang/issues/2152): property accessors can now be individually marked as obsolete.\n- [Permit `t is null` on unconstrained type parameter](https://github.com/dotnet/csharplang/issues/1284)\n\n# C# 7.3 - Visual Studio 2017 version 15.7\n- `System.Enum`, `System.Delegate` and [`unmanaged`](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.3/blittable.md) constraints.\n- [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`).\n- [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 };`.\n- [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.\n- [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.\n- [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.\n- [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.\n-\t[Tuple comparison](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.3/tuple-equality.md): Tuples can now be compared with `==` and `!=`.\n-\t[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.\n\n# [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\n- [Span and ref-like types](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/span-safety.md)\n- [In parameters and readonly references](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/readonly-ref.md)\n- [Ref conditional](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/conditional-ref.md)\n- [Non-trailing named arguments](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/non-trailing-named-arguments.md)\n- [Private protected accessibility](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/private-protected.md)\n- [Digit separator after base specifier](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/leading-separator.md)\n\n# [C# 7.1](https://blogs.msdn.microsoft.com/dotnet/2017/10/31/welcome-to-c-7-1/) - Visual Studio 2017 version 15.3\n- [Async main](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/async-main.md)\n- [Default expressions](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/target-typed-default.md)\n- [Reference assemblies](https://github.com/dotnet/roslyn/blob/master/docs/features/refout.md)\n- [Inferred tuple element names](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/infer-tuple-names.md)\n- [Pattern-matching with generics](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/generics-pattern-match.md)\n\n# [C# 7.0](https://blogs.msdn.microsoft.com/dotnet/2017/03/09/new-features-in-c-7-0/) - Visual Studio 2017\n- [Out variables](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/out-var.md)\n- [Pattern matching](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-7.0/pattern-matching.md)\n- [Tuples](https://github.com/dotnet/roslyn/blob/master/docs/features/tuples.md)\n- [Deconstruction](https://github.com/dotnet/roslyn/blob/master/docs/features/deconstruction.md)\n- [Discards](https://github.com/dotnet/roslyn/blob/master/docs/features/discards.md)\n- [Local Functions](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/local-functions.md)\n- [Binary Literals](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/binary-literals.md)\n- [Digit Separators](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/digit-separators.md)\n- [Ref returns and locals](https://docs.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/ref-returns)\n- [Generalized async return types](https://github.com/dotnet/roslyn/blob/master/docs/features/task-types.md)\n- [More expression-bodied members](https://docs.microsoft.com/dotnet/csharp/programming-guide/statements-expressions-operators/expression-bodied-members)\n- [Throw expressions](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/throw-expression.md)\n\n# [C# 6](https://github.com/dotnet/roslyn/blob/master/docs/wiki/New-Language-Features-in-C%23-6.md) - Visual Studio 2015\n- [Draft Specification online](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/README.md)\n- Compiler-as-a-service (Roslyn)\n- [Import of static type members into namespace](https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/using-static)\n- [Exception filters](https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/when)\n- Await in catch/finally blocks\n- Auto property initializers\n- Default values for getter-only properties\n- [Expression-bodied members](https://docs.microsoft.com/dotnet/csharp/programming-guide/statements-expressions-operators/expression-bodied-members)\n- Null propagator (null-conditional operator, succinct null checking)\n- [String interpolation](https://docs.microsoft.com/dotnet/csharp/language-reference/tokens/interpolated)\n- [nameof operator](https://docs.microsoft.com/dotnet/csharp/language-reference/operators/nameof)\n- Dictionary initializer\n\n# [C# 5](https://blogs.msdn.microsoft.com/mvpawardprogram/2012/03/26/an-introduction-to-new-features-in-c-5-0/) - Visual Studio 2012\n- [Asynchronous methods](https://docs.microsoft.com/dotnet/csharp/programming-guide/concepts/async/)\n- [Caller info attributes](https://docs.microsoft.com/dotnet/csharp/language-reference/attributes/caller-information)\n- foreach loop was changed to generates a new loop variable rather than closing over the same variable every time\n\n# [C# 4](https://msdn.microsoft.com/magazine/ff796223.aspx) - Visual Studio 2010\n- [Dynamic binding](https://docs.microsoft.com/dotnet/csharp/programming-guide/types/using-type-dynamic)\n- [Named and optional arguments](https://docs.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments)\n- [Co- and Contra-variance for generic delegates and interfaces](https://docs.microsoft.com/dotnet/standard/generics/covariance-and-contravariance)\n- [Embedded interop types (\"NoPIA\")](https://docs.microsoft.com/dotnet/framework/interop/type-equivalence-and-embedded-interop-types)\n\n# [C# 3](https://msdn.microsoft.com/library/bb308966.aspx) - Visual Studio 2008\n- [Implicitly typed local variables](https://docs.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/implicitly-typed-local-variables)\n- [Object and collection initializers](https://docs.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/object-and-collection-initializers)\n- [Auto-Implemented properties](https://docs.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/auto-implemented-properties)\n- [Anonymous types](https://docs.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/anonymous-types)\n- [Extension methods](https://docs.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/extension-methods)\n- [Query expressions, a.k.a LINQ (Language Integrated Query)](https://docs.microsoft.com/dotnet/csharp/linq/query-expression-basics)\n- [Lambda expression](https://docs.microsoft.com/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions)\n- [Expression trees](https://docs.microsoft.com/dotnet/csharp/programming-guide/concepts/expression-trees/)\n- [Partial methods](https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/partial-method)\n- [Lock statement](https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/lock-statement)\n\n# [C# 2](https://msdn.microsoft.com/library/7cz8t42e(v=vs.80).aspx) - Visual Studio 2005\n- [Generics](https://docs.microsoft.com/dotnet/csharp/programming-guide/generics/)\n- [Partial types](https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/partial-type)\n- [Anonymous methods](https://docs.microsoft.com/dotnet/csharp/programming-guide/statements-expressions-operators/anonymous-functions)\n- [Iterators, a.k.a yield statement](https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/yield)\n- [Nullable types](https://docs.microsoft.com/dotnet/csharp/language-reference/builtin-types/nullable-value-types)\n- Getter/setter separate accessibility\n- Method group conversions (delegates)\n- [Static classes](https://docs.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/static-classes-and-static-class-members)\n- Delegate inference\n- Type and namespace aliases\n- [Covariance and contravariance](https://docs.microsoft.com/dotnet/csharp/programming-guide/concepts/covariance-contravariance/)\n\n# [C# 1.2](https://docs.microsoft.com/dotnet/csharp/whats-new/csharp-version-history#c-version-12) - Visual Studio .NET 2003\n- Dispose in foreach\n- foreach over string specialization\n\n# [C# 1.0](https://en.wikipedia.org/wiki/Microsoft_Visual_Studio#.NET_.282002.29) - Visual Studio .NET 2002\n- [Classes](https://docs.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/classes)\n- [Structs](https://docs.microsoft.com/dotnet/csharp/language-reference/builtin-types/struct)\n- [Enums](https://docs.microsoft.com/dotnet/csharp/language-reference/builtin-types/enum)\n- [Interfaces](https://docs.microsoft.com/dotnet/csharp/programming-guide/interfaces/)\n- [Events](https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/event)\n- [Operator overloading](https://docs.microsoft.com/dotnet/csharp/language-reference/operators/operator-overloading)\n- [User-defined conversion operators](https://docs.microsoft.com/dotnet/csharp/language-reference/operators/user-defined-conversion-operators)\n- [Properties](https://docs.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/properties)\n- [Indexers](https://docs.microsoft.com/dotnet/csharp/programming-guide/indexers/)\n- 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))\n- [`params` arrays](https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/params)\n- [Delegates](https://docs.microsoft.com/dotnet/csharp/programming-guide/delegates/)\n- Expressions\n- [using statement](https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/using-statement)\n- [goto statement](https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/goto)\n- [Preprocessor directives](https://docs.microsoft.com/dotnet/csharp/language-reference/preprocessor-directives/)\n- [Unsafe code and pointers](https://docs.microsoft.com/dotnet/csharp/programming-guide/unsafe-code-pointers/)\n- [Attributes](https://docs.microsoft.com/dotnet/csharp/programming-guide/concepts/attributes/)\n- Literals\n- [Verbatim identifier](https://docs.microsoft.com/dotnet/csharp/language-reference/tokens/verbatim)\n- Unsigned integer types\n- [Boxing and unboxing](https://docs.microsoft.com/dotnet/csharp/programming-guide/types/boxing-and-unboxing)\n"
  },
  {
    "path": "README.md",
    "content": "# C# Language Design\n\n[![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)\n\nWelcome to the official repo for C# language design. This is where new C# language features are developed, adopted and specified.\n\nC# is designed by the C# Language Design Team (LDT) in close coordination with the [Roslyn](https://github.com/dotnet/roslyn) project, which implements the language.\n\nYou can find:\n\n- Active C# language feature proposals in the [proposals folder](proposals)\n- Notes from C# language design meetings in the [meetings folder](meetings)\n- Summary of the [language version history here](Language-Version-History.md).\n\nIf you discover bugs or deficiencies in the above, please leave an issue to raise them, or even better: a pull request to fix them.\n\nFor *new feature proposals*, however, please raise them for [discussion](https://github.com/dotnet/csharplang/labels/Discussion), and *only* submit a proposal as an issue or pull request if invited to do so by a member of the Language Design Team (a \"champion\").\n\nThe complete design process is described [here](Design-Process.md). A shorter overview is below.\n\n## Discussions\n\nDebate pertaining to language features takes place in the form of [Discussions](https://github.com/dotnet/csharplang/discussions) in this repo.\n\nIf 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).\n\nDiscussions 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:\n\n- Discussion should be relevant to C# language design. If they are not, they will be summarily closed.\n- Choose a descriptive topic that clearly communicates the scope of discussion.\n- 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.\n- Is your comment useful for others to read, or can it be adequately expressed with an emoji reaction to an existing comment?\n\nLanguage proposals which prevent specific syntax from occurring can be achieved with a [Roslyn analyzer](https://docs.microsoft.com/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.\n\n## Proposals\n\nWhen a member of the C# LDM finds that a proposal merits consideration by the broader team, 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. Proposals are always discussed in linked discussions, not in the champion issue. We didn't always follow this policy, so many champion issues will have discussion on them; we now lock issues to prevent new discussion from occurring on them. Each champion issue will have a discussion link on it.\n\n## Design Process\n\n[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.\n\nIn 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:\n\n- Parsing (if applicable) should be resilient to experimentation: typing should not cause crashes.\n- Include minimal tests demonstrating the feature at work end-to-end.\n- Include minimal IDE support (keyword coloring, formatting, completion).\n\nOnce approved, a feature should be fully implemented in [Roslyn](https://github.com/dotnet/roslyn), and fully specified in the [language specification](spec), whereupon the proposal is moved into the appropriate folder for a completed feature, e.g. [C# 7.1 proposals](proposals/csharp-7.1).\n\n**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.\n\n### Milestones\n\nWe have a few different milestones for issues on the repo:\n* [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.\n* [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.\n* [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.\n* [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.\n* 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 compatibility or other issues as we near release.\n\n## Language Design Meetings\n\nLanguage 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.\n\n## Language Specification\n\nThe current ECMA-334 specification can be found in markdown form on the [C# Language Standard](https://github.com/dotnet/csharpstandard/) repository.\n\n## Implementation\n\nThe reference implementation of the C# language can be found in the [Roslyn repository](https://github.com/dotnet/roslyn). This repository also tracks the [implementation status for language features](https://github.com/dotnet/roslyn/blob/main/docs/Language%20Feature%20Status.md). Until recently, that was also where language design artifacts were tracked. Please allow a little time as we move over active proposals.\n"
  },
  {
    "path": "meetings/2013/LDM-2013-10-07.md",
    "content": "# C# Language Design Notes for Oct 7, 2013\n\n## Agenda\nWe looked at a couple of feature ideas that either came up recently or deserved a second hearing.\n1.\tInvariant meaning of names <_scrap the rule_>\n2.\tType testing expression <_can’t decide on good syntax_>\n3.\tLocal functions <_not enough scenarios_>\n4.\tnameof operator <_yes_>\n\n## Invariant meaning of names\nC# has a somewhat unique and obscure rule called “invariant meaning in blocks” (documented in section 7.6.2.1 of the language specification) which stipulates that if a simple name is used to mean one thing, then nowhere in the immediately enclosing block can the same simple name be used to mean something else.\n\nThe idea is to reduce confusion, make cut & paste refactoring a little more safe, and so on.\n\nIt is really hard to get data on who has been saved from a mistake by this rule. On the other hand, everyone on the design team has experience being limited by it in scenarios that seemed perfectly legit.\n\nThe rule has proven to be surprisingly expensive to implement and uphold incrementally in Roslyn. This has to do with the fact that it cannot be tied to a declaration site: it is a rule about use sites only, and information must therefore be tracked per use – only to establish in the 99.9% case that no, the rule wasn’t violated with this keystroke either.\n\n### Conclusion\nThe invariant meaning rule is well intentioned, but causes significant nuisance for what seems to be very little benefit. It is time to let it go.\n\n## Type testing expressions\nWith declaration expressions you can now test the type of a value and assign it to a fresh variable under the more specialized type, all in one expression. For reference types and nullable value types:\n``` c#\nif ((var s = e as string) != null) { … s … } // inline type test\n```\nFor non-nullable value types it is a little more convoluted, but doable:\n``` c#\nif ((var i = e as int?) != null) { … i.Value … } // inline type test\n```\nOne can imagine a slightly nicer syntax using a `TryConvert` method:\n``` c#\nif (MyHelpers.TryConvert(e, out string s)) { … s … }\n```\nThe signature of the `TryConvert` method would be something like\n``` c#\npublic static bool TryConvert<TSource, TResult>(TSource src, out TResult res);\n```\nThe problem is that you cannot actually implement `TryConvert` efficiently: It needs different logic depending on whether `TResult` is a non-nullable value type or a nullable type. But you cannot overload a method on constraints alone, so you need two methods with different names (or in different classes).\n\nThis leads to the idea of having dedicated syntax for type testing: a syntax that will a) take an expression, a target type and a fresh variable name, b) return a boolean for whether the test succeeds, c) introduce a fresh variable of the target type, and d) assign the converted value to the fresh variable if possible, or the default value otherwise.\n\nWhat should that syntax be? A previous proposal was an augmented version of the “is” operator, allowing an optional variable name to be tagged onto the type:\n``` c#\nif (e is string s) { … s … } // augmented is operator\n```\nOpinions on this syntax differ rather wildly. While we agree that some mix of “is” and “as” keywords is probably the way to go, no proposal seems appealing to everyone involved. Here are a few:\n``` c#\ne is T x\nT x is e\nT e as x\n```\n(A few sillier proposals were made:\n``` c#\ne x is T\nT e x as\n```\nBut this doesn’t feel like the right time to put Easter eggs in the language.)\n\n### Conclusion\nProbably 90% of cases are with reference (or nullable) types, where the declaration-expression approach is not too horrible. As long as we cannot agree on a killer syntax, we are fine with not doing anything.\n\n## Local functions\nWhen we looked at local functions on Apr 15, we lumped them together with local class declarations, and dismissed them as a package. We may have given them somewhat short shrift, and as we have had more calls for them we want to make sure we do the right thing with local functions in their own right.\n\nA certain class of scenarios is where you need to declare a helper function for a function body, but no other function needs it. Why would you need to declare a helper function? Here are a few scenarios:\n\n* Task-returning functions may be fast-path optimized and not implemented as async functions: instead they delegate to an async function only when they cannot take the fast path.\n* Iterators cannot do eager argument validation so they are almost always wrapped in a non-iterator function which does validation and delegates to a private iterator.\n* Exception filters can only contain expressions – if they need to execute statements, they need to do it in a helper function.\n\nAllowing these helper functions to be declared inside the enclosing method instead of as private siblings would not only avoid pollution of the class’ namespace, but would also allow them to capture type parameters, parameters and locals from the enclosing method. Instead of writing\n``` c#\npublic static IEnumerable<T> Filter<T>(IEnumerable<T> s, Func<T, bool> p)\n{\n    if (s == null) throw new ArgumentNullException(\"s\");\n    if (p == null) throw new ArgumentNullException(\"p\");\n    return FilterImpl<T>(s, p);\n}\nprivate static IEnumerable<T> FilterImpl<T>(IEnumerable<T> s, Func<T, bool> p)\n{\n    foreach (var e in s)\n        if (p(e)) yield return e;\n}\n```\nYou could just write this:\n``` c#\npublic static IEnumerable<T> Filter<T>(IEnumerable<T> s, Func<T, bool> p)\n{\n    if (s == null) throw new ArgumentNullException(\"s\");\n    if (p == null) throw new ArgumentNullException(\"p\");\n    IEnumerable<T> Impl() // Doesn’t need unique name, type params or params\n    {\n        foreach (var e in s)          // s is in scope\n            if (p(e)) yield return e; // p is in scope\n    }\n    return Impl<T>(s, p);\n}\n```\nThe underlying mechanism would be exactly the same as for lambdas: we would generate a display class with a method on it. The only difference is that we would not take a delegate to that method.\n\nWhile it is nicer, though, it is reasonable to ask if it has that much over private sibling methods. Also, those scenarios probably aren’t super common.\n\n### Inferred types for lambdas\nThis did bring up the discussion about possibly inferring a type for lambda expressions. One of the reasons they are so unfit for use as local functions is that you have to write out their delegate type. This is particularly annoying if you want to immediately invoke the function:\n``` c#\n((Func<int,int>)(x => x*x))(3); // What??!?\n```\nVB infers a type for lambdas, but a fresh one every time. This is ok only because VB also has more lax conversion rules between delegate types, and the result, if you are not careful, is a chain of costly delegate allocations.\n\nOne option would be to infer a type for lambdas only when there happens to be a suitable `Func<…>` or `Action<…>` type in scope. This would tie the compiler to the pattern used by the BCL, but not to the BCL itself. It would allow the BCL to add more (longer) overloads in the future, and it would allow others to add different overloads, e.g. with ref and out parameters.\n\n### Conclusion\nAt the end of the day we are not ready to add anything here. No local functions and no type inference for lambdas.\n\n## The nameof operator\nThe `nameof` operator is another feature that was summarily dismissed as a tag-along to a bigger, more unwieldy feature: the legendary `infoof` operator.\n``` c#\nPropertyInfo info = infoof(Point.X);\nstring name = nameof(Point.X); // \"X\"\n```\nWhile the `infoof` operator returns reflection information for a given language element, `nameof` just returns its name as a string. While this seems quite similar at the surface, there is actually quite a big difference when you think about it more deeply. So let’s do that!\n\nFirst of all, let’s just observe that when people ask for the `infoof` operator, they are often really just looking to get the name. Common scenarios include throwing `ArgumentException`s and `ArgumentNullException`s (where the parameter name must be supplied to the exception’s constructor), as well as firing `Notify` events when properties change, through the `INotifyPropertyChanged` interface.\n\nThe reason people don’t want to just put strings in their source code is that it is not refactoring safe. If you change the name, VS will help you update all the references – but it will not know to update the string literal. If the string is instead provided by the compiler or the reflection layer, then it will change automatically when it’s supposed to.\n\nAt a time when we are trying to minimize the use of reflection, it seems wrong to add a feature, `infoof`, that would contribute significantly to that use. `nameof` would not suffer from that problem, as the compiler would just replace it with a string in the generated IL.  It is purely a design time feature.\n\nThere are deeper problems with `infoof`, pertaining to how the language element in question is uniquely identified. Let’s say you want to get the `MethodInfo` for an overload of a method `M`. How do you designate which overload you are talking about?\n``` c#\nvoid M(int x);\nvoid M(string s);\nvar info = infoof(M…); // Which M? How do you say it?\n```\nWe’d need to create a whole new language for talking about specific overloads, not to mention members that don’t have names, such as user defined operators and conversions, etc.\n\nAgain, though, `nameof` does not seem to have that problem. It is only for named entities (why else would you want the name), and it only gives you the name, so you don’t need to choose between overloads, which all have the same name!\n\nAll in all, therefore, it seems that the concerns we have about `infoof` do not apply to `nameof`, whereas much (most?) of its value is retained. How exactly would a `nameof` operator work?\n\n### Syntax\nWe would want the operator to be syntactically analogous to the existing `typeof(…)`. This means we would allow you to say `nameof(something)` in a way that at least sometimes would parse as an invocation of a method called `nameof`. This is ambiguous with existing code only to the extent that such a call binds. We would therefore take a page out of `var`’s book and give priority to the unlikely case that this binds as a method call, and fall back to `nameof` operator semantics otherwise. It would probably be ok for the IDE to always highlight `nameof` as a keyword.\n\nThe operand to `nameof` has to be “something that has a name”. In the spirit of the `typeof` operator we will limit it to a static path through names of namespaces, types and members. Type arguments would never need to be provided, but in every name but the last you may need to provide “generic dimension specifiers” of the shape `<,,,>` to disambiguate generic types overloaded on arity.\n\nThe grammar would be something like the following:\n> _nameof-expression:_\n> * `nameof`   `(`   _identifier_   `)`\n> * `nameof`   `(`   _identifier_   `::`   _identifier_   `)`\n> * `nameof`   `(`   _unbound-type-name_   `.`   _identifier_   `)`\n\nWhere _unbound-type-name_ is taken from the definition of `typeof`. Note that it always ends with an identifier. Even if that identifier designates a generic type, the type parameters (or dimension specifiers) are not and cannot be given. \n\n### Semantics\nIt is an error to specify an operand to `nameof(…)` that doesn’t “mean” anything. It can designate a namespace, a type, a member, a parameter or a local, as long as it is something that is in fact declared.\n\nThe result of the `nameof` expression would always be a string containing the final identifier of the operand. There are probably scenarios where it would be desirable to have a “fully qualified name”, but that would have to be constructed from the parts. After all, what would be the syntax used for that? C# syntax? What about VB consumers, or doc comments, or comparisons with strings provided by reflection? Better to leave those decisions outside of the language.\n\n### Conclusion\nWe like the `nameof` operator and see very few problems with it. It seems easy to spec and implement, and it would address a long-standing customer request. With a bit of luck, we would never (or at least rarely) hear requests for `infoof` again.\n\nWhile not the highest priority feature, we would certainly like to do this.\n\n\n\n"
  },
  {
    "path": "meetings/2013/LDM-2013-10-21.md",
    "content": "# C# Design Notes for Oct 21, 2013\n## Agenda\nPrimary constructors is the first C# 6.0 feature to be spec’ed and implemented. Aleksey, who is doing the implementing joined us to help settle a number of details that came up during this process. We also did a rethink around Lightweight Dynamic.\n1.\tPrimary Constructors \\<fleshed out a few more details>\n2.\tLightweight Dynamic \\<we examined a much simpler approach>\n\n## Primary Constructors\n\nPrimary constructors were first discussed in the design meeting on Apr 15, where we decided to include them, but have been around as a suggestion for much longer. It has great synergy with features such as initializers on auto-properties (May 20), because it puts constructor parameters in scope for initializers.\n\nThe evolving “speclet” for primary constructors can be found in the “Csharp 6.0 Speclets” working document in the design notes archive (see link above). It reflects a number of implementation choices, and also (at the time of the meeting) left some issues open, which we settled as best we could. Some decisions may change as we get experience with the feature – indeed the early focus on implementing this feature is so that we can incorporate feedback from usage.\n\n### Partial types\n\nPrimary constructors involve a parameter list on “the” class or struct header, as well as an optional argument list on “the” base class specification. But what if the type declaration is split over multiple partial types?\n\nThere is different precedence with partial classes. Sometimes elements can occur in only one part (members), sometimes they must occur and be the “same” in all parts (type parameters), sometimes they are optional but must agree where present (accessibility and constraints) and sometimes they are cumulative over parts (attributes).\n\nThere seems to be little value in allowing class parameters for primary constructors to occur in multiple parts – indeed it would require us to come up with a notion of sameness that only adds complication to the language. So class parameters are allowed only on one of the parts. Arguments to the base class are allowed only in the part where the class parameters occur. The class parameters are in scope in all the parts. This is also the approach that most resembles what is the case today: constructor parameters occur only in one place, and the privates used to hold their values are in scope in all the parts.\n\n### User-provided constructor body\n\nAs currently specified, primary constructors give rise to a constructor that is entirely compiler-generated. There is no syntax for the developer to specify statements to be executed as part of the primary constructor invocation. This is less of an issue than it might seem, since more than 90% of what people do in constructor bodies is probably what primary constructors now do for them – copying parameter values into private fields. Even initialization of other fields can now usually take place in initializers, because the constructor parameters are in scope for those.\n\nEven so, for the remaining scenarios the user would fall off a cliff: they would have to renounce primary constructors and turn them back into explicit constructors. This is a shame, and it is definitely worth considering what syntax we would use to fix this.\n\nA radical idea is to just allow statements directly in the class body. This would be weird for several reasons though. Aside from syntactic issues, there’s the problem of evaluation order relative to fields with initializers: initializers run before the base call, whereas statements in a constructor body usually run after, so interspersing them would have very surprising results.\nIn reality we’d need to place the statements in a block, and the only question is how we “dress up” the block – if at all. Some ideas:\n``` c#\nclass C(int x): B(x)\n{\n    // Repeat the full signature – redundant and error prone\n    C(int x) { Register(this); } \n    // Class name and empty parens – clashes with noarg constructor syntax, \n    // but similar to static constructors\n    C() { Register(this); }\n    // Just the class name – a little unfamiliar\n    C { Register(this); }\n    // Prefix with ‘this’ keyword – again a bit unfamiliar\n    this { Register(this); }\n    // Just the block – succinct but mysterious – and has the eval order issue\n    { Register(this); }\n}\n```\n\nMany of these options are reasonable. We’ll hold off though and see how the feature fares without user specified statements for now.\n\n### Struct issues\n\nStructs always have a default constructor. Should we allow explicit constructors in a struct with a primary constructor to delegate to the default constructor instead of the primary constructor? I.e. is the following ok?\n``` c#\nstruct S(int x)\n{\n    public S(bool b) : this() { … }\n}\n```\nIt seems that the restriction on explicit constructors to always chain to the primary constructor cannot be upheld just by requiring a this(…) initializer on them: we must also require that it isn’t referencing the default (no-arg) constructor.\n\nAlso, members in structs are allowed to assign to ‘this’. Should we allow that also in constructor bodies when there are primary constructors? We probably cannot reasonably prevent it, and people who do this are already in the ‘advanced’ category. But we have to spec that it causes the primary constructor parameters to be reset to their default value.\n\n### Attribute targets\n\nCurrently, we allow “method” targets on constructors. We should allow an attribute on a class or a struct with a primary constructor to specify a “method” target in order to be applied to the underlying generated constructor.\n\nWe should also allow attributes on the individual parameters of the primary constructor to specify a “field” target in order to be applied to the underlying field. In practice there may be optimizations so that the field is not generated when not needed, but the field target should force the field to be generated.\n\n### Accessibility on primary constructor parameters\n\nThere is an idea known from other languages (e.g. Scala, TypeScript) of allowing accessibility modifiers on class parameters. This would mean that a property is generated on the class with the name of the parameter, and the accessibility specified.\n\nThis would make some scenarios even more succinct, but it is not a straightforward feature. For instance, parameter names are typically lower case and property names typically upper case. We think this is a feature that can be added later if we feel there is significant further gain. Right now we are willing to bet on the combination of primary constructors and more terse property specification (e.g. with expression bodied properties and initializers for auto-properties) as a sufficiently great advance in the specification of data-like classes and structs.\n\n### Conclusion\n\nWe continue to bake the details of primary constructors.\n\n## Lightweight Dynamic\n\nWe took a fresh look at Lightweight Dynamic, based on feedback from Dino, who used to work on the “old” dynamic infrastructure.\n\nThe purpose of Lightweight Dynamic is to allow the behaviors of operations on an object to be specified programmatically, as part of the implementation of the object’s class. Dino pointed out that most behaviors can already be specified, using operator overloading, user defined conversions and indexers. Really, the “only” things missing are invocation and dotting. So instead of coming up with yet another new infrastructure for programmatic definition of object behaviors, we should just augment the one we’ve had all along with facilities for invocation and member access.\n\nDoing more with less is a pretty attractive idea! So we experimented with what that would look like.\n\n### Invokers\n\nIt seems reasonable to allow specification of what it means to invoke an object. The scenario seems similar to indexers, which are a special kind of instance members that can be abstract and virtual, take arguments, and be overloaded on signature.\n\nThe main difference would be that parameters are specified in round parentheses, and that the body is simply a method body, rather than a pair of accessors:\n\n``` c#\npublic int this(int x) { return x*x; } // allow instances to be invoked with ints\n```\n\nOne could imagine using this feature to build alternatives to delegate types, but more interestingly, this could provide semi-typed invocation capabilities for e.g. service calls:\n\n``` c#\npublic object this(params object[] args) { … } // generalized dynamic invoker\n```\n\nWhile it is straightforward to imagine this feature, it is also of relatively limited value: You can always provide an explicit Invoke method that the user can call at little extra cost.\n\n``` c#\nmyOperation.Invoke(5, \"Hello\"); // instead of\nmyOperation(5, \"Hello\");\n```\n\nEven so, it is interesting to consider.\n\n### Member access\n\nFor programmatic member access it seems superficially attractive – or at least powerful – to allow overriding of the dot operator. Maybe in the form of some kind of operator overload?\n\n``` c#\npublic static JsonObject operator .(JsonObject receiver, string name) { … }\n```\n\nThe problem of course is that dot is such a fundamental operator. If you overload it to hide the native meaning, you can hardly do anything with the underlying object. How would you even implement the dot operator without using the built in dot for accessing state etc. on the object?\n\nYou could of course have rules like we do for events, where the meaning is different on the inside and the outside. But that is not exactly elegant. The fact of the matter is that overriding dot on a statically typed class is simply too disruptive.\n\nHere is where Visual Basic may provide some interesting inspiration. The typical way you’d implement the dot operator would be some sort of dictionary lookup, and in fact you’d probably be fine if dotting did the same as indexing with a string, only with slightly more elegant syntax. Well, VB has an operator for that: The lookup operator, `!`.\n\nWe could essentially resign ourselves to not using dot for “lightweight dynamic” member access, instead using `!` as a just-as-short substitute. We would then simply define these two expressions to mean the same:\n\n``` c#\nobj!x\nobj[\"x\"]\n```\n\nIf you want to implement dynamic behavior for member access, you just provide an indexer over strings. Your callers will have to use a `!` instead of a `.`, but that is probably a good thing: that way they can still access your “real” members using a normal dot. This was a real issue with the Lightweight dynamic model we’ve explored before, one that we had yet to find a good solution to.\n\n### Conclusion\n\nWe still need to dig deeper here, but we think that adding the `!` lookup operator as a short hand for indexing with a string may quite possibly be the only work we have to do in the language for lightweight dynamic! That is quite possibly the biggest reduction of work associated with a feature we’ve ever accomplished in a single sitting!\n"
  },
  {
    "path": "meetings/2013/LDM-2013-11-04.md",
    "content": "# C# Design Notes for Nov 4, 2013\n## Agenda\nNext up for implementation are the features for auto-properties and function bodies, both of which go especially well with primary constructors. For the purpose of spec’ing those, we nailed down a few remaining details. We also took another round discussing member access in the lightweight dynamic scenario.\n1. Initialized and getter-only auto-properties \\<details decided>\n2. Expression-bodied function members \\<details decided>\n3. Lightweight dynamic \\<member access model and syntax discussed>\n\n## Initialized and getter-only auto-properties\nWe are allowing initializers for auto-properties, and we are allowing getter-only auto-properties, where the underlying field is untouched after the initializer has run. This was last discussed on May 20, and allows declarations like this:\n``` c#\npublic bool IsActive { get; } = true;\n```\nIn order to spec these feature additions there are a couple of questions to iron out.\n## Getter-only auto-properties without initializers\nInitializers will be optional on get-set auto-properties. Should we allow them to be left out on getter-only properties?\n``` c#\npublic bool IsActive { get; } // No way to get a non-default value in there\n```\nThere’s a symmetry and simplicity argument that we should allow this. However, anyone writing it is probably making a mistake, and even if they really meant it, they (and whoever inherits their code) are probably better off explicitly initializing to the default value.\n### Conclusion\nWe’ll disallow this.\n### Is the backing field of getter-only auto-properties read-only?\nThere’s an argument for fewer differences with get-set auto-properties. However, the field is really never going to change, and any tool that works on the underlying field (e.g. at the IL level) would benefit from seeing that it is indeed readonly. \n\nReadonly does not prevent setting through reflection, so deserialization wouldn’t be affected.\n### Conclusion\nLet’s make them readonly. There’s a discrepancy with VB’s decision here, which should be rationalized.\n## Expression-bodied function members\n\nThis feature would allow the body of methods and of getter-only properties to be expressed very concisely with a single expression. This feature was last discussed on April 15, and would allow code like this:\n``` c#\npublic class Point(int x, int y) {\n    public int X => x;\n    public int Y => y;\n    public double Dist => Math.Sqrt(x * x + y * y);\n    public Point Move(int dx, int dy) => new Point(x + dx, y + dy);\n}\n```\nAgain, there are a few details to iron out.\n### Are we happy with the syntax for expression-bodied properties?\nThe syntax is so terse that it may not be obvious to the reader that it is a property at all. It is just one character off from a field with an initializer, and lacks the telltale get and/or set keywords. \n\nOne could imagine a slightly more verbose syntax:\n``` c#\npublic int X { get => x; }\n```\nThis doesn’t read quite as well, and gives less of an advantage in terms of terseness.\n### Conclusion\nWe’ll stick with the terse syntax, but be open to feedback if people get confused.\n## Which members can have expression bodies?\nWhile methods and properties are clearly the most common uses, we can imagine allowing expression bodies on other kinds of function members. For each kind, here are our thoughts.\n### Operators: Yes\nOperators are like static methods. Since their implementations are frequently short and always have a result, it makes perfect sense to allow them to have expression bodies:\n``` c#\npublic static Complex operator +(Complex a, Complex b) => a.Add(b);\n```\n### User defined conversions: Yes\nConversions are just a form of operators:\n``` c#\npublic static implicit operator string(Name n) => n.First + \" \" + n.Last;\n```\n### Indexers: Yes\nIndexers are like properties, except with parameters:\n``` c#\npublic Customer this[Id id] => store.LookupCustomer(id);\n```\n### Constructors: No\nConstructors have syntactic elements in the header in the form of this(…) or base(…) initializers which would look strange just before a fat arrow. More importantly, constructors are almost always side-effecting statements, and don’t return a value.\n### Events: No\nEvents have add and remove accessors. Both must be specified, and both would be side-effecting, not value returning. Not a good fit.\n### Finalizers: No\nFinalizers are side effecting, not value returning.\n### Conclusion\nTo summarize, expression bodies are allowed on methods and user defined operators (including conversions), where they express the value returned from the function, and on properties and indexers where they express the value returned from the getter, and imply the absence of a setter.\n### void-returning methods\nMethods returning void, and async methods returning task, do not have a value-producing return statement. In that respect they are like some of the member kinds we rejected above. Should we allow them all the same?\n### Conclusion\nWe will allow these methods to have expression bodies. The rule is similar to expression-bodied lambdas: the body has to be a statement expression; i.e. one that is “certified” to be executed for the side effect.\n## Lightweight dynamic member access\nAt the design meeting on Oct 21, we discussed options for implementing “user-defined” member access. There are two main directions:\n- Allow users to override the meaning of dot\n- Introduce a “dot-like” syntax for invoking string indexers\n\nThe former really has too many problems, the main one being what to do with “real” dot. Either we make “.” retain is current meaning and only delegate to the user-supplied meaning when that fails. But that means the new dot does not get a full domain of names. Or we introduce an escape hatch syntax for “real dot”. But then people would start using that defensively everywhere, especially in generated code. It also violates substitutability where o.x suddenly means something else on a subtype than a supertype. \n\nWe strongly prefer the latter option, providing a “dot-like” syntax that translates into simply invoking a string indexer with the provided identifier as a string. This has the added benefit of working with existing types that have string indexers. The big question of course is what dot-like syntax. Here are some candidates we looked at in order to home in on a design philosophy:\n``` c#\nx!Foo   // Has a dot, but not as a separate character\nx.\"Foo\" // That looks terrible, too much like any value could be supplied\nx.[Foo] // Doesn’t feel like Foo is a member name\nx.#Foo  // Not bad\nx.+Foo  // Hmmmm\n```\nSome principles emerge from this exercise:\n- Using \"…\" or […] kills the illusion of it being a member name\n- Having characters after the identifier breaks the flow\n- Using a real dot feels right, and would help with the tooling experience\n- What comes after that real dot really matters!\n\n### Conclusion\nWe like the “dot-like” syntax approach to LW dynamic member access, and we think it should be of the form x.\\<glyph>Foo for some value of \\<glyph>.\n"
  },
  {
    "path": "meetings/2013/LDM-2013-12-16.md",
    "content": "# C# Design Notes for Dec 16, 2013\n\n## Agenda\nThis being the last design meeting of the year, we focused on firming up some of the features that we’d like to see prototyped first, so that developers can get going on implementing them.\n1. Declaration expressions <_reaffirmed scope rules, clarified variable introduction_>\n2. Semicolon operator <_reaffirmed enclosing parentheses_>\n3. Lightweight dynamic member access <_decided on a syntax_>\n\n## Declaration expressions\nOn Sep 23 we tentatively decided on rules for what the scope is when a variable is introduced by a declaration expression. Roughly speaking, the rules put scope boundaries around “structured statements”. While this mostly makes sense, there is one idiom, the “guard clause” pattern, that falls a little short here:\n``` c#\nif (!int.TryParse(s, out int i)) return false; // or throw, etc.\n… // code ideally consuming i\n```\nSince the variable `i` would be scoped to the if statement, using a declaration statement to introduce it inside of the if would not work.\n\nWe talked again about whether to rethink the scope rules. Should we have a different rule to the effect essentially of the variable declaration being introduced “on the preceding statement”? I.e. the above would be equivalent to\n``` c#\nint i;\nif (!int.TryParse(s, out i)) return false; // or throw, etc.\n… // code consuming i\n```\nThis opens its own can of worms. Not every statement _has_ a preceding statement (e.g. when being nested in another statement). Should it bubble up to the enclosing statement recursively? Should it introduce a block around the current statement to hold the generated preceding statement, etc.\n\nMore damning to this idea is the issue of initialization. If a variable with an initializer introduced in e.g. a while loop body is understood to really be a single variable declared outside of the loop, then that same variable would be re-initialized every time around the loop. That seems quite counterintuitive.\n\nThis brings us to the related issue about variable lifetimes. When a variable is introduced somewhere in a loop, is it a fresh variable each time around? It would probably seem strange if it weren’t. In fact we took a slight breaking change in C# 5.0 in order to make that the case for the loop variable in `foreach`, because the alternative didn’t make sense to people, and tripped them up when they were capturing the variable in lambdas, etc.\n\n### Conclusion\nWe keep the scope rules described earlier, despite the fact that the guard clause example doesn’t work. We’ll look at feedback on the implementation and see if we need to adjust. On variable lifetimes, each iteration of a loop will introduce its own instance of a variable introduced in the scope of that loop. The only exception is if it occurs in the initializer of a for loop, because that part is evaluated only on entry to the loop. \n\n## Semicolon operator\nWe previously decided that a sequence of expressions separated by semicolons need to be enclosed in parentheses. This is so that we don’t get into situations where e.g. commas and semicolons are interspersed among expressions and it isn’t visually clear what the precedence is.\n\nWe discussed briefly whether those parentheses are necessary even when there is other bracketing around the semicolon-separated expressions.\n\n### Conclusion\nIt’s not worth having special rules for this. Instead, semicolons are a relatively straightforward addition to parenthesized expressions – something like this:\n\n> _parenthesized-expression:_\n> *  `(`   *expression-sequence*\\_opt   expression_   `)`\n\n> _expression-sequence:_\n> *    *expression-sequence*\\_opt   _statement-expression_   `;`\n> *    *expression-sequence*\\_opt   _declaration-expression_   `;`\n\n## Lightweight dynamic member access\nOn Nov 4 we decided that lightweight member access should take the form `x.<glyph>Foo` for some value of `<glyph>`. One candidate for the glyph is `#`, so that member access would look like this:\n``` c#\npayload.#People[i].#Name\n```\nHowever, `#` plays really badly with preprocessor directives. It seems almost impossible to come up with syntactic rules that reconcile with the deep lexer-based recognition of `#`-based preprocessor directives. After searching the keyboard for a while, we settled on ‘`$`’ as a good candidate. It sort of invokes a “string” aspect in a tip of the hat to classic Basic:\n``` c#\npayload.$People[i].$Name\n```\nOne key aspect of dynamicness that we haven’t captured so far is the ability to declaratively construct an object with “lightweight dynamic members”, i.e. with entries accessible with string keys. A core syntactic insight here is to think of `$Foo` above as a unit – as a “lightweight dynamic member name”. What this enables is to think of object construction in terms of object initializers – where the member names are dynamic:\n``` c#\nvar json = new JsonObject \n{ \n    $foo = 1,\n    $bar = new JsonArray { \"Hello\", \"World\" },\n    $baz = new JsonObject { $x = 1, $y = 2 }\n};\n```\nWe could also consider allowing a free standing `$Foo` in analogy with a free standing simple name being able to reference an enclosing member in the implicit meaning of `this.$Foo`. This seems a little over the top, so we won’t do that for now.\nOne thing to consider is that objects will sometimes have keys that aren’t identifiers. This is quite common in Json payloads. That’s fine as far as member access is concerned: just fall back to indexing syntax when necessary:\n``` c#\npayload.$People[i].[\"first name\"]\n```\nIt would be nice to also be able to initialize such “members” in object initializers. This leads to the idea of a generalized “dictionary initializer” syntax in object initializers:\n``` c#\nvar payload = new JsonObject\n{\n    [\"first name\"] = \"Donald\",\n    [\"last name\"] = \"Duck\",\n    $city = \"Duckburg\" // equivalent to [\"city\"] = \"Duckburg\"\n};\n```\nSo just as `x.$Foo` is a shorthand for `x[\"Foo\"]` in expressions, `$Foo=value` is shorthand for `[\"Foo\"]=value` in object initializers. That syntax in turn is a generalized dictionary initializer syntax, that lets you index and assign on the newly created object, so that the above is equivalent to\n``` c#\nvar __tmp = new JsonObject();\n__tmp[\"first name\"] = \"Donald\";\n__tmp[\"last name\"] = \"Duck\";\n__tmp[\"city\"] = \"Duckburg\";\nvar payload = __tmp;\n```\nIt could be used equally well with non-string indexers.\nA remaining nuisance is having to write all the type names during construction. Could some of them be inferred, or a default be chosen? That’s a topic for a later time.\n\n### Conclusion\nWe’ll introduce a notion of dictionary initializers `[index]=value`, which are indices enclosed in `[…]` being assigned to in object initializers. We’ll also introduce a shorthand `x.$Foo` for indexing with strings `x[\"Foo\"]`, and a shorthand `$Foo=value` for a string dictionary initializer `[\"Foo\"]=value`.\n"
  },
  {
    "path": "meetings/2013/README.md",
    "content": "# C# Language Design Notes for 2013\n\nOverview of meetings and agendas for 2013\n\n## Oct 7, 2013\n\n[C# Language Design Notes for Oct 7, 2013](LDM-2013-10-07.md)\n\n1.\tInvariant meaning of names <*scrap the rule*>\n2.\tType testing expression <*can’t decide on good syntax*>\n3.\tLocal functions <*not enough scenarios*>\n4.\tnameof operator <*yes*>\n\n[C# Language Design Notes for Oct 21, 2013](LDM-2013-10-21.md)\n\n1.\tPrimary Constructors <*fleshed out a few more details*>\n2.\tLightweight Dynamic <*we examined a much simpler approach*>\n\n## Nov 4, 2013\n\n[C# Language Design Notes for Nov 4, 2013](LDM-2013-11-04.md)\n\n1. Initialized and getter-only auto-properties <*details decided*>\n2. Expression-bodied function members <*details decided*>\n3. Lightweight dynamic <*member access model and syntax discussed*>\n\n## Dec 16, 2013\n\n[C# Language Design Notes for Dec 16, 2013](LDM-2013-12-16.md)\n\n1. Declaration expressions <*reaffirmed scope rules, clarified variable introduction*>\n2. Semicolon operator <*reaffirmed enclosing parentheses*>\n3. Lightweight dynamic member access <*decided on a syntax*>\n"
  },
  {
    "path": "meetings/2014/LDM-2014-01-06.md",
    "content": "# C# Design Notes for Jan 6, 2014\n\nNotes are archived [here](https://roslyn.codeplex.com/wikipage?title=CSharp%20Language%20Design%20Notes).\n\n## Agenda\nIn this meeting we reiterated on the designs of a couple of features based on issues found during implementation or through feedback from MVPs and others.\n1.\tSyntactic ambiguities with declaration expressions <_a solution adopted_>\n2.\tScopes for declaration expressions <_more refinement added to rules_>\n\n# Syntactic ambiguities with declaration expressions\nThere are a couple of places where declaration expressions are grammatically ambiguous with existing expressions. The knee-jerk reaction would be to prefer the existing expressions for compatibility, but those turn out to nearly always lead to semantic errors later.\n\nThere are two kinds of full ambiguities (i.e. ones that don’t resolve with more lookahead):\n``` c#\na * b // multiplication expression or uninitialized declaration of pointer?\na < b > c // nested comparison or uninitialized declaration of generic type?\n```\nThe latter one exists also in a method argument version that seems more realistic:\n``` c#\na ( b < c , d > e ) // two arguments or one declaration expression?\n```\nHowever, in all these cases the expression, when interpreted as a declaration expression, is uninitialized. This means that in the vast majority of cases (except for structs with no accessible members) it will be considered unassigned. Which means that it will be a semantic error for it to occur as a value: it has to occur in one of the few places where an unassigned variable is allowed:\n\n1. On the left hand side of an assignment expression\n2. As an argument to an out parameter\n3. In parentheses in one of the previous positions\n\nThose are places where a multiplication or comparison expression cannot currently occur, because they are always values, never variables. We can therefore essentially split the world neatly for the two interpretations of the ambiguous expressions:\n\n* If they occur in a place where a variable is required, they are parsed as declaration expressions\n* Everywhere else, they are parsed as they are today.\n\nThis is a purely syntactic distinction. Rules of definite assignment etc. aren’t actually used by the compiler to decide, just by us designers to justify that the rule isn’t breaking.\n\nThere is one potential future conflict we can imagine: If we start allowing ref returning methods and those include user defined overloads of operators, then you could imagine someone defining an overload of “`*`” that returns a ref, and would therefore give meaning to the expression `(a*b) = c`, even when interpreted as multiplication. The rules as proposed here would not allow that; they would try to see `(a*b)` as a parenthesized declaration expression of a variable `b` with pointer type `a*`.\n\n### Conclusion\nWe like the rule that parsing prefers declaration expressions in ambiguous cases _only_ in places where a variable is required: when occurring as an out argument, on the left hand side of an assignment, or nested in any number of parentheses within those. This is non-breaking, and doesn’t seem too harmful to the future design space.\n\n## Scopes for declaration expressions\nThe initial rules for declaration expression scopes are in need of some refinement in at least two scenarios:\n``` c#\nif (…) m(int x = 1); else m(x = 2); // cross pollution between branches?\nwhile (…) m(int x = 1; x++); // survival across loop iterations?\n```\nWe want to make sure that declarations are isolated between branches and loop iterations. This means we need to add more levels of scopes. Essentially, whenever an _embedded-expression_ occurs as an embedded expression (as opposed to where any _expression_ can occur), we want to introduce a new nested scope.\n\nAdditionally, for for-loops we want to nest scopes for each of the clauses in the header:\n``` c#\nfor (int i = (int a = 0);\n     i < (int b = 10); // i and a in scope here\n     i += (int c = 1)) // i, a and b in scope here\n  (int d += i);        // i, a and b but not c in scope here\n```\nIt’s as if the for loop was rewritten as\n``` c#\n{\n  int i = (int a = 0);\n  while (i < (int b = 10))\n  {\n    { i += (int c = 1)); }\n    (int d += i);\n  }\n}\n```\n\n### Conclusion\nWe’ll adopt these extra scope levels which guard against weird spill-over.\n"
  },
  {
    "path": "meetings/2014/LDM-2014-02-03.md",
    "content": "# C# Language Design Notes for Feb 3, 2014\n\n## Agenda\nWe iterated on some of the features currently under implementation \n1.  Capture of primary constructor parameters <_only when explicitly asked for with new syntax_>\n1.  Grammar around indexed names <_details settled_>\n1.  Null-propagating operator details <_allow indexing, bail with unconstrained generics_>\n\n## Capture of primary constructor parameters\nPrimary constructors as currently designed and implemented lead to automatic capture of parameters into private, compiler-generated fields of the object whenever those parameters are used after initialization time.\n\nIt is becoming increasingly clear that this is quite a dangerous design. To illustrate, what’s wrong with this code?\n``` c#\npublic class Point(int x, int y)\n{\n    public int X { get; set; } = x;\n    public int Y { get; set; } = y;\n    public double Dist => Math.Sqrt(x * x + y * y);\n    public void Move(int dx, int dy)\n    {\n        x += dx; y += dy;\n    }\n}\n```\nThis appears quite benign, but is in fact catastrophically wrong. The use of `x` and `y` in `Dist` and `Move` causes these values to be captured as private fields. The auto-properties `X` and `Y` each cause their own backing fields to be generated, initialized with the `x` and `y` values passed in to the primary constructors. But from then on, `X` and `Y` lead completely distinct lives from `x` and `y`. Assignments to the `X` and `Y` properties will cause them to be observably updated, but the value of `Dist` remains unchanged. Conversely, changes through the `Move` method will reflect in the value of `Dist`, but not affect the value of the properties.\n\nThe way for the developer to avoid this is to be extremely disciplined about not referencing `x` and `y` except in initialization code. But that is like giving them a gun already pointing at their foot: sooner or later it will go subtly wrong, and they will have hard to find bugs.\n\nThere are other incarnations of this problem, e.g. where the parameter is passed to the base class and captured multiple times.\n\nThere are also other problems with implicit capture: we find, especially from MVP feedback, that people quickly want to specify certain things about the generated fields, such as readonly-ness, attributes, etc. We could allow those on the parameters, but they quickly don’t look like parameters anymore.\n\nThe best way for us to deal with this is to simply disallow automatic capture. The above code would be disallowed, and given the same declarations of `x`, `y`, `X` and `Y`, `Dist` and `Move` would have to written in terms of the properties:\n\n``` c#\n    public double Dist => Math.Sqrt(X * X + Y * Y);\n    public void Move(int dx, int dy)\n    {\n        X += dx; Y += dy;\n    }\n```\n\nNow this raises a new problem. What if you want to capture a constructor parameter in a private field and have no intention of exposing it publicly. You can do that explicitly:\n\n``` c#\npublic class Person(string first, string last)\n{\n    private string _first = first;\n    private string _last = last;\n    public string Name => _first + \" \" + _last;\n}\n```\n\nThe problem is that the “good” lower case names in the class-level declaration space are already taken by the parameters, and the privates are left with (what many would consider) less attractive naming options.\n\nWe could address this in two ways (that we can think of) in the primary constructor feature: \n1. Allow primary constructor parameters and class members to have the same names, with the excuse that their lifetimes are distinct: the former are only around during initialization, where access to the latter through this is not yet allowed.\n1. Introduce a syntax for explicitly capturing a parameter. If you ask for it, presumably you thought through the consequences.\n\nThe former option seems mysterious: two potentially quite different entities get to timeshare on the same name? And then you’d get confusing initialization code like this:\n\n``` c#\n    private string first = first; // WHAT???\n    private string last = last;\n```\n\nIt seems that the latter option is the better one. We would allow field-like syntax to occur in a parameter list, which is a little odd, but kind of says what it means. Specifically specifying an accessibility on a parameter (typically private) would be what triggers capture as a field:\n\n``` c#\npublic class Person(private string first, private string last)\n{\n    public string Name => _first + \" \" + _last;\n}\n```\n\nOnce there’s an accessibility specified, we would also allow other field modifiers on the parameter; readonly probably being the most common. Attributes could be applied to the field in the same manner as with auto-properties: through a field target.\n\nConclusion\nWe like option two. Let’s add syntax for capture and not do it implicitly.\n\nGrammar for indexed names\nFor the lightweight dynamic features, we’ve been working with a concept of “pseudo-member” or _indexed name_ for the `$identifier` notation.\n\nWe will introduce this as a non-terminal in the grammar, so that the concept is reified. However, for the constructs that use it (as well as ordinary identifiers) we will create separate productions, rather than unify indexed names and identifiers under a common grammatical category.\n\nFor the stand-alone dictionary initializer notation of `[expression]` we will not introduce a non-terminal.\n\n## Null-propagating operator details\nNailing down the design of the null-propagating operator we need to decide a few things:\n\n### Which operators does it combine with?\nThe main usage of course is with dot, as in `x?.y` and `x?.m(…)`. It also potentially makes sense for element access `x?[…]` and invocation `x?(…)`. And we also have to consider interaction with indexed names, as in `x?.$y`.\n\nWe’ll do element access and indexed member access, but not invocation. The former two make sense in the context that lightweight dynamic is addressing. Invocation seems borderline ambiguous from a syntactic standpoint, and for delegates you can always get to it by explicitly calling Invoke, as in `d?.Invoke(…)`.\n\n### Semantics\nThe semantics are like applying the ternary operator to a null equality check, a null literal and a non-question-marked application of the operator, except that the expression is evaluated only once:\n\n``` c#\ne?.m(…)   =>   ((e == null) ? null : e0.m(…))\ne?.x      =>   ((e == null) ? null : e0.x)\ne?.$x     =>   ((e == null) ? null : e0.$x)\ne?[…]     =>   ((e == null) ? null : e0[…])\n```\n\nWhere `e0` is the same as `e`, except if `e` is of a nullable value type, in which case `e0` is `e.Value`. \n\n### Type\nThe type of the result depends on the type `T` of the right hand side of the underlying operator: \n* If `T` is (known to be) a reference type, the type of the expression is `T`\n* If `T` is (known to be) a non-nullable value type, the type of the expression is `T?`\n* If `T` is (known to be) a nullable value type, the type of the expression is `T`\n* Otherwise (i.e. if it is not known whether `T` is a reference or value type) the expression is a compile time error.\n\n"
  },
  {
    "path": "meetings/2014/LDM-2014-02-10.md",
    "content": "# C# Design Notes for Feb 10, 2014\n\n## Agenda\n1.\tDesign of using static <_design adopted_>\n2.\tInitializers in structs <_allow in certain situations_>\n3.\tNull-propagation and unconstrained generics <_keep current design_>\n\n## Design of using static\nThe “using static” feature was added in some form to the Roslyn codebase years ago, and sat there quietly waiting for us to decide whether to add it to the language. Now it’s coming out, it’s time to ensure it has the right design.\n### Syntax\nShould the feature have different syntax from namespace usings, or should it be just like that, but just specifying a type instead? The downside of keeping the current syntax is that we need to deal with ambiguities between types and namespaces with the same name. That seems relatively rare, though, and sticking with current syntax definitely makes it feel more baked in:\n``` c#\nusing System.Console;\n```\nas opposed to, e.g.:\n``` c#\nusing static System.Console;\n```\n#### Conclusion\nWe’ll stick with the current syntax.\n\n### Ambiguities\nThis leads to the question of how to handle ambiguities when there are both namespaces and types of a given name. We clearly need to prefer namespaces over types for compatibility reasons. The question is whether we make a choice at the point of the specified name, or whether we allow “overlaying” the type and the namespace, disambiguating at the next level down by preferring names that came from the namespace over ones from the type.\n\n#### Conclusion\nWe think overlaps are sufficiently rare that we’ll go with the simple rule: A namespace completely shadows a type of the same name, and you can’t import the members of such a type. If this turns out to be a problem we’re free to loosen it up later.\n\n### Which types can you import?\nStatic classes, all classes, enums? It seems it is almost always a mistake to import non-static types: they will have names that are designed to be used with the type name, such as `Create`, `FromArray`, `Empty`, etc., that are likely to appear meaningless on their own, and clash with others. Enums are more of a gray area. Spilling the enum members to top-level would often be bad, and could very easily lead to massive name clashes, but sometimes it’s just what you want.\n\n#### Conclusion\nWe’ll disallow both enums and non-static classes for now.\n\n### Nested types\nShould nested types be imported as top-level names?\n\n#### Conclusion\nSure, why not? They are often used by the very members that are being “spilled”, so it makes sense that they are spilled also.\n\n### Extension methods\nShould extension methods be imported as extension methods? As ordinary static methods? When we first introduced extension methods, a lot of people asked for a more granular way of applying them. This could be it: get the extension methods just from a single class instead of the whole namespace. For instance:\n``` c#\nusing System.Linq.Enumerable;\n```\nWould import just the query methods for in-memory collections, not those for `IQueryable<T>`.\nOn the other hand, extension methods are designed to be used as such: you only call them as static methods to disambiguate. So it seems wrong if they are allowed to pollute the top-level namespace as static methods. On the _other_ other hand, this would be the first place in the language where an extension method wouldn’t be treated like a static method.\n\n#### Conclusion\nWe will import extension methods as extension methods, but not as static methods. This seems to hit the best usability point.\n\n## Initializers in structs\nCurrently, field initializers aren’t allowed in structs. The reason is that initializers _look_ like they will be executed every time the struct is created, whereas that would not be the case: If the struct wasn’t `new`’ed, or it was `new`’ed with the default constructor, no user defined code would run. People who put initializers on fields might not be aware that they don’t always run, so it’s better to prevent them.\n\nIt would be nice to have the benefits of primary constructors on structs, but that only really flies if the struct can make use of the parameters in scope through initializers. Also, we now have initializers for auto-properties, making the issue worse. What to do?\n\nWe can never prevent people from having uninitialized structs, and the struct type authors still need to make sure that an uninitialized struct is meaningful. However, if a struct has user-defined constructors, chances are they know what they’re doing and initializers wouldn’t make anything worse. However, initializers would only run if the user-defined constructors don’t chain to the default constructor with `this()`.\n\n### Conclusion\nLet’s allow field and property initializers in structs, but only if there is a user-defined constructor (explicit or primary) that does not chain to the default constructor. If people want to initialize with the default constructor first, they should call it from their constructor, rather than chain to it.\n``` c#\nstruct S0 { public int x = 5; } // Bad\nstruct S1 { public int x = 5; S1(int i) : this() { x += i; } } // Bad\nstruct S2 { public int x = 5; S2(int i) { this = new S2(); x += i; } } // Good\nstruct S3(int i) { public int x = 5 + i; } // Good\n```\n## Unconstrained generics in null-propagating operator\nWe previously looked at a problem with the null-propagating operator, where if the member accessed is of an unconstrained generic type, we don’t know how to generate the result, and what its type should be:\n``` c#\nvar result = x?.Y;\n```\nThe answer is different when `Y` is instantiated with reference types, non-nullable value types and nullable value types, so there’s nothing reasonable we can do when we don’t know which.\nThe proposal has been raised to fall back to type `object`, and generate code that boxes (which is a harmless operation for values that are already of reference type).\n\n### Conclusion\nThis seems like a hack. While usable in some cases, it is weirdly different from the mainline semantics of the feature. Let’s prohibit and revisit if it becomes a problem.\n\n"
  },
  {
    "path": "meetings/2014/LDM-2014-04-21.md",
    "content": "# C# Language Design Notes for Apr 21, 2014\n\n## Agenda\nIn this design meeting we looked at some of the most persistent feedback on the language features showcased in the BUILD CTP, and fixed up many of the most glaring issues.\n\n1.\tIndexed members <_lukewarm response, feature withdrawn_>\n2.\tInitializer scope <_new scope solves all kinds of problems with initialization_>\n3.\tPrimary constructor bodies <_added syntax for a primary constructor body_>\n4.\tAssignment to getter-only auto-properties from constructors <_added_>\n5.\tSeparate accessibility for type and primary constructor <_not worthy of new syntax_>\n6.\tSeparate doc comments for field parameters and fields <_not worthy of new syntax_>\n7.\tLeft associative vs short circuiting null propagation <_short circuiting_>\n\n## Indexed members\nThe indexed member feature – `e.$x` and `new C { $x = e }` – has been received less than enthusiastically. People aren’t super happy with the syntax, but most of all they aren’t very excited about the feature.\n\nWe came to this feature in a roundabout way, where it started out having much more expressiveness. For instance, it was the way you could declaratively create an object with values at given indices. But given the dictionary initializer syntax – `new C { [\"x\"] = e }` – the `$` syntax is again just thin sugar for using string literals in indexers. Is that worth new syntax? It seems not.\n\n### Conclusion\nWe’ll pull the feature. There’s little love for it, and we shouldn’t litter the language unnecessarily. If this causes an outcry, well that’s different feedback, and we can then act on that.\n\n## Initializer scope\nThere are a couple of things around primary constructors and scopes that are currently annoying:\n\n1.\tYou frequently want a constructor parameter and a (private) field with the same name. In fact we have a feature just for that – the so-called field parameters, where primary constructors annotated with an accessibility modifier cause a field to be also emitted. However, if you try to declare this manually, we give an error because members and primary constructor parameters are in the same declaration space.\n\n2.\tWe have special rules for primary constructor parameters, making it illegal to use them after initialization time, even though they are “in scope”.\n\nSo in this code:\n``` c#\npublic class ConfigurationException(Configuration configuration, string message) \n    : Exception(message)\n{\n    private Configuration configuration = configuration;\n    public override string ToString() => message + \"(\" + configuration + \")\";\n}\n```\nThe declaration of the field `configuration` is currently an error, because it clashes with the parameter of the same name in the same declaration space, but it would be nice if it just worked.\n\nThe use of `message` in a method body is and should be an error, but it would be preferable if that was a more natural consequence of existing scoping rules, instead of new specific restrictions.\n\nAn idea to fix this is to introduce what we’ll call the ___initialization scope___. This is a scope and declaration space that is nested within the type declaration’s scope and declaration space, and which includes the parameters and base initializer arguments of a primary constructor (if any) and the expressions in all member initializers of the type. \n\nThat immediately means that this line becomes legal and meaningful:\n\n``` c#\n    private Configuration configuration = configuration;\n```\n\nThe _field_ `configuration` no longer clashes with the _parameter_ `configuration`, because they are no longer declared in the same declaration space: the latter’s is nested within the former’s. Moreover the reference to `configuration` in the initializer refers to the parameter, not the field, because while both are in scope, the parameter is nearer.\n\nSome would argue that a line like the above is a little confusing. You are using the same name to mean different things. That is a fair point. The best way to think of it is probably the corresponding line in a normal constructor body:\n\n``` c#\n    this.configuration = configuration;\n```\n\nWhich essentially means the same thing. Just as we’ve gotten used to `this` disambiguating that line, we’ll easily get used to the leading modifier and type of the field declaration disambiguating the field initializer.\n\nThe initialization scope also means that this line is naturally disallowed:\n\n``` c#\n    public override string ToString() => message + \"(\" + configuration + \")\";\n```\n\nBecause the reference to `message` does not appear within the initialization scope, and the parameter is therefore not in scope. If there was a field with that name, the field would get picked up instead; it wouldn’t be shadowed by a parameter which would be illegal to reference.\n\nA somewhat strange aspect of the initialization scope is that it is textually discontinuous: it is made up of bits and pieces throughout a type declaration. Hopefully this is not too confusing: conceptually it maps quite clearly to the notion of “initialization time”. Essentially, the scope is made up of “the code that runs when the object is initialized”.\n\nThere are some further desirable consequences of introducing the initialization scope:\n\n### Field parameters\nThe feature of field parameters is currently the only way to get a primary constructor parameter and a field of the same name:\n\n``` c#\npublic class ConfigurationException(private Configuration configuration, …)\n```\n\nWith the initialization scope, the feature is no longer special magic, but just thin syntactic sugar over the field declaration above. If for some reason field parameters don’t work for you, you can easily fall back to an explicit field declaration with the same name as the parameter.\n\nIt raises the question of whether we’d even _need_ field parameters, but they still seem like a nice shorthand.\n\n### The scope of declaration expressions in initializers\nIn the current design, each initializer provides its own isolated scope for declaration expressions: there was no other choice really. With the initialization scope, however, declaration expressions in initializers would naturally use that as their scope, allowing the use of locals to flow values between initializers. This may not be common, but you can certainly imagine situations where that comes in handy:\n\n``` c#\npublic class ConfigurationException(Configuration configuration, string message) \n    : Exception(message)\n{\n    private Configuration configuration = configuration;\n    public bool IsRemote { get; } = (var settings = configuration.Settings)[\"remote\"];\n    public bool IsAsync { get; } = settings[\"async\"];\n    public override string ToString() => Message + \"(\" + configuration + \")\";\n}\n```\n\nThe declaration expression in `IsRemote`’s initializer captures the result of evaluating `configuration.Settings` into the local variable `settings`, so that it can be reused in the initializer for `IsAsync`.\n\nWe need to be a little careful about partial types. Since the “textual order” between different parts of a partial type is not defined, it does not seem reasonable to share variables from declaration expressions between different parts. Instead we should introduce a scope within each part of a type containing the field and property initializers contained in that part. This scope is then nested within the initializer scope, which itself covers all the parts.\n\nA similar issue needs to be addressed around the argument to the base initializer. Textually it occurs _before_ the member initializers, but it is evaluated _after_. To avoid confusion, the argument list needs to be in its own scope, nested inside the scope that contains the field and property initializers (of that part of the type). That way, locals introduced in the argument list will not be in scope in the initializers, and members introduced in the initializers cannot be used in the argument list (because their use would textually precede their declaration).\n\n### Primary constructors in VB\nImportantly, the notion of the initialization scope would also make it possible to introduce primary constructors in VB. The main impediment to this has been that, because of case insensitivity, the restriction that primary constructor parameters could not coexist with members of the same name became too harsh. If you need both a parameter, a backing field and a property, you quickly run out of names!\n\nThe initialization scope helps with that, by introducing a separate scope that the parameters can live in, so they no longer clash with other names.\n\nUnlike C#, VB today allows initializers to reference previously initialized fields. With the initialization scope this would still be possible, as long as there’s not a primary constructor parameter shadowing that field. And if there is, you probably want the parameter anyway. An if you don’t, you can always get at the field through `Me` (VB’s version of `this`).\n\nIt is up to the VB design team whether to actually add primary constructors this time around, but it is certainly nice to have a model that will work in both languages.\n\n### Conclusion\nThe initialization scope solves many problems, and leaves the language cleaner and with less magic. This clearly outweighs the slight oddities it comes with.\n\n## Primary constructor bodies\nBy far the most commonly reported reason why people cannot use primary constructors is that they don’t allow for easy argument validation: there is simply no “body” within which to perform checks and throw exceptions.\n\nWe could certainly change that. The simplest thing, syntactically, is to just let you write a block directly in the type body, and that block then gets executed when the object is constructed:\n\n``` c#\npublic class ConfigurationException(Configuration configuration, string message) \n    : Exception(message)\n{\n    {\n        if (configuration == null) \n        {\n            throw new ArgumentNullException(nameof(configuration));\n        }\n    }\n    private Configuration configuration = configuration;\n    public override string ToString() => Message + \"(\" + configuration + \")\";\n}\n```\n\nThis looks nice, but there is a core question we need to answer: when _exactly_ is that block executed? There seem to be two coherent answers to that, and we need to choose:\n\n1.\tThe block is an ___initializer body___. It runs before the base call, following the same textual order as the surrounding field and property initializers. You could even imagine allowing multiple of them interspersed with field initialization, and they can occur regardless of whether there is a primary constructor.\n\n2.\tThe block is a ___constructor body___. It is the body of the primary constructor and therefore runs after the base call. You can only have one, and only if there is a primary constructor that it can be part of.\n\nBoth approaches have pros and cons. The initializer body corresponds to a similar feature in Java, and has the advantage that you can weed out bad parameters before you start digging into them or pass them to the base initializer (though arguments passed to the base initializer should probably be validated by the base initializer rather than in the derived class anyway).\n\nAs an example of this issue, our previous example where an initializer digs into the contents of a primary constructor parameter, wouldn’t work if the validation was done in a constructor body, after initialization (here in a simplified version):\n\n``` c#\n    public bool IsRemote { get; } = configuration.Settings[\"remote\"];\n```\n\nIf the passed-in `configuration` is null, this would yield a null reference exception before a constructor body would have a chance to complain (by throwing a better exception). Instead, in a constructor body interpretation, the initialization of `IsRemote` would either have to happen in the constructor body as well, following the check, or it would have to make copious use of the null propagating operator that we’re also adding:\n\n``` c#\n    public bool IsRemote { get; } = configuration?.Settings?[\"remote\"] ?? false;\n```\n\nOn the other hand, the notion of a constructor body is certainly more familiar, and it is easy to understand that the block is stitched together with the parameter list and the base initializer to produce the constructor declaration underlying the primary constructor.\n\nMoreover, a constructor body has access to fields and members, while `this` access during initialization time is prohibited. Therefore, a constructor body can call helper methods etc. on the instance under construction; also a common pattern.\n\n### Conclusion\nAt the end of the day we have to make a choice. Here, familiarity wins. While the initializer body approach has allure, it is also very much a new thing. Constructor bodies on the other hand work the way they work. The downsides have workarounds. So a constructor body it is.\n\nIn a partial type, the constructor body must be in the same part as the primary constructor. Scope-wise, the constructor body is nested within the scope for the primary constructor’s base arguments, which in turn is nested within the scope for the field and property initializers of that part, which in turn is nested within the initialization scope that contains the primary constructor parameters:\n\n``` c#\npartial class C(int x1) : B(int x3 = x1 /* x2 in scope but can’t be used */)\n{\n    public int X0 { get; } = (int x2 = x1);\n    {\n        int x4 = X0 + x1 + x2 + x3;\n    }\n}\n```\n\nLet’s look at the scopes (and corresponding declaration spaces) nested in each other here:\n\n* The scope `S4` spans the primary constructor body. It directly contains the local variable `x4`, and is nested within `S3`.\n* The scope `S3` spans `S4` plus the argument list to the primary constructor’s base initializer. It directly contains the local variable `x3`, and is nested within `S2`.\n* The scope `S2` spans `S3` plus all field and property initializers in this part of the type declaration. It directly contains the local variable `x2`, and is nested within `S1`.\n* The scope `S1` spans `S2` plus similar “`S2`’s” from other parts of the type declaration, plus the parameter list of the primary constructor. It directly contains the parameter `x1`, and is nested within `S0`.\n* The scope `S0` spans all parts of the whole type declaration, including `S1`. It directly contains the property `X0`.\n\nOn top of this, the usual rule applies for local variables, that they cannot be used in a position that textually precedes their declaration.\n\n## Assignment to getter-only auto-properties\nThere are situations where you cannot use a primary constructor. We have to make sure that you do not fall off too steep of a cliff when you are forced to abandon primary constructor syntax and use an ordinary constructor.\n\nOne of the main nuisances that has been pointed out is that the only way to initialize a getter-only auto-property is with an initializer. If you want to initialize it from constructor parameters, you therefore need to have a primary constructor, so those parameters can be in scope for initialization. If you cannot have a primary constructor, then the property cannot be a getter-only auto-property: You have to fall back to existing, more lengthy and probably less fitting property syntax.\n\nThat’s a shame. The best way to level the playing field here is to allow assignment to getter-only auto-properties from within constructors: \n``` c#\npublic class ConfigurationException : Exception\n{\n    private Configuration configuration;\n    public bool IsRemote { get; }\n    public ConfigurationException(Configuration configuration, string message) \n        : base(message)\n    {\n        if (configuration == null) \n        {\n            throw new ArgumentNullException(nameof(configuration));\n        }\n        this.configuration = configuration;\n        IsRemote = configuration.Settings[\"remote\"];\n    }\n}\n```\n\nThe assignment to `IsRemote` would go directly to the underlying field (since there is no setter to call). Thus, semantics are a little different from assignment to get/set auto-properties, where the setter is called even if you assign from a constructor. The difference is observable if the property is virtual. We could restore symmetry by changing the meaning of assignment to a get/set auto-property to also go directly to the backing field, but that would be a breaking change.\n\n### Conclusion\nLet’s allow assignment to getter-only auto-properties from constructor bodies. It translates into assignment directly to the underlying field (which is `readonly`). We are ok with the slight difference in semantics from get/set auto-property assignment.\n\n## Separate accessibility on type and primary constructor\nThere are scenarios where you don’t want the constructors of your type to have the same accessibility as the type. A common case is where the type is public, but the constructor is private or protected, object construction being exposed only through factories.\n\nShould we invent syntax so that a primary constructor can get a different accessibility than its type?\n\n### Conclusion\nNo. There is no elegant way to address this. This is a fine example of a scenario where developers should just fall back to normal constructor syntax. With the previous decisions above, we’ve done our best to make sure that that cliff isn’t too steep.\n\n## Separate doc comments for field parameters and their fields\nDoc comments for a primary constructor parameter apply to the parameter. If the parameter is a field parameter, there is no way to add a doc comment that goes on the field itself. Should there be?\n\n### Conclusion\nNo. If the field needs separate doc comments, it should just be declared as a normal field. With the introduction of initialization scopes above, this is now not only possible but easy.\n\n## Null propagating operator associativity\nWhat does the following mean?\n\n``` c#\nvar x = a?.b.c;\n```\n\nPeople gravitate to two interpretations, which each side maintains is perfectly intuitive and the only thing that makes sense.\n\nOne interpretation is that `?.` is an operator much like `.`. It is left associative, and so the meaning of the above is roughly the same as\n\n``` c#\nvar x = ((var tmp = a) == null ? null : tmp.b).c;\n```\n\nIn other words, we access `b` only if `a` is not null, but `c` is accessed regardless. This is obviously likely to lead to a null reference exception; after all the use of the null propagating operator indicates that there’s a likelihood that `a` is null. So advocates of the “left associative” interpretation would put a diagnostic on the code above, warning that this is probably bad, and pushing people to write, instead:\n\n``` c#\nvar x = a?.b?.c;\n```\n\nWith a null-check again before accessing `c`.\n\nThe other interpretation has been called “right associative”, but that isn’t exactly right (no pun intended): better to call it “short circuiting”. It holds that the null propagating operator should short circuit past subsequent member access (and invocation and indexing) when the receiver is null, essentially pulling those subsequent operations into the conditional:\n\n``` c#\nvar x = ((var tmp = a) == null ? null : tmp.b.c);\n```\n\nThere are long discussions about this, which I will no attempt to repeat here. The “short circuiting” interpretation is slightly more efficient, and probably more useful. On the other hand it is more complicated to fit into the language, because it needs to “suck up” subsequent operations in a way those operations aren’t “used to”: since when would the evaluation of `e.x` not necessarily lead to `x` being accessed on `e`? So we’d need to come up with alternative versions of remote access, indexing and invocation that can represent being part of a short-circuited chain following a null propagating operator.\n\n### Conclusion\nDespite the extra complexity and some disagreement on the design team, we’ve settled on the “short circuiting” interpretation.\n"
  },
  {
    "path": "meetings/2014/LDM-2014-05-07.md",
    "content": "# C# Language Design Notes for May 7, 2014\n\n## Agenda\n1.\tprotected and internal <_feature cut – not worth the confusion_>\n2.\tField parameters in primary constructors <_feature cut – we want to keep the design space open_>\n3.\tProperty declarations in primary constructors <_interesting but not now_>\n4.\tTypeswitch <_Not now – more likely as part of a future more general matching feature_>\n\n## protected and internal\nProtected and internal was never a feature we were super enthusiastic about. The CLR supports it and it seemed reasonable to surface it in the language. However, the syntactic options are not great. For every suggestion there are significant and good reasons why it doesn’t work. The community has been incredibly helpful in its creativity about names, as well as in pointing out their flaws.\n\n### Conclusion\nWe won’t do this feature. Guidance for the scenarios it addresses will be to use `internal`: the most important aspect is to hide the member from external consumers of the assembly. The `protected` aspect is more of a software engineering thing within the team. You could imagine at some point adding the protected aspect as an attribute, either recognized by the compiler or respected by a custom diagnostic.\n\n## Field parameters in primary constructors\nNow that we’ve added the initialization scope to classes, it is no longer a problem to have primary constructor parameters with the same name as members. This removes most of the motivation for having the field parameters feature, where an explicit accessibility modifier on a parameter would indicate that there should additionally be a field of that name.\n\n### Conclusion\nAs the next topic demonstrates, there are more interesting things to consider using this design space for in the future. Let’s not occupy it now with this relatively unimportant feature. It is fine that people have to declare their fields explicitly.\n\n## Property declarations in primary constructors\nWhile declaration of fields in the primary constructor parameter list is of limited value, it is very often the case that a constructor parameter is accompanied by a corresponding property. It might be nice if there was a shorthand for this. You could imagine very terse class declarations completely without bodies in some cases.\n\nA hurdle here is the convention that parameters are `camelCase` (start with lower case) and public properties are `PascalCase` (start with upper case). To be general, we’d need for each parameter to give not one but two names – something like this:\n``` c#\npublic class Point(int x: X, int y: Y);\n```\nWhich would yield public getter-only properties named `X` and `Y` as well as constructor parameters `x` and `y` with which the properties are initialized. It would expand to this:\n``` c#\npublic class Point(int x, int y)\n{\n   public int X { get; } = x;\n   public int Y { get; } = y;\n}\n```\nThis syntax looks fairly nice in the above example, but it gets a little unwieldy when the names are longer:\n``` c#\npublic class Person(string firstName: FirstName, string lastName: LastName);\n```\nMaybe we could live with not having separate parameter names. We could reuse the syntax we’ve just dropped for field parameters and use it for property parameters instead:\n``` c#\npublic class Person(public string FirstName, public string LastName);\n```\nThis would be shorthand for writing\n``` c#\npublic class Person(string FirstName, string LastName)\n{\n   public string FirstName { get; } = FirstName;\n   public string LastName { get; } = LastName;\n}\n```\nNow the parameters would show up as PascalCase. This does not seem like a big deal for new types, but it would mean that most current code couldn’t be moved forward to this syntax without breaking callers who use named arguments.\n\nThe implied association of parameter and property could certainly be useful in its own right. You could imagine allowing the use of object initializers to initialize these getter-only properties. Instead of translating it into setter calls, the compiler would know the corresponding constructor parameters to pass the values to:\n``` c#\nvar p = new Person { LastName = \"Pascal\", FirstName = \"Blaise\" };\n```\nWould turn into:\n``` c#\nvar p = new Person(\"Blaise\", \"Pascal\");\n```\nAlso, in the future, if we were to consider pattern matching or deconstruction features, this association could be helpful.\n\n### Conclusion\nWe like the idea of providing a shorthand in the primary constructor parameter list for generating simple corresponding properties. However, we are not ready to go down this route just yet. We need to decide on the upper-case/lower-case issue for one thing. We note that primary constructors already provide quite an improvement over what you have to write in C# 5.0. That’s just going to have to be good enough for now.\n\n## Typeswitch\nFor a long time we’ve had the idea to add a typeswitch feature to C#. In this coming release, VB is seriously looking at expanding its `Select Case` statement to allow matching on types. Syntactically, this seems to fit right in as a natural extension in VB. In C#, maybe not so much: the `switch` statement is quite restrictive and only a little evolved from C’s original jump table oriented design. It doesn’t easily accommodate such a different form of case condition.\n\nSo if we were to add typeswitching capabilities to C#, we most likely would do it as a new feature with its own syntax. Options range from a switch-like construct with blocks for each match, to a more expression-oriented style reminiscent of pattern matching in functional languages.\n\nA major point here is that type switching can be seen as a special case of pattern matching. Would we ever add generalized pattern matching to C#? It certainly seems like a reasonable possibility. If so, then we should think of any typeswitching feature in that light: it needs to have the credible ability to “grow up” into a pattern matching feature in the future.\n\n### Conclusion\nWe’ve looked some at this, trying to imagine what a pattern matching future would look like. We have some great ideas, but we are not confident that we can map them out at this point to an extent where we would trust a current typeswitch design to fit well with it. And we do not have capacity to design and implement the full feature set in the current round. \n\nLet’s rather wait with the whole package and see if we can attack it in one go in the future.\n\n"
  },
  {
    "path": "meetings/2014/LDM-2014-05-21.md",
    "content": "# C# Language Design Notes for May 21, 2014\n\n## Agenda\n1.\tLimit the nameof feature? <_keep current design_>\n2.\tExtend params IEnumerable? <_keep current design_>\n3.\tString interpolation <_design nailed down_>\n\n## Limit the nameof feature?\nThe current design of the `nameof(x)` feature allows for the named entity to reference entities that are not uniquely identified by the (potentially dotted) name given: methods overloaded on signature, and types overloaded on generic arity.\n\nThis was rather the point of the feature: since you are only interested in the name, why insist on binding uniquely to just one symbol? As long as there’s at least one entity with the given name, it seems fine to yield the name without error. This sidesteps all the issues with the mythical `infoof()` feature (that would take an entity and return reflective information for it) of coming up with language syntax to uniquely identify overloads. (Also there’s no need to worry about distinguishing generic instantiations from uninstantiated generics, etc.: they all have the same name).\n\nThe design, however, does lead to some interesting challenges for the tooling experience: \n``` c#\npublic void M();\npublic void M(int i);\npublic void M(string s);\nWriteLine(nameof(M)); // writes the string \"M\"\n```\nWhich definition of `M` should “Go To Definition” on `M` go to? When does renaming an overload cause a rename inside of the `nameof`? Which of the overloads does the occurrence of `nameof(M)` count as a reference to? Etc. The ambiguity is a neat trick at the language level, but a bit of a pain at the tooling level.\n\nShould we limit the application of `nameof` to situations where it is unambiguous?\n\n### Conclusion\nNo. Let’s keep the current design. We can come up with reasonable answers for the tooling challenges. Hobbling the feature would hurt real scenarios.\n\n## Extend params IEnumerable?\nBy current design, params is extended to apply to `IEnumerable<T>` parameters. The feature still works by the call site generating a `T[]` with the arguments in it; but that array is of course available inside the method only as an `IEnumerable<T>`.\n\nIt has been suggested that we might as well make this feature work for other generic interfaces (or even all types) that arrays are implicitly reference convertible to, instead of just `IEnumerable<T>`.\n\nIt would certainly be straightforward to do, though there are quite a lot of such types. We could even infer an element type for the array from the passed-in arguments for the cases where the collection type does not have an element type of its own.\n\nOn the other hand, it is usually bad practice for collection-expecting public APIs to take anything more specific than `IEnumerable<T>`. That is especially true if the API is not intending to modify the collection, and no meaningful params method would do so: after all, if your purpose is to cause a side effect on a passed-in collection, why would you give the caller the option not to pass one?\n\n### Conclusion\nParams only really makes sense on `IEnumerable<T>`. If we were designing the language from scratch today we wouldn’t even have params on arrays, but only on `IEnumerable<T>`. So let’s keep the design as is.\n\n## String interpolation\nThere have been a number of questions around how to add string interpolation to C#, some a matter of ambition versus simplicity, some just a matter of syntax. In the following we settle on these different design aspects.\n\n### Safety\nConcatenation of strings with contents of variables has a long tradition for leading to bugs or even attack vectors, when the resulting string is subsequently parsed up and used as a command. Presumably if you make string concatenation easier, you are more vulnerable to such issues – or at least, by having a dedicated string interpolation features, you have a natural place in the language to help address such problems.\n\nConsequently, string interpolation in the upcoming EcmaScript 6 standard allows the user to indicate a function which will be charged with producing the result, based on compiler-generated lists of string fragments and expression results to be filled in. A given trusted function can prevent SQL injection or ensure the well-formedness of a URI.\n\n#### Conclusion\nWe don’t think accommodating custom interpolators in C# is the sweet spot at this point. Most people are probably just looking for simpler and more readable syntax for filling out holes in strings. However, as we settle on syntax we should keep an eye on our ability to extend for this in the future.\n\n### Culture\nIn .NET there’s a choice between rendering values in the current culture or an invariant culture. This determines how common values such as dates and even floating point numbers are shown in text. The default is current culture, which even language-recognized functions such as `ToString()` make use of.\n\nCurrent culture is great if what you’re producing is meant to be read by humans in the same culture as the program is run in. If you get more ambitious than that with human readers, the next step up is to localize in some more elaborate fashion: looking up resources and whatnot. At that point, you are reaching for heavier hammers than the language itself should probably provide.\n\nThere’s an argument that when a string is produced for machine consumption it is better done in the invariant culture. After all, it is quite disruptive to a comma-separated list of floating point values if those values are rendered with commas instead of dots as the decimal point!\n\nShould a string interpolation feature default to current or invariant culture, or maybe provide a choice?\n\n#### Conclusion\nWe think this choice has already been made for us, with the language and .NET APIs broadly defaulting to current culture. That is probably the right choice for most quick-and-easy scenarios. If we were to accommodate custom interpolators in the future, there could certainly be one for culture-invariant rendering.\n\n### Syntax\nThe general format is strings with “holes”, the holes containing expressions to be “printed” in that spot. We’d like the syntax to stress the analogy to `String.Format` as much as possible, and we therefore want to use curly braces `{…}` in the delimiting of holes. We’ll return to what exactly goes in the curly braces, but for now there is one central question: how do we know to do string interpolation at all?\n\nThere are two approaches we can think of:\n1.\tProvide new syntax around the holes\n2.\tProvide new syntax around the string itself\n\nTo the first approach, we previously settled on escaping the initial curly brace of each hole to mean this was a string interpolation hole, and the contents should be interpreted as expression syntax:\n``` c#\n\"Hello, \\{name}, you have \\{amount} donut{s} left.\"\n```\nHere, `name` and `amount` refer to variables in scope, whereas `{s}` is just part of the text.\nThis has a few drawbacks. It doesn’t look that much like a format string, because of the backslash characters in front of the curlies. You also need to visually scan the string to see if it is interpolated. Finally there’d be no natural place for us to indicate a custom interpolation function in the future.\n\nAn example of the second approach would be to add a prefix to the string to trigger interpolation, e.g.:\n``` c#\n$\"Hello, {name}, you have {amount} donut\\{s\\} left.\"\n```\nNow the holes can be expressed with ordinary braces, and just like format strings you have to escape braces to actually get them in the text (though we are eager to use backslash escapes instead of the double braces that format strings use). You can see up front that the string is interpolated, and if we ever add support for custom interpolators, the function can be put immediately before or after the `$`; whichever we decide:\n``` c#\nLOC$\"Hello, {name}, you have {amount} donut\\{s\\} left.\"\nSQL$\"…\"\nURI$\"…\"\n```\nThe prefix certainly doesn’t have to be a `$`, but that’s the character we like best for it. \n\nWe don’t actually have to do it with a prefix. JavaScript is going to use back ticks to surround the string. But prefix certainly seems better than yet another kind of string delimiter.\n\n#### Conclusion\nThe prefix approach seems better and more future proof. We are happy to use `$`. It wouldn’t compose with the `@` sign used for verbatim strings; it would be either one or the other.\n\n### Format specifiers\nFormat strings for `String.Format` allow various format specifiers in the placeholders introduced by commas and colons. We could certainly allow similar specifiers in interpolated strings. The semantics would be for the compiler to just turn an interpolated string into a call to `String.Format`, passing along any format specifiers unaltered:\n``` c#\n$\"Hello, {name}, you have {amount,-3} donut\\{s\\} left.\"\n```\nThis would be translated to\n``` c#\nString.Format(\"Hello, {0}, you have {1,-3} donut{{s}} left.\", name, amount)\n```\n(Note that formatting of literal curlies needs to change if we want to keep our backslash escape syntax, which, tentatively, we do).\nThe compiler would be free to not call `String.Format`, if it knows how to do things more optimally. This would typically be the case when there are no format specifiers in the string.\n\n#### Conclusion\nAllow all format specifiers that are allowed in the format strings of `String.Format`, and just pass them on.\n\n### Expressions in the holes\nThe final – important – question is which expressions can be put between the curly braces. In principle, we could imagine allowing almost any expression, but it quickly gets weird, both from a readability and from an implementation perspective. What if the expression itself has braces or strings in it? We wouldn’t be able to just lex our way past it (when to stop?), and similarly a reader, even with the help of colorization, would get mightily confused about what gets closed out when exactly.\n\nAdditionally the choice to allow format specifiers limits the kinds of expressions that can unambiguously precede those. \n``` c#\n$\"{a as b ? – c : d}\" // ?: or nullable type and format specifier?\n```\nThe other extreme is to allow just a very limited set of expressions. The common case is going to be simple variables anyway, and anything can be expressed by first assigning into variables and then using those in the string.\n\n#### Conclusion\nWe want to be quite cautious here, at least to begin with. We can always extend the set of expressions allowed, but for now we want to be close to the restrictive extreme and allow only simple and dotted identifiers.\n\n\n"
  },
  {
    "path": "meetings/2014/LDM-2014-07-09.md",
    "content": "# C# Language Design Notes for July 9, 2014\n\n## Agenda\n1.\tDetailed design of nameof <_details settled_>\n2.\tDesign of #pragma warning extensions <_allow identifiers_>\n\n## Details of nameof\nThe overall design of `nameof` was decided in the design meeting on [Oct 7, 2013](https://roslyn.codeplex.com/discussions/552376). However, a number of issues weren’t addressed at the time.\n\n### Syntactic ambiguity\nThe use of `nameof(…)` as an expression can be ambiguous, as it looks like an invocation. In order to stay compatible, if there’s an invokable `nameof` in scope we’ll treat it as an invocation, regardless of whether that invocation is valid. This means that in those cases there is no way to apply the nameof operator. The recommendation of course will be to get rid of any use of `nameof` as an identifier, and we should think about having diagnostics helping with that.\n\n###\tWhich operands are allowed?\nThe symbols recognized in a nameof expression must represent locals, range variables, parameters, type parameters, members, types or namespaces. Labels and preprocessor symbols are not allowed in a nameof expression.\n\nIn general, free-standing identifiers are looked up like simple names, and dotted rightmost identifiers are looked up like member access. It is thus an error to reference locals before their declaration, or to reference inaccessible members. However, there are some exceptions:\n\n_All members are treated as if they were static members._ This means that instance members are accessed by dotting off the type rather than an instance expression. It also means that the accessibility rules around protected instance members are the simpler rules that apply to static members.\n\n_Generic types are recognized by name only._ Normally there needs to be a type parameter list (or at least dimension specifier) to disambiguate, but type parameter lists or dimension specifiers are not needed, and in fact not allowed, on the rightmost identifier in a nameof.\n\n_Ambiguities are not an error._ Even if multiple entities with the same name are found, nameof will succeed. For instance, if a property named `M` is inherited through one interface and a method named `M` is inherited through another, the usual ambiguity error will not occur.\n\n### The referenced set\nBecause ambiguities are allowed, a nameof operator can reference a set of different entities at the same time. The precise set of referenced entities in the presence of ambiguity can be loosely defined as “those it would be ambiguous between”. Thus, shadowed members or other entities that wouldn’t normally be found by lookup, e.g. because they are in a base class or an enclosing scope of where an entity is found, will not be part of the referenced set.\n\nThe notion of referenced set has little importance for the language-level semantics, but is important for the tooling experience, e.g. for refactorings, go-to-definition, etc.\nReference to some entities, e.g. obsolete members, `Finalize` or ‘`op_`’ methods, is normally an error. However, it is not an error in `nameof(…)` unless _all_ members of the referenced set would give an error. If all non-error references give warnings, then a warning is given.\n\n### The resulting string\nC# doesn’t actually have a notion of canonical name. Instead, equality between names is currently defined directly _between_ names that may contain special symbols.\n\nFor `nameof(… i)` we want the resulting string to be the identifier `I` given, except that formatting characters are omitted, and Unicode escapes are resolved. Also, any leading `@` is removed.\n\nIn the case of aliases, this means that those are not resolved to their underlying meaning: the identifier is that of the alias itself.\n\nAs a result, the meaning of the identifier is always only used to check if it is valid, never to decide what the resulting string is. There is no semantic component to determining the result of a nameof operator, only to determining if it is allowed.\n\n## Pragma warning directives\nNow that custom diagnostics are on their way, we want to allow users to turn these on and off from source code, just as we do with the compiler’s own diagnostics today. To allow this, we need to extend the model of how a diagnostic is identified: today a number is used, but that is not a scalable model when multiple diagnostic providers are involved.\n\nInstead the design is that diagnostics are identified by an identifier. For compatibility the C# compiler’s own diagnostics can still be referenced with a number, but can also be referred to with the pattern `CS1234`:\n``` c#\n#pragma warning disable AsyncCoreSet\n#pragma warning disable CS1234\n```\n\n"
  },
  {
    "path": "meetings/2014/LDM-2014-08-27.md",
    "content": "# C# Design Notes for Aug 27, 2014\n\n## Agenda\nThe meeting focused on rounding out the feature set around structs.\n1.\tAllowing parameterless constructors in structs <_allow, but some unresolved details_>\n2.\tDefinite assignment for imported structs <_revert to Dev12 behavior_>\n\n## Parameterless constructors in structs\nUnlike classes, struct types cannot declare a parameterless constructor in C# and VB today. The reason is that the syntax `new S()` in C# has historically been reserved for producing a zero-initialized instance of the struct. VB.Net has always had an alternative syntax for that (`Nothing`) and C# 2.0 also added one: `default(T)`. So the `new S()` syntax is no longer necessary for this purpose.\n\nIt is possible to define parameterless constructors for structs in IL, but neither C#, VB or F# allow you to. All three languages have mostly sane semantics when consuming one, though, _mostly_ having `new S()` call the constructor instead of zero-initializing the struct (except in some corner cases visited below).\n\nNot being able to define parameterless constructors in structs has always been a bit of a pain, and now that we’re adding initializers to structs it becomes outright annoying.\n\n### Conclusion\nWe want to add the ability to declare explicit public parameterless constructors in structs, and we also want to think about reducing the number of occurrences of `new S()` that produce a default value. In the following we explore details and additional proposals.\n\n### Accessibility\nC#, VB and F# will all call an accessible parameterless constructor if they find one. If there is one, but it is not accessible, C# and VB will backfill `default(T)` instead. (F# will complain.)\n\nIt is problematic to have successful but different behavior of `new S()` depending on where you are in the code. To minimize this issue, we should make it so that explicit parameterless constructors have to be public. That way, if you want to replace the “default behavior” you do it everywhere.\n\n#### Conclusion\nParameterless constructors will be required to be public.\n\n### Compatibility\nNon-generic instantiation of structs with (public) parameterless constructors does the right thing in all three languages today. With generics it gets a little more subtle. All structs satisfy the `new()` constraint. When `new T()` is called on a type parameter `T`, the compiler _should_ generate a call to `Activator.CreateInstance` – and in VB and F# it does. However, C# tries to be smart, discovers at runtime that `T` is a struct (if it doesn’t already know from the `struct` constraint), and emits `default(T)` instead!\n\n``` c#\npublic T M<T>() where T: new() { return new T(); }\n```\n\nClearly we should remove this “optimization” and always call `Activator.CreateInstance` in C# as well. This is a bit of a breaking change, in two ways. Imagine the above method is in a library:\n\n1.\tThe more obvious – but also more esoteric – break is if people today call the library with a struct type (written directly in IL) which has a parameterless constructor, yet they depend on the library _not_ calling that parameterless constructor. That seems extremely unlikely, and we can safely ignore this aspect.\n2.\tThe more subtle issue is if such a library is not recompiled as we start populating the world with structs with parameterless constructors. The library is going to be wrongly not calling those constructors until someone recompiles it. But if it’s a third party library and they’ve gone out of business, no-one ever will.\n\nWe believe even the second kind of break is relatively rare. The `new()` constraint isn’t used much. But it would be nice to validate.\n\n#### Conclusion\nChange the codegen for generic `new T()` in C# but try to validate that the pattern is rare in known code.\n\n### Default arguments\nFor no good reason C# allows `new` expressions for value types to occur as default arguments to optional parameters:\n\n``` c#\nvoid M(S s = new S()){ … }\n```\n\nThis is one place where we cannot (and do not) call a parameterless constructor even when there is one. This syntax is plain bad. It suggests one meaning but delivers another.\n\nWe should do what we can (custom diagnostic?) to move developers over to use `default(S)` with existing types. More importantly we should not allow this syntax at all when `S` has a parameterless constructor. This would be a slight breaking change for the vanishingly rare IL-authored structs that do today, but so be it.\n\n#### Conclusion\nForbid `new S()` in default arguments when `S` has a parameterless constructor, and consider a custom diagnostic when it doesn’t. People should use `default(S)` instead.\n\n### Helpful diagnostic\nIn general, with this change we are trying to introduce more of a distinction between default values and constructed values for structs. Today it is very blurred by the use of `new S()` for both meanings.\n\nArguably the use of `new S()` to get the default value is fine as long as `S` does not have any explicit constructors. It can be viewed a bit like making use of the default constructor in classes, which gets generated for you if you do not have _any_ explicit constructors.\n\nThe confusion is when a struct type “intends” to be constructed, by advertising one or more constructors. Provided that none of those is parameterless, `new S()` _still_ creates an unconstructed default value. This may or may not be the intention of the calling code. Oftentimes it would represent a bug where they meant to construct it (and run initializers and so forth), but the lack of complaint from the compiler caused them to think everything was all right.\n\nOccasionally a developer really does want to create an uninitialized value even of a struct that has constructors. In those cases, though, their intent would be much clearer if they used the `default(S)` syntax instead. \n\nIt therefore seems that everyone would be well served by a custom diagnostic that would help “clear up the confusion” as it were, by\n* Flagging occurrences of `new S()` where `S` has constructors but not a parameterless one\n* Offering a fix to change to `default(T)`, as well as fixes to call the constructors\n\nThis would help identify subtle bugs where they exist, and make the developer’s intent clearer when the behavior is intentional.\n\nThe issue of course is how disruptive such a diagnostic would be to existing code. Would it be so annoying that they would just turn it off? Also, is the above assumption correct, that the occurrence of any constructor means that the library author intended for a constructor to always run?\n\n#### Conclusion\nWe are cautiously interested in such a diagnostic, but concerned that it would be too disruptive. We should evaluate its impact on current code.\n\n### Chaining to the default constructor when there’s a parameterless one\nA struct constructor must ensure that the struct is definitely assigned. It can do so by chaining to another constructor or by assigning to all fields.\n\nFor structs with auto-properties there is an annoying fact that you cannot assign to the underlying field because its name is hidden, and you cannot assign to the setter, because you are not allowed to invoke a function member until the whole struct is definitely assigned. Catch 22!\n\nPeople usually deal with this today by chaining to the default constructor – which will zero-initialize the entire struct. If there is a user-defined parameterless constructor, however, that will not work. (Especially not if that is the constructor you are trying to implement!)\n\nThere is a workaround. Instead of writing\n``` c#\nS(int x): this() { this.X = x; }\n```\nYou can make use of the fact that in a struct, `this` is an l-value:\n``` c#\nS(int x) { this = default(S); this.X = x; }\n```\nIt’s not pretty, though. In fact it’s rather magical. We may want to consider adding an alternative syntax for zero-initializing from a constructor; e.g.:\n``` c#\nS(int x): default() { this.X = x; }\n```\nHowever, it is also worth noting that auto-properties themselves are evolving. You can now directly initialize their underlying field with an initializer on the auto-property. And for getter-only auto-properties, assignment in the constructor will also directly assign the underlying field. So maybe problem just isn’t there any longer. You can just zero-initialize the auto-properties directly:\n``` c#\npublic int X { get; set; } = 0;\n```\nNow the definite assignment analysis will be happy when you get to running a constructor body.\n\n#### Conclusion\nDo nothing about this right now, but keep an eye on the issue.\n\n### Generated parameterless constructors\nThe current rule is that initializers are only allowed if there are constructors that can run them. This seems reasonable, but look at the following code:\n\n``` c#\nstruct S \n{\n\tstring label = \"<unknown>\";\n\tbool pending = true;\n\tpublic S(){}\n\t…\n}\n```\n\nDo we _really_ want to force people to write that trivial constructor? Had this been a class, they would just have relied on the compiler-generated default constructor. \n\nIt is probably desirable to at least do what classes do and generate a default constructor when there are no other constructors. Of course we wouldn’t generate one when there are no initializers either: that would be an unnecessary (and probably slightly breaking) change over what we do today, as the generated constructor would do exactly the same as the default `new S()` behavior anyway.\n\nA question though is if we should generate a parameterless constructor to run initializers even if there are also parameterful ones. After all, don’t we want to ensure that initializers get run in as many cases as possible?\n\nThis seems somewhat attractive, though it does mean that a struct with initializers doesn’t get to choose _not_ to have a generated parameterless constructor that runs the initializers.\n\nAlso, in the case that there’s a primary constructor it becomes uncertain what it would mean for a parameterless constructor to run the initializers: after all they may refer to primary constructor parameters that aren’t available to the parameterless constructor:\n``` c#\nstruct Name(string first, string last)\n{\t\n\tstring first = first;\n\tstring last = last;\n}\n```\nHow is a generated parameterless constructor supposed to run those initializers? To make this work, we would probably have to make the parameterless constructor chain to the primary constructor (all other constructors must chain to the primary constructor), passing _default values_ as arguments. \n\nAlternatively we could require that all structs with primary constructors _also_ provide a parameterless constructor. But that kind of defeats the purpose of primary constructors in the first place: doing the same with less code.\n\nIn all we seem to have the following options:\n1. Don’t generate anything. If you have initializers, you must also provide at least one constructor. The only change from today’s design is that one of those constructors can be parameterless.\n2. Only generate a parameterless constructor if there are no other constructors. This most closely mirrors class behavior, but it may be confusing that adding an explicit constructor “silently” changes the meaning of `new S()` back to zero-initialization. (The above diagnostic would help with that, though).\n3. Generate a parameterless constructor only when there is not a primary constructor and\n    a. Still fall back to zero-initialization for new S() in this case\n    b. Require a parameterless constructor to be explicitly specified\n    This seems to introduce an arbitrary distinction between primary constructors and other constructors that prevents easy refactoring back and forth between them.\n4. Generate a parameterless constructor even when there is a primary constructor\n    a. using default values and/or\n    b. some syntax to provide the arguments as part of the primary constructor\n    This seems overly magical, and again treats primary constructors more differently than was the intent with their design.\n\n#### Conclusion\nThis is a hard one, and we didn’t reach agreement. We probably want to do at least option 2, since part of our goal is for structs to become more like classes. But we need to think more about the tradeoffs between that and the more drastic (but also more helpful?) approaches.\n\n## Definite assignments for imported structs\nUnlike classes, private fields in structs do need to be observed in various ways on the consumer side – they cannot be considered entirely an implementation detail.\n\nIn particular, in order to know if a struct is definitely assigned we need to know if its fields have all been initialized. For inaccessible fields, there is no sure way to do that piecemeal, so if such inaccessible fields exist, the struct-consuming code must insist that the struct value as a whole has been constructed or otherwise initialized.\n\nSo the key is to know if the struct has inaccessible fields. The native compiler had a long-running bug that would cause it to check imported structs for inaccessible fields _only_ where those fields were of value type! So if the struct had only a private field of a reference type, the compiler would fail to ensure that it was definitely assigned.\n\nIn Roslyn we started out implementing the specification, which was of course stricter and turned out to break some code (that was buggy and should probably have been fixed). Instead we then went to the opposite extreme and just stopped ensuring definite assignment of these structs altogether. This lead to its own set of problems, primarily in the form of a new set of bugs that went undetected because of the laxer rules.\n\nIdeally we would go back to implementing the spec. This would break old code, but have the best experience for new code. If we had a “quirks” mode approach, we could allow e.g. the lang-version flag to be more lax on older versions. Part of migrating a code base to the new version of the language would involve fixing this kind of issue.\n\n### Conclusion\nUnfortunately we do not have the notion of a quirks mode. Like a number of issues before, this one alone does not warrant introducing one – after all, it is a new kind of upgrade tax on customers. We should compile a list of things we would do if we had a quirks mode, and evaluate if the combined value would be enough to justify it.\n\nDefinite assignment for structs should be on that list. In the meantime however, the best we can do is to revert to the behavior of the native compiler, so that’s what we’ll do.\n\n"
  },
  {
    "path": "meetings/2014/LDM-2014-09-03.md",
    "content": "# C# Design Notes for Sep 3, 2014\n\nQuote of the day: “It’s a design smell. But it’s a good smell.”\n\n## Agenda\nThe meeting focused on rounding out the design of declaration expressions\n1.\tRemoving “spill out” from declaration expressions in simple statements <_yes, remove_>\n2.\tSame name declared in subsequent else-if’s <_condition decls out of scope in else-branch_>\n3.\tAdd semicolon expressions <_not in this version_>\n4.\tMake variables in declaration expressions readonly <_no_>\n\n## “Spill out”\nThe scope rules for variables introduced in declaration expressions are reasonably regular: the scope of such a variable extends to the nearest enclosing statement, and like all local variables, it may be used only after it has been defined, textually.\n\nWe did make a couple of exceptions, though: an expression-statement or a declaration-statement does _not_ serve as a boundary for such a variable – instead it “spills out” to the directly enclosing block – if there is one.\n\nSimilarly, a declaration expression in one field initializer is in scope for neighboring field initializers (as long as they are in the same part of the type declaration).\n\nThis was supposed to enable scenarios such as this:\n``` c#\nGetCoordinates(out var x, out var y);\n… // use x and y;\n```\n\nto address the complaint that it is too much of a hassle to use out and ref parameters. But we have a nagging suspicion that this scenario – pick up the value in one statement and use it in the next – is not very common. Instead the typical scenario looks like this:\n``` c#\nif (int.TryParse(s, out int i)) { … i … }\n```\nWhere the introduced local is used in the _same_ statement as it is declared in.\n\nOutside of conditions, probably the most common use is the inline common-subexpression refactoring, where the result of an expression is captured into a variable the first time it is used, so the variable can be applied to the remaining ones:\n``` c#\nConsole.WriteLine(\"Result: {0}\", (var x = GetValue()) * x);\n```\n\nThe spill-out is actually a bit of a nuisance for the somewhat common scenario of passing dummies to ref or out parameters that you don’t need (common in COM interop scenarios), because you cannot use the same dummy names in subsequent statements.\n\nFrom a rule regularity perspective, the spilling is quite complicated to explain. It would be a meaningful simplification to get rid of it. While complexity of spec’ing and implementing shouldn’t stand in the way of a good feature, it is often a smell that the design isn’t quite right.\n\n### Conclusion\nLet’s get rid of the spilling. Every declaration expression is now limited in scope to it nearest enclosing statement. We’ll live with the (hopefully) slight reduction in usage scenarios.\n\n## Else-if’s\nDeclaration expressions lend themselves particularly well to a style of programming where an if/else-if chain goes through various options, each represented by a variable declared in a condition, using those variables in the then-clause:\n``` c#\nif ((var i = o as int?) != null) { … i … }\nelse if ((var s = o as string) != null) { … s … }\nelse if …\n```\nThis particular pattern _looks_ like a chain of subsequent options, and even indents like that, but linguistically the else clauses are nested. For that reason, with our current scope rules the variable `I` introduced in the first condition is in scope in all the rest of the statement – even though it is only meaningful and interesting in the then-branch. In particular, it blocks another variable with the same name from being introduced in a subsequent condition, which is quite annoying.\n\nWe do want to solve this problem. There is no killer option that we can think of, but there are a couple of plausible approaches:\n\n1. Change the scope rules so that variables declared in the condition of an if are in scope in the then-branch  but not in the else-branch\n2. Remove the restriction that locals cannot be shadowed by other locals\n3. Do something very scenario specific\n\n### Changing the scope rules\nChanging the scope rules would have the unfortunate consequence of breaking the symmetry of if-statements, so that \n``` c#\nif (b) S1 else S2\n```\nNo longer means exactly the same as\n``` c#\nif (!b) S2 else S1\n```\nIt kind of banks on the fact that the majority of folks who would introduce declaration expressions in a condition would do so for use in the then-branch only. That certainly seems to be likely, given the cases we have seen (type tests, uses of the `Try…` pattern, etc.). But it still may be surprising to some, and downright bothersome in certain cases.\n\nWorse, there may be tools that rely on this symmetry principle. Refactorings to swap then and else branches (negating the condition) abound. These would no longer always work.\n\nMoreover, of course, this breaks with the nice simple scoping principle for declaration expressions that we just established above: that they are bounded (only) by their enclosing statement.\n\n### Removing the shadowing restriction\nSince C# 1.0, it has been forbidden to shadow a local variable or parameter with another one. This is seen as one of the more successful rules of hygiene in C# - it makes code safe for refactoring in many scenarios, and just generally easier to read.\n\nThere are existing cases where this rule is annoying:\n``` C#\ntask.ContinueWith(task => … task …); // Same task! Why can’t I name it the same?\n```\nHere it seems the rule even runs counter to refactoring, because you need to change every occurrence of the name when you move code into a lambda.\n\nLifting this restriction would certainly help the else-if scenario. While previous variables would still be in scope, you could now just shadow them with new ones if you choose.\n\nIf you do not choose to use the same name, however, the fact that those previous variables are in scope may lead to confusion or accidental use.\n\nMore importantly, are we really ready to part with this rule? It seems to be quite well appreciated as an aid to avoid subtle bugs.\n\n### Special casing the scenario\nInstead of breaking with general rules, maybe we can do something very localized? Some combination of the two?\nIt would have to work both in then and else branches; otherwise, it would still break the if symmetry, and be as bad as the first option.\n\nWe could allow only variables introduced in conditions of if-statements to be shadowed only by other variables introduced in conditions of if-statements?\n\nThis might work, but seems inexcusably ad-hoc, and is almost certain to cause a bug tail in many tools down the line, as well as confusion when refactoring code or trying to experiment with language semantics. \n\n### Conclusion\nIt seems there truly is no great option here. However, we’d rather solve the problem with a wart or two than not address it at all. On balance, option 1, the special scope rule for else clauses, seems the most palatable, so that’s what we’ll do.\n\n## Semicolon expressions\nWe previously proposed a semicolon operator, to be commonly used with declaration expressions, to make “let-like” scenarios a little nicer:\n``` c#\nConsole.WriteLine(\"Result: {0}\", (var x = GetValue(); x * x));\n```\nInstead of being captured on first use, the value is now captured first, _then_ used multiple times.\n\nWe are not currently on track to include this feature in the upcoming version of the language. The question is; should we be? There’s an argument that declaration expressions only come to their full use when they can be part of such a let-like construct. Also, there are cases (such as conditional expressions) where you cannot just declare the variable on first use, since the use is in a branch separate from later uses.\n\nNevertheless, it might be rash to say that this is our let story. Is this how we want let to look like in C#? We don’t easily get another shot at addressing the long-standing request for a let-like expression. It probably needs more thought than we have time to devote to it now.\n\n### Conclusion\nLet’s punt on this feature and reconsider in a later version.\n\n## Should declaration expression variables be mutable?\nC# is an imperative language, and locals are often used in a way that depends on mutating them sometime after initialization. However, you could argue that this is primarily useful when used across statements, whereas it generally would be a code smell to have a declaration that’s only visible _inside_ one statement rely on mutation.\n\nThis may or may not be the case, but declaration _expressions_ also benefit from a strong analogy with declaration _statements_. It would be weird that `var s = GetString()` introduces a readonly variable in one setting but not another. (Note: it does in fact introduce a readonly variable in a few situations, like foreach and using statements, but those can be considered special).\n\n### Conclusion\nLet’s keep declaration expressions similar to declaration statements. It is too weird if a slight refactoring causes the meaning to change. It may be worth looking at adding readonly locals at a later point, but that should be done in an orthogonal way.\n"
  },
  {
    "path": "meetings/2014/LDM-2014-10-01.md",
    "content": "There were two agenda items...\n1. Assignment to readonly autoprops in constructors (we fleshed out details)\n2. A new compiler warning to prevent outsiders from implementing your interface? (no, leave this to analyzers)\n\n# Assignment to readonly autoprops in constructors\n\n```cs\npublic struct S {\n   public int x {get;}\n   public int y {get; set;}\n   public Z z {get;}\n\n   public S() {\n      x = 15;\n      y = 23;\n      z.z1 = 1;\n   }\n}\n\npublic struct Z { int z1; }\n```\n\n_What are the rules under which assignments to autoprops are allowed in constructors?_\n\n__Absolute__ We can't be more permissive in what we allow with readonly autoprops than we are with readonly fields, because this would break PEVerify. (Incidentally, PEVerify doesn't check definite assignment in the constructor of a struct; that's solely a C# language thing).\n\n__Overall principle__ When reading/writing to an autoprop, do we go via the accessor (if there is one) or do we bypass it (if there is one) and access the underlying field directly?\n_Option1:_ language semantics say the accessor is used, and codegen uses it.\n_Option2:_ in an appropriate constructor, when there is a \"final\" autoprop (either non-virtual, or virtual in a sealed class), access to an autoprop _means_ an access to the underlying field. This meaning is used for definite assignment, and for codegen. Note that it is semantically visible whether we read from an underlying field vs through an accessor, e.g. in `int c { [CodeSecurity] get;}`\n_Resolution: Option1_. Under Option2, if you set a breakpoint on the getter of an autoprop, gets of it would not hit the breakpoint if they were called in the constructor which is weird. Also it would be weird that making the class sealed or the autoprop non-virtual would have this subtle change. And things like Postsharper wouldn't be able to inject. All round Option2 is weird and Option1 is clean and expected.\n\n__Definite Assignment__. Within an appropriate constructor, what exactly are the rules for definite assignment? Currently if you try to read a property before _all_ fields have been assigned then it says CS0188 'this' cannot be used before all fields are assignment, but reading a field is allowed so long as merely that field has been assigned. More precisely, within an appropriate constructor, for purposes of definite assignment analysis, when does access of the autoprop behave as if it's an access of the backing field?\n_Option1_: never\n_Option2_: Only in case of writes to readonly autoprops\n_Option3_: In the case of writes to all autoprops\n_Option4_: In the case of reads and writes to all autoprops\n_Resolution: Option4_. This is the most helpful to developers. You might wonder what happens if it's a virtual autoprop and someone overrides getter or setter in derived types in such a way that would violate the definite assignment assumptions. But for structs there won't be derived types, and for classes the semantics say that all fields are assigned to default(.) so there's no difference.\n\n__Piecewise initialization of structs__. In the code above, do we allow `z.z1 = 15` to assign to the _field_ of a readonly struct autoprop?\n_Option1:_ Yes by threating access to \"z\" for purposes of definite assignment as an access of the underlying field.\n_Option2:_ No because in `z.z1` the read of `z` happens via the accessor as per the principle above, and thus returns an rvalue, and hence assignment to `z.z1` can't work. Instead you will have to write `z = new Z(...)`.\n_Resolution: Option2_. If we went with Option1, then readonly autoprops would end up being more expressive than settable autoprops which would be odd! Note that in VB you can still write `_z.z1 = 15` if you do want piecewise assignment.\n\n__Virtual__. What should happen if the readonly autoprop is virtual, and its getter is overridden in a derived class?\n_Resolution:_ All reads of the autoprop go via its accessor, as is already the case.\n\n__Semantic model__. In the line `x = 15` what should the Roslyn semantic model APIs say for the symbol `x` ?\n_Resolution:_ they refer to the property x. Not the backing field. (Under the hood of the compiler, during lowering, if in an appropriate constructor,  for write purposes, it is implicitly transformed into a reference to the backing field). More specifically, for access to an autoprop in the constructor,\n1. It should _bind_ to the property, but the property should be treated as a readable+writable (for purposes of what's allowed) in the case of a readonly autoprop.\n2. The definite assignment behavior should be as if directly accessing the backing field.\n3. It should code gen to the property accessor (if one exists) or a field access (if not).\n\n__Out/ref arguments in C#__. Can you pass a readonly autoprop as an out/ref argument in C#?\n_Resolution: No_. For readonly autoprops passed as _ref_ arguments, that wouldn't obey the principle that access to the prop goes via its accessor. For passing readonly autoprops as _out_ arguments with the hope that it writes to the underlying field, that wouldn't obey the principle that we bind to the property rather than the backing field. For writeonly autoprops, they don't exist because they're not useful.\n\n__Static readonly autoprops__ Should everything we've written also work for static readonly autoprops?\n_Resolution: Yes._ Note there's currently a bug in the native compiler (fixed in Dev14) where the static constructor of a type G\\<T> is able to initialize static readonly fields in specializations of G e.g. `G<T>.x=15;`. The CLR does indeed maintain separate storage locations for each static readonly fields, so `G<int>.g` and `G<string>.g` are different variables. (The native compiler's bug where the static constructor of G could assign to all of them resulted in unverifiable code).\n\n__VB rules in initializers as well as constructors__. VB initializers are allowed to refer to other members of a class, and VB initializers are all executed during construction time. Should everything we've said about behavior in C# constructors also apply to behavior in VB initializers?\n_Resolution: Yes_.\n\n__VB copyback for ByRef parameters__. In VB, when you pass an argument to a ByRef parameter, then either it passes it as an lvalue (if the argument was a local variable or field or similar) or it uses \"copy-in to a temporary then invoke the method then copy-out from the temporary\" (if the argument was a property), or it uses \"copy-in to a temporary then invoke the method then ignore the output\" (if the argument was an rvalue or a constant). What should happen when you pass a readonly autoprop to a ByRef parameter?\n_Option1:_ Emit a compile-time error because copyback is mysterious and bites you in mysterious ways, and this new way is even more mysterious than what was there before.\n_Option2:_ Within the constructor/initializers, copy-in by reading via the accessor, and copy-back by writing to the underlying field. Elsewhere, copy-in with no copy-out. Also, just as happens with readonly fields, emit an error if assignment to a readonly autoprop happens in a lambda in a constructor (see code example below)\n_Resolution: Option2_. Exactly has happens today for readonly fields. Note incidentally that passing a readonly autoprop to a ByRef parameter will have one behavior in the constructor and initializers (it will do the copy-back), and will silently have different behavior elsewhere (it won't do any copy-back). This too is already the case with readonly fields. On a separate note, developers would like to have feedback in some cases (not constants or COM) where copyback in a ByRef argument isn't done. But that's not a question for the language design meeting.\n\n__VB copyin for writeonly autoprops__. VB tentatively has writeonly autoprops for symmetry, even though they're not useful. What should happen when you pass a writeonly autoprop as a ByRef argument?\n_Resolution: Yuck._ This is a stupid corner case. Notionally the correct thing is to read from the backing field, and write via the setter. But if it's easier to just remove support for writeonly autoprops, then do that.\n\n```vb\nClass C\n    ReadOnly x As Integer = 15\n\n    Public Sub New()\n        f(x)\n        Dim lambda = Sub()\n                         f(x) ' error BC36602: 'ReadOnly' variable\n                         ' cannot be the target of an assignment in a lambda expression\n                         ' inside a constructor.\n                     End Sub\n    End Sub\n    Shared Sub f(ByRef x As Integer)\n        x = 23\n    End Sub\nEnd Class\n```\n\nWe discussed a potential new error message in the compiler.\n\n__Scenario:__ Roslyn ships with ISymbol interface. In a future release it wants to add additional members to the interface. But this will break anyone who implemented ISymbol in its current form. Therefore it would be good to have a way to prevent anyone _else_ from implementing ISymbol. That would allow us to add members without breaking people.\n\nIs this scenario widespread? Presumably, but we don't have data and haven't heard asks for it. There are a number of workarounds today. Some workarounds provide solid code guarantees. Other workarounds provide \"suggestions\" or \"encouragements\" that might be enough for us to feel comfortable breaking people who took dependencies where we told them not to.\n\n__Counter-scenario:__ Nevertheless, I want to _MOCK_ types. I want to construct a mock ISymbol myself maybe using MOQ, and pass it to my functions which take in an ISymbol, for testing purposes. I still want to be able to do this. (Note: MOQ will automatically update whenever we add new members to ISymbol, so users of it won't be broken).\n\n\n__Workarounds__\n\n1. Ignore the problem and just break people.\n2. Like COM, solve it by adding new incremental interfaces ISymbol2 with the additional members. As Adam Speight notes below, you can make ISymbol2 inherit from ISymbol.\n3. Instead of interfaces, use abstract classes with internal constructors. Or abstract classes but never add abstract methods to it; only virtual methods.\n4. Write documentation for the interface, on MSDN or in XML Doc-Comments, that say \"Internal class only; do not implement it\". We see this for instance on ICorThreadpool.\n5. Declare a method on the interface which has an internal type in its signature. The CLR allows this but the language doesn't so it would have to be authored in IL. Every type which implements the interface would have to provide an implementation of that method.\n6. Write run-time checks at the public entry points of key Roslyn methods that take in an ISymbol, and throw if the object given was implemented in the wrong assembly.\n7. Write a Roslyn analyzer which is deployed by the same NuGet package that contains the definition of ISymbol, and have this analyzer warn if you're trying to implement the interface. This analyzer could be part of Roslyn, or it could be an independent third-party analyzer used by many libraries.\n\n\n__Proposal:__ Have the compiler recognize a new attribute. Given the following code\n```cs\n[System.Runtime.CompilerServices.InternalImplementationOnly] interface I<...> {...}\n```\nit should be a compile-time warning for a type to implement that interface, directly or indirectly, unless the class is in the same assembly as \"I\" or is in one of its InternalsVisibleTo friends. It will also be a compile-time error for an interface to inherit from the interface in the same way. Also, we might ask for the .NET Framework team to add this attribute in the same place as System.Runtime.CompilerServices.ExtensionAttribute, and CallerMemberNameAttribute. But doing it isn't necessary since the compiler will recognize any attribute with that exact fully-qualified name and the appropriate (empty) constructor. \n\nNote that this rule would not be cast-iron, since it won't have CLR enforcement. It would still be possible to bypass it by writing IL by hand, or by compiling with an older compiler. But we're not looking for cast-iron. We're just looking for discouragement strong enough to allow us to add members to ISymbol in the future. (In the case of ISymbol, it's very likely that people will be using Roslyn to compile code relating to ISymbol, but that doesn't apply to other libraries).\n\n\n__Resolution:__ Workaround #7 is a better option than adding this proposal to the language.\n\n"
  },
  {
    "path": "meetings/2014/LDM-2014-10-15.md",
    "content": "# nameof operator: spec v5\nThe nameof(.) operator has the form nameof(expression). The expression must have a name, and may refer to either a single symbol or a method-group or a property-group. Depending on what the argument refers to, it can include static, instance and extension members.\n\nThis is v5 of the spec for the \"nameof\" operator. [[v1](https://roslyn.codeplex.com/discussions/552376), [v2](https://roslyn.codeplex.com/discussions/552377), [v3](https://roslyn.codeplex.com/discussions/570115), [v4](https://roslyn.codeplex.com/discussions/570364)]. The key decisions and rationales are summarized below. _Please let us know what you think!_\n\n\n# Rationale\n\nQuestion: why do we keep going back-and-forth on this feature?\n\nAnswer: I think we're converging on a design. It's how you do language design! (1) make a proposal, (2) _spec it out_ to flush out corner cases and make sure you've understood all implications, (3) _implement the spec_ to flush out more corner cases, (4) try it in practice, (5) if what you hear or learn at any stage raises concerns, goto 1.\n\n* _v1/2 had the problem \"Why can't I write nameof(this.p)? and why is it so hard to write analyzers?\"_\n* _v3 had the problem \"Why can't I write nameof(MyClass1.p)? and why is it so hard to name method-groups?\"_\n* _v4 had the problem \"What name should be returned for types? and how exactly does it relate to member lookup?\"_\n\nThis particular \"nameof v5\" proposal came from a combined VB + C# LDM on 2014.10.22. We went through the key decisions:\n\n1. __Allow to dot an instance member off a type? Yes.__ Settled on the answer \"yes\", based on the evidence that v1/v2 had it and it worked nicely, and v3 lacked it and ended up with unacceptably ugly \"default(T)\" constructions.\n2. __Allow to dot instance members off an instance? Yes.__ Settled on the answer \"yes\", based on the evidence that v1/v2 lacked it and it didn't work well enough when we used the CTP, primarily for the case \"this.p\"\n3. __Allow to name method-groups? Yes.__ Settled on the answer \"yes\", based on the evidence that v1/v2 had it and it worked nicely, and v3 lacked it and ended up with unacceptably ugly constructions to select which method overload.\n4. __Allow to unambiguously select a single overload? No.__ Settled on the answer \"no\" based on the evidence that v3 let you do this but it looked too confusing. I know people want it, and it would be a stepping stone to infoof, but at LDM we rejected these (good) reasons as not worth the pain. The pain is that the expressions look like they'll be executed, and it's unclear whether you're getting the nameof the method or the nameof the result of the invocation, and they're cumbersome to write.\n5. __Allow to use nameof(other-nonexpression-types)? No.__ Settled on the answer \"only nameof(expression)\". I know people want other non-expression arguments, and v1/v2 had them, and it would be more elegant to just write nameof(List<>.Length) rather than having to specify a concrete type argument. But at LDM we rejected these (good) reasons as not worth the pain. The pain is that the language rules for member access in expressions are too different from those for member access in the argument to nameof(.), and indeed member access for StrongBox<>.Value.Length doesn't really exist. The effort to unify the two concepts of member access would be way disproportionate to the value of nameof. This principle, of sticking to existing language concepts, also explains why v5 uses the standard language notions of \"member lookup\", and hence you can't do nameof(x.y) to refer to both a method and a type of name \"y\" at the same time.\n6. __Use source names or metadata names? Source.__ Settled on source names, based on the evidence... v1/v2/v3 were source names because that's how we started; then we heard feedback that people were interested in metadata names and v4 explored metadata names. But I think the experiment was a failure: it ended up looking like _disallowing_ nameof on types was better than picking metadata names. At LDM, after heated debate, we settled on source names. For instance `using foo=X.Y.Z; nameof(foo)` will return \"foo\". Also `string f<T>() => nameof(T)` will return \"T\". There are pros and cons to this decision. In its favor, it keeps the rules of nameof very simple and predictable. In the case of nameof(member), it would be a hindrance in most (not all) bread-and-butter cases to give a fully qualified member name. Also it's convention that \"System.Type.Name\" refers to an unqualified name. Therefore also nameof(type) should be unqualified. If ever you want a fully-qualified type name you can use typeof(). If you want to use nameof on a type but also get generic type parameters or arguments then you can construct them yourself, e.g. nameof(List\\<int>) + \"`2\". Also the languages have no current notion of metadata name, and metadata name can change with obfuscation.\n7. __Allow arbitrary expressions or just a subset?__ We want to try out the proposal \"just a subset\" because we're uneasy with full expressions. That's what v5 does. We haven't previously explored this avenue, and it deserves a try.\n8. __Allow generic type arguments?__ Presumably 'yes' when naming a type since that's how expression binding already works. And presumably 'no' when naming a method-group since type arguments are used/inferred during overload resolution, and it would be confusing to also have to deal with that in nameof. [this item 8 was added after the initial v5 spec]\n\n\nI should say, we're not looking for unanimous consensus -- neither amongst the language design team nor amongst the codeplex OSS community! We hear and respect that some people would like something closer to infoof, or would make different tradeoffs, or have different use-cases. On the language design team we're stewards of VB/C#: we have a responsibility to listen to and understand _every opinion_, and then use our own judgment to weigh up the tradeoffs and use-cases. I'm glad we get to do language design in the open like this. We've all been reading the comments on codeplex and elsewhere, our opinions have been swayed, we've learned about new scenarios and issues, and we'll end up with a better language design thanks to the transparency and openness. I'm actually posting these notes on codeplex as my staging ground for sharing them with the rest of the team, so the codeplex audience really does see everything \"in the raw\".\n\n\n# C# Syntax\n```\nexpression: ... | nameof-expression\n\nname-of-expression:\n    nameof ( expression )\n```\nIn addition to the syntax indicated by the grammar, there are some additional syntactic constraints: (1) the argument expression can only be made up out of simple-name, member-access, base-access, or \"this\", and (2) cannot be simply \"this\" or \"base\" on its own. These constraints ensure that the argument looks like it has a name, and doesn't look like it will be evaluated or have side effects. I found it easier to write the constraints in prose than in the grammar.\n\n[clarification update] Note that member-access has three forms, `E.I<A1...AK>` and `predefined-type.I<A1...AK>` and `qualified-alias-member.I`. All three forms are allowed, although the first case `E` must only be made out of allowed forms of expression.\n\nIf the argument to nameof at its top level has an unacceptable form of expression, then it gives the error \"This expression does not have a name\". If the argument contains an unacceptable form of expression deeper within itself, then it gives the error \"This sub-expression cannot be used as an argument to nameof\".\n\nIt is helpful to list some things not allowed as the nameof argument:\n```\n    invocation-expression        e(args)\n    assignment                   x += 15\n    query-expression             from y in z select y\n    lambda-expression            () => e\n    conditional-expression       a ? b : c\n    null-coalescing-expression   a?? b\n    binary-expression            ||, &&, |, ^, &, ==, !=,\n                                 <, >, <=, >=, is, as, <<,\n                                 >>, +, -, *, /, %\n    prefix-expression            +, -, !, ~, ++, --,\n                                 *, &, (T)e\n    postfix-expression           ++, --\n    array-creation-expression    new C[…]\n    object-creation-expression   new C(…)\n    delegate-creation-expression new Action(…)\n    anonymous-object-creation-expression new {…}\n    typeof-expression            typeof(int)\n    checked-expression           checked(…)\n    unchecked-expression         unchecked(…)\n    default-value-expression     default(…)\n    anonymous-method-expression  delegate {…}\n    pointer-member-access        e->x\n    sizeof-expression            sizeof(int)\n    literal                      \"hello\", 15\n    parenthesized-expression     (x)\n    element-access               e[i]\n    base-access-indexed          base[i]\n    await-expression             await e\n    nameof-expression            nameof(e)\n    vb-dictionary-lookup         e!foo \n```\n\nNote that there are some types which are not counted as expressions by the C# grammar. These are not allowed as nameof arguments (since the nameof syntax only allows expressions for its argument). There's no need to spell out that the following things are not valid expressions, since that's already said by the language syntax, but here's a selection of some of the types that are not expressions:\n```\n    predefined-type              int, bool, float, object,\n                                 dynamic, string\n    nullable-type                Customer?\n    array-type                   Customer[,]\n    pointer-type                 Buffer*, void* \n    qualified-alias-member       A::B\n    void                         void\n    unbound-type-name            Dictionary<,>\n```           \n\n\n# Semantics\n\nThe nameof expression is a constant. In all cases, nameof(...) is evaluated at compile-time to produce a string. Its argument is not evaluated at runtime, and is considered unreachable code (however it does not emit an \"unreachable code\" warning).\n\n_Definite assignment._ The same rules of definite assignment apply to nameof arguments as they do to all other unreachable expressions.\n\n_Name lookup_. In the following sections we will be discussing member lookup. This is discussed in $7.4 of the C# spec, and is left unspecified in VB. To understand nameof it is useful to know that the existing member lookup rules in both languages either return a single type, or a single instance/static field, or a single instance/static event, or a property-group consisting of overloaded instance/static properties of the same name (VB), or a method-group consisting of overloaded instance/static/extension methods of the same name. Or, lookup might fail either because no symbol was found or because ambiguous conflicting symbols were found that didn't fall within the above list of possibilities.\n\n_Argument binding_. The nameof argument refers to one or more symbols as follows.\n\n__nameof(simple-name)__, of the form I or I<A1...AK>\nThe normal rules of simple name lookup $7.6.2 are used but with one difference...\n* The third bullet talks about member lookup of I in T with K type arguments. Its third sub-bullet says _\"Otherwise, the result is the same as a member access of the form T.I or T.I<A1...AK>. In this case, it is a binding-time error for the simple-name to refer to an instance member.\"_ For the sake of nameof(simple-name), this case does not constitute a binding-time error.\n\n\n__nameof(member-access)__, of the form E.I or E.I<A1...AK>\nThe normal rules of expression binding are used to evaluate \"E\", with _no changes_. After E has been evaluated, then E.I<A1...AK> is evaluated as per the normal rules of member access $7.6.4 but with some differences...\n* The third bullet talks about member lookup of I in E. Its sub-bullets have rules for binding when I refers to static properties, fields and events. For the sake of nameof(member-access), each sub-bullet applies to instance properties, fields and events as well.\n* The fourth bullet talks about member lookup of I in T. Its sub-bullets have rules for binding when I refers to instance properties, fields and events. For the sake of nameof(member-access), each sub-bullet applies to static properties, fields and events as well.\n\n__nameof(base-access-named)__, of the form base.I or base.I<A1...AK>\nThis is treated as nameof(B.I) or nameof(B.I<A1...AK> where B is the base class of the class or struct in which the construct occurs.\n\n\n_Result of nameof_. The result of nameof is the identifier \"I\" with the _standard identifier transformations_. Note that, at the top level, every possible argument of nameof has \"I<A1...AK>\".\n\n[update that was added after the initial v5 spec] If \"I\" binds to a method-group and the argument of nameof has generic type arguments at the top level, then it produces an error \"Do not use generic type arguments to specify the name of methods\". Likewise for property-groups.\n\nThe standard identifier transformations in C# are detailed in $2.4.2 of the C# spec: first any leading @ is removed, then Unicode escape sequences are transformed, and then any formatting-characters are removed. This of course still happens at compile-time. In VB, any surrounding [] is removed\n\n# Implementation\nIn C#, nameof is stored in a normal InvocationExpressionSyntax node with a single argument. That is because in C# 'nameof' is a contextual keyword, which will only become the \"nameof\" operator if it doesn't already bind to a programmatic symbol named \"nameof\". TO BE DECIDED: what does its \"Symbol\" bind to?\n\nIn VB, NameOf is a reserved keyword. It therefore has its own node:\n```vb\nClass NameOfExpressionSyntax : Inherits ExpressionSyntax\n    Public ReadOnly Property Argument As ExpressionSyntax\nEnd Class\n```\nTO BE DECIDED: Maybe VB should just be the same as C#. Or maybe C# should do the same as VB.\n\nWhat is the return value from `var r = semanticModel.GetSymbolInfo(argument)`? In all cases, r.Candidates is the list of symbol. If there is only one symbol then it is in r.Symbol; otherwise r.Symbol is null and the reason is \"ambiguity\".\n\nAnalyzers and the IDE will just have to deal with this case.\n\n\n# IDE behavior\n```cs\nclass C {\n   [3 references] static void f(int i) {...nameof(f)...}\n   [3 references] void f(string s) {...nameof(this.f)...}\n   [3 references] void f(object o) {...nameof(C.f)...}\n}\nstatic class E {\n   [2 references] public static void f(this C c, double d) {}\n}\n```\n\n__Highlight symbol from argument__: When you set your cursor on an argument to nameof, it highlights all symbols that the argument bound to. In the above examples, the simple name \"nameof(f)\" binds to the three members inside C. The two member access \"nameof(this.f)\" and \"nameof(C.f)\" both bind to extension members as well.\n\n__Highlight symbol from declaration__: When you set your cursor on any declaration of f, it highlights all nameof arguments that bind to that declaration. Setting your cursor on the extension declaration will highlight only \"this.f\" and \"C.f\". Setting your cursor on any member of C will highlight both all three nameof arguments.\n\n__Goto Definition__: When you right-click on an argument to nameof in the above code and do GoToDef, it pops up a FindAllReferences dialog to let you chose which declaration. (If the nameof argument bound to only one symbol then it would go straight to that without the FAR dialog.)\n\n__Rename declaration__: If you do a rename-refactor on one of the declarations of f in the above code, the rename will only rename this declaration (and will not rename any of the nameof arguments); the rename dialog will show informational text warning you about this. If you do a rename-refactor on the _last remaining_ declaration of f, then the rename will also rename nameof arguments. Note that if you turn on the \"Rename All Overloads\" checkbox of rename-refactor, then it will end up renaming all arguments.\n\n__Rename argument__: If you do a rename-refactor on one of the nameof arguments in the above code, the rename dialog will by default check the \"Rename All Overloads\" button.\n\n__Expand-reduce__: The IDE is free to rename \"nameof(p)\" to \"nameof(this.p)\" if it needs to do so to remove ambiguity during a rename. This might make nameof now bind to more things than it used to...\n\n__Codelens__: We've articulated the rules about what the argument of nameof binds to. The CodeLens reference counts above are a straightforward consequence of this.\n\n\n## Bread and butter cases\n```cs\n// Validate parameters \nvoid f(string s) {\n    if (s == null) throw new ArgumentNullException(nameof(s));\n}\n```\n\n```cs\n// MVC Action links\n<%= Html.ActionLink(\"Sign up\",\n             @typeof(UserController),\n             @nameof(UserController.SignUp))\n%>\n```\n\n```cs\n// INotifyPropertyChanged\nint p {\n    get { return this._p; }\n    set { this._p = value; PropertyChanged(this, new PropertyChangedEventArgs(nameof(this.p)); }\n}\n// also allowed: just nameof(p)\n```\n\n```cs\n// XAML dependency property\npublic static DependencyProperty AgeProperty = DependencyProperty.Register(nameof(Age), typeof(int), typeof(C));\n```\n\n```cs\n// Logging\nvoid f(int i) {\n    Log(nameof(f), \"method entry\");\n}\n```\n\n```cs\n// Attributes\n[DebuggerDisplay(\"={\" + nameof(getString) + \"()}\")]\nclass C {\n    string getString() { ... }\n}\n```\n\n# Examples\n\n```cs\nvoid f(int x) {\n   nameof(x)\n}\n// result \"x\": Parameter (simple name lookup)\n```\n\n```cs\nint x=2; nameof(x)\n// result \"x\": Local (simple name lookup)\n```\n\n```cs\nconst x=2; nameof(x)\n// result \"x\": Constant (simple name lookup)\n```\n\n```cs\nclass C {\n   int x;\n   ... nameof(x)\n}\n// result \"x\": Member (simple name lookup)\n```\n\n```cs\nclass C {\n   void f() {}\n   nameof(f)\n}\n// result \"f\": Member (simple name lookup)\n```\n\n```cs\nclass C {\n   void f() {}\n   nameof(f())\n}\n// result error \"This expression does not have a name\"\n```\n\n```cs\nclass C {\n   void f(){}\n   void f(int i){}\n   nameof(f)\n}\n// result \"f\": Method-group (simple name lookup)\n```\n\n```cs\nCustomer c; ... nameof(c.Age)\n// result \"Age\": Property (member access)\n```\n\n```cs\nCustomer c; ... nameof(c._Age)\n// result error \"_Age is inaccessible due to its protection level: member access\n```\n\n```cs\nnameof(Tuple.Create)\n// result \"Create\": method-group (member access)\n```\n\n```cs\nnameof(System.Tuple)\n// result \"Tuple\": Type (member access). This binds to the non-generic Tuple class; not to all of the Tuple classes.\n```\n\n```cs\nnameof(System.Exception)\n// result \"Exception\": Type (member access)\n```\n\n```cs\nnameof(List<int>)\n// result \"List\": Type (simple name lookup)\n```\n\n```cs\nnameof(List<>)\n// result error \"type expected\": Unbound types are not valid expressions\n```\n\n```cs\nnameof(List<int>.Length)\n// result \"Length\": Member (Member access)\n```\n\n```cs\nnameof(default(List<int>))\n// result error \"This expression doesn't have a name\": Not one of the allowed forms of nameof\n```\n\n```cs\nnameof(default(List<int>).Length)\n// result error \"This expression cannot be used for nameof\": default isn't one of the allowed forms\n```\n\n```cs\nnameof(int)\n// result error \"Invalid expression term 'int'\": Not an expression. Note that 'int' is a keyword, not a name.\n```\n\n```cs\nnameof(System.Int32)\n// result \"Int32\": Type (member access)\n```\n\n```cs\nusing foo=System.Int32;\nnameof(foo) \n// result \"foo\": Type (simple name lookup)\n```\n\n```cs\nnameof(System.Globalization)\n// result \"Globalization\": Namespace (member access)\n```\n\n```cs\nnameof(x[2])\nnameof(\"hello\")\nnameof(1+2)\n// error \"This expression does not have a name\": Not one of the allowed forms of nameof\n```\n\n```vb\nNameOf(a!Foo)\n' error \"This expression does not have a name\": VB-specific. Not one of the allowed forms of NameOf.\n```\n\n```vb\nNameOf(dict(\"Foo\"))\n' error \"This expression does not have a name\": VB-specific. This is a default property access, which is not one of the allowed forms.\n```\n\n```vb\nNameOf(dict.Item(\"Foo\"))\n' error \"This expression does not have a name\": VB-specific. This is an index of a property, which is not one of the allowed forms.\n```\n\n```vb\nNameOf(arr(2))\n' error \"This expression does not have a name\": VB-specific. This is an array element index, which is not one of the allowed forms.\n```\n\n```vb\nDim x = Nothing\nNameOf(x.ToString(2))\n' error \"This expression does not have a name\": VB-specific. This resolves to .ToString()(2), which is not one of the allowed forms.\n```\n\n```vb\nDim o = Nothing\nNameOf(o.Equals)\n' result \"Equals\". Method-group. Warning \"Access of static member of instance; instance will not be evaluated\": VB-specific. VB allows access to static members off instances, but emits a warning.\n```\n\n```cs\n[Foo(nameof(C))]\nclass C {}\n// result \"C\": Nameof works fine in attributes, using the normal name lookup rules.\n```\n\n```cs\n[Foo(nameof(D))]\nclass C { class D {} }\n// result \"D\": Members of a class are in scope for attributes on that class\n```\n\n```cs\n[Foo(nameof(f))]\nclass C { void f() {} }\n// result \"f\": Members of a class are in scope for attributes on that class\n```\n\n```cs\n[Foo(nameof(T))]\nclass C<T> {}\n// result error \"T is not defined\": A class type parameter is not in scope in an attribute on that class\n```\n\n```cs\n[Foo(nameof(T))] void f<T> { }\n// result error \"T not defined\": A method type parameter is not in scope in an attribute on that method\n```\n\n```cs\nvoid f([Attr(nameof(x))] int x) {}\n// result error \"x is not defined\": A parameter is not in scope in an attribute on that parameter, or any parameter in the method\n```\n\n```vb\nFunction f()\n  nameof(f)\nEnd Function\n' result \"f\": VB-specific. This is resolved as an expression which binds to the implicit function return variable\n```\n\n```vb\nNameOf(New)\n' result error \"this expression does not have a name\": VB-specific. Not one of the allowed forms of nameof. Note that New is not a name; it is a keyword used for construction.\n```\n\n```vb\nClass C\n  Dim x As Integer\n  Dim s As String = NameOf(x)\nEnd Class\n' result \"x\": Field (simple name lookup)\n```\n\n```cs\nclass C {\n   int x;\n   string s = nameof(x);\n}\n// result \"x\". Field (simple name lookup)\n```\n\n```cs\nclass C {\n   static int x;\n   string s = nameof(x);\n}\n// result \"x\". Field (simple name lookup)\n```\n\n```cs\nclass C {\n   int x;\n   string s = nameof(C.x);\n}\n// result \"x\". Member (member access)\n```\n\n```cs\nclass C {\n   int x;\n   string s = nameof(default(C).x);\n}\n// result error \"This expression isn't allowed in a nameof argument\" - default.\n```\n\n```cs\nstruct S {\n   int x;\n   S() {var s = nameof(x); ...}\n}\n// result \"x\": Field access (simple name lookup). Nameof argument is considered unreachable, and so this doesn't violate definite assignment.\n```\n\n```cs\nint x; ... nameof(x); x=1;\n// result \"x\": Local access (simple name lookup). Nameof argument is unreachable, and so this doesn't violate definite assignment.\n```\n\n```cs\nint x; nameof(f(ref x));\n// result error \"this expression does not have a name\".\n```\n\n```cs\nvar @int=5; nameof(@int)\n// result \"int\": C#-specific. Local (simple name lookup). The leading @ is removed.\n```\n\n```cs\nnameof(m\\u200c\\u0065)\n// result \"me\": C#-specific. The Unicode escapes are first resolved, and the formatting character \\u200c is removed.\n```\n\n```vb\nDim [Sub]=5 : NameOf([Sub])\n' result \"Sub\": VB-specific. Local (simple name lookup). The surrounding [.] is removed.\n```\n\n```cs\nclass C {\n  class D {}\n  class D<T> {}\n  nameof(C.D)\n}\n// result \"D\" and binds to the non-generic form: member access only finds the type with the matching arity.\n```\n\n```cs\nclass C<T> where T:Exception {\n  ... nameof(C<string>)\n}\n// result error: the type 'string' doesn't satisfy the constraints\n```\n\n# [String Interpolation for C#](http://1drv.ms/1tFUvbq) #\n\nAn *interpolated string* is a way to construct a value of type `String` (or `IFormattable`) by writing the text of the string along with expressions that will fill in \"holes\" in the string. The compiler constructs a format string and a sequence of fill-in values from the interpolated string.\n\nWhen it is treated as a value of type `String`, it is a shorthand for an invocation of\n\n```cs\nString.Format(string format, params object args[])\n```\n\nWhen it is converted to the type `IFormattable`, the result of the string interpolation is an object that stores a compiler-constructed *format string* along with an array storing the evaluated expressions. The object's implementation of\n\n```cs\nIFormattable.ToString(string format, IFormatProvider formatProvider)\n```\n\nis an invocation of\n\n```cs\nString.Format(IFormatProviders provider, String format, params object args[])\n```\n\nBy taking advantage of the conversion from an interpolated string expression to `IFormattable`, the user can cause the formatting to take place later in a selected locale. See the section `System.Runtime.CompilerServices.FormattedString` for details.\n\nNote: the converted interpolated string may have more \"holes\" in the format string than there were interpolated expression holes in the interpolated string. That is because some characters (such as `\"\\{\"` `\"}\"`) may be translated into a hole and a corresponding compiler-generated fill-in.\n\n## Lexical Grammar ##\n\nAn interpolated string is treated initially as a token with the following lexical grammar:\n\n```\ninterpolated-string:\n    $ \" \"\n    $ \" interpolated-string-literal-characters \"\n\ninterpolated-string-literal-characters:\n    interpolated-string-literal-part interpolated-string-literal-parts\n    interpolated-string-literal-part\n\ninterpolated-string-literal-part:\n    single-interpolated-string-literal-character\n    simple-escape-sequence\n    hexadecimal-escape-sequence\n    unicode-escape-sequence\n    interpolation\n\nsimple-escape-sequence:  one of\n    \\'  \\\"  \\\\  \\0  \\a  \\b  \\f  \\n  \\r  \\t  \\v  \\{  \\}\n\nsingle-interpolated-string-literal-character:\n    Any character except \" (U+0022), \\ (U+005C), { (U+007B) and new-line-character\n\ninterpolation:\n    { interpolation-contents }\n\ninterpolation-contents:\n    balanced-text\n    balanced-text : interpolation-format\n\nbalanced-text:\n    balanced-text-part\n    balanced-text-part balanced-text\n\nbalanced-text-part\n    Any character except \", (, [, {, /, \\ and new-line-character\n    ( balanced-text )\n    { balanced-text }\n    [ balanced-text ]\n    regular-string-literal\n    delimited-comment\n    unicode-escape-sequence\n    / after-slash\n\nafter-slash\n    Any character except \", (, [, {, /, \\, * and new-line-character\n    ( balanced-text )\n    { balanced-text }\n    [ balanced-text ]\n    regular-string-literal\n    * delimited-comment-text[opt] asterisks /\n    unicode-escape-sequence\n\ninterpolation-format:\n    regular-string-literal\n    literal-interpolation-format\n\nliteral-interpolation-format:\n    interpolation-format-part\n    interpolation-format-part literal-interpolation-format\n\ninterpolation-format-part\n    Any character except \", :, \\, } and new-line-character\n```\n\nWith the additional restriction that a *delimited-comment-text* that is a *balanced-text-part* may not contain a *new-line-character*.\n\nThis lexical grammar is ambiguous in that it allows a colon appearing in *interpolation-contents* to be considered part of the *balanced-text*, or as the separator between the *balanced-text* and the *interpolation-format*. This ambiguity is resolved by considering it to be a separator between the *balanced-text* and *interpolation-format*.\n\n## Syntactic Grammar ##\n\nAn *interpolated-string* token is reclassified, and portions of it are reprocessed lexically and syntactically, during syntactic analysis as follows:\n\n- If the *interpolated-string* contains no *interpolation*, then it is reclassified as a *regular-string-literal*.\n- Otherwise\n  - the portion of the *interpolated-string* before the first *interpolation* is reclassified as an *interpolated-string-start* terminal;\n  - the portion of the *interpolated-string* after the last *interpolation* is reclassified as an *interpolated-string-end* terminal;\n  - the portion of the *interpolated-string* between one *interpolation* and another *interpolation* is reclassified as an *interpolated-string-mid* terminal;\n  - the *balanced-text* of each *interpolation-contents* is reprocessed according to the language's lexical grammar, yielding a sequence of terminals;\n  - the colon in each *interpolation-contents* that contains an *interpolation-format* is classified as a colon terminal;\n  - each *interpolation-format* is reclassified as a *regular-string-literal* terminal; and\n  - the resulting sequence of terminals undergoes syntactic analysis as an *interpolated-string-expression*.\n\n```\nexpression:\n    interpolated-string-expression\n\ninterpolated-string-expression:\n    interpolated-string-start interpolations interpolated-string-end\n\ninterpolations:\n    single-interpolation\n    single-interpolation interpolated-string-mid interpolations\n\nsingle-interpolation:\n    interpolation-start\n    interpolation-start : regular-string-literal\n\ninterpolation-start:\n    expression\n    expression , expression\n```\n\n## Semantics ##\n\nAn *interpolated-string-expression* has type `string`, but there is an implicit *conversion from expression* from an *interpolated-string-expression* to the type `System.IFormattable`. By the existing rules of the language (7.5.3.3 Better conversion from expression), the conversion to `string` is a better conversion from expression.\n\nAn *interpolated-string-expression* is translated into an intermediate *format string* and *object array* which capture the contents of the interpolated string using the semantics of [Composite Formatting](http://msdn.microsoft.com/en-us/library/txafckwd(v=vs.110).aspx \"Composite Formatting\"). If treated as a value of type `string`, the formatting is performed using `string.Format(string format, params object[] args)` or equivalent code. If it is converted to `System.IFormattable`, an object of type [`System.Runtime.CompilerServices.FormattedString`](#FormattedString) is constructed using the format string and argument array, and that object is the value of the *interpolated-string-expression*.\n\nThe format string is constructed of the literal portions of the *interpolated-string-start*, *interpolated-string-mid*, and *interpolated-string-end* portions of the expression, with special treatment for `{` and `}` characters (see [Notes](#Notes)).\n\n**The evaluation order needs to be specified**.\n\n**The definite assignment rules need to be specified**.\n\n## single-interpolation Semantics ##\n\n**This section should describe in detail the construction of a [*format item*](http://msdn.microsoft.com/en-us/library/txafckwd(v=vs.110).aspx) from a single-interpolation, and the corresponding element of the object array**.\n\nIf an *interpolation-start* has a comma and a second expression, the second expression must evaluate to a compile-time constant of type `int`, which is used as the [*alignment* of a *format item*](http://msdn.microsoft.com/en-us/library/txafckwd(v=vs.110).aspx).\n\nIf a *single-interpolation* has a colon and a *regular-string-literal*, then the string literal is used as the [*formatString* of a *format item*](http://msdn.microsoft.com/en-us/library/txafckwd(v=vs.110).aspx).\n\n## Notes ##\n\nThe compiler is free to translate an interpolated string into a format string and object array where the number of objects in the object array is not the same as the number of interpolations in the *interpolated-string-expression*. In particular, the compiler may translate `{` and `}` characters into a fill-in in the format string and a corresponding string literal containing the character. For example, the interpolated string `$\"\\{ {n} \\}\"` may be translated to `String.Format(\"{0} {1} {2}\", \"{\", n, \"}\")`.\n\nThe compiler is free to use any overload of `String.Format` in the translated code, as long as doing so preserves the semantics of calling `string.Format(string format, params object[] args)`.\n\n## Examples ##\n\nThe interpolated string\n```\n$\"{hello}, {world}!\"\n```\nis translated to\n```\nString.Format(\"{0}, {1}!\", hello, world)\n```\n\nThe interpolated string\n```\n$\"Name = {myName}, hours = {DateTime.Now:hh}\"\n```\nis translated to\n```\nString.Format(\"Name = {0}, hours = {1:hh}\", myName, DateTime.Now)\n```\n\nThe interpolated string\n```\n$\"\\{{6234:D}\\}\"\n```\nis translated to\n```\nString.Format(\"{0}{1:D}{2}\", \"{\", 6234, \"}\")\n```\n\nFor example, if you want to format something in the invariant locale, you can do so using this helper method\n\n```cs\npublic static string INV(IFormattable formattable)\n{\n    return formattable.ToString(null, System.Globalization.CultureInfo.InvariantCulture);\n}\n```\n\nand writing your interpolated strings this way\n\n```cs\n   string coordinates = INV(\"longitude={longitude}; latitude={latitude}\");\n```\n\n## System.Runtime.CompilerServices.FormattedString ##\n\nThe following platform class is used to translate an interpolated string to the type `System.IFormattable`.\n\n```cs\nnamespace System.Runtime.CompilerServices \n{ \n    public class FormattedString : System.IFormattable \n    {\n        private readonly String format;\n        private readonly object[] args;\n        public FormattedString(String format, params object[] args)\n        {\n            this.format = format;\n            this.args = args;\n        }\n        string IFormattable.ToString(string ignored, IFormatProvider formatProvider)\n        {\n            return String.Format(formatProvider, format, args);\n        }\n    } \n} \n```\n\n## Issues ##\n\n1. As specified, an interpolated string with no interpolations cannot be converted to `IFormattable` because it is a string literal. It should have such a conversion.\n\n"
  },
  {
    "path": "meetings/2014/README.md",
    "content": "# C# Language Design Notes for 2014\n\nOverview of meetings and agendas for 2014\n\n## Jan 6, 2014\n\n[C# Language Design Notes for Jan 6, 2014](LDM-2014-01-06.md)\n\n1.\tSyntactic ambiguities with declaration expressions <_a solution adopted_>\n2.\tScopes for declaration expressions <_more refinement added to rules_>\n\n## Feb 3, 2014\n\n[C# Language Design Notes for Feb 3, 2014](LDM-2014-02-03.md)\n\n1.  Capture of primary constructor parameters <_only when explicitly asked for with new syntax_>\n2.  Grammar around indexed names <_details settled_>\n3.  Null-propagating operator details <_allow indexing, bail with unconstrained generics_>\n\n\n## Feb 10, 2014\n\n[C# Language Design Notes for Feb 10, 2014](LDM-2014-02-10.md)\n\n1.\tDesign of using static <_design adopted_>\n2.\tInitializers in structs <_allow in certain situations_>\n3.\tNull-propagation and unconstrained generics <_keep current design_>\n\n\n## Apr 21, 2014\n\n[C# Language Design Notes for Apr 21, 2014](LDM-2014-04-21.md)\n\n1.\tIndexed members <_lukewarm response, feature withdrawn_>\n2.\tInitializer scope <_new scope solves all kinds of problems with initialization_>\n3.\tPrimary constructor bodies <_added syntax for a primary constructor body_>\n4.\tAssignment to getter-only auto-properties from constructors <_added_>\n5.\tSeparate accessibility for type and primary constructor <_not worthy of new syntax_>\n6.\tSeparate doc comments for field parameters and fields <_not worthy of new syntax_>\n7.\tLeft associative vs short circuiting null propagation <_short circuiting_>\n\n\n## May 7, 2014\n\n[C# Language Design Notes for May 7, 2014](LDM-2014-05-07.md)\n\n1.\tprotected and internal <_feature cut – not worth the confusion_>\n2.\tField parameters in primary constructors <_feature cut – we want to keep the design space open_>\n3.\tProperty declarations in primary constructors <_interesting but not now_>\n4.\tTypeswitch <_Not now – more likely as part of a future more general matching feature_>\n\n\n## May 21, 2014\n\n[C# Language Design Notes for May 21, 2014](LDM-2014-05-21.md)\n\n1.\tLimit the nameof feature? <_keep current design_>\n2.\tExtend params IEnumerable? <_keep current design_>\n3.\tString interpolation <_design nailed down_>\n\n\n## Jul 9, 2014\n\n[C# Language Design Notes for Jul 9, 2014](LDM-2014-07-09.md)\n\n1.\tDetailed design of nameof <_details settled_>\n2.\tDesign of #pragma warning extensions <_allow identifiers_>\n\n\n## Aug 27, 2014\n\n[C# Language Design Notes for Aug 27, 2014](LDM-2014-08-27.md)\n\n1.\tAllowing parameterless constructors in structs <_allow, but some unresolved details_>\n2.\tDefinite assignment for imported structs <_revert to Dev12 behavior_>\n\n\n## Sep 3, 2014\n\n[C# Language Design Notes for Sep 3, 2014](LDM-2014-09-03.md)\n\n1.\tRemoving “spill out” from declaration expressions in simple statements <_yes, remove_>\n2.\tSame name declared in subsequent else-if’s <_condition decls out of scope in else-branch_>\n3.\tAdd semicolon expressions <_not in this version_>\n4.\tMake variables in declaration expressions readonly <_no_>\n\n## Oct 1, 2014\n\n[C# Language Design Notes for Oct 1, 2014](LDM-2014-10-01.md)\n\n1. Assignment to readonly autoprops in constructors (we fleshed out details)\n2. A new compiler warning to prevent outsiders from implementing your interface? (no, leave this to analyzers)\n\n\n## Oct 15, 2014\n\n[C# Language Design Notes for Oct 15, 2014](LDM-2014-10-15.md)\n\n1. nameof operator: spec v5\n2. [String Interpolation for C#](http://1drv.ms/1tFUvbq)\n"
  },
  {
    "path": "meetings/2015/LDM-2015-01-21.md",
    "content": "C# Design Meeting Notes for Jan 21, 2015\n========================================\n\nDiscussion thread on these notes can be found at https://github.com/dotnet/roslyn/issues/98.\n\nQuotes of the day: \n\n> Live broadcast of design meetings: we could call it C#-SPAN\n>\n> We've made it three hours without slippery slopes coming up!\n\n\nAgenda\n------\n\nThis is the first design meeting for the version of C# coming after C# 6. We shall colloquially refer to it as C# 7. The meeting focused on setting the stage for the design process and homing in on major themes and features.\n\n1. Design process\n2. Themes\n3. Features\n\nSee also [Language features currently under consideration by the language design group](https://github.com/dotnet/roslyn/issues?q=is%3Aopen+label%3A%22Area-Language+Design%22+label%3A%221+-+Planning%22+ \"Language Features Under Consideration\").\n\n1\\. Design process\n==================\n\nWe have had great success sharing design notes publicly on CodePlex for the last year of C# 6 design. The ability of the community to see and respond to our thinking in real time has been much appreciated.\n\nThis time we want to increase the openness further:\n\n- we involve the community from the beginning of the design cycle (as per these notes!)\n- in addition to design notes (now issues on GitHub) we will maintain feature proposals (as checked-in Markdown documents) to reflect the current design of the feature\n- we will consider publishing recordings of the design meetings themselves, or even live streaming\n- we will consider adding non-Microsoft members to the design team.\n\nDesign team\n-----------\n\nThe C# 7 design team currently consists of\n\n- [Anders Hejlsberg](https://github.com/ahejlsberg)\n- [Mads Torgersen](https://github.com/MadsTorgersen)\n- [Lucian Wischik](https://github.com/ljw1004)\n- [Matt Warren](https://github.com/mattwar)\n- [Neal Gafter](https://github.com/gafter)\n- [Anthony D. Green](https://github.com/AnthonyDGreen)\n- [Stephen Toub](https://github.com/stephentoub)\n- [Kevin Pilch-Bisson](https://github.com/Pilchie)\n- [Vance Morrison](https://github.com/vancem)\n- [Immo Landwerth](https://github.com/terrajobst)\n\nAnders, as the chief language architect, has ultimate say, should that ever become necessary. Mads, as the language PM for C#, pulls together the agenda, runs the meetings and takes the notes. (Oooh, the power!)\n\nTo begin with, we meet 4 hours a week as we decide on the overall focus areas. There will not be a separate Visual Basic design meeting during this initial period, as many of the overall decisions are likely to apply to both and need to happen in concert. \n\nFeature ideas\n-------------\n\nAnyone can put a feature idea up as an *issue* on GitHub. We'll keep an eye on those, and use them as input to language design.\n\nA way to gauge interest in a feature is to put it up on UserVoice, where there's a voting system. This is important, because the set of people who hang out in our GitHub repo are not necessarily representative of our developer base at large. \n\nDesign notes\n------------\n\nDesign notes are point-in-time documents, so we will put them up as *issues* on GitHub. For a period of time, folks can comment on them and the  reactions will feed into subsequent meetings.\n\nOwners and proposals\n--------------------\n\nIf the design team decides to move on with a feature idea, we'll nominate an *owner* for it, typically among the design team members, who will drive the activities related to the design of that feature: gathering feedback, making progress between meetings, etc. Most importantly, the owner will be responsible for maintaining a *proposal* document that describes the current state of that feature, cross-linking with the design notes where it was discussed.\n\nSince the proposals will evolve over time, they should be documents in the repo, with history tracked. When the proposal is first put up, and if there are major revisions, we will probably put up an issue too, as a place to gather comments. There can also be pull requests to the proposals.\n\nWe'll play with this process and find a balance.\n\nOther ways of increasing openness\n---------------------------------\n\nWe are very interested in other ideas, such as publishing recordings (or even live streaming?) of the design meeting themselves, and inviting non-Microsoft luminaries, e.g., from major players in the industry, onto the design team itself. We are certainly open to have \"guests\" (physical or virtual) when someone has insights that we want to leverage.\n\nHowever, these are things we can get to over time. We are not going to do them right out of the gate.\n\nDecisions\n---------\n\nIt's important to note that the C# design team is still in charge of the language. This is not a democratic process. We derive immense value from comments and UserVoice votes, but in the end the governance model for C# is benevolent dictatorship. We think design in a small close-knit group where membership is long-term is the right model for ensuring that C# remains tasteful, consistent, not too big and generally not \"designed by committee\".\n\nIf we don't agree within the design team, that is typically a sign that there are offline activities that can lead to more insight. Usually, at the end of the day, we don't need to vote or have the Language Allfather make a final call.\n\nPrototypes\n----------\n\nIdeally we should prototype every feature we discuss, so as to get a good feel fro the feature and allow the best possible feedback from the community. That may note be realistic, but once we have a good candidate feature, we should try to fly it.\n\nThe cost of the prototyping is an issue. This may be feature dependent: Sometimes you want a quick throwaway prototype, sometimes it's more the first version of an actual implementation.\n\nCould be done by a member of the design team, the product team or the community.\n\nAgenda\n------\n \nIt's usually up to Mads to decide what's ready to discuss. Generally, if a design team member wants something on the agenda, they get it. There's no guarantee that we end up following the plan in the meeting; the published notes will just show the agenda as a summary of what was *actually* discussed.\n\n\n2\\. Themes\n==========\n\nIf a feature is great, we'll want to add it whether it fits in a theme or not. However, it's useful to have a number of categories that we can rally around, and that can help select features that work well together.\n\nWe discussed a number of likely themes to investigate for C# 7.\n\nWorking with data\n-----------------\n\nToday’s programs are connected and trade in rich, structured data: it’s what’s on the wire, it’s what apps and services produce, manipulate and consume. \n\nTraditional object-oriented modeling is good for many things, but in many ways it deals rather poorly with this setup: it bunches functionality strongly with the data (through encapsulation), and often relies heavily on mutation of that state. It is \"behavior-centric\" instead of \"data-centric\".\n\nFunctional programming languages are often better set up for this: data is immutable (representing *information*, not *state*), and is manipulated from the outside, using a freely growable and context-dependent set of functions, rather than a fixed set of built-in virtual methods. Let’s continue being inspired by functional languages, and in particular other languages – F#, Scala, Swift – that aim to mix functional and object-oriented concepts as smoothly as possible.\n\nHere are some possible C# features that belong under this theme:\n\n- pattern matching\n- tuples\n- \"denotable\" anonymous types\n- \"records\" - compact ways of describing shapes\n- working with common data structures (List/Dictionary)\n- extension members\n- slicing\n- immutability\n- structural typing/shapes?\n    \nA number of these features focus on the interplay between \"kinds of types\" and the ways they are used. It is worth thinking of this as a matrix, that lets you think about language support for e.g. denoting the types (*type expressions*), creating values of them (*literals*) and consuming them with matching (*patterns*) :\n\n| Type       | Denote                  | Create                       | Match                    |\n|------------|-------------------------|------------------------------|--------------------------|\n| General    | `T`                     | `new T()`, `new T { x = e }` | `T x`, `var x`, `*`      |\n| Primitive  | `int`, `double`, `bool` | `5`, `.234`, `false`         | `5`, `.234`, `false`     |\n| String     | `string`                | `\"Hello\"`                    | `\"Hello\"`                |\n| Tuple      | `(T1, T2)`              | `(e1, e2)`                   | `(P1, P2)`               |\n| Record     | `{ T1 x1, T2 x2 }`      | `new { x1 = e1, x2 = e2 }`   | `{ x1 is P1, x2 is P2 }` |  \n| Array      | `T[]`                   | `new T[e]`, `{ e1, e2 }`     | `{ P1, P2 }`, `P1 :: P2` |\n| List       | ?                       | ?                            | ?                        |\n| Dictionary | ?                       | ?                            | ?                        |\n| ...        |                         |                              |                          |\n\n\nA lot of the matrix above is filled in with speculative syntax, just to give an idea of how it could be used.\n\nWe expect to give many of the features on the list above a lot of attention over the coming months: they have a lot of potential for synergy if they are designed together.\n\nPerformance and reliability (and interop)\n-----------------------------------------\n\nC# and .NET has a heritage where it sometimes plays a bit fast and loose with both performance and reliability. \n\nWhile (unlike, say, Java) it has structs and reified generics, there are still places where it is hard to get good performance. A top issue, for instance is the frequent need to copy, rather than reference. When devices are small and cloud compute cycles come with a cost, performance certainly starts to matter more than it used to.\n\nOn the reliability side, while (unlike, say, C and C++) C# is generally memory safe, there are certainly places where it is hard to control or trust exactly what is going on (e.g., destruction/finalization).\n\nMany of these issues tend to show up in particular on the boundary to unmanaged code - i.e. when doing interop. Having coarse-grained interop isn't always an option, so the less it costs and the less risky it is to cross the boundary, the better.\n\nInternally at Microsoft there have been research projects to investigate options here. Some of the outcomes are now ripe to feed into the design of C# itself, while others can affect the .NET Framework, result in useful Roslyn analyzers, etc.\n\nOver the coming months we will take several of these problems and ideas and see if we can find great ways of putting them in the hands of C# developers.\n\nComponentization\n----------------\n\nThe once set-in-stone issue of how .NET programs are factored and combined is now under rapid evolution.\n\nWith generalized extension members as an exception, most work here may not fall in the language scope, but is more tooling-oriented:\n\n- generating reference assemblies\n- static linking instead of IL merge\n- determinism\n- NuGet support\n- versioning and adaptive light-up\n\nThis is a theme that shouldn't be driven primarily from the languages, but we should be open to support at the language level.\n\nDistribution\n------------\n\nThere may be interesting things we can do specifically to help with the distributed nature of modern computing.\n\n- Async sequences: We introduced single-value asynchrony in C# 5, but do not yet have a satisfactory approach to asynchronous sequences or streams\n- Serialization: we may no longer be into directly providing built-in serialization, but we need to make sure we make it reasonable to custom-serialize data - even when it's immutable, and without requiring costly reflection.\n\nAlso, await in catch and finally probably didn't make it into VB 14. We should add those the next time around.\n\nMetaprogramming\n---------------\n\nMetaprogramming has been around as a theme on the radar for a long time, and arguably Roslyn is a big metaprogramming project aimed at writing programs about programs. However, at the language level we continue not to have a particularly good handle on metaprogramming. \n\nExtension methods and partial classes both feel like features that could grow into allowing *generated* parts of source code to merge smoothly with *hand-written* parts. But if generated parts are themselves the result of language syntax - e.g. attributes in source code, then things quickly get messy from a tooling perspective. A keystroke in file A may cause different code to be generated into file B by some custom program, which in turn may change the meaning of A. Not a feedback loop we're eager to have to handle in real time at 20 ms keystroke speed!\n\nOftentimes the eagerness to generate source comes from it being too hard to express your concept beautifully as a library or an abstraction. Increasing the power of abstraction mechanisms in the language itself, or just the syntax for applying them, might remove a lot of the motivation for generated boilerplate code.\n\nFeatures that may reduce the need for boilerplate and codegen:\n\n- Virtual extension methods/default interface implementations\n- Improvements to generic constraints, e.g.:\n    - generic constructor constraints\n    - delegate and enum constraints\n    - operators or object shapes as constraints (or interfaces), e.g. similar to C++ concepts\n- mixins or traits\n- delegation\n\nNull\n----\n\nWith null-conditional operators such as `x?.y` C# 6 starts down a path of more null-tolerant operations. You could certainly imagine taking that further to allow e.g. awaiting or foreach'ing null, etc.\n\nOn top of that, there's a long-standing request for non-nullable reference types, where the type system helps you ensure that a value can't be null, and therefore is safe to access.\n\nImportantly such a feature might go along well with proper safe *nullable* reference types, where you simply cannot access the members until you've checked for null. This would go great with pattern matching!\n\nOf course that'd be a lot of new expressiveness, and we'd have to reconcile a lot of things to keep it compatible. In his [blog](http://blog.coverity.com/2013/11/20/c-non-nullable-reference-types), Eric Lippert mentions a number of reasons why non-nullable reference types would be next to impossible to fully guarantee. To be fully supported, they would also have to be known to the runtime; they couldn't just be handled by the compiler.\n\nOf course we could try to settle for a less ambitious approach. Finding the right balance here is crucial.\n\nThemeless in Seattle\n--------------------\n\n*Type providers*: This is a whole different kind of language feature, currently known only from F#. We wouldn't be able to just grab F#'s model though; there'd be a whole lot of design work to get this one right!\n\n*Better better betterness*: In C# we made some simplifications and generalizations to overload resolution, affectionately known as \"better betterness\". We could think of more ways to improve overload resolution; e.g. tie breaking on staticness or whether constraints match, instead of giving compiler errors when other candidates would work.\n\n*Scripting*: The scripting dialect of C# includes features not currently allowed in C# \"proper\": statements and member declarations at the top level. We could consider adopting some of them.\n\n*params IEnumerable*.\n\n*Binary literals and digit separators*.\n\n\n\n3\\. Features\n============\n\nThe Matrix above represents a feature set that's strongly connected, and should probably be talked about together: we can add kinds of types (e.g. tuples, records), we can add syntax for representing those types or creating instances of them, and we can add ways to match them as part of a greater pattern matching scheme.\n\nPattern matching\n----------------\n\nCore then is to have a pattern matching framework in the language: A way of asking if a piece of data has a particular shape, and if so, extracting pieces of it.\n\n``` c#\nif (o is Point(var x, 5)) ...\n```\n\nThere are probably at least two ways you want to use \"patterns\":\n\n1. As part of an expression, where the result is a bool signaling whether the pattern matched a given value, and where variables in the pattern are in scope throughout the statement in which the pattern occurs.\n2. As a case in a switch statement, where the case is picked if the pattern matches, and the variables in the pattern are in scope throughout the statements of that case.\n\nA strong candidate syntax for the expression syntax is a generalization of the `is` expression: we consider the type in an `is` expression just a special case, and start allowing any pattern on the right hand side. Thus, the following would be valid `is` expressions:\n\n``` c#\nif (o is Point(*, 5) p) Console.WriteLine(o.x);\nif (o is Point p) Console.WriteLine(p.x);\nif (p is (var x, 5) ...\n```\n\nVariable declarations in an expression would have the same scope questions as declaration expressions did. \n\nA strong candidate for the switch syntax is to simply generalize current switch statements so that\n\n- the switch expression can be any type\n- the case labels can contain patterns, not just constants\n- the cases are checked in order of appearance, since they can now overlap\n\n``` c#\nswitch (o) {\ncase string s:\n    Console.WriteLine(s);\n    break;\ncase int i:\n    Console.WriteLine($\"Number {i}\");\n    break;\ncase Point(int x, int y):\n    Console.WriteLine(\"({x},{y})\");\n    break;\ncase null:\n    Console.WriteLine(\"<null>);\n    break\n}\n```\n\nOther syntaxes you can think of:\n\n*Expression-based switch*: An expression form where you can have multiple cases, each producing a result value of the same type.\n\n*Unconditional deconstruction*: It might be useful to separate the deconstruction functionality out from the checking, and be able to unconditionally extract parts from a value that you know the type of:\n\n``` c#\n(var x, var y) = getPoint();\n```\n\nThere is a potential issue here where the value could be null, and there's no check for it. It's probably ok to have a null reference exception in this case.\n\nIt would be a design goal to have symmetry between construction and deconstruction syntaxes. \n\nPatterns *at least* have type testing, value comparison and deconstruction aspects to them.\n\nThere may be ways for a type to specify its deconstruction syntax.\n\nIn addition it is worth considering something along the lines of \"active patterns\", where a type can specify logic to determine whether a pattern applies to it or not.\n\nImagine positional deconstruction or active patterns could be expressed with certain methods:\n\n``` c#\nclass Point {\n    public Point(int x, int y) {...}\n    void Deconstruct(out int x, out int y) { ... }\n    static bool Match(Point p, out int x, out int y) ...\n    static bool Match(JObject json, out int x, out int y) ...\n}\n```\n\nWe could imagine separate syntax for specifying this.\n\nOne pattern that does not put new requirements on the type is matching against properties/fields:\n\n``` c#\nif (o is Point { X is var x, Y is 0 }) ...\n```\n\nOpen question: are the variables from patterns mutable?\n\nThis has a strong similarity to declaration expressions, and they could coexist, with shared scope rules.\n\nRecords\n-------\n\nLet's not go deep on records now, but we are aware that we need to reconcile them with primary constructors, as well as with pattern matching.\n\nArray Slices\n------------\n\nOne feature that could lead to a lot of efficiency would be the ability to have \"windows\" into arrays - or even onto unmanaged swaths of memory passed along through interop. The amount of copying that could be avoided in some scenarios is probably very significant.\n\nArray slices represent an interesting design dilemma between performance and usability. There is nothing about an array slice that is functionally different from an array: You can get its length and access its elements. For all intents and purposes they are indistinguishable. So the best user experience would certainly be that slices just *are* arrays - that they share the same type. That way, all the existing code that operates on arrays can work on slices too, without modification.\n\nOf course this would require quite a change to the runtime. The performance consequences of that could be negative even on the existing kind of arrays. As importantly, slices themselves would be more efficiently represented by a struct type, and for high-perf scenarios, having to allocate a heap object for them might be prohibitive.\n\nOne intermediate approach might be to have slices be a struct type Slice\\<T>, but to let it implicitly convert to T[] in such a way that the underlying storage is still shared. That way you can use Slice\\<T> for high performance slice manipulation (e.g. in recursive algorithms where you keep subdividing), but still make use of existing array-based APIs at the cost of a boxing-like conversion allocating a small object.\n\nref locals and ref returns\n--------------------------\n\nJust like the language today has ref parameters, we could allow locals and even return values to be by `ref`. This would be particularly useful for interop scenarios, but could in general help avoid copying. Essentially you could return a \"safe pointer\" e.g. to a slot in an array.\n\nThe runtime already fully allows this, so it would just be a matter of surfacing it in the language syntax. It may come with a significant conceptual burden, however. If a method call can return a *variable* as opposed to a *value*, does that mean you can now assign to it?:\n\n``` c#\nm(x, y) = 5;\n```\n\nYou can now imagine getter-only properties or indexers returning refs that can be assigned to. Would this be quite confusing?\n\nThere would probably need to be some pretty restrictive guidelines about how and why this is used.\n\nreadonly parameters and locals\n------------------------------\n\nParameters and locals can be captured by lambdas and thereby accessed concurrently, but there's no way to protect them from shared-mutual-state issues: they can't be readonly.\n\nIn general, most parameters and many locals are never intended to be assigned to after they get their initial value. Allowing `readonly` on them would express that intent clearly.\n\nOne problem is that this feature might be an \"attractive nuisance\". Whereas the \"right thing\" to do would nearly always be to make parameters and locals readonly, it would clutter the code significantly to do so.\n\nAn idea to partly alleviate this is to allow the combination `readonly var` on a local variable to be contracted to `val` or something short like that. More generally we could try to simply think of a shorter keyword than the established `readonly` to express the readonly-ness.\n\nLambda capture lists\n--------------------\n\nLambda expressions can refer to enclosing variables:\n\n``` c#\nvar name = GetName();\nvar query = customers.Where(c => c.Name == name);\n```\n\nThis has a number of consequences, all transparent to the developer:\n- the local variable is lifted to a field in a heap-allocated object\n- concurrent runs of the lambda may access and even modify the field at the same time\n- because of implementation tradeoffs the content of the variable may be kept live by the GC, sometimes even after lambdas directly using them cease to exist.\n\nFor these reasons, the recently introduced lambdas in C++ offer the possibility for a lambda to explicitly specify what can be captured (and how). We could consider a similar feature, e.g.:\n\n``` c#\nvar name = GetName();\nvar query = customers.Where([name]c => c.Name == name);\n```\nThis ensures that the lambda only captures `name` and no other variable. In a way the most useful annotation would be the empty `[]`, making sure that the lambda is never accidentally modified to capture *anything*.\n\nOne problem is that it frankly looks horrible. There are probably other syntaxes we could consider. Indeed we need to think about the possibility that we would ever add nested functions or class declarations: whatever capture specification syntax we come up with would have to also work for them.\n\nC# always captures \"by reference\": the lambda can observe and effect changes to the original variable. An option with capture lists would be to allow other modes of capture, notable \"by value\", where the variable is copied rather than lifted:\n``` c#\nvar name = GetName();\nvar query = customers.Where([val name]c => c.Name == name);\n```\nThis might not be *too* useful, as it has the same effect as introducing another local initialized to the value of the original one, and then capture *that* instead.\n\nIf we don't want capture list as a full-blown feature, we could consider allowing attributes on lambdas and then having a Roslyn analyzer check that the capture is as specified.\n\nMethod contracts\n----------------\n\n.NET already has a contract system, that allows annotation of methods with pre- and post-conditions. It grew out of the Spec# research project, and requires post-compile IL rewriting to take full effect. Because it has no language syntax, specifying the contracts can get pretty ugly.\n\nIt has often been proposed that we should add specific contract syntax:\n``` c#\npublic void Remove(string item)\n    requires item != null\n    ensures Count >= 0\n{\n   ...\n}\n\n```\n\nOne radical idea is for these contracts to be purely runtime enforced: they would simply turn into checks throwing exceptions (or FailFast'ing - an approach that would need further discussion, but seems very attractive).\n\nWhen you think about how much code is currently occupied with arguments and result checking, this certainly seems like an attractive way to reduce code bloat and improve readability.\n\nFurthermore, the contracts can produce metadata that can be picked up and displayed by tools.\n\nYou could imagine dedicated syntax for common cases - notably null checks. Maybe that is the way we get some non-nullability into the system?\n\n"
  },
  {
    "path": "meetings/2015/LDM-2015-01-28.md",
    "content": "C# Design Meeting Notes for Jan 28, 2015\n========================================\n\nDiscussion thread for these notes can be found at https://github.com/dotnet/roslyn/issues/180.\n\nQuote of the day: \n\n> It's not turtles all the way down, it's frogs. :-)\n\nAgenda\n------\n\n1. Immutable types\n2. Safe fixed-size buffers\n3. Pattern matching\n4. Records\n\nSee also [Language features currently under consideration by the language design group](https://github.com/dotnet/roslyn/issues?q=is%3Aopen+label%3A%22Area-Language+Design%22+label%3A%221+-+Planning%22+ \"Language Features Under Consideration\").\n\n1\\. Immutable types\n===================\n\nIn research prototypes we've experimented with an `immutable` modifier on types, indicating that objects of the type are *deeply* immutable - they recursively do not point to mutable fields. Issue #159 describes the proposal in more detail.\n\nHow do we construct types which once fully constructed can't be changed? \n\n- all fields are readonly, and  recursively have immutable types\n- can only inherit from other immutable types (or `object`)\n- the constructor can't use \"this\" other than to access fields\n\n`unsafe` or some other notation could be used to escape scrutiny, in order to create \"observable immutability\" while cheating under the hood (typically for performance reasons). You could factor such unsafeness into a few types, e.g. `Lazy<T>`.\n\nThe feature is designed to work with generics. There would be a new constraint `where T: immutable`. However don't want to bifurcate on `Tuple<T>` vs `ImmutableTuple<T>` just based on whether the content type is constrained to `immutable`. \n\nInstead an immutable `Tuple<T>` would instantiate to immutable types *only* if type arguments are all immutable. So `Tuple<int>` would be immutable, `Tuple<StringBuilder>` wouldn't be. Immutable generic types would allow type parameters in fields, because that still maintains the recursive guarantee.\n\nImmutable interfaces are also part of the proposal. Somewhat strangely an immutable interface can only be implemented by types that pass all their non-immutable type parameters to the interface!\n\nWhat's the value? It's mostly a tool for the compiler to help you ensure you are following your intent of writing deeply immutable types. \n\nWhy is that a valuable property to ensure in objects?\n- it would allow safe parallel operations over them (modulo holes, see below)\n- it would allow burning an object graph into the DLL by compile time evaluation of static initializers\n- they can be passed to others without defensive copying\n\nImmutable delegates are ones that can only bind to methods on immutable types. At the language level, that means closures would need to be generated as immutable when possible - which it won't often be, unless we adopt readonly parameters and locals (#98, #115).\n\nAs for choice of keyword: `readonly` indicates \"shallow\", that's why `immutable` may be a better word.\n\nGiven the restrictions, you'd expect that any method call on an immutable type would have side effects only on data that was passed in to the method - so a parameterless method (or one taking only immutable parameters) would essentially be pure.\n\nUnfortunately that is not quite true. This expectation can be undermined by two things (other than the built-in facility for cheating): mutable static fields and reflection. We can probably live with reflection, that's already a way to undermine so many other language level expectations! However, mutable statics are unfortunate, not just for this scenario but in general. It would be a breaking change to start disallowing them, of course, bu they could be prevented with a Roslyn analyzer.\n\nEven then, while not having side effects, calling such a method twice with the same arguments might not yield the same result: even returning a new object isn't idempotent.\n\nGiven the holes and gotchas, the question is whether it is still valuable enough to have this feature? If it's not a full guarantee but mostly a help to not make mistakes, maybe we should do this through attributes and analyzers? The problem with analyzers is that you can't rely on other folks to run them on their code that you depend on. It wouldn't e.g. prevent defensive copies.\n\nIn our research project, this turned out to be very valuable in detecting bugs and missed optimization opportunities.\n\nThe object freezing could be done without the feature just by carefully analyzing static fields. But the feature might better help people structure things to be ripe for it.\n\nIDE tooling benefits: Extract method would not need to grab all structs by ref.\n\nWe would have to consider making it impossible to implement an immutable interface even via the old compiler. Otherwise there's a hole in the system. Something with \"modrec\"?\n\nIf we added a bunch of features that introduce readonly objects to C# 7 (like records, tuples, ...) and then add this feature later, would we end up being in trouble? Only if we violated the rules we would end up applying.\n\nMarking an existing unsealed type as immutable would be a breaking change. If we introduce such classes in C# 7, it would be breaking to make them immutable later.\n\nAs a case study, has Roslyn suffered from the lack of this feature? There have been race conditions, but those would still have happened. Is Roslyn not a great example?\n\nProbably not. Roslyn is *not* immutable. It's presenting an immutable *view*, but is mutable inside. Would that be the common case, though? \n\nSome of the \"cheating\" in Roslyn (caching, free lists, etc) is for performance, some is for representing cycles. Insofar as the immutable types feature is *also* for performance, it seems that there's a tension between using it or not.\n\nIn summary, we are unsure of the value. Let's talk more.\n\n\n2\\. Safe Fixed-Size buffers\n===========================\n\nWhy are fixed-size buffers unsafe? We could generate safe code for them - at least when not in unsafe regions.  Proposal described at #126.\n\nIt might generate a lot of code. You could do it with different syntax, or switch on how you generate.\n\nThis is a very constrained scenario. It wouldn't be harmful, and a few people would celebrate, but is it worth our effort?\n\nIt would allow arbitrary types, not just primitive like today. That may be the bigger value.\n\nNot a high-pri, not one of the first we should commit to.\n\n\n3\\. Pattern matching\n====================\n\nA view on pattern matching:\n\nA pattern is not an expression, but a separate construct. It can be recursive.\nIt's idempotent, doesn't affect the state of the program or \"compute\" something.\n\nSktech of possible pattern syntax:\n\n> *pattern:*\n&emsp; `*`\n&emsp; *literal*\n&emsp; `var` *identifier*\n&emsp; *type* *identifier*<sub>opt</sub>\n&emsp; *type* `{` *member* `is` *pattern* ... `}` *identifier*<sub>opt</sub>\n\n> *expression:*\n&emsp; *expression* `is` *pattern* \n\n> *switch-label:*\n&emsp; `case` *pattern* `:` \n\n\nActually we'd separate into simple and complex patterns and only allow some at the top level.\n\nWe'd have to think carefully about semantics to make it fit into existing is expressions and switch statements. Alternatively we'd come up with a new kind of switch statement. The syntax of switch is already among the least appealing parts of C# - maybe time for a revamp anyway?\n\nAdditionally we could imagine a switch *expression*, e.g. of the form:\n\n``` c#\nmatch (e) { pattern => expression; ... ; default => expression }\n```\nThis would result in a value, so it would have to be complete - exactly one branch would have to be taken. Maybe an expression would be allowed to throw. In fact, `throw` could be made an expression.\n\nExpanded `is` operator\n----------------------\n\nHere's an example scenario from the Roslyn framework. This should not be taken to say that this is a feature specific to building compilers, though! First, without pattern matching:\n\n``` c#\nvar e = s as ExpressionStatement;\nif (e != null) {\n    var a = e.Expr as AssignmentExpressionSyntax;\n    if (a != null) {\n        var l = a.Left as IdentifierName;\n        var r = a.Right as IdentifierName;\n        if (l != null && r != null & l.Name.name == r.Name.name) ...\n```\n\nUgh! With just the `e is T x` non-recursive pattern match we can do a lot better, handling everything in a single if condition:\n\n``` c#\nif (s is ExpressionStatement e &&\n    e.Expr is AssignmentExpressionSyntax a &&\n    a.Left is IdentifierName l &&\n    a.Right is IdentifierName r &&\n    l.Name.name == r.Name.name) ...\n```\n\nMuch more readable! The explicit null checks and the nesting are gone, and everything still has sensible names.\n\nThe test digs pretty deep inside the structure. Here's what if would look like with recursive `T { ... }` patterns:\n\n``` c#\nif (s is ExpressionStatement {\n        Expr is AssignmentExpressionSyntax {\n            Left is IdentifierName { Name is val l },\n            Right is IdentifierName { Name is val r } } }\n    && l.name = r.name) ...\n```\n\nHere the pattern match sort of matches the structure of the object itself, nesting patterns for nested objects. It is not immediately obvious which is more readable, though - at least we disagree enthusiastically on the design team about that.\n\nIt is possible that the nesting approach has more things going for it, though:\n\n- patterns might not just be type tests - we could embrace \"active patterns\" that are user defined\n- we could do optimized code gen here, since evaluation order might not necessarily be left to right.\n- the code becomes more readable because the structure of the code matches the shape of the object.\n- the approach of coming up with more top-level variable names may run out of steam the deeper you go.\n\nThe `T { ... }` patterns are a little clunky, but would apply to any object. For more conciseness, we imagine that types could specify positional matching, which would be more compactly matched through a `T (...)` pattern.That would significantly shrink the recursive example:\n\n``` c#\nif (s is ExpressionStatement(\n        AssignmentExpressionSyntax(IdentifierName l, IdentifierName r)) \n    && l.name = r.name) ...\n```\n\nThis is more concise, but it relies on you knowing what the positions stand for since you are not giving them a name at the consumption site.\n\nSo, in summary, it's interesting that the `e is T x` form in itself gives most of the value. The incremental improvement of having recursive patterns may not be all that significant.\n\nEither way, the built-in null check is likely to help with writing null-safe code.\n\nOn the tooling side, what would the stepping behavior be? One answer is that there is no stepping behavior. That's already the case inside most expressions. Or we could think it through and come up with something better if the need is there.\n\nThe variables are definitely assigned only when true. There is a scoping issue with else if. It's similar to the discussions around declaration expressions in C# 6: \n\n``` c#\nif (o is string s) { ... s ... }\nelse if (o is short s) { ... s ... } // error: redeclaration of s\nelse ...\n```\n\nAll else equal, though not definitely assigned there, the `string s` introduced in the first if condition would also be in scope in the else branch, and the nested if clause would therefore not be allowed to introduce another variable with the same name `s`.\n\nWith declaration expressions we discussed having special rules around this, e.g. making variables introduced in an if condition *not* be in scope in the else clause. But this gets weird if you try to negate the condition and swap the branches: all of a sudden the variables would be in scope only where they are *not* definitely assigned.\n\nExpanded `switch` statement\n---------------------------\n\nThe above examples are in the context of if(...is...), but for switch statements you can't just put `&&...` after the initial pattern. Maybe we would allow a `where ...` (or `when`) in the case labels to add additional filtering:\n\n``` c#\nswitch (o) {\ncase ExpressionStatement(\n        AssignmentExpressionSyntax(IdentifierName l, IdentifierName r)\n        where (l.name == r.name):\n    ...\n}\n```\n\nIf we add pattern matching to switch statements, one side effect is that we generalize the type of thing you can switch on to anything classified as a value.\n\n``` c#\nobject o = ...\nswitch(o) {\n    case 1:\n    case 2:\n    case 3:\n    case Color.Red:\n    case string s:\n    case *: // no\n    case var x: // would have to be last and there'd have to not be a default:\n    default:\n}\n```\nWe would probably disallow `*`, the wildcard, at the top level. It's only useful in recursive positional notation.\n\nEvaluation order would now be important. For back compat, we would allow default everywhere, and evaluate it last.\n\nWe would diagnose situations where an earlier pattern hides a later one:\n\n``` c#\ncase Point(*, 2):\ncase Point(1, 2): // error/warning\n```\n\nWe could allow case guards, which would make the case not subsume other cases:\n\n``` c#\ncase Point(var x, 2) where (x > 2): \ncase Point(1, 2): // fine\n```\n\nUser-defined `is` operator\n--------------------------\n\nWe've sneaked uses of a positional pattern match above. For that to work, a type would have to somehow specify which positional order to match it in. One very general approach to this would be to allow declaration of an `is` operator on types:\n\n``` c#\npublic class Point\n{\n    public Point(int x, int y) { this.X = x; this.Y = y; }\n    public int X { get; }\n    public int Y { get; }\n    overrides public int GetHashCode() ...\n    overrides public bool Equals(...)...\n    public static bool operator is(Point self out int x, out int y) {...}\n}\n```\n\nThe operator `is` is a particular way of specifying custom matching logic, similar to F# active patterns. We could imagine less ambitious ways, in particular if we just want to specify deconstruction and not additional logic. That's something to dive into later.\n\n4\\. Records\n===========\n\nA value-semantics class like the above would be automatically generated by a \"record\" feature, e.g. from something like:\n\n``` c#\nclass Point(int X, int Y);\n```\n\nBy 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:\n\n``` c#\nclass Point(int X, int Y)\n{\n    public int X { get; set; } = X;\n}\n```\n\nYou could have syntax to create separate parameter names from member names:\n\n``` c#\nclass Point(int x:X, int y:Y)\n{\n    public int X { get; set; } = x;\n}\n```\n\nWhether in this form or otherwise, we definitely want to pursue more concise type declarations that facilitate value semantics and deconstruction. We want to pursue the connection with anonymous types and we want to pursue tuples that mesh well with the story too.\n\n"
  },
  {
    "path": "meetings/2015/LDM-2015-02-04.md",
    "content": "C# Design Meeting Notes for Feb 4, 2015\n========================================\n\nDiscussion thread on these notes can be found at https://github.com/dotnet/roslyn/issues/396.\n\nAgenda\n------\n\n1. Internal Implementation Only (C# 6 investigation)\n2. Tuples, records and deconstruction\n3. Classes with value semantics\n\n\n1\\. Internal implementation only\n================================\n\nWe have a versioning problem in the Roslyn APIs that we suspect is somewhat common - that of inherited hierarchies.\n\nThe essence of the problem is that we want to describe an inheritance *hierarchy* of types in the abstract, as well as several concrete \"implementations\" of the hierarchy.\n\nIn Roslyn, the main example is that we have a language agnostic hierarchy of symbols, as well as a C# and VB specific implementation of that.\n\nThis leads to a need for multiple inheritance: \"C#-specific local symbol\" needs to both inherit \"C#-specific symbol\" and \"abstract local symbol\". The only way to represent this is to express the abstract hierarchy with interfaces:\n\n``` c#\npublic interface ISymbol { ... }\npublic interface ILocalSymbol : ISymbol { ... }\n\npublic abstract class CSharpSymbol : ISymbol { ... }\npublic class CSharpLocalSymbol : CSharpSymbol, ILocalSymbol { ... }\n\n// Etc...\n```\n\nSo far, so good. However, even though `ISymbol` and friends are interfaces, we don't actually want anyone else to implement them. They are not intended as extension points, we merely made them interfaces to allow multiple base types. On the contrary we would like to be able to add members to these types in the future, as the Roslyn API evolves.\n\nHad these types been abstract classes, we could have prevented implementation from other assemblies by having only internal constructors. That would have protected the types for future extensions. However, for interfaces no such trick exists.\n\nAs a result, if we ever want to evolve these interfaces by adding more members, but someone implemented them *despite our intent*, we will break those people.\n\nOur options, current and future, seem to include:\n\n1. Tell people really loudly in comments on the interfaces that they shouldn't implement them, because we will break them\n2. Add an attribute, `ImplicitImplementationOnlyAttribute`, to the interfaces\n3. Write an analyzer that enforces the attribute, make it be installed and on by default and hope that catches enough cases\n4. Make the compiler enforce the attribute\n5. Add a mechanism to the language to safely evolve interfaces\n    * default implementations of interface methods (like in Java) - will require CLR support\n6. Add an alternative multiple-inheritance mechanism to the language\n    * mixins or traits\n\nOptions 1, 2 and 3 are open to us today. However, the concern is whether we can consider them strong enough discouragement that our future selves will feel good about evolving the interfaces. If we do 1, 2 and 3, will we then be ready to later break people who disregard the discouragement?\n\nWe have never been 100% on compat. Reliance on reflection, codegen patterns etc, can cause code to be breakable today. The BCL has a clear set of guidelines of which things they allow themselves to change even if they can break existing code: adding private fields, etc. \n\nTheir rule on interfaces is that we cannot add members to an interface. In inherited-hierarchies situations such as the one in Roslyn that constraint is hard to live with.\n\nAnalyzers\n---------\n\nAnalyzers can easily detect when an interface with the attribute is being implemented outside of its assembly.\n\nThe problem here is that it is easy to land in a situation where you do not have the analyzer, or it is not turned on. Analyzers are optional by design: they help you use an API, but the API author can't rely on them being enforced.\n\nCompiler enforcement\n--------------------\n\nMoving this check into the compiler would make the \"hole\" smaller, but, perhaps surprisingly, wouldn't completely deal with it: a pre C# 6 compiler would still happily compile an implementation of an interface with the attribute on. Now, upgrading to C# 6 and the Roslyn-based compiler would be a breaking change!\n\nAlso, this may play badly with mocking. Though many of the automated mocking frameworks already have a way to work around internal requirements, explicit or manual mocking would still suffer.\n\nThere are probably some design details around how this works in conjunction with `InternalsVisibleTo`:\n\nAssembly A:\n\n``` c#\n[assembly: InternalVisibleTo(\"B\")]\n\n[InternalImplementationOnly]\npublic interface IA {}\n```\n\nAssembly B:\n\n``` c#\npublic abstract class B : IA {}\npublic interface IB : IA {} // implicitly inherits restriction?\n```\n\nAssembly C:\n\n``` c#\npublic class C : B {}     // OK\npublic class D : B, IA {} // not OK\npublic class E : IB {}    // not OK\n```\n\nConclusion \n----------\n\nWe need to talk to the BCL team to decide whether we would consider either of these approaches sufficient to protect the evolvability of interfaces.\n\n\n2\\. Tuples, records, deconstruction\n===================================\n\nWe are eager to look at language support for tuples. They should facilitate multiple return values from methods, including async ones, and a consumption experience that includes deconstruction.\n\nWe'll have a proposal ready to discuss in the next meeting (It is now here: #347).\n\nWe are also interested in making it much easier to write something akin to algebraic datatypes (discriminated unions), whose shape and contents are easily pattern-matched on and, probably, deconstructed.\n\nWhile we have a proposal for records that caters to that (#206), there's a sense that this might be more closely connected with the tuple feature than the current proposals suggest, and we should churn on these together to produce a unified, or at least rationalized, design. \n\nAre tuples just a specific kind of record? Are records just tuples with a name? Further exploration is needed! \n\nThe next point is one such exploration.\n\n\n3\\. Classes with values\n=======================\n\nWe explored a possible pattern for immutable classes. It may or may not be the right thing to do, but it generated a lot of ideas for features that would be possible with it, and that it would be interesting to pursue regardless of the pattern.\n\nThe core idea is: if you want value semantics for your object, maybe your object should literally have a `Value`:\n\n``` c#\npublic class Person \n{\n\tpublic readonly PersonValue Value;\n\tpublic Person(PersonValue value) { Value = value; }\n\tpublic string Name => Value.Name;\n\tpublic int Age => Value.Age;\n\t…\n\tpublic struct PersonValue\n\t{\n\t\tpublic string Name;\n\t\tpublic int Age;\n\t}\n}\n```\n\nThe core idea is that there is a *mutable* value type representing the actual state. The object wraps a `readonly` field `Value` of that value type and exposes properties that just delegate to the `Value`.\n\nThis starts out with the obvious downside that there are two types instead of one. We'll get back to that later.\n\n\nValue semantics\n---------------\n\nValue semantics mean a) being immutable and b) having value-based equality (and hash code). Value types *already* have value-based equality and hash code, and the `Value` field is `readonly`. So instead of having to negotiate computation of hashcodes, a developer using this pattern can just forward these questions to the `Value`:\n\n``` c#\npublic override bool Equals(object other) => (other as Person)?.Value.Equals(Value) ?? false; // or similar\npublic override int GetHashCode() => Value.GetHashCode;\n```\n\nNo need to write per-member code. All is taken care of by the `Value`. So for bigger types this definitely leads to less code bloat.\n\nYou could implement `IEquatable<T>` for better performance, but this illustrates the point.\n\n\nBuilder pattern\n---------------\n\nThis approach is essentially a version of the Builder pattern: `PersonValue` acts as a builder for `Person` in that it can be manipulated, and eventually passed to the constructor (which implements the Parameter Object pattern by taking all its parameters as one object).\n\nThis allows for the use of object initializers in creating new instances:\n\n``` c#\nvar person = new Person(new PersonValue { Name = \"John Doe\" });\n```\n\nIt also lets you create new objects from old once using mutation to incrementally change it:\n\n``` c#\nvar builder = Person.Value;\nbuilder.Name = \"John Deere\";\nperson = new Person(builder);\n```\n\nThis again scales to much larger objects, and illustrates one of the points why the builder pattern is popular. Another popular approach is to use \"Withers\", methods for returning a new instance of an immutable type that's incrementally changed in one way from an old one:\n\n``` c#\nperson.WithName(\"John Deere\");\n```\n\nWithers are more elegant to use, at least when you are only changing one property. But when changing multiple ones, you need to chain them, creating intermediate objects along the way. What's worse, you need to declare a `WithFoo` method for every single property, which is a lot of boilerplate.\n\nMaybe we can make the Builder pattern more elegant to use - more like the Wither pattern?\n\n\nObject initializers\n-------------------\n\nOne idea is to allow two new uses of object initializers:\n\n* when creating new immutable objects that implement the builder pattern\n* when non-destructively \"modifying\" immutable objects by creating new ones with deltas\n\nFirst, let's allow this (similar to what's proposed in #229):\n\n``` c#\nvar person = new Person { Name = \"John Doe\" };\n```\n\nIt would simply rewrite to this:\n\n``` c#\nvar person = new Person(new PersonValue { Name = \"John Doe\" });\n```\n\nWhich is what we had above.\n\nSecond, let's allow object initializers on *existing* values instead of just new expressions. This is a much requested feature already, because it would apply to factories etc.\n\nIt would allow us to do a lot better on the incremental modification:\n\n``` c#\nperson = new Person(person.Value { Name = \"John Deere\" });\n```\n\nIf we are uncomfortable just letting object initializers occur directly on any expression, we could consider adding a keyword, like `with`.\n\nNow we can get the builder, modify it and create a new Person from it, all in one expression.\n\nBut of course the kicker is to combine the two ideas, allowing you to write:\n\n``` c#\nperson = person { Name = \"John Deere\" };\n```\n\nto the same effect: \n\n* Since `person` doesn't have a writable member `Name`, get its builder\n* modify the builder based on the object initializer\n* create a new `Person` from the builder\n\nSo in summary, adding the builder patter in *some* compiler-recognized form allows us to tinker with the object initializer feature, making it work as well for immutable objects as  it does for mutable ones, and essentially serving as built-in \"wither\" support.\n\n\nUsing tuples as the values\n--------------------------\n\nTuples are far from a done deal, but assuming a design like #347, where tuples are mutable structs, they could actually serve as the type of the `Value` field, thus obliterating the need for a second type declaration:\n\n``` c#\npublic class Person \n{\n\tpublic readonly (string Name, int Age) Value; // a tuple\n\tpublic Person((string Name, int Age) value) { Value = value; }\n\t…\n}\n```\n\nThis opens up one more opportunity. Assuming you want your immutable type to be deconstructable the same way as a tuple - by position. How do you indicate that? Well maybe having a tuple as your `Value` is how: deconstruction is simply yet another aspect that is delegated to the `Value`:\n\n``` c#\n(var n, var a) = GetPerson(); // deconstructed as per the `Value` tuple\n```\n\nRecords\n-------\n\nIf we have a pattern that the compiler supports in various ways for immutable types (whether this pattern or another), it makes sense that that pattern should also underlie any record syntax that we add.\n\nAssuming a record syntax like in #206, the record definition:\n\n``` c#\nclass Person(string Name, int Age);\n```\n\nWould then generate the class\n\n``` c#\nclass Person \n{\n    public readonly (string Name, int Age) Value;\n\tpublic Person((string Name, int Age) value) { Value = value; }\n    public string Name => Value.Name;\n    public int Age => Value.Age;\n    public override bool Equals(object other) => (other as Person)?.Value.Equals(Value) ?? false; // or similar\n    public override int GetHashCode() => Value.GetHashCode;\n}\n```\n\nAnd would therefore support object initializers and positional deconstruction.\n\n\nConclusion\n----------\n\nWe are not at all sure if this is the right general direction, let alone the right *specific* pattern if it is. But builders are a common pattern, and for a reason. It would be interesting if support for them was somehow included in what we do for immutable types in C# 7.\n"
  },
  {
    "path": "meetings/2015/LDM-2015-02-11.md",
    "content": "C# Design Meeting Notes for Feb 11, 2015\n=========================================\n\nDiscussion on these notes can be found at https://github.com/dotnet/roslyn/issues/1207.\n\nAgenda\n------\n\n1. Destructible types <*we recognize the problem but do not think this is quite the right solution for C#*>\n2. Tuples <*we like the proposal, but there are several things to iron out*>\n\n\n1\\. Destructible types\n======================\n\nIssue #161 is a detailed proposal to add destructible types to C#.\n\nThe problem area is deterministic disposal of resources. \n\nFinalizers are notoriously non-deterministic (you can never know when or even whether they run), and rampant usage is quite a hit on performance. `using` statements are the language's current attempt at providing for deterministic disposal.\n\nThe problem with `using` statements is that no-one is forced to use them. An `IDisposable` resource is disposed of only if people remember to wrap it in a `using`. FxCop rules and now Roslyn diagnostics can be employed to help spot places where things aren't disposed that should be, but these have notoriously run into false positives and negatives, to the extent that they are a real nuisance and often get turned off.\n\nAt least one reason for this is the lack of their ability to track ownership. Whose responsibility is it to ultimately dispose the resource, and how is that responsibility transferred?\n\nDestructible types offer a sweeping approach to deal with this, that is a complete departure from `using` and `IDisposable` and instead leans more closely on C++-like RAII features.\n\nThe core idea is that destructible types are a language concept (they have to be declared as such):\n\n``` c#\ndestructible struct Handle\n{\n    IntPtr ptr;\n\n    ~Handle()\n    {\n        if (ptr != IntPtr.Zero) Free(ptr);\n    }\n}\n```\n\nDestructible types can only be fields in other destructible types.\n\nVariables of destructible type have their contents automatically disposed when they go out of scope.\n\nTo prevent multiple disposal, such variables can't just be assigned to others. Instead, ownership must be explicitly transferred (with a `move` keyword):\n\n``` c#\nvoid M()\n{\n    Handle h = CreateHandle();\n    Handle h2 = h; // Not allowed! Moves are explicit\n    Handle h3 = move h; // Explicit owner transfer\n    \n    M2(new Handle()); // ok, no owner\n    M2(h3); // Not allowed!\n    M2(move h3); // ok, explicit owner transfer\n\n}\nvoid M2(Handle h) ...\n```\n\nAt the end of M, all locals with destructible types are destructed, in opposite order of their introduction.\n\nAdditionally variables can be \"borrowed\" by being passed by `ref` to a method.\n\nThere are a lot of limitations to the feature, and it doesn't replace `IDisposable`, because you cannot use destructible types as type arguments, in arrays, and as fields of non-destructible types. Also, they cannot implement interfaces.\n\nAs a release valve one can have a `Box<T>` that \"magically\" transfers the ownership of a destructible type to the finalizer. The finalizer will crash the process if the destructible hasn't been properly destructed.\n\nThere has been some negative feedback around the destruction being implicit, even as the ownership transfer was explicit. When assignment overwrites a value, that value has to be destructed. But what about cases like this?\n\n``` c#\n{\n    D x;\n    if (e) x = new x();\n    x = new x();\n}\n```\n\nHow to know whether the second assignment overwrites a value, that should therefore be destructed? We'd have to keep track at runtime. Or prevent this situation through definitely assigned or unassigned rules, or the like.\n\n\nConclusion\n----------\n\nOverall, we see how this adds value, but not enough that having these concepts in the face of all C# developers. It doesn't earn back it's -100 points.\n\nCould we take a step back and have analyzers encourage practices that are less error prone? Yes. You just cannot have analyzers enforce correctness. And you cannot have them improve perf by affecting codegen. And they cannot do the heavy lifting for you.\n\nAn analyzer can help you with where to put your `using` statements. FxCop tries to do that today, but has too many false positives (use vs ownership). Even if you could get rid of those, there's a lot of code you'd need to write.\n\nPeople do struggle with `IDisposable` today. They don't know when things are `IDisposable`, whether they are the ones who should dispose things.\n\nWe would like to solve the problem in C#, and pick over this proposal for ideas, but we'd need to noodle with it to make it a better fit. It would need to integrate better with current `IDisposable`.\n\n\n2\\. Tuples\n==========\n\nIssue #347 is a proposal for adding tuples to C#. The main guiding principle for the proposal is to enable multiple return values, and wherever possible design them in analogy with parameter lists.\n\nAs such, a tuple type is a parenthesized list of types and names, just like a parameter list:\n\n``` c#\npublic (int sum, int count) Tally(IEnumerable<int> values) { ... }\n\nvar t = Tally(myValues);\nConsole.WriteLine($\"Sum: {t.sum}, count: {t.count}\");  \n```\n\nAlong the same lines, tuple values can be constructed using a syntax similar to argument lists. By position:\n\n``` c#\npublic (int sum, int count) Tally(IEnumerable<int> values) \n{\n    var sum = 0; var count = 0;\n    foreach (var value in values) { sum += value; count++; }\n    return (sum, count); // target typed to the return type\n}\n```\n\nOr by name:\n\n``` c#\npublic (int sum, int count) Tally(IEnumerable<int> values) \n{\n    var res = (sum: 0, count: 0); // infer tuple type from names and values\n    foreach (var value in values) { res.sum += value; res.count++; }\n    return res;\n}\n```\n\nFinally, there'd be syntax to deconstruct tuples into variables for the individual members:\n\n``` c#\n(var sum, var count) = Tally(myValues); // deconstruct result\nConsole.WriteLine($\"Sum: {sum}, count: {count}\");  \n```\n\nTuples should be thought of as temporary, ephemeral constellations of values without inherent conceptual connection: they just \"happen to be traveling together\".\n\nWe are generally eager to pursue this design. There are a number of open issues, that we explore in the following.\n\n\nType equivalence\n----------------\n\nIntuitively you'd expect that every time you use the same tuple type expression, it denotes the same type - that there is *structural equivalence*. However, depending on how we implement tuple types on top of the CLR, that may not always be easy to achieve - especially when unifying across different assemblies.\n\nTo take it to an extreme, what if they didn't even unify *within* an assembly? Even then they'd probably have significant value. They would be good for the \"ephemeral\" core scenario of things traveling together. It wouldn't let them serve as e.g. builders; they would really only work for the multiple return values scenario.\n\nEven then there'd be issues with virtual method overrides, etc: When you override and restate the return type, it doesn't really work if that declares a *different* return type.\n\n``` c#\nclass C\n{\n    public abstract (int x, int y) GetCoordinates();\n}\nclass D : C\n{\n    public override (int x, int y) GetCoordinates() { ... } // Error! different return type!!?!\n}\n```\n\nA middle ground is for these methods to unify *within* but not *across* assemblies. This is what we do for anonymous types today. However, there we are careful never to let the types occur in member signatures, whereas that would be the whole point of tuples.\n\nThis makes a little more sense than no unification at all, since at least all mentions of a tuple type within the same member body and even type body refer to the same type. However there'd still be weird behavior involving overrides across assembly boundaries, equivalence of generic types constructed with tuple types, etc. We could try to be smart about reusing types from other assemblies when possible, etc, but it would be quite a game of whack-a-mole to get all the edge cases behaving sensibly.\n\nThe only thing that really makes sense at the language level is true structural equivalence. Unfortunately, the CLR doesn't really provide for unification of types with similar member names across assemblies. Ideally we could *add* that to the CLR, but adding new functionality to the CLR is not something to be done lightly, as it breaks all downlevel targeting.\n\nA way to get structural equivalence working at compile time would be to encode tuples with framework types similar to the current `Tuple<...>` types. Member access would be compiled into access of members called `Item1` etc. The language level member names would be encoded in attributes for cross-assembly purposes:\n\n``` c#\nstruct VTuple2<T1, T2> { ... }\nstruct VTuple3<T1, T2, T3> { ... }\n\n/* Source: */\n(x: int, y: int) f() { ... }\n\n/* Generates: */\n[TupleNames(\"x\", \"y\")]\nVTuple2<int, int> f() {...}\n```\n\nUnfortunately this leaves problems at runtime: now there's *too much* type equivalence. If I want to do a runtime test to see if an object is an `(int x, int y)`, I would get false positives for an `(int a, int b)`, since the names wouldn't be part of the runtime type:\n\n``` c#\nobject o = (a: 7, b: 9);\nif (o is (int x, int y) t) WriteLine(t.x); // false positive\n```\n\nAlso the member names would be lost to `dynamic`:\n\n``` c#\ndynamic d = (a: 7, b: 9);\nWriteLine(t.a); // Error! Huh ??!?\n```\n\n\nOf course we could come up with tricks so that a tuple would carry some kind of member name info around at runtime, but not without cost. Or we could decide that the names are ephemeral, compile time only entities, kind of like parameter names, and losing them when boxing is actually a good thing. \n\nAlso, this approach means that languages that don't know about tuples would see the actual `Item1` member names when referencing member signatures containing tuples. Such languages include previous versions of C#! So for compatibility with those versions of C#, even in the new, tuple-aware, version, access through `Item1` etc would have to be still legal (though probably hidden from IntelliSense etc.).\n\nA nice thing about this scheme is that it leads to very little code bloat: it only relies on framework types, and not on compiler generated types in the assembly.\n\nThis remains an issue for further debate.\n\n\nConversions\n-----------\n\nThere are several kinds of conversions you can imagine allowing between tuple types:\n\n``` c#\n(string name, int age) t = (\"Johnny\", 29);\n\n/* Covariance */\n(object name, int age) t1 = t;\n\n/* Truncation */\n(object name) t2 = t;\n\n/* Reordering */\n(int age, string name) t3 = t;\n\n/* Renaming */\n(string n, int a) t4 = t;\n```\n\nNote that you cannot have both reordering and renaming in the language; we would have to choose.\n\nHowever, we are more inclined not to allow *any* of these conversions. They don't seem particularly helpful, and are likely to mask something you did wrong. People can always deconstruct and reconstruct if they want to get to a different tuple type, so our default position is to be super rigid here and only match exactly the same names and types in exactly the same order.\n\n\nDeconstruction\n--------------\n\nThere are a couple of issues with the proposed deconstruction syntax.\n\nFirst of all, since the recipient variables are on the left, there is no equivalent to parameter help guiding you as to what to name them. In that sense it would be better to have a syntax that receives the values on the right. But that seems an odd place to declare new variables that are intended to be in scope throughout the current block:\n\n``` c#\nTally(myValues) ~> (var sum, var count); // strawman right side alternative\nConsole.WriteLine($\"Sum: {sum}, count: {count}\");  \n```\n\nThat's not an actual proposed syntax, but just intended to show the point!\n\nA related issue is that you'd sometimes want to deconstruct into *existing* variables, not declare new ones:\n\n``` c#\n(sum, count) = Tally(myValues);\n```\n\nShould this be allowed? Is deconstruction then a declaration statement, an assignment statement or something different?\n\nFinally, once we have a deconstruction syntax, we'd probably want to enable it for other things than tuples. Maybe types can declare how they are to be deconstructed, in a way that the language understands. So deconstruction syntax should be considered in this broader context. For instance, if deconstructable types can be reference types, can deconstruction throw a null reference exception?\n\n\nLINQ\n----\n\nYou could imagine tuples becoming quite popular in LINQ queries, to the point of competing with anonymous types:\n\n``` c#\nfrom c in customers\nselect (name: c.Name, age: c.Age) into p\nwhere p.name == \"Kevin\"\nselect p;\n``` \n\nTo this end it would be useful for tuple \"literals\" to support *projection*, i.e. inference of member names, like anonymous types do:\n\n``` c#\nfrom c in customers\nselect (c.Name, c.Age) into p // infers (string Name, int Age)\nwhere p.Name == \"Kevin\"\nselect p;\n```\n\n\nOut parameters\n--------------\n\nF# allows out parameters to be seen as additional return values. We could consider something similar:\n\n``` c#\nbool TryGet(out int value){ ... }\n\n/* current style */\nint value;\nbool b = TryGet(out value);\n\n/* New style */\n(int value, bool b) = TryGet();\n```\n\n\nConclusion\n----------\n\nWe'd very much like to support tuples! There are a number of open questions, as well as interactions with other potential features. We'll want to keep debating and experimenting for a while before we lock down a design, to make sure we have the best overall story.\n"
  },
  {
    "path": "meetings/2015/LDM-2015-03-04.md",
    "content": "C# Design Meeting Notes for Mar 4, 2015\n========================================\n\nDiscussion on these notes can be found at https://github.com/dotnet/roslyn/issues/1303.\n\nAgenda\n------\n\n1. `InternalImplementationOnly` attribute <*no*>\n2. Should `var x = nameof(x)` work? <*no*>\n3. Record types with serialization, data binding, etc. <*keep thinking*>\n4. \"If I had a [billion dollars](http://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare)...\": nullability <*daunting but worth pursuing*>\n\n\n1\\. InternalImplementationOnly\n==============================\n\nThis was a last-minute proposal for C# 6 and VB 14 to recognize and enforce an attribute to the effect of disallowing non-internal implementation of an interface. It would be useful to represent \"abstract hierarchies\", while reserving the right to add new members at a later stage.\n\n\nConclusion\n---------- \n\nLet's not do this. We cannot enforce it well enough since old compilers don't know about it. \n\n\n2\\. Should `var x = nameof(x)` work?\n====================================\n\nThis was raised as issue #766.\n\n``` c#\nvar POST = nameof(POST);\n```\n\n\nConclusion\n----------\n\nThis works the same as with any other construct, i.e.: not. This is not a special case for `nameof`, and it doesn't seem worth special casing to allow it.\n\n\n3\\. Records\n===========\n\nThere's general excitement around proposals such as #206 to add easier syntax for declaring \"records\", i.e. simple data shapes.\n\nThis discussion is about the degree to which such a feature should accommodate interaction with databases, serialization and UI data binding. \n\nThe problem has compounded in recent times. In a mobile app, pretty much everything has to be serialized one way or another. There's a big difference between e.g. JSON and binary serialization. In one you want readable property names (in a certain format), in the other you want compactness. ORMs are also essentially serialization. POCO was invented in that same context, but only gets you part of the way there.\n\nClearly, tying the language feature to specific such technologies is not a sustainable idea. There will not be built-in JSON literals, or `INotifyPropertyChanged` implementation or anything like that.\n\nThat said, It is worth thinking about what can be done *in general* to support such features better.\n\nOne problem is that each specific serialization and data binding technology tends to have certain requirements of the shape of the data objects. Serialization frameworks may expect the fields to be mutable, or to have certain attributes on them. UIs may expect properties to notify on change. Such requirements make it hard to have a single language-sanctioned mechanism for specifying the data shapes.\n\nA separate problem may be the degree to which reflection is used by these technologies. It is commonly used to get at metadata such as member names, but is also sometimes used to set or get the actual values. It ends up being the case that both serialization and UI use the objects only in a \"meta\" fashion; the only part of the program that actually makes use of the data in a strongly typed way ends up being the business logic in between.\n\nSo in effect, data objects need to both facilitate strongly typed business logic based on their property names and shapes (and often in hierarchies), *and* satisfy requirements that are specific to the serialization and UI environments they are used in. Cross-cutting aspects, one might say, that clash in the implementation of the data objects.\n\nThere are several possible approaches, not necessarily mutually exclusive:\n\n**Write the data types manually**: Often what ends up happening today. Just grit your teeth and churn out those INotifyPropertyChanged implementations.\n\n**Separate objects**: Often the \"best practice\" is to have separate objects for serialization, logic, and presentation. But having to write the glue code between these is a big pain, and people often have to do at least some of it manually.\n\n**Non-reflective meta-level access model**: E.g. implement dictionary-like behavior. Prevents need for reflection, but is it actually better or faster?\n\n**\"Fake\" types**: Maybe at runtime the data objects shouldn't have strongly typed properties at all. Maybe the business logic is written up against a new kind of types that are only there at compile time, and which either simply erase like in TypeScript, or cause weakly typed but smart access code to be generated like with F# type providers. Then, from the perspective of serialization and UI, all the objects have the same type.\n\n**Compile-time metaprogramming**: Generate the types (either into source or IL) from code describing the data shapes, adding whatever serialization or presentation functionality is required.\n\nA particularly common requirement of these frameworks is for the data properties to be mutable. That might clash spectacularly with a records feature that tries to encourage immutability by default.\n\n\nConclusion\n----------\n\nWe'll keep thinking about this situation. A next step in particular is to reach out to teams that own the serialization and presentation technologies that we'd like to work well with.\n\n\n4\\. Nullability and reference types\n===================================\n\nThe horrifying thing about null being allowed as a member of reference types is that it does not obey the contract of those types. Reference types can be null *and* reference types can be dereferenced, But dereferencing null is a runtime error! No wonder Sir Tony famously calls null pointers his \"[billion dollar mistake](http://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare)\".\n\nThere are type systems that prevent null reference errors, and it is easy enough to do. It takes different shapes in different languages, but the core of it is that there is a non-nullable kind of reference type that can be dereferenced but cannot be null, and a nullable \"wrapper\" of that, which *can* be null, but cannot be dereferenced. The way you go from nullable to nonnullable is through a guard to test that the nullable value wasn't in fact null. Something like:\n\n``` c#\nstring? n; nullable string\nstring! s; non-nullable string\n\nn = null; // Sure; it's nullable\ns = null; // Error!\n\nWriteLine(s.Length); // Sure; it can't be null so no harm\nWriteLine(n.Length); // Error!\nif (n is string! ns) WriteLine(ns.Length); // Sure; you checked and dug out the value\n```\n\nOf course, if such a type system were around from day one, you wouldn't need the `!` annotation; `string` would just *mean* non-nullable.\n\nIt's a very common request (in fact [the top C# request on UserVoice](http://visualstudio.uservoice.com/forums/121579-visual-studio/category/30931-languages-c)) for us to do something about null reference exceptions along those lines. There are numerous obstacles, however:\n\n**Backward compatibility**: The cat is already very much out of the bag in that existing code needs to continue to compile without error - no matter how null-unsafe it is. The best we can do about *existing* code is to offer optional analyzers to point out dangerous places.\n\n**A default value for all types**: It is deeply ingrained in .NET and the CLR that every type has a default value. When you create an array with `new T[10]`, the array elements are initialized to the default value of `T`. There's even syntax to get the default value of a type, `default(T)`, and it is allowed even on unconstrained type parameters. But what is the default value of a non-nullable reference type?\n\n**Definite assignment of non-nullable fields is unenforceable**. Eric Lippert explains it well [on his blog](http://blog.coverity.com/2013/11/20/c-non-nullable-reference-types/).\n\n**Evolving libraries is breaking**: Say we added non-null annotations to the language. You'd then want to use them on your existing libraries to provide further guidance to your clients. Adding them on parameters would of course be breaking:\n\n``` c#\npublic void Foo(string! name) { ... } // '!' newly added\n\nFoo(GetString()); // Unless GetString also annotated, this is now broken\n```\n\nMore subtly, adding the extra guarantee of non-nullability to a *return* type would also be breaking:\n\n``` c#\npublic string! Foo() { ... } // '!' newly added\n\nvar s = Foo(); // Now infers 'string!' instead of 'string' for s\n...\ns = GetString(); // So this assignment is now broken\n```\n\nType inference and overload resolution generally make strengthening of return types a potentially breaking change, and adding non-nullability is just a special case of that.\n\n\nConclusion\n----------\n\nMoving C# to a place of strong guarantees around nullability seems out of the question. But that is not to say that we cannot come up with an approach that meaningfully reduces the number of null reference exceptions. We want to keep digging here to see what can be done. The perfect is definitely the enemy of the good with this one.\n"
  },
  {
    "path": "meetings/2015/LDM-2015-03-10-17.md",
    "content": "C# Design Meeting Notes for Mar 10 and 17, 2015\n===============================================\n\nDiscussion thread for these notes can be found at https://github.com/dotnet/roslyn/issues/1648.\n\nAgenda\n------\n\nThese two meetings looked exclusively at nullable/non-nullable reference types. I've written them up together to add more of the clarity of insight we had when the meetings were over, rather than represent the circuitous path we took to get there.\n\n1. Nullable and non-nullable reference types\n2. Opt-in diagnostics\n3. Representation\n4. Potentially useful rules\n5. Safely dereferencing nullable reference types\n6. Generating null checks\n\n1\\. Nullable and non-nullable reference types\n=============================================\n\nThe core features on the table are nullable and non-nullable reference types, as in `string?` and `string!` respectively. We might do one or both (or neither of course).\n\nThe value of these annotations would be to allow a developer to express intent, and to get errors or warnings when working against that intent.\n\n\n2\\. Opt-in diagnostics\n======================\n\nHowever, depending on various design and implementation choices, some of these diagnostics would be a breaking change to add. In order to get the full value of the new feature but retain backward compatibility, we therefore probably need to allow the enforcement of some or most of these diagnostics to be *opt-in*. That is certainly an uncomfortable concept, and adding switches to the language changing its meaning is not something we have much of an appetite for. \n\nHowever, there are other ways of making diagnostics opt-in. We now have an infrastructure for custom analyzers (built on the Roslyn infrastructure). In principle, some or all of the diagnostics gained from using the nullability annotations could be custom diagnostics that you'd have to switch on.\n\nThe downside of opt-in diagnostics is that we can forget any pretense to guarantees around nullability. The feature would help you find more errors, and maybe guide you in VS, but you wouldn't be able to automatically trust a `string!` to not be null.\n\nThere's an important upside though, in that it would allow you to gradually strengthen your code to nullability checks, one project at a time.\n\n\n\n3\\. Representation\n==================\n\nThe representation of the annotations in metadata is a key decision point, because it affects the number of diagnostics that can be added to the language itself without it being a breaking change. There are essentially four options:\n\n1. Attributes: We'd have `string?` be represented as `string` plus an attribute saying it's nullable. This is similar to how we represent `dynamic` today, and for generic types etc. we'd use similar tricks to what we do for `dynamic` today.\n\n2. Wrapper structs: There'd be struct types `NullableRef<T>` and `NonNullableRef<T>` or something like that. The structs would have a single field containing the actual reference.\n\n3. Modreq's: These are annotations in metadata that cause an error from compilers that don't know about them. \n\n4. New expressiveness in IL: Something specific to denote these that only a new compiler can even read.\n\nWe can probably dispense with 3 and 4. We've never used modreq's before, and who knows how existing compilers (of all .NET languages!) will react to them. Besides, they cannot be used on type arguments, so they don't have the right expressiveness. A truly new metadata annotation has similar problems with existing compilers, and also seems like overkill. \n\nOptions 1 and 2 are interesting because they both have meaning to existing compilers.\n\nSay a library written in C# 7 offers this method:\n\n``` c#\npublic class C\n{\n    string? M(string! s) { ... }\n}\n```\n\nWith option 1, this would compile down to something like this:\n\n``` c#\npublic class C\n{\n    [Nullable] string M([NonNullable] string s) { ... }\n}\n```\n\nA consuming program in C# 6 would not be constrained by those attributes, because the C# 6 compiler does not know about them. So this would be totally fine:\n\n``` c#\nvar l = C.M(null).Length;\n```\n\nUnfortunately, if something is fine in C# 6 it has to also be fine in C# 7. So C# 7 cannot have rules to prevent passing null to a nonnullable reference type, or prevent dereferencing a nullable reference type!\n\nThat's obviously a pretty toothless - and hence useless - version of the nullability feature in and of itself, given that the value was supposed to be in getting diagnostics to prevent null reference exceptions! This is where the opt-in possibility comes in. Essentially, if we use an attribute encoding, we need all the diagnostics that make nullability annotations useful be opt-in, e.g. as custom diagnostics.\n\nWith option 2, the library would compile down to this:\n\n``` c#\npublic class C\n{\n    NullableRef<string> M(NonNullableRef<string> s) { ... }\n}\n```\n\nNow the C# 6 program above would not compile. The C# 6 compiler would see structs that can't be null and don't have a Length. Whatever members those structs *do* have, though, would be accessible, so C# 7 would still have to accept using them as structs. (We could mitigate this by not giving the structs any public members).\n\nFor the most part, this approach would make the C# 6 program able to do so little with the API that C# 7, instead of adding *restrictions*, can allow *more* things than C# 6.\n\nThere are exceptions, though. For instance, casting any returned such struct to `object` would box it in C# 6, whereas presumably the desired behavior in C# 7 would be to unwrap it. This is exactly where the CLR today has special behavior, boxing nullable value types by first unwrapping to the underlying type if possible.\n\nAlso, having these single-field structs everywhere is likely going to have an impact on runtime performance, even if the JIT can optimize many of them away.\n\nProbably the most damning objection to the wrapper structs is probably the degree to which they would hamper interoperation between the different variations of a type. For instance, the conversion from `string!` to `string` and on to `string?` wouldn't be a reference conversion at runtime. Hence, `IEnumerable<string!>` wouldn't convert to `IEnumerable<string>`, despite covariance. \n\nWe are currently leaning strongly in the direction of an attribute-based representation, which means that there needs to be an opt-in mechanism for enforcement of the useful rules to kick in.\n\n\n4\\. Potentially useful rules to enforce\n=======================================\n\n**Don't dereference `C?`**: you must check for null or assert that the value is not null.\n\n**Don't pass `null`, `C` or `C?` to `C!`:** you must check for null or assert that the value is not null.\n\n**Don't leave `C!` fields unassigned:** require definite assignment at the end of the constructor. (Doesn't prevent observing null during initialization)\n\n**Avoid `default(C!)`:** it would be null!\n\n**Don't instantiate `C![]`:** it's elements would be null. This seems like a draconian restriction - as long as you only ever read fields from the array that were previously written, no-one would observe the default value. Many data structures wrapping arrays observe this discipline.\n\n**Don't instantiate `G<C!>`:** this is because the above rules aren't currently enforced on even unconstrained type parameters, so they could be circumvented in generic types and methods. Again, this restriction seems draconian. No existing generic types could be used on nonnullable reference types. Maybe the generic types could opt in?\n\n**Don't null-check `C!`:** oftentimes using e.g. `?.` on something that's already non-nullable is redundant. However, since non-nullable reference types *can* be null, maybe flagging such checks is not always so helpful?\n  \nWe very much understand that these rules can't be perfect. The trade-off needs to be between adding value and allowing continuity with existing code.\n\n\n5\\. Safely dereferencing nullable reference types\n=================================================\n\nFor nullable reference types, the main useful error would come from dereferencing the value without checking for null. That would often be in the shape of the null-conditional operator:\n\n``` c#\nstring? s = ...;\nvar l = s?.Length;\nvar c = s?[3];\n```\n\nHowever, just as often you'd want the null test to guard a block of code, wherein dereferencing is safe. An obvious candidate is to use pattern matching:\n\n``` c#\nstring? ns = ...;\nif (ns is string! s) // introduces non-null variable s\n{\n    var l = s.Length;\n    var c = s[3];\n}\n```\n\nIt is somewhat annoying to have to introduce a new variable name. However, in real code the expression being tested (`ns` in the above example) is more likely to be a more complex expression, not just a local variable. Or rather, the `is` expression is how you'd get a local variable for it in the first place.\n\nMore annoying is having to state the type again in `ns is string! s`. We should think of some shorthand, like `ns is ! s` or `ns is var s` or something else.\n\nWhatever syntax we come up with here would be equally useful to nullable *value* types.\n\n\n6\\. Generating null checks for parameters\n=========================================\n\nThere'd be no guarantees that a `string!` parameter actually isn't going to be null. Most public API's would probably still want to check arguments for null at runtime. Should we help with that by automatically generating null checks for `C!` parameters?\n\nEvery generated null check is performance overhead and IL bloat. So this may be a bad idea to do on every parameter with a non-nullable reference type. But we could have the user more compactly indicate the desire to do so. As a complete strawman syntax:\n\n``` c#\npublic void M(string!! s) { ... }\n```\nWhere the double `!!` means the type is non-nullable *and* a runtime check should be generated.\n\nIf we choose to also do contracts (#119), it would be natural for this feature to simply be a shorthand for a null-checking `requires` contract.\n"
  },
  {
    "path": "meetings/2015/LDM-2015-03-18.md",
    "content": "C# Design Meeting Notes for Mar 18, 2015\n========================================\n\nDiscussion thread for these notes can be found at https://github.com/dotnet/roslyn/issues/1677\n\nAgenda\n------\n\nIn this meeting we looked over the top [C# language feature requests on UserVoice](http://visualstudio.uservoice.com/forums/121579-visual-studio/category/30931-languages-c) to see which ones are reasonable to push on further in C# 7.\n\n\n\n1. Non-nullable reference types (*already working on them*)\n2. Non-nullary constructor constraints (*require CLR support*)\n3. Support for INotifyPropertyChanged (*too specific; metaprogramming?*)\n4. GPU and DirectX support (*mostly library work; numeric constraints?*)\n5. Extension properties and static members (*certainly interesting*)\n6. More code analysis (*this is what Roslyn analyzers are for*)\n7. Extension methods in instance members (*fair request, small*)\n8. XML comments (*Not a language request*) \n9. Unmanaged constraint (*requires CLR support*)\n10. Compilable strings (*this is what nameof is for*)\n11. Multiple returns (*working on it, via tuples*)\n12. ISupportInitialize (*too specific; hooks on object initializers?*)\n13. ToNullable (*potentially part of nullability support*)\n14. Statement lambdas in expression trees (*fair request, big feature!*)\n15. Language support for Lists, Dictionaries and Tuples (*Fair; already working on tuples*)\n\nA number of these are already on the table.\n\n\n1\\. Non-nullable reference types\n================================\n\n[http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2320188-add-non-nullable-reference-types-in-c](http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2320188-add-non-nullable-reference-types-in-c)\n\nWe're already working on this; see e.g. #1648.\n\n\n2\\. Non-nullary constructor constraints\n=======================================\n\n[http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2122427-expand-generic-constraints-for-constructors](http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2122427-expand-generic-constraints-for-constructors)\n\nIt is odd that we only support the `new()` constraint for empty parameter lists. In order to generalize this, however, we'd need CLR support to express it - see #420.\n\n\n3\\. Support for INotifyPropertyChanged\n======================================\n\n[http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2255378-inotifypropertychanged](http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2255378-inotifypropertychanged)\n\nThis is too specific an interface to bake in special knowledge for in the language. However, we recognize the pain of having to repeat the boilerplate around this, even as we've improved the situation here a bit with C# 6.\n\nWe think that this may be better addressed with metaprogramming. While we don't have a clear story for how to support this better, in the language or compiler tool chain, we think that Roslyn in and of itself helps here.\n\nWe'll keep watching the space and the specific scenario.\n\n\n4\\. GPU and DirectX support\n===========================\n\n[http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2730068-greatly-increase-support-for-gpu-programming-in-c](http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2730068-greatly-increase-support-for-gpu-programming-in-c)\n[http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/3646222-enable-hlsl-directx-and-graphics-development-tool](http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/3646222-enable-hlsl-directx-and-graphics-development-tool)\n\nThese are mostly library-level requests, independent of the language.\n\nOne feature that could potentially improve such libraries would be the ability to specify generic constraints that somehow express the presence of numeric operators. Being able to write generic methods, say, over anything that has a `+` operator, allowing `+` to be used directly in that method body, would certainly improve the experience of writing such code, and would prevent a lot of repetition.\n\nUnfortunately, like other new constraints, such a numeric constraint facility would require new support from the CLR.\n\n\n5\\. Generalized extension members\n=================================\n\n[http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2242236-allow-extension-properties](http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2242236-allow-extension-properties)\n[http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2060313-c-support-static-extension-methods-like-f](http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2060313-c-support-static-extension-methods-like-f)\n\nThe requests for extension properties and for static extension methods are essentially special cases of a general desire to be able to more generally specify extension member versions of all kinds of function members: properties, indexers, constructors, static members - why not?\n\nThis is a reasonable request. The main problem we have is that the current scheme for extension methods doesn't easily generalize to other kinds of members. We'd need to make some very clever syntactic tricks to do this without it feeling like a complete replacement of the current syntax.\n\nThis is certainly one that we will look at further for C# 7.\n\n\n6\\. More code analysis\n======================\n\n[http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/4428274-improve-code-analysis](http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/4428274-improve-code-analysis)\n\nThis feels like it is best addressed via Roslyn-based analyzers.\n\n\n7\\. Extension methods in non-static classes\n===========================================\n\n[http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/3359397-allow-extension-methods-to-be-defined-in-instance](http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/3359397-allow-extension-methods-to-be-defined-in-instance)\n\nWe were very cautious when we first introduced extension methods, and surrounded them with a lot of restrictions. This is a well argued scenario where allowing them inside instantiable classes would enable a fluent style for private helper methods.\n\nThis seems fair enough, and we could loosen this restriction, though it's probably a relatively low priority work item. \n\n\n8\\. XML comments\n================\n\n[http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2709987-xml-comments-schema-customization-in-c](http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2709987-xml-comments-schema-customization-in-c)\n\nThis is not a language suggestion. \n\n\n9\\. Unmanaged constraint\n========================\n\n[http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/4716089-unmanaged-generic-type-constraint-generic-pointe](http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/4716089-unmanaged-generic-type-constraint-generic-pointe)\n\nThis would be great in order to enable pointers over type parameters. However, it requires CLR support.\n\n\n10\\. Compilable strings\n=======================\n\n[http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/5592955-compliable-strings](http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/5592955-compliable-strings)\n\nThis is mostly addressed by `nameof` in C# 6; it's unlikely there is basis for more language level functionality here.\n\n\n11\\. Multiple returns\n=====================\n\n[http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2083753-return-multiple-values-from-functions-effortlessly](http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2083753-return-multiple-values-from-functions-effortlessly)\n\nWe're already looking at addressing this through tuples.\n\n\n12\\. ISupportInitialize\n=======================\n\n[http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2094881-add-support-for-isupportinitialize-on-object-initi](http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2094881-add-support-for-isupportinitialize-on-object-initi)\n\nThis suggestion addresses the need to perform validation upon initialization. While depending on the ISupportInitialize interface is probably too specific, it is interesting to ponder if there is a way to e.g. hook in after an object initializer has run.\n\n\n13\\. ToNullable\n===============\n\n[http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2531917-structure-all-nullable-values](http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2531917-structure-all-nullable-values)\n\nThis suggestion would add a new operator to make type parameters nullable only if they are not already so.\n\nYou could certainly imagine something like this in conjunction with at least some variations of the nullability proposals we have been discussing lately.\n\n\n14\\. Statement lambdas in expression trees\n==========================================\n\n[http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/4255391-let-lambdas-with-a-statement-body-be-converted-to](http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/4255391-let-lambdas-with-a-statement-body-be-converted-to)\n\nThe language today doesn't allow statement lambdas to be converted to expression trees, despite there being expression tree classes for most features. Moreover, in fact, it disallows several expression forms, including `await` expressions.\n\nThis would be a lovely gap to fill, especially since it would come with no conceptual overhead - more code would just work as expected. However, it is also an enormous feature to take on. We are not sure we have the weight of scenarios necessary to justify taking on the full magnitude of this.\n\nIt is also possible that we'd address a subset.\n\n\n15\\. Language support for Lists, Dictionaries and Tuples\n========================================================\n\n[http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2405699-build-list-dictionary-and-tuple-into-the-language](http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2405699-build-list-dictionary-and-tuple-into-the-language)\n\nWe are already looking at tuples, and we do have it on our radar to consider language syntax for lists and dictionaries in some form. Many shapes of this feature would require a strong commitment to specific BCL types. However, you could also imagine having anonymous expression forms that target type to types that follow a given pattern.\n"
  },
  {
    "path": "meetings/2015/LDM-2015-03-24.md",
    "content": "C# Design Meeting Notes for Mar 24, 2015\n========================================\n\nDiscussion thread on these notes is at https://github.com/dotnet/roslyn/issues/1898.\n\n*Quote of the Day:* If we have slicing we also need dicing!\n\n\nAgenda\n------\n\nIn this meeting we went through a number of the performance and reliability features we have discussed, to get a better reading on which ones have legs. They end up falling roughly into three categories:\n\n* Green: interesting - let's keep looking\n* Yellow: there's something there but this is not it\n* Red: probably not\n\nAs follows:\n\n1. ref returns and locals <*green*> (#118)\n2. readonly locals and parameters <*green*> (#115)\n3. Method contracts <*green*> (#119)\n4. Does not return <*green*> (#1226)\n5. Slicing <*green*> (#120)\n6. Lambda capture lists <*yellow - maybe attributes on lambdas*> (#117)\n7. Immutable types <*yellow in current form, but warrants more discussion*> (#159)\n8. Destructible types <*yellow - fixing deterministic disposal is interesting*> (#161)\n9. Move <*red*> (#160)\n10. Exception contracts <*red*>\n11. Static delegates <*red*>\n12. Safe fixed-size buffers in structs <*red*> (#126)\n\nSome of these were discussed again (see below), some we just reiterated our position.\n\n\n1\\. Ref returns and locals\n==========================\n\nAt the implementation level these would require a verifier relaxation, which would cause problems when down targeting in sandboxing scenarios. This may be fine.\n\nAt the language level, ref returns would have to be allowed on properties and indexers only if they do not have a setter. Setters and ref would be two alternative ways of allowing assignment through properties and indexers. For databinding scenarios we would need to check whether reflection would facilitate such assignment through a ref.\n\nA danger of ref returns in public APIs: say you return a ref into the underlying array of e.g. a list, and the list is grown by switching out the underlying array. Now someone can get a ref, modify the collection, follow the ref and get to the wrong place. So maybe ref returns are not a good thing on public API boundary.\n\nThere's complexity around \"safe to return\": You should only return refs that you received as parameters, or got from the heap. This leads to complexity around allowing reassignment of ref locals: how do you track whether the ref they are pointing to is \"safe to return\" or not? We'd have to either\n\n* add syntax to declare which kind the local points to (complex)\n* allow only one of the kinds to be assigned to locals (restrictive)\n* track it as best we can through flow analysis (magic) \n\nThere's complexity in how refs relate to readonly. You either can't take a ref to a readonly, or you need to be able to express a readonly ref through which assignments is illegal. The latter would need explicit representation in metadata, and ideally the verifier would enforce the difference.\n\nThis can't very well be a C# only feature, at least if it shows up in public APIs. VB and F# would need to at least know about it.\n\nThis feature would be a decent performance win for structs, but there aren't a lot of structs in the .NET ecosystem today. This is a chicken-and-egg thing: because structs need to be copied, they are often too expensive to use. So this feature could lower the cost of using structs, making them more attractive for their other benefits.\n\nEven so, we are still a bit concerned that the scenario is somewhat narrow for the complexity the feature adds. The proof will have to be in the use cases, and we're not entirely convinced about those. It would be wonderful to hear more from the community. This is also a great candidate for a prototype implementation, to allow folks to experiment with usability and performance.\n\n\n2\\. Readonly locals and parameters\n==================================\n\nAt the core this is a nice and useful feature. The only beef we have with it is that you sort of want to use `readonly` to keep your code safe, and you sort of don't because you're cluttering your code. The `readonly` keyword simply feels a bit too long, and it would be nice to have abbreviations at least in some places. \n\nFor instance `readonly var` could be abbreviated to `val` or `let`. Probably `val` reads better than `let` in many places, e.g. declaration expressions. We could also allow `val` as an abbreviation for `readonly` even in non-var situations. \n\nIn Swift they use `let` but it reads strange in some contexts. In Swift it's optional in parameter positions, which helps, but we couldn't have that for back compat reasons.\n\nThis is promising and we want to keep looking at it.\n\n\n4\\. Does Not Return\n===================\n\nIt would be useful to be able to indicate that a method will never return successfully. It can throw or loop.\n\nThe proposal is to do it as an attribute, but there would be more value if it was part of the type system. Essentially it replaces the return type, since nothing of that type is ever returned. We could call it `never`. The `never` type converts to pretty much anything.\n\nThis would allow us to add throw *expressions* in the language - their type would be `never`.\n\nHaving it in the type system allows e.g. returning `Task<never>`, so that you can indicate an async method that will only ever produce an exception, if anything.\n\nBecause of the Task example you do want to allow `never` in generics, but that means you could have generic types that unwittingly operate on never values, which is deeply strange. This needs to be thought about more.\n\nIf through nasty tricks you get to a point in the code that according to never types should not be reachable, the code should probably throw.\n\nA common usage would be helper methods to throw exceptions. But throw as an expression is the most useful thing out of this.\n\n \n6\\. Attributes on lambdas\n=========================\n\nWhy? Guiding an analyzer, e.g. to prevent variable capture. Syntactically it might collide with XML literals in VB.\n\nWe could probably hack it in. The attribute would be emitted onto the generated method.\n\n"
  },
  {
    "path": "meetings/2015/LDM-2015-03-25-Design-Review.md",
    "content": "C# Language Design Review, Mar 25, 2015\n=======================================\n\nDiscussion thread for these notes can be found at https://github.com/dotnet/roslyn/issues/1921.\n\nWe've recently changed gears a little on the C# design team. In order to keep a high design velocity, part of the design team meets one or two times each week to do detailed design work. Roughly monthly the full design team gets together to review and discuss the direction. This was the first such review.\n\n\nAgenda\n------\n\n1. Overall direction\n2. Nullability features\n3. Performance and reliability features\n4. Tuples\n5. Records\n6. Pattern matching\n\n1\\. Overall direction\n=====================\n\nIn these first two months of design on C# 7 we've adopted a mix of deep dive and breadth scouring. There's agreement that we should be ambitious and try to solve hard problems, being willing to throw the result away if it's not up to snuff. We should keep an open mind for a while still, and not lock down too soon on a specific feature set or specific designs.\n\n \n2\\. Nullability features\n========================\n\nNon-nullable types are the number one request on UserVoice. We take it that the *underlying problem* is trying to avoid null reference exceptions. Non-nullable types are at best only part of the solution to this. We'd also need to help prevent access when something is *nullable*.\n\nWe've looked at this over a couple of design meetings (#1303, #1648). Ideally we could introduce non-null types, such as `string!` that are guaranteed never to be null. However, the problems around initialization of fields and arrays, etc., simply run too deep. We can never get to full guarantees.\n\nWe've been mostly looking at implementation approaches that use type erasure, and that seems like a promising approach. \n\nHowever, the thing we need to focus on more is this: when you get a nullability warning from this new feature, how do you satisfy the compiler? If you need to use unfamiliar new language features or significant extra syntax to do so, it probably detracts from the feature.\n\nInstead we should at least consider an flow-based approach, where the \"null-state\" of a variable is tracked based on tests, assignments etc. \n\n``` c#\nif (x == null) return;\n// not null here\n```\n\nIt's an open question how far we would go. Would we track only locals and parameters, or would we also keep track of fields?\n\n``` c#\nif (foo.x == null) ...\n```\n\nThis is more problematic, not just because of the risk of other threads changing the field, but also because other code may have side effects on the field or property.\n\nTypeScript uses information about type guards to track union types in if branches, but it's not full flow analysis, and works only for local variables. Google Closure is more heuristics based, and is happy to track e.g. `foo.bar.baz` style patterns.\n\nA core nuisance with nullability checking is that it raises a wealth of compat questions that limit the design in different ways. There may need to be some sort of opt-in to at least some of the diagnostics you'd get, since you wouldn't want them if you were just recompiling old code that used to \"work\".\n\n\n3\\. Performance and reliability\n===============================\n\nThe list produced at a recent design meeting (#1898) looks sensible.\n\nval / readonly\n--------------\n\nWe should cross check with Scala on their syntax.\n\n\nref return / locals\n-------------------\n\nLots of compexitity - we question whether it is worth the cost?\n\n\nNever type\n----------\n\nThe type system approach is interesting, and allows throw expressions.\n\nMethod contracts\n----------------\n\n`requires` / `ensures`, show up in docs, etc. This looks great. The biggest question is what happens on failure: exceptions? fail fast?\n\n\nSlices\n------\n\nWe got strong feedback that array slices are only interesting if we unify them with arrays. Otherwise there's yet another bifurcation of the world. There's *some* value to have a `Slice<T>` struct type just show up in the Framework. But it really doesn't seem worth it unless it's a runtime feature. That unification is really hard to achieve, and would require CLR support. It's valuable enough to try to pursue even with high likelihood of failure.\n\nSlicing as a language syntax could also be \"overloadable\" - on IEnumerables for instance.\n\nIn Go, if you treat a slice as an object, it gets boxed. \n\n\nLambda capture lists\n--------------------\n\nNot interesting as a feature, but the idea of allowing attributes on lambdas might fly. \n\n\nImmutable types\n---------------\n\nGeneral concern that this doesn't go far enough, is lying to folks, etc. It tries to have strong guarantees that we can't make.\n\nBut a lot of people would appreciate *something* here, so the scenario of immutability should continue to motivate us.\n\n\nDestructible types\n------------------\n\nThe scenario is good, not the current proposal.\n\n\n4\\. Tuple types\n===============\n\nThere's agreement on wanting the feature and on the syntax (#347, #1207).\n\nWe probably prefer a value type version of Tuple\\<T>. Of course those would be subject to tearing, like all structs. We're willing to be swayed.\n\nThere are performance trade offs around allocation vs copying, and also around generic instantiation. We could do some experiments in F# source code, which already has tuples.\n\n\n5\\. Records\n===========\n\nSee #180, #206, #396, #1303, #1572.\n\nIn the current proposal, we should just give up on the ability to name constructor parameters and members differently. The motivation was to be able to upgrade where parameter names start with lower case and member names upper case, but it's not worth the complexity.\n\nShould it have `==` and `!=` that are value based? Clashes a little with the ability to make them mutable.\n\nIf I introduce extra state, then I have to write my own GetHashCode. That seems unfortunate.\n\nAll the gunk today is part of why Roslyn uses XML to generate its data structure. A test of success would be for the Roslyn syntax trees to be concise to write in source code.\n\nA big issue here is incremental non-destructive modification. Roslyn follows the pattern of \"Withers\", a method for each property that takes a new value for that property and returns a new object that's a copy of the old one except for that property. Withers are painfully verbose to declare, and ideally this feature would offer a solution to that.\n\nSerialization has to work *somehow*, even though many of the members will be generated.\n\nWe should not be *too* concerned about the ability to grow up to represent all kinds of things. Start from it being the POD feature, and work from there.\n\n\n6\\. Pattern matching\n====================\n\nSee #180, #206, #1572.\n\nWhether introduced variables are mutable or not is not a key question: we can go with language uniformity or scenario expectation.\n\nIntegral value matching is an opportunity to generalize. The pattern 3 may match the value 3 of all integral types rather than just the int 3.\n\nNamed matching against all objects and positional against ones that define a positional match. Are recursive patterns necessary? No, but probably convenient and there's no reason not to have them.\n\nPattern matching could be shoe-horned into current `switch` statements as well as `is` expressions. And we could have a switching *expression* syntax as well:\n\n``` c#\nvar x = match(e) { p => e, p => e, * => e }\n```\nAn expression version would need to be checked by the compiler for completeness. A little clunky, but much more concise than using a switch.\n\nSimilar to a current pattern in the Roslyn code base:\n\n``` c#\nMatch<T1, T2, TResult>(Func<T1, TResult> f1, Func<T2, TResult> f2) { ... }\nvar x = Match((string s) => e, (int i) => e);\n```\n\nMaybe the fat arrow is not right. We need to decide on syntax. Another option is to use the case keyword instead.\n"
  },
  {
    "path": "meetings/2015/LDM-2015-03-25-Notes.md",
    "content": "C# Design Meeting 2015-03-25\n============================\n\nDiscussion thread for these notes can be found at https://github.com/dotnet/roslyn/issues/1572.\n\nThese are notes that were part of a presentation on 2015-03-25 of a snapshot of our design discussions for C# 7 and VB 15. The features under discussion are described in detail in #206 and elsewhere.\n\n[Records](https://github.com/dotnet/roslyn/issues/206)\n=======\n\nChanges since Semih Okur's work:\n- Remove `record` modifier\n- `with` expressions (#5172)\n- Working on serialization\n\nWorking proposal resembles Scala case classes with active patterns.\n\n------\n\n```cs\nclass Point(int X, int Y);\n```\n\n- defines a class (struct) and common members\n\t- constructor\n\t- `readonly` properties\n\t- GetHashCode, Equals, ToString\n\t- operator== and operator!= (?)\n\t- Pattern-matching decomposition operator\n- an association between ctor parameters and properties\n- Any of these can be replaced by hand-written code\n- Ctor-parameter and property can have distinct names\n\n------\n\n### Use Cases\n- Simplifies common scenarios\n- Simple immutable user-defined data types\n\t- Roslyn Syntax Trees, bound nodes\n- Over-the-wire data\n- Multiple return values\n\n------\n\n### With expressions\n\nIllustrates an example of the value of having parameter-property association.\n\nGiven\n\n```cs\nstruct Point(int X, int Y);\nPoint p = ...\n```\n\nthe expression\n\n```cs\np with { Y = 4 }\n```\n\nis translated to\n\n```cs\nnew Point(p.X, 4)\n```\n\n------\n\n### Open issues\n- Closed hierarchy (and tag fields)\n- Readonly\n- Parameter names\n- Can you opt out of part of the machinery?\n- Serialization (in all of its forms)\n- Construction and decomposition syntax\n\n------\n\n[Pattern Matching](https://github.com/dotnet/roslyn/issues/206)\n================\n\n### Sources of Inspiration\n- Scala\n- F#\n- Swift\n- Rust\n- Erlang\n- Nemerle\n\n------\n\n### A pattern-matching operation\n- Matches a *value* with a *pattern*\n- Either *succeeds* or *fails*\n- Extracts selected values into *variables*\n\n```cs\n    object x = ...;\n    if (x is 3) ...\n\tif (x is string s) ...\n\tif (x is Point { X is 3, Y is int y }) ...\n    if (x is Point(3, int y)) ...\n```\n\n------\n\n### Other aspects\n- Patterns defined recursively\n- \"select\" from among a set of pattern forms\n- Typically an expression form\n- *active patterns* support interop and user-defined types\n\n```cs\nswitch (o)\n{\n    case 3:\n\t\t...\n\t\tbreak;\n\tcase string s:\n\t\tM(s);\n\t\tbreak;\n\tcase Point(3, int y):\n\t\tM(y);\n\t\tbreak;\n\tcase Point(int x, 4):\n\t\tM(x);\n\t\tbreak;\n}\n```\n\nWe think we want an expression form too (no proposed syntax yet, but for inspiration):\n\n```cs\n   M(match(e) {\n\t\t3 => x,\n\t\tstring s => s.foo,\n\t\tPoint(3, int y) => y,\n\t\t* => null })\n```\n\n------\n\n### Benefits\n- Condenses long sequences of complex logic with a test that resembles the shape of the thing tested\n\n### Use Cases\n- Simplifies common scenarios\n- Language manipulation code\n\t- Roslyn\n\t- Analyzers\n- Protocol across a wire\n\n------\n\n### Open questions\n- How much of the pattern-matching experience do we want (if any)?\n- Matching may be compiler-checked for completeness\n- May be implemented using tags instead of type tests\n- Which types have syntactic support?\n\t- Primitives and string\n\t- Records\n\t- Nullable\\<T>\n\t- objects with properties\n\t- anonymous types?\n\t- arrays?\n\t- List? Dictionary?\n\t- Tuple<...>?\n\t- IEnumerable\\<T>?\n"
  },
  {
    "path": "meetings/2015/LDM-2015-04-01-08.md",
    "content": "C# Design Meeting Notes for Apr 1 and Apr 8, 2015\n=================================================\n\nDiscussion thread for these notes is at https://github.com/dotnet/roslyn/issues/2119.\n\nAgenda\n------\n\nMatt Warren wrote a Roslyn analyzer as a low cost way to experiment with nullability semantics. In these two meetings we looked at evolving versions of this analyzer, and what they imply for language design.\n\nThe analyzer is here: https://github.com/mattwar/nullaby.\n\n\n\nFlow-based nullability checking\n===============================\n\nAt the design review on Mar 25 (#1921), there was strong support for adding nullability support to the language, but also the advice to make it easy to transition into using nullability checking by recognizing current patterns for null checking.\n\nThis suggests a flow-based approach, where the \"null state\" of variables is tracked by the compiler, and may be different in different blocks of code. Comparisons of the variable, and assignments to the variable, would all change its null state within the scope of effect of those operations.\n\nAn inherent danger with flow-based checks like that is that a variable may change in an untracked way. The risk of that for parameters and local variables is limited: the variable would have to be captured and modified by a lambda, and that lambda would have to be executed elsewhere *during* the running of the current function. Given that any null-checking machinery we build would have to be somewhat approximate anyway, we can probably live with this risk.\n\nIt gets gradually worse if we try to track fields of `this` or other objects, or even properties or array elements. In all likelihood, tracking just parameters and local variables would deliver the bulk of the value, but at least \"dotted chains\" would certainly also be useful.\n\n\n\nAttributes versus syntax\n========================\n\nThe analyzer makes use of attributes to denote when a variable is \"nullable\" (`[CouldBeNull]`) or \"non-nullable\" (`[ShouldNotBeNull]`). Compared to a built-in syntax, this has several disadvantages:\n\n* It's less syntactic convenient of course\n* The attribute cannot be applied to local variables\n* The attribute cannot be applied to a type argument or an array element type\n\nThese limitations are inherent to the nature of the experiment, but we know how to counter them if we add language syntax, even if that syntax is encoded with the use of attributes. (We learned all the tricks when we introduced `dynamic`.)\n\n\n\nAnalyzers versus built-in rules\n===============================\n\nProviding nullability diagnostics by means of an analyzer comes with a number of pros and cons compared to having those diagnostics built in to the language.\n\n* Language rules need to be clearly specified and reasonable to explain. An analyzer can employ more heuristics.\n* Language-based diagnostics need to consider back compat for the language, whereas analyzers can introduce warnings on currently valid code.\n* For the same reason, analyzers can evolve over time\n* With an analyzer, individual rules can be turned on and off. Some may want a harsher medicine than others. With the language it has to be one size fits all.\n\nOn the other hand:\n\n* Rules can probably be implemented more efficiently in the compiler itself (though we might be able to come up with tricks to deal with that for analyzers too)\n* The language has an opportunity to standardize what exactly is allowed\n* The rules would still apply in contexts where analyzers aren't run\n* It would be odd to add `!` and `?` syntax to the language, without adding the accompanying semantics\n* We could avoid many issues with back compat if we adopt the notion of \"warning waves\" (#1580), where later versions of the language can add new warnings.\n\nThe analyzer has several shortcomings due to the lack of a public flow analysis API in Roslyn. That would be a great addition, regardless of what we do for nullability checking.\n\nWith a cruder/simpler analysis built-in to the language, you can imagine folks building enhancement analyzers on top of it. Those may not just add new diagnostics, but might want to *turn off* compiler warnings where more heuristics can determine that they are in fact not warranted. The analyzer infrastructure doesn't currently support this.\n\n\n\nTaking the analyzer for a spin\n==============================\n\nGiven the following declaration\n\n``` c#\nvoid Foo([ShouldNotBeNull] string s) { }\n```\n\nThe following statements would yield warnings because `s` is declared to be nullable, but is used in a way that requires it not to be:\n\n``` c#\nvoid Bad([CouldBeNull] string s)\n{\n    Foo(s);           // Warning!\n    var l = s.Length; // Warning!\n}\n```\n\nHowever, all the following methods are ok, because the flow analysis can determine that `s` is not null at the point where it is used:\n \n``` c#\nvoid Ok1([CouldBeNull] string s)\n{\n    s = \"Not null\";\n    Foo(s); // Ok\n}\nvoid Ok2([CouldBeNull] string s)\n{\n    if (s != null)\n    {\n        Foo(s); // Ok\n    }\n}\nvoid Ok3([CouldBeNull] string s)\n{\n    if (s == null)\n    {\n        throw new ArgumentNullException();\n    }\n    Foo(s); // Ok\n}\nvoid Ok4([CouldBeNull] string s)\n{\n    if (s == null)\n    {\n        s = \"NotNull\";\n    }\n    Foo(s); // Ok\n}\nvoid Ok5([CouldBeNull] string s)\n{\n    if (s != null && s.Length > 0) // Ok\n    {\n    }\n}\nvoid Ok6([CouldBeNull] string s)\n{\n    if (s == null || s.Length > 0) // Ok\n    {\n    }\n}\n```\n\nThis seems hugely useful, because current code will just continue to work in the vast majority of cases.\n\nIt is a change of thinking from where nullability is strongly part of the *type* of a variable, and is established at declaration time. In that paradigm, establishing that a given variable is not null doesn't help you; you have to capture its value in a new, more strongly typed variable, which is more cumbersome, and which would require existing code to be extensively rewritten to match new patterns.\n\n\n\nConclusion\n==========\n\nMatt's experiment is great, and we are very interested in the nullability tracking approach, because it has the potential to make the bulk of existing code work in the face of new annotations.\n"
  },
  {
    "path": "meetings/2015/LDM-2015-04-14.md",
    "content": "C# Design Meeting Notes for Apr 14, 2015\n========================================\n\nDiscussion thread for these notes can be found at https://github.com/dotnet/roslyn/issues/2134.\n\nBart De Smet visited from the Bing team to discuss their use of Expression Trees, and in particular the consequences of their current shortcomings.\n\nThe Expression Tree API today is not able to represent all language features, and the language supports lambda conversions even for a smaller subset than that.\n\n\n\nBackground\n==========\n\nCertain Bing services, such as parts of Cortana, rely on shipping queries between different machines, both servers in the cloud and client devices.\n\nIn a typical scenario a lambda expression tree is produced in one place, ideally via the conversion from lambda expressions to expression trees that exists in C#. The expression tree is then serialized using a custom serialization format, and sent over the wire. At the receiving end it will often be stitched into a larger expression tree, which is then compiled with the `Compile` method and executed.\n\nAlong the way, several transformations are often made on the trees, for efficiency reasons etc. For instance, rather than invoke a lambda its body can often be inlined in the enclosing tree that the lambda gets stitched into.\n\nThe serialization format is able to carry very specific type information along with the code, but can also represent the code loosely. A looser coupling makes for code that is more resilient to \"schema\" differences between the nodes, and also allows for use of types and functions that aren't present where the lambda is concocted. However, it also makes it harder to stitch things back up right on the other side.\n\n\n\nShortcomings in the Expression Tree API\n=======================================\n\nThe expression tree API was introduced with Linq and C# 3.0, and was extended to support the implementation infrastructure of `dynamic` along with C# 4.0. However, it has not been kept up to date with newer language features.\n\nThis is a list of ones that are confounding to the Bing team.\n\n\nDynamic\n-------\n\nEven though the API was extended for the benefit of the dynamic feature, the feature itself ironically is not well represented in the API. This is not a trivial undertaking: in Expression Trees today, all invoked members are represented using reflection structures such as `MemberInfo`s etc. Dynamic invocations would need a completely different representation, since they are by definition not bound by the time the expression tree is produced.\n\nIn the Bing scenario, dynamic would probably help a lot with representing the loosely coupled invocations that the serialization format is able to represent.\n\nAlternatively, if the C# language added something along the \"lightweight dynamic\" lines that were discussed (but ultimately abandoned) for C# 6, the representation of that in Expression Trees would probably yield similar benefit with a fraction of the infrastructure.\n\n\nAwait\n-----\n\nRepresenting await would probably be easy in the Expression Tree API. However, the implementation of it in `Expression.Compile` would be just as complex as it is in the C# and VB compilers today. So again, this is a significant investment, though one with much less public surface area complexity than `dynamic`.\n\nNeedless to say, distributed scenarios such as that of Bing services have a lot of use for `await`, and it can be pretty painful to get along without it.\n\n\nNull conditional operators and string interpolation\n---------------------------------------------------\n\nThese should also be added as Expression Tree nodes, but could probably be represented as reducible nodes. Reducible nodes are a mechanism for describing the semantics of a node in terms of reduction to another expression tree, so that the `Compile` method or other consumers don't have to know about it directly.\n\n\nHigher level statements\n-----------------------\n\nWhile expression trees have support for statements, those tend to be pretty low level. Though there is a `loop` node there are no `for` or `foreach` nodes. If added, those again could be reducible nodes.\n\n\n\nShortcomings in the languages\n=============================\n\nC# and VB are even more limited in which lambdas can be converted to expression trees. While statements are part of the Expression Tree API, the languages will not convert them. Also, assignment operators will not be converted.\n\nThis is a remnant of the first wave of Linq, which focused on allowing lambdas for simple, declarative queries, that could be translated to SQL.\n\nThere has traditionally been an argument against adding more support to the languages based on the pressure this would put on existing Linq providers to support the new nodes that would start coming from Linq queries in C# and VB.\n\nThis may or may not ever have been a very good argument. However, with Roslyn analyzers now in the world, it pretty much evaporates. Any Linq provider that wants to limit at design time the kinds of lambdas allowed, can write a diagnostic analyzer to check this, and ship it with their library.\n\nNone of this support would require new syntax in the language, obviously. It is merely a matter of giving fewer errors when lambdas are converted to expression trees, and of mapping the additional features to the corresponding nodes in what is probably a straightforward fashion.\n\n\n\nConclusion\n==========\n\nThere is no remaining design reason we can think of why we shouldn't a) bring the Expression Tree API up to date with the current state of the languages, and b) extend the language support accordingly.\n\nThe main issue here is simply that it is likely to be a huge undertaking. We are not sure that the sum of the scenarios will warrant it, when you think about the opportunity cost for other language evolution. Bing is a very important user, but also quite probably an atypical one.\n\nSo in summary, as a language design team, we certainly support completing the picture here. But with respect to priorities, we'd need to see a broader call for these improvements before putting them ahead of other things.\n"
  },
  {
    "path": "meetings/2015/LDM-2015-04-15.md",
    "content": "C# Design Meeting Notes for Apr 15, 2015\n========================================\n\nDiscussion thread for these notes is at https://github.com/dotnet/roslyn/issues/2133.\n\nAgenda\n------\n\nIn this meeting we looked at nullability and generics. So far we have more challenges than solutions, and while we visited some of them, we don't have an overall approach worked out yet.\n\n1. Unconstrained generics\n2. Overriding annotations\n3. FirstOrDefault\n4. TryGet\n\n\nUnconstrained generics\n======================\n\nFitting generics and nullability together is a delicate business. Let's look at unconstrained type parameters as they are today. One the one hand they allow access to members that are on all objects - `ToString()` and so on - which is bad for nullable type arguments. On the other hand they allow `default(T)` which is bad for non-nullable type arguments.\n\nNevertheless it seems draconian to not allow instantiations of unconstrained type parameters with, say, `string?` and `string!`. We suspect that most generic types and methods probably behave pretty nicely in practice.\n\nFor instance, `List<T>`, `Dictionary<T>` etc. would certainly have internal  data structures - arrays - that would have the default value in several places. However, their logic would be written so that no array element that hadn't explicitly been assigned a value from the user would ever expose its default value later. So if we look at a `List<string!>` we wouldn't actually ever see nulls come out as a result of the internal array having leftover nulls from its initial allocation. No nulls would come in, and therefore no nulls would come out. We want to allow this.\n\n\nOverriding annotations\n======================\n\nWhen type parameters are known to be reference types it may make sense to allow overriding of the nullability of the type parameter: `T?` would mean `sting?` regardless of whether the type argument was `string!`, `string` or `string?`.\n\nThis would probably help in some scenarios, but with most generics the type parameter isn't actually known to be a reference type.\n\n\nFirstOrDefault\n==============\n\nThis pattern explicitly returns a default value if the operation fails to find an actual value to return. Obviously that is unfortunate if the element type is non-nullable - you'd still get a null out!\n\nIn practice, such methods tend to be so glaringly named (precisely because their behavior is a little funky) that most callers would probably already be wary of the danger. However, we might be able to do a little better.\n\nWhat if there was some annotation you could put on `T` to get the nullable version *if* `T` should happen to be a reference type. Maybe the situation is rare enough for this to just be an attribute, say `[NullableIfReference]`:\n\n``` c#\npublic [return:NullableIfReference] T FirstOrDefault<T>(this IEnumerable<T> src)\n{\n    if ...\n    else return default(T);\n}\n```\n\nApplied to `List<string!>` (or `List<string>`) this would return a `string?`. But applied to `List<int>` it would return an `int` not an `int?`.\n\nThis seems perfectly doable, but may not be worth the added complexity.\n\n\nTryGet\n======\n\nThis pattern has a bool return value signaling whether a value was there, and an out parameter for the result, which is explicitly supposed to be default(T) when there was no value to get:\n\n``` c#\npublic bool TryGet(out T result) { ... }\n```\n\nOf course no-one is expected to ever look at the out parameter if the method returns false, but even so it might be nice to do something about it.\n\nThis is not a situation where we want to apply the `[NullableIfReference]` attribute from above. The consumer wants to be able to access the result without checking for null if they have already checked the returned bool!\n\nWe could imagine another attribute, `[NullableIfFalse]` that would tell the compiler at the consuming site to track nullability based on what was returned from the method, just as if there had been a null check directly in the code.\n\nAgain, this might not be worth the trouble but is probably doable.\n"
  },
  {
    "path": "meetings/2015/LDM-2015-04-22-Design-Review.md",
    "content": "# C# Language Design Review, Apr 22, 2015\n\nDiscussion for these notes can be found at https://github.com/dotnet/roslyn/issues/3910.\n\n## Agenda\n\nSee #1921 for an explanation of design reviews and how they differ from design meetings.\n\n1. Expression tree extension\n2. Nullable reference types\n3. Facilitating wire formats\n4. Bucketing\n\n\n# Expression Trees\n\nExpression trees are currently lagging behind the languages in terms of expressiveness. A full scale upgrade seems like an incredibly big investment, and doesn't seem worth the effort. For instance, implementing `dynamic` and `async` faithfully in expression trees would be daunting.\n\nHowever, supporting `?.` and string interpolation seems doable even without introducing new kinds of nodes in the expression tree library. We should consider making this work.\n\n\n# Nullable reference types\n\nA big question facing us is the \"two-type\" versus the \"three-type\" approach: We want you to guard member access etc. behind null checks when values are meant to be null, and to prevent you from sticking or leaving null in variables that are not meant to be null. In the \"three-type\" approach, both \"meant to be null\" and \"not meant to be null\" are expressed as new type annotations (`T?` and `T!` respectively) and the existing syntax (`T`) takes on a legacy \"unsafe\" status. This is great for compatibility, but means that the existing syntax is unhelpful, and you'd only get full benefit of the nullability checking by completely rooting out its use and putting annotations everywhere.\n\nThe \"two-type\" approach still adds \"meant to be null\" annotations (`T?`), but holds that since you can now express when things *are* meant to be null, you should only use the existing syntax (`T`) when things are *not* meant to be null. This certainly leads to a simpler end result, and also means that you get full benefit of the feature immediately in the form of warnings on all existing unsafe null behavior! Therein of course also lies the problem with the \"two-type\" approach: in its simplest form it changes the meaning of unannotated `T` in a massively breaking way.\n\nWe think that the \"three-type\" approach is not very helpful, leads to massively rewritten over-adorned code, and is essentially not viable. The \"two-type\" approach seems desirable if there is an explicit step to opt in to the enforcement of \"not meant to be null\" on ordinary reference types. You can continue to use C# as it is, and you can even start to add `?` to types to force null checks. Then when you feel ready you can switch on the additional checks to prevent null from making it into reference types without '?'. This may lead to warnings that you can then either fix by adding further `?`s or by putting non-null values into the given variable, depending on your intent.\n\nThere are additional compatibility questions around evolution of libraries, but those are somewhat orthogonal: Maybe a library carries an assembly-level attribute saying it has \"opted in\", and that its unannotated types should be considered non-null.\n\nThere are still open design questions around generics and library compat.\n\n\n# Wire formats\n\nWe should focus attention on making it easier to work with wire formats such as JSON, and in particular on how to support strongly typed logic over them without forcing them to be deserialized to strongly typed objects at runtime. Such deserialization is brittle, lossy and clunky as formats evolve out of sync, and extra members e.g. aren't kept and reserialized on the other end.\n\nThere's a range of directions we could take here. Assuming there are dictionary-style objects representing the JSON (or other wire data) in a weakly typed way, options include:\n\n* Somehow supporting runtime conversions from such dictionaries to interfaces (and back)\n* Compile-time only \"types\" a la TypeScript, which translate member access etc. to a well-known dictionary pattern\n* Compile-time type providers a la F#, that allow custom specification not only of the compile-time types but also the code generated for access.\n\nWe'd need to think about construction, not just consumption.\n\n``` c#\nvar thing = new Thing { name = \"...\", price = 123.45 }\n```\n\nMaybe `Thing` is an interface with an attribute on it:\n\n``` c#\n[Json] interface { string name; double price; }\n```\n\nOr maybe it is something else. This warrants further exploration; the right feature design here could be an extremely valuable tool for developers talking to wire formats - and who isn't?\n\n# Bucketing\n\nWe affirmed that the bucketing in issue #2136 reflects our priorities."
  },
  {
    "path": "meetings/2015/LDM-2015-05-20.md",
    "content": "C# Design Meeting Notes for May 20, 2015\n========================================\n\nDiscussion for this issue can be found at https://github.com/dotnet/roslyn/issues/3911.\n\n_Quote of the day:_ The slippery slope you are talking about is that if we satisfy our customers they'll want us to satisfy them some more.\n\n\nAgenda\n------\n\nToday we discussed whether and how to add local functions to C#, with the aim of prototyping the feature in the near future. Proposal at issue #259. Some details are discussed in issue #2930.\n\n1. Local functions\n\n\n\nLocal Functions\n===============\n\nWe agree that the scenario is useful. You want a helper function. You are only using it from within a single function, and it likely uses variables and type parameters that are in scope in that containing function. On the other hand, unlike a lambda you don't need it as a first class object, so you don't care to give it a delegate type and allocate an actual delegate object. Also you may want it to be recursive or generic, or to implement it as an iterator.\n\n\nLambdas or local functions?\n---------------------------\n\nThere are two ways of approaching it:\n\n* Make lambdas work for this\n* Add local function syntax to the language\n\nOn the face of it, this seems like it would be better to reuse an existing feature. After all, we are not looking to address a new problem but just make existing code more convenient to write. In VB this scenario works pretty nicely with lambdas already - can't we just take a page out of VB's book?\n\nWell, it turns out you need a plethora of little features to achieve the full effect with lambdas:\n\n* lambdas would need to have an intrinsic (compiler-generated) delegate type that we can infer for them when they are not target typed to a specific delegate type:\n\n``` c#\nvar f = (int x) => x * x; // infers a compiler generated delegate type for int -> int.\n```\n\n* lambdas need to be able to recursively call themselves through a variable name they get assigned to. This introduces a problem with inferring a return type:\n\n``` c#\nvar f = (int x, int c) => c = 0 ? x : f(x) * x; // can we reasonably infer a return type here?\nvar f = (int x, int c) => (int)(c = 0 ? x : f(x) * x); // or do we need to cast the result?\n```\n\n* lambdas need to be able to be iterators. Since they don't have a specified return type, how can we know if the iterator is supposed to be `IEnumerable<T>`, `IEnumerator<T>`, `IEnumerable` or `IEnumerator`?\n\n``` c#\nvar f = (int x, int c) => { for (int i = 0; i < c; i++) { yield return x; } }; // default to IEnumerable<T>?\n```\n\n* We'd want lambdas to be generic. What's the syntax for a generic lambda - where do the type parameters go? Presumably in front of the parameter list? And wait a minute, we don't even have a notion of delegate types for generic functions!\n\n``` c#\nvar f = <T>(IEnumerable<T> src) => src.FirstOrDefault(); // Is this unambiguous? What's the delegate type?\n```\n\nVB does a subset of these, probably enough to get by, but all in all for C# it seems both the better and easier path to simply let you define a function in method scope.\n\nOn top of this is the performance aspect: the lambda approach implies a lot of allocations: one for the delegate and one for the closure object to capture surrounding variables and type parameters. \n\nSometimes one or both of these can be optimized away by a clever compiler. But with functions, the delegate is never there (unless you explicitly decide to create one when you need it), and if the function itself is not captured as a delegate, the closure can be a struct on the stack.\n\n**Conclusion**: Local functions are the better choice. Let's try to design them.\n\n\nSyntax\n------\n\nThe syntax of a local functions is exactly as with a method, except that it doesn't allow the syntactic elements that are concerned  with it being a member. More specifically: \n\n* No attributes\n* No modifiers except `async` and `unsafe`\n* The name is always just an identifier (not `Interface.MemberName`)\n* The body is never just `;` (always `=> ...` or `{ ... }`)\n\nWe'll consider *local-function-declaration* to be a third kind of *declaration-statement*, next to *local-variable-declaration* and *local-constant-declaration*. Thus it can appear as a statement at the top level of a block, but cannot in itself be e.g. a branch of an if statement or the body of a while statement.\n\nLocal functions need to be reconciled with top level functions in script syntax, so that they work as similarly as possible. Nested local functions in blocks, just like nested local variables, would truly be local functions even in script.\n\n\nExamples\n-------- \n\nA classical example is that of doing argument validation in an iterator function. Because the body of an iterator method is executed lazily, a wrapper function needs to do the argument checking. The actual iterator function can now be a local function, and capture all the arguments to the wrapper function:\n\n``` c#\npublic static IEnumerable<T> Filter<T>(IEnumerable<T> source, Func<T, bool> predicate)\n{\n    if (source == null) throw new ArgumentNullException(nameof(source));\n    if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n    IEnumerable<T> Iterator()\n    {\n        foreach (var element in source)\n        if (predicate(element))\n        yield return element;\n    }\n    return Iterator();\n}\n\n```\n\nAn example of a recursive local function would be a Quicksort, for instance:\n\n``` c#\npublic static void Quicksort<T>(T[] elements) where T : IComparable<T>\n{\n    void Sort(int start, int end)\n    {\n        int i = start, j = end;\n        var pivot = elements[(start + end) / 2];\n\n        while (i <= j)\n        {\n            while (elements[i].CompareTo(pivot) < 0) i++;\n            while (elements[j].CompareTo(pivot) > 0) j--;\n            if (i <= j)\n            {\n                T tmp = elements[i];\n                elements[i] = elements[j];\n                elements[j] = tmp;\n                i++;\n                j--;\n            }\n        }\n        if (start < j) Sort(elements, start, j);\n        if (i < end) Sort(elements, i, end);\n    }\n\n    Sort(elements, 0, elements.Length - 1);\n}\n```\n\nAgain it captures parameters and type parameters of the enclosing method, while calling itself recursively.\n\nFor optimization purposes, some async methods are implemented with a \"fast path\" where they don't allocate a state machine or a resulting `Task` unless they discover that it's necessary. These aren't themselves `async`, but can have a nested local async function that they call when necessary, returning the resulting `Task`. Something along the lines of:\n\n``` c#\npublic Task<byte> GetByteAsync()\n{\n    async Task<byte> ActuallyGetByteAsync()\n    {\n        await buffer.GetMoreBytesAsync();\n        byte result;\n        if (!buffer.TryGetBufferedByte(out result)) throw ...; // we just got more\n        return result;\n    }\n\n    byte result;\n    if (!buffer.TryGetBufferedByte(out result)) return ActuallyGetByteAsync(); // slow path\n\n    if (taskCache[result] == null) taskCache[result] = Task.FromResult(result);\n    return taskCache[result];\n}\n```\n\nBy the way, we just did `taskCache[result]` three times there in the last two lines, each with its own bounds check. We could maybe optimize a little with a local function taking a ref:\n\n``` c#\n    Task<byte> GetTask(ref Task<byte> cache)\n    {\n        if (cache == null) cache = Task.FromResult(result);\n        return cache;\n    }\n    return GetTask(ref taskCache[result]); // only indexing once\n```\n\nOf course if we *also* add ref locals to the language, such trickery would not be necessary.\n\n\nScope and overloading\n---------------------\n\nIn various ways we need to choose whether local functions are more like methods or more like local variables:\n\n* Local variables only allow one of a given name, whereas methods can be overloaded\n* Local variables shadow anything of the same name in outer scopes, whereas method lookup will keep looking for applicable methods\n* Local variables are not visible (it is an error to use them) before their declaration occurs, whereas methods are.\n\nThere are probably scenarios where it would be useful to overload local functions (or at least more elegant not to have to give them all separate names). You can also imagine wanting to augment a set of existing overloads with a few local ones. \n\nHowever, it is somewhat problematic to allow local functions to be visible before their declaration: they can capture local variables, and it would provide an easy loophole for manipulating those variables before their declaration:\n\n``` c#\nf(3);\nint x; // x is now 3!\nvoid f(int v) { x = v; }\n```\n\nSuch pre-declaration manipulation is certainly possible today, but it requires more sneaky use of lambdas or goto statements, e.g.:\n\n``` c#\n    goto Assign;\nBefore:\n    goto Read;\nDeclare:\n    int x = 5;\n    goto Read;\nAssign:\n    x = 3;\n    goto Before;\nRead:\n    WriteLine(x);\n    if (x == 3) goto Declare;\n```\n\nThis prints 3 and 5. Yeah, yuck. We should think twice before we allow local functions to make this kind of thing so much easier that you might likely do it by mistake.\n\nOn the other hand, there's no nice way to write mutually recursive local functions, unless the first can also see the second. (The workaround would be to nest one within the other, but that's horrible).\n\nFor now, for prototyping purposes, we'll say that local functions are more like local variables: there can only be one of a given name, it shadows same-named things in outer scopes, and it cannot be called from a source location that precedes its declaration. We can consider loosening this later.\n\nDefinite assignment analysis of locals captured by local functions should be similar to lambdas for now. We can think of refining it later.\n\n\nType inference\n--------------\n\nLambdas have a mechanism for inferring their return type. It is used for instance when a lambda is passed to a generic method, as part of that generic method's type inference algorithm.\n\nWe could allow local functions to be declared with `var` as their return type. Just as `var` on local variables doesn't always succeed, we could fail whenever finding the return type of the local function is too hard; e.g. if it is recursive or an iterator.\n\n``` c#\nvar fullName(Person p) => $\"{p.First} {p.Last}\"; // yeah, it's probably going to be a string.\n```\n\nWe don't need this for prototyping, but it is nice to consider for the final design of the feature.\n\n\nDeclaration expressions\n-----------------------\n\nOne thing lambdas have going for them is that they can be embedded in expression contexts, whereas local declarations currently can't, though we had a proposal for declaration expressions in C# 6. If we were to do some sort of let expressions, local functions should ideally work alongside local variables. The proposed C# 6 scheme would work for that:\n\n``` c#\nreturn (IEnumerable<T> Impl() { ... yield return ... }; Impl()); // Or no semicolon?\n```\n\nWhy would you do that? For encapsulation, but especially if you're in a big expression context where pulling it out is too far. Imagine a string-interpolated JSON literal that has an array inside it that I want to construct with an iterator:\n\n``` c#\nreturn $@\"\"\"hello\"\": \"\"world\"\"\n          ... // 30 lines of other stuff\n          \"\"list\"\" : { (\n              IEnumerable<int> GetValues() {\n                  ... yield return ...\n              };\n              JsonConvert.SerializeObject(GetValues())) }\";\n```\n\nWe don't have to think about this now, but it is nice to know that it's possible if we ever do declaration expressions to include local functions as one of the things you can declare in an expression context.\n\n\nSlippery slope\n--------------\n\nLocal classes might be the next ask, but we perceive them as much less frequent, and other features we're discussing would make them even less so.\n"
  },
  {
    "path": "meetings/2015/LDM-2015-05-25.md",
    "content": "# C# Design Meeting Notes for May 25, 2015\n\nDiscussion for these notes can be found in https://github.com/dotnet/roslyn/issues/3912.\n\n## Agenda\n\nToday we went through a bunch of the proposals on GitHub and triaged them for our list of features in issue #2136. Due to the vastness of the list, we needed to use *some* criterion to sort by, and though far from ideal we ordered them by number of comments, most to least.\n\nHere's where we landed, skipping things that were already \"Strong interest\". Some are further elaborated in sections below.\n\n1. Method contracts <*Stay at \"Some interest\"*>(#119)\n2. Destructible types <*Stay at \"Probably never\"*> (#161)\n3. Params IEnumerable <*Stay at \"Small but Useful*>(#36)\n4. Multiple returns <*Addressed by tuples. Close.*> (#102)\n5. More type inference <*Not a coherent proposal. Close*> (#17)\n6. Readonly parameters and locals <*Stay at \"Some interest\"*>(#115)\n7. Implicitly typed lambdas <*Add at \"Probably never\"*>(#14)\n8. Immutable types <*Stay at \"Some interest*>(#159)\n9. Object initializers for immutable objects <*Add at \"Some interest\"*>(#229)\n10. First item is special <*Add at \"Never\"*>(#131)\n11. Array slices <*Keep at \"Interesting but needs CLR support\"*>(#120)\n12. Vararg calling convention <*Merge with params IEnumerable*>(#37)\n13. XML Literals <*Add to \"Never\"*>(#1746)\n14. Local Functions <*Move to \"Some interest*>(#259)\n15. Covariant returns <*Stay at \"Some interest*>(#357)\n\n# Params IEnumerable\n\nThis needs more thinking - let's not just implement the straightforward design. There are perf issues, for instance, around implementing through the `IEnumerable<T>` interface instead of arrays directly.\n\n# More type inference\n\nNot a coherent proposal. But even if there was one, we probably wouldn't want it in C#.\n\n# Implicitly typed lambdas\n\nThese are mostly subsumed by local functions, which we'd rather do. It has some individual usefulness but not much synergy.\n\n# Object initializers for immutable objects\n\nWe want to think this together with withers, not sure what form it would take.\n\n# first item in loops is special\n\nWe recognize the scenario but it's not worthy of a feature.\n\n# vararg calling convention\n\nRoll it in with params IEnumerable discussion for investigation.\n\n# XML literals\n\nNever! We won't bake in a specific format.\n\n"
  },
  {
    "path": "meetings/2015/LDM-2015-07-01.md",
    "content": "# C# Design Meeting Notes for Jul 1, 2015\n\nDiscussion for these notes can be found at https://github.com/dotnet/roslyn/issues/3913.\n\n## Agenda\n\nWe are gearing up to prototype the tuple feature, and put some stakes in the ground for its initial design. This doesn't mean that the final design will be this way, and some choices are arbitrary. We merely want to get to where a prototype can be shared with a broader group of C# users, so that we can gather feedback and learn from it.\n\n# Tuples\n\nThe tuples proposal #347 is pretty close to what we want, but has some open questions and unaddressed aspects.\n\n## Names\n\nWe want the elements of tuples to be able to have names. It is exceedingly useful to be able to describe which elements have which meaning, and to be able to dot into a tuple with those names.\n\nHowever, it is probably not useful to make the names too strongly a part of the type of a tuple. There is no really good reason to consider (int x, int y) an fundamentally different tuple type than (int a, int b). In fact, according to the analogy with parameter lists, the names should be of secondary importance: useful for getting at the elements, yes, but just as parameter lists with different parameter names can overwrite each other, as long as the types match at the given parameter positions, so should tuple types be considered equivalent when they have the same types at the same positions.\n\nAnother way to view it is that all tuples with the same types at the same positions share a common underlying type. We will make that type denotable in the language, in that you can write anonymous tuple types, `(int, int)`, even though you cannot write an anonymous parameter list.\n\nFor now we don't think we will allow partially named tuples: it is either all names or none.\n\n``` c#\n(int x, int y) t1 = ...;\n(int a, int b) t2 = t1; // identity conversion\n(int, int) t3 = t1;     // identity conversion\n```\n\nAll \"namings\" of a tuple type are considered equivalent, and are convertible to each other via an identity conversion. For type inference purposes, an inferred tuple type will have the names if all \"candidate types\" with names agree on them, otherwise it will be unnamed.\n\n``` c#\nvar a1 = new[]{ t1, t1 }; // infers (int x, int y)[], since all agree\nvar a2 = new[]{ t1, t2 }; // infers (int, int)[], since not all agree\nvar a3 = new[]{ t1, t3 }; // infers (int x, int y)[] since all with names agree\n```\n\nFor method overriding purposes, a tuple type in a parameter or return position can override a differently named tuple type. The rule for which names apply at the call site are the same as those used for named arguments: the names from the most specific statically known overload.\n\nTuple literals likewise come in named an unnamed versions. They can be target typed, but sometimes have a type of their own:\n\n``` c#\nvar t1 = (\"Hello\", \"World\");           // infers (string, string)\nvar t2 = (first: \"John\", last: \"Doe\"); // infers (string first, string last)\nvar t3 = (\"Hello\", null);              // fails to infer because null doesn't have a type\nvar t4 = (first: \"John\", last: null);  // fails to infer because null doesn't have a type\n\n(string, string) t5 = (\"Hello\", null);                           // target typed to (string, string)\n(string first, string last) t6 = (\"John\", null);                 // target typed to (string first, string last)\n(string first, string last) t7 = (first: \"John\", second: \"Doe\"); // error: when given, names must match up\n(string first, string last) t8 = (last: \"Doe\", first: \"John\");   // fine, values assigned according to name\n```\n\nThe last two are probably the only possibly controversial examples. When target typing with names in the literal, this seems very similar to using named arguments for a method call. These rules match that most closely.\n\nThis is something we may want to return to, as it has some strange consequences. For instance, if we introduce a temporary variable for the tuple, and do not use target typing:\n\n``` c#\nvar tmp = (last: \"Doe\", first: \"John\"); // infers (string last, string first)\n(string first, string last) t8 = tmp;   // assigns by position, so first = \"Doe\"\n```\n\nBut for now, let's try these rules out and see what they feel like.\n\n## Encoding\n\nAre core question is what IL we generate for tuples. The equivalence-across-names semantics make it easy to rely on a fixed set of underlying generic library types.\n\nWe want tuples to be value types, since we expect them to be created often and copied less often, so it's probably worthwhile avoiding the GC overhead.\n\nStrangely perhaps, we want tuples to be mutable. We think that there are valid scenarios where you want to keep some data in a tuple, but be able to modify parts of it independently without overwriting the whole tuple. Also, calling methods on readonly tuple members that are themselves value types, would cause those methods to be called on a throw-away copy. This is way too expensive - it means that there may be no non-copying way of doing e.g. value-based equality on such tuples.\n\nSo we encode each tuple arity as a generic struct with mutable fields. It would be very similar to the current Tuple<...> types in the BCL, and we would actively avoid purely accidental differences. For this reason, the fields will be called `Item1` etc. Also, tuples bigger than a certain arity (probably 8)  will be encoded using nesting through a field called `Rest`.\n\nSo we are looking at types like this:\n\n``` c#\npublic struct ValueTuple<T1, T2, T3>\n{\n    public T1 Item1;\n    public T2 Item2;\n    public T3 Item3;\n}\n```\n\nPossibly with a constructor, some `Equals` and `GetHashCode` overrides and maybe an implementation of `IEquatable<...>` and `IStructurallyEquatable<...>`, but at its core exceedingly simple.\n\nIn metadata, a named tuple is represented with its corresponding `ValueTuple<...>` type, plus an attribute describing the names for each position. The attribute needs to be designed to also be able to represent names in nested tuple types.\n\nThe encoding means that an earlier version of C#, as well as other languages, will see the tuple members as `Item1` etc. In order to avoid breaking changes, we should probably keep recognizing those names as an alternative way of getting at any tuple's elements. To avoid confusion we should disallow `Item1` etc. as names in named tuples - except, perhaps, if they occur in their right position.\n\n## Deconstruction syntax\n\nMost tuple features have a deconstruction syntax along the following lines:\n\n``` c#\n(int sum, int count) = Tally(...);   \n```\n\nIf we want such a syntax there are a number of questions to ask, such as can you deconstruct into existing fields or only newly declared ones?\n\nFor now we sidestep the question by not adding a deconstruction syntax. The names make access much easier. If it turns out to be painful, we can reconsider.\n\n## Other issues\n\nWe will not consider tuples of arity zero or one - at least for now. They may be useful, especially from the perspective of generated source code, but they also come with a lot of questions.\n\nIt seems reasonable to consider other conversions, for instance implicit covariant conversions between tuples, but this too we will let lie for now.  \n"
  },
  {
    "path": "meetings/2015/LDM-2015-07-07.md",
    "content": "# C# Design Notes for Jul 7 2015\n\nDiscussion for these notes can be found at https://github.com/dotnet/roslyn/issues/5031.\n\nQuotes of the day:\n\n> \"I don't think I've had a Quote of the Day for years \\<sigh>\" \n> \"What you just described is awful, so we can't go there!\"\n\n## Agenda\n\nWith Eric Lippert from Coverity as an honored guest, we looked further at the nullability feature.\n\n1. Adding new warnings\n2. Generics and nullability\n\n# New warnings\n\nThe very point of this feature is to give new warnings about existing bugs. What's a reasonable experience here? Ideally folks will always be happy to be told more about the quality of the code. Of course there needs to be super straightforward ways of silencing warnings for people who just need to continue to build, especially when they treat warnings as errors (since those would be breaking). We've previously been burned by providing new warnings that then broke people.\n\nThere's a problem when those warnings are false positives, which though hopefully rare, is going to happen: I checked for null in a way the compiler doesn't recognize. Can I build an analyzer to turn warnings *off* if it knows better? Anti-warnings? That's a more general analyzer design question.\n\nCoverity for instance have very advanced analysis to weed out false positives, and avoid the analysis becoming noisy.\n\n# Generics\n\nThere's a proposal to treat generics in the following way: Both nullable and nonnullable types are allowed as type arguments. Nullability flows with the type. Type inference propagates nullability - if any input type is nullable the inferred type will be, too.\n\nConstraints can be nullable or nonnullable. Any nonnullable constraints mean that only non-nullable reference types can satisfy them (without warning). Unconstrained generics is reinterpreted to mean constrained by `object?`, in order to continue to allow all safe types as type arguments. If a type parameter `T` is constrained to be nonnullable, `T?` can be used without warning.\n\nThus:  \n\n``` c#\nclass C<T> where T : Animal? \n{\n  public T x;\n  public T? y; // warning\n}\nclass D<T> where T : Animal \n{\n  public T x;\n  public T? y;\n}\n\nC<Giraffe>\nC<Giraffe?>\n\nD<Squirrel>\nD<Squirrel?> // warning\n```\n\nInside of generics, type parameters are always expected to possibly be nonnullable. Therefore assigning null or nullable values to them always yields a warning (except probably when they are from the *same* possibly nullable type parameter!).\n\nThis is nice and consistent. Unfortunately it isn't quite expressive enough. There are cases such as `FirstOrDefault` where we'd really want to return \"the nullable version of T if it isn't already nullable\". Assume an operator \"`^`\" (that shouldn't *actually* be the syntax) to mean take the nullable of any nonnullable reference type, leave it alone otherwise:\n\n``` c#\npublic static T^ FirstOrDefault<T>(this IEnumerable<T> source);\n\nvar a = new string[] { \"a\", \"b\", \"c\" };\nvar b = new string[] {};\n\nvar couldBeNull = condition ? a.FirstOrDefault() : b.FirstOrDefault(); // string?\n```\n\nWe would need to decide what the syntax for `^` *actually* is if we want to have that expressiveness.\n\n`T^` can also serve the purpose of helping null-check code *inside* of a generic method or type. A `List<T>` type for instance could declare its storage array to be `T^[]` instead of `T[]` so that it warns you where you use it that the array elements could be null.\n\n`T?` cannot exist when T is not constrained to either struct or class, because it means different things in the two cases, and we can't code gen across them.\n\nCast doesn't do null check, just suppresses warning.\n"
  },
  {
    "path": "meetings/2015/LDM-2015-08-18.md",
    "content": "# C# Design Notes for Aug 18, 2015\n\nDiscussion for these notes can be found at https://github.com/dotnet/roslyn/issues/5033.\n\n## Agenda\n\nA summary of the design we (roughly) landed on in #5031 was put out on GitHub as #5032, and this meeting further discussed it.\n\n1. Array creation\n2. Null checking operator\n3. Generics\n\n# Array creation with non-nullable types\n\nFor array creation there is the question whether to allow (big hole) or disallow (big nuisance?) on non-nullable reference types. We'll leave it at allow for now, but may reconsider.\n\n# Null checking operator\n\nCasting to a non-nullable reference type would not, and should not, do a runtime null check. Should we, however, have an *operator* for checking null, throwing if the value *is* null, resulting in the non-null value if it isn't?\n\nThis seems like a good idea. The operator is postfix `!`, and it should in fact apply to values of nullable *value* types as well as reference types. It \"upgrades\" the value to non-nullable, by throwing if it is null.\n\n``` c#\nif (person.Kind == Student) \n{\n  List<Course> courses = person.Courses!; // I know it's not null for a student, but the compiler doesn't.\n  ...\n}\n```\n\nThe `!` operator naturally leads to `x!.y`, which is great! Although `!.` is two operators, it will feel as a cousin of `?.` (which is one operator). While the latter is conditional on null, the former just plows through. Naively, it implies two redundant null checks, one by `!` and one by `.`, but we'll optimize that of course. \n\n``` c#\nif (person.Kind == Student) \n{\n  var passed = !person.Courses!.Any(c => c.Grade == F);\n  ...\n}\n```\n\nTechnically this would allow `x!?.y`, which comes quite close to swearing. We should consider warning when you use `?.` on non-null things.\n\nVB may have a problem with post-fix `!`. We'll cross that bridge when we get there.\n\n\n# Generics and nullability\n\nIs it too heavyhanded to require `?` on constraints to allow nullable type arguments?\n\nOften, when you have a constraint it is because you want to operate on instances. So it's probably good that the default is not nullable.\n\nIt may feel a bit egregious to require it on *all* the constraints of a type parameter, though. Should we put any `?`'s on the type parameter declaration instead of in the constraints? No, that is too weird and different. The case of multiple nullable constraints is probably sufficiently rare that it is reasonable to ask folks to put a `?` on each. In fact we should disallow having `?` on only some, since those question marks won't have an effect: they'll be cancelled by the non-nullable fellow constraints.\n\nThe proposal talks about allowing `?` on the use of type parameters to explicitly override their nullness. Maybe we should have an explicit `!` as well, to explicitly override in the other direction: non-nullable. Think for instance of a `FirstNonNull` method.\n\n``` c#\nT! FirstNonNull<T>(IList<T> list) { ... }\nT? FirstOrDefault<T>(IList<T> list) { ... }\n```\n\nThis means complexity slowly creeps into the proposal, thanks to generics. However, it seems those overrides are relatively rare, yet really useful when you need them. \n\n`T!` would only be allowed on type parameters, and only when they are not already non-null by constraint. \n\n\n"
  },
  {
    "path": "meetings/2015/LDM-2015-09-01.md",
    "content": "C# Design Meeting Sep 1 2015\n============================\n\nDiscussion for these notes can be found at https://github.com/dotnet/roslyn/issues/5233.\n\nAgenda\n------\n\nThe meeting focused on design decisions for prototypes. There's no commitment for these decisions to stick through to a final feature; on the contrary the prototypes are being made in order to learn new things and improve the design.\n\n1. ref returns and ref locals\n2. pattern matching\n\n\nRef returns and ref locals\n==========================\n\nProposal in #118, Initial PR for prototype in #4042.\n\nThis feature is a generalization of ref parameters, and as such doesn't have much new, either conceptually or in how you work with it. As is already the case, refs cannot be null (they always reference a memory location), and you access the location they point to without explicitly dereferencing. The new thing is that you can return refs from methods and other functions, and that you can have locals that are refs to other memory locations.\n\nThere's a new notion of \"safe-to-return\". It would be bad if you could return a ref to your own stack frame, for instance. Therefore there's a simple analysis to always track if a ref is \"safe-to-return\" - and a compile time error if you return something that isn't.\n\nA given method can get refs from a number of places:\n\n1. refs to locals in this method\n2. ref parameters passed to it\n3. refs into heap objects\n4. refs returned from calls\n5. ref locals in this method\n\nThe 1st are never safe to return; the 2nd and 3rd always are. The 4th are safe to return if every ref passed *into* the call is safe to return - since we then know that the returned ref cannot be to a local of the calling (or called) method.\n\nThe 5th is more involved, as it depends on which semantics we adopt for ref locals.\n\nRef locals\n----------\n\nThere are a couple of different questions to consider for ref locals:\n\n1. Can they be reassigned or are they fixed to a location at declaration time (like ref parameters)?\n2. When are they safe to return? Always? Never? Depends?\n\nIf ref locals can be reassignable *and* unsafe-to-return, that means that we have to worry about lifetime analysis:\n\n``` c#\nref int r;\nwhile (...)\n{\n  int x = ...;\n  if (...) ref r = ref x;\n}\nWriteLine(r); // What now?\n```\n\nIn other words we have to concern ourselves with the situation where locals are assigned to a ref that is longer lived than the local itself. We would have to detect it and either forbid it or resort to expensive techniques (similar to variable capture by lambdas) that  run counter to the perf you were probably hoping for by using refs in the first place.\n\nOn the other hand, if ref locals cannot be assigned after initialization, there will be no opportunity to assign variables to them that live in a more nested, and hence shorter-lived, scope. And if they are required to be safe-to-return, then *no* locals can be assigned to them, regardless of lifetime. Either of these seem more attractive!\n\nWe think that not being able to assign locals to ref locals is too limiting. For instance, it would be common to keep a struct in a local, and then call a function with a ref to it to locate and return a ref to some data nested in it. You'd want to store the result of that in a ref local:\n\n``` c#\nNode n = ...; struct\nref Node l = ref GetLeftMostSubNode(ref n);\nl.Contents = ...; // modify leftmost node\n```\n\nSo we definitely want to allow ref locals that are non-reassignable and unsafe-to-return.\n\nHowever, it is also reasonable to want to call similar helper methods on refs that *are* safe to return, to store the results and to then return them:\n\n``` c#\nref Node M(ref Node n)\n{\n  if (...)\n  {\n    ref Node l = ref GetLeftMostSubNode(ref n);\n    l.Contents = ...; // modify leftmost node\n    return ref l;\n  }\n  ...\n}\n```\n\nIt seems that we want ref locals to be safe-to-return or not *depending on what they are initialized with*.\n\nWe think that there is also some value in having reassignable ref locals. For instance, you can imagine a ref local being the current \"pointer\" in a loop over a struct array.\n\nWe can imagine a rule that simply says that ref locals are reassignable *except if they are initialized with an unsafe-to-return ref*. Then, only safe-to-return refs can be assigned to the reassignable ones, and we still don't have lifetime tracking issues.\n\nOn closer scrutiny, though, this scenario does raise harder issues. If you use a ref as a current pointer, what's its initial value? Do we need null refs in the language now? How do you increment it? Can it point \"past the edge\" at the end?\n\nThese are questions we don't want to answer right now for a somewhat hypothetical scenario.\n\n**Conclusion**: for the prototype, ref locals are non-reassignable, and get their \"safe-to-return\" status from their mandatory ref initializer.\n\nIf there are scenarios not covered by this, we'll discover as folks start using the prototype and tell us.\n\nBy avoiding reassignment we avoid answering a couple of difficult questions:\n* What's the syntax of a ref assignment? `ref x = y`? `ref x = ref y`? `x = ref y`?\n* Are ref assignments expressions, and what does that mean?\n* Null/default values or definite assignment analysis to prevent the need for them\n\n`this` in structs\n-----------------\n\nFor non-readonly structs, `this` is generally described as being like a ref parameter. However, considering it safe-to-return like ref parameters in struct methods leads to undesirable behavior: It lets a ref to `this` be returned from the method. Therefore a caller needs to consider a ref returned from a method on a struct local *not* safe to return (the returned ref could be the struct local itself or part of it). In essence, the ref `this` \"contaminates\" any ref-returning method called on a local value type.\n\nScenarios where this is a problem include using structs as wrapper types for heap objects.\n\nSomewhat counterintuitively perhaps, the better rule is to consider `this` in struct methods unsafe-to-return. Since struct methods will never return a ref to the receiver, you can call them with safe-to-return ref parameters and get safe-to-return ref results.\n\nThis also solves a problem with generics, where you don't *know* if a receiver is going to be a struct. Now you don't have to program defensively against that; ref returning methods called on *anything* will be independent of their receiver with regards to safe-to-return determination.  \n\nOther issues\n------------\n\n* We may want an unsafe language-level feature to convert between refs and pointers. We'll look at that later.\n* PEVerify considers ref return unsafe. We need to chase that down, but for the prototype it's fine.\n* It'd be useful to have a notion of \"readonly refs\" - refs through which you cannot write to the referenced storage. This is a separate (big) topic for later.\n\n\nPattern matching\n================\n\nProposal in #206, initial PR in #4882.\n\nSyntax: There are patterns, extended is-expressions, and (later) switch.\n``` c#\npattern:\n  *\n  type identifier // scope is a separate issue\n  type { id is pattern, ... } [identifier]\n  type (pattern, ...)\n  constant-expression\n\nis-expression:\n  relational-expression is pattern\n```\n\nFor constants, we would have integral constants be flexible between types. Floats probably not. This has tons of levers, that we can obsess over, but in the prototype this is what we'll go with.\n\nRelational operators in patterns? `e is > 3`? Maybe later.\n\nFor VB probably more issues. Save for later.\n\nScope for variables: in scope in nearest enclosing statement, *except* the else-block of an if-statement. This is a weird but useful exception that allows subsequent else-if's to introduce variables with the same name as previous ones in the conditions.\n\nFOr now, the introduced variables are not reassignable. This could have both positive and negative perf impact. It's an opportunity to do \"the right thing\", but also a deviation from what we do with other variables. We'll try it in the prototype and see what it feels like.\n\nDeconstruction and guards are interesting further topics that we don't want to pursue yet.\n\nRecord types are not part of this prototype.\n\nSome concerns about the active pattern part being too weird or different. Best resolved by prototyping it and playing with it.\n\n"
  },
  {
    "path": "meetings/2015/LDM-2015-09-02.md",
    "content": "C# Design Notes Sep 2 2015\n==========================\n\nDiscussion for these notes can be found at https://github.com/dotnet/roslyn/issues/5234.\n\nQuote of the day: Are you pulling the curtain away from my magic retort?\n\nAgenda\n------\n\n1. Extending nameof\n2. What do branches mean\n3. Supersedes\n\n\nExtending nameof\n================\n\nShould we allow empty type argument lists? When we first designed nameof the idea was to allow the same operands as typeof. During design we took it more in the direction of expressions, which seemed more useful.\n\nHowever, it leaves a nuisance of providing type arguments that don't really provide any value.\n\nOne problem with this approach is what to do about situations like `MyList<>.First.P` where `First`'s type is the type parameter of `MyList`.\n\nWe would think of `MyList<>` as having a type argument that has no members at all - not even the ones from object. Thus, if you dot on it, you get an error.\n\nMore simply, just allow what's in typeof, followed by one member access. Make sure that, like in typeof, type arguments are either given everywhere or nowhere.\n\nFor inherited members/nested types, we should do the same as typeof does.\n\nWe don't expect this to upset analyzers much. We would make sure that the unbound types do have members in the semantic model. *Those* members just don't have members. Thus `MyList<>.First` is fine, but `MyList<>.First.P` is not.\n\nWe like this.\n\nWhat do branches mean\n=====================\n\nAs prototypes start to come online, we need to decide how we use our branches. The Future branch is for when things are at prototype level for the whole experience - including IDE. Features will be guarded by a feature flag until it's the confident plan of record to ship the feature in its current form.\n\nWe are working on enabling VSIXes to change the language model in the IDE without the need for customers to install over VS. Hopefully this capability will be available in an update to VS in a not too distant future. Once that is in place, we can ship prototypes that run without risk to customers' VS installation.\n \n\nSupersedes\n==========\n\nFor metaprogramming, like Javas annotation processing tool (APT), we would like to facilitate generating additional code from existing code (e.g. based on attributes or patterns). Roslyn now provides an excellent stack for that.\n\nAs a language C# is already better suited for this than Java because of partial types and methods: they allow the merging of existing and generated code to be less convoluted.\n\nHowever we can do even better. We can allow omitting `partial` on one of the parts, so the user written code doesn't need it. But more interestingly we can consider a `supersedes` feature (where the keyword `supersedes` may need to be replaced by something that people have less trouble spelling!):\n\n``` c#\nclass C\n{\n  public void M()\n  {\n    // do stuff\n  }\n\n  [INPC] public int X {\n    get { ... }\n    set { ... }\n}\n\n// generated\npartial class C\n{\n  public supersedes void M()\n  {\n    // do something\n    superseded(); // calls original method\n    // do more\n  }\n\n  public supersedes int X {\n    get { return superseded; }\n    set \n    {\n      superseded = value;\n      RaiseNPC(nameof(X));\n    }\n  }\n}\n```\n\nThe compiler would generate code to keep the original `M` and `X` under a mangled name, inlined or something.\n\nChallenge: composing multiple rewriters: either we have an ordering rule, or we get errors. This is a challenging problem.\n\nAnother good question: Do you have just one generator phase, or keep going to a fix point. Java keeps going until no changes.\n\nIs the generated code visible to the user? You should see it like generated code today, and the compiler would parse it again to guard from mistakes. That way, code could also be generated by t4 and other tools, as well as Roslyn.\n\nConcern: we are adding a new concept. Would it be better to use existing concepts, like Java does?\n\nConcern: efficiency. Forces binding, throws away first result and binds again against generated code. \n\nThis is very interesting and promising, but there are many juicy challenges ahead.\n\n\n\n "
  },
  {
    "path": "meetings/2015/LDM-2015-09-08.md",
    "content": "# C# Design Notes for Sep 8, 2015\n\nDiscussion for these notes can be found at https://github.com/dotnet/roslyn/issues/5383.\n\n## Agenda\n\n1. Check-in on some of our desirable features to see if we have further thoughts\n2. Start brainstorming on async streams\n\n\n# Check-in on features \n\n## Bestest betterness\n \nOverload resolution will sometimes pick a candidate method only to lead to an error later on. For instance, it may pick an instance method where only a static one is allowed, a generic method where the constraints aren't satisfied or an overload the relies on a method group conversion that will ultimately fail.\n\nThe reason for this behavior is usually to keep the rules simple, and to avoid accidentally picking another overload than what you meant. However, it also leads to quite a bit of frustration. It might be time to sharpen the rules.\n\n## Private protected\n\nIn C# 6 we considered adding a new accessibility level with the meaning protected *and* internal (`protected internal` means protected *or* internal), but gave up because it's hard to settle on a syntax. We wanted to use `private protected` but got a lot of loud push back on it.\n\nNo-one has come up with a better syntax in the meantime though. We are inclined to think that `private protected` just takes a little getting used to. We may want to try again.\n\n## Attributes\n\nThere are a number of different features related to attributes. We should return to these in a dedicated meeting looking at the whole set of proposals together:\n\n* Generic attributes: They seem to be allowed by the runtime, but for some reason are disallowed by the language\n* Compile-time only attributes: For attributes that are intended to be used only before IL gen, it'd be nice to have them elided and not bloat metadata\n* Attributes in more places: There are more places where it makes sense to allow attributes, such as on lambda expressions. If they are compile-time only, they can even be in places where there is no natural code gen.\n* Attributes of more types: For attributes that are not going into code gen, we could relax the restrictions on the types of their constructor parameters.\n\nA lot of these would be particularly helpful to Roslyn based tools such as analyzers and metaprogramming.\n\n## Local extern functions\n\nWe should allow local functions to be extern. You'd almost always want to wrap an extern method in a safe to call wrapper method. \n\n## Withers for arbitrary types\n\nIf we want to start focusing more on immutable data structures, it would be nice if there was a language supported way of creating new objects from existing ones, changing some subset of properties along the way:\n\n``` c#\nvar newIfStatement = ifStatement with { Condition = newCondition, Statement = newStatement }; // other properties copied \n```\n\nCurrently the Roslyn code base, for example, uses the pattern of \"withers\", which are methods that return a new object with one property changed. There needs to  be a wither per property, which is quite bloatful, and in Roslyn made feasible by having them automatically generated. Even so, changing multiple properties is suboptimal:\n\n``` c#\nvar newIfStatement = ifStatement.WithCondition(newCondition).WithStatement(newStatement); \n```\n\nIt would be nice if we could come up with an efficient API pattern to support a built-in, efficient `with` expression.\n\nRelated to this, it would also be nice to support object initializers on immutable objects. Again, we would need to come up with an API pattern to support it; possibly the same that would support the with expression.\n\n## Params IEnumerable\n\nThis is a neat little feature that we ultimately rejected or didn't get to in C# 6. It lets you do away with the situation where you have to write two overloads of a method, one that takes an `IEnumerable<T>` (for generality) and another one that takes `params T[]` and calls the first one with its array.\n\nThe main problem raised against params IEnumerable is that it encourages an inefficient pattern for how parameters are captured: An array is allocated even when there are very few arguments (even zero!), and the implementation then accesses the elements through interface dispatches and further allocation (of an IEnumerator).\n\nProbably this won't matter for most people - they can start out this way, and then build a more optimal pattern if they need to. But it might be worthwhile considering a more general language pattern were folks can build a params implementation targeting something other than arrays.\n\n\n# Async streams\n\nWe shied back from a notion of asynchronous sequences when we originally introduced async to C#. Part of that was to see whether there was sufficient demand to introduce framework and language level concepts, and get more experience to base their design on. But also, we had some fear that using async on a per-element level would hide the true \"chunky\" degree of asynchrony under layers of fine-grained asynchronous abstractions, at great cost to performance.\n\n## IAsyncEnumerable\n\nAt this point in time, though, we think that there is definitely demand for common abstractions and language support: foreach'ing, iterators, etc. Furthermore we think that the performance risks - allocation overhead in particular - of fine grained asynchrony can large be met with a combination of the compiler's existing optimizations and a straightforward asynchronous \"translation\" of `IEnumerable<T>` into `IAsyncEnumerable<T>`:\n\n``` c#\npublic interface IAsyncEnumerable<T>\n{\n  public IAsyncEnumerator<T> GetEnumerator();\n}\n\npublic interface IAsyncEnumerator<T>\n{\n  public T Current { get; }\n  public Task<bool> MoveNextAsync();\n}\n```\n\nThe only meaningful difference is that the `MoveNext` method of the enumerator interface has been made async: it returns `Task<bool>` rather than `bool`, so that you need to await it to find out whether there is a next element (which you can then acquire from the `Current` property) or the sequence is finished.\n\n## Allocations\n\nLet's assume that you are foreach'ing over such an asynchronous sequence, which is buffered behind the scenes, so that 99.9% of the time an element is available locally and synchronously. Whenever a `Task` is awaited that is already completed, the compiler avoids the heavy machinery and just gets the value straight out of the task without pause. If *all* awaited Tasks in a given method call are already completed, then the method will never allocate a state machine, or a delegate to store as a continuation, since those are only constructed the first time they are needed. \n\nEven when the async method reaches its return statement synchronously, without the awaits having ever paused, it needs to construct a Task to return. So normally this would still require one allocation. However, the helper API that the compiler uses for this will actually cache completed Tasks for certain common values, including `true` and `false`. In summary, a `MoveNextAsync` call on a sequence that is buffered would typically not allocate anything, and the calling method often wouldn't either.\n\nThe lesson is that fine-grained asynchrony is bad for performance if it is done in terms of `Task<T>` where completed Tasks are never or rarely cached, e.g. `Task<string>` or `Task<int>`. It should be done in terms of `Task<bool>` or even non-generic `Task`.\n\nWe think that there may or may not be scenarios where people want to get explicit about the \"chunks\" that data is transmitted in. If so, they can express this as `IAsyncEnumerable<Chunk<T>>` or some such thing. But there is no need to complicate asynchronous streaming by forcing people to deal with chunking by default.\n\n## Linq bloat\n\nAnother concern is that there are many API's on `IEnumerable<T>` today; not least the Linq query operators `Select`, `Where` and so on. Should all those be duplicated for `IAsyncEnumerable<T>`?\n\nAnd when you think about it, we are not just talking about one extra set of overloads. Because once you have asynchronously foreach'able streams, you'll quickly want the delegates applied by the query operators to *also* be allowed to be async. So we have potentially four combinations:\n\n``` c#\npublic static IEnumerable<T> Where<T>(this IEnumerable<T> source, Func<T, bool> predicate);\npublic static IAsyncEnumerable<T> Where<T>(this IAsyncEnumerable<T> source, Func<T, bool> predicate);\npublic static IAsyncEnumerable<T> Where<T>(this IEnumerable<T> source, Func<T, Task<bool>> predicate);\npublic static IAsyncEnumerable<T> Where<T>(this IAsyncEnumerable<T> source, Func<T, Task<bool>> predicate);\n```\n\nSo either we'd need to multiply the surface area of Linq by four, or we'd have to introduce some new implicit conversions to the language, e.g. from `IEnumerable<T>` to `IAsyncEnumerable<T>` and from `Func<S, T>` to `Func<S, Task<T>>`. Something to think about, but we think it is probably worth it to get Linq over asynchronous sequences one way or another.\n\nAlong with this, we'd need to consider whether to extend the query syntax in the language to also produce async lambdas when necessary. It may not be worth it - using the query operators may be good enough when you want to pass async lambdas.\n\n## Language support\n\nIn the language we would add support for foreach'ing over async sequences to consume them, and for async iterators to produce them. Additionally (we don't discuss that further here) we may want to introduce a notion of `IAsyncDisposable`, for which we could add an async version of the `using` statement.\n\nOne concern about async versions of language features such as foreach (and using) is that they would generate `await` expressions that aren't there in source. Philosophically that may or may not be a problem: do you want to be able to see where all the awaiting happens in your async method? If that's important, we can maybe add the `await` or `async` keyword to these features somewhere:\n\n``` c#\nforeach (string s in asyncStream) { ... } // or\nforeach async (string s in asyncStream) { ... } // or\nforeach (await string s in asyncStream) { ... } // etc.\n```\n\nEqually problematic is when doing things such as `ConfigureAwait`, which is important for performance reasons in libraries. If you don't have your hands on the Task, how can you `ConfigureAwait` it? The best answer is to add a `ConfigureAwait` extension method to `IAsyncEnumerable<T>` as well. It returns a wrapper sequence that will return a wrapper enumerator whose `MoveNextAsync` will return the result of calling `ConfigureAwait` on the task that the wrapped enumerator's `MoveNextAsync` method returns:\n\n``` c#\nforeach (string s in asyncStream.ConfigureAwait(false)) { ... }\n```\n \nFor this to work, it is important that async foreach is pattern based, just like the synchronous foreach is today, where it will happily call any `GetEnumerator`, `MoveNext` and `Current` members, regardless of whether objects implement the official \"interfaces\". The reason for this is that the result of `Task.ConfigureAwait` is not a `Task`.\n\nA related issue is cancellation, and whether there should be a way to flow a `CancellationToken` to the `MoveNextAsync` method. It probably has a similar solution to `ConfigureAwait`.\n\n## Channels in Go\n\nThe Go language has a notion of channels, which are communication pipes between threads. They can be buffered, and you can put things in and take them out. If you put things in while the channel is full, you wait. If you take things out while it is empty, you wait.\n\nIf you imagine a `Channel<T>` abstraction in .NET, it would not have blocking waits on the endpoints; those would instead be asynchronous methods returning Tasks.\n\nGo has an all-powerful language construct called `select` to consume the first available element from any set of channels, and choosing the logic to apply to that element based on which channel it came from. It is guaranteed to consume a value from only one of the channels.\n\nIt is worthwhile for us to look at Go channels, learn from them and consider to what extent a) we need a similar abstraction and b) it is connected to the notion of async streams.\n\nSome preliminary thoughts: Channels and select statements are very easy to understand, conceptually. On the other hand they are somewhat low-level, and extremely imperative: there is a strong coupling from the consumer to the producer, and in practice there would typically only *be* one consumer. It seems like a synchronization construct like semaphores or some of the types from the DataFlow library.\n\nThe \"select\" functionality is interesting to ponder more generally. If you think about it from an async streams perspective, maybe the similar thing you would do would be to merge streams. That would need to be coupled with the ability to tie different functionality to elements from different original streams - or with different types. Maybe pattern matching is our friend here?\n\n``` c#\nforeach (var e in myInts.Merge(myStrings))\n{\n  switch (e)\n  {\n    case int i:\n      ...\n    case string s:\n      ...\n  }\n}\n```\n\nEither way, it isn't as elegant by a long shot. If we find it's important, we'd need to consider language support.\n\nAnother important difference between IAsyncEnumerable and Channels is that an enumerable can have more than one consumer. Each enumerator is independent of the others, and provides access to all the members - at least from the point in time where it is requested. \n\n\n## Conclusion\n\nWe want to keep thinking about async streams, and probably do some prototyping."
  },
  {
    "path": "meetings/2015/LDM-2015-10-07-Design-Review.md",
    "content": "Notes on Records and Pattern Matching for 2015-10-07 design review\n==================================================================\n\nDiscussion for these notes can be found at https://github.com/dotnet/roslyn/issues/5757.\n\n### Records and Pattern Matching (https://github.com/dotnet/roslyn/issues/206)\n\nPrototyped together last year by @semihokur, but that prototype is\nbased on very out-of-date Roslyn code. We also have some design changes\nsince that time and we want to separate a pattern-matching prototype from\nrecords/ADTs so we can make independent decisions about whether\nand when to include them in the language(s).\n\nFirst step is to port pattern matching to the latest sources.\nIn-progress port at https://github.com/dotnet/roslyn/pull/4882\n\n### Spec changes since the 2014 prototype\n\nFor pattern matching:\n\n1. Scoping of pattern-introduced variables (with \"funny\" rule for `if`)\n2. Rules for `switch` statement that make it a compatible extension of the existing construct (https://github.com/dotnet/roslyn/issues/4944)\n3. An expression form of multi-arm pattern-matching (https://github.com/dotnet/roslyn/issues/5154)\n4. A `when` clause added to `switch` cases.\n\nAnd, for records:\n\n1. No `record` keyword necessary\n2. `with` expressions (https://github.com/dotnet/roslyn/issues/5172)\n3. Approach for algebraic data types\n\n### Implementation status of prototype port\n\n1. For pattern matching, checklist at https://github.com/dotnet/roslyn/pull/4882 tracking the progress\n2. For records, port not started\n\n### Making the extension of `switch` backward-compatible\n\n- We say that the cases are matched in order, except `default` which is always the last\nresort.\n\n- Integral-typed case labels match any integral-valued control expression with the same value.\n\n- One issue around user-defined conversions to switchable types is\nresolved (https://github.com/dotnet/roslyn/issues/4944). In the draft spec,\na conversion will be applied on the `case`s, not on the control-expression unilaterally.\nInstead of converting only to `switchable` types, each\n`case` arm will consider any conversions that allow the `case` to be applied.\nAny given conversion would be applied at most once. \n\n```cs\nFoo foo = ...; // has a conversion to int\nswitch (foo)\n{\n    case 1: // uses the converted value\n    case Foo(2): // uses the original value\n    case 3: // uses the converted value\n}\n```\n\n- The `goto case` statement is extended to allow any expression as its argument.\n\n### Expression form of multi-arm pattern matching (https://github.com/dotnet/roslyn/issues/5154)\n\n```cs\nvar areas =\n    from primitive in primitives\n    let area = primitive match (\n        case Line l: 0\n        case Rectangle r: r.Width * r.Height\n        case Circle c: Math.PI * c.Radius * c.Radius\n        case *: throw new ApplicationException()\n    )\n    select new { Primitive = primitive, Area = area };\n```\n\nThere is no `default` here, so cases are handled strictly in order.\n\nI propose the spec require that the compiler \"prove\" that all cases are handled\nin a `match` expression using not-yet-specified rules. Writing those rules\nis an open work item, but I imagine it will require the compiler to build\na decision tree and check it for completeness. That will also be needed to\nimplement checks that no case is subsumed by a previous case, which will\ncause a warning (for `switch`) or error (for `match`).\n\n### With-expressions (https://github.com/dotnet/roslyn/issues/5172)\n\n```cs\nclass Point(int X, int Y, int Z);\n...\n    Point p = ...;\n    Point q = p with { Y = 2 };\n```\n\nThe latter is translated into\n\n```cs\n    Point q = new Point(X: p.X, Y: 2, Z: p.Z);\n```\n\nWe know how to do this for record types (because the language specifies the\nmapping between constructor parameters and properties). We're examining how\nto extend it to more general types.\n\nTo support inheritance, rather than directly using the constructor (as above) the generated code will\ninvoke a compiler-generated (but user-overridable) factory method.\n\n```cs\n    Point q = p.With(X: p.X, Y: 2, Z: p.Z);\n```\n\n### Draft approach for algebraic data types\n\n```cs\nabstract sealed class Expression\n{\n    class Binary(Operator Operator, Expression Left, Expression Right) : Expression;\n    class Constant(int Value) : Expression;\n}\n```\n\nNone of these classes would be permitted to be extended elsewhere.\na `match` expression that handles both `Binary` and `Constant` cases\nwould not need a `*` (default) case, as the compiler can prove it\nis complete.\n\n### Remaining major issues\n\n1. We need to specify the rules for checking\n - If the set of cases in a `match` is complete \n - If a `case` is subsumed by a previous `case`\n\n2. We need more experience with algebraic data types and active patterns.\n\n3. Can we extend `with` expressions to non-record types?\n"
  },
  {
    "path": "meetings/2015/LDM-2015-11-02-Design-Demo.md",
    "content": "Here’s an outline of a demo at the MVP summit on 2015-11-02\n===========================================================\n\nDiscussion for these notes can be found at https://github.com/dotnet/roslyn/issues/6505.\n\n### Let’s talk about local functions.\n\nA method often has other private “helper” methods that are used in its implementation. Those methods are in the scope of the enclosing type, even though they are only intended to be used in a single place. Local functions allow you to define a function where it is used. For example, given a helper method\n\n    static int Fib(int n)\n    {\n        return (n < 2) ? 1 : Fib(n - 1) + Fib(n - 2);\n    }\n\nOr, using the new syntax added in C# 6:\n\n    static int Fib(int n) => (n < 2) ? 1 : Fib(n - 1) + Fib(n - 2);\n\nAnd the method that it is used in\n\n    static void Main(string[] args)\n    {\n        Console.WriteLine(Fib(7));\n        Console.ReadKey();\n    }\n\nIn C# 7 you’ll be able to define the helper function in the scope where it is used:\n\n    static void Main(string[] args)\n    {\n        int Fib(int n) => (n < 2) ? 1 : Fib(n - 1) + Fib(n - 2); //!\n\n        Console.WriteLine(Fib(7));\n        Console.ReadKey();\n    }\n\nLocal functions can use variables from the enclosing scope: \n\n    static void Main(string[] args)\n    {\n        int fib0 = 1; //!\n        int Fib(int n) => (n < 2) ? fib0 : Fib(n - 1) + Fib(n - 2);\n\n        Console.WriteLine(Fib(7));\n        Console.ReadKey();\n    }\n\nYou can imagine having to pass such state as additional parameters to a helper method if it were declared in the enclosing type, but local function can use local variables directly.\n\nCapturing state like this does not require allocating frame objects on the heap as it would for delegates, or allocating a delegate object either, so this is much more efficient than what you would have to do to simulate this feature by hand.\n\n### Let’s talk about pattern matching.\n\nWith object-oriented programming, you define a virtual method when you have to dispatch an operation on the particular kind of object. That works best when the author of the types can identify ahead of time all of the operations (virtual methods) on the types, but it enables you to have an open-ended set of types.\n\nIn the functional style, on the other hand, you define your data as a set of types without virtual functions, and define the functions separately from the data. Each operation provides an implementation for each type in the type hierarchy. That works best when the author of the types can identify ahead of time all of the shapes of the data, but it enables you to have an open-ended set of operations.\n\nC# does a great job for the object-oriented style, but the functional style (where you cannot identify all the operations ahead of time) shows up as a frequent source of awkwardness in C# programs.\n\nLet’s get really concrete. Suppose I have a small hierarchy of types\n\n\t// class Person(string Name);\n\tclass Person\n\t{\n\t    public Person(string name) { this.Name = name; }\n\t    public string Name { get; }\n\t}\n\t\n\t// class Student(string Name, double Gpa) : Person(Name);\n\tclass Student : Person\n\t{\n\t    public Student(string name, double gpa) : base(name)\n\t\t\t{ this.Gpa = gpa; }\n\t    public double Gpa { get; }\n\t}\n\t\n\t// class Teacher(string Name, string Subject) : Person(Name);\n\tclass Teacher : Person\n\t{\n\t    public Teacher(string name, string subject) : base(name)\n\t\t\t{ this.Subject = subject; }\n\t    public string Subject { get; }\n\t}\n\nThe comments, by the way, shows a possible future syntax we are considering for C# 7 that we call records. We’re still working on records, so I won’t say more about that today. Here is an operation that uses these types\n\n    static string PrintedForm(Person p)\n    {\n        Student s;\n        Teacher t;\n        if ((s = p as Student) != null && s.Gpa > 3.5)\n        {\n            return $\"Honor Student {s.Name} ({s.Gpa})\";\n        }\n        else if (s != null)\n        {\n            return $\"Student {s.Name} ({s.Gpa})\";\n        }\n        else if ((t = p as Teacher) != null)\n        {\n            return $\"Teacher {t.Name} of {t.Subject}\";\n        }\n        else\n        {\n            return $\"Person {p.Name}\";\n        }\n    }\n\nAnd for the purposes of the demo, a client of that operation\n\n    static void Main(string[] args)\n    {\n        Person[] oa = {\n            new Student(\"Einstein\", 4.0),\n            new Student(\"Elvis\", 3.0),\n            new Student(\"Poindexter\", 3.2),\n            new Teacher(\"Feynmann\", \"Physics\"),\n            new Person(\"Anders\"),\n        };\n        foreach (var o in oa)\n        {\n            Console.WriteLine(PrintedForm(o));\n        }\n        Console.ReadKey();\n    }\n\nNote the need to declare the variables `s` and `t` ahead of time in `PrintedForm`. Even though they are only used in one branch of the series of if-then-else statements, they are in scope throughout. That means that you have to think up distinct names for all of these temporary variables. As part of the pattern-matching feature we are repurposing the “is” operator to take a pattern on the right-hand-side. And one kind of pattern is a variable declaration. That allows us to simplify the code like this\n\n    static string PrintedForm(Person p)\n    {\n        if (p is Student s && s.Gpa > 3.5) //!\n        {\n            return $\"Honor Student {s.Name} ({s.Gpa})\";\n        }\n        else if (p is Student s)\n        {\n            return $\"Student {s.Name} ({s.Gpa})\";\n        }\n        else if (p is Teacher t)\n        {\n            return $\"Teacher {t.Name} of {t.Subject}\";\n        }\n        else\n        {\n            return $\"Person {p.Name}\";\n        }\n    }\n\n\nNow the temporary variables `s` and `t` are declared and scoped to just the place they need to be. Unfortunately we’re testing against the type `Student` more than once. Back to that in a moment.\n\nWe’ve also repurposed the `switch` statement so that the case branches are patterns instead of just constants (though constants are one kind of pattern). That enables you to use `switch` as a \"type switch\":\n\n    static string PrintedForm(Person p)\n    {\n        switch (p) //!\n        {\n            case Student s when s.Gpa > 3.5 :\n                return $\"Honor Student {s.Name} ({s.Gpa})\";\n            case Student s :\n                return $\"Student {s.Name} ({s.Gpa})\";\n            case Teacher t :\n                return $\"Teacher {t.Name} of {t.Subject}\";\n            default :\n                return $\"Person {p.Name}\";\n        }\n    }\n\nThe compiler is careful so that we don’t type-test against `Student` more than once in the generated code for `switch`.\n\nNote the new `when` clause in the switch statement.\n\nWe’re also working on an expression equivalent to the switch statement, which is like a multi-branch `?:` operator for pattern matching:\n\n    static string PrintedForm(Person p)\n    {\n        return p match ( //!\n            case Student s when s.Gpa > 3.5 :\n                $\"Honor Student {s.Name} ({s.Gpa})\"\n            case Student s :\n                $\"Student {s.Name} ({s.Gpa})\"\n            case Teacher t :\n                $\"Teacher {t.Name} of {t.Subject}\"\n            case * :\n                $\"Person {p.Name}\"\n        );\n    }\n\nBecause you sometimes need to throw an exception when some condition is unexpected, we’re adding a *throw expression* that you can use in a match expression:\n\n        return p match (\n            case Student s when s.Gpa > 3.5 :\n                $\"Honor Student {s.Name} ({s.Gpa})\"\n            case Student s :\n                $\"Student {s.Name} ({s.Gpa})\"\n            case Teacher t :\n                $\"Teacher {t.Name} of {t.Subject}\"\n            case null :\n                throw new ArgumentNullException(nameof(p)) //!\n            case * :\n                $\"Person {p.Name}\"\n        );\n\nAnother useful kind of pattern allows you to match on members of a type:\n\n        return p match (\n            case Student s when s.Gpa > 3.5 :\n                $\"Honor Student {s.Name} ({s.Gpa})\"\n            case Student { Name is \"Poindexter\" } : //!\n                \"A Nerd\"\n            case Student s :\n                $\"Student {s.Name} ({s.Gpa})\"\n            case Teacher t :\n                $\"Teacher {t.Name} of {t.Subject}\"\n            case null :\n                throw new ArgumentNullException(nameof(p))\n            case * :\n                $\"Person {p.Name}\"\n        );\n\nSince this is an expression, we can use the new “=>” form of a method. Our final method is\n\n    static string PrintedForm(Person p) => p match (\n        case Student s when s.Gpa > 3.5 :\n            $\"Honor Student {s.Name} ({s.Gpa})\"\n        case Student { Name is \"Poindexter\" } :\n            \"A Nerd\"\n        case Student s :\n            $\"Student {s.Name} ({s.Gpa})\"\n        case Teacher t :\n            $\"Teacher {t.Name} of {t.Subject}\"\n        case null :\n            throw new ArgumentNullException(nameof(p))\n        case * :\n            $\"Person {p.Name}\"\n        );\n\nIn summary:\n- Local functions (capturing state is cheap)\n- Pattern-matching\n  - Operator is\n  - Switch, “when” clauses\n  - `match` expression\n  - Patterns\n    - Constant patterns e.g. `1` in an ordinary switch\n    - type-match patterns e.g. `Student s`\n    - property patterns e.g. `Student { Name is \"Poindexter\" }`\n    - wildcard e.g. `*`\n- Still working on\n  - Records, algebraic data types\n  - Tuples\n"
  },
  {
    "path": "meetings/2015/README.md",
    "content": "# C# Language Design Notes for 2015\n\nOverview of meetings and agendas for 2015\n\n\n## Jan 21, 2015\n\n[C# Design Meeting Notes for Jan 21, 2015](LDM-2015-01-21.md)\n\nThis is the first design meeting for the version of C# coming after C# 6. We shall colloquially refer to it as C# 7. The meeting focused on setting the stage for the design process and homing in on major themes and features.\n\n1. Design process\n2. Themes\n3. Features\n\n\n## Jan 28, 2015\n\n[C# Design Meeting Notes for Jan 28, 2015](LDM-2015-01-28.md)\n\n1. Immutable types\n2. Safe fixed-size buffers\n3. Pattern matching\n4. Records\n\n\n## Feb 4, 2015\n\n[C# Design Meeting Notes for Feb 4, 2015](LDM-2015-02-04.md)\n\n1. Internal Implementation Only (C# 6 investigation)\n2. Tuples, records and deconstruction\n3. Classes with value semantics\n\n\n## Feb 11, 2015\n\n[C# Design Meeting Notes for Feb 11, 2015](LDM-2015-02-11.md)\n\n1. Destructible types <*we recognize the problem but do not think this is quite the right solution for C#*>\n2. Tuples <*we like the proposal, but there are several things to iron out*>\n\n\n## Mar 4, 2015\n\n[C# Design Meeting Notes for Mar 4, 2015](LDM-2015-03-04.md)\n\n1. `InternalImplementationOnly` attribute <*no*>\n2. Should `var x = nameof(x)` work? <*no*>\n3. Record types with serialization, data binding, etc. <*keep thinking*>\n4. \"If I had a [billion dollars](http://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare)...\": nullability <*daunting but worth pursuing*>\n\n\n## Mar 10 and 17, 2015\n\n[C# Design Meeting Notes for Mar 10 and 17, 2015](LDM-2015-03-10-17.md)\n\nThese two meetings looked exclusively at nullable/non-nullable reference types. I've written them up together to add more of the clarity of insight we had when the meetings were over, rather than represent the circuitous path we took to get there.\n\n1. Nullable and non-nullable reference types\n2. Opt-in diagnostics\n3. Representation\n4. Potentially useful rules\n5. Safely dereferencing nullable reference types\n6. Generating null checks\n\n\n## Mar 18, 2015\n\n[C# Design Meeting Notes for Mar 18, 2015](LDM-2015-03-18.md)\n\nIn this meeting we looked over the top [C# language feature requests on UserVoice](http://visualstudio.uservoice.com/forums/121579-visual-studio/category/30931-languages-c) to see which ones are reasonable to push on further in C# 7.\n\n1. Non-nullable reference types (*already working on them*)\n2. Non-nullary constructor constraints (*require CLR support*)\n3. Support for INotifyPropertyChanged (*too specific; metaprogramming?*)\n4. GPU and DirectX support (*mostly library work; numeric constraints?*)\n5. Extension properties and static members (*certainly interesting*)\n6. More code analysis (*this is what Roslyn analyzers are for*)\n7. Extension methods in instance members (*fair request, small*)\n8. XML comments (*Not a language request*) \n9. Unmanaged constraint (*requires CLR support*)\n10. Compilable strings (*this is what nameof is for*)\n11. Multiple returns (*working on it, via tuples*)\n12. ISupportInitialize (*too specific; hooks on object initializers?*)\n13. ToNullable (*potentially part of nullability support*)\n14. Statement lambdas in expression trees (*fair request, big feature!*)\n15. Language support for Lists, Dictionaries and Tuples (*Fair; already working on tuples*)\n\nA number of these are already on the table.\n\n\n## Mar 24, 2015\n\n[C# Design Meeting Notes for Mar 24, 2015](LDM-2015-03-24.md)\n\nIn this meeting we went through a number of the performance and reliability features we have discussed, to get a better reading on which ones have legs. They end up falling roughly into three categories:\n\n* Green: interesting - let's keep looking\n* Yellow: there's something there but this is not it\n* Red: probably not\n\nAs follows:\n\n1. ref returns and locals <*green*> (#118)\n2. readonly locals and parameters <*green*> (#115)\n3. Method contracts <*green*> (#119)\n4. Does not return <*green*> (#1226)\n5. Slicing <*green*> (#120)\n6. Lambda capture lists <*yellow - maybe attributes on lambdas*> (#117)\n7. Immutable types <*yellow in current form, but warrants more discussion*> (#159)\n8. Destructible types <*yellow - fixing deterministic disposal is interesting*> (#161)\n9. Move <*red*> (#160)\n10. Exception contracts <*red*>\n11. Static delegates <*red*>\n12. Safe fixed-size buffers in structs <*red*> (#126)\n\nSome of these were discussed again, some we just reiterated our position.\n\n\n## Mar 25, 2015 (Design Review)\n\n[C# Language Design Review, Mar 25, 2015](LDM-2015-03-25-Design-Review.md)\n[Additional Notes](LDM-2015-03-25-Notes.md)\n\nWe've recently changed gears a little on the C# design team. In order to keep a high design velocity, part of the design team meets one or two times each week to do detailed design work. Roughly monthly the full design team gets together to review and discuss the direction. This was the first such review.\n\n1. Overall direction\n2. Nullability features\n3. Performance and reliability features\n4. Tuples\n5. Records\n6. Pattern matching\n\n\n## Apr 1 and Apr 8, 2015\n\n[C# Design Meeting Notes for Apr 1 and Apr 8, 2015](LDM-2015-04-01-08.md)\n\nMatt Warren wrote a Roslyn analyzer as a low cost way to experiment with nullability semantics. In these two meetings we looked at evolving versions of this analyzer, and what they imply for language design.\n\nThe analyzer is [here](https://github.com/mattwar/nullaby).\n\n\n## Apr 14, 2015\n\n[C# Design Meeting Notes for Apr 14, 2015](LDM-2015-04-14.md)\n\nBart De Smet visited from the Bing team to discuss their use of Expression Trees, and in particular the consequences of their current shortcomings.\n\nThe Expression Tree API today is not able to represent all language features, and the language supports lambda conversions even for a smaller subset than that.\n\n\n## Apr 15, 2015\n\n[C# Design Meeting Notes for Apr 15, 2015](LDM-2015-04-15.md)\n\nIn this meeting we looked at nullability and generics. So far we have more challenges than solutions, and while we visited some of them, we don't have an overall approach worked out yet.\n\n1. Unconstrained generics\n2. Overriding annotations\n3. FirstOrDefault\n4. TryGet\n\n\n## Apr 22, 2015 (Design Review)\n\n[C# Language Design Review, Apr 22, 2015](LDM-2015-04-22-Design-Review.md)\n\n1. Expression tree extension\n2. Nullable reference types\n3. Facilitating wire formats\n4. Bucketing\n\n\n## May 20, 2015\n\n[C# Design Meeting Notes for May 20, 2015](LDM-2015-05-20.md)\n\n1. We discussed whether and how to add local functions to C#, with the aim of prototyping the feature in the near future.\n\n\n## May 25, 2015\n\n[C# Design Meeting Notes for May 25, 2015](LDM-2015-05-25.md)\n\nToday we went through a bunch of the proposals on GitHub and triaged them for our list of features. \n\n\n## Jul 1, 2015\n\n[C# Design Meeting Notes for Jul 1, 2015](LDM-2015-07-01.md)\n\nWe are gearing up to prototype the tuple feature, and put some stakes in the ground for its initial design. This doesn't mean that the final design will be this way, and some choices are arbitrary. We merely want to get to where a prototype can be shared with a broader group of C# users, so that we can gather feedback and learn from it.\n\n\n## Jul 7, 2015\n\n[C# Design Meeting Notes for Jul 7, 2015](LDM-2015-07-07.md)\n\nWith Eric Lippert from Coverity as an honored guest, we looked further at the nullability feature.\n\n1. Adding new warnings\n2. Generics and nullability\n\n\n## Aug 18, 2015\n\n[C# Design Meeting Notes for Aug 18, 2015](LDM-2015-08-18.md)\n\nA summary of the design we (roughly) landed on in #5031 was put out on GitHub as #5032, and this meeting further discussed it.\n\n1. Array creation\n2. Null checking operator\n3. Generics\n\n\n## Sep 1, 2015\n\n[C# Design Meeting Notes for Sep 1, 2015](LDM-2015-09-01.md)\n\nThe meeting focused on design decisions for prototypes. There's no commitment for these decisions to stick through to a final feature; on the contrary the prototypes are being made in order to learn new things and improve the design.\n\n1. ref returns and ref locals\n2. pattern matching\n\n\n## Sep 2, 2015\n\n[C# Design Meeting Notes for Sep 2, 2015](LDM-2015-09-02.md)\n\n1. Extending nameof\n2. What do branches mean\n3. Supersedes\n\n\n## Sep 8, 2015\n\n[C# Design Meeting Notes for Sep 8, 2015](LDM-2015-09-08.md)\n\n1. Check-in on some of our desirable features to see if we have further thoughts\n2. Start brainstorming on async streams\n\n\n## Oct 7, 2015 (Design Review)\n\n[Preparatory Notes on Records and Pattern Matching for Oct 7, 2015 Design Review](LDM-2015-10-07-Design-Review.md)\n\n## Nov 2, 2015 (Design Demo)\n\n[Outline of demo at the Nov 2, 2015 MVP summit](LDM-2015-11-02-Design-Demo.md)\n\n"
  },
  {
    "path": "meetings/2016/LDM-2016-02-29.md",
    "content": "C# Language Design Notes Feb 29, 2016\n=====================================\n\nDiscussion for these notes can be found at https://github.com/dotnet/roslyn/issues/9330.\n\n## Catch up edition (deconstruction and immutable object creation)\n\nOver the past couple of months various design activities took place that weren't documented in design notes. The following is a summary of the state of design regarding positional deconstruction, with-expressions and object initializers for immutable types.\n\n# Philosophy\n\nWe agree on the following design tenets:\n\nPositional deconstruction, with-expressions and object initializers are separable features, enabled by the presence of certain API patterns on types that can be expressed manually, as well as generated by other language features such as records.\n\n# API Patterns\n\nAPI patterns for a language feature facilitate two things:\n\n* Provide actual APIs to call _at runtime_ when the language feature is used\n* Inform the compiler _at compile time_ about how to generate code for the feature\n\nIt turns out the biggest design challenges are around the second part. Specifically, all these API patterns turn out to need to bridge between positional and name-based expressions of the members of types. How each API pattern does that is a central question of its design.\n\nAssume the following running example:\n\n``` c#\npublic class Person\n{\n  public string FirstName { get; }\n  public string LastName { get; }\n\n  public Person(string firstName, string lastName)\n  {\n    FirstName = firstName;\n    LastName = lastName;\n  }\n}\n```\n\nIn the following we'll consider extending and changing this type to expose various API patterns as we examine the individual language features.\n\nHere's an example of using the three language features:\n\n``` c#\nvar p = new Person { FirstName = \"Mickey\", LastName = \"Mouse\" }; // object initializer\nif (p is Person(\"Mickey\", *)) // positional deconstruction\n{\n  return p with { FirstName = \"Minney\" }; // with-expression\n}\n```\n\nSemantically this corresponds to something like this:\n\n``` c#\nvar p = new Person(\"Mickey\", \"Mouse\"); // constructor call\nif (p.FirstName == \"Mickey\") // property access\n{\n  return new Person(\"Minney\", p.LastName); // constructor call\n}\n```\n\nNotice how the new features that use property names correspond to API calls using positional parameters, whereas the feature that uses positions corresponds to member access by name!\n\n# Object initializers for immutable objects\n(See e.g. #229)\n\nThis feature allows an object initializer for which assignable properties are not found, to fall back to a constructor call taking the properties' new values as arguments.\n\n``` c#\nnew Person { FirstName = \"Mickey\", LastName = \"Mouse\" }\n```\nbecomes\n``` c#\nnew Person(\"Mickey\", \"Mouse\")\n```\n\nThe question then is: how does the compiler decide to pass the given FirstName as the first argument? Somehow it needs clues from the `Person` type as to which properties correspond to which constructor parameters. These clues cannot just be the constructor body: we need this to work across assemblies, so the clues must be evident from metadata.\n\nHere are some options:\n\n1: The type or constructor explicitly includes metadata for this purpose, e.g. in the form of attributes.\n2: The names of the constructor parameters must match exactly the names of the corresponding properties.\n\nThe former is unattractive because it requires the type's author to write those attributes. It requires the type to be explicitly edited for the purpose.\n\nThe latter is better in that it doesn't require extra API elements. However, API design guidelines stipulate that public properties start with uppercase, and parameters start with lower case. This pattern would break that, and for the same reason is highly unlikely to apply to any existing types.\n\nThis leads us to:\n\n3: The names of the constructor parameters must match the names of the corresponding properties, _modulo case_!\n\nThis would allow a large number of existing types to just work (including the example above), but at the cost of introducing case insensitivity to this part of the C# language. \n\n# With-expressions\n(see e.g. #5172)\n\nWith-expressions are similar to object initializers, except that they provide a source object from which to copy all the properties that aren't specified. Thus it seems reasonable to use a similar strategy for compilation; to call a constructor, this time filling in missing properties by accessing those on the source object.\n\nThus the same strategies as above would apply to establish the connection between properties and constructor parameters.\n\n``` c#\np with { FirstName = \"Minney\" }\n```\nbecomes\n``` c#\nnew Person(\"Minney\", p.LastName)\n```\n\nHowever, there's a hitch: if the runtime source object is actually of a derived type with more properties than are known from its static type, it would typically be expected that those are copied over too. In that case, the static type is also likely to be abstract (most base types are), so it wouldn't offer a callable constructor.\n\nFor this situation there needs to be a way that an abstract base class can offer \"with-ability\" that correctly copies over members of derived types. The best way we can think of is to offer a virtual `With` method, as follows:\n\n``` c#\npublic abstract class Person\n{\n  ...\n  public abstract Person With(string firstName, string lastName);\n}\n``` \n\nIn the presence of such a `With` method we would generate a with expression to call that instead of the constructor:\n\n``` c#\np.With(\"Minney\", p.LastName)\n```\n\nWe can decide whether to make with-expressions _require_ a `With` method, or fall back to constructor calls in its absence.\n\nIf we _require_ a `With` method, that makes for less interoperability with existing types. However, it gives us new opportunities for how to provide the position/name mapping metadata through the declaration of that `With` method: For instance, we could introduce a new kind of default parameter that explicitly wires the parameter to a property:\n\n``` c#\n  public abstract Person With(string firstName = this.FirstName, string lastName = this.LastName);\n``` \n\nTo explicitly facilitate interop with an existing type, a mandatory `With` method could be allowed to be provided as an extension method. It is unclear how that would work with the default parameter approach, though.\n\n# Positional deconstruction\n(see e.g. #206)\n\nThis feature allows a positional syntax for extracting the property values from an object, for instance in the context of pattern matching, but potentially also elsewhere.\n\nIdeally, a positional deconstruction would simply generate an access of each member whose value is obtained:\n\n``` c#\np is Person(\"Mickey\", *)\n```\nbecomes\n``` c#\np.FirstName == \"Mickey\"\n```\n\nAgain, this requires the compiler's understanding of how positions correspond to property names. Again, the same strategies as for object initializers are possible. See e.g. #8415.\n\nAdditionally, just as in with-expressions, one might wish to override the default behavior, or provide it if names don't match. Again, an explicit method could be used:\n\n``` c#\npublic abstract class Person\n{\n  ...\n  public void Person GetValues(out string firstName, out string lastName);\n}\n```\nThere are several options as to the shape of such a method. Instead of out-parameters, it might return a tuple. This has pros and cons: there could be only one tuple-returning `GetValues` method, because there would be no parameters to distinguish signatures. This may be a good or a bad thing.\n\nJust as the `With` method, we can decide whether deconstruction should _require_ a `GetValues` method, or should fall back to metadata or to name matching against the constructor's parameter names.\n\nIf the `GetValues` method is used, the compiler doesn't need to resolve between positions and properties: the deconstruction as well as the method are already positional. We'd generate the code as follows:\n\n``` c#\nstring __p1;\nstring __p2;\np.GetValues(out __p1, out __p2);\n...\n__p1 == \"Mickey\"\n```\n\nSomewhat less elegant for sure, and possibly less efficient, since the `LastName` is obtained for no reason. However, this is compiler generated code that no one has to look at, and it can probably be optimized, so this may not be a big issue.\n\n# Summary\n\nFor each of these three features we are grappling with the position-to-property match. Our options:\n\n1. Require specific metadata\n2. Match property and parameter names, possibly in a case sensitive way\n3. For deconstruction and with-expressions, allow or require specific methods (`GetValues` and `With` respectively) to implement their behavior, and possibly have special syntax in `With` methods to provide the name-to-position matching.\n\nWe continue to work on this."
  },
  {
    "path": "meetings/2016/LDM-2016-04-06.md",
    "content": "C# Design Notes for Apr 6, 2016\n===============================\n\nDiscussion for these design notes can be found at https://github.com/dotnet/roslyn/issues/10429.\n\nWe settled several open design questions concerning tuples and pattern matching.\n\n# Tuples\n\n## Identity conversion\n\nElement names are immaterial to tuple conversions. Tuples with the same types in the same order are identity convertible to each other, regardless of the names.\n\nThat said, if you have an element name at *one* position on one side of a conversion, and the same name at *another* position on the other side, you almost certainly have bug in your code:\n\n``` c#\n(string first, string last) GetNames() { ... }\n(string last, string first) names = GetNames(); // Oops!\n```\n\nTo catch this glaring case, we'll have a warning. In the unlikely case that you meant to do this, you can easily silence it e.g. by assigning through a tuple without names at all.\n\n## Boxing conversion\n\nAs structs, tuples naturally have a boxing conversion. Importantly, the names aren't part of the runtime representation of tuples, but are tracked only by the compiler. Thus, once you've \"cast away\" the names, you cannot recover them. In alignment with the identity conversions, a boxed tuple will unbox to any tuple type that has the same element types in the same order.\n\n## Target typing\n\nA tuple literal is \"target typed\" whenever possible. What that means is that the tuple literal has a \"conversion from expression\" to any tuple type, as long as the element expressions of the tuple literal have an implicit conversion to the element types of the tuple type.\n\n``` c#\n(string name, byte age) t = (null, 5); // Ok: the expressions null and 5 convert to string and byte\n```\n\nIn cases where the tuple literal is not part of a conversion, it acquires its \"natural type\", which means a tuple type where the element types are the types of the constituent expressions. Since not all expressions have types, not all tuple literals have a natural type either:\n\n``` c#\nvar t = (\"John\", 5); // Ok: the type of t is (string, int)\nvar t = (null, 5); //   Error: null doesn't have a type\n```\n\nA tuple literal may include names, in which case they become part of the natural type:\n\n``` c#\nvar t = (name: \"John\", age: 5); // The type of t is (string name, int age)\n```\n\n## Conversion propagation\n\nA harder question is whether tuple types should be convertible to each other based on conversions between their element types. Intuitively it seems that implicit and explicit conversions should just \"bleed through\" and compose to the tuples. This leads to a lot of complexity and hard questions, though. What kind of conversion is the tuple conversion? Different places in the language place different restrictions on which conversions can apply - those would have to be \"pushed down\" as well.\n\n``` c#\nvar t1 = (\"John\", 5);   // (string, int)\n(object, long) t2 = t1; // What kind of conversion is this? Where is it allowed\n```\n\nOn the whole we think that, while intuitive, the need for such conversions isn't actually that common. It's hard to construct an example that isn't contrived, involving for instance tuple-typed method parameters and the like. When you really need it, you can deconstruct the tuple and reconstruct it with a tuple literal, making use of target typing.\n\nWe'll keep an eye on it, but for now the decision is *not* to propagate element conversions through tuple types. We do recognize that this is a decision we don't get to change our minds on once we've shipped: adding conversions in a later version would be a significant breaking change.\n\n## Projection initializers\n\nTuple literals are a bit like anonymous types. The latter have \"projection initializers\" where if you don't specify a member name, one will be extracted from the given expression, if possible. Should we do that for tuples too?\n\n``` c#\nvar a = new { Name = c.FirstName, c.Age }; // Will have members Name and Age\nvar t = (Name: c.FirstName, c.Age); // (string Name, int Age) or error?\n```\n\nWe don't think so. The difference is that names are optional in tuples. It'd be too easy to pick up a random name by mistake, or get errors because two elements happen to pick up the same name.\n\n## Extension methods on tuples\n\nThis should just work according to existing rules. That means that extension methods on a tuple type apply even to tuples with different element names:\n\n``` c#\nstatic void M(this (int x, int y) t) { ... }\n\n(int a, int b) t = ...;\nt.M(); // Sure\n```\n\n## Default parameters\n\nLike other types, you can use `default(T)` to specify a default parameter of tuple type. Should you also be allowed to specify a tuple literal with suitably constant elements?\n\n``` c#\nvoid M((string, int) t = (\"Bob\", 7)) { ... } // Allowed?\n```\n\nNo. We'd need to introduce a new attribute for this, and we don't even know if it's a useful scenario.\n\n## Syntax for 0-tuples and 1-tuples?\n\nWe lovingly refer to 0-tuples as nuples, and 1-tuples as womples. There is already an underlying `ValueTuple<T>` of size one. We should will also have the non-generic `ValueTuple` be an empty struct rather than a static class.\n\nThe question is whether nuples and womples should have syntactic representation as tuple types and literals? `()` would be a natural syntax for nuples (and would no doubt find popularity as a \"unit type\" alternative to `void`), but womples are harder: parenthesized expressions already have a meaning! \n\nWe made no final decisions on this, but won't pursue it for now.\n\n## Return tuple members directly in scope\n\nThere is an idea to let the members of a tuple type appearing in a return position of a method be in scope throughout the method:\n\n``` c#\n(string first, string last) GetName()\n{\n  first = ...; last = ...; // Assign the result directly\n  return;                  // No need to return an explicit value\n}\n```\n\nThe idea here is to enhance the symmetry between tuple types and parameter lists: parameter names are in scope, why should \"result names\"?\n\nThis is cute, but we won't do it.  It is too much special casing for a specific placement of tuple types, and it is also actually preferable to be able to see exactly what is returned at a given `return` statement.\n\n\n# Integrating pattern matching with is-expressions and switch-statements\nFor pattern matching to feel natural in C# it is vital that it is deeply integrated with existing related features, and does in fact take its queues from how they already work. Specifically we want to extend is-expressions to allow patterns where today they have types, and we want to augment switch-statements so that they can switch on any type, use patterns in case-clauses and add additional conditions to case-clauses using when-clauses.\n\nThis integration is not always straightforward, as witnessed by the following issues. In each we need to decide what patterns should *generally* do, and mitigate any breaking changes this would cause in currently valid code.\n\n\n## Name lookup\n\nThe following code is legal today:\n\n``` c#\nif (e is X) {...}\nswitch(e) { case X: ... }\n```\n\nWe'd like to extend both the places where `X` occurs to be patterns. However, `X` means different things in those two places. In the `is` expression it must refer to a type, whereas in the `case` clause it must refer to a constant. In the `is` expression we look it up as a type, ignoring any intervening members called `X`, whereas in the `case` clause we look it up as an expression (which can include a type), and give an error if the nearest one found is not a constant.\n\nAs a pattern we think `X` should be able to both refer to a type and a constant. Thus, we prefer the `case` behavior, and would just stop giving an error when `case X:` refers to a type. For `is` expressions, to avoid a breaking change, we will first look for just a type (today's behavior), and if we don't find one, rather than error we will look again for a constant.\n\n## Conversions in patterns\n\nAn `is` expression today will only acknowledge identity, reference and boxing conversions from the run-time value to the type. It looks for \"the actual\" type, if you will, without representation changes:\n \n``` c#\nbyte b = 5;\nWriteLine(b is byte);           // True:  identity conversion\nWriteLine((object)b is byte);   // True:  boxing conversion\nWriteLine((object)b is object); // True:  reference conversion\nWriteLine(b is int);            // False: numeric conversion changes representation\n```\n\nThis seems like the right semantics for \"type testing\", and we want those to carry over to pattern matching. \n\nSwitch statements are more weird here today. They have a fixed set of allowed types to switch over (primitive types, their nullable equivalents, strings). If the expression given has a different type, but has a unique implicit conversion to one of the allowed ones, then that conversion is applied! This occurs mainly (only?) when there is a user defined conversion from that type to the allowed one.\n\nThat of course is intended only for constant cases. It is not consistent with the behavior we want for type matching per the above, and it is also not clear how to generalize it to switch expressions of arbitrary type. It is behavior that we want to limit as much as possible.\n\nOur solution is that in switches *only* we will apply such a conversion on the incoming value *only* if all the cases are constant. This means that if you add a non-constant case to such a switch (e.g. a type pattern), you will break it. We considered more lenient models involving applying non-constant patterns to the *non*-converted input, but that just leads to weirdness, and we don't think it's necessary. If you *really* want your conversion applied, you can always explicitly apply it to the switch expression yourself.\n\n\n## Pattern variables and multiple case labels\n\nC# allows multiple case labels on the same body. If patterns in those case labels introduce variables, what does that mean?\n\n``` c#\ncase int i:\ncase byte b:\n    WriteLine(\"Integral value!\");\n    break;\n```\n\nHere's what it means: The variables go into the same declaration space, so it is an error to introduce two of the same name in case clauses for the same body. Furthermore, the variables introduced are not definitely assigned, because the given case clause assigns them, and you didn't necessarily come in that way. So the above example is legal, but the body cannot read from the variables `i` and `b` because they are not definitely assigned.\n\nIt is tempting to consider allowing case clauses to share variables, so that they could be extracted from similar but different patterns:\n``` c#\ncase (int age, string name):\ncase (string name, int age):\n    WriteLine($\"{name} is {age} years old.\");\n    break;\n```\n\nWe think that is way overboard right now, but the rules above preserve our ability to allow it in the future.\n\n## Goto case\n\nIt is tempting to ponder generalizations of `goto case x`. For instance, maybe you could do the whole switch again, but on the value `x`. That's interesting, but comes with lots of complications and hidden performance traps. Also it is probably not all that useful.\n\nInstead we just need to preserve the simple meaning of `goto case x` from current switches: it's allowed if `x` is constant, if there's a case with the same constant, and that case doesn't have a `when` clause.\n\n## Errors and warnings\n\nToday `3 is string` yields a warning, while `3 as string` yields and error. They philosophy seems to be that the former is just asking a question, whereas the other is requesting a value. Generalized `is` expressions like `3 is string s` are sort of a combination of `is` and `as`, both answering the question and (conditionally) producing a value. Should they yield warnings or errors?\n\nWe didn't reach consensus and decided to table this for later.\n\n## Constant pattern equality\n\nIn today's `switch` statement, the constants in labels must be implicitly convertible to the governing type (of the switch expression). The equality is then straightforward - it works the same as the `==` operator. This means that the following case will print `Match!`.\n\n``` c#\nswitch(7)\n{\n  case (byte)7:\n    WriteLine(\"Match!\");\n    break;\n}\n```\n\nWhat should be the case if we switch on something of type object instead?:\n\n``` c#\nswitch((object)7)\n{\n  case (byte)7:\n    WriteLine(\"Match!\");\n    break;\n}\n```\n\nOne philosophy says that it should work the same way regardless of the static type of the expression. But do we want constant patterns everywhere to do \"intelligent matching\" of integral types with each other? That certainly leads to more complex runtime behavior, and would probably require calling helper methods. And what of other related types, such as `float` and `double`? There isn't similar intelligent behavior you can do, because the representations of most numbers will differ slightly and a number such as 2.1 would thus not be \"equal to itself\" across types anyway.\n\nThe other option is to make the behavior different depending on the compile-time type of the expression. We'll use integral equality only if we know statically which one to pick, because the left hand side was also known to be integral. That would preserve the switch behavior, but make the pattern's behavior dependent on the static type of the expression.\n\nFor now we prefer the latter, as it is simpler.\n\n\n# Recursive patterns\n\nThere are several core design questions around the various kinds of recursive patterns we are envisioning. However, they seem to fall in roughly two categories:\n\n1. Determine the syntactic shape of each recursive pattern in itself, and use that to ensure that the places where patterns can occur are syntactically well-formed and unambiguous.\n2. Decide exactly how the patterns work, and what underlying mechanisms enable them.\n\nThis is an area to focus more on in the future. For now we're just starting to dig in.\n\n## Recursive pattern syntax\n\nFor now we envision three shapes of recursive patterns\n\n1. Property patterns: `Type { Identifier_1 is Pattern_1, ... , Identifier_n is Pattern_n }`\n2. Tuple patterns: `(Pattern_1, ... Pattern_n)`\n3. Positional patterns: `Type (Pattern_1, ... Pattern_n)`\n\nThere's certainly room for evolution here. For instance, it is not lost on us that 2 and 3 are identical except for the presence of a type in the latter. At the same time, the presence of a type in the latter seems syntactically superfluous in the cases where the matched expression is already known to be of that type (so the pattern is used purely for deconstruction and/or recursive matching of the elements). Those two observations come together to suggest a more orthogonal model, where the types are optional:\n\n1. Property patterns: `Type_opt { Identifier_1 is Pattern_1, ... , Identifier_n is Pattern_n }`\n2. Positional patterns: `Type_opt (Pattern_1, ... Pattern_n)`\n\nIn this model, what was called \"tuple patterns\" above would actually not just apply to tuples, but to anything whose static type (somehow) specifies a suitable deconstruction.\n\nThis is important because it means that \"irrefutable\" patterns - ones that are known to always match - never need to specify the type. This in turn means that they can be used for unconditional deconstruction even in syntactic contexts where positional patterns would be ambiguous with invocation syntax. For instance, we could have what would amount to a \"deconstruction\" variant of a declaration statement, that would introduce all its match variables into scope as local variables for subsequent statements:\n \n``` c#\n(string name, int age) = GetPerson();    // Unconditional deconstruction\nWriteLine($\"{name} is {age} years old\"); // name and age are in scope\n\n```\n\n## How recursive patterns work\n\nProperty patterns are pretty straightforward - they translate into access of fields and properties.\n\nTuple patterns are also straightforward if we decide to handle them specially.\n\nPositional patterns are more complex. We agree that they need a way to be specified, but the scope and mechanism for this is still up for debate. For instance, the `Type` in the positional pattern may not necessarily trigger a type test on the object. Instead it may name a class where a more general \"matcher\" is defined, which does its own tests on the object. This could be complex stuff, like picking a string apart to see if it matches a certain format, and extracting certain information from it if so.\n\nThe syntax for declaring such \"matchers\" may be methods, or a new kind of user defined operator (like `is`) or something else entirely. We still do not have consensus on either the scope or shape of this, so there's some work ahead of us.\n\nThe good news is that we can add pattern matching in several phases. There can be a version of C# that has pattern matching with none or only some of the recursive patterns working, as long as we make sure to \"hold a place for them\" in the way we design the places where patterns can occur. So C# 7 can have great pattern matching even if it doesn't yet have *all* of it. \n "
  },
  {
    "path": "meetings/2016/LDM-2016-04-12-22.md",
    "content": "# C# Design Notes for Apr 12-22, 2016\n\nThese notes summarize discussions across a series of design meetings in April on several topics related to tuples and patterns:\n- Tuple syntax for non-tuple types\n- Tuple deconstruction\n- Tuple conversions\n- Deconstruction and patterns\n- Out vars and their scope\n\nThere's still much more to do here, but lots of progress.\n# Tuple syntax for other types\n\nWe are introducing a new family of `System.ValueTuple<...>` types to support tuples in C#. However, there are already types that are tuple-like, such as `System.Tuple<...>` and `KeyValuePair<...>`. Not only are these often used throughout C# code, but the former is also what's targeted by F#'s tuple mechanism, which we'd want our tuple feature to interoperate well with.\n\nAdditionally you can imagine allowing other types to benefit from some, or all, of the new tuple syntax.\n\nThe obvious kinds of interop would be tuple construction and deconstruction. Since tuple literals are target typed, consider a tuple literal that is assigned to another tuple-like type:\n\n``` c#\nSystem.Tuple<int, string> t = (5, null);\n```\n\nWe could think of this as calling `System.Tuple`'s constructor, or as a conversion, or maybe something else. Similarly, tuples will allow deconstruction and \"decorated\" names tracked by the compiler. Could we allow those on other types as well?\n\nThere are several levels of support we could decide land on:\n1. Only tuples are tuples. Other types are on their own.\n2. Specific well-known tuple-like things are also tuples (probably `Tuple<...>` and `KeyValuePair<...>`).\n3. An author of a type can make it tuple-like through certain API patterns\n4. I can make anything work with tuple syntax without being the author of it\n5. All types just work with it\n\nLevel 2 would be enough to give us F# interop and improve the experience with existing APIs using `Tuple<...>` and `KeyValuePair<...>`. Option 3 could rely on any kind of declarations in the type, whereas option 4 would limit that to instance-method patterns that someone else could add through extension methods. \n\nIt is hard to see how option 5 could work for deconstruction, but it might work for construction, simply by treating a tuple literal as an argument list to the type's constructor. One might consider it invasive that a type's constructor can be called without a `new` keyword or any mention of the type! On the other hand this might also be seen as a really nifty abbreviation. One problem would be how to use it with constructors with zero or one argument. So far we haven't opted to add syntax for 0-tuples and 1-tuples.\n\nWe haven't yet decided which level we want to target, except we want to at least make  `Tuple<...>` and `KeyValuePair<...>` work with tuple syntax. Whether we want to go further is a decision we probably cannot put off for a later version, since a later addition of capabilities might clash with user-defined conversions.\n# Tuple deconstruction\n\nWhether deconstruction works for other types or not, we at least want to do it for tuples. There are three contexts in which we consider tuple deconstruction:\n1. **Assignment:** Assign a tuple's element values into existing variables\n2. **Declaration:** Declare fresh variables and initialize them with a tuple's element values\n3. **Pattern matching:** Recursively apply patterns to each of a tuple's element values\n\nWe would like to add forms of all three.\n## Deconstructing assignments\n\nIt should be possible to assign to existing variables, to fields and properties, array elements etc., the individual values of a tuple:\n\n``` c#\n(x, y) = currentFrame.Crop(x, y); // x and y are existing variables\n(a[x], a[x+1], a[x+2]) = GetCoordinates();\n```\n\nWe need to be careful with the evaluation order. For instance, a swap should work just fine:\n\n``` c#\n(a, b) = (b, a); // Yay!\n```\n\nA core question is whether this is a new syntactic form, or just a variation of assignment expressions. The latter is attractive for uniformity reasons, but it does raise some questions. Normally, the type and value of an assignment expression is that of its left hand side after assignment. But in these cases, the left hand side has multiple values and types. Should we construct a tuple from those and yield that? That seems contrary to this being about _deconstructing_ not _constructing_ tuples!\n\nThis is something we need to ponder further. As a fallback we can say that this is a new form of assignment _statement_, which doesn't produce a value.\n## Deconstructing declarations\n\nIn most of the places where local variables can be introduced and initialized, we'd like to allow deconstructing declarations - where multiple variables are declared, but assigned collectively from a single tuple (or tuple-like value):\n\n``` c#\n(var x, var y) = GetCoordinates();             // locals in declaration statements\nforeach ((var x, var y) in coordinateList) ... // iteration variables in foreach loops\nfrom (x, y) in coordinateList ...              // range variables in queries\nM(out (var x, var y));                         // tuple out parameters\n```\n\nFor range variables in queries, this would depend on clever use of transparent identifiers over tuples. \n\nFor out parameters this may require some form of post-call assignment, like VB has for properties passed to out parameters. That may or may not be worth it.\n\nFor syntax, there are two general approaches: \"Types-with-variables\" or \"types-apart\".\n\n``` c#\n// Types-with-variables:\n(string first, string last) = GetName(); // Types specified\n(var first, var last) = GetName();       // Types inferred\nvar (first, last) = GetName();           // Optional shorthand for all var\n\n// Types-apart:\n(string, string) (first, last) = GetName(); // Types specified\nvar (first, last) = GetName();              // All types inferred\n(var, var) (first, last) = GetName();       // Optional long hand for types inferred\n```\n\nThis is mostly a matter of intuition and taste. For now we've opted for the types-with-variables approach, allowing the single `var` shorthand. One benefit is that this looks more similar to what we envision deconstruction in tuples to look like. Feedback may change our mind on this.\n\nMultiple variables won't make sense everywhere. For instance they don't seem appropriate or useful in using-statements. We'll work through the various declaration contexts one by one.\n## Other deconstruction questions\n\nShould it be possible to deconstruct a longer tuple into fewer variables, discarding the rest? As a starting point, we don't think so, until we see scenarios for it.\n\nShould we allow optional tuple member names on the left hand side of a deconstruction? If you put them in, it would be checked that the corresponding tuple element had the name you expected:\n\n``` c#\n(x: a, y: b) = GetCoordinates(); // Error if names in return tuple aren't x and y \n```\n\nThis may be useful or confusing. It is also something that can be added later. We made no immediate decision on it.\n# Tuple conversions\n\nViewed as generic structs, tuple types aren't inherently covariant. Moreover, struct covariance is not supported by the CLR. And yet it seems entirely reasonable and safe that tuple values be allowed to be assigned to more accommodating tuple types:\n\n``` c#\n(byte, short) t1 = (1, 2);\n(int, int t2) = t1; // Why not?\n```\n\nThe intuition is that tuple conversion should be thought of in a _pointwise_ manner. A tuple type is convertible (in a given manner) to another if each of their element types are pairwise convertible (in the same manner) to each other.\n\nHowever, if we are to allow this we need to build it into the language specifically - sometimes implementing tuple assignment as assigning the elements one-by-one, when the CLR doesn't allow the wholesale assignment of the tuple value.\n\nIn essence we'd be looking at a situation similar to when we introduced nullable value types in C# 2. Those are implemented in terms of generic structs, but the language adds extensive special semantics to these generic structs, allowing operations - including covariant conversions - that do not automatically fall out from the underlying representation.\n\nThis language-level relaxation comes with some subtle breaks that can happen on upgrade. Consider the following code, where C.dll is a C# 6 consumer of C# 7 libraries A.dll and B.dll:\n\n``` c#\nA.dll:\n\n(int, long) Foo()... // ValueTuple<int, long> Foo();\n\nB.dll:\n\nvoid Bar(object o)\nvoid Bar((int?, long?) t)\n\nC.dll:\n\nBar(Foo());\n```\n\nBecause C# 6 has no knowledge of tuple conversions, it would pick the first overload of `Bar` for the call. However, when the owner of C.dll upgrades to C# 7, relaxed tuple conversion rules would make the second overload applicable, and a better pick.\n\nIt is important to note that such breaks are esoteric. Exactly parallel examples could be constructed for when nullable value types were introduced; yet we never saw them in practice. Should they occur they are easy to work around. As long as the underlying type (in our case `ValueTuple<...>`) and the conversion rules are introduced at the same time, the risk of programmers getting them mixed in a dangerous manner is minimal.\n\nAnother concern is that \"pointwise\" tuple conversions, just like nullable value types, are a pervasive change to the language, that affects many parts of the spec and implementation. Is it worth the trouble? After all it is pretty hard to come up with compelling examples where conversions between two tuple _types_ (as opposed to _from_ tuple literals or _to_ individual variables in a deconstruction) is needed.\n\nWe feel that tuple conversions are an important part of the intuition around tuples, that they are primarily \"groups of values\" rather than \"values in and of themselves\". It would be highly surprising to developers if these conversions didn't work. Consider the baffling difference between these two pieces of code if tuple conversions didn't work:\n\n``` c#\n(long, long) tuple = (1, 1);\n\nvar tmp = (1, 1);\n(long, long) tuple = tmp; // Doesn't work??!?\n```\n\nAll in all we feel that pointwise tuple conversions are worth the effort. Furthermore it is crucial that they be added at the same time as the tuples themselves. We cannot add them later without significant breaking changes.\n## Tuples vs ValueTuple\n\nIn accordance with this philosophy we cannot say more about the relationship between language level tuple types and the underlying `ValueTuple<...>` types.\n\nJust like `Nullable<T>` is equivalent to `T?`, so `ValueTuple<T1, T2, T3>` should be in every way equivalent to the unnamed `(T1, T2, T3)`. That means the pointwise conversions also work when tuple types are specified using the generic syntax.\n\nIf the tuple is bigger than the limit of 7, the implementation will nest the \"tail\" as a tuple into the eighth element recursively. This nesting is visible by accessing the `Rest` field of a tuple, but that field is considered an implementation detail, and is hidden from e.g. auto-completion, just as the ItemX field names are hidden but allowed when a tuple has named elements.\n\nA well formed \"big tuple\" will have names `Item1` etc. all the way up to the number of tuple elements, even though the underlying type doesn't physically have those fields directly defined. The same goes for the tuple returned from the `Rest` field, only with the numbers \"shifted\" appropriately. All this says is that the tuple in the `Rest` field is treated the same as all other tuples.\n# Deconstructors and patterns\n\nWhether or not we allow arbitrary values to opt in to the unconditional tuple deconstruction described above, we know we want to enable such positional deconstruction in recursive patterns:\n\n``` c#\nif (o is Person(\"George\", var last)) ...\n```\n\nThe question is: how exactly does a type like `Person` specify how to be positionally deconstructed in such cases? There are a number of dimensions to this question, along with a number of options for each:\n- Static or instance/extension member?\n- `GetValues` method or new `is` operator?\n- Return tuple or tuple out parameter or several out parameters?\n\nSelecting between these, we have to observe a number of different tradeoffs:\n1. Overloadable or not?\n2. Yields tuple or individual values?\n3. Growth path to \"active patterns\"?\n4. Can be applied to existing types without modifying them?\n\nLet's look at these in turn.\n## Overloadability\n\nIf the multiple extracted values are returned as a tuple from a method (whether static or instance) then that method cannot be overloaded. \n\n``` c#\npublic (string firstName, string lastName) GetValues() { ... }\n```\n\nThe deconstructor is essentially canonical. That may not be a big deal from a usability perspective, but it does hamper the evolution of the type. If it ever adds another member and wants to enable access to it through deconstruction, it needs to _replace_ the deconstructor, it cannot just add a new overload. This seems unfortunate.\n\nA method that yields it results through one or more out parameters can be overloaded in C#. Also, for a new kind of user defined operator we can decide the overloading rule whichever way we like. For instance, conversion operators today can be overloaded on return type.\n## Tuple or individual values\n\nIf a deconstructor yields a tuple, then that confers special status to tuples for deconstruction. Essentially tuples would have their own built-in deconstruction mechanism, and all other types would defer to those by supplying a tuple.\n\nEven if we rely on multiple out parameters, tuples cannot just use the same mechanism. In order to do so, long tuples would need to be enhanced by the compiler with an implementation that hides the nested nature of such tuples.\n\nThere doesn't seem to be any strong benefit to yielding a single tuple over multiple values (in out parameters). \n## Growing up to active patterns\n\nThere's a proposal where one type gets to specify deconstruction semantics for another, along even with logic to determine whether the pattern applies or not. We do not plan to support that in the first go-around, but it is worth considering whether the deconstruction mechanism lends itself to such an extension.\n\nIn order to do so it would need to be static (so that it can specify behavior for an object of _another_ type), and would benefit from an out-parameter-based approach, so that the return position could be reserved for returning a boolean when the pattern is conditional.\n\nThere is a lot of speculation involved in making such concessions now, and we could reasonably rely on our future selves to invent a separate specification mechanism for active patterns without us having to accommodate it now. \n## Conclusion\n\nThis was an exploration of the design space. The actual decision is left to a future meeting.\n# Out vars and their scope\n\nWe are in favor of reviving a restricted version of the declaration expressions that were considered for C# 6. This would allow methods following the TryFoo pattern to behave similarly to the new pattern-based is-expressions in conditions:\n\n``` c#\nif (int.TryParse(s, out var i) && i > 0) ...\n```\n\nWe call these \"out vars\", even though they are perfectly fine to specify a type. The scope rules for variables introduced in such contexts would be the same as variables coming from a pattern: they generally be in scope within all of the nearest enclosing statement, except when that is an if-statement, where they would not be in scope in the else-branch.\n\nOn top of that there are some relatively esoteric positions we need to decide on.\n\nIf an out var occurs in a _field initializer_, where should it be in scope? Just within the declarator where it occurs, not even in subsequent declarators of the same field declaration.\n\nIf an out var occurs in a _constructor initializer_ (`this(...)` or `base(...)`) where should it be in scope? Let's not even allow that - there's no way you could have written equivalent code yourself.\n"
  },
  {
    "path": "meetings/2016/LDM-2016-05-03-04.md",
    "content": "# C# Design Notes for May 3-4, 2016\n\nThis pair of meetings further explored the space around tuple syntax, pattern matching and deconstruction. \n1. Deconstructors - how to specify them\n2. Switch conversions - how to deal with them\n3. Tuple conversions - how to do them\n4. Tuple-like types - how to construct them\n\nLots of concrete decisions, that allow us to make progress on implementation.\n# Deconstructors\n\nIn [#11031](https://github.com/dotnet/roslyn/issues/11031) we discussed the different contexts in which deconstruction should be able to occur, namely deconstructing _assignment_ (into existing variables), _declaration_ (into freshly declared local variables) and _patterns_ (as part of applying a recursive pattern).\n\nWe also explored the design space of how exactly \"deconstructability\" should be specified for a given type, but left the decision open - until now. Here's what we decided - and why. We'll stick to these decisions in initial prototypes, but as always are willing to be swayed by evidence as we roll them out and get usage.\n\n**_Deconstruction should be specified with an instance (or extension) method**_. This is in keeping with other API patterns added throughout the history of C#, such as `GetEnumerator`, `Add`, and `GetAwaiter`. The benefit is that this leads to a relatively natural kind of member to have, and it can be specified with an extension method so that existing types can be augmented to be deconstructable outside of their own code.\n\nThe choice limits the ability of the pattern to later grow up to facilitate \"active patterns\". We aren't too concerned about that, because if we want to add active patterns at a later date we can easily come up with a separate mechanism for specifying those.\n\n**_The instance/extension method should be called `Deconstruct`**_. We've been informally calling it `GetValues` for a while, but that name suffers from being in too popular use already, and not always for a similar purpose. This is a decision we're willing to alter if a better name comes along, and is sufficiently unencumbered.\n\n**_The Deconstruct method \"returns\" the component values by use of individual out parameters**_. This choice may seem odd: after all we're adding a perfectly great feature called tuples, just so that you can return multiple values! The motivation here is primarily that we want `Deconstruct` to be overloadable. Sometimes there are genuinely multiple ways to deconstruct, and sometimes the type evolves over time to add more properties, and as you extend the `Deconstruct` method you also want to leave an old overload available for source and binary compat.\n\nThis one does nag us a little, because the declaration form with tuples is so much simpler, and would be sufficient in a majority of cases. On the other hand, this allows us to declare decomposition logic _for_ tuples the same way as for other types, which we couldn't if we depended on tuples for it!\n\nShould this become a major nuisance (we don't think so) one could consider a hybrid approach where both tuple-returning and out-parameter versions were recognized, but for now we won't.\n\nAll in all, the deconstructor pattern looks like one of these:\n\n``` c#\nclass Name\n{\n    public void Deconstruct(out string first, out string last) { first = First; last = Last; }\n    ...\n}\n// or\nstatic class Extensions\n{\n    public static void Deconstruct(this Name name, out string first, out string last) { first = name.First; last = name.Last; }\n}\n```\n# Switch conversions\n\nSwitch statements today have a wrinkle where they will apply a unique implicit conversion from the switched-on expression to a (currently) switchable type. As we expand to allow switching on any type, this may be confusing at times, but we need to keep it at least in some scenarios, for backwards compatibility.\n\n``` c#\nswitch (expr) // of some type Expression, which \"cleverly\" has a user defined conversion to int for evaluation\n{\n    case Constant(int i): ... // Won't work, though Constant derives from Expression, because expr has been converted to int\n    ...\n}\n```\n\nOur current stance is that this is fringe enough for us to ignore. If you run into such a conversion and didn't want it, you'll have to work around it, e.g. by casting your switch expression to object.\n\nIf this turns out to be more of a nuisance we may have to come up with a smarter rule, but for now we're good with this.\n# Tuple conversions\n\nIn #11031 we decided to add tuple conversions, that essentially convert tuples whenever their elements convert - unlike the more restrictive conversions that follow from `ValueTuple<...>` being a generic struct. In this we view nullable value types as a great example of how to imbue a language-embraces special type with more permissive conversion semantics.\n\nAs a guiding principle, we would like tuple conversions to apply whenever a tuple can be deconstructed and reassembled into the new tuple type:\n\n``` c#\n(string, byte) t1 = ...;\n(object, int) t2 = t1;     // Allowed, because the following is:\n(var a, var b) = t1;       // Deconstruct, and ...\n(object, int) t2 = (a, b); // reassemble\n```\n\nOne problem is that nullable value type conversions are rather complex. They affect many parts of the language. It'd be great if we could make tuple conversions simpler. There are two principles we can try to follow:\n1. A tuple conversion is a specific _kind_ of conversion, and it allows specific _kinds_ of conversions on the elements\n2. A tuple conversion works in a given setting if all of its element conversions would work in that setting\n\nThe latter is more general, more complex and possibly ultimately necessary. However, somewhat to our surprise, we found a definition along the former principle that we cannot immediately poke a hole in:\n\n> An _implicit tuple conversion_ is a standard conversion. It applies between two tuple types of equal arity when there is _any_ implicit conversion between each corresponding pair of types. \n\n(Similarly for explicit conversions).\n\nThe interesting part here is that it's a standard conversion, so it is able to be composed with user defined conversions. Yet, its elements are allowed to perform their own user defined conversions! It feels like something could go wrong here, with recursive or circular application of user defined conversions, but we haven't been able to pinpoint an example.\n\nA definition like this would be very desirable, because it won't require so much special casing around the spec.\n\nWe will try to implement this and see if we run into problems.\n# Tuple-like construction of non-tuple types\n\nWe previously discussed to what extent non-tuple types should benefit from the tuple syntax. We've already decided that the deconstruction syntax applies to any type with a deconstructor, not just tuples. So what about construction?\n\nThe problem with allowing tuple literal syntax to construct any type is that _all_ types have constructors! There's no opt-in. This seems too out of control. Furthermore, it doesn't look intuitive that any old type can be \"constructed\" with a tuple literal:\n\n``` c#\nDictionary<int, string> d = (16, EqualityComparer<int>.Default); / Huh???\n```\n\nThis only seems meaningful if the constructor arguments coming in through a \"tuple literal\" are actually the constituent data of the object being created.\n\nFinally, we don't have syntax for 0 and 1-tuples, so unless we add that, this would only even work when there's more than one constructor argument to the target type.\n\nAll in all, we don't think tuple literals should work for any types other than the built-in tuples. Instead, we want to brush off a feature that we've looked at before; the ability to omit the type from an object creation expression, when there is a target type:\n\n``` c#\nPoint p = new (3, 4); // Same as new Point(3, 4)\nList<string> l1 = new (10); // Works for 0 or 1 argument\nList<int> l2 = new (){ 3, 4, 5 }; // Works with object/collection initializers, but must have parens as well.\n```\n\nSyntactically we would say that an object creation expression can omit the type when it has a parenthesized argument list. In the case of object and collection initializers, you cannot omit both the type and the parenthesized argument list, since that would lead to ambiguity with anonymous objects.\n\nWe think that this is promising. It is generally useful, and it would work nicely in the case of existing tuple-like types such as `System.Tuple<...>` and `KeyValuePair<...>`.\n"
  },
  {
    "path": "meetings/2016/LDM-2016-05-10.md",
    "content": "# C# Language Design Notes for May 10, 2016\n\nIn this meeting we took a look at the possibility of adding new kinds of extension members, beyond extension methods.\n## Extension members\n\nEver since we added extension methods in C# 3.0, there's been a consistent ask to add a similar feature for other kinds of function members. While \"instance methods\" are clearly the most important member kind to \"extend with\" from the outside, it seems arbitrary and limiting not to have e.g. properties, constructors or static members.\n\nUnfortunately, the declaration syntax for extension methods is sort of a local optimum. The static method with the extra `this` parameter works great for methods: It is low cost, and it comes with an obvious disambiguation syntax. However, this approach doesn't carry over well to other kinds of members. A property with an extra `this` parameter? And how would extension static members attach to their type - cannot be through a `this` parameter representing an instance! As we were designing C# 4 we tried very hard to answer these questions and design an \"extension everything\" feature that was a syntactic extension (no pun intended) of extension methods. We failed, creating a succession of monsters until we gave up.\n\nThe other option is to take a step back, and do a different style of design. Most proposals nowadays do this, and the idea actually goes all the way back to debates we had when adding extension methods in the first place: instead of the extension _members_ saying what they extend, maybe they should be grouped into \"extensions\"; class-like groups of extension methods that all extend the same type. With the enclosing \"extension class\" doing all the extension, the members can just be declared with their normal syntax:\n\n``` c#\nclass Person\n{\n    public string Name { get; }\n    public Person(string name) { Name = name; }\n}\n\nextension class Enrollee extends Person\n{\n    static Dictionary<Person, Professor> enrollees = new ();                                            // static field\n    public void Enroll(Professor supervisor) { enrollees[this] = supervisor; }                          // instance method\n    public Professor Supervisor => enrollees.TryGetValue(this, out var supervisor) ? supervisor : null; // instance property\n    public static ICollection<Person> Students => enrollees.Keys;                                       // static property\n    public Person(string name, Professor supervisor) : this(name) { this.Enroll(supervisor); }          // constructor\n}\n```\n\nIssue [#11159](https://github.com/dotnet/roslyn/issues/11159) summarizes the recent proposals along these lines.\n\nThis syntactic approach has clear advantages - writing an extension member is as simple as writing a normal member. It does have some challenges, too. One is, what does it compile into? Another is, how do you disambiguate when several extension members are in scope? Those are trivially answered by the current extension methods, but need more elaborate answers here.\n\nLooking at our current BCL libraries, it is clear that there are many places where layering is poor. Essentially, there's a trade off between layering (separating dependencies) and discoverability (offering members _on_ the important types). _If_ you have a file system, you want to offer a constructor overload that takes a file name. Extension constructors (for instance) address this.\n\nAlso, extension members allow putting concrete functionality on interfaces, and on specific instances of generic types.\n\nWe think that the most useful and straightforward kinds of extension methods to add would be instance and static versions of methods, properties and indexers, as well as static fields. We don't think instance fields make sense - where would they live? The answer to that is at best complicated, and probably not efficient.\n\nExtension constructors would also be useful. There's a bit more of a design space here, depending on whether you want them to be just like instance constructors (which would require the specific extended type to already have a constructor to delegate to), or more like factories (which could be added to interfaces etc. and produce instances of more derived types).\n\nExtension operators are in a bit of a gray zone. Some of them, like arithmetic operators, probably make sense. Equality operators are hard, because everyone's already got one, so the \"built-in\" would always shadow. Implicit conversion operators are especially problematic, because their invocation doesn't have an associated syntax, so it's very subtle when they are applied, and there's no easy way to choose _not_ to do it.\n\nImplementation-wise, the extension class would probably turn into a static class, and the extension members would probably be represented as static methods, with the most obvious mapping we can find. There's a case for implementing extension properties via \"indexed properties\" which are supported in IL (and VB), though maybe we'd prefer mapping to something that could be written directly in C#.\n\nThe name of the extension would be the name of the static class, and can also be used in disambiguation, for which we would need a syntax. Maybe existing syntax, such as `((Enrollee)person).Supervisor` or `(person as Enrollee).Supervisor` could be used when disambiguating instance members or operators, whereas static members would just be accessed directly off of the generated static class, as in `Enrollee.Students`.\n\nArguably, consumption is more important than production. In this case, that is an argument both for and against introducing a new syntactic approach to declaring extension members: On the one hand, it makes it less of a problem if we effectively deprecate the existing syntax, on the other it makes it less compelling to add syntax for it, instead of maybe some attribute-based approach, or other less syntax-heavy solutions.\n\nFor extension properties, people often point to `Enumerable.Count(IEnumerable src)` as an example of why they want them, but that's a terrible example, because it isn't efficient. Even so, there's probably a good need for these - the Roslyn code base for instance has many little extension methods on top of interfaces, that \"should\" have been properties. `Kind()` is a perfect example.\n## Conclusion\n\nWe think this is worth pursuing further. We will come back to it in future design meetings to start ironing out the details.\n"
  },
  {
    "path": "meetings/2016/LDM-2016-07-12.md",
    "content": "# C# Language Design Notes for Jul 12, 2016\n## Agenda\n\nSeveral design details pertaining to tuples and deconstruction resolved.\n# All or nothing with element names?\n\nThere's certainly a case for partial names on literals - sometimes you want to specify the names of _some_ of the elements for clarity. These names have to fit names in the tuple type that the literal is being converted to:\n\n``` c#\nList<(string firstName, string lastName, bool paid)> people = ...;\n\npeople.Add((\"John\", \"Doe\", paid: true)); \n```\n\nDo we also want to allow partial names in _types_?\n\nYes we do. We don't have strong arguments against it, and generality calls for it. It's likely that there are scenarios, and not allowing will feel arbitrary. \"The `bool` deserves a clarifying name, but the `TypeSymbol` is clear\".\n\n``` c#\nvar t = (1, y: 2); // infers (int, int y)\n(int x, int) t = (1, 2);\n```\n\nAs a reminder, we distinguish between leaving out the name and explicitly specifying `Item1`, `Item2`, etc. You get a warning if you use `Item1`... in literals if they are not explicitly there in the target type. (Warning)`\n\n``` c#\n(int, int) t = (Item1: 1, Item2: 2); // Warning, names are lost\n```\n\nFor the editor experience we imagine offering completion of a named element in the corresponding position of a tuple literal.\n# ITuple\n\n``` c#\ninterface ITuple\n{\n    int Size;\n    object this[int i] { get; }\n}\n```\n\n`ITuple` is really an interface for dynamically checking for deconstructability. Whether we should add `ITuple` now depends on whether we think we want to allow recursive patterns to do that, once we add them.\n\nWe _do_ think we want that.\n\nWe cannot use an existing collection interface (such as `IReadOnlyCollection`) because we want to be able to distinguish between deconstructable objects and collections (which might one day get their own pattern). It is fine for a class to implement both.\n\n`ValueTuple<...>` should of course implement `ITuple`, and the translation of long tuples should work.\n\nThe Framework team should chime in on the specific shape and names on the interface. Is `ITuple` the right name, or is it too narrow?  Is `IDeconstructable` more to the point or is it too long? Should it be `Size` or `Length` or `Count`?\n# var when var type exists\n\n``` c#\nclass var {}\nvar (x, y) = e;\n```\n\nPeople use this trick to block the use of `var`, and we should let them, even though we disagree with the practice. So even though a type isn't valid in that position, we will let the presence of a `var` type turn this into an error.\n# var method\n\nWhat if there's a _method_ called `var`?\n\n``` c#\nref int var(int x, int y);\nvar(x, y) = e; // deconstruction or call?\n```\n\nHere there is no prior art, so we will always interpret the `var` to mean a deconstructing declaration. If you wanted the method call, parenthesize the call or use @.\n"
  },
  {
    "path": "meetings/2016/LDM-2016-07-13.md",
    "content": "# C# Language Design Notes for Jul 13, 2016\n## Agenda\n\nWe resolved a number of questions related to tuples and deconstruction, and one around equality of floating point values in pattern matching.\n# Handling conflicting element names across type declarations\n\nFor tuple element names occurring in partial type declarations, we will require the names to be the same.\n\n``` c#\npartial class C : IEnumerable<(string name, int age)> { ... }\npartial class C : IEnumerable<(string fullname, int)> { ... } // error: names must be specified and the same\n```\n\nFor tuple element names in overridden signatures, and when identity convertible interfaces conflict, there are two camps:\n1. Strict: the clashes are _disallowed_, on the grounds that they probably represent programmer mistakes\n   - when overriding or implementing a method, tuple element names in parameter and return types must be preserved\n   - it is an error for the same generic interface to be inherited/implemented twice with identity convertible type arguments that have conflicting tuple element names\n2. Loose: the clashes are _resolved_, on the grounds that we shouldn't (and don't otherwise) dictate such things (e.g. with parameter names)\n   - when overriding or implementing a method, different tuple element names can be used, and on usage the ones from the most derived statically known type win, similar to parameter names\n   - when interfaces with different tuple element names coincide, the conflicting names are elided, similar to best common type.\n\n``` c#\ninterface I1 : IEnumerable<(int a, int b)> {}\ninterface I2 : IEnumerable<(int c, int d)> {}\ninterface I3 : I1, I2 {} // what comes out when you enumerate?\nclass C : I1 { public IEnumerator<(int e, int f)> GetEnumerator() {} } // what comes out when you enumerate?\n```\n\nWe'll go with the strict approach, barring any challenges we find with it. We think helping folks stay on the straight and narrow here is the most helpful. If we discover that this is prohibitive for important scenarios we haven't though of, it will be possible to loosen the rules in later releases.\n# Deconstruction of tuple literals\n\nShould it be possible to deconstruct tuple literals directly, even if they don't have a \"natural\" type?\n\n``` c#\n(string x, byte y, var z) = (null, 1, 2);\n(string x, byte y) t = (null, 1);\n```\n\nIntuitively the former should work just like the latter, with the added ability to handle point-wise `var` inference.\n\nIt should also work for deconstructing assignments:\n\n``` c#\nstring x;\nbyte y;\n\n(x, y) = (null, 1);\n(x, y) = (y, x); // swap!\n```\n\nIt should all work. Even though there never observably is a physical tuple in existence (it can be thought of as a series of point-wise assignments), semantics should correspond to introducing a fake tuple type, then imposing it on the RHS.\n\nThis means that the evaluation order is \"breadth first\":\n1. Evaluate the LHS. That means evaluate each of the expressions inside of it one by one, left to right, to yield side effects and establish a storage location for each.\n2. Evaluate the RHS. That means evaluate each of the expressions inside of it one by one, left to right to yield side effects\n3. Convert each of the RHS expressions to the LHS types expected, one by one, left to right\n4. Assign each of the conversion results from 3 to the storage locations found in 1.\n\nThis approach ensures that you can use the feature for swapping variables `(x, y) = (y, x);`!\n# var in tuple types?\n\n``` c#\n(var x, var y) = GetTuple(); // works\n(var x, var y) t = GetTuple(): // should it work?\n```\n\nNo. We will keep `var` as a thing to introduce local variables only, not members, elements or otherwise. For now at least. \n# Void as result of deconstructing assignment?\n\nWe decided that deconstructing assignment should still be an expression. As a stop gap we said that its type could be void. This still grammatically allows code like this:\n\n``` c#\nfor (... ;; (current, next) = (next, next.Next)) { ... }\n```\n\nWe'd like the result of such a deconstructing assignment to be a tuple, not void. This feels like a compatible change we can make later, and we are open to it not making it into C# 7.0, but longer term we think that the result of a deconstructing assignment should be a tuple. Of course a compiler should feel free to not actually construct that tuple in the overwhelming majority of cases where the result of the assignment expression is not used.\n\nThe normal semantics of assignment is that the result is the value of the LHS after assignment. With this in mind we will interpret the deconstruction in the LHS as a tuple: it will have the values and types of each of the variables in the LHS. It will not have element names. (If that is important, we could add a syntax for that later, but we don't think it is).\n# Deconstruction as conversion and vice versa\n\nDeconstruction and conversion are similar in some ways - deconstruction feels a bit like a conversion to a tuple. Should those be unified somehow?\n\nWe think no. the existence of a `Deconstruct` method should not imply conversion: implicit conversion should always be explicitly specified, because it comes with so many implications.\n\nWe could consider letting user defined implicit conversion imply `Deconstruct`. It leads to some convenience, but makes for a less clean correspondence with consumption code.\n\nLet's keep it separate. If you want a type to be both deconstructable and convertible to tuple, you need to specify both.\n# Anonymous types\n\nShould they implement `Deconstruct` and `ITuple`, and be convertible to tuples?\n\nNo. There are no really valuable scenarios for moving them forward. Wherever that may seem desirable, it seems tuples themselves would be a better solution.\n# Wildcards in deconstruction\n\nWe should allow deconstruction to feature wildcards, so you don't need to specify dummy variables.\n\nThe syntax for a wildcard is `*`. This is an independent feature, and we realize it may be bumped to post 7.0.\n# compound assignment with distributive semantics\n\n``` c#\npair += (1, 2);\n```\n\nNo.\n# Switch on double\n\nWhat equality should we use when switching on floats and doubles?\n- We could use `==` - then `case NaN` wouldn't match anything.\n- We could use `.Equals`, which is similar except treating `NaN`s as equal.\n\nThe former struggles with \"at what static type\"? The latter is defined independently of that. The former would equate 1 and 1.0, as well as byte 1 and int 1 (if applied to non-floating types as well). The latter won't.\n\nWith the latter we'd feel free to optimize the boxing and call of Equals away with knowledge of the semantics.\n\nLet's do `.Equals`.\n"
  },
  {
    "path": "meetings/2016/LDM-2016-07-15.md",
    "content": "# C# Design Language Notes for Jul 15, 2016\n## Agenda\n\nIn this meeting we took a look at what the scope rules should be for variables introduced by patterns and out vars.\n# Scope of locals introduced in expressions\n\nSo far in C#, local variables have only been:\n1. Introduced by specific kinds of statements, and\n2. Scoped by specific kinds of statements\n\n`for`, `foreach` and `using` statements are all able to introduce locals, but at the same time also constitute their scope. Declaration statements can introduce local variables into their immediate surroundings, but those surroundings are prevented by grammar from being anything other than a block `{...}`. So for most statement forms, questions of scope are irrelevant.\n\nWell, not anymore! Expressions can now contain patterns and out arguments that introduce fresh variables. For any statement form that can contain expressions, we therefore need to decide how it relates to the scope of such variables.\n## Current design\n\nOur default approach has been fairly restrictive:\n- All such variables are scoped to the nearest enclosing statement (even if that is a declaration statement)\n- Variables introduced in the condition of an `if` statement aren't in scope in the `else` clause (to allow reuse of variable names in nested `else if`s)\n\nThis approach caters to the \"positive\" scenarios of `is` expressions with patterns and invocations of `Try...` style methods with out parameters:\n\n``` c#\nif (o is bool b) ...b...; // b is in scope\nelse if (o is byte b) ...b...; // fine because bool b is out of scope\n...; // no b's in scope here\n```\n\nIt doesn't handle unconditional uses of out vars, though:\n\n``` c#\nGetCoordinates(out var x, out var y);\n...; // x and y not in scope :-(\n```\n\nIt also fits poorly with the \"negative\" scenarios embodied by what is sometimes called the \"bouncer pattern\", where a method body starts out with a bunch of tests (of parameters etc.) and jumps out if the tests fail. At the end of the test you can write code at the highest level of indentation that can assume that all the tests succeeded:\n\n```\nvoid M(object o)\n{\n  if (o == null) throw new ArgumentNullException(nameof(o));\n  ...; // o is known not to be null\n}\n```\n\nHowever, the strict scope rules above make it intractable to extend the bouncer pattern to use patterns and out vars:\n\n``` c#\nvoid M(object o)\n{\n  if (!(o is int i)) throw new ArgumentException(\"Not an int\", nameof(o));\n  ...; // we know o is int, but i is out of scope :-(\n}\n```\n## Guard statements\n\nIn Swift, this scenario was found so important that it earned its own language feature, `guard`, that acts like an inverted `if`, except that a) variables introduced in the conditions are in scope after the `guard` statement, and b) there must be an `else` branch that leaves the enclosing scope. In C# it might look something like this:\n\n``` c#\nvoid M(object o)\n{\n  guard (o is int i) else throw new ArgumentException(\"Not an int\", nameof(o)); // else must leave scope\n  ...i...; // i is in scope because the guard statement is specially leaky\n}\n```\n\nA new statement form seems like a heavy price to pay. And a guard statement wouldn't deal with non-error bouncers that correct the problem instead of bailing out:\n\n``` c#\nvoid M(object o)\n{\n  if (!(o is int i)) i = 0;\n  ...; // would be nice if i was in scope and definitely assigned here\n}\n```\n\n(In the bouncer analogy I guess this is equivalent to the bouncer lending the non-conforming customer a tie instead of throwing them out for not wearing one).\n## Looser scope rules\n\nIt would seem better to address the scenarios and avoid a new statement form by adopting more relaxed scoping rules for these variables.\n\n_How_ relaxed, though?\n\n**Option 1: Expression variables are only scoped by blocks**\n\nThis is as lenient as it gets. It would create some odd situations, though:\n\n``` c#\nfor (int i = foo(out int j);;); \n// j in scope but not i?\n```\n\nIt seems that these new variables should at least be scoped by the same statements as old ones:\n\n**Option 2: Expression variables are scoped by blocks, for, foreach and using statements, just like other locals:**\n\nThis seems more sane. However, it still leads to possibly confusing and rarely useful situations where a variable \"bleeds\" out many levels:\n\n``` c#\nif (...)\n  if (...)\n    if (o is int i) ...i...\n...; // i is in scope but almost certainly not definitely assigned \n```\n\nIt is unlikely that the inner `if` intended `i` to bleed out so aggressively, since it would almost certainly not be useful at the outer level, and would just pollute the scope.\n\nOne could say that this can easily be avoided by the guidance of using curly brace blocks in all branches and bodies, but it is unfortunate if that changes from being a style guideline to having semantic meaning.\n\n**Option 3: Expression variables are scoped by blocks, for, foreach and using statements, as well as all embedded statements:**\n\nWhat is meant by an embedded statement here, is one that is used as a nested statement in another statement - except inside a block. Thus the branches of an `if` statement, the bodies of `while`, `foreach`, etc. would all be considered embedded.\n\nThe consequence is that variables would always escape the condition of an `if`, but never its branches. It's as if you put curlies in all the places you were \"supposed to\".\n## Conclusion\n\nWhile a little subtle, we will adopt option 3. It strikes a good balance:\n- It enables key scenarios, including out vars for non-`Try` methods, as well as patterns and out vars in bouncer if-statements.\n- It doesn't lead to egregious and counter-intuitive multi-level \"spilling\".\n\nIt does mean that you will get more variables in scope than the current restrictive regime. This does not seem dangerous, because definite assignment analysis will prevent uninitialized use. However, it prevents the variable names from being reused, and leads to more names showing in completion lists. This seems like a reasonable tradeoff.\n"
  },
  {
    "path": "meetings/2016/LDM-2016-08-24.md",
    "content": "C# Language Design Meeting, Aug 24, 2016\n========================================\n\n## Agenda\n\nAfter a meeting-free period of implementation work on C# 7.0, we had a few issues come up for resolution.\n\n1. What does it take to be task-like?\n2. Scope of expression variables in initializers\n\n# Task-like types\n\nThe generalization of async return types requires the return type of an async method to provide an implementation for the \"builder object\" that the method body's state machine interacts with when it awaits, and when it produces the returned \"task-like\" value.\n\nHow should it provide this implementation? There are a couple of options:\n\n1. A `GetAsyncMethodBuilder` method on the task-like type following a specific compiler-recognized pattern\n2. 1 + a modifier on the type signifying \"buy-in\" to being an async type\n3. An attribute that encodes the builder type\n\nWe like the attribute approach, because this is really a metadata concern. The attribute sidesteps issues with accessibility (is the type only task-like when the `GetAsyncMethodBuilder` method is accessible?), and doesn't pollute the member set of the type. Also it works on interfaces. For instance, it could conceivably apply to WinRT's `IAsyncAction` etc.\n\nWe only expect very few people to ever build their own task-like types. We may or may not choose to ever actually *ship* the attribute we will use. Implementers can just roll their own internal implementation. The compiler only looks for the name - which will be `System.Runtime.CompilerServices.AsyncBuilderAttribute`.\n\nThere are a couple of options for what the attribute should contain:\n\n1. Nothing - it is just a marker, and there is still a static method on the task-like type\n2. The name of a method to call on the task-like type\n3. The builder type itself\n4. A static type for *getting* the builder\n\nOption 1 and 2 we've already ruled out, because we don't want to depend on accessible members on the task-like type itself.\n\nOption 3 would require a `Type` argument to the constructor that is either non-generic (for void-yielding or non-generic result-yielding task-like types) or an open generic type with one type parameter (for generic result-yielding task-like types)\nOption 4 is essentially a \"builder builder\", and would let us have a less dirty relationship between type parameters on the builder and task-like:\n\n``` c#\nstatic class ValueTaskBuilderBuilder\n{\n    ValueTaskBuilder<T> GetBuilder<T>(ValueTask<T> dummy);\n}\n```\n\nThat is probably a bridge too far, so we will go with Option 3.\n\nThe builder type given in the attribute is required to have a static, accessible, non-generic Create method.\n\nThis would work for `IAsyncAction` etc. from WinRT, assuming that a builder is implemented for them, and an attribute placed on them.\n\nThe proposal to allow the builder to be referenced from the async method is attractive, but something for another day.\n\n# Scope of expression variables in initializers\n\n``` c#\nint x = M(out int t), y = t;\n```\n\nIf this is a local declaration, `t` is in scope after the declaration. If this is a _field_ declaration, though, should it be? It's problematic if it is, and inconsistent if it isn't! Also, if we decide one way or another, we can never compatibly change our mind on it.\n\nLet's block this off and not allow expression variables to be introduced in field initializers! It's useless today, and we should save the scoping decisions for when future features give us a use case.\n\n``` c#\npublic C() : base(out int x)\n{\n\t// use x?\n}\n```\n\nA variable declared in a `this` or `base` initializer should be in scope in the whole constructor body.\n"
  },
  {
    "path": "meetings/2016/LDM-2016-09-06.md",
    "content": "# C# Language Design Notes for Sep 6, 2016\n\n## Agenda\n\n1. How do we select `Deconstruct` methods?\n\n# How do we select Deconstruct methods?\n\n`(int x, var y) = p` cannot just turn into `p.Deconstruct(out int x, out var y)`, because we want it to find a `Deconstruct` method with a more specific type than `int`, e.g. `byte`.\n\nWe should look only at the arity of the `Deconstruct` method. If there's more than one with the given arity, we fail. If necessary, we will then translate this into passing temporary variables to the `Deconstruct` method, instead of the ones declared in the deconstruction. E.g., if `p` has \n\n``` C#\nvoid Deconstruct(out byte x, out byte y) ...;\n```\n\nWe would translate it equivalently to:\n\n``` c#\np.Deconstruct(out byte __x, out byte __y);\n(int x, int y) = (__x, __y);\n```"
  },
  {
    "path": "meetings/2016/LDM-2016-10-18.md",
    "content": "C# Language Design Meeting Notes, Oct 18, 2016\n==============================================\n\n\n## Agenda\n\nGo over C# 7.0 features one last (?) time to make sure we feel good about them and address remaining language-level concerns.\n\n1. Wildcard syntax\n2. Design \"room\" between tuples and patterns\n3. Local functions\n4. Digit separators\n5. Throw expressions\n6. Tuple name mismatch warnings\n7. Tuple types in `new` expressions\n\n\n# Pattern matching\n\n## Wildcards\nIf we want to reopen the discussion of using `_`, and it doesn't make C# 7.0, we may find ourselves wanting to block off use of `_` as an ordinary identifier in the new declaration contexts (patterns, deconstruction, out vars). Let's front load the final design of wildcards to decide if anything needs to happen here.\n\n## Design \"room\" between tuples and pattern matching\n\n`case (int, int) x:` is not currently allowed, in order to leave design space. More specifically we want this to mean a recursive pattern, rather than just a tuple type, once we get to recursive patterns. We're good with leaving this an error in the meantime, even though it may occasionally be puzzling to developers.\n\n\n# Local functions\n\nWe want to ideally allow any expression or set of statements to be lifted out in a local method. There are two ways in which this cannot be realized:\n\n1. assignment to readonly fields in constructors - the runtime disallows those assignments if we lift them out to methods.\n2. async methods and iterators - they aren't done executing when they return, so they can't generally contribute to definite assignment of enclosing variables. For async local functions we do recognize assignments that happen before the first await. Is this too subtle? Maybe, but it's fine to keep it.\n\n\n# Digit separators\n\nWe don't allow leading or trailing underbars - they have to be *between* digits: they are digit *separators* after all! We think this is fine, but if we hear feedback to the contrary we can try to relax it later.\n\n\n# Throw expressions\n\nThey are allowed as expression bodies, as the second operand of `??`, and as the second and third operand of `?:`. They are not allowed in `&&` and `||`, and cannot be parenthesized. We think this is a fine place to land.\n\n\n# Tuples\n\n## Name mismatch warnings\n\nWe don't currently warn about names moving to a different position. Should we?\n\n``` c#\n(int first, int last) M() ...\n\n(int last, int first) t = M(); // Oops!\n```\n\nIdeally yes. There are a lot of weird cases that would be hard to track down, though. Let's get the obvious ones. Essentially where we do implicit conversions we would check and warn.\n\n\n## Use of tuples in `new`\n\nYou cannot `new` up a tuple type. However, we should certainly allow arrays of tuples to be created. It is probably also fine to keep allowing `new`ing of nullable tuple types:\n\n``` c#\nvar array = new (int x, int y)[10];   // Absolutely\nvar nullable = new (int x, int y)?(); // Why not?\n```\n"
  },
  {
    "path": "meetings/2016/LDM-2016-10-25-26.md",
    "content": "C# Language Design Notes for Oct 25 and 26, 2016\n================================================\n\nAgenda\n------\n\n- Declaration expressions as a generalizing concept\n- Irrefutable patterns and definite assignment\n- Allowing tuple-returning deconstructors\n- Avoiding accidental reuse of out variables\n- Allowing underbar as wildcard character\n\n\nDeclaration expressions\n=======================\n\nIn C# 6.0 we embraced, but eventually abandoned, a very general notion of \"declaration expressions\" - the idea that a variable could be introduced *as* an expression `int x`.\n\nThe full generality of that proposal had some problems:\n\n* A variable introduced like `int x` is unassigned and therefore unusable in most contexts. It also leads to syntactic ambiguities\n* We therefore allowed an optional initializer `int x = e`, so that it could be used elsewhere. But that lead to weirdness around when `= e` meant assignment (the result of which is a *value*) and when it meant initialization (the result of which is a *variable* that can be assigned to or passed by ref).\n\nHowever, there's value in looking at C#'s new deconstruction and out variable features through the lens of declaration expressions.\n\nCurrently we have\n\n* Deconstructing *assignments* of the form `(x, y) = e`\n* Deconstructing *declarations* of the form `(X x, Y y) = e`\n* Out variables of the form `M(out X x)`\n\nThis calls for generalization. What if we said that\n\n* Tuple expressions `(e1, e2)` can be lvalues if all their elements are lvalues, and will cause deconstruction when assigned to\n* There are declaration expressions `X x` that can only occur in positions where an unassigned variable is allowed, that is\n\t* In or as part of the left hand side of an assignment\n\t* In or as part of an out argument\n\nThen all the above features - and more - can be expressed in terms of combinations of the two:\n\n* Deconstructing assignments are just a tuple on the left hand side of an assignment\n* Deconstructing declarations are just deconstructing assignments where all the nested variables are declaration expressions\n* Out variables are just declaration expressions passed as an out argument\n\nGiven the short time left for fixes to C# 7.0 we could still keep it to these three special cases for now. However, if those restrictions were later to be lifted, it would lead to a number of other things being expressible:\n\n* Using a \"deconstructing declaration\" as an expression (today it is a statement)\n* Mixing existing and new variables in a deconstructing assignment `(x, int y) = e`\n* deconstruction in out context `M(out (x, y))`\n* single declaration expression on the left hand side of assignment `int x = e`\n\nThe work involved in moving to this model *without* adding this functionality would be to modify the representation in the Roslyn API, so that it can be naturally generalized later.\n\nConclusion\n----------\n\nLet's re-cast the currently planned C# 7.0 features in turns of declaration expressions and tuple expressions, and then plan to later add some or all of the additional expressiveness this enables.\n\n\nIrrefutable patterns\n====================\n\nSome patterns are \"irrefutable\", meaning that they are known by the compiler to be always fulfilled. We currently make very limited use of this property in the \"subsumption\" analysis of switch cases. But we could use it elsewhere:\n\n``` c#\nif (GetInt() is int i) { ... }\nUseInt(i); // Currently an error. We could know that i is definitely assigned here\n```\n\nThis might not seem to be of much value - why are you applying a pattern if it never fails? But in a future with recursive patterns, this may become more useful:\n\n``` c#\nif (input is Assignment(Expression left, var right) && left == right) { ... }\n... // condition failed, but left and right are still assigned\n```\n\nConclusion\n----------\n\nThis seems harmless, and will grow more useful over time. It's a small tweak that we should do.\n\n\nTuple-returning deconstructors\n==============================\n\nIt's a bit irksome that deconstructors must be written with out parameters. This is to allow overloading on arity, but in practice most types would only declare one. We could at least optionally allow one of them to be defined with a return tuple instead: \n\n``` c#\n(int x, int y) Deconstruct() => (X, Y);\n```\n\nInstead of:\n``` c#\nvoid Deconstruct(out int x, out int y) => (x, y) = (X, Y);\n```\n\nEvidence is inconclusive as to which is more efficient: it depends on circumstances.\n\nConclusion\n----------\n\nNot worth it.\n\n\nDefinite assignment for out vars\n================================\n\nWith the new scope rules, folks have been running into this:\n\n``` c#\nif (int.TryParse(s1, out var i)) { ... i ... }\nif (int.TryParse(s2, out var j)) { ... i ... } // copy/paste bug - still reading i instead of j\n```\n\nIt works the same as when people had to declare their own variables outside the `if`, but it seems a bit of a shame that we can't do better now. Could we do something with definite assignment of out variables that could prevent this situation?\n\nConclusion\n----------\n\nWhatever we could do here would be too specific for a language solution. It would be a great idea for a Roslyn analyzer, which can \n- identify `TryFoo` methods by looking for \"Try\" in the name and the `bool` return type\n- find this bug in existing code declaring the variable ahead of time, *as well as* in new code using out variables\n\n\nUnderbar wunderbar\n==================\n\nCan we make `_` the wildcard instead of `*`? We'd need to be sneaky in order to preserve current semantics (`_` is a valid identifier) while allowing it as a wildcard in new kinds of code.\n\n``` c#\nM(out var _);\nint _ = e.M(_ => ..._...x...); // outer _ is still a named variable?\n(int x, var _) = e.M(_ => ..._...x...);\n(_, _) = (\"x\", 2);\n```\nWe would need to consider rules along the following lines:\n\n* Make `_` always a wildcard in deconstructions and patterns\n* Make `_` always a wildcard in declaration expressions and patterns\n* Allow `_` as a wildcard in other l-value situations (out arguments at least, but maybe assignment) when it's not already defined\n* Allow `_` to be declared more than once in the same scope, in which case it is a wildcard when mentioned\n* Allow `_` to be \"redeclared\" in an inner scope, and then it's a wildcard in the inner scope\n\n\"Once a wildcard, always a wildcard!\"\n\nConclusion\n----------\n\nThis is worth pursuing. More thinking is needed!\n\n"
  },
  {
    "path": "meetings/2016/LDM-2016-11-01.md",
    "content": "# C# Language Design Notes for Nov 1, 2016\n\n*Raw notes - need cleaning up*\n\n## Agenda\n\n- Abstracting over memory with `Span<T>`\n\n# Abstracting over memory spans\n\n\nIt's common for teams building IO/data pipelines to invent a type similar to Span\\<T>, which is intended to abstract over native and managed memory, so that you write code over them only ones.\n\n* Native memory\n* Managed arrays\n* stackalloc\n* stack-allocated\n\nWe are now in a situation (unlike when C# started out) where every bit of performance counts. You can't afford overhead in terms of:\n\n* indirection\n* bounds checking\n* virtual calls\n* GC\n* copying\n\nSpan needs to be as efficient to access/index as an array. It should essentially be a \"safe pointer\".\n\nlogically:\n\n``` c#\nstruct Span<T>\n{\n\tref T data;\n\tint length;\n}\n```\n\nCan't be declared like this, because the CLR doesn't support ref fields. But there are IntPtr tricks that can be used.\n\nThese need to be treated as \"ref-like\":\n\n* Can't go on the heap\n* Can't be captured by lambdas, iterators or async\n* Can't be a type argument\n* Etc...\n\nAlso need a ReadOnlySpan\\<T> or similar.\n\nSo need a way to specify ref-like types, so that the compiler wants to enforce it.\n\nThe stack-only-ness helps not having to spend anything on lifetime issues. It lets you pass it to something, and when they return you know they didn't keep any references to it.\n\n\n\nShould we make existing types \"span-aware\"? Arrays? Strings?\n\nWe need to figure out what the right trade-off is.  \n\n\nGenerally we would keep Span\\<T> at the 1% of users. It's analogous to array in the sense that it's rarely used directly in higher-level code.\n\nFor the rest there's wrapper types that are not limited to the stack, and can go into Span-land on demand.\n\n\nRef-like types\n==============\n\nLet's call the ref-like types \"ref structs\".\n\n(Unlike refs these can be fields. ref fields require new runtime semantics, whereas we can otherwise make do with runtime *optimizations*, so we'll skip on ref fields for now)\n\nRef-like-ness should be declarative; it shouldn't be something you infer. Because something could change somewhere else that changes whether you are or not.\n\n(The structs capturing ref-like locals when you have local functions would be inferred. But that's locally in code).\n\n\nA problem something like Span may have at the language level is that it doesn't *look* like something that restrictions apply to, unlike `ref int` or `int*`. We could at least have a naming convention.\n\n``` c#\nM(await X, GetSpan());\n```\n\nLifting out GetSpan() to a local wouldn't work. So that speaks to there being a notation on usage.\n\n* Nothing?\n* Naming conventions?\n* syntax? `ref`? `*`?\n\nIs this really only going to be done by 1% of users (which is still many).\n\n\nStackalloc\n----------\n\n``` c#\nSpan<byte> s = stackalloc byte[4];\n```\n\nRef return rules\n----------------\n\nNeed to be adjusted a bit. YOu should only be able to return spans to things that are safe to return.\n\n\nDownlevel use\n-------------\n\nDo we need to poison these type for downlevel import, and how do we do that?\n\noptreq`s? Mangled names? Obsolete it and recognize something about that in the new compiler that will make it not obsolete it.\n\n\n\n\nReadonly ref\n============\n\nIf we want to enable spans representing strings, for instance, we need readonly spans. And their indexer needs to return a readonly ref.\n\nNot so central to this proposal, but generally interesting: Can we make struct methods that don't copy (their `this` would be readonly ref)? In practice you'd probably want to call the whole struct readonly.\n\n\n\n\nSlicing\n=======\n\nEssentially an API feature, but would want nice overloadable syntax.\n\n\nStructs that can't be passed by value\n-------------------------------------\n\nTO avoid copying costs, semantic errors etc. Icing.\n\n\nFOr Memory\\<T>\n-------------\n\nNot ready to discuss yet, but is there a way that you can prevent a Memory\\<T> from getting freed while a Span is \"out\".\n\nMaybe some version of \"fixed\" can help. A challenge to generalize this from Span to any ref-like type.\n\n``` c#\nSpan<byte> b = ...;\nfixed(byte* p = &b.GetRawPointer())\n```\n\nMaybe this can be expressed more easily?\n\n\nLimitations around ref locals today\n-----------------------------------\n\nThere are many limitations to keep the rules simple, including the fact that ref locals are readonly at the ref level.\n\nWhat should the restrictions be around ref-like types? One difference is that e.g. Span has a default value; 0-length span.\n\n\nNext steps\n----------\n\nAt the language level: Add an attribute to express ref-like-ness, and build a compiler to enforce it!\n\n"
  },
  {
    "path": "meetings/2016/LDM-2016-11-15.md",
    "content": "C# Language Design Notes, Nov 15, 2016\n======================================\n\n> *Quote of the day*: \"Bad people don't get good features!\"\n\n\nAgenda\n------\n\n- Tuple name warnings\n- \"Discards\"\n\n\nTuple name warnings\n===================\n\nThere are two kinds of warnings on the table regarding names in tuples:\n\n1. A warning on tuple *literals* only, if the literal uses an element name that isn't in the target type\n2. A warning on all expressions of tuple type if an element name in the expression is used for a *different* element in the target type\n\nThe first warning helps get the names right when writing a tuple literal, and while maintaining it. It is already in the product:\n\n``` c#\n(int x, int y) t = (a: 1, b: 2); // Oops, forgot to update tuple literal? Names a and b would be lost\n```\n\nThe second warning would help guard against bugs due to reordering of tuple elements:\n\n``` c#\n(string firstName, string lastName) GetName();\n\n(string lastName, string firstName) name = GetName(); // Oops, forgot to swap the element names in name?\n```\n\nThis warning is currently *not* in the product. We would like it to be, but don't have the runway to implement it.\n\nIn the future it could be added as an analyzer, or as a compiler warning protected by warning waves (#1580).\n\n\n\"Discards\"\n==========\n\nWe got great feedback on \"wildcards\" at the MVP Summit, including changing its name to the term \"discards\", which is spreading in industry.\n\nWe are also encouraged to use `_` as the discard character instead of `*`. It works better visually, and is what many other languages already use.\n\nThere is a small matter of `_` already being a valid identifier. In order for it to coexist as a discard with existing valid uses we need to use a few tricks. Here are the essential rules:\n\n1. A standalone `_` when no `_` is defined in scope is a discard\n2. A \"designator\" `var _` or `T _` in deconstruction, pattern matching and out vars is a discard\n\nDiscards are like unassigned variables, and do not have a value. They can only occur in contexts where they are assigned to.\n\nExamples:\n\n``` c#\nM(out _, out var _, out int _); // three out variable discards\n(_, var _, int _) = GetCoordinates(); // deconstruction into discards\nif (x is var _ && y is int _) { ... } // discards in patterns\n```\n\nOne use case is to silence warnings when dropping Tasks from async methods:\n\n``` c#\n_ = FooAsync();\n```\n\nWe also want to allow discards as lambda parameters `(_, _) => 0`, but don't expect that to make it in C# 7.0. Today `_` is allowed as an ordinary identifier; the rule would be that it would become a discard if there's more than one.\n\nWe can also consider allowing top-level discards in foreach loops:\n\n``` c#\nforeach (_ in e) { ... } // I don't care about the values\n```\n\nBut that does not seem too important, especially since you can use `var _` to the same effect.\n\nIn general, whenever use of standalone `_` as a discard is precluded, either by syntactic restrictions or by `_` being declared in the scope, `var _` is often a fine substitute with the same meaning. However, if the declared `_` is a parameter or local, there are situations where you are out of luck:\n\n``` c#\npublic override void M(int _) // declaring _ to signal that this override doesn't care about it\n{\n\t_ = TryFoo();     // Error: cannot assign bool result to int variable _\n\tvar _ = TryFoo(); // Error: cannot declare local _ when one is already in scope\n}\n``` \n\nThese situations are always local to a member, so it is relatively easy to rewrite them, e.g. to rename the incoming parameter. We could consider accommodating them in the future: the error for a local redeclaration of `_` when one is already in scope could be changed to allowing it, but consider the second declaration a discard. This may be too subtle, and not useful enough, but it is worth considering post C# 7.0."
  },
  {
    "path": "meetings/2016/LDM-2016-11-16.md",
    "content": "C# Language Design Notes for Nov 16, 2016\n=========================================\n\nIn this meeting we looked at the proposal for nullable reference types in [nullable-reference-types.md](https://github.com/dotnet/csharplang/tree/7981ea1fb4d89571fd41e3b75f7c9f7fc178e837/proposals/nullable-reference-types.md).\n\nThe below has few answers and many questions. It is essentially a laundry list of things to work on as we design the feature.\n\n\nNullable types\n==============\n\n## Calling it \"types\"\nMVP Feedback: There's a bit of a dissonance between calling it \"types\" and not having guarantees. Maybe talk about it more like analyzers.\n\nShould this be part of a general annotations framework? Do we want to keep doing this specifically per feature or have a general framework for it? Maybe. Let's keep that in the back of our minds. We don't want to be blocked by figuring that out right now.\n\n## Overload resolution\nIt's not the intention that knowing something is not-null influences overload resolution.\n\n## Tracking nested reference fields and properties\nWe need to decide whether to track `x.y` when both are reference types, and to what extent we will track aliasing. Guarantees vs usefulness.\n\n## The dammit operator\nShould it generate a runtime check? There are pros and cons. \n\nIt would sort of break with a principle that nullability stuff has no runtime semantics, and also impose runtime cost (though that can be eliminated by a smart compiler, when the next thing that follows - e.g. dereferencing - also already starts with a null check). \n\nOn the other hand it might be good to verify non-nullness right then and there, rather than experience random fallout later. Is it an \"I know what I'm doing\" or a \"check that I know what I'm doing\" operator?\n\n## Nested annotations\n\nIs it really that useful to have nested nullability annotations, as in `string?[]` or `List<string?>`? On arrays you almost always have null elements. We suspect that it *is* useful, and would detract from the combo with generics if not there, but on the other hand it is a great simplification to only track nullability at the top level.\n\nOne problem with nested nullability is that casts will not be able to check the nullability of type arguments. A cast cannot distinguish `(List<string>)o` from `(List<string?>)o`, since the runtime object in `o` won't know if it was instantiated with `string` or `string?`. So the notion that \"all is good after a successful cast\" is lost. \n\nIf we *do* allow nullable type parameters, should you be able to say `!` on type parameters that may be nullable?\n\nFor generics we should find a few samples that we believe are representative, and focus on them. May be able to reuse ones from the Midori project.\n\n## Warning types\nThe distinction between nullable and non-null warnings is not useful, and some of them (conversions) kind of belong to both.\n\n## When are types the same\nIssue: We need to think about when types are considered to be the same for declarative reasons (overrides, etc)\n\nIt's similar to tuples in that we have runtime types ornated with extra compile time information. That's a good analogy for a check list, but we should feel free to reach different conclusions.\n\n## null literals\nRules should apply not just to the null literal but to null constants\n\n## The construction rule\nThere's a rule that checks that all non-nullable reference fields and properties are initialized by a constructor.\n\nIt needs to also look recursively through fields and properties of value types for nested non-null reference types.\n\nWe need to decide *when* to check during a constructor. It could be before calling helpers on the instance (since they may assume non-nullability) or only at the end. Usefulness vs guarantee!\n\n## Arrays\n\nShould we disallow/discourage arrays of non-null, to try to avoid the array hole where you have an array of a non-nullable element type, initialized entirely with nulls? \n\nWhat should people do to go from `T?[]` to `T[]`? Can `!` be applied for the recursive case? Otherwise, casts may be necessary.\n\n## Default\nIs `default(T)` of type `T` or `T?`? If it gives a warning, you could shut it up with `!`.\n\n## Referenced assemblies\nShould it be evident from an assembly whether unannotated means non-null or not? \n\nThe compiler would have to be able to embrace the \"don't care\" old fashioned kind of reference type, even when opted in to non-nullability.\n\nWhat are the semantics around such \"shut-up types\", and sources of them?\n\n## Unconstrained type parameters\nWhen T is constrained by U, we need to ensure that T is assignable to T, and T to U. It's more complicated than just saying warn from both sides.\n\n## Are the warnings part of the language\nAre this set of warnings part of the language, or are they a \"compiler feature\" - essentially some built-in analyzers. In the latter case we might allow them to evolve in a breaking way.\n\n## Is nullability always explicit?\nIt is probably fine that you can get nullable reference types implicitly (e.g. inference from `string`, `null`).\n\n## Locals\nNot annotating locals would reduce the number of places that would need to be fixed when turning nullability on. They would then have their nullability inferred instead. It's a trade-off between expressiveness and upgrade burden. This goes to granularity of opt-in as well. It would cause a readability disconnect between locals and fields.\n\nShould `var?` be allowed? should `var` always be nullable? Should it infer its nullability? How to best express intent here?\n\n## Parameters\nThere's a proposal to allow `!` on parameter types `M(T! x)` to cause a runtime null check to be generated. That would be better written as `M(T x!)`, putting the `! on the parameter, since it's about the parameter itself, and would actually name the parameter in the exception thrown!\n\n## Expressing TryGet\nCould get away with non-language flourishes, such as attributes. \"DefinitelyAssignedWhenTrue\".\n\n## Applying flow analysis to value types\nThe proposal of also doing the flow analysis for nullable value types is more concerning, because it's adding new runtime semantics.\n\nAlso, it may work for dereferencing those values, but not so well if it is an argument: Does it influence overload resolution? What if there are many arguments?\n\nFlow for nullable value types is a nice-to-have add-on, not essential to the proposal.\n\n\n\n\n"
  },
  {
    "path": "meetings/2016/LDM-2016-11-30.md",
    "content": "C# Language Design Notes for Nov 30, 2016\n=========================================\n\n\nAgenda\n------\n\n- Scope of while condition expression variables\n- Mixed deconstruction\n- Unused expression variables\n- Declarations in embedded statements\n- Not-null pattern\n\n\nScope of while condition expression variables\n=============================================\n\nWe are compelled by the argument in #15529 about the scope of expression variables occurring in `while` conditions. \n\n``` c#\nwhile (src.TryGetNext(out int x))\n{\n\t// Same or different `x` each time around?\n}\n// x in scope here?\n```\n\nMore broadly we seem to have the following options for scopes and lifetimes of such declarations:\n\n1. There is a single variable `x` for the whole `while` statement, which is initialized repeatedly, each time around. It is in scope outside the `while` statement.\n2. There is a single variable `x` for the whole `while` statement, which is initialized repeatedly, each time around. It is only in scope inside the `while` statement.\n3. There is a fresh variable `x` for each iteration of the `while` statement, initialized in the condition. It is only in scope inside the `while` statement.\n\nThere is a clear argument for the lifetime of the variable being a single iteration. We know from `foreach` that this leads to better capture in lambdas, but perhaps more importantly it avoids the odd behavior of the same variable getting initialized multiple times. (Pretty much the only way to otherwise achieve that in C# is through insidious use of `goto`).\n\nThis puts us squarely in option 3 above, where it is meaningless to put \"the\" variable in scope outside of a while loop. Indeed, from the outside there is no notion of \"the\" variable: there will be multiple `x`es over the execution of the loop.\n\nConsequences in for loops\n-------------------------\n\nIn light of a changed `while` loop we also need to examine what that means to the `for` loop, which, while not defined as such in the spec, can be informally understood as \"desugaring\" into a `while` loop.\n\n``` c#\n\nfor (<decl>; <cond>; <incr>) <body>\n\n==>\n\n{\n    <decl>\n    while(<cond>)\n    {\n        <body>\n\tcont:\n        { <incr> }\n    }\n}\n```\n\nSo with respect to scopes and lifetimes, `<cond>` should behave the same as the condition in a while loop. \n\nSimilarly, `<incr>` should be a fresh variable each time around. Furthermore it should occur in its own little nested scope, since variables introduced in it won't be definitely assigned until the end of each iteration.\n\n\nConclusion\n----------\n\nWe want to change to the narrow scopes and short lifetime for expression variables introduced in the condition of while and for loops, and in the increment of for loops.\n\nThis means that the `if` statement becomes more of a special case, with expression variables in its condition having broad scope. That is probably a good place to land. The main scenarios for this behavior are driven by the if statement to begin with, and it is also the one kind of statement where the lifetime and definite assignment situation for such variables makes it reasonable for them to persist outside of the statement.\n\n\nMixed deconstruction\n====================\n\nThe reinterpretation of deconstruction in terms of declaration expressions would let us generalize so that: \n\n- Would allow mixing existing and newly declared variables in a deconstruction\n- Would allow newly declared variables in deconstruction nested in expressions\n- No error when occuring as an embedded statement\n\nConclusion\n----------\n\nFrom a language design point of view we are confident in this generalization of the deconstruction feature. It is doubtful whether the change can make it into C# 7.0 at this point. Even though it is a small code change in and of itself, it introduces testing work and general churn.\n\n\nWarn about unused expression variables?\n=======================================\n\nShould we warn when an expression variable goes unused? Typically such variables would be dummy variables, and with discards `_` you no longer need them.\n\nOn the other hand, we could leave it to the IDE to suggest discards etc, rather than give a warning from the language.\n\nConclusion\n----------\n\nLet's not add the warning. Keep the warning in place where it already is in existing C#.\n\n\nDeclarations in embedded statements\n===================================\n\nC# currently has a grammatically enforced restriction against declaring \"useless\" variables as \"embedded statements\":\n\n``` c#\nif (x > 3) var y = x; // Error: declaration statement not allowed as an embedded statement\n```\n\nOf course expression variables now give you new ways of similarly declaring variables that are immediately out of scope and hence \"useless\". Should we give errors for those new situations also?\n\nConclusion\n----------\n\nLet's not add errors for deconstruction situations. In principle we probably want to remove even the existing limitation, but it's work we won't push for in C# 7.0.\n\n\nPattern to test not-null?\n=========================\n\nIt's been suggested to have a pattern for testing non-nullness (just as there is a `null` pattern for checking nullness).\n\nConclusion\n----------\n\nNo time in C# 7.0 but a good idea.\n"
  },
  {
    "path": "meetings/2016/LDM-2016-12-07-14.md",
    "content": "C# Language Design Notes for Dec 7 and Dec 14, 2016\n=================================================\n\nAgenda\n------\n\n- Expression variables in query expressions\n- Irrefutable patterns and reachability\n- Do-while loop scope\n\n \nExpression variables in query expressions\n=========================================\n\nIt seems desirable to allow expression variables in query clauses to be available in subsequent clauses:\n\n``` c#\nfrom s in strings\nwhere int.TryParse(s, out int i)\nselect i;\n```\n\nThe idea is that the `i` introduced in the `where` clause becomes a sort of extra range variable for the query, and can be used in the `select` clause. It would even be definitely assigned there, because the compiler is smart enough to figure out that variables that are \"definitely assigned when true\" in a where clause expression would always be definitely assigned in subsequent clauses.\n\nThis is intriguing, but when you dig in it does raise a number of questions.\n\nTranslation\n-----------\n\nHow would a query like that be translated into calls of existing query methods? In the example above we would need to split the `where` clause into a call to `Select` to compute both the boolean result and the expression variable `i`, then a call to `Where` to filter out those where the boolean result was false. For instance:\n\n``` c#\nstrings\n\t.Select(s => new { s, __w = int.TryParse(s, out int i) ? new { __c = true, i } : new { __c = false, i = default } })\n\t.Where(__p => __p.__w.__c);\n\t.Select(__p => __p.__c.i);\n```\n\nThat first `Select` call is pretty unappetizing. We can do better, though, by using a trick: since we know that the failure case is about to be weeded out by the `Where` clause, why bother constructing an object for it? We can just null out the whole anonymous object to signify failure:\n\n``` c#\nstrings\n\t.Select(s => int.TryParse(s, out int i) ? new { s, i } : null)\n\t.Where(__p => __p != null)\n\t.Select(__p => __p.i);\n```\n\nMuch better!\n\nOther query clauses\n-------------------\n\nWe haven't really talked through how this would work for other kinds of query clauses. We'd have to go through them one by one and establish what the meaning is of expression variables in each expression in each kind of query clause. Can they all be propagated, and is it meaningful and reasonable to achieve?\n\nMutability\n----------\n\nOne thing to note is that range variables are immutable, while expression variables are mutable. We don't have the option of making expression variables mutable across a whole query, so we would need to make them immutable either:\n- everywhere, or\n- outside of the query clause that introduces them.\n\nHaving them be mutable inside their own query clause would allow for certain coding patterns such as: \n\n```\nfrom o in objects\nwhere o is int i || (o is string s && int.TryParse(s, out i))\nselect i;\n```\n\nHere `i` is introduced and then mutated in the same query clause.\n\nThe above translation approaches would accommodate this \"mutable then immutable\" semantics if we choose to adopt it\n\nPerformance\n-----------\n\nWith a naive query translation scheme, this could lead to a lot of hidden allocations even when an expression variable is *not* used in a subsequent clause. Today's query translation already has the problem of indiscriminately carrying forward all range variables, regardless of whether they are ever needed again. This feature would exacerbate that issue.\n\nWe could think in terms of language-mandated query optimizations, where the compiler is allowed to shed range variables once they are never referenced again, or at least if they are never referenced outside of their introducing clause.\n\n\nBlocking off\n------------\n\nWe won't have time to do this feature in C# 7.0. If we want to leave ourselves room to do it in the future, we need to make sure that we don't allow expression variables in query clauses to mean something *else* today, that would contradict such a future.\n\nThe current semantics is that expression variables in query clauses are scoped to only the query clause. That means two subsequent query clauses can use the same name in expression variables, for instance. That is inconsistent with a future that allows those variables to share a scope across query clause boundaries.\n\nThus, if we want to allow this in the future we have to put in some restrictions in C# 7.0 to protect the design space. We have a couple of options:\n\n- Disallow expression variables altogether in query clauses\n- Require that all expression variables in a given query expression have different names\n\nThe former is a big hammer, but the latter requires a lot of work to get right - and seems at risk for not blocking off everything well enough.\n\nDeconstruction\n--------------\n\nA related feature request is to allow deconstruction in the query clauses that introduce new range variables:\n\n``` c#\nfrom (x, y) in points\nlet (dx, dy) = (x - x0, y - y0)\nselect Sqrt(dx * dx + dy * dy)\n```\n\nThis, again, would simply introduce extra range variables into the query, and would sort of be equivalent to the tedious manual unpacking:\n\n``` c#\nfrom __p1 in points\nlet x = __p1.Item1\nlet y = __p1.Item2\nlet __p2 = (x - x0, y - y0)\nlet dx = __p2.Item1\nlet dy = __p2.Item2\nselect Sqrt(dx * dx, dy * dy)\n```\n\nExcept that we could do a much better job of translating the query into fewer calls:\n\n``` c#\npoints\n\t.Select(__p1 => new { x = __p1.Item1, y = __p1.Item2 })\n\t.Select(__p2 => new { dx = __p2.x - x0, dy = __p2.y - y0, * = __p2 }\n\t.Select(__p3 => Sqrt(__p3.dx * __p3.dx, __p3.dy * __p3.dy)\n```\n\nConclusion\n----------\n\nWe will neither do expression variables nor deconstruction in C# 7.0, but would like to do them in the future. In order to protect our ability to do this, we will completely disallow expression variables inside query clauses, even though this is quite a big hammer.\n\n\nIrrefutable patterns and reachability\n=====================================\n\nWe could be smarter about reachability around irrefutable patterns:\n\n``` c#\nint i = 3\nif (i is int j) {}\nelse { /* reachable? */ }\n```\n\nWe could consider being smart, and realizing that the condition is always true, so the else clause is not reachable.\n\nBy comparison, though, in current C# we don't try to reason about non-constant conditions:\n\n``` c#\nif (false && ...) {}\nelse { /* reachable today */ }\n```\nConclusion\n----------\n\nThis is not worth making special affordances for. Let's stick with current semantics, and not introduce a new concept for \"not constant, but we know it's true\".\n\n\nDo-while loop scope\n===================\n\nIn the previous meeting we decided that while loops should have narrow scope for expression variables introduced in their condition. We did not explicitly say that the same is the case for do-while, but it is."
  },
  {
    "path": "meetings/2016/README.md",
    "content": "# C# Language Design Notes for 2016\n\nOverview of meetings and agendas for 2016\n\n## Feb 29, 2016\n\n[C# Language Design Notes for Feb 29, 2016](LDM-2016-02-29.md)\n\n*Catch up edition (deconstruction and immutable object creation)*\n\nOver the past couple of months various design activities took place that weren't documented in design notes. This a summary of the state of design regarding positional deconstruction, with-expressions and object initializers for immutable types.\n\n## Apr 6, 2016\n\n[C# Language Design Notes for Apr 6, 2016](LDM-2016-04-06.md)\n\nWe settled several open design questions concerning tuples and pattern matching.\n\n\n## Apr 12-22, 2016\n\n[C# Language Design Notes for Apr 12-22, 2016](LDM-2016-04-12-22.md)\n\nThese notes summarize discussions across a series of design meetings in April on several topics related to tuples and patterns:\n- Tuple syntax for non-tuple types\n- Tuple deconstruction\n- Tuple conversions\n- Deconstruction and patterns\n- Out vars and their scope\n\n## May 3-4, 2016\n\n[C# Language Design Notes for May 3-4, 2016](LDM-2016-05-03-04.md)\n\nThis pair of meetings further explored the space around tuple syntax, pattern matching and deconstruction. \n1. Deconstructors - how to specify them\n2. Switch conversions - how to deal with them\n3. Tuple conversions - how to do them\n4. Tuple-like types - how to construct them\n\n## May 10, 2016\n\n[C# Language Design Notes for May 10, 2016](LDM-2016-05-10.md)\n\nIn this meeting we took a look at the possibility of adding new kinds of extension members, beyond extension methods.\n\n\n## Jul 12, 2016\n\n[C# Language Design Notes for Jul 12, 2016](LDM-2016-07-12.md)\n\nSeveral design details pertaining to tuples and deconstruction resolved.\n\n## Jul 13, 2016\n\n[C# Language Design Notes for Jul 13, 2016](LDM-2016-07-13.md)\n\nWe resolved a number of questions related to tuples and deconstruction, and one around equality of floating point values in pattern matching.\n\n\n## Jul 15, 2016\n\n[C# Design Language Notes for Jul 15, 2016](LDM-2016-07-15.md)\n\nIn this meeting we took a look at what the scope rules should be for variables introduced by patterns and out vars.\n\n\n## Aug 24, 2016\n\n[C# Design Language Notes for Aug 24, 2016](LDM-2016-08-24.md)\n\nAfter a meeting-free period of implementation work on C# 7.0, we had a few issues come up for resolution.\n\n1. What does it take to be task-like?\n2. Scope of expression variables in initializers\n\n## Sep 6, 2016\n\n[C# Language Design Notes for Sep 6, 2016](LDM-2016-09-06.md)\n\n1. How do we select `Deconstruct` methods?\n\n## Oct 18, 2016\n\n[C# Language Design Meeting Notes, Oct 18, 2016](LDM-2016-10-18.md)\n\n1. Wildcard syntax\n2. Design \"room\" between tuples and patterns\n3. Local functions\n4. Digit separators\n5. Throw expressions\n6. Tuple name mismatch warnings\n7. Tuple types in `new` expressions\n\n\n## Oct 25-26, 2016\n\n[C# Language Design Meeting Notes, Oct 25-26, 2016](LDM-2016-10-25-26.md)\n\n1. Declaration expressions as a generalizing concept\n2. Irrefutable patterns and definite assignment\n3. Allowing tuple-returning deconstructors\n4. Avoiding accidental reuse of out variables\n5. Allowing underbar as wildcard character\n\n## Nov 1, 2016\n\n[C# Language Design Meeting Notes, Nov 1, 2016](LDM-2016-11-01.md)\n\n1. Abstracting over memory with `Span<T>`\n\n## Nov 15, 2016\n\n[C# Language Design Meeting Notes, Nov 15, 2016](LDM-2016-11-15.md)\n\n1. Tuple name warnings\n2. \"Discards\"\n\n## Nov 16, 2016\n\n[C# Language Design Meeting Notes, Nov 16, 2016](LDM-2016-11-16.md)\n\n\n1. Nullable reference types\n\n## Nov 30, 2016\n\n[C# Language Design Meeting Notes, Nov 30, 2016](LDM-2016-11-30.md)\n\n\n1. Scope of while condition expression variables\n2. Mixed deconstruction\n3. Unused expression variables\n4. Declarations in embedded statements\n5. Not-null pattern\n\n## Dec 7 and 14, 2016\n\n[C# Language Design Meeting Notes, Dec 7 and 14, 2016](LDM-2016-12-07-14.md)\n\n1. Expression variables in query expressions\n2. Irrefutable patterns and reachability\n3. Do-while loop scope\n"
  },
  {
    "path": "meetings/2017/CLR-2017-03-23.md",
    "content": "2017-03-23 CLR Behavior for Default Interface Methods\n==========================================\n\nMet today with\n- [Neal Gafter](https://github.com/gafter)\n- [David Wrighton](https://github.com/davidwrighton)\n- [Aleksey Tsingauz](https://github.com/AlekseyTs)\n- [Yi Zhang (CLR)](https://github.com/yizhang82)\n\nTo discuss the CLR handling of default interface methods.\n\n### (1) Runtime handling of ambiguities\n\nQuestion (1) is about what the CLR should do when the runtime does not find a most specific override for an interface method. For example, if this program is compiled (each interface being in a separate assembly)\n\n``` c#\npublic interface IA\n{\n    void M();\n}\npublic interface IB : IA\n{\n    override void IA.M() { WriteLine(\"IB\"); }\n}\npublic interface IC : IA\n{\n}\nclass C : IB, IC\n{\n    static void Main()\n    {\n        IA a = new C();\n        a.M();\n    }\n}\n```\n\nand then subsequently `IC` is changed\n\n``` c#\npublic interface IC : IA\n{\n    override void IA.M() { WriteLine(\"IB\"); }\n}\n```\n\nThis would cause an error at compile-time if class `C` were recompiled (because there is no most specific override for `IA.M`). However, what happens if this program is run without recompiling `C`?\n\nThere are two most choices:\n1. The runtime selects, deterministically, between the implementations of `IA.M` in `IB` and `IC`; or\n2. The runtime fails at some time before this invocation is run.\n  a. At load time; or\n  b. At the time of the invocation\n\nWe did not have consensus which approach is preferred; there are advantages and disadvantages to either. We will defer this issue until it can be discussed in a larger group.\n\n### Static methods\n\nStatic methods are already permitted in interfaces.\n\n### Protection levels\n\nFrom the point of view of the CLR, once we start accepting a protection level other than private, we might as well accept all of them. The semantics are clear.\n\nWith the possible exception of `protected` and its related protection levels. We would need to clearly define both the language and runtime constraints implied by this protection level. For example, is a `protected` member in an interface accessible in a class that implements the interface? What would be the syntax in source (note that interface members are not inherited into classes that implement them)? What would be the verifiable form of the generated IL?\n\nWe tentatively agreed that the CLR will accept protection levels other than `public` in interfaces, but open questions remain about `protected`.\n\n### Sealed override\n\nIt is an open question whether a `sealed override` should be permitted within an interface. Given the most specific override rule, such code could prevent unrelated sister interfaces from implementing the method.\n\nIf it were permitted, we need to check that there is a way to represent it in IL.\n\n### Non-virtual methods in interfaces\n\nNon-virtual methods in interfaces are not a problem for the CLR, presuming we have a way to represent them. We need to check that existing interface methods have a `newslot` bit set. We think so. If so, then we would simply omit that from non-virtual methods.\n\n### Implicit overrides in interfaces\n\nWe agree that the compiler-generated IL for an \"implicit\" override\n\n``` c#\npublic interface IA\n{\n    void M();\n}\npublic interface IB : IA\n{\n    override void M() { WriteLine(\"IB\"); }\n}\n```\n\nshould be roughly the same as for an \"explicit\" override\n\n``` c#\npublic interface IB : IA\n{\n    override void IA.M() { WriteLine(\"IB\"); }\n}\n```\n\nIn both cases the compiler produces a `methodimpl` record for the overridden method(s). The CLR will not consider a method in an interface to be an implementation of another method without the `methodimpl` bit. We should confirm that we are OK with the binary compatibility implications of this.\n\nAll override declarations should omit the `newslot` bit to ensure no new vtable slot is allocated.\n\n### Open Question: Which interfaces are searched\n\nThere is an open question which interfaces are searched for implementations, and in which order. For example, if we have\n\n``` c#\ninterface IA { void M() {} }\ninterface IB: IA { override void M() {} }\n\nclass Base : IB { }\nclass Derived : Base, IA { }\n```\n\nThen is the override appearing in `IB` the final override selected for class `Derived`, even though `IB` does not appear in the interface list for `Derived`?\n\n### Open Question: Diamond Inheritance between Class and Interface\n\nWhat should occur in cases involving diamond inheritance with classes and interfaces:\n\n``` c#\ninterface IA { void M() {} }\ninterface IB: IA { override void M() {} }\n\nclass Base : IA { void IA.M() { } }\nclass Derived : Base, IB { }\n```\n\nIn this case neither `Base` nor `IB` is a subtype of the other. Is class `Derived` legal? If so, what is its implementation of `IA.M`?"
  },
  {
    "path": "meetings/2017/LDM-2017-01-10.md",
    "content": "# C# Language Design Notes for Jan 10, 2017\n\n## Agenda\n\n- Discriminated unions via \"closed\" types\n\n# Discriminated unions via \"closed\" types\n\nThere's a [proposal](https://github.com/dotnet/roslyn/issues/8729) to allow adding `closed` to an abstract type. This prevents inheriting from any other assembly, meaning that there would be a known set of derived types, all in the same assembly as the closed abstract type. This is somewhat similar to Scala's case classes.\n\nAt the metadata level, this could possibly be implemented by generating an internal abstract member. In fact that member could make itself useful as a property returning a tag, so we can do efficient tag-based switching.\n\nA nice aspect is that `closed` can be added to existing hierarchies, adding a notion of completeness and protecting from \"unauthorized\" inheritance.\n\nAdding this to existing code may lead to completeness warnings in consuming code.\n\nIn a lot of places where you switch, you don't even *want* completeness. It's almost like it's something you have to ask for at the switch site. Special syntax?\n\n\"Catch all\" is a problem. Often I want to have a catch all *even* as I want to be told if there's a new case. We *could* say that if there's a closed type, then you need to be complete in a switch. Which you can be with a `default`, but then you won't know if there's a new case: it's up to you.\n\nEnums: We could allow `closed` on those, and then eliminate the explicit conversion to it, as well as arithmetic. Switching could generate a default that throws, in case someone monkeyed an illegal value in there.\n\nA closed enum wouldn't get much value out of being an enum, since we don't want operators to work on them. We could consider making them not be enums from the runtime perspective.\n\n## Conclusion\n\nAn interesting approach to discriminated unions that might be a better fit with the spirit of C#.\n"
  },
  {
    "path": "meetings/2017/LDM-2017-01-11.md",
    "content": "# C# Language Design Notes for Jan 11, 2017\n\n*Raw notes - need cleaning up*\n\n## Agenda\n\n- Language aspects of [compiler intrinsics](https://github.com/dotnet/roslyn/issues/11475)\n\nIntrinsics\n\nTwo compiler behaviors:\n1. Recognize declarations as intrinsics, and implement them\n2. Enforce whichever special rules apply on call\n\nCould grow the list over time.\n\nScenario: avoid il rewrite or inefficient impls\n\nLets you do cross-platform libraries.\n\nThis feels cheap, and limits the implact to just the compiler.\n\nCan't be abstracted out into generic methods - at least without combinatorial explosion\n\nSome might be obsoleted over time as language features (\"static delegates\"?) come along.\n\nCould allow optionally specifying the intrinsic name in the attribute, so you could call the method something else if you like\n\nOpen question: local functions.\n\nWouldn't emit to metadata.\n\nHow supported should this be, as a language feature? Should semantic analysis understand this, and give you good live feedback? Doesn't need a lot of tooling support out of the gate; it's a feature for a very small set of \n\n\n\n\n``` c#\nswitch(...)\n{\n\tcase string s when .... x1:\n\tcase int i when .... x2 & capture x1:\n\tcase 1 when ... capture x1;\n\t\tbreak\n\n\tcase string s when .... x3:\n\tcase int i when .... x4:\n\tcase 1 when .... & capture something\n\t\tbreak;\n}\n```\n\nThe code needed to be surprised by the lifetime of expression variables in case headers being the whole switch block is quite convoluted (just like this sentence).\n\n``` c#\ncase 1 => WriteLine(...);\ncase 2\n{\n\n}\n\ncase string s when (...)\n{\n   ...\n}\n```\n\n- Broaden scope and lifetime of expr variables to whole switch block\n- Broaden lifetime of expr variables, but not the scope\n- Limit scope of variables in bodies of cases that are \"new\"\n- \n\n\nWhen there are expression variables in the case header, in the case body forbid:\n- ref locals \n\t- to expr variables\n- local functions\n\t- that capture case-section expr variables\n- labels \n\t- that are jumped to from other case sections\n\nDrop the subbullets for now, and maybe we can relax later\n\n\nOut of all these approaches, we still think expanding the lifetime (but not the scope) has the lowest risk. Fallout work is likely in the debugger, which will have a suboptimal experience in these scenarios. This work is probably puntable.\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-01-17.md",
    "content": "# C# Language Design Notes for Jan 17, 2017\n\n## Agenda\n\nA few C# 7.0 issues to review.\n\n1. Constant pattern semantics: which equality exactly?\n2. Extension methods on tuples: should tuple conversions apply?\n\n# Constant pattern semantics\n\n[Issue #16513](https://github.com/dotnet/roslyn/issues/16513) proposes a change to the semantics of constant patterns in `is` expressions. For the code\n\n``` c#\ne is 42\n```\n\nWe currently generate the call `object.Equals(e, 42)` (or equivalent code), but we should instead generate `object.Equals(42, e)`.\n\nThe implementation of `object.Equals` does a few reference equality and null checks, but otherwise delegates to the instance method `Equals` of its *first* argument. So with the current semantics the above would call `e.Equals(42)`, whereas in the proposal we would call `42.Equals(e)`.\n\nThe issue lists several good reasons, and we can add more to the list:\n\n- The constant pattern isn't very *constant*, when it's behavior is determined by the non-constant operand!\n- Optimization opportunities are few when we cannot depend on known behavior of calling `c.Equals` on a constant value. \n- Intuitively, the pattern should do the testing, not the object being tested\n- Calling a method on the expression could cause side effects!\n- The difference from switch semantics is jarring\n- Switching would preserve the nice property of `is` expressions today that it only returns `true` if the left operand is implicitly convertible to the (type of the) right. \n\nThere really is no downside to this, other than the little bit of work it requires to implement it.\n\n## Conclusion\n\nDo it.\n\n\n# Extension methods on tuples\n\n[Issue #16159](https://github.com/dotnet/roslyn/issues/16159) laments the facts that extension methods only apply to tuples if the tuple types match exactly. This is because extension methods currently only apply if there is an *identity, reference or boxing conversion* from the receiver to the type of the extension method's first parameter.\n\nThe spirit of this rule is that if it applies to a type or its bases or interfaces, it will work. We agree that it *feels* like it should also work for tuples - at least \"sometimes\". We cannot make it just always work for tuple conversions, though, since they may recursively apply all kinds of conversions, including user defined conversions.\n\nWe could check *recursively* through the tuple type for \"the right kind of conversion\". Compiler-wise this is a localized and low-risk change. It makes tuples compose well with extension methods. It's another place where things should \"distribute over the elements\" of the tuple.\n\nThis is a now-or-never kind of change. It would be a breaking change to add later.\n\n## Conclusion\n\nTry to do it now if at all possible.\n"
  },
  {
    "path": "meetings/2017/LDM-2017-01-18.md",
    "content": "# C# Language Design Notes for Jan 18, 2017\n\n*Raw notes - need cleaning up*\n\n## Agenda\n\n- Async streams (visit from Oren Novotny)\n\n# Cancellation\n\nWe decided per enumerator. This means:\nCan't have an enumerator be shared between multiple threads.\n\nYou can imagine channel-like data sources that provide enumerators but each enumerator gets a distinct set of values.\n\nThe interface is just giving you an access pattern, not a contract. They could be \"hot\" or \"cold\" / repeatable or not.\n\nShould we be close to Channel or is that something else?\n\nShould not force people to provide a token. For scenarios where that's needed, use analyzers.\n\n``` c#\nstruct AsyncEnumerableWithCancellation<T>(IAsyncEnumerable<T> src, CancellationToken ct)\n{\n\tpublic IAsyncEnumerator<T> GetAsyncEnumerator() => src.GetAsyncEnumerator(ct);\n}\n\npublic static class AsyncEnumerable\n{\n\tpublic static AsyncEnumerableWithCancellation<T> WithCancellation<T>(this IAsyncEnumerable<T> src, CT ct) => new AEWC<T>(...);\n}\n```\n\n`IAsyncEnumerable<T>` itself could expose a nullary GetAsyncEnumerator in one of the following ways:\n\n1. have another overload :-(\n2. have a default parameter (CLS :-()\n3. have an extension method (requires the extension method in scope)\n\nAs an alternative, the compiler can know to pass a default CT\n\n``` c#\npublic interface IAsyncEnumerable<T>\n{\n\tIAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken ct = default);\n}\n```\n\nCan use same trick for `ConfigureAwait`. Can combine the two sneakily.\n\n\n# Iterators\n\nHow do you get the cancellation token?\n\n- You don't unless you're implementing the GetAsyncEnumerator yourself\n- There's special syntax to get at the state machine\n\n``` c#\npublic async IAsyncEnumerable<T> Where<T>(this IAE<T> src, Func<T, CT token, Task<bool>> pred)(CT token)\n{\n\tforeach (await var v in src.With(token: token))\n\t{\n\t\tif (await pred(v, token)) yield return v;\n\t}\n}\n```\n\nThis is overly specific. But a general solution might be a big piece of work, and would possibly eliminate the \"shared -able/-tor\" optimization.\n\nOptions:\n- As above: special magic for iterators\n- an intrinsic method to get the token\n- other special syntax to get at the state machine\n- more general: single-method interfaces, anonymous classes...\n\nCan't make IAsyncEnumerable a delegate type,because we want to implement it on specific classes.\nCould we make IAsyncEnumerator a delegate? Would need to reduce to one method. But that can't both be covariant and return a Task\\<bool>.\n\nIterators may not be the *most* highly used feature, and it may be ok if this is a bit woolly. But it's *super* useful when you need it.\n\n# LINQ\n\nWould want overloads with async delegates (using `ValueTask` for efficiency)\n\nSyntax?\n- no different, when you use await we automatically add \"async\" to lambda\n- start the whole querty with `async` to \"opt in\"\n- `async` on each clause that needs it\n\nNeed to think about what's intuitive, and what's useful\n\nAdding query operators with async delegates is probably a breaking change, unless we give them new names. `WhereAsync` etc. We need to do some experimenting.\n\nWe may want overloads that take `IEnumerable` and async functions, and return `IAsyncEnumerable`.\n\n\n\n\n\n\n\n\n\n# ConfigureAwait\n# Performance\n# Batching\n# Syntax\n# \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n# Cancellation\n\nPrior conclusion: Should be specified *per iteration*, i.e. every time `GetEnumerator` is called.\n\nBest shot: \n- Make it an (optional?) parameter to `GetEnumerator`\n- Provide a `WithCancellation` extension method on `IAsyncEnumerable<T>`\n\n``` c#\npublic interface IAsyncEnumerable<out T>\n{\n\tIAsyncEnumerator<T> GetEnumerator(CancellationToken token);\n\tIAsyncEnumerator<T> GetEnumerator() => GetEnumerator(default(CancellationToken)); \n}\n\npublic static class AsyncEnumerable\n{\n\tclass AsyncEnumerableWithCancellation<T> : IAsyncEnumerable<T>{ ... }\n\tpublic static IAsyncEnumerable<T> WithCancellation<T>(this IAsyncEnumerable<T> enumerable, CancellationToken token)\n\t  => new IAsyncEnumerableWithCancellation<T>(enumerable, token);\n\n\t// Or\n\tpublic static IAsyncEnumerator<T> WithCancellation<T>(this IAsyncEnumerable<T> enumerable, CancellationToken token)\n\t  => enumerable.GetEnumerator(token);\n}\n```\n\nOptions here:\n\n`GetEnumerator` can have\n- One overload that takes a `CancellationToken`\n- One overload that takes an optional `CancellationToken`\n- Two overloads: One that takes a `CancellationToken` and one that doesn't. This works best if we have default interface member implementations\n\nThe `await foreach` rewrite can\n- Work just on enumerables, requiring them to carry in a `CancellationToken`\n- Work just on enumerables, but offering a syntax to pass in a `CancellationToken`\n- Work also on enumerators, offering the option to create one manually with a `CancellationToken`\n\n`WithCancellation` can\n- Return a wrapper Enumerable that holds on to the `CancellationToken`, and passes it in on `GetEnumerator` calls\n- Be just a wrapper for `GetEnumerable`, passing the token along\n- Be deemed unnecessary\n\n# Iteration\n\nThe `IAsyncEnumerator<T>` interface needs to be covariant, so `T` must occur as a return type only.\n\nThe most obvious candidate is this:\n\n``` c#\npublic interface IAsyncEnumerator<out T>\n{\n\tTask<bool> MoveNextAsync();\n\tT Current { get; }\n}\n```\n\n# Controlling asynchronous getting\n\nIt would be nice to provide the ability to understand if there's stuff \"queued up\", in order to make a decision whether to trigger the next get.\n\nThere seems to be two approaches:\n- Provide a method on the interface to `TryMoveNext` synchronously. \n- Facilitate explicit chunking/batching\n\n`TryMoveNext` could look like:\n\n```\n\tbool? TryMoveNext();\n```\n\nWhere `true` and `false` are the usual `MoveNext` results, and a `null` would mean you need to call `MoveNextAsync` to know whether there's more left.\n\nThe problem with this approach is that it's not meaningful to everyone, and some would not even be able to implement it usefully.\n\nExplicit chunking is something that you could expose if you want to, just using existing interfaces:\n\n``` c#\npublic IAsyncEnumerable<IEnumerable<Customer>> GetElementsAsync(); \n```\n\nNow the problem is that query operators and other things no longer work in terms of the core element type. You'd need some nifty type gymnastics to expose the enumerator pattern in terms of the nested collections, but implement the `IAsyncEnumerator` interface in terms of the core element type.\n\nIt would also be hard for utility methods like queries to wire through this knowledge of whether a next element is available.\n\n\n# Async foreach\n\nWhat's the syntax?\n\n``` c#\nforeach await (var v in src) ...\nawait foreach (var v in src) ...\nforeach (await var v in src) ...\n```\n\nHow does it deal with cancellation? (see above)\n- through explicit syntax\n- by being able to take enumerators as well as enumerables?\n- not at all - left to the library (calls `GetEnumerator()` with no arguments)\n\nHow about disposing?\n- look for `IDisposable`?\n- look for `IAsyncDisposable`?\n- Both? Neither?\n\n\n# Iterators\n\nCould be like current iterators.\n\nProblem: How is cancellation exposed to the iterator body?\n- special syntax?\n- if you want to access cancellation, use the iterator to write the enumerator, not the enumerable?\n\nBoth are painful\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-02-14.md",
    "content": "# C# Language Design Notes for Feb 14, 2017\n\n*Upcoming meeting*\n\n## Agenda\n\n- Meet with Unity to discuss language features relevant to game developers"
  },
  {
    "path": "meetings/2017/LDM-2017-02-15.md",
    "content": "# C# Language Design Notes for Feb 15, 2017\n\n*Upcoming meeting*\n\n## Agenda\n\n- Design Review"
  },
  {
    "path": "meetings/2017/LDM-2017-02-21.md",
    "content": "# C# Language Design Notes for Feb 21, 2017\n\n## Agenda\n\nWe triaged some of the [championed features](https://github.com/dotnet/csharplang/issues?q=is%3Aopen+is%3Aissue+label%3A%22Proposal+champion%22), to give them a tentative milestone and ensure they had a champion.\n\nAs part of this we revisited potential 7.1 features and pushed several out.\n\n1. Implicit interface implementation in Visual Basic *(VB 16)*\n2. Delegate and enum constraints *(C# X.X)*\n3. Generic attributes *(C# X.0 if even practical)*\n4. Replace/original *(C# X.0 if and when relevant)*\n5. Bestest betterness *(C# 7.X)*\n6. Null-coalescing assignments and awaits *(C# 7.X)*\n7. Deconstruction in from and let clauses *(C# 7.X)*\n8. Target-typed `new` expressions *(C# 7.X)*\n9. Mixing fresh and existing variables in deconstruction *(C# 7.1)*\n10. Implementing `==` and `!=` on tuple types *(C# 7.X)*\n11. Declarations in embedded statements *(No)*\n12. Field targeted attributes on auto-properties *(C# 7.1)*\n\n\n# Implicit interface implementation in Visual Basic\n[Champion \"Implicit interface implementation\"](https://github.com/dotnet/vblang/issues/38)\n\nThis long-requested feature in VB would also help deal with problems related to [default implementations of interface members](https://github.com/dotnet/csharplang/issues/52).\n\n## Conclusion\nCandidate for VB 16.\n\n\n# Delegate and enum constraints\n[Champion \"Generic constraint `delegate` (or allow `System.Delegate` as a constraint)\"](https://github.com/dotnet/csharplang/issues/103)\n\n[Champion \"Generic constraint `enum` (or allow `System.Enum` as a constraint)\"](https://github.com/dotnet/csharplang/issues/104)\n\nThis is a common request. Could\n\n- semantically require an actual delegate/enum or just allow the base class\n- syntactically show up as either the base class or the keyword\n\nFor delegates we need to consider how to deal with `MulticastDelegate`.\n\n## Conclusion\nCandidates for a minor C# version.\n\n\n# Generic attributes\n[Champion \"Allow Generic Attributes\"](https://github.com/dotnet/csharplang/issues/124)\n\nEven though this would work in principle, there are bugs in most versions of the runtime so that it wouldn't work correctly (it was never exercised).\n\nWe need a mechanism to understand which target runtime it works on. We need that for many things, and are currently looking at that. Until then, we can't take it.\n\n## Conclusion\nCandidate for a major C# version, if we can make a sufficient number of runtime versions deal with it.\n\n\n# Replace/original\n[Champion \"Replace/original and code generation extensions\"](https://github.com/dotnet/csharplang/issues/107)\n\nIf there's renewed investment in source generators, we'll add this, but this is not driven from the language end.\n\n## Conclusion\nCandidate for a major C# version, if and when source generators or similar efforts take place.\n\n\n# Bestest betterness\n[Champion \"Bestest Betterness\"](https://github.com/dotnet/csharplang/issues/98)\n\nWe want to do it, but not low-hanging enough for C# 7.1 time frame.\n\n## Conclusion\nCandidate for a minor C# release in the 7.X wave.\n\n\n# Null-coalescing assignments and awaits\n[Champion \"Null-coalescing assignments\"](https://github.com/dotnet/csharplang/issues/34)\n\n[Champion \"Null-conditional await\"](https://github.com/dotnet/csharplang/issues/35)\n\nThese need a little more design work and general bake time than what 7.1 allows.\n\n`await?` is an odd kind of keyword, but changing `await` to not throw on null may also be an issue. Thought needed.\n\n## Conclusion\nCandidate for a minor C# release in the 7.X wave.\n\n\n# Deconstruction in from and let clauses\n[Champion \"deconstruction in from and let\"](https://github.com/dotnet/csharplang/issues/189)\n\nToo many worms in the can for 7.1.\n\n## Conclusion\nCandidate for a minor C# release in the 7.X wave.\n\n\n# Target-typed `new` expressions\n[Champion \"Target-typed `new` expression\"](https://github.com/dotnet/csharplang/issues/100)\n\nLinks well with target typed `default` expressions, but too much design and potential fallout for 7.1. Interaction with anonymous objects as well.\n\n## Conclusion\nCandidate for a minor C# release in the 7.X wave.\n\n\n# Mixing fresh and existing variables in deconstruction\n[Champion \"Mix Declarations and Variables in Deconstruction\"](https://github.com/dotnet/csharplang/issues/125)\n\nThis rounds out the C# 7.0 experience, and was a late design change we didn't get to implementing.\n\nMay lead to occasional confusion, as in `M((int x, y) = e)` (declaring `y`)? We are OK with that.\n\n## Conclusion\nCandidate for C# 7.1.\n\n\n# Implementing `==` and `!=` on tuple types\n[Champion \"Support for == and != on tuple types\"](https://github.com/dotnet/csharplang/issues/190)\n\nThere's design work. It's not just call `.Equals` recursively.\n\n`==` today works between int and byte, for instance. We should probably make `(i1, i2) == (b1, b2)` work with that same equality.\n\nAlso for generics, for a type parameter `T` and a `t` of that type, we should allow `(t, i) == (null, 0)` by recursively applying the special \"compare to null\" semantics of equality over type parameters of C# today.\n\nToo big for 7.1.\n\n## Conclusion\nCandidate for a minor C# release in the 7.X wave.\n\n\n# Declarations in embedded statements\n\nNow that you can declare expression variables in an embedded statement, it's odd that old-fashioned declaration statements are forbidden in an embedded position (such as an if-branch, for instance). However, now that you can use a discard instead of a dummy variable declaration, the motivating scenario also goes away.\n\n## Conclusion\nLet's not do it.\n\n\n# Field targeted attributes on auto-properties\n[Champion \"Auto-Implemented Property Field-Targeted Attributes\"](https://github.com/dotnet/csharplang/issues/42)\n\nTechnically a breaking change, since the field target is already permitted today, but ignored. We don't expect anyone to be relying on this, though!\n\n## Conclusion\nCandidate for 7.1.\n"
  },
  {
    "path": "meetings/2017/LDM-2017-02-22.md",
    "content": "# C# Language Design Notes for Feb 22, 2017\n\n## Agenda\n\nWe went over the proposal for `ref readonly`: [Champion \"Readonly ref\"](https://github.com/dotnet/csharplang/issues/38).\n\n# readonly refs\n\nPassing and returning by ref addresses the copying and out parameter nightmare of performance critical code over structs. However, the use of it comes with risk: the recipient of a passed or returned ref can freely modify it.\n\nThis proposal introduces a `readonly` modifier on ref parameters and returns that incurs restrictions on the recipient of the ref similar to those incurred by a `readonly` modifier on a field. Thus, a ref can safely be passed or returned without risk of the recipient mutating it. This eliminates one common source of (deliberate, defensive) struct copying in C# code.\n\n## Conclusion\nWe want to support this.\n\n\n# readonly struct types\n\nIn and of itself, though, readonly refs contribute to another source of struct copying: when a method or property is invoked on a `readonly` struct (including now a readonly ref parameter or local), the C# compiler *implicitly* copies the struct, as a defense against the method or property invocation mutating the original struct. In the common case where the member is not actually mutating the struct, this is pure waste.\n\nTo counter this, the proposal also allows the `readonly` modifier on struct type declarations themselves. This signifies that no function member is mutating, and therefore calling them does not need to incur a copy. Inside struct members, `this` would be a readonly ref instead of a ref.\n\nOnce we have this feature, we could start warning on the compiler's defensive copying (with a warning wave for back compat).\n\nMore detailed versions are possible, where readonly-ness can be per struct member. This may not be necessary in practice, based on experience from the Midori project. (Or we can make it not strictly enforced, or allow exceptions that are somehow marked.)\n\n## Conclusion\nSupport `readonly` just on whole struct types for now, until and unless evidence shows the need for per-member decisions.\n\n\n# Syntax\n\nWe've been calling this feature \"readonly ref\", but it is really not the ref that is readonly; rather it is the thing that is referenced. For that reason is more correct to call it `ref readonly`, as in:\n\n``` c#\npublic ref readonly int Choose(ref readonly int i1, ref readonly int i2) { ... }\n```\n\nCurrently, refs *themselves* are always single-assignment in C#, but if we decide at some point to make them reassignable by default (which we could do without breaking), then you might want to be able to *explicitly* put a `readonly` modifier on the refs themselves. That would be `readonly ref`. And of course you could have `readonly ref readonly` where both the ref and the target are readonly.\n\n## `in` parameters\n\n`ref readonly` is a bit of a mouthful. For parameters, `ref readonly` is in fact the exact opposite of `out`: something that comes in but cannot be modified. It would make total sense to call them `in` parameters. However, it would probably be confusing to call a *return* value `in`, so `in` should be allowed as a shorthand for `ref readonly` exclusively on parameters.\n\n``` c#\npublic ref readonly int Choose(in int i1, in int i2) { ... } // Equivalent to the above\n```\n\n## Call site annotations\n\nWith today's refs you need a call site `ref` annotation. This is to warn the caller of potential side effects and make sure they buy into them. Do we need it for `ref readonly` parameters, where there are no side effects by definition? We believe not. \n\n``` c#\nint x = 1, y = 2;\nint z = Choose(x, y); // implicitly passed by readonly ref\n```\n\nWe didn't question the `ref` annotation on return statements in `ref readonly` returning methods, but maybe we should.\n\n## Values as `in` arguments?\n\nThe proposal allows literals to be passed as an `in` argument. A variable is created under the hood, assigned the value and passed along. Is that bad? On the one hand, it makes for less predictable performance, in that some arguments cause copying (into a fresh variable), and others do not. On the other hand, since no `ref` is required, the arguments look like value arguments, that are already copied.\n\nAt least initially, as we prototype this, we will allow any expression of the right type, and we will just copy into a shadow variable when necessary. Even when a variable of a different but convertible type is passed. If this turns out to be a problem, or a cause of confusion or overly defensive programming, then we'll reevaluate. \n\n\n# Extension methods\n\nWe want extension methods on structs to be able to work by ref, so that they don't copy. VB already allows this. We should allow both ref and ref readonly extension methods on value types.\n\nRef extension methods on classes could be controversial - like an `EnsureNotNull` method that replaces the object reference in the variable. We are not necessarily opposed to this in principle, but we don't need it for this scenario, and we'd have to track down weird consequences of it. So for now, extension methods with `ref` and `in` this-parameters must extend a value type.\n\n\n# Readonly parameters and locals\n\nA separate feature, but seems to be part of the same package, and is a long standing request. Let's try to do these at the same time.\n\n\n# Versioning\n\nWhat happens when older code references newer code with ref readonly return types? The old compiler might not understand the `readonly` annotation, and would happily allow mutation. Upgrade the compiler, and you're broken. Can we encode it in metadata in such a way that it breaks downlevel? modreqs? Possibly, but then putting it on existing libraries is a library breaking change.\n\nThe CLR already does not protect readonly-ness, and there are therefore already ways you can circumvent it and mutate anyway. You can't avoid bad actors (reflection etc), but we would like to avoid accidentally breaking guarantees, and also breaking code.\n\n## Conclusion\n\nWe'll build the first version using attributes, and therefore leaving us open to breaking on upgrade. We'll consider if there are mitigations, but poisoning downlevel code, e.g. with modreqs, seems like too big of a hammer.\n\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-02-28.md",
    "content": "# C# Language Design Notes for Feb 28, 2017\n\n*Quote of the Day:* \"I don't have time to dislike your proposal, but I do!\"\n\n## Agenda\n\n1. Conditional operator over refs (*Yes, but no decision on syntax*)\n2. Async Main (*Allow Task-returning Main methods*)\n\n\n# Conditional operator over refs\n\n[Champion \"conditional ref operator\"](https://github.com/dotnet/csharplang/issues/223)\n\nChoice between two variables is not easily expressed, even with ref returns. \n\nIf array `a1` is non-null, you want to modify its first element, otherwise you want to modify the first element of `a2`:\n\n``` c#\nChoose(a1 != null, ref a1[0], ref a2[0]) = value; // Null reference exception\n```\n\nIt would be nice if the ternary conditional operator just worked with refs in the branches:\n\n``` c#\n(a1 != null ? ref a1[0] : ref a2[0]) = value; // Right!\n```\n\nBoth branches would have `ref`, and would need to evaluate to variables of the same type.\n\n## Syntax\n\nWith the syntax as proposed, there's a concern that there will be an abundance of `ref` keywords in common code, leading to confusion. For instance, to store the selected variable above in a ref local would be:\n\n``` c#\nref int r = ref (a1 != null ? ref a1[0] : ref a2[0]); // Four \"ref\"s\n```\n\nAlternative proposal: Do not add new syntax for this. Instead, if both branches of an existing conditional expression are variables of the same type, let the compiler treat the conditional expression as a whole as a variable:\n\n``` c#\n(a1 != null ? a1[0] : a2[0]) = value; \nref int r = ref (a1 != null ? a1[0] : a2[0]); // Two \"ref\"s\n```\n\nThis does have a problem that it would subtly change semantics of existing code. Think of a value type `S` that has a mutating method `M`:\n\n``` c#\n(b ? v1 : v2).M(); \n```\n\nThis would now mutate the *original* `v1` or `v2` of type `S`, instead of a copy! In practice such code today is probably buggy: why would you want to call a method to mutate a throw-away copy? But the fact remains that this would be a breaking change, unless we think up some very insidious mitigation.\n\nAn example of such a scheme would be to decide that a conditional is a variable, not based on what's *inside* it, but on what's *around* it. Whenever it's being used as a variable (\n\nAn approach is to define variable-ness of ternaries not from the inside out, but by \"reinterpreting\" it whenever it occurs in variable contexts not allowed today (ref, assignment).\n\n## Readonly and safe-to-return\n\nThis should also work for [\"ref readonly\"](https://github.com/dotnet/csharplang/issues/38), if and when that goes in. For that to work, we'd either need to require further syntax (`ref readonly` in the branches) or infer readonly-ness from the branches. The latter is more appetizing. We could:\n\n1. require both or neither branch be readonly\n2. infer that the conditional expression is readonly if at least one branch is readonly\n\nLet's do 2. There seems to be no good reason for a stronger restriction.\n\nSimilarly we need to establish whether the resulting ref is safe-to-return. We can infer that the resulting ref is safe-to-return if both branches are safe-to-return.\n\n## Order of evaluation\n\nThere are subtle differences between the current spec and implementation when it comes to order of evaluation of an assignment. We need to make sure we fully understand how that plays in when the left hand side of an assignment is a conditional expression.\n\n## Conclusion\n- Yes to doing it\n- Syntax: leaning towards no refs inside (recursively), but worried about breaking changes\n- Precedence not an issue - `ref` is not part of the expression\n- Field like events: sure, if it makes sense\n\n\n# Async Main\n\n[Champion \"Async Main\"](https://github.com/dotnet/csharplang/issues/97)\n\nWe want to allow program entry points (`Main` methods) that contain `await`. The temptation is to allow the `async` keyword on existing entry points returning `void` (or `int`?). However, that makes it *look* like an `async void` method, which is fire-and-forget, whereas we actually want program execution to wait for the main method to finish. So we'd have to make it so that if the method is invoked as an *entry* point we (somehow) wait for it to finish, whereas if it's invoked by another method, it is fire-and-forget.\n\nThat is not ideal. Instead, we should allow new entry points returning `Task` and `Task<int>`:\n\n``` c#\nTask Main();\nTask Main(string[] args);\nTask<int> Main();\nTask<int> Main(string[] args);\n```\n\nSince such methods can exist today, but are not entry points, we should give precedence to existing entry points for backwards compatibility.\n\nThese new entry points are then entered as if being called like this:\n\n``` c#\nMain(...).GetAwaiter().GetResult();\n```\n\nIn other words, they rely on the built-in capability of `Task` awaiters to block on the getting the result.\n\nC# 7.0 allows declaration of other \"tasklike\" types. We won't allow those in entry points yet, but that is easy to work around: Just `await` your tasklike in an `async Task Main`.\n\n## Conclusion\n\nAllow `Task` and `Task<int>` returning `Main` methods as entry points, invoking as `Main(...).GetAwaiter().GetResult()`.\n"
  },
  {
    "path": "meetings/2017/LDM-2017-03-01.md",
    "content": "# C# Language Design Notes for Mar 1, 2017\n\n## Agenda\n\n1. Shapes and extensions (*exploration*)\n2. Conditional refs (*original design adopted*)\n\n\n# Shapes and extensions\n[Exploration: Shapes and Extensions](https://github.com/dotnet/csharplang/issues/164)\n\nThe write-up explores a version of \"type classes\" for C#, that can be implemented by types by means of extension declarations. It is aimed at improving the ability to adapt code, and to abstract over shapes of types without having to predict the need when the types are declared.\n\nThis is static approach, where you imbue types with new members *statically*, but they are not part of the objects at runtime. This can be contrasted with runtime ideas of \n\n* \"protocols\", understood as real, runtime types that objects can fit \"after the fact\"\n* \"extension interfaces\", where a type can be made to implement an interface in separate code\n\nBoth of these lead to objects having new types at runtime, whereas type classes - the present proposal - create a compile time \"illusion\", which leads to certain different trade-offs. These are competing approaches to attain many of the same goals, and in the end we'd have to weigh the trade-offs and decide one approach to go with. It's possible that we could devise a middle ground between the more static and the more dynamic approaches.\n\n## Implementation\n\nOne such trade-off is whether the runtime needs to change. The type-classes proposal comes with an efficient implementation strategy on top of the existing runtime.\n\nThe implementation exploits generic specialization for value types. This leads to many instantiations of the same generic type at runtime, which usually isn't too much of a concern from a memory perspective, but does add significantly to startup cost. Precompilation mechanisms such as NGEN can help with this, but those vary between platforms.\n\nThe proposal is assuming no changes to the runtime, but you could make the runtime do better and understand more, even in compatible ways. This is worth exploring.\n\n## Impedance mismatch\n\nOne downside of a static approach is that it relies on translation into different runtime concepts. Therefore the language-level compile-time world ends up differing more from the run-time world as seen through reflection and from other languages. And we have to remember that such \"other languages\" include existing versions of C#, unless the feature implementation does something to specifically \"poison\" the code for down-level consumption.\n\nIt's worth calling out, for instance, that many approaches to dependency injection rely on selecting between interface implementations through reflection. This would probably not work well with the \"shapes\" of the proposal, as the \"implements\" relationship is no longer evident at runtime.\n\nThis particular proposal goes further in hiding the details of the translation than e.g. [the proposal](https://github.com/MattWindsor91/roslyn/blob/master/concepts/docs/csconcepts.md) it is inspired by. While that leads to a simpler user-level model perhaps, it also hides details that are important at the next level down (such as extra type parameters!), and which would need to be reconciled with older versions of the C# compiler encountering this in libraries, as well as with other languages.\n\nA runtime approach would be able to keep a faithful representation of the language-level world. This would let typechecks and reflection \"get it right\", and counteract the language and runtime gliding further away from each other. However, it would lead to challenges interacting with existing code: If new concepts are introduced at the assembly level, older compilers are likely to be confounded, and effectively prevented from consuming it. \n\n## Issues with the specific approach\n\nThe proposal uses \"extension declarations\", as already envisioned through [\"extension everything\"](https://github.com/dotnet/roslyn/issues/11159) proposals, to also \"witness\" a type implementing a shape. This is intended to lower the concept count and unify some related ideas, but it also can be seen as too much of a conflation.\n\nThe disambiguation scheme in the proposal will not work when type parameters are constrained by more than one shape, each of which needs to be witnessed.\n\nWe should make sure we think through shapes that have more than one type parameter.\n\n## Conclusion\n\nWe should keep talking about ways to \"add types to objects\", and in particular try to do a similar exploration of more runtime-based approaches, so that we can compare.\n\n\n# ref conditional operator\n\nIn the [previous meeting](LDM-2017-02-28.md) we left open the syntax for the conditional operator over variables:\n\n``` c#\ncond ? ref v1 : ref v2 // original proposal\ncond ? v1 : v2 // alternative: just figure out if it's variable or not\n```\n\nThe alternative was considered on account of being more succinct. However, it leads to problems. On the semantic level:\n\n``` c#\n(cond ? v1 : v2).M(...); // breaking change?\n```\n\nWhat if `v1` and `v2` are of a value type, and `M` is a mutating method? Today `M` mutates a copy, which is probably silly and a bug. But it's been harmless for a long time, and there may be people depending on it.\n\n- If we change the behavior to mutate the selected variable, then that's a breaking change\n- If we don't, then you cannot as easily express mutating the original variable when it is *actually* useful\n\nThere's also a more implementation-oriented issue:\n\n``` c#\n(cond ? v1 : v2).M(await ...); // can't \"spill\"\n```\n\nWhen generating code for an await, we need to \"spill\" the stack, including any variable refs sitting on it, to the heap. Since refs cannot be in the heap, we do tricks: since we know the variable may need spilling, we don't actually resolve it in place. Instead we keep around the constituent parts (e.g. an array and an index, an object and a member, etc) and only look it up *after* the code has resumed after the await.\n\nBut here we cannot easily store the constituent parts, because we won't know which branch of the conditional will end up getting executed, and each may lead to different forms of constituent parts! While there may be extremely sneaky and possibly expensive ways around this, we could also just forbid the await. However, the error message would be very strange indeed if it came on an ordinary shape of conditional, whereas it is easier to say referring to a special syntactic form of the conditional.\n\n## Conclusion\n\nOn the whole, these challenges lead us to prefer the original proposal with the explicit occurrences of `ref` in the syntax. "
  },
  {
    "path": "meetings/2017/LDM-2017-03-07.md",
    "content": "# C# Language Design Notes for Mar 7, 2017\n\nQuote of the Day: \"Now `(T)default` means the same as `default(T)`!\"\n\n## Agenda\n\nWe continued to flesh out the designs for features currently considered for C# 7.1.\n\n1. Default expressions (*design adopted*)\n2. Field target on auto-properties (*yes*)\n3. private protected (*yes, if things work as expected*)\n\n\n# Default expressions\n[github.com/dotnet/csharplang/issues/102](https://github.com/dotnet/csharplang/issues/102)\n\nWe plan to allow target typed `default` expressions, where the type is left off:\n\n``` c#\nint i = default(int); // Current\nint i = default;      // New\nvar i = default;      // Error: no target type\n```\n\nIn essence, `default` is like `null`: an inherently typeless expression, that can acquire a type through implicit or explicit conversion. Unlike `null`, `default` can be converted to *any* type `T`, including non-nullable value types, and is equivalent to `default(T)` for that `T`. For types where both `null` and `default` are allowed, they both have the same value, namely null.\n\n## Constants\n\nLike `null` and `default(T)`, `default` is a constant expression *for certain types*.\n\n``` c#\nconst string S = null;    // sure\nconst string S = default; // sure\nconst int? NI = null;     // error\nconst int? NI = default;  // error\n```\n\nThis is just a consequence of the existing limitations on which types can be constants.\n\n## Constant patterns\n\nConstant patterns are interpreted in context of the type of the expression they are tested against. For instance, if the left hand side of an `is` expression is of an enum type `E`, `0` is the zero value of that enum type, not the int zero:\n\n``` c#\nE myE = ...;\n\nif (e is 0) ... // 0 means (E)0, not (int)0;\n```\n\nFor `null`, this means that the null value created by the constant pattern is of the reference or nullable value type of the left hand side. A `null` pattern is not allowed if the type of the left hand side is a non-nullable value type, or a type parameter not known to be a reference type. \n\nAs a special dispensation, however, `null` *is* allowed as a constant pattern even if the type of the left hand side is not one that allows constants. \n\nWe will allow `default` as a constant pattern when the type of the matched expression is a reference type, a nullable value type or a constant type. \n\n### case default\n\nAs a special case (no pun intended), this decision means that it would be permitted to write `case default:` in a switch statement! That is surely going to be confused with a `default:` label, and is almost certainly either a bug or a very bad idea. For this particular syntactic pattern, therefore, we should yield a warning. The warning goes away if you parenthesize `case (default):` or add a type `case default(T):` or similar.\n\n## Optional parameters\n\nExpressions of the form `default(T)` are explicitly allowed as default arguments of optional parameters even when non-constant. Therefore, so is `default`:\n\n``` c#\nvoid M(MyStruct ms = default) { ... } // sure\n```\n\n## Special forms\n\nToday `null` is specially allowed in a number of situations, where it is treated as a value even though it is not given a type. We have to decide whether `default` is similarly allowed in those places. Our general position is \"no\": While `null` conceptually has a specific value, even though its representation varies, `default` conceptually has different values depending on context. Therefore it doesn't make sense to treat it as a value in typeless contexts.\n\nSpecifics listed out below.\n\n### Equality\n\nWe allow `null == null` as a special case, called out specifically in the language spec. We don't think we should allow `default == default`. Even though it would probably be true regardless of the type, it doesn't make sense with no type.\n\n### is-expressions\n\n`null` is allowed on the left hand side of `is` expressions:\n\n``` c#\nbool b = null is T; // allowed, always false\n```\n\nShould `default` similarly be allowed? It is important to note that the type `T` in these expressions is *not* a context type for the expression: the compiler does *not* convert the expression to the type. For instance, when you write\n\n``` c#\nif (0 is DateTime) { ... }\n```\n\nThe result is always *false* (the compiler even warns about it), even though 0 converts to the enum `DateTime`. This is because `0` is interpreted on its own, not through a literal conversion, and on its own it has the type `int`. The `int` zero is not a `DateTime`, so the result is false. It is essentially as if the expression was boxed to `object`, and *then* checked at runtime against the type.\n\nBy the same reasoning, if we allowed `default` on the left hand side it would not mean `default(T)` but `default(object)`. That would surely be confusing to the programmer:\n\n``` c#\nif (0 is int)            { ... } // True: 0 is an int \nif (default(int) is int) { ... } // True: 0 is still an int\nif (default is int)      { ... } // Would be false! default(object) is null, which is not an int.\n```\n\nFor this reason, we will not allow `default` on the left hand side of an is-expression.\n\n### as-expressions\n\n`null` is allowed on the left hand side of `as` expressions:\n\n``` c#\nT t = null as T; // allowed, always null\n```\n\nShould `default` similarly be allowed? In case of `as`, the type is restricted to be a reference type or a nullable value type. Therefore `default` always meaning `null` wouldn't be surprising in the same way that it would be for the `is` operator.\n\nIn this particular case, therefore, it seems alright to allow `default`, essentially as an alias for `null`.\n\n### throw statements and expressions\n\nYou are allowed to `throw null` in C#. It leads to a runtime error, which ironically causes a `NullReferenceException` to be thrown. So it is a sneaky/ugly idiom for throwing a `NullReferenceException`.\n\nThere's no good reason to allow this for `default`. We don't think the user has any intuition that that should work, or about what it does. \n\n## Using `default` versus `null`\n\nWhen should I use `default`, and when should I use `null`? Are we setting up for style wars?\n\nOne proposal to circumvent this issue is to not adopt the `default` syntax, but instead use `null` - even for non-nullable value types. Not only would this be confusing, it would also be breaking: It would allow `null` to convert to e.g. `int`, which would affect overload resolution.\n\nAnother idea is to allow `default` *only* when the type is not known to be a reference or nullable value type. So the two would be mutually exclusive, and you'd never have a choice.\n\nLet's not restrict it in the language. It would be a matter of style, and an IDE might even give you code style options about it. The recommendation would probably be `null` when we can, `default` otherwise, and `default(T)` when we have to. But you can imagine for instance using `default` for nullable things for uniformity, where a swath of code initializes multiple things, some nullable and some non-nullable. Not allowing that seems unnecessarily restrictive.\n\n## Conclusion\nAdopt `default` expressions with the design decisions described above, targeting C# 7.1.\n\n\n# Field target on auto-properties\n[github.com/dotnet/csharplang/issues/42](https://github.com/dotnet/csharplang/issues/42)\n\nThrough several releases we have neglected to make the field target on attributes work right when applied to auto-implemented properties. It should attach the attribute to the underlying generated field, just as it does when applied to field-like events.\n\nThere are extremely esoteric ways in which this can be a breaking change; essentially when someone exploits unintended leniency in today's compiler. There is absolutely no benefit from such exploitation, and we don't imagine anyone would rely on it. If it turns out we're wrong, we can reintroduce the leniency specifically for the breaking case, but we don't think it is worth it here.\n\n## Conclusion\nAdopt the feature with a current target of C# 7.1.\n\n\n# Private protected\n\nWe have a complete feature design and a very nearly complete implementation. What we need in order to go forward is to test out a lot of things:\n\n- Do completion, refactorings, etc. work in IDEs?\n- How does it work with languages that don't understand it, including F# and older versions of C#\n- How much would it confuse other tools such as CCI?\n- Does this fully and completely work as expected in the runtime?\n\nEven though the feature is already allowed in C++/CLI, there's reason to suspect it wasn't exercised all that broadly, so there may be corner cases that don't work as expected.\n\nThis feature would need to be added to both C# and VB for API parity reasons. We would need to do the work to implement it in VB.\n\n## Conclusion\nIf all those things work out well enough, we do want the feature.\n"
  },
  {
    "path": "meetings/2017/LDM-2017-03-08.md",
    "content": "# C# Language Design Notes for Mar 8, 2017\n\n## Agenda\n\nWe looked at default interface member implementations.\n\n1. Xamarin interop scenario\n2. Proposal\n3. Inheritance from interface to class\n4. Overriding and base calls\n5. The diamond problem\n6. Binary compatibility\n7. Other semantic challenges\n\n\n# Xamarin interop scenario\n\nAndroid interfaces are written in Java, and can therefore now have default implementations on members. Xamarin won't be able to seamlessly project those interfaces into .NET.\n\nOn iOS, Objective-C and Swift have protocols, of the general shape:\n\n``` c#\nprotocol Foo\n{\n    void Hello();\n@optional\n\tint Color { get; set; }\n\tint Bye();\n}\n```\n\nAgain, the best we can do is to project the non-optional parts into C# interfaces, whereas the optional parts must be handled in less appetizing ways:\n\n``` c#\ninterface IFoo\n{\n\tvoid Hello();\n}\n```\n\n\n# Proposal\n\n[The current proposal](https://github.com/dotnet/csharplang/blob/master/proposals/default-interface-methods.md) is to allow the following in interfaces:\n\n- member bodies\n- nonvirtual static and private members\n- overrides of members\n\nPutting a concrete body on your method (etc), means you don't have to implement it on the class.\n\nNot proposing (but may want to look at):\n- non-virtual public instance members\n- protected and internal members\n- nested types\n- operator declarations\n- etc...\n\nDon't want:\n- state!\n- conversions\n\nThis gives parity with where Java is: they made tweaks over time based on feedback, and this is where they landed (private and static members were added).\n\nThe more you go to the side of adding things, the more this is a philosophy change for interfaces.\n\n\n# Inheritance from interface to class\n\nImportant question: is the member inherited into the class, or is it \"explicitly implemented\"? Our assumption is that it's explicitly implemented:\n\n``` c#\ninterface I { int M() => 0; }\nclass C : I { } // C does not have a public member \"M\"\n```\n\nThat means you can't \"just\" refactor similar implementations into an interface the way you do into a base class.\n\n\n# Overriding and base calls\n\nShould overrides be able to call `base`? Yes, but we would need new syntax to deal with ambiguity arising from the fact that you can have more than one base interface:\n\n``` c#\ninterface I1 { void M() { WriteLine(\"1\"); } }\ninterface I2 : I1 { override void M() { WriteLine(\"2\"); } }\ninterface I3 : I1 { override void M() { WriteLine(\"3\"); } } \ninterface I4 : I2, I3 { override void M() { base(I2).M(); } }\n```\n\nThe exact syntax for disambiguating base calls is TBD. Some ideas:\n\n``` c#\nI.base.M()  // what Java has\nbase(I).M() // similar to default(I)\nbase.I.M()  // ambiguous with existing meaning\nbase<I>.M() // looks like generics\n```\n\n# The diamond problem\n\n`I4` above inherits two default implementations, one each from `I2` and `I3`, but explicitly provides a new implementation, so that there's never a doubt as to which one applies. However, imagine:\n\n``` c#\ninterface I5: I2, I3 { }\nclass C : I2, I 3 { }\n```\n\nThe class declaration of `C` above must certainly be an error, since there is no good (symmetric) unambiguous way of determining a default implementation. Also, the interface declaration of `I5` should be an error, or at least a warning.\n\nThis means that adding an override to an interface can break existing code. This can happen in source, but depending on compilation order, it may also be possible to successfully compile such code.\n\n# Binary compatibility\n\nWhat should the runtime do when an interface adds a default implementation and that causes an ambiguity in code that isn't recompiled?\n\nShould this be a runtime error? It would lead to some hard-to-understand failures. Should it \"just pick one\"? \n\n\"Why did you not let my program run?\" vs \"why did you not prevent this hole\"?\n\nWe need to decide what is less harmful. We should look at what Java does and why.\n\n\n# Other semantic challenges\n\nThe feature reveals some \"seams\" between C# and the CLR in how they understand interface overriding. In the following, imagine `I`, `C` and the consuming code are in three different assemblies:\n\n``` c#\n// step 1\n\ninterface I { }\n\nclass C : I { public void M() { /* C.M */ } }\n\n// step 2\n\ninterface I { void M() { /* I.M */} }\n\nI i = new C();\ni.M(); // calls I.M default implementation\n\n// step 3: recompile C\n\nI i = new C();\ni.M(); // calls C.M non-virtual method\n```\n\nThe problem here is that the runtime doesn't consider non-virtual members able to implement interface members, but C# does. To bridge the gap, C# generates a hidden virtual stub method to implement the interface member. However, during step 1 there is no interface member to implement, and during step 2 the class declaration isn't recompiled. The runtime doesn't consider `C.M` an implementation of `I.M`, so if you call `M` on a `C` through the `I` interface, you get the default behavior. As soon as `C` is recompiled, however, the compiler inserts its stub, and the behavior changes.\n\nWe have to decide it there is something we can and will do about this. We may just accept it as a wart.\n"
  },
  {
    "path": "meetings/2017/LDM-2017-03-15.md",
    "content": "# C# Language Design Notes for Mar 15, 2017\n\n*Quote of the Day:* \"Little leek - isn't that called a spring onion?\"\n*Quote of the Other Day:* \"Who's champion for recursive patterns? It says 'see champion for recursive patterns'.\"\n\n## Agenda\n\nTriage of championed features\n\n1. JSON literals\n2. Fixing of captured locals\n3. Allow shadowing of parameters\n4. Weak delegates\n5. Protocols/duck typing/concepts/type classes\n6. Zero and one element tuples\n7. Deconstruction in lambda parameters\n8. Private protected\n\n\n# JSON literals\n\nNo\n\n\n# Fixing of captured locals\n\nNot worth any effort, probably even as up for grabs\n\n\n# Allow shadowing of parameters\n\nCurrent rule saves your bacon a couple of times:\n\n``` c#\nvar t = FooAsync(...)\n\nt.ContinueWith(t => ... ); // whoops\n```\n\nDiscards would make this worse, in a sense, because they lead people to be more likely to capture.\n\nShadowing could be used to avoid capturing, but that would be better served by a non-capture feature. Could be a `static` on lambdas to avoid capture - or it could be a capture list approach.\n\n\"Capture nothing\", \"capture what I want\", \"capture this\" are three potential levels with different cost.\n\nCould be `this`, `static` and nothing in front of the lambda. But it might be nice to have an explicit annotation for the default, for people who care to express that they explicitly thought about it.\n\nIndividual items in a capture list are worthless if you don't care about different *kinds* of capture for a given variable.\n\nAlso a great candidate for custom annotations so we don't put it in the language. That would also allow folks that want more detail to have that.\n\nAttributes on lambdas seem like a more general feature. Let's feed this in as a scenario for attributes on lambdas.\n\n\n# Weak delegate \n\nBest approach is the small leak pattern which creates a wrapper delegate with a weak reference to the original receiver. That doesn't solve the whole problem, though - how about unregistering, etc?\n\nThis isn't necessarily a language feature. This should be a library that you pass the method to, and it wraps it. It would be helped by the language allowing for a delegate constraint.\n\nConclusion: Not as a language feature right now; figure it out as a library feature, and *maybe*, someday we would add syntax around it.\n\n\n# Protocols/duck typing/concepts/type classes\n\nMore dynamic or more static approaches to \"adding a 'type' after the fact\".\n\nA separate important subissue is the dependency explosion.\n\nDifferent solutions to the same problem. They should be addressed as one design effort.\n\n8.0 as a milestone is probably crazy and unrealistic, but helps us prioritize investigation work\n\n\n# Zero and one element tuples\n\n``` c#\nvar () = e;       // who cares to deconstruct?\nvar (x) = e;      // just get through property?\nvar (x, (y)) = e; // recursive - can't just grab a member\n```\n\nIn other languages `()` are list-like unit type things - an alternative to `void`, that is more of a first class type and can therefore be used in generics.\n\n``` c#\n() M(...) => (); // returns zero things\n```\n\nAlso if we ever embrace bool-returning Deconstruct methods (or the like), you might want zero-length decontructors to mean \"there wasn't anything\".\n\nWomples (one-element tuples) are more likely to be useful, especially for deconstruction. But they are also the ones that clash most fiercely with existing syntax (parenthesized expressions!).\n\n``` c#\n() t = ();\n(int x) = (5);\n(int x) = (d); // could go either way - deconstruct a womple, or deconstruct d?\n```\n\nProbably not that useful to have womple expressions. Could allow using named element(s) or even `:` alone:\n\n``` c#\nvar t = (x: 3);\nvar t = (: 3); // yuck!\n```\n\nOn a deconstruction side:\n\n``` c#\n(x) = e;\n(x, (y)) = e;\n```\n\nthat already means something today. You could do:\n\n``` c#\n(x: x) = e;\n(: x) = e;\n```\n\nWe would have \n\n``` c#\nif (o is OneDPoint(3)) ...\nif (odp is (3)) ...\n```\n\nOpen questions abound.\n\n\n# Deconstruction in lambda parameters\n\nIt's a special case of deconstruction in parameters \n\n``` c#\n(var (x, y)) => x + y;\ndouble M((int x1, int y1), (int x2, int y2)) => Sqrt(x1 * x2 + y1 * y2);\n```\n\n# private protected\n\nWould not use so much in the BCL, but in APIs with deeper hierarchies, definitely.\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-03-21.md",
    "content": "# C# Language Design Notes for Mar 21, 2017\n\n## Agenda\n\nDiscussion of default interface member implementations, based on [this guided tour](https://github.com/dotnet/csharplang/issues/288).\n\n1. Concerns raised on GitHub and elsewhere\n2. Inheritance?\n3. Breaking name lookup on `this`\n4. Events\n5. Modifiers\n6. Methods\n7. Properties\n8. Overrides\n9. Reabstraction\n10. Most specific override\n11. Static non-virtual members\n12. Accessibility levels\n13. Existing programs\n\n\n# Concerns raised in various fora\n\n- Traits: Not what we're out to address! It may have similar capabilities, but the design point is different, based on different motivations.\n- We are also *not* out to add multiple inheritance to the language - we already have it with interfaces, and we're just making sure that continues to work.\n- It's a bit funny that members of interfaces are inherited into interfaces but not into classes.\n\nInteresting design point: This isn't really fully traits, because interface members aren't inherited. The interfaces can't be building blocks for classes.\n\nFor structs, there aren't really any other ways to factor out behavior. \n\nJava did this years ago, and the world did not fall apart.\n\n# Inheritance?\n\nWe could consider letting default-implemented interface members be inherited into classes. That would be a big break away from interfaces today, where an implementing class always has to do *something* to get a corresponding public member. It would also probably make it a breaking change to *add* a default implementation to an existing member, which does not seem attractive.\n\nWe could have a feature where when you specify a base interface you can ask to have its default implemented members inherited.\n\n\n# Breaking name lookup on `this`\n\nThere's a new kind of breaking change that may arise from adding new members to interfaces, where derived interfaces will get name lookup conflicts in their concrete implementations:\n\n``` c#\nitf IA { void Foo() {} }\n\nitf IB {}\n\nitf IC : IA, IB \n{ \n    void Bar() \n    { \n        Foo();            // allowed? What if IB adds Foo()?\n        this.Foo();       // same? different?\n        ((IA)this).Foo(); // would be allowed\n        this(IA).Foo();   // new syntax?\n    } \n}\n```\n\n# Events?\n\nAbsolutely. They aren't materially different. Any member you can declare in an interface should be able to have default implementations.\n\n# Modifiers\n\nVirtualness is default in interfaces today. We could allow `sealed` to mean non-virtual if you want to override that.\n\nPublic is default in interface. Should we allow the default to be explicitly stated? All other accessibilities are potentially interesting as well.\n\n`extern` scenario: people really like the idea of a scoped PInvoke. People want it for local functions as well.\n\n`static`? Yes\n\n\nNested types?\n\n**Philosophically**, we can either go all (or most of) the way to what classes can do, or do it as sparingly as possible, adding only things that are really needed. Once I can put implementation in an interface, I want all of the other stuff. Moving a method implementation from a class up to an interface shouldn't all of a sudden put a bunch of limitations on how to implement it.\n\nMove from \"let me have this\" to \"tell me why I can't have this\".\n\n\n# Methods\n\nCan I use plain old `base` (without disambiguation)? \n- Is it of type `object`, and exposes `object` methods?\n- disallow?\n- `base` means \"the\" base interface, if applicable - may even \"mesh\" the base interfaces.\n\nNo `base` for now, just for initial simplicity.\n\n\n# Properties\n\nAbstract properties and events let you implement just one accessor. Can interface properties do that? Our strawman is \"yes\". \n\n# Overrides\n\n- Allow explicitly overriding an interface member that you override?\n- Allow implicitly overriding ...?\n\n``` c#\ninterface I1 { void M(); }\ninterface I2 : I1 { override void I1.M() { ... } } // \"explicit\" override\ninterface I3 : I1 { override void M() { ... } }    // \"implicit\" override\n```\n\nAllowing the latter means that the `override` keyword is needed, in order to avoid syntactic ambiguity. The latter may override *all* such members? Yes. Direct *and* indirect.\n\nThere's a bit here about which \"class\" analogy we apply: the \"class inherits class\" analogy, or the \"class implements interface\" analogy. The latter doesn't really apply anyway, so it's more similar to \"class inherits class\". Therefore we should require the `override` keyword even on `IA.M` explicit member overriding.\n\nProperties, can override just one accessor.\n\nTuple names must match, just as between classes. For `dynamic`, same as between classes.\n\n\n# reabstraction\n\nAllow an override to remove implementation. `abstract` keyword is optional.\n\n\n# Most specific override\n\nThere has to be a most specific override, otherwise it's an error. \n\nProperties and events, the accessors could in principle be treated independently (though there may be a problem with the Roslyn API). Let's instead say that it happens at the whole property level: there must be a most specific override of the property itself.\n\n\n# static non-virtual members on interfaces\n\nWould be useful even without this feature. But a shared helper may also be static.\n\n\n# all accessibility levels?\n\n`public` and `private` for sure. Let's investigate what `internal` and `protected` mean.\n\n\n# Existing programs\n\nWe think that example 3 (in this section of the guided tour) is analogous to 2, and should be allowed. However, how can we help someone who thought they were implementing the interface member, but were writing an unrelated private method?\n\nDeciding whether a method implicitly implements an interface method is not just matching by signature. \n\nWe should accept the behavior now, and then look at pitfalls here later.\n "
  },
  {
    "path": "meetings/2017/LDM-2017-03-28.md",
    "content": "# C# Language Design Notes for Mar 28, 2017\n\n## Agenda\n\nDesign some remaining 7.1 features\n\n1. Fix pattern matching restriction with generics\n2. Better best common type\n\n\n# Fix pattern matching restriction with generics\n\nToday `x as T` is allowed if \n\n1. there is a reasonable relationship between the left and right type, or\n2. one of them is an open type\n\nBut for the `is` operator we don't have the second. That means that we can't always replace uses of `as` followed by null check with an `is` with a type pattern.\n\nAlso, the restrictions are supposed to rule out only obviously useless cases, whereas some of these are demonstrably useful.\n\nLet's allow it, look again if there are unexpected problems.\n\n\n# Better best common type\n\nBest common type should combine a value type with null literal to get a nullable value type.\n\n``` c#\nb1 ? 1 : b2 ? null : b3 ? 2 : default; // default is 0\nb1 ? 1 : b2 ? default : b3 ? 2 : null; // default is null\n\nb1 ? 1 : (b2 ? null : (b3 ? 2 : default)); // default is 0\nb1 ? 1 : (b2 ? default : (b3 ? 2 : null)); // default is null\n```\n\nThis is weird, but fine:\n\n``` c#\nM(1, default, null); // int?\n```\n\nNext step is trying to spec it. It's a bit complicated.\n\n``` c#\nM(myShort, myNullableInt, null); Should continue to infer int? , not short?\n```\n"
  },
  {
    "path": "meetings/2017/LDM-2017-03-29.md",
    "content": "# C# Language Design Notes for Mar 29, 2017\n\n## Agenda\n\n1. Nullable scenarios\n2. `Span<T>` safety\n\n# Nullable scenarios\n\nIdentify all the scenarios where nullable needs to be right.\n\nPhilosophical debate about what the feature is. Should it be as strict as possible, or more forgiving? Is it more a type feature or more a helpful warning feature? \n\nWe've made decisions about where we are on that spectrum. Do we trust that as a starting point, or do we want to reexamine those at this point?\n\nExample: We want to track variables with flow analysis. for simple names `x` (local variables, parameters) that has reasonably high fidelity. As we move to `x.y.z` the confidence goes down, but the usefulness goes up.\n\nLet's agree right now that we're pretty far from the perfect guarantee. It's not that there is anything fundamentally wrong with that, there's just no way to fit it. Let's make lemonade.\n\nWe have design choices and we have interesting scenarios. Two kinds:\n- Here are situations where people get into problems with nulls; look at whether the feature solves it\n- Understand false positives and negatives too: getting errors that incorrectly flag a \"problem\", vs not being told about a problem.\n\nFalse alarms are a problem, because they will discourage people from taking on the feature, and from taking the reports seriously. We can't be too strict.\n\nAlso an issue of writing the libraries: is this sufficiently expressible? \n\nAnother measure of success: How much does a client of a newly annotated old library have to change in order to accommodate?\n\nExample: If we are going to say that you annotate your locals, that might be more consistent with the rest of the language, but might also cause more code to need to be changed.\n\nThis may be a question of gradual adoption strategies. It could be that you start out consuming nullables (which are the new thing, syntactically), without making unannotated mean \"non-null\".\n\nGenerics is always a fun situation. Are they in subtyping relationship? That informs variance. And so on.\n\nNext steps: Get some samples going.\n\n\n# `Span<T>` safety\n\n`Span<T>` is special: it logically contains a `ref` and a size/range. Can't be allowed to tear, and may reference things on the stack: Therefore can't live on the heap. Also, needs to respect the lifetime of a local to which it has a ref. We'll introduce a notion of \"ref-like\" types, in anticipation of more of these.\n\nOther \"ref-like\" types already exist (e.g. `TypedReference`), but are pretty obscure and unsafe. We won't let our design influence by them, but might opportunistically unify. Also their implementation in the compiler can serve as a checklist for dealing with the new notion of ref-like types.\n\nDeclaration: need something in metadata. Old compilers will ignore it. We cannot poison a type with modreq's. We could `Obsolete` the type, and the new compiler could recognize it somehow. \n\nFor now we shouldn't support language-level declaration of ref-like types. There's a whole set of rules we'd need to figure out for such declarations; instead we are good with just recognizing this in metadata and acting accordingly for now.\n\nref-like types cannot be passed by ref, only by `in`, Therefore they must be readonly structs, so that `this` is not passed by ref.\n\nIn general, these rules are quite restrictive in certain ways. Let's try it and see if it works in our scenarios. There may be an `unsafe` opt-out, or we may nuance the rules.\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-04-05.md",
    "content": "# C# Language Design Notes for Apr 5, 2017\n\n## Agenda\n\n1. Non-virtual members in interfaces\n2. Inferred tuple element names\n3. Tuple element names in generic constraints\n\n\n# Non-virtual members in interfaces\n\nDo we *want* to allow non-virtual declarations in interfaces? In practice you probably at least want private methods. But it's likely you'll want internal, and maybe public. What's the syntactic distinction from normal \"virtual/abstract\" interface members?:\n\n``` c#\ninterface I1\n{\n    virtual void M1() { ... }\n    void M2() { ... } // non-virtual\n}\ninterface I2\n{\n    void M1() { ... } \n    sealed void M2() { ... } // non-virtual\n}\ninterface I3\n{\n    virtual void M1() { ... } \n    sealed void M2() { ... } // non-virtual\n}\n```\n\nIf you want this for traits based programming, you'd want to have the same things available, when you \"port things over\" to a trait.\n\nIntuitively, though, it feels against the spirit of interfaces.\n\nShould an interface be required to put `abstract` in order to allow derived interfaces to override them? No. So it probably also shouldn't require `virtual`. So it's the \"virtualness\" that's implicit, not specifically the \"abstractness\". \n\nThe core motivating scenario is default-ness of implementations. So that is the thing we should design around. Is the copy-paste scenario between interfaces and classes important? It already is very far from possible. For instance, property declarations in interfaces today are syntactically identical to auto-properties in classes today!\n\nRequiring a modifier (e.g. `virtual`) on a virtual interface member with a default member, as in `I1` and `I3` above, causes an inconsistency between interface members with and without default implementations. \n\nAlso, taking unmodified members with bodies to be non-virtual, as in `I1` above, is a bit dangerous: adding a body changes the member from virtual to non-virtual. While an implementing class may still think it is implicitly implementing the member, it is in fact just declaring an unrelated member:\n\n``` c#\nclass C : I1\n{\n    public void M2() { ... } // Doesn't implement I1.M2, which isn't virtual!\n}\n```\n\nIt is better to require a modifier (e.g. `sealed`) on non-virtual members in interfaces, to clearly distinguish them, as in `I2` and `I3` above.\n\nThe best combination, then, is illustrated by `I2`, where non-virtual members must be marked, and virtual ones must not (and maybe cannot).\n\nTentatively we'll go forward with the following decisions:\n\n- Non-virtualness should be explicitly expressed through `sealed`\n- We want to allow all modifiers in interfaces, in analogy with classes, but with different defaults \n- Default accessibility for interface members is public, including for nested types\n- `private` function members in interfaces are implicitly `sealed`, and `sealed` is not permitted on them. `private` nested *classes* can be `sealed`, and that means `sealed` in the class sense.\n\nAbsent a good proposal, `partial` is still not allowed on interfaces or their members.\n\n\n# Inferred tuple element names\n\nAnonymous objects allow \"projection initializers\", where the name of a member can be automatically inferred from an expression ending in a name:\n\n``` c#\nnew { X = X, Y }; // infers Y as name of second member\n```\n\nProposal is to do the same for tuple literals, picking up any names in element expressions if the element doesn't explicitly have a name:\n\n``` c#\nint a = 1;\n...\nvar t = (a, b: 2, 3); // (int a, int b, int)\n```\n\nJust as with anonymous types we pick up names from expressions that are simple names (`x`), dotted names (`e.x`) and `?.`'ed names (`e?.x`).\n\nThis is technically a breaking change from C# 7.0, but it is quite esoteric. It is hard to construct an example where you depend on a tuple element *not* having a particular name, but here's one:\n\n``` c#\nAction y = () => {}\nvar t = (x: x, y) // (int x, Action y) or (int x, Action)?\nt.y(); // a call of the second component or of an extension method y on the type (int, int)?\n```\n\nWe think that this is low enough risk that we can introduce the feature, especially if we do it quickly (C# 7.1).\n\nA subtlety of the feature is that inferred names should not trigger the warnings around unused names:\n\n``` c#\n(int, int) t = (x: x, y); // warning for x. No warning for y, because inferred\n```\n\n\n# Tuple names in constraints\n\nThere are some gnarly issues questions around tuple element names in generic constraints. In general we try to avoid use of different tuple element names across related declarations, but with constraints it is hard.\n\nA simple example is \n\n``` c#\nclass C<U> where U : I<(int a, int b)>, I<(int notA, int notB)> // this is currently allowed, and would become an error\n```\n\nBut more complex examples involve indirect differences.\n\n``` c#\nclass C<U> where U : I<(int a, int b)>, I2 // where I2 implements I<(int notA, int notB)>\n```\n\nIn the case of type implementations, we prevent those and even check for possible type unifications.\nBut in the case of constraints, we currently don’t check as much (no type unification check).\n\nThe third level of difficulty is illustrated by:\n\n``` c#\nclass C<U, T> where U : I<(int a, int b)>, I2<T> // where I2 implements I<(T notA, T notB)>\n```\n\nWe think you could never declare a class (in C#) that satisfies the constraints (in C#) in these examples. You could construct things in IL to circumvent, but it's ok for us not to deal with that. So it's probably ok for C# not emit an error here.\n\nWe do try to emit an error when constraints conflict. But the value is low and it is hard and esoteric and makes the compiler slower.\n\n\n\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-04-11.md",
    "content": "# C# Language Design Notes for Apr 11, 2017\n\n## Agenda\n\n1. Runtime behavior of ambiguous default implementation\n\n\n# Runtime behavior of ambiguous default implementation\n\nThe feature is intended to work when a new default-implemented member is added to an interface `I`, even when an implementing class `C` is not recompiled. So the runtime needs to know about default implementations and be able to find them.\n\nIn the case of overrides, there may be diamond-hierarchy cases where the compiler knows of only one override, but one is added later to another interface. The implementations are now ambiguous, and a recompilation would cause an ambiguity, but it would seem desirable that the runtime should choose \"the one the compiler knew about\"; that, somehow, that knowledge would be baked in to the compiled class `C`.\n\nStarting out with these type declarations in separate assemblies:\n\n``` c#\ninterface I1 { void M() { Impl1 } }\ninterface I2 : I1 { override void M() { Impl2 } }\ninterface I3 : I1 { }\nclass C : I2, I3 { }\n```\n\nEveryone's happy, and `C`'s implementation of `M` would unambiguously come from `I2`.\n\nNow `I3` is modified and recompiled:\n\n``` c#\ninterface I3 : I1 { override void M() { Impl3 } }\n```\n\nWhat should happen at runtime? When `C` was compiled, it \"thought\" everything was alright. At runtime it isn't. Can the compilation of `C` bake in a preference based on its understanding of the world at the time of compilation? Should it?\n\nIt is not obvious how this would work. What if the default implementation `C` depends on is moved, deleted or overridden? Should it just be a \"vague\" preference in case of ambiguity, to get the runtime on the right track?\n\nThis seems complicated, fragile and fraught with peril, but ending up with an ambiguity at runtime is also bad.\n\nRegardless, there will always be runtime ambiguities; \"baking in\" preferences would only address a subset. Two open questions:\n\n1. Should we try to help resolve ambiguities by baking in compile time preferences? Unresolved.\n2. Should we fail or pick an \"arbitrary\" implementation in case of inevitable ambiguities at runtime? Unresolved. Bad to error. Bad to run \"arbitrary\" code.\n\nWe should look more deeply into what Java does here. There must be accumulated insight already on this topic.\n"
  },
  {
    "path": "meetings/2017/LDM-2017-04-18.md",
    "content": "# C# Language Design Notes for Apr 18, 2017\n\n*Quote of the Day*: \"I don't want to require `MainAsync`. It sounds like mayonnaise-ink!\"\n\n## Agenda\n\n1. Default implementations for event accessors in interfaces\n2. Reabstraction in a class of default-implemented member\n3. `sealed override` with default implementations\n4. Use of `sealed` keyword for non-virtual interface members\n5. Implementing inaccessible interface members\n6. Implicitly implementing non-public interface members\n7. Not quite implementing a member\n8. asynchronous `Main`\n\n\n# Default implementations for event accessors in interfaces\n\nToday, syntactically, either both or neither accessor can have an implementation.\n\nShould we allow just one to be specified? Overridden?\n\n## Conclusion\nIf you have only one, you probably have a bug. Let's not allow it for now.\n\n\n# Reabstraction in a class of default-implemented member\n\nShould an abstract class be allowed to implicitly implement an interface member with an abstract member, even when the interface member has a default implementation?\n\n## Conclusion\n\nYes, of course. Adding a body to an interface member declaration shouldn't ever break an implementing class.\n\n\n# `sealed override` for default implementations\n\nShould it be allowed? would it prevent overrides in *classes* or only in *interfaces*?\n\nIt seems odd to prevent either. Also, it is weird in connection with diamond inheritance: what if one branch is sealed?\n\n## Conclusion\n\nLet's not allowed `sealed` on overrides in interfaces. The only use of `sealed` on interface members is to make them non-virtual in their initial declaration.\n\n\n# Use of `sealed` keyword for non-virtual interface members\n\nSome folks find it a weird use of `sealed`, and that they look too much like things that can be implemented in classes.\n\n## Conclusion\n\nWe think non-virtual members in interfaces are going to be useful, but will come back to the syntax. This is a mental model tripping block.\n\n\n# Implementing inaccessible interface members\n\nThe way the runtime works today, a class member can happily implement an interface member that isn't accessible! That's not likely to be depended on today (no language will generate that interface), but we need to decide what semantics to have here.\n\nWe could continue to only have *public* members in interfaces be virtual. But if we want protected, internal and private, we should probably have it so they can only be implemented by classes that can see them. But this means that interfaces can *prevent* other assemblies from implementing them! This may be a nice feature - it allows closed sets of implementations.\n\n## Conclusion\n\nThis is still open, but our current stake in the ground is we should *allow* non-public virtual interface members, but *disallow* overriding or implementing them in places where they are not accessible.\n\n\n# Implicitly implementing non-public interface members\n\nWould we allow non-public interface members to be implemented implicitly? If so, what is required of the accessibility of the implementing method? Some options:\n\n* Must be public\n* Must be the exact same accessibility\n* Must be at least as accessible\n\n## Conclusion\n\nFor now, let's simply not allow it. Only public interface members can be implicitly implemented (and only by public members). We can relax as we think through it.\n\n\n# Not quite implementing a member\n\nYou have a member and you implement an interface. The interface adds a new member with a default implementation, that looks like your method but doesn't *quite* make it an implementation. Bug? Intentional? We can't provide a warning, because it would assume it was a bug.\n\n## Conclusion\n\nCan't do anything about this.\n\n\n# asynchronous `Main`\n\nWe've decided to allow a `Main` method that returns `Task` and `Task<int>`. Whether it's `async` or not is completely optional, and an implementation detail of the method.\n\nThis feature relies on the pattern of calling `GetAwaiter().GetResult()` on the returned task, and on an expectation that this call blocks until the task is complete. That is the case for the framework's implementations of `Task` and `Task<T>`.\n\nWhat if someone uses an alternative implementation? We can't prevent that. They either know what they are doing, or they are asking for it.\n\nWhat about other awaitable types? Should they be allowed? This would be easy enough to implement; the concern is whether it is reasonable to expect their `GetResult()` method to block? After all, the compiler has not previously relied on this in its use of `GetResult()` on awaitable types, so one would assume that no particular effort has been put into ensuring it in the implementation of those types.\n\nIf we don't allow other awaitables in `Main` directly, folks can easily work around it just by having an `async Task Main` that awaits it:\n\n``` c#\nstatic MyTask MyMain() { ... }\nstatic async Task Main() => await MyMain(); // problem solved\n```\n\n## Conclusion\n\nLet's still keep the `async` keyword optional.\n\nLet's stick with the name `Main` instead of `MainAsync` for now.\n\nLet's stick to `Task` and `Task<T>`, but refine the rule:\n\n1. Look for `Main()` or `Main(string[] args)`\n2. Does exactly one return `void` or `int`? If one, use that. If more, error.\n3. Otherwise, look for `Task` and `Task<T>`, where the return type of `GetAwaiter().GetResult()` is `int` or `void`."
  },
  {
    "path": "meetings/2017/LDM-2017-04-19.md",
    "content": "# C# Language Design Notes for Apr 19, 2017\n\n*Quote of the day*: \"I'm not thrilled with the decision, but it was a constrained call\"\n\n## Agenda\n\n1. Improved best common type\n2. Diamonds with classes\n3. Structs and default implementations\n4. Base invocation\n\n\n# Improved best common type\n\n``` c#\nb ? null : 7 // should be int? not error\n```\n\nThis is a small, isolated change that leads to a nice improvement. Let's do it!\n\n\n# Diamonds with classes\n\nA class implementation of an interface member should always win over a default implementation in an interface, even if it is inherited from a base class. Default implementations are always a fallback only for when the class does not have any implementation of the member at all.\n\n\n# Structs and default implementations\n\nIt is very hard to use default implementations from structs without boxing. In general, the only way to use interface methods on a struct without copying or boxing is through generics and ref parameters:\n\n``` c#\npublic static void Increment<T>(ref T t) where T : I => t.Increment();\n```\n\nBut for default implementations, even that won't necessarily avoid boxing! What is the type of `this` in the default implementation of `I.Increment`? If it's `I`, then `this` is a boxed form of the struct! We can avoid that by having an implicit type parameter, a \"this type\", which is constrained by `I`. But then, what is the name of that implicit type parameter in the body? If it doesn't have a name, you can't use it in the body. If it does have a name, what is the syntax for that?\n\nFor inherited members on structs today, they do in fact get boxed, but it is never observable - because the behavior of those three methods (`ToString`, etc.) doesn't mutate, or otherwise reveal the boxing.\n\nWhat can we do?\n1. *Forbid structs to make use of default implementations*: Can't do that. Now adding a new interface member with a default implementation would break implementing structs.\n2. *Come up with some code gen strategy like implicit this types*: Pushes the problem elsewhere, at a high cost and with a high risk that you box later anyway.\n3. *Don't worry about it, and leave it as a wart in the language*: It looks like a cop out, but there really doesn't seem to be a good alternative. C# already has places where structs and interfaces behave weirdly together; this just adds to the pile.\n\n## Conclusion\n\nLet's stick with option 3. It would be a breaking change to do 2 later, so we can never change it.\n\n\n# Base invocation\n\nWhat should be the syntax for base invocation? Some candidates:\n\n``` c#\nI.base.M()\nbase(I).M()\nbase<I>.M()\n```\n\n`base(I)` is the winner. It reads like `default(T)`, and seems the best fit.\n\nShould these be permitted in classes too, to specify base interface implementations? Yes. Otherwise the diamond problem isn't solved.\n\nWe could actually expand it to work *on* classes too, to allow a more distant base implementation to be called. Let's decide that later.\n\nIn an interface, can I say `base(IA)` that isn't a *direct* base interface? Yes.\n\nIn a class, can I say `base(IA)` that isn't a *direct* base interface? Yes."
  },
  {
    "path": "meetings/2017/LDM-2017-05-16.md",
    "content": "# C# Language Design Notes for May 16, 2017\n\n## Agenda\n\n1. Triage C# 7.1 features that didn't make it\n2. Look at C# 7.2 features\n3. GitHub procedure around new design notes and proposals\n4. Triage of championed features\n\n\n# Triage C# 7.1 features that didn't make it\n\n## Private protected\n\nAlmost there, push to 7.2 for completion.\n\n## Field-targeted attributes\n\nThis is a bug fix level change, and very useful. Push to 7.2\n\n\n# Look at C# 7.2 features\n\n\"Slicing\" needs to be split into \"ref structs\" and \"slicing syntax\".\n\nPush out everything, except \n- things that are \"in theme\" - related to refs, spans, etc.\n- things that are almost done (field-targeted attributes, private protected)\n\nKeep everything that's in theme until we can sit with the `Span<T>` folks and prioritize.\n\n\n# GitHub procedure around new design notes and proposals\n\nWe should use issues as a notification mechanism for when design notes and proposals are completed. Revisions are comments on the same issue.\n\n(This has now been adopted for design notes back to Mar 15, 2017.)\n\n\n# Triage of championed features\n\n## CallerArgumentExpression\n\nPush to 7.X and start process for getting the attribute in place.\n\n## Leading and trailing digit \"separators\"\n\n``` c#\nM(0b_1, 0x_A)\n```\n\nVery low additional value. Would probably help some code generators, and some code layout. Might accept a pull request.\n\n## Static delegates\n\nDelegates require, generally, 2 allocations, and are crappy for interop. Static delegates are typed `IntPtr`s, essentially.\n`ValueAction` and `ValueFunc`. Lot of asks from CoreRT, for PInvoke etc. Of course they won't be able to close over anything, so they'd require significant language support.\n\n## Namespace XML doc comments\nThis is hard to take as a community contribution: it's primarily about the IDE behavior. Not all of that may even be open source today.\nIt would also affect the rest of the ecosystem, which would now have to handle it. Need to coordinate with IDE team.\n\n## `??` and `?.` for pointers\n\nProbably lo-pri to make this pleasant. But nothing against it. This seems suitable for up-for-grabs.\n\nThe syntax should probably be `?->`. For double pointers, you're out of options!\n\n\n## Non-trailing named arguments\n\nHelps selectively use parameter names for readability. Would relieve people from bending over backwards to put name-prone parameters last. Also would make it work better with params.\n\nWould need some ide work.\n\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-05-17.md",
    "content": "# C# Language Design Notes for May 17, 2017\n\n## Agenda\n\nMore questions about default interface member implementations\n\n1. Conflicting override of default implementations\n2. Can the Main entry point method be in an interface?\n3. Static constructors in interfaces?\n4. Virtual properties with private accessors\n5. Does an override introduce a member?\n6. Parameter names\n\n# Conflicting override of default implementations\n\nIf at runtimes you have ambiguous overrides:\n\n``` c#\ninterface I1 { void M1(); }\n\ninterface I2 : I1 { override void M1() { ... } } \n\ninterface I3 : I1 { override void M1() { ... } } \n\nclass C : I2, I3 {} // what happens when you load?\n\nC x;\nx.M1(); // what happens when you call?\n```\n\nThis can happen without compiler complaint through certain orders of compilation.\n\nOptions:\n1. throw on load\n2. throw on call (like Java)\n3. pick arbitrarily (but consistently)\n4. bake in what you meant at compile time\n\t1. always use the baked in one, error if it's gone\n\t2. pick the unique one, fallback to baked-in if unsuccessful\n\nBaking in causes a lot to hinge on recompilation. We should leave to the runtime to resolve the virtual call. So not 4. Also, 1 seems too harsh. If you don't call it, why complain? If you call an arbitrary method, that's a little dangerous: you can't reason about what the program does.\n\n## Conclusion\nOption 2 it is. We can throw. If we realize we were wrong about this later, we can move from there. No bake in.\n\n\n# Can the Main entry point method be in an interface?\nYes. No good reason why not. Also, that's the least work.\n\n\n# Static constructors in interfaces?\nProbably, but let the runtime folks think about this. Reason is static fields. We could allow initializers for static fields, but not an explicit static constructor. Can think about adding later.\n\n\n# Virtual properties with private accessors\nIn classes you can define a virtual property with private accessor. Allowed in interfaces? What does it mean? Probably disallow.\n\n\n# Does an override introduce a member?\n\n- Does it introduce parameter names?\n- Does it introduce a new virtual method that could be implemented independently\n\nIf the call site sees two separately declared methods, that's already an ambiguity.\n\n``` c#\ninterface I1 { void M1(); }\n\ninterface I2 { void M1() { ... } }\n\ninterface I3 : I1, I2 { override void M1() { ... } }\n\nI3 x;\nx.M1();\n```\n\nShould `I3` be allowed? Does it override both?\nShould `x.M1()`;\n\nExplicit override syntax removes the problem, but do we want to force people to always put the interface in front?\n\nJava's solution does not help us, because independently declared interface members unify in Java.\n\nXamarin does not expect to need override. They'll just need to know whether there is a default implementation or not. They will need reflection support to query the default methods.\n\nIt's not an option to depend on order.\n\n## Conclusion\n`I3` is fine, but does not introduce a new member. So the call to `M1` is ambiguous. The work-around is to cast to one of the interfaces. However, oddly, you *can* call it through `base(I3)`.\n\n\n# Parameter names\n\n``` c#\ninterface I1 { void M1(int a); }\n\ninterface I2 : I1 { override void M1(int b); } // allowed to change parameter names?\n\nI2 x;\nx.M(a: 3); // allowed?\nx.M(b: 4); // allowed?\n```\n\nThe class behavior is to pick the most specific names, but that does mean that introducing an override (with different parameter names) can be a breaking change. But we could issue guidance to not change names in this situation.\n\nFrom experience, people do intentionally change names on override, but others ask for features to prevent them from doing it!\n\nCommon scenario is implementing a generic instance. Going from `T` to `Dog`.\n\n## Conclusion\nLet's take the names from the original declaration, deliberately being inconsistent with the class rule for simplicity's sake.\n\nNew open question: what about `base(I2)` and parameter names?"
  },
  {
    "path": "meetings/2017/LDM-2017-05-26.md",
    "content": "# C# Language Design Notes for May 26, 2017\n\n## Agenda\n\n1. Native ints\n\n# Native ints\n\nWe would like to supply high-quality native-size integers. The best we have today is `IntPtr`, which lacks most operators and have a few behavioral weaknesses, including a suboptimal `ToString` implementation. Xamarin has introduced user-defined `nint` and `nuint` types for interop, but those can't completely do the trick; for instance, user-defined operators cannot distinguish between checked and unchecked contexts.\n\nOptions:\n\n1. Improve `IntPtr` with operators\n2. Add `nint` and `nuint` as a user defined struct (the Xamarin approach)\n3. Add `nint` and `nuint` to the language\n\t1. compile down to `IntPtr` and add an attribute to persist the additional type info in metadata\n\t2. project language-level types to new user defined structs\n4. A combo of 1 and 3\n\n`IntPtr` has a few operators today; for instance `+` with `int` (which is checked on 32 bit and unchecked on 64 bit!), and some conversions.\n\nThe new structs in 3.2 look something like this:\n\n``` c#\nstruct NativeInt \n{ \n\tpublic IntPtr Value;\n\tpublic override string ToString() { ... }\n}\n/// etc\n```\n\nBut operators are implemented by the language, not as user-defined operators.\n\nThe difference between 3.1 and 3.2 is that with 3.2 at runtime we have different types, so we can have differentiated runtime behavior: `ToString` and reflection can tell them apart.\n\nA downside is that operations that take `ref IntPtr` (like `Interlocked.CompareExchange`) wouldn't automatically take `ref nint`. Having the public mutable field would let things still work for people, and we could go through and add `nint` overloads over time to make it better.\n\nThis should be in mscorlib, but that takes time. Is there anything we can do to mitigate in the meantime? We could ship a nuget package etc, but there's some cost to that, including indefinite maintenance. But some of the people who would benefit from this will be in a terrible spot if we don't provide something. \n\nWe also need to deal with native float. There is no option to do 3.1 for floats; there is no `IntPtr` equivalent. So that one would need a framework type. However, we could probably live with that `nfloat` struct moving into the frameworks over time - other than Xamarin, which would add it faster for its interop scenarios.\n\nWith 3.1, if you consume a `nint`-attributed `IntPtr` with an old compiler, would it treat it as an `intPtr`? If that's the case then the code would subtly change behavior on compiler upgrade. Unfortunate! We could perhaps poison `nint` with `ModReq` so that they cannot be consumed by existing compilers, but now `nint` really *is* a different type, and requires separate overloads of methods that take it as a parameter.\n\nAnother option is to obsolete the user-defined operators on `IntPtr`, to drive people to use `nint` instead.\n\n## Objections to 3.2:\n- Adoption, where a separate struct would take a while to propagate (we feel we've mostly mitigated this)\n- We'll emit slightly less efficient and more verbose IL in a couple of cases\n- Needing new overloads for `nint` where there are `IntPtr` overloads today (or at least a conversion, and new overloads where there are `ref IntPtr` parameters).\n\nObjection to 3.1:\n- No runtime distinction (reflection and `ToString`)\n- `ToString` happens all the time\n\n## Conclusion\nWe're torn, and evenly balanced on preferring 3.1 vs 3.2. Could maybe be convinced to 3.2 if we can solve how do existing users of `IntPtr` migrate.\n\n\n\n\n\n\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-05-31.md",
    "content": "# C# Language Design Notes for May 31, 2017\n\n## Agenda\n\n1. Default interface members: overriding or implementing?\n2. Downlevel poisoning of ref readonly in signatures\n3. Extension methods with ref this and generics\n4. Default in operators\n\n\n# Default interface members: overriding or implementing?\n\nSo far, when a derived interface wants to provide a default implementation for a member declared by a base interface, we have been thinking of it by analogy with overriding of virtual methods in classes, even using the `override` keyword:\n\n``` c#\ninterface I1\n{\n\tvoid M1();\n}\n\ninterface I2 : I1\n{\n\toverride void M1() { ... }\n}\n```\n\nThis design philosophy forces us to grapple with a lot of stuff from classes that may not be very useful.\n\nImplementing on the other hand is different. You don't have to match accessibility, etc. You can implement multiple interface members with one class member. A base class can highjack an implementation from an interface:\n\n``` c#\nclass C1\n{\n\tpublic void M1() { ... }\n}\n\nclass C2 : C1, I2\n{\n\t// class wins\n}\n```\n\nMaybe we should try to stay true to the notion of *implementing* when it comes to default interface members. So \"overriding\" should instead be expressed as an explicit interface member implementation:\n\n``` c#\ninterface I2 : I1\n{\n\tvoid I1.M1 { ... }\n}\n```\n\nThis seems to have more of an \"interface camp\" feel to it: it is more similar to what you can do with interface members today, only you can now do it in interfaces.\n\nWe like this approach! Let's investigate some of its consequences.\n\n## \"Base calls\" to default interface implementations\n\nWith the \"explicit implementation\" approach above, how do you *call* the implementation from another one? Well you have that problem today: you *cannot* directly call an explicit implementation today; not even from within the implementing class itself.\n\nHowever, for default interface implementations that's a significant reduction in expressiveness. You'd have to do so via a non-virtual helper method. So the implementation has to anticipate needing to be reused and factor out to a helper method.\n\nFor instance, when you do an \"implement interface\" refactoring, what does it do? Leave out already implemented ones? implement them again with a call to `base` (if that's possible)? With a `throw`?\n\nWon't it be common to want to reuse a default implementation, adding \"just a little bit more\", i.e., calling `base`? Well, that gets into an accessibility game: the accessibility for ultimate use, versus the accessibility for being non-virtually called as `base`. \n\n## Ambiguity of base calls\n\nIf we allow base calls to default implementations, there are two different kinds of ambiguities.\n\nAmbiguity of declaration:\n\n``` c#\ninterface I1 { void M() { ... } }\ninterface I2 { void M() { ... } }\ninterface I3 : I1, I2 { void N() { base.M(); } } // which declaration of M()?\n```\n\nAmbiguity of implementation:\n\n``` c#\ninterface I1 { void M(); }\ninterface I2: I1 { void I1.M() { ... } }\ninterface I3: I1 { void I1.M() { ... } }\ninterface I4: I2, I3 { void N() { base.M(); } } // which implementation of M()?\n```\n\nYou need to get into weird-ish stuff like this:\n\n``` c#\nbase(I3).(I1.M1)<string>(1, 2, 3); // Call I3's implementation of I1's M1\n```\n\nIf we want to do something like this, we would also consider allowing *classes* to pick which one they grab the implementation from: even though classes have no ambiguity about which is the most *specific* override, you could potentially allow \"reaching around\" and grabbing an older one.\n\n## Deimplementation\n\nWhen we were on the `override` plan, we intended to allow \"reabstraction\", where an interface could `override` a base method to *not* have an implementation.\n\nIn this new scheme, should we allow \"deimplementation\" - the ability for an interface to say that an inherited member does *not* have a default implementation, contrary to what a base interface said?\n\nThe meaning would be \"I declare that the default implementation is not useful (or is harmful) to classes implementing me.\"\n\nThis would probably be rare. People can implement to throw an exception instead.\n\n## Conclusion\n\nStrangely this approach moves the design closer to its intended purpose. It keeps it about implementation, without mixing inheritance into it.\n\nIt does mean you have to type the interface name every time you want to provide a new implementation for a base interface member. Should we have a shorthand for when the interface name is unambiguous and obvious? No. We haven't needed it for explicit implementation in classes, we probably don't need it now.\n\nLet's think about whether we can live entirely without base calls to default implementations, and come back to this when we've mulled it a bit.\n\n\n# Downlevel poisoning of ref readonly in signatures\n\nWe currently poison with a `modreq` all the places in signatures where unaware compilers could do something unsafe (write into read-only memory) by using a `ref readonly` as if it was a mutable `ref`.\n\n`Modreq`s aren't very discerning, so a virtual method cannot even be called by unaware compilers, even when only overriding is unsafe. We accept this degree of granularity as the best possible state of affairs.\n\nThe only role of the `modreq` is to poison unaware compilers. The actual information about read-only-ness of refs is carried in attributes. Should we reject methods that have the attributes but not the `modreq`? It makes it harder to relax it later. But it protects the contract from manual finagling. So yes, refuse to consume such methods.\n\nIt's hard for us to add a new modifier. We may have to reuse one. If we had our own, we could avoid using attributes altogether, just make it modopt or modreq depending on whether it is required for safety. Let's keep this idea around, in case we do get to have our own.\n\n\n# Extension methods with ref this and generics\n\nExtension methods will be allowed to take value types by `ref` or `ref readonly`. It doesn't make sense for reference types, so those are disallowed. However, what about unconstrained (or interface constrained) type parameters? \n\nShould we allow so as to get the benefit when a type argument happens to be a value type? Probably not. \n\n- For mutable ref it seems a little dangerous and surprising that an extension method can modify a variable of reference type\n- For readonly ref, chances are it would lead to much unintended copying, as the readonly-ness would cause the value to get copied whenever you tried to do something useful with it in the body (e.g. based on an interface constraint).\n\n## Conclusion\nDon't allow.\n\n\n# Default in operators\n\n`default` as an operand to unary or binary operators would sometimes work, and sometimes not, depending on whether there happens to be a best operator across all available predefined or user-defined ones for all types:\n\n``` c#\n        var a = default + default;  // error\n        var b = default - default;  // ok\n        var c = default * default;  // ok\n        var d = default / default;  // error\n```\n\nThis feels arbitrary. But worse, it is actually a recipe for future compat disasters. Imagine we added a `-` operator to, say, arrays in the future. Now the second line above would break, because the `int` overload of the pre-defined `-` operator would no longer happen to be best.\n\n## Conclusion\nDon't allow `default` as an operand to a unary or binary operator. We need to protect the ability to add new operator overloads in the future.\n"
  },
  {
    "path": "meetings/2017/LDM-2017-06-13.md",
    "content": "# C# Language Design Notes for Jun 13, 2017\n\n## Agenda\n\n1. Native-size ints\n2. Native-size floats\n\n\n# Native-size ints\n\nWe want `nint` and `nuint` to be part of the language. They will be used in contexts where we care about respecting checked vs unchecked in operator behavior, for example.\n\nWe have two options for how to represent at runtime:\n\n1. Project to `IntPtr`, track the `nint` or `nuint` \"overlay\" in metadata for compile-time consumption only\n2. Project to new struct types that wrap an `IntPtr` and potentially exhibit different behavior at runtime too\n\nOption 2 had some objections attached. Let's go through them:\n\n- Adoption/roll out of new types would take time\n\t- We could embed these struct types in the generated assembly and use the NoPIA machinery to unify them across assemblies.\n- Would have a slight cost on IL size. \n\t- Probably not a decisive objection\n- Need new overloads for a few things, such as `Interlocked.CompareExchange`\n\t- We could probably live with those rolling out gradually, especially with access to the `IntPtr` of a `nint` or `nuint` as a public field (so it can be passed by `ref` to existing overloads)\n- There is a bifurcation because the types are really distinct at runtime. There's interop pain between them.\n\t- This may be a good thing. Arguably they represent different concepts: `IntPtr` is more of an opaque handle, whereas `nint` and `nuint` are real integers with number semantics.\n\nOption 1 has some objections as well:\n\n- `ToString` doesn't work right\n\t- This could probably be fixed. It is unlikely that the current deficiencies are depended upon\n- you lose context on box/unbox\n\t- That is already the case today with other common types, such as tuples, nullable value types and `dynamic`. Is it really so bad?\n- Imprecise reflection info\n\t- Again, we live with this in many places\n\n`String.Format` would exhibit the combination of the first and second problem: passing a `nint` as an argument, it would box and lose context, so `IntPtr.ToString` would get called.\n\nThings to ponder regardless of implementation strategy:\n\n- **Conversions:** Should there be conversions between `nint`/`nuint` and `IntPtr`? If so, which way (if any) should be implicit?\n- **Upgrade:** Someone using `IntPtr` today might want to switch to `nint`. This would mostly just work, but would have very subtle changes of behavior here and there.\n\n## Conclusion\nWe are still hung on what to do. We want to more deeply understand objections against Option 1, and understand if mitigations considered would address e.g. Xamarin's concerns.\n\n\n# Native-size floats\n\nFloat really is a different discussion. Language embedding is less significant: we don't have a notion of checked/unchecked. The main objective would just be to have an alias."
  },
  {
    "path": "meetings/2017/LDM-2017-06-14.md",
    "content": "# C# Language Design Notes for Jun 14, 2017\n\n## Agenda\n\nSeveral issues related to default implementations of interface members\n\n1. Virtual properties with private accessors\n2. Requiring interfaces to have a most specific implementation of all members\n3. Member declaration syntax revisited\n4. Base calls\n\n# Virtual properties with private accessors\n\nClasses (strangely) allow virtual properties with one accessor being private. Should interfaces allow something similar?\n\n## Conclusion\n\nNo. It is not obvious what it means, or whether it's in any way useful.\n\n\n# Requiring interfaces to have a most specific implementation of all members\n\nShould it be an error for an interface to not have a single most specific implementation if each member (even inherited) that has default implementations?\n\n## Conclusion\n\nThis might be desirable if we were designing the language from scratch, but it would be breaking, since existing compilers wouldn't know to check that. Also, there'd be no way to fix it if they could.\n\nSo we cannot disallow this. The buck stops with the implementing class, which is the one that has to implement any interface member that doesn't have a unique most specific default implementation.\n\nThis does allow you to \"reabstract\" a default-implemented member by injecting a diamond situation and forcing a class level error, but so be it.\n\n\n# Member declaration syntax revisited\n\nIn a [previous meeting](https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-05-31.md) we changed the syntax around \"overriding\" of default implementations to match that of explicit implementation in classes today.\n\nThis topic explores whether we have the right syntax when declaring an interface member and giving it a default implementation *at the same time*.\n\nToday the syntax for this and an overriding implementation is simply:\n\n``` c#\ninterface I1\n{\n    int M(int i, bool b, string s) { return s?.Length ?? i; }\n}\n\ninterface I2 : I1\n{\n    int I1.M(int i, bool b, string s) { return b ? i : s?.Length ?? 0; }\n}\n```\n\nOr, if we use expression bodies:\n\n``` c#\ninterface I1\n{\n    int M(int i, bool b, string s) => s?.Length ?? i;\n}\n\ninterface I2 : I1\n{\n    int I1.M(int i, bool b, string s) => b ? i : s?.Length ?? 0;\n}\n```\n\nThe declaration syntax in `I1` has both pros and cons. One the one hand:\n\n- It is simply what you get if you take today's interface member declaration syntax and add a body\n- It looks similar to a class member that might implicitly implement an interface member\n\nOn the other:\n\n- It looks exactly like a non-virtual class member, which cannot be overridden/reimplemented by anything else\n- It's odd why the implementation in `I2` needs to look like an explicit implementation (`I1.M`) when one that's immediately declared does not\n\nOne could argue that the current syntax should be reserved for the same meaning that it has in classes: a non-virtual member. But either way leads to confusion and surprise for some:\n\n- I \"simply\" add a body to an interface member, and all of a sudden it is no longer implementable by classes or derived interfaces!\n- I \"simply\" copy a nonvirtual member from a class to an interface, and all of a sudden it is re-implementable by classes and derived interfaces!\n\nWe need to decide which side of this conundrum to land on. If we *were* to change the meaning of\n\n``` c#\n    int M(int i, bool b, string s) => s?.Length ?? i;\n```\n\nto be \"nonvirtual\" member what *would* an implementable interface member with a default implementation look like instead? Let's explore some options:\n\n## Proposal 0\n\nStatus quo. Non-virtual members are explicitly annotated with `sealed`, which isn't great, but we can live with it. \n\n## Proposal 1\n\nMake a separate declaration that uses the same \"explicit implementation\" syntax as in the derived classes:\n\n``` c#\ninterface I1\n{\n    int M(int i, bool b, string s); // declares the member\n \tint I1.M(int i, bool b, string s) => s?.Length ?? i; // provides a default implementation\n}\n\ninterface I2 : I1\n{\n    int I1.M(int i, bool b, string s) => b ? i : s?.Length ?? 0; // no change\n}\n```\n\nThis is probably the most hideous and verbose option we can come up with. But points for consistency!\n\n## Proposal 2\n\nUse a `default` keyword as a modifier to signal that a default implementation is provided:\n\n``` c#\ninterface I1\n{\n    default int M(int i, bool b, string s) => s?.Length ?? i;\n}\n```\n\n`default` may or may not be allowed and/or required on a derived implementation as well:\n\n``` c#\ninterface I2 : I1\n{\n    default int I1.M(int i, bool b, string s) => b ? i : s?.Length ?? 0;\n}\n```\n\nWe don't hate this option, but it may be a bit too much syntax \"just for the benefit of first timers\".\n\nIt signals: \"I am not really implementing it here; I'm providing a default!\" That may allay the sense that interfaces are becoming too much like classes.\n\n## Proposal 3\n\nSame as 2, but with the `virtual` keyword instead:\n\n``` c#\ninterface I1\n{\n    virtual int M(int i, bool b, string s) => s?.Length ?? i;\n}\n```\n\n`virtual` may or may not be allowed and/or required on a derived implementation as well:\n\n``` c#\ninterface I2 : I1\n{\n    virtual int I1.M(int i, bool b, string s) => b ? i : s?.Length ?? 0;\n}\n```\n\nThis feels like we're going back towards virtual methods in classes in a way we don't want to. Also, it anything it should probably then be `override` and not `virtual` on the derived implementation, but now we're just going in circles.\n\n## Additional consideration\n\nIf we ever want to allow implementable static members in interfaces (that are required to be provided by implementing classes), then the syntactic choices we make here will potentially come back to bite us. \n\n## Conclusion\n\nWe don't like Option 3, and we hate Option 1. We're not totally averse to Option 2, but for now we'll keep the status quo, which seems to have the least syntax for the most common tasks.\n\n\n# Base calls\n\nWe pondered briefly whether we could live without the ability to call default implementations directly, just as you cannot call an explicit implementation today. However, we think that we do need to allow it. A particularly strong example is when you have ambiguous default implementations from different base interfaces. How do you pick one if you cannot call it?\n\n## Disambiguation\n\nThere are two ways in which a base call to a default implementation can be ambiguous:\n\n- **Implementation ambiguity:** For a given original declaration, there may be two base interfaces both inheriting that declaration and providing competing implementations for it. Which one did you want to call?\n- **Declaration ambiguity:** There may be two base interfaces that happen to declare members of the same signature. Which one did you mean?\n\nWe can think of disambiguating syntax for both:\n\n- `base(I1).M`: I want `I1`'s implementation of `M`\n- `base.(I1.M)`: I want my `base`'s implementation of the `M` that was declared in `I1`\n- `base(I3).(I1.M)`: I want `I3`'s implementation of the `M`  that was declared in `I1`\n\nHowever we think that implementation ambiguity is going to be common, and declaration ambiguity is more esoteric. We are happy to add disambiguation syntax only for implementations for now.\n\n## Aside: Name disambiguation \n\nThere's an interesting and more general feature waiting for another time in the ability to disambiguate a member *name* by where it's declared, as in `e.(I1.M)`. This could be used to get at hidden members or implemented interface members without casting, etc. But let's save that for another day.\n\n## Syntax\n\nAs for the implementation disambiguation, we have three proposals on the table:\n\n``` c#\nbase(T) // 1\nbase<T> // 2\nT.base  // 3\n```\n\nWe don't like 3 at all (even though that's essentially Java's syntax for it). We have some sympathy for 2, but it looks like there's generics involved, and there's not. We like 1 the best. It is reminiscent of other places in the language where a keyword is followed by a type in parentheses:\n\n``` c#\ntypeof(T)\ndefault(T)\nsizeof(T)\n```\n\n\n## Semantics\nWhen you access a base implementation with the syntax `base(T)`, the meaning is \"get the implementation of the member from `T`\". This should at least work when `T` is an interface (but we are also interested in making it work for classes, letting you skip to an earlier base).\n\nIt is a compile time error if there is no default implementation of the member in `T`. If there is, that implementation is called directly. At runtime, if the implementation is no longer there, it is probably not worth it to try to walk the graph and find another one: we should just throw at this point.\n\nThese semantics mean that you can get in trouble if you rearrange your default implementations and don't recompile things that depend on you. So be it.\n\n## Unqualified base\n\n`base` *without* a type should also be allowed for default implementations, as long as it is unambiguous. It means the same as `base(T)` where `T` is the interface that has the unique most specific default implementation at the time where the `base` access is compiled.\n\n## Conclusion\n`base` and `base(T)` will be allowed to access default implementations in interfaces, both from derived interfaces and implementing classes. They are compiled to directly call the implementation in the interface they (implicitly or explicitly) designate.\n\nIt is worth pondering whether this is all too \"static\". It is not enlisting the runtime as much as perhaps it could, meaning that more specific default implementations could be ignored if they weren't known when the calling code was compiled. It is, however, equivalent to what we do with base calls in classes today. And it avoids a whole class of problems and error modes, because the compiler hardwires its choice of implementation into the code.\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-06-27.md",
    "content": "# C# Language Design Notes for Jun 27, 2017\n\n*Quotes of the day:*\n> \"Let's support most operators, but not equal and not-equal\"\n\n> \"We'll rename the next version to C# l'eight\"\n\n## Agenda\n\n1. User-defined operators in interfaces\n2. return/break/continue as expressions\n\n\n# User-defined operators in interfaces\n\n## Conversion operators\n\nLet's not allow conversion operators in interfaces, since they are not allowed *on* interfaces today, even when defined elsewhere.\n\n## Equality operators\n\nThere'd be no way to override `Equals` and `GetHashCode`, so you couldn't do `==` and `!=` in a recommended way. That's an argument for disallowing. What if we *did* allow `Equals` and `GetHashCode` to be overridden in interfaces? That would be a major undertaking, for what seems like modest gains.\n\nHowever, if we allow `<=` and `>=` you can get the effect of `==` anyway, through `&`. This may or may not be an argument for disallowing *more* - or maybe all - operators.\n\nSome options:\n\n1. Drop operators across the board\n2. Let's not allow `==` and `!=` and see what feedback we get\n3. Let's allow `==` and `!=` and see what people use it for\n\n### Conclusion\nLet's stick with option 2 for now. We'll see from prototype use whether this is an intolerable limitation, but we believe it is a decent place to land.\n\n\n## Is the remainder worthwhile?\n\nConversion and equality are the most useful operators, in that they apply to any domain, whereas most of the other operators are for more specific, often math-related, purposes. If we don't allow them, is it worth allowing the rest?\n\n### Conclusion\nLet's assume that it is. Those specific domains are likely still important to express in interfaces.\n\n\n## Lookup rules for operators\n\nWe only even look for operator implementations in interfaces if one of the operands has a type that is an interface or a type parameter with a non-empty effective base interface list.\n\n### Unary operators\nThe applicable operators from classes/structs shadow those in interfaces. This matters for constrained type parameters: the effective base class can shadow operators from effective base interfaces.\n\n### Binary operators\nHere there could be operators declared in interfaces that are more specific than ones implemented in classes.\n\nWe should look at operators from classes first, in order to avoid breaking changes. Only if there are no applicable user-defined operators from classes will we look in interfaces. If there aren't any there either, we go to built-ins.\n\nWe hypothesize that there's no case (outside of equality and conversion) where user-defined operators in interfaces shadow predefined operators, but we may be wrong. So that needs to be investigated a bit.\n\n\n## Shadowing within interfaces\n\nIf we find an applicable candidate in an interface, that candidate shadows all applicable operators in base interfaces: we stop looking. This is a bit more complicated than in classes, where it's linear, but we can express it right.\n\n\n# return/break/continue as expressions\n\nIt's been proposed to allow `return`, `break` and `continue` as expressions, the same way we now allow `throw` expressions.\n\nThere's a bigger discussion of whether we should seek to make C# more expression-oriented, adding a \"value\" (or at least a classification) for each statement kind, and allowing all or most statements in an expression context. However, this specific proposal does not need to be part of that discussion: we already have `throw` expressions, and the potential value of adding these other *jump-statement*s can be evaluated in that narrower context.\n\nThere are clearly scenarios that can be expressed more concisely with this feature, but the really compelling ones involve the use of `??` on nullable value types (and presumably on nullable reference types in the future). It provides an elegant way to get at the underlying type without having to more explicitly unpack it:\n\n``` c#\nint z = x + y ?? return null; // where x and y are of type int?\n\n//as opposed to something like\nif (x is null || y is null) return null;\nint z = (x + y).Value; // explicit unpacking\n\n// or\nint? nz = x + y;\nif (nz is null) return null;\nint z = nz ?? 0; // dummy unpacking\n\n// or using patterns\nif (!(x + y is int z)) return null;\n```\n\nThe scenarios involving the ternary conditional operator seem less compelling, as they are more easily replaced by a \"bouncer\" if-statement:\n\n``` c#\naccumulator += (y != 0) ? x/y : continue;\n\n// as opposed to\nif (y == 0) continue;\naccumulator += x/y;\n```\n\nYes, it's more concise, but is it more clear?\n\n`break` and `continue` differ from `throw` in that the latter just gets out of there, whereas these affect definite assignment more subtly and locally.\n`return` feels more like `throw`, in that it leaves the whole call context. However, unlike `throw` it is normal control flow.\n\nThere's something unfortunate about calls like these:\n\n``` c#\nM(Foo1(), Foo2() ?? break, int.TryParse(s, out int x) ? x * 10 : continue);\n```\n\nYou start computing arguments and then you decide not to do the call. Wouldn't it have been better (at least more efficient) to decide before starting to compute the arguments? Maybe, but that also leads to more ceremony and less locality of the code. \n\n## Conclusion\nWe are somewhat compelled by the `??` examples. They really do read better than using patterns for nullable things. \n\nLet's have someone champion it, and keep it on the radar.\n\n\n\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-06-28.md",
    "content": "# C# Language Design Notes for Jun 28, 2017\n\n## Agenda\n1. Tuple name round-tripping between C# 6.0 and C# 7.0\n2. Deconstruction without `ValueTuple`\n3. Non-trailing named arguments\n\n\n# Tuple name round-tripping between C# 6.0 and C# 7.0\n\nThere are a few unintended breaking changes with tuples that came out through real use cases.\n\nSay there's an interface `IUtil`:\n\n``` c#\npublic interface IUtil\n{\n    void M((int a, int b) x);\n}\n```\n\nI want to implement this interface with code that works both in C# 6.0, but it turns out I can't! In C# 7.0 we force you to use the same tuple element names when you implement an interface member, but of course you can't do that (and aren't being forced to) in C# 6.0, where your only option is to use `ValueTuple<...>` directly.\n\nMaybe using the `TupleName` attribute directly in C# 6.0 would help? It is hard to use, but it turns out VS 2015 happily inserts it for you to match the attribute found on the interface member. Little does it know that this attribute is about to become compiler-reserved in C# 7.0, and if you try to compile the C# 6.0 compliant implementation with the attribute in C# 7.0, it still fails, now complaining that you cannot use that attribute in source code!\n\nThere are no less than two breaking changes here, so we'll address them one at a time:\n\n## Issue 1: C# 6.0 has to implement it without names, but C# 7.0 requires names\n\nThis will not do. We need to relax the rules in C# 7.0 to allow for a C# 6.0 implementation to continue compiling.\n\nA couple of reasonable options:\n- a tuple type *without* names can always be given when one *with* names is required (but one with different names cannot)\n- you are permitted to omit required names only if you use the `ValueTuple<...>` syntax, not with tuple syntax\n\nThe latter is attractive in that it pushes things to a corner, but it does break the fact that `ValueTuple<int, string>` is exactly equivalent to `(int, string)` in all scenarios.\n\nIt also has a bit of a problem in establishing whether the tuple syntax *was* used:\n\n``` c#\nitf I {\n\tvoid M((int a, int b) x);\n}\n\ncls Base {\n\tpublic void M((int, int) y);\n}\n\n// Separate assembly\ncls Derived, I {} // how does it know which syntax Base used?\n```\n\n### Conclusion\nLet's go with a strict version of the former option: If a member has *any* tuple element names in it, and is required to match another member (by overriding or implementing), then *all* required tuple element names have to be matched. Only a member declaration with *no* tuple element names in it  can override or implement a member in which tuple element names are found, without matching those names.\n\n## Issue 2: VS 2015 Implement Interface will explicitly spit the attributes, but C# 7.0 doesn't allow them\n\nThis would have been a problem with `dynamic` too, but we never really heard of it. Maybe there was less usage, more of a gap between framework version, or the impact was less because we didn't have round tripping back then. For whatever reason, this never seemed to be a problem before.\n\nOptions:\n\n- Keep the attribute usage an error\n- Allow it but ignore it\n\t- possibly with a warning when tuple syntax is used\n\n\n### Conclusion\nKeep it an error, willing to take it up again if necessary. We are unsure that this is really a problem.\n\nFor the future we want to get better at marking attributes as compiler-only in a well-known way, so that they won't be put in source code even by older compilers. One option is to do that using `Obsolete`; then no compiler will allow them in source, but will be happy to detect or emit them in metadata.\n\n\n# Deconstruction without ValueTuple\n\nDeconstructing assignments are expressions, and their value is a tuple. This is natural from a language perspective, even though the result value of assignments is rarely used, and we expect this goes for deconstructing assignments as well.\n\nUnfortunately, even in the common case where the assignment occurs as an expression statement (so the resulting tuple is discarded), the compiler currently still requires the associated `ValueTuple<...>` type to be present. That means you have the hassle of importing `ValueTuple` even when you never use a tuple - if you happen to make use of deconstruction.\n\n## Conclusion\nWe'll rewrite the compiler to be more lazy about `ValueTuple<...>`, requiring it only when it actually needs it for code gen.\n\n\n# Non-trailing named arguments\n\nIt looks like this is making it into C# 7.2. The basic idea is that we allow named arguments *that are in their place, positionally* to be followed by positional arguments. This is mainly for the self-documenting convenience of calling out the meaning of a positional argument where it is non-obvious in the calling context. However, it can be useful for disambiguation of overloads also.\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-07-05.md",
    "content": "# C# Language Design Notes for Jul 5, 2017\n\n## Agenda\n\nTriage of features in the C# 7.2 milestone. They don't all fit: which should be dropped, which should be kept, and which should be pushed out?\n\n1. Static delegates *(8.0)*\n2. Native int and IntPtr operators *(7.X)*\n3. Field target *(anytime)*\n4. Utf8 strings *(8.0)*\n5. Slicing *(7.X)*\n6. Blittable *(7.2)*\n7. Ref structs *(7.2)*\n8. Ref readonly *(7.2)*\n9. Conditional ref *(7.2)*\n10. Ref extensions on structs *(7.2)*\n11. Readonly locals and params *(X.X)*\n12. ref structs in tuples *(don't)*\n13. Overload resolution tie breakers with long tuples *(use underlying generics)*\n\n\n# Static delegates\nWon't have time, and should probably be in a major release. \n\n## Conclusion\n8.0 for now.\n\n\n# Native int and IntPtr operators\nThis won't make 7.2. \n\n## Conclusion\nLet's try to keep in 7 wave as 7.X (in case we have more point releases) . Probably only one of these will become a feature, but keeping both for now until we decide.\n\n\n# Field target\nBug fix, do this anytime. \n\n## Conclusion\nMake sure it is on the Roslyn backlog.\n\n\n# Utf8 strings\nThere's a bigger story that needs to be worked out here. There needs to be decisions around interpolated strings, formattable strings etc. This feels low on the list, and we don't have enough data to design it yet. \n\n## Conclusion\nNext major release: 8.0.\n\n\n# Slicing\nWe would want to add a `Range` type, a syntax `3..5` to create a `Range` and then people can write indexers over ranges to implement slicing.\n\nWe could make it an entirely target-typed thing, where something with a proper constructor could be initialized with a span. Lots to think about.\n\nEither way, `Span<T>` APIs would eventually want to make use of this, but would not depend on it from the outset.\n\n## Conclusion\nThis won't make 7.2 but keeping it 7.X to keep thinking about it.\n\n\n# Blittable\nSmall language feature, useful for certain scenarios but not central to 7.2 value proposition. \n\n## Conclusion\nLet's do it if we get to it. Keep it 7.2, but low pri for that release.\n\n\n# Ref structs\nEssential to the scenario and also almost done. \n\nStill need `stackalloc` rules worked out. We'd prefer to keep that part of the functionality in, but could delay it if necessary.\n\n## Conclusion\nStay in 7.2.\n\n\n# Ref readonly\nEssential to the scenario and pretty much done.\n\n## Conclusion\nKeep in 7.2.\n\n\n# Conditional ref\nNot essential but already done.\n\n## Conclusion\nKeep in 7.2.\n\n\n# Ref extensions on structs\nNot essential but already done.\n\n## Conclusion\nKeep in 7.2.\n\n\n# Readonly locals and params\nStands on its own. It has some commonality with 7.2 scenarios, but is not essentially tied. Could be done together with ref readonly locals later. Also it has a lot of design work still to be done. \n\n## Conclusion\nPush to X.X.\n\n\n# ref structs in tuples\nTuples can't contain ref structs because those can't be type arguments. \n\n## Conclusion\nThat's a big pandora's box to open, and we won't.\n\n\n# Overload resolution tie breakers with long tuples\nThere's an esoteric difference between whether \"specificity\" tie breaker should special case long tuple as a flat list, or should work according to the underlying generics, which are nested.\n\n## Conclusion\nWe stick with how it works now, which is the underlying generics.\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-07-26.md",
    "content": "# C# Language Design Notes for Jul 24 and 26, 2017\n\n## Agenda\n\nWe started putting a series of stakes in the ground for nullable reference types, based on the evolving strawman proposal [here](https://github.com/dotnet/csharplang/issues/790). We're doing our first implementation of the feature based on this, and can then refine as we learn things from usage.\n\n1. Goals\n2. Nullable reference types\n3. Rarely-null members\n\n\n# Goals\n\nThe goals make sense.\n\n## Goal 3: Incrementality\n\nAre our existing mechanisms good enough, or is more needed? Currently the proposal has an in-language approach to gradualness, where it mainly comes from the gradual addition of `?`s where nullability is intended, and dealing with the fallout of those one by one. We'll go in on the assumption that this is incremental enough, but trying the feature out may prove us wrong.\n\n\n## Goal 4: No semantic impact\n\nShould this only yield warnings, or should some of them be errors? It should at least be configurable, and we can change our mind about the default settings.\n\nIf they are errors *in the language*, that affects overload resolution. \"Warn as errors\" is better because it doesn't affect overload resolution.\n\nThere may be an opportunity for optimizations based on the compiler's reasoning about nullability; however it would be hampered by all the places where we aren't 100% sure. Worth looking into at some point.\n\n## Goal 5: Library upgrades\n\nShould libraries continue to do null checks?\n\nGood question. We can't really trust our callers to not pass null. But maybe we can slide more in the direction of just letting the method body fail however it may, if people violate the contract, not checking at every boundary. The Midori experience was that this doesn't make a huge impact to performance, so it might not be worth changing guidelines away from explicit null checks.\n\nIt's very similar to when we added iterators. Some people will want to have a very high bar, others may be able to relax.\n\nWe have an accompanying feature proposal (not yet in the strawman) for a short hand null checking syntax for parameters:\n\n``` c#\npublic void M(string name!) { ... }\n\n// equivalent to\npublic void M(string name)\n{\n    if (name is null) throw new ArgumentNullException(nameof(name));\n    ...\n}\n```\n\n# Nullable reference types\n\nThe strawman proposes an always-on, non-breaking nullable reference types feature, where a postfix `?` annotation on reference types leads to warnings if values thereof are dereferenced directly or indirectly without (what the compiler recognizes as) a null check.\n\n## Warning on conversion\n\nA key point of the proposal is that it mandates a warning on conversion from nullable to not-nullable reference type. This even though there is nothing wrong with having null in not-nullable reference types *until* you opt in to not-null checks.\n\nThis may seem controversial or overly aggressive, but we ended up approving it for a couple of reasons:\n\n- If nullable reference types are to protect their values from being dereferenced even indirectly, they can only do so by warning when you take those values out of the nullable space. \n- This leads to better incrementality, because you get these warnings piecemeal every time you add a `?`, instead of in a flood when you turn on non-null checks.\n- These warnings aren't breaking. There's no reason to protect a feature behind a switch if it isn't breaking.\n\n## Tracked variables\n\nThe strawman allows the null state of dotted chains `x.y.z` to be tracked by the flow analysis. Is this too lax? Imagine an await in the middle. There would absolutely be cases where this would lead us to consider code null safe even when there's a null at runtime.\n\nWe're assuming people are already checking for null, and are trying to help find where they forgot. We are *not* trying to add new idioms and features, we are trying to lower the bar for getting people to where the warnings they get are useful.\n\nStake in the ground: we will allow dotted chains. We may want to offer suggestions here, or a knob of aggression. \n \n## Local variable declarations\n\nThe strawman proposes that we make a sort of exception for local variable declarations. There'll be a lot of local variable declarations in existing code using an explicit type (which in existing code never has a `?` on it). Their use of it may be completely null safe, but when something they get assigned gets a nullable annotations, those assignments would still generate a warning.\n\nThe concern is that such warnings will drown out warnings about actual null-unsafe code:\n\n``` c#\nvoid M(string s);\n\nM(p.MiddleName);\nstring s = p.MiddleName; // warning here\nM(s); // but the problem is really here\n```\n\nThe strawman therefore proposes to *infer* the nullability of a local variable *even* when it is declared with an explicit type.\n\nWe ended up not agreeing to this. There's a worry about whether people understand the feature if type declarations mean different things in locals versus members.\n\nThe proposal is too preemptive. We're assuming people will be put off by warnings on this, but is it that bad? The cure may be worse than the disease. When people do not use `var` it is because they *want* to be explicit about the type, and inferring part of it anyway rubs right against that.\n\nInstead we will try to mitigate the \"drowning out\" by having \"fix all\" options in the IDE, etc.\n\n## Cross-assembly\n\nDo we need per-assembly granularity? Concern: heading towards too much complexity.\n\nStake in the ground:\n\n- Assemblies opt in with an attribute to having annotations. By default (no attribute) they don't. By default, however, the new compiler will put the attribute.\n- You can opt out per assembly if you don't want their annotations heeded.\n\n\n# Rarely-null members\n\nThe compiler code base has a property (`BoundExpression.Type`) that's non-null in 95% of the cases. In a few places under very specific and well-defined circumstances it is allowed to be null.\n\nWhat's the guidance for this kind of property?\n\nFor this kind of member you want the burden to be put on the few, not the many. It should be declared as not null, and the few places that will use it as null anyway should explicitly circumvent the annotation. Those places are no worse off than today, and are in fact helped a little bit by warnings reminding them to circumvent the non-nullness (e.g. with a `!` operator).\n\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-08-07.md",
    "content": "# C# Language Design Notes for Aug 7, 2017\n\n## Agenda\n\nWe continued refining the nullable reference types feature set with the aim of producing a public prototype for experimentation and learning.\n\n1. Warnings\n2. Local variables revisited\n3. Opt-in mechanisms\n\n\n# Warnings\n\nThe nullable features lead to three distinct kinds of warnings:\n\n1. *Direct dereference* of nullable values\n2. *Indirect dereference* of nullable values - conversion to not-nullable\n3. *Not-nullable is non-null* - Conversion of null value to not-nullable type\n\nExamples:\n\n``` c#\nstring s = ...;\nstring? n = ...;\n\nvar l = n.Length; // Warning 1: Direct dereference\ns = n;            // Warning 2: Indirect dereference\ns = null;         // Warning 3: null conversion\n```\n\nThe design decisions in the following influence which of these warnings need to be on by default.\n\nThere are two dual viewpoints on the value of these warnings:\n\n- Warning on assignment of null is the most important part of the feature, because that's how null values get in there in the first place. (This is true on API boundaries)\n- Warning of dereference is the most important part of the feature, because that's what protects you from null reference exceptions. (This is true in code bodies)\n\nThe fact is that both kinds are important, and go hand in hand in protecting against null reference exceptions.\n\n\n# Local variables revisited\n\nThe current plan of record is that nullability annotations (`string` vs `string?`) matter just the same in local variable declarations as elsewhere.\n\n``` c#\nclass C\n{\n    public static string  S { get; } // won't be null\n    public static string? N { get; } // might be null\n\n    public void M()\n    {\n        int l;\n\n        string s; // won't be null\n        s = C.S; // ok\n        s = C.N; // warning 2: Indirect dereference\n        s = null; // warning 3: null conversion\n        l = s.Length; // ok\n        l = (s != null) ? s.length : 0; // ok\n\n        string? n; // might be null\n        n = C.S; // ok\n        n = C.N; // ok\n        n = null; // ok\n        l = n.Length; // warning 1: Direct dereference\n        l = (n != null) ? n.length : 0; // ok\n    }\n}\n```\n\nWith this approach, like everywhere else, unannotated local variables are non-null, and are protected by warnings from having null assigned to them, as where warning 2 and 3 are given above. `?`-annotated locals on the other hand are subjected to a flow-analysis, and if this shows them to potentially be null at a particular point in the code, a warning is given on dereference, as with warning 1 above.\n\nThis causes a problem with existing code. Since the `?` annotation wasn't previously available in C#, many local variables that *are* supposed to be null will not have it in their declaration. Their subsequent use may be completely safe (i.e. have null checks everywhere necessary), but with the advent of nullability checking we'd still be bothering the developer with warning 2 (as soon as `C.N` has gotten a `?` of its own) and 3 above.\n\nAn alternative proposal is to make all locals (of reference type) nullable, regardless of their annotation. There'd be no notion of preventing locals from assuming a null value. Instead, they would all be uniformly protected by flow analysis. Thus, the `s` part of the above code would act as follows:\n\n``` c#\n        string s; // might be null\n        s = C.S; // ok\n        s = C.N; // ok\n        s = null; // ok\n        l = s.Length; // warning 1: Direct dereference\n        l = (s != null) ? s.length : 0; // ok\n```\n\nThat is, identical to the `n` code above.\n\nThe upside of this approach is that you would get no \"cosmetic\" warnings when the nullable feature is turned on and used; i.e. no flood of warnings telling you to add `?` to a bunch of perfectly safe locals.\n\nThe downside of course is that locals would be treated completely differently from all other declarations in the language. It might be very confusing to read and maintain the code.\n\nUnlike the current plan, this would require all of the warnings 1-3 to be opt-in, as there would be nullable things in code even without any explicit `?`s. The current plan at least has a hope of letting warnings 1-2 be always on for source code (since only new code introduces nullable types). This may or may not be important.\n\n## Conclusion\n\nWe do recognize the problem that the alternative approach sets out to solve. However, we believe that locals should be consistent with other declarations, and that code is better off getting fixed up to reflect nullability in local variable declarations. Explicitly typed locals should declare their intent the same way other declarations do.\n\nThere are mitigations:\n- People who use `var` won't have this problem, as the nullability flows with the type.\n- We can do a lot with \"fix all\" style tooling to help you quickly fix all local declarations that e.g. are initialized with a nullable expression.\n\nAlso, if the \"cosmetic\" warnings get too noisy during upgrades to use the feature, there may be some version of the alternative approach available as an intermediate setting.\n\nLet's get a public prototype out. It is fine (maybe actually great) if it's configurable, but should have a default according to where the LDM is trending. It would be nice to have some of the tooling as well (\"fix all\"), because that's part of the experience we are comparing.\n\n\n# Opt-in mechanisms\n\nThere are various parts of the nullable reference types feature set that lead to new warnings on existing code:\n\n- Assignment of `null` to unannotated reference types is perfectly allowed today: `string s = null;`\n- Libraries with `?` annotations (which would be compiler-encoded into attributes in the assembly) may be used via older compilers that don't recognize the annotations, then all of a sudden would take effect when upgrading to C# 8.0.\n\nIn addition, libraries should be encouraged to add annotations to new versions, and upgrading to those versions would yield new warnings.\n\nOn the whole, all these new warnings are a good thing, and in a sense the purpose of the feature. However, there needs to be *some* way to avoid them, so that they don't constitute a breaking change that requires existing code to be edited in order to get clean.\n\nWe've been discussing the various upgrade scenarios and possible kinds and granularities of opt-in mechanisms to help the developers achieve a smooth upgrade at their own pace. However, these mechanisms come with their own complexities, and we need to decide which ones are worth that.\n\n## Opt-in for all new nullable warnings\n\nThis is the notion that there's one big switch on the compiler. If it's on, you get all nullable warnings on your code, if its off you get none. You can leave it off forever if you're just in maintenance mode. You can repeatedly turn it on, fix up some stuff, then turn it back off until your code is properly null-annotated and your null-reference-exception bugs have been fixed.\n\nTypeScript took this approach when adding nullable types and the accompanying checks. When on, it means that all existing libraries are seen as non-nullable on all input and output, regardless of whether that's what they intended. This sounds quite unfortunate on the face of it, but has actually proven a lot less of a problem than anticipated: preventing people from passing null to an API is most often the right thing, occasionally unnecessary but benign, and rarely actually limiting to the use of the API. In those cases you can work around it - in C# that would be with use of the postfix `!` operator to shut up the warning.\n\nSo there's at least an argument to be made that this is \"good enough\", and it has a lot going for it in terms of simplicity!\n\n## Per-reference opt-in\n\nThis approach lets the client of a library decide whether to \"see\" its nullability warnings or not. This might be useful when\n\n- A new version of a library adds annotations, but the client isn't ready to deal with them yet\n- The client upgrades to C# 8.0 and discovers annotations in libraries they were already using, but aren't ready to deal with the warnings yet\n- The library has not been annotated, and the client experience of treating the library as all non-null is too frustrating\n\nThis is expected to come with heavy tooling costs, because we need to wire through UI to turn null warnings on and off for each referenced assembly, add support in config files, etc. But it gives the client great control over what they would like to be bothered with right now.\n\n## Library self-opt-in\n\nThis approach lets the library express, through attributes, whether to consider its unannotated types non-nullable. The default would be no, so that an existing nullability-unaware library would continue working as it does today, i.e. lead to no warnings.\n\nWe sometimes call this option \"URTANN\" because the meaning of the attribute is \"**U**nannotated **R**eference **T**ypes **A**re **N**on-**N**ullable\".\n\nThe attribute could be used at the assembly level, but you can also imagine making it more granular, using it to mark parts of the code that \"have been annotated\". The client's compiler would then emit warnings only when nulls are passed to the URTANN-marked unannotated parameters.\n\nIn this way, the approach becomes a poor man's version of the feature design that has separate syntaxes for \"non-null\" (`string!`) and \"oblivious\" (`string`). We decided not to go that syntactic route (for good reasons described elsewhere!), but this would allow close-to-similar expressiveness on API boundaries using an extralingual mechanism (attributes) rather than syntax.\n\nA problem with this approach is that it's not clear what code means. Am I currently under URTANN? I'd have to look around and make sure. Also, if highly granular application is allowed, it may be tempting to leave libraries half-annotated in some complicated pattern.\n\nAnother issue is that this would make it impossible for a client to interpret existing (unannotated) libraries as all-non-null, even when that would be the best thing to do.\n\nBut it does provide a potentially very granular mechanism for a library to express its own intent, nullability-wise.\n\n## Conclusion\n\nWe're imagining all kinds of ways the user could get screwed by this feature, and coming up with opt-ins/opt-outs to mitigate. But we don't actually know if it's all that bad, and if those mechanisms are worth the complexity that they add.\n\nWhat we'll do for now is to have only \"big switch\" feature opt-in in the prototype. We'll use that to learn what scenarios are painful enough that we should reach back into our catalogue of opt-in ideas and try one out."
  },
  {
    "path": "meetings/2017/LDM-2017-08-09.md",
    "content": "# C# Language Design Notes for Aug 9, 2017\n\n## Agenda\n\nWe discussed how nullable reference types should work in a number of different situations.\n\n1. Default expressions\n2. Array creation\n3. Struct fields\n4. Unconstrained type parameters\n\n\n# Default expressions\n\nThere's an argument to be made that `default(string)` should have the type `string?`. After all, we know it is going to produce a null value! On the other hand, there's also an argument that `default(T)` should produce a `T` for any `T`, and even that `default(string)` is just bad practice, that should be warned on. After all, it's very much like saying `(string)null`, which *would* get a warning.\n\n## Conclusion\n\nIn keeping with the resolution to the local variables question from [Monday's meeting](https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-08-07.md), we hold to an emerging principle that *\"the type you say is the type you get\"*. That means that `default(string)` should have the type `string`. We should probably also warn on it, since we *are* producing a null value of a non-nullable type. The fix for the warning is to put a `?` on the type (if you want it nullable), or use a `!` (if you don't).\n\nIt is not clear that `default(string)!` would actually silence the warning. After all it is the `default(string)` expression itself that causes the warning, not a conversion of it. For `!` to work here, we would probably need to special case it. \n\nFor the new target-typed version of the `default` expression, it would simply work the same way as a `null` literal: if the target type is a nonnullable reference type we'll warn, unless there's a trailing `!`.\n\n\n# Array creation\n\nSimilar to default expressions there's an argument (but weaker) that `new string[10]` should have the type `string?[]`. After all, it produces an array full of nulls! On the other hand there's also an argument that `new T[10]` should continue to produce a `T[]` for any `T`, and maybe even (somewhat more weakly) that `new string[10]` is just bad practice that should be warned on.\n\n## Conclusion\n\nIn keeping with the resolution for default expressions above, array creation expressions should have the type they say they create: `new string[10]` creates a `string[]`.\n\nIt's more open whether it should produce a warning. If it doesn't, then arrays leave a gaping hope in the \"null protection\" story: you can say `(new string[10])[0].Length` and get a null reference exception without a warning. There is no way that we can establish reliably that a given new `string[]` is initialized to all non-nulls, and it is not clear that this would always be desirable. Many safe uses of `string[]` would simply keep track of which elements have been assigned (with non-null strings) at a given time, and only allow access to those.\n\nIf we do warn on array creation, that's going to hit every single array creation expression today, except when the element type is a value type. That seems harsh! On the other hand, it gives the developer *somewhere* to realize that there's danger, and that they may want to consider an array with nullable elements. How to silence the warning if not? Maybe you can apply `!` to the array creation expression. Again, this is a more general version of `!` that applies not just to the nullability of the value itself (the array), but also types that it is constructed from. Thus, `new string[10]!` would suppress the warning.\n\nWe are going to adopt the warning for now in the prototype, since we believe we'll learn more from it. However, we are not very confident that this warning will stay on by default. It may also be one of those warnings that's better served by a standalone analyzer for folks who want to be stricter (maybe combined with some attempts to track initialization), or at least have its own opt-in in the compiler.\n\n\n# Struct fields\n\nWe've been saying that we want to warn when non-nullable reference fields are not initialized by a constructor. \n\n``` c#\nclass C\n{\n\tstring s1;\n    string s2 = \"Hello\";\n    string s3; // warning: not initialized to non-null value\n    public C(string s) => s1 = s;\n}\n```\n\nHowever, all structs can occur uninitialized, with default values in all fields. Does that mean it should be a warning for a struct to have *any* fields of non-nullable reference type?\n\n``` c#\nstruct S\n{\n    public string s; // warn anyway?\n    public S(string s) => this.s = s;\n}\n\nS[] a = ...; // array of uninitialized S's\nvar l = a[0].s.Length; // null reference exception\n```\n\nThis would lead to a *lot* of warnings in existing source code! It feels similar to the array warning, in that it would invalidate the *only* way of doing things in pre-C# 8.0 code. Unlike the array situation, however, there is no way to silence the warning with a `!` to say \"I know what I'm doing!\"\n\nWe did not decide what to do here.\n\n\n# Unconstrained generics\n\nUnconstrained type parameters should be allowed to take nullable type arguments. Even though we've previously said that \"unconstrained\" is the same as \"constrained to `object`\", we should now say that it's the same as \"constrained to `object?`\".\n\nThis leads to type parameters `T` where *we don't know* if they are nullable reference types or not. Thus, we have to exercise caution and apply warnings \"from both sides\": on the one hand they may be null, so we should warn on unguarded reference. On the other, they may *not* be nullable, so we should warn on things that might make them null.\n\nOf course, you cannot assign `null` to an unconstrained type parameter today (it might be instantiated with a value type), but there are still default expressions:\n\n``` c#\nT M<T>()\n{\n\treturn default(T); // warning\n\treturn default;    // warning\n}\n```\n\nNow this is a problem: default expressions were added to the language *specifically* so you could use them in a generic setting! And now we would say you cannot use them? That seems harsh! Of course you can silence them every time you use them, but that's a nuisance.\n\n*Not* having a warning would be a hole. We could consider it anyway (as we might for `new string[]`), and just say that this sacrifices safety for convenience.\n\nAnother option is to come up with a new type constructor over T that means \"nullable if reference type\". We could overload the postfix `?` if it's not too confusing. so `T?` on an unconstrained generic type would mean:\n\n- `V` if `T` is a value type `V` (either nullable or nonnullable)\n- `N` if `T` is a nullable reference type `N`\n- `C?` if `T` is a nonnullable reference type `C`\n\nIt's a little subtle, and has some weird consequences, especially if we use the `T?` syntax, since it wouldn't *always* be a nullable type:\n\n``` c#\nvoid M<T>()\n{\n    T? t = null; // would be an error!\n}\n```\n\nAlso `T?` would mean different things depending on whether `T` has a `struct` constraint or not:\n\n``` c#\nT? M1<T>(T t) => t;\nT? M2<T>(T t) where T : struct => t;\n\nvar i1 = M1(1); // 'int'\nvar i2 = M2(2); // 'int?'\n```\n\nThis is quite confusing, but might just speak to having another syntax than `T?`. On the other hand, that's *yet* another syntax, and extra complexity in the language.\n\nIt's worth noting that `T?` would be useful as the return type of `FirstOrDefault` and its brethren among the query operators, which otherwise wouldn't have a good way of expressing their signature. That would at least address *one* of a handful of patterns that aren't well served by nullable reference types as currently proposed.\n\nWe didn't reach a verdict on this topic. \n "
  },
  {
    "path": "meetings/2017/LDM-2017-08-14.md",
    "content": "# C# Language Design Notes for Aug 14, 2017\n\n## Agenda\n\nWe looked at the interaction between generics and nullable reference types\n\n1. Unconstrained type parameters\n2. Nullable constraints\n3. Conversions between constructed types\n\n\n# Unconstrained type parameters\n\nUnconstrained type parameters should allow nullable reference types as type arguments. One way to look at it is that the default constraint is no longer `object` but `object?`. This is important, so that existing unconstrained generic types work with nullable reference types; e.g. `List<string?>`.\n\nThis means that the body of a generic type or method has to deal with type parameters that can be instantiated with both nullable and nonnullable reference types. To be safe, it must impose both nullable and non-nullable restrictions:\n\n\n``` c#\nvar s = t.ToString(); // warning: dereference without null check\nT t = default(T); // warning: may be creating null value of non-nullable ref type\n```\n\n## Dereferencing\n\nThe rules around dereferencing values of unconstrained generic type should be no different than for nullable reference types: The compiler needs to see you check for null, or else you get a warning.\n\nThis is not likely to happen a lot, as there aren't that many members available on unconstrained type parameters; only the `object` ones.\n\n## Default expressions\n\n`default(T)` is of type `T`, and in and of itself yields a warning, because it may create a null value of a non-nullable type. This is just like `default(string)`, as per previous meeting's decisions.\n\nHow can you fix this warning? Well there are no super good options. After all, you are writing code that will create a null value of a non-nullable type. We should make sure that e.g. the `!` operator is capable of silencing the warning:\n``` c#\nT t = default(T)!; // if that's allowed, or some version of it\nT t = default!;    // if that's allowed\n```\n\n## Defaultable types\n\nAnother option is to introduce a notion of \"defaultable types\" that can be applied to an unconstrained type parameter. For all type arguments it means the type itself, except for non-nullable reference types, where it is the nullable counterpart. We may want to overload the `?` syntax for it:\n\n``` c#\nT? t = default(T?); // if that's allowed\n```\n\nWith the decisions above, this is more of a \"side feature\", and doesn't impose itself on users who don't ask for it. This may be important, as it is on the complex side. The previous notes had examples of some confusing aspects of this type constructor.\n\nThis feature would also be useful to express patterns of the `FirstOrDefault` ilk:\n\n``` c#\nT? FirstOrDefault<T>(this IEnumerable<T> src)\n```\n\nSimilarly, we can imagine someone out there who wants to express occasional APIs that take null as an argument, even when their type argument does not allow it. You may have a more local contract that allows null even when the overall type or generic context does not.\n\nLet's embrace `T?` in the prototype and look out for confusion, usage, implementation issues, etc.\n\nSomebody will need to work on type inference rules in the presence of `T?` in signatures.\n\n## TryGet\n\nIf we embrace defaultable `T?`, it would technically be a correct type for the out parameter of `TryGet` methods:\n\n``` c#\nbool TryGet(out T? value); // correct, but weak\n```\n\nIt's probably not useful, though. Consumers only very occasionally look at the output when the result is fall. The majority, instead, would be annoyed that they cannot assume the value is non-null when they checked the bool and found it to be true.\n\nLet's put off decisions around this for a bit. There should probably be a special mechanism for this scenario.\n\n\n# Nullable constraints\n\nRegardless of whether we allow nullable reference constraints explicitly, they will exist anyway:\n\n- unconstrained type parameters are like having the `object?` constraint\n- inherited constraints on overrides may implicitly be nullable\n\nSo we might as well embrace nullable reference types as constraint. The rule is that if any constraint is non-nullable, then instantiations with nullable reference types yield warnings.\n\n## object as constraint\n\nCurrently `object` is disallowed as an explicit constraint, since it is implied. We should start allowing `object` as a constraint.\n\n## The class constraint\n\nShould the `class` constraint allow type arguments that are nullable reference types? If yes, how do you ask for only the non-nullable ones? If no, how do you allow the nullable ones?\n\nIt seems we have a couple of syntactic options:\n\n1. `class` allows nullable, `class, object` does not\n2. `class?` allows nullable, `class` does not\n3. `class` allows nullable, `class!` does not\n\nThe 3rd option adds new syntax that isn't warranted. The 1st option adds no new syntax, but it is tedious to specify a non-nullable reference constraint.\n\nThe 2nd option seems most in line with the general direction. However, there is a slight concern that people today might be using the `class` constraint *specifically* so that they can use `null`. All of those will have to add `?` to their `class` constraints.\n\nWe will still go with option 2 on general principle.\n\n\n# Conversions between constructed types\n\nThere's an identity conversion between constructed types that differ only in the nullness of their type arguments.\n\nBut sometimes there's a warning. When? How do you get rid of it?\n\n``` c#\nDictionary<string, string?> d = new Dictionary<string?, string>(); // warning in both directions\n```\n\nEssentially the rule is as follows:\n\n- Generally warn on non-matching nullability in both directions.\n- For covariant type parameters, don't warn going from `T` to `T?`\n- For contravariant type parameters, don't warn going from `T?` to `T`\n\nWe would like the `!` operator to be able to silence this, when there is an expression. An explicit cast should also work, but may \"do too much\".\n\nThis may be quite complex to implement in current compiler, but we think it is important and do want to push on it.\n"
  },
  {
    "path": "meetings/2017/LDM-2017-08-16.md",
    "content": "# C# Language Design Notes for Aug 16, 2017\n\n*Quote of the day:*\n> \"It's an open question whether we go out with a bang`!`\"\n\n## Agenda\n\n1. The null-forgiving operator\n\n\n# The null-forgiving operator\n\nHow exactly does the null-forgiving post-fix `!` operator work?\n\nProposal:\n\n1. *Target typed*: `e!` implicitly converts to `T` if `e` does, but without nullability warnings\n\t- `string s = null!;`\n\t- `string s = default!`\n\t- `string s = GetNameOrNull()!;`\n\t- `List<string> l = GetList<string?>()!;`\n\t- `List<string?> l = GetList<string>()!;`\n2. *Inherent type*: if the type of `e` is a nullable reference type `T?`, then the inherent type of `e!` is `T`\n\t- `var s = GetNameOrNull()!;`\n\t- `GetNameOrNull()!.Length;`\n3. *Default expressions*: if `T` is a non-nullable reference type, then `default(T)!` suppresses the warning normally given by `default(T)`\n\nFor 2, an alternative is to have a dedicated `!.` and `![...]` operator, cousins of `?.` and `?[...]`. Then you wouldn't get to factor out to a local with `var`, though.\n\n3 is a bit of a corner case. Most people would choose to just rewrite it to something else - there are plenty of options. But `default(T)` is a good strategy for code generators, so probably worth keeping the ability to silence that warning.\n\nWe could generalize `!` to silencing all nullability warnings even in subexpressions. This seems ill-motivated, though, and there's no particular expectation that you want silencing in subexpressions at the same time you want it on the overall expression.\n\nIf `!` is applied in a place that yields no nullability warnings, does that lead to a warning? No. We don't want to create a new source of warnings caused by a warning-suppressing operator! There is a legit scenario, which is to clean up superfluous \"!\"s when a depended-upon API gets properly annotated. But this seems more the province of analyzers or similar tools.\n\nWe can make `!!` an error. If you really want two consecutive bangs (we don't believe there's *any* scenario, other than swearing) you can parenthesize: `(e!)!`.\n\nAn alternative is to make the type of `e!` oblivious, if we choose to embrace a notion of oblivious. That's attractive in that it makes a type for \"something that doesn't yield warnings\", but it's also viral - could lead to many things not being checked. It's an option to be considered in future.\n\n## Conclusion\n\nFollow the proposal. Make `!!` an error."
  },
  {
    "path": "meetings/2017/LDM-2017-08-21.md",
    "content": "# C# Language Design for Aug 21, 2017\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n\n# Type classes\n\nMultiple implementations (ints and groups)\n- You can explicitly provide the type argument for an implicit type parameter\n- (but it might get messy)\n\n\nNeed explicit instance\n- Nothing fundamental preventing a more structural approach\n- Two levels of inference possible: \n\t- a: explicit instance, infer members\n\t- b: implicit instance even\n\n\nTo bridge to existing interface-based abstractions, you can just provide a very general, generic instance\n\n\nNeed an implicit type parameter but don't use it. Maybe a bit too magical. Might be better to require dotting off of the implicit type parameter. For operators that would be nice, though.\n\n\nInstance members? need some syntax like extension methods, maybe, or like explicit interface implementation.\n\n\nConcepts can be for more than one type, so they are not always tied to a single domain type. This may be a step too far, but it does have real value: Graph algorithms that have both Node and Edge types.\n\nMain competitor, conceptually, would be something that allows for interfaces to play the role of concepts. That comes with challenges of its own, and lots of limitations. But that sort of the thing you have to justify why you're not.\n\n\nCould you use this to make the environment of a lambda a struct? Combined with closures as structs, passed by ref.\n\n\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-08-23.md",
    "content": "# C# Language Design Notes for Aug 23, 2017\n\n## Agenda\n\nWe discussed various aspects of nullable reference types\n\n1. How does flow analysis silence the warning\n2. Problems with dotted names\n3. Type inference\n4. Structs with fields of non-nullable type\n\n\n# How does flow analysis silence the warning\n\nWhat exactly is the mechanism by which a nullable variable can be dereferenced without warning, when it's known not to be null?\n\n``` c#\nvoid M<T>(string? s, T t)\n{\n    if (s != null) WriteLine(s.Length);     // How is the warning silenced?\n    if (t != null) WriteLine(t.ToString()); // How is the warning silenced?\n}\n```\n\nSo far we've said that when a nullable variable is known to not be null, it's *value* is simply considered to be of the underlying nonnullable type. So for `s` in the above example, inside the `if` where it is tested, its value is of type `string`. Thus, the dereference does not earn a warning.\n\nHowever, this doesn't immediately work for type parameters. In the example above, we don't *know* that `T` is a nullable reference type, we just have to assume it. Therefore, it does not *have* an underlying nonnullable type. We could invent one, say `T!`, that means \"nonnull `T` if `T` was nullable\", but it starts to get complex.\n\nAn alternative mechanism is to say that the type of a variable and its value *does not change*. The null state tracking does not work through changing the type, but simply by directly silencing null warnings on \"dangerous\" operations.\n\nThis works for both `s` and `t` above. \n\nWith the new proposal, you can better imagine separating out the null warnings to an analyzer, because the type system understanding of the `?` would be logically separated from the flow analysis.\n\nIntelliSense will be a challenge:\n\n``` c#\nvoid M(string s) => ...;\n\nstring? s = \"Hello\";\n\nM(s); // Does IntelliSense confuse you here if the type of 's' is shown as 'string?' ?\n``` \n\nBut there's non-trivial experience work in the IDE no matter what we do.\n\n\n## Impact on type inference\n\n``` c#\nstring? n = \"Hello\";\nvar s = n; // 'string' or 'string?' ?\n```\n\nIf null state affects the type, then `s` above is of type `string`, because `n` is known to be non-null at the point of assignment. If not, then it is `string?` (but currently known not to be null).\n\nThis also affects which type is contributed to generic type inference:\n\n``` c#\nList<T> M<T>(T t) => new List<T>{ t };\n\nvoid N(string? s)\n{\n    if (s != null) WriteLine(M(s)[0].Length);     // 1\n    if (s != null) { var l = M(s); l.Add(null); } // 2\n}\n```\n\nIf the type of `s` changes to `string` in the non-null context, then the calls to `M` infer `T` to be `string`, and return `List<string>`. Thus, `//1` is fine, but `//2` yields a warning that `null` is being passed to a non-null type.\n\nConversely, if the type of `s` remains `string?` in a non-null context, then the calls to `M` infer `T` to be `string?`, and return `List<string?>`. Thus, `//2` is fine, but `//1` yields a warning about a possible null dereference.\n\n\n## Impact on `!` operator\n\nThe currently proposed `!` operator changes the type of a nullable value to a non-nullable one. The deeper philosophy behind this, though, is simply that `!` should do the same to the value of a variable (that is not target typed) as a non-null null-state would have done.\n\n``` c#\nstring? n = GetStringOrNull();\n\nvar l = n!.Length; // why no warning?\nvar s = n!;\n```\n\nWith the current proposal, `n!` would be of type `string`, and there'd be no warning on the dereference because of that. \n\nWith the new proposal, `n!` would be of type `string?`, but the `!` would itself silence the warning on dereference.\n\nIn a way the new proposal unifies the target-typed and non-target-typed meanings of `!`. It is never about changing the type of the expression, just about silencing null warnings.\n\nWe need to get more specific about exactly what it means that it \"silences the warnings\".\n\n## Conclusion\n\nLet's roll with the new approach. As always, we'll keep an eye on whether that leads to a good experience, and are willing to revisit.\n\n\n# Dotted names problems\n\nThere are different approaches with different safeties:\n\n- Don't track dotted names at all (safest): this pushes you to introduce a local for every null test of every field or property\n- Track dotted names but invalidate when prefix is \"manipulated\" (passed or called a method on): doesn't catch aliasing or indirect mutation\n- Track dotted names and assume it's still valid no matter how prefix is manipulated: bigger risk that it's wrong\n\nThe problem is that people have code today that checks on dotted names.\n\nShould we have a dial? Otherwise we need to decide how we weigh safety vs convenience.\n\n## Conclusion\nIn the prototype, since dotted names aren't implemented, let's try the more restrictive approach. People will let us know where this is too painful.\n\n\n# Type inference\n\nHow are nullable reference types inferred?\n\nProposal:\n\n- Consider nullness an orthogonal aspect to the rest of the type being inferred\n- If any contributing type is nullable, that should contribute nullness to the inference\n- A `null` literal expression should contribute nullness to the inference, even though it doesn't otherwise contribute to the type\n\nWe should consider this for nullable value types as well.\n\n\n# Structs with fields of non-nullable type\n\nStructs can be created without going through a declared constructor, all fields being set to their default value. If those fields are of non-nullable reference type, their default value will still be null!\n\nIt seems we can chase this in three ways:\n\n1. Not at all. We just aren't that ambitious.\n2. We warn on all fields of structs that have non-nullable reference types. That's a *lot*! How do you \"fix\" it? Make them nullable? No version of the `!` operator works here, since the whole point is you don't control initialization from user code.\n3. We warn whenever a struct that has such fields is created as a default value. In other words, we treat the type the same as a non-null reference type, recursively. (And we warn on passing for a type parameter constrained by `new()` or `struct`?)\n\n## Conclusion\nThe options to handle are painful. No conclusion.\n"
  },
  {
    "path": "meetings/2017/LDM-2017-08-28.md",
    "content": "# C# Language Design Notes for Aug 28, 2017\n\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n## Agenda\n\n\n# Ref-like types safety rules\n\nhttps://github.com/dotnet/csharplang/blob/master/proposals/span-safety.md#draft-language-specification\n\nThe need for ref-like types quickly arises, when you need to flow more than one span, etc.\n\nThe fact that span is array like is not very interesting for the safety rules. The interesting thing is that it embeds a reference. Indexing is not a core concern in the general case.\n\nOnce you can embed refs in struct, the question: How can you assign them?\n\nWith assignment, you can now assign to ref parameters of ref-like structs, so every assignment is a potential return.\n\n\"Let's not refer to local data\" does not work here:\n\n- we *want* the feature to refer to local data. stackalloc, etc.\n\t- lightweight params, etc.\n- we want to protect our future ability to allow this even if we could live with it now\n\nSo: We need to allow local data inside ref-like structs.\n\nWe tie a scope to variables holding ref-like structs. That scope is based on what the variable is initialized with. We call this the \"escape level\".\n\nEssentially, on the assignment we check that the assigned-to variable's scope is no wider than the assigned value's scope.\n\nThe rules assume that everyone plays by them.\n\n\nSpecial craziness for multiple arguments, some which are refs, some which are refs to ref-like:\n\n``` c#\nvoid M(ref Span<int> x, ref int y) \n{\n    // One of two things must be true about this:\n    //  1. This is an error\n    //  2. The caller has guaranteed this is safe\n    x = new Span<int>(ref y); \n}\n```\nWe need to do this on the caller, who knows most about the situation. The caller therefore has to assume that there is cross-assignment in the callee.\n\n\nQ: Could you track the escape level during flow analysis, changing it locally? It's possible we could, but it seems extremely complex. We propose strict rules now; a flow analysis later would be more permissive, if we can figure it out. That's an important property!\n\n\n\"ref safe to escape\" is how far you can escape the variable. \"safe to escape\" is how far you can escape a value. Only relevant if that value is a ref-like struct that can contain a ref.\n\nQuality of error messages: We'll do a decent job, but a) it rarely gets complicated/cascading, b) we can improve them later if they turn out not to be good enough. Rust has error messages about this kind of thing that are just stellar, but this is bread-and-butter code in Rust, whereas it's exceptional here.\n\nDefer: Should uninitialized ref-struct locals be allowed?\nDefer: Should default values of ref-struct types be allowed?\n\n\n\nMethods can return by-ref, ref-like and by-ref ref-like! We say that by-ref ref-like parameters are not returnable!\n\nOpen issue with ref dynamic: Treat them like in parameters, in how we deal with compiler-generated temps.\n\n\nLanguage restrictions:\n\n- Local functions - it's a shame that we can't factor out this stuff to local functions, because of the closure rule. But we can fix it later if necessary.\n\n\n\n \n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-08-30.md",
    "content": "# C# Language Design Notes for Aug 30, 2017\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n# IAsyncDisposable\n\n`IAsyncDisposable` is sort of required, due to the way we translate `foreach`. Also it's useful in a lot of situations.\n\nDon't take a `CancellationToken`, since when you cancel an operation you don't want to also cancel the clean-up.\n\nContract should be similar to `Dispose`, where you can call multiple times (sequentially) without problem.\n\nIf an enumerator (for instance) implements both sync and async, the client is only required to call one of them. The expansion of foreach will prefer sync or async naturally through the expansion.\n\nDoes the CT given to an enumerator apply during disposal? That would need to be up to the implementation. Standard guidance would be not to cancel any of what the disposal does. Advanced implementors might use the fact that the enumerator was canceled to skip some work.\n\n# Alternative IAsyncEnumerable pattern\n\nThere's an alternative that does \"explicit chunking\", by asynchronously yielding synchronous enumerables, to be consumed in a nested loop.\n\nTests show that this is a lot more efficient than the simple design. \n\nWe are cautiously leaning in this direction. As long as we can work out iterators, which are not fully explored.\n\n# ConfigureAwait\n\nCan use extension methods on IAE\n\n# foreach\n\nProposal to support foreach over enumera_tors_, not just enunera_bles_.\n\nShould enumerators be first class currency? There's a path we can take where everything is still enumerables, and you can get enumerables from other enumerables representing e.g. something with a CT, a certain starting point, etc. \n\nDownsides: If you're just foreaching over an enumerator, is it your responsibility to dispose it? Also, should LINQ then be implemented over those as well?\n\nLet's not open that Pandora's box for now. Let's stick with enumerable.\n\nConsider a ToEnumerable on enumerators.\n\n## Syntax options\n\nNeed to think about it in connection with `using` also.\n\nWe'll stick with `foreach await ( ... )` for now.\n\n## pattern-based\n\nSimilar to today. We get that one layer of optimization. There's more wrapping here (MoveNextAsync, WithCancellation), so we quickly still end up with interface dispatch.\n\n# iterators\n\nSame as current iterators, except with an `async` keyword, and IAsyncEnumerable/tor return type. Needs to feel exactly like putting iterators and async methods together.\n\nCould consider custom builders for this. Skip for now.\n\nIf we do the fancier version of IAE we need to find out how to compile. Need to spec the contract completely and then follow that. (Probably some sequences of calls would be unspecified).\n\n## Cancellation\n\nThere are two competing models around this.\n\n1. Take CT into GetEnumerator, and find a way to syntactically expose it in an iterator body\n2. Don't pass CT's into the enumerator at all; pass them to iterator methods\n\nWe actually want to start out with 2, and see if that gets us into trouble\n\n\n# LINQ\n\nThere are 200 overloads on enumerable, and most would need to be duplicated on IAE. Then, mixing sync and async would add another axis of this.\n\nIx has an implementation of these already, and they would adjust to what we decide.\n\nIf you have that, query expressions would work to some degree, when the bodies are sync.\n\nHowever, we don't currently allow `await` in query clauses, because the lambdas we target don't have the `async` modifier.\n\nFine to not do it now. At some point we would want to deeply investigate how to get those awaits in.\n\n\n\n\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-09-25.md",
    "content": "# C# Language Design Notes for Sep 25. 2017\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n# Ref readonly locals\n\nWe have nowhere to put a ref readonly result. Ref readonly locals are like ref locals, except that they don't allow mutation of the ref'ed variable.\n\n```\nvar x = a[1];\nref readonly var r = ref a[1];\n```\n\nWe could have `var` infer the `readonly` as well. It wouldn't be breaking to add later.\n\nWhy do we allow the silent copying of readonly struct values in these new scenarios? Do we like that?\n\nNo, but for consistency. People will need to use analyzers already to catch the existing cases. Those analyzers should just have this feature in there as well.\n\nWe agree that this is a reasonable feature to have, and the design is right.\n\nLike ref locals, these aren't currently reassignable, but there's no dependence on that. We could change it later. There's then technically room for an extra `readonly` in front.\n\nFor \n\n``` c#\nMyRefTaker(42);\nMyRefTaker(ref MyRefReturner());\nref readonly int r = 42;\nref readonly int r = ref MyRefReturner();\nb ? 42 : MyRefReturner()\n\nreturn ref r;\n\nref readonly int x = a[1];\n```\n\nDiscussion about whether the implicitness is a good thing. \n\nThere are other options: require \"ref\" in arguments, require \"in\" in arguments. We still want the implicit ref in parameters.\n\nFor operators, during overload resolution we ignore the refness.\n\n## Conclusion\n\nLet's flip to requiring `ref` in argument position. `ref 42` and `ref x+y` etc are allowed.\n\n\n(Other small decisions)\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-09-27.md",
    "content": "# C# Language Design Notes for Sep 27, 2017\n\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\nQOTD: `in int i = in init(in it);`\n\nWe changed our minds to allow and require explicit `ref` for `ref readonly` arguments.\n\n``` c#\nconst int x = 42;\nfoo(ref x);\n```\n\nIn the compiler, the order of things change, which is the most churning fix.\n\nTechnically not hard to do.\n\n## Concern 1\nIs 'ref' the right keyword? Putting `ref` signals to the caller that mutation may be happening. You need to understand what you are passing it *to* in order to know whether it's safe from mutation.\n\nIn other cases, like `return ref x` or `ref readonly r = ref x` the `readonly` is nearby, and it doesn't cause the same concern.\n\n## Concern 2\nAlso, the `ref` in front of rvalues feels wrong. \n\n``` c#\nFoo(ref 42);\nFoo(ref await FooAsync());\n```\n\nThere's an argument that `ref` is about *how* the value is passed, not about the guarantees of the callee. On the other hand we use both `out` and `ref`, where the only difference is the guarantee.\n\nCompromise position:\n\nUse keyword to pass by ref, no keyword to pass \"by value\" (really by creating a new local and putting the value in).\n\nWarn (or error) when an lvalue is being passed without the keyword, that could have been passed by ref.\n\n* Is it important to be able to see in the code if something is passed by ref?\n* Is it important to be able to see in the code if something is copied?\n* Is it important that the parameter passing mode reflects the contract?\n* Is it important that the same keyword is used for passing and returning?\n\nOther compromise:\n- No modifier: Do you best\n- Modifier: Require ref, don't copy\n\nThe keyword would be `in`. \n\nShould it then also be `in` in parameter declarations? A danger is that people misunderstand it for \"being explicit\" about value parameters, whereas `ref readonly` leaves no such room for interpretation. On the other hand, this may be a case where we'd overoptimize for newcomers to the feature, leaving too much syntax for too little benefit. A bit of education, maybe some warnings, maybe analyzers...\n\n## Conclusion\n\n- At the parameter declaration site, use `in`. `ref readonly` is no longer allowed.\n- At the call site, `in` is optional. If it is used, the argument has to an lvalue that can be passed directly by ref. If not, then the compiler does its best: copy only if necessary.\nNo change to `ref readonly` return signature, or to `return ref`.\nNo change to `ref readonly int r = ref ...`\n\nWe would consider allowing `ref readonly int r = 42;` in the future, but it is only useful once we have ref reassignment.\n\nWe could consider a warning for `in` parameters of small types (reference types and built-in value types, maybe), but sometimes you do need that. Better left to an analyzer.\n\nWhat about ambiguity:\n\n``` c#\nM(in int x){}\nM(int x){}\n\nM(42); // how do you resolve in direction of value\n```\n\nWe could deal with this through a tie breaker in overload resolution, but it's probably not worth it. \n\nIf you have an API like that, there's going to be a method overload you cannot call. We could always add it later.\n\nThis scenario isn't entirely esoteric: if I want to update my API from value-passing to in-passing, then either:\n\n- I add an overload. Then all existing call sites are broken on recompilation.\n- I replace the current overload. The all existing assemblies are broken until recompilation.\n\nInstead, you can add an optional parameter, change parameter names etc. to give another means of distinguishing.\n\n\n\nDelegate conversion: No contravariance in the type of parameters, unlike value parameters. THis is because the CLR doesn't know about it. It's similar to the restriction on out parameters.\n\n\nConditional: If one of the branches is readonly, the whole thing is readonly. That means that calling a mutating member on it would mutate a copy, *regardless* of whether the actual branch chosen was readonly or not:\n\n``` c#\nvoid M(bool b, in x, ref y)\n{\n    (b ? ref x : ref y).M(); // M is always called on a copy, even if b is false\n}\n```\n\n# ref structs\n\n## Syntax\n\nPartial has to keep being the last modifier; ref can for now only be right before `struct` or `partial struct`.\n\nLong term we want `ref` to float freely as a modifier. Just may not get to do the work now.\n\n\n\n\n\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-10-02.md",
    "content": "# Milestone philosophy\n\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n7.3 is a bucket for next steps with pattern matching.\n\nNon-exhaustive list\n\n- recursive patterns\n- non-null patterns\n- switch expression\n- negated if-condition\n\n8.0 is for major language features\n\n\n# Discussion on how we get input\n\nWe should solicit problems, not just solutions\n\n# Triage\n\n## 945\nCould make it always prefer by-value as a tie-breaker.\n\n## 933\nMotivating scenarios:\n\n1. Hold on to the content variable in linked list elements\n2. assign one as a default and have an if overwrite it with another\n\nSyntax! Should we be putting `ref` in front of the LHS, or just the RHS?\n\n``` c#\nref r = ref v; // or\nr = ref v;\n```\n\nNot requiring ref lets us:\n\n- Be more terse\n- Work as an expression (because no expression starts with ref)\n\nRequiring makes it syntactically clear whether you are assigning to `r` itself (in the ref space) or to the variable currently pointed to by `r` (in the value space). Also, what the hell does code mean if e.g. a ref-reassigning expression occurs as a ref or out argument?\n\n``` c#\nM(out r = ref v); //What?\n```\n\nWe'd just recommend parenthesizing the assignment, like we recommend everywhere else assignments are used as expressions.\n\nThere's a limit which is that there's no proper default, so we'd still always require initialization, picking up the lifetime from the initializer. This is a bit painful when you want it to have global lifetime (no good default to provide).\n\nWe should instead allow you to not have an initializer. We do definite assignment analysis. It has global lifetime.\n\n\n\n``` c#\nref readonly tmp = ref Get();\nM(in tmp);\n```\n\nAnnoying that there's sort of three different ways to talk about a `ref readonly`: `ref readonly`, `ref` and `in`.\n\nShould we switch parameter to `ref readonly`? Allow choice.\n\nNo: Let's keep having only one way of doing it, and let's have that way be consistent with what you say at the call site.\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-10-04.md",
    "content": "# C# Language Design Review, Oct 4, 2017\n\n*Quote of the Day:* \n> \"You don't get to use this with your grandfather's Oldsmobile\"\n\n## Agenda \n\nWe looked at nullable reference types with the reviewers, Anders Hejlsberg and Kevin Pilch.\n\n1. Overall philosophy\n2. Switches\n3. Libraries\n4. Dotted names\n5. Type narrowing\n6. The dammit operator\n7. Array covariance\n8. Null warnings\n9. Special methods\n10. Conclusion\n\n# Overall philosophy\n\nThink of this feature as a linting tool, an analyzer. It will help you find many bugs, but it will not guarantee anything. It is important that it does not lead to too much inconvenience, and does not yell too much over existing code. Too much whining at programmers makes them turn the feature off. First appearances are everything.\n\nWe should not think of the feature as dialable, with multiple switches or settings. We should design our way to the best balance, and stick to it. One switch: On or off.\n\nDon't worry too much about unannotated libraries. Push on the library owners to get annotations, and live with the lack of them until that happens. In many cases the feature will still be useful even on unannotated libraries, because the default of assuming non-null is often going to be correct.\n\n\n# Switches\n\nHave just one on/off switch for the warnings. The annotations should be allowed regardless of whether the warnings are on or off.\n\nNew projects should have it on by default, existing projects probably off.\n\n\n# Libraries\n\nWe should push to get our libraries upgraded to have annotations. Since it's only about adding attributes, it's possible we can do something with reference assemblies, leaving the actual binaries untouched.\n\nEven if some libraries aren't upgraded, or not at the same pace, it's not a disaster, and we shouldn't hold up the feature waiting for a sufficient amount of libraries to be ready. Instead, use the availability and (hopefully) popularity of the feature to drive libraries to annotate.\n\n\n# Dotted names\n\nThe flow analysis should track dotted names. We have experience from TypeScript, and customers there would definitely complain if we didn't. We also know that it is common in existing code bases to check a dotted name (e.g. a property) for null, then dereference it. In particular, of course, \"dotted\" names with an implicit `this.` are common.\n\nIt would be a disaster for existing code not to track the null state of dotted names.\n\nIf we do, what does it take to invalidate assumptions about a dotted name? In principle, any intervening call can cause a property to change. Even another thread could do that!\n\nBut assuming the worst on this is just going to lead to a lot of pain. We have to be lenient, and assume that dotted names remain the same unless something in the dotted chain is assigned to, or maybe passed by out or ref.\n\nThere's going to be a type of subtle bug that we won't catch as a result of this lenience. But the price of catching it is too high in most cases, in terms of the amount of perfectly safe existing code that it would flag.\n\n\n# Type narrowing\n\nWe are currently tracking nullness of variables separately from the type system. Even when a nullable variable is known not to be null at a given place in the source code, it's *type* is still nullable, and that's what we feed into e.g. type inference around it.\n\nThis allows us to handle things that are *not* necessarily nullable, such as type parameters. However, when we *do* know the type is nullable and not null, it feels like we're throwing away useful information not to narrow the type.\n\nWe should consider a hybrid, where we narrow the type to non-nullable when we can.\n\nSimilarly for use of the `!` (dammit) operator. Yes it should silence warnings on conversions and dereferencing. But it should also narrow the type of the expression to non-nullable when possible.\n\n\n# The dammit operator\n\nTypeScript also has this, and it is often a nuisance that it doesn't \"stick\" - it applies only locally to the expression it is used on. It might be nice with some sort of assertion that sticks throughout the scope of the variable. We should consider it.\n\nIt's a little suspicious to use the same operator for silencing warnings and narrowing the type, but probably better than having two different ones. Casts aren't good for suppressing warnings, because they also imply a runtime check (which we may not want, since the suppression of the warning may be because you *want* to allow a null).\n\n\n# Array covariance\n\nWe currently treat arrays as invariant with respect to element nullability. \n\n``` c#\narrayOfNullable = arrayOfNonNullable; // warning\n```\n\nBut arrays are covariant, albeit unsafely. We should consider applying the same covariance to nullability, for consistency. I.e., we would allow the above code without warning. That is *even though* a null check won't be part of the runtime type check that arrays do on write. The alternative is worse.\n\n\n# Null warnings\n\nwe should warn on the majority of cases where a null value makes it into a nonnullable variable. However, there are cases where it simply gets too harsh on existing code.\n\nPlaces where we should warn:\n- constructors that don't initialize fields of nonnullable reference type\n- converting a null literal to a nonnullable reference type\n- passing or assigning a nullable reference value to a non-nullable reference type\n- `default(T)` expressions when `T` is a nonnullable reference type\n\nThe last one could also yield a `T?` and no warning, but that would just lead to other warnings further down the line. Besides, default isn't used very much on reference types.\n\nOn the other hand we should *not* warn on array creation expressions, even though they create a whole array of forbidden null values:\n\n``` c#\nvar array = new string[10];\n``` \n\nThese are numerous in current code, and very often they are fine. Besides, the code one would have to write instead is quite unappetizing!\n\nWe *could* maybe find special cases, where we could warn, e.g. if a newly created array of nonnullable element type is read from without ever having been written to at all.\n\n\n# Special methods\n\nSome methods have a special relationship with null: if `string.IsNullOrEmpty` returns false, then the argument was not null. If a `TryGet` method returns false, then the resulting out parameter may be null.\n\nTypeScript has a notion of user-defined predicates, which are methods that claim to establish membership of a given type for a given value. We may try to think along similar lines, and consider whether methods can somehow convey extra knowledge about nullability.\n\n\n# Conclusion\n\nThis is going to be a great feature, and people will love it. Have a list of known holes, and make clear that there's no guarantee.\n\nWe're not going to get everything in the world. It's not possible! And even some of the possible stuff is too inconvenient.\n\nThere are only so many greenfield projects in this very established world. Don't be discouraged by low adoption in the beginning. These things take time.\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-10-09.md",
    "content": "# C# Language Design Notes for Oct 9, 2017\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n\n# 882 Negated if or negative patterns\n\nThree approaches\n\n1. bang outside if condition (then should I do that on while etc, too) `if !(o is int i)`\n2. negative patterns (but not very useful recursively) `not int i`\n3. `is not` as an expression operator\n\n# 867 \n\nAvoid some statement cliffs...\n\nPut it in X.X with a note to consider again when we have match expressions\n\n# 414\n\nThere's a \"there\" there.\n\nWe think this should be addressed, and will keep the championing issue to represent it.\n\nHowever, it should be different:\n\n1. It should not be strongly tied to the `Dictionary<K, V>` type, but be target typed\n2. We should look at initializing immutable objects (also for object and collection initializers)\n3. We already have index initializers. Are they good enough?\n\n# 973 Declaration expressions\n\nLast time, we had two issues:\n\n1. Weren't ready to commit to scoping rules\n2. Weren't sure that we could get decent error recovery on syntax\n\n1 is dealt with. \n2 was more that it was hard to show intellisense because more things were legal\n\nScenario is introduce a local variable in expressions without having to use trivial pattern matching. Also ref.\n\nWe feel like we need to spend more time with it to judge its value. 8.0 for now to trigger that discussion.\n\n# 881 and 33\n\nFits with nullable in 8.0\n\n# 185\n\nSettle this in the 7.3 timeframe\n\n# 187 Blittable\n\n# 435\n\n# 287\n\n# 32\n\n# 125\n\nMissing, but not much ask for it\n\n# 111\n\nWe would want to deal with single parameters. A problem is that discards do not shadow today, whereas identifiers do. We may want to change that.\n\n# 191 \n\nNeed more motivation\n\n# 190\n\nSome open design discussions\n\n# \n\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-10-11.md",
    "content": "# C# Language Design Notes for Oct 11, 2017\n\n## Agenda\n\nWe looked at the Oct 4 design review feedback for nullable reference types, and considered how to react to it.\n\n1. Philosophy\n2. Switches\n3. Dotted names\n4. Type narrowing\n5. Dammit operator type narrowing\n6. Dammit operator stickiness\n7. Array covariance\n8. Null warnings\n\n\n# Philosophy\n\nFeedback: We should view this as a linting tool. We have to make most existing code pass muster, and it's ok with a little more complexity and forgiveness in the rules to achieve that.\n\n## Conclusion \nWe agree with this general philosophy, and it is helpful to apply it to specific decisions.\n\n\n# Switches\n\nFeedback: Don't have many switches and levers. Just \"on\" or \"off\". \"Off\" would suppress the warnings, but the `?` syntax would still be allowed. Make the hard decisions once and for all at the language level, rather than leave people with too many options.\n\n## Conclusion\n\nThis is a good philosophy. We do think that there's possibly room for an \"Xtreme\" mode as well, for people that care more about catching more cases regardless of inconvenience.\n\n\n# Dotted names\n\nFeedback: We should track dotted names, and be very forgiving about what invalidates the null state. Otherwise it violates the general philosophy and complains about too much existing code. Things that *would* invalidate non-null-ness of a dotted chain is assigning to (or maybe passing to an out or ref parameter) the variable itself or any mutable prefix.\n\n## Conclusion\n\nAgree! If we adopt an Xtreme mode, this is probably one of the places where it would be harsher.\n\n\n# Type narrowing\n\nFeedback: when a variable of a nullable reference type (e.g. `string?`) is known to not be null, we should consider its value to be of the narrower type `string`.\n\n```\nvoid M(string? n)\n{\n\tif (n == null) return;\n\tvar s = n;        // s is string, not string? \n\tvar l = s.Length; // ok\n\tn = null;         // ok\n\ts = null;         // warning\n}\n```\n\nWe previously abandoned this approach, because it doesn't work for e.g. type parameters, where we don't know if they are nullable reference types or not, and don't necessarily have an underlying non-nullable type to narrow *to*.\n\n## Conclusion\n\nThis is one of those places where we should forego simplicity for friendliness. We should adopt a hybrid approach: When a type is a known nullable reference type, then having a non-null state *should* narrow its type. When it is a type parameter that might be instantiated with nullable reference types, then we can't narrow it, and should just keep track of its null state.\n\n\n# Dammit operator type narrowing\n\nFeedback: The dammit operator should also narrow the type of a nullable reference to be nonnullable.\n\n``` c#\nvoid M(string? n)\n{\n\tvar s = n!;       // s is string, not string? \n\tvar l = s.Length; // ok\n}\n\nT[] MakeArray<T>(T v)\n{\n\treturn new T[] { v };\n}\n\nvoid M(string? n)\n{\n\tvar a = MakeArray(n!); // a is string[], not string?[]\n\tvar l = a[0].Length;   // ok\n}\n```\n\n## Conclusion\n\n`! should keep its warning suppression, but also narrow the outermost type when it can, to match the new behavior when null-state is non-null.\n\nThere's hesitation because of the muddiness of using `!` for two different things. But we don't have a better idea. Explicit casts are quite verbose. We may need to revisit later, but for now, `!` suppresses warnings *and* de-nullifies the type when it can.\n\n\n# Dammit operator stickiness\n\nFeedback: The dammit operator lacks \"stickiness\" - you have to keep applying it (or introduce another local).\n\nOne idea is to maybe have some top-level \"assertion\" that would declare a thing not-null for the whole scope.\n\nAnother idea is to have `s!` influence null state for flow analysis, staying \"valid\" for as long as a non-null state would have.\n\n``` c#\nstring? s = ...\n\nif (s != null && s.Length == 5) ... // It flows here\nM(s!, s);                           // why not here?\n```\n\nIt would sort of make `s!` mean the same as `s = s!`.\n\nThere are also cases where you *wouldn't* want it to be sticky, e.g. when you are using `!` to shut up a specific unannotated API that is lacking a `?`. Here you don't use `!` in the meaning of \"this is really not null\", but to the effect of \"I am actually fine passing a null here\". That meaning shouldn't really be contagious to subsequent lines.\n\n## Conclusion\n\nWe don't know what, if anything, to do here. For now we'll leave it as is.\n\n\n# Array covariance\n\nFeedback: Arrays are (unsafely) covariant over reference types, and for consistency we should also make them covariant over nullability.\n\n## Conclusion\n\nThis is probably right. We'll think about this more, but let's go with covariance for now.\n\n\n# Null warnings\n\nFeedback: Fine to warn in most places where a null value is given a nonnullable type, but we should beware of a \"sea of warnings\" effect. Specifically, we shouldn't warn on array creation, as in `new string[10]`, even though it creates a whole array of undesired nulls, because it is so common in current code, and couldn't have been done \"safely\" before.\n\n## Conclusion\n\nWe agree. Xtreme mode, if we adopt that, may warn on array creation, though.\n"
  },
  {
    "path": "meetings/2017/LDM-2017-10-16.md",
    "content": "# C# Language Design Notes for Oct 16, 2017\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n\n\"Being on the same floor as SPJ is a good way to shake out difficult corner cases\"\n\n1. LINQ\n2. Shapes\n\n\n# Applying to LINQ\n\nMixed results.\n\nLooking for perf, and ways to do more selective specialization.\n\n## Sum\n\nSpecialized to some numeric types, but not all. 500 lines of code. In those, the loop is unspecialized too.\n\nOne page of code!\n\nA new design dimension: should I use interfaces or concepts: pay for abstraction or pay for specialization\n\nGeneric soup: this may be a superficial design issue, or even tooling issue.\n\nFor instance, the `AssociatedType`s, other languages allow them to be retrieved by dot notation. Jeremy Siek paper \"Associated Types and ...\". `TColl.TEnum` etc.\n\nFrom experience, abstracting over enumerators tends to need associated types or higher-kinded types.\n\nShouldn't be too discouraged by being smoked by LINQOptimizer. That one optimizes big queries, but what keeps people away from LINQ is more the death by a thousand paper cuts of using LINQ all the time. Roslyn avoids things that allocate, which today means not using LINQ. THis could be the thing that would allow it to.\n\n## Select\n\nThe return type is associated. The problem is that adding new instances can change the return type from afar, upsetting the consuming code.\n\nImproves by 2/3rds when the array specialization is used.\n\n## SelectMany\n\nThe generic type inference gets very messy here. It shows that concept inference needs to be interleaved with type inference in a way that we are still only loosely grasping.\n\nThis is a place where LINQ allocates a lot, whereas this allocates hardly anything. We go at .75 the time even unspecialized. Also, the specialized version is twice as fast as the unspecialized.\n\nIt shows that if you open up for specializations to be plopped in, there's quite a lot to gain.\n\n## Conclusion\n\nSome promise on optimization. Pinches of salt here and there. The approach definitely seems to have promise.\n\nMore tests to do.\n\n\n# Shapes\n\nConcepts can tie in to the richness of expression in C# around different kinds of operations (operators, conversions, constructors...)\n\nInteresting to consider whether there's more of a specialization relationship between concepts and instances, rather than a type/instance relationship.\n\nIf this went further, there's a very large laundry list.\n\n\n\n\n\n\n# Conclusion\n\nWe *really* would like to be able to do the post-hoc implementation of concepts. This \n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-10-18.md",
    "content": "# C# Language Design Notes for Oct 18, 2017\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n\n## Agenda\n\n\n# 189\n\n``` c#\nfrom s in strings\nlet (b, i) = (int.TryParse(s, out var x), x)\nwhere b\nselect i\n```\n\nProblem is that out vars also aren't yet allowed. \n\nWe don't allow declaration expressions in\n\n1. queries\n2. constructor initializers\n3. field/property initializers\n\nAll of these were because we didn't settle the scope question. Time to do that.\n\nLet's put these as issues. And let's put those issues as 7.3. And let's put this one as 7.3.\n\n\n# 100\n\nThe difficulty of this depends on the level of ambition. It has to play in to applicability of overloads this is passed to. If we allow member initializers, then we need to bind those \n\n``` c#\nM(new { X = 7, Y = new { A = \"Hello\" } });\n\nx = new () { Y = { e1, e2 } };\n```\n\nIf we're lucky, this is just about whether the conversion exists or not. \n\nWould there be a way that this would even influence generic type inference?\n\n``` c#\nM(() => new (1));\n```\n\nWe'd need to think about this.\n\nIt may be that there's a subset of the feature that's simpler. We would need that subset to not preclude going further later.\n\nSpooky action at a distance\n\n``` c#\nM(Foo)\nM(Goo)\n\nM(new (1))\n```\n\nGoo has a constructor that takes an int. Adding such a constructor to Foo will break the code.\n\nNow, adding a constructor is equivalent to adding a conversion in terms of the breaks it can entail.\n\nMay also need more betterness rules.\n\n\nIt could be that it's better to limit the feature so it does not participate  in type inference and betterness, and can always be checked as a conversion. It might even be worth considering it only specifically to where one target type is known (so no overload applicability).\n\n\nFor now, let's put it in 8.0. We don't believe it's going to make 7.3, but that makes us still consider it for design time.\n\n\n# 179\n\nFor people who care about perf, they already need 3 or 4 overloads, and this would be yet another overload people will yell at them to add.\n\nFor no parameters today, you no longer need an overload to avoid allocation, because we now use `Array.Empty`.\n\n`params IEnumerable<T>` would be even less performant than the array one, because enumeration allocates.\n\nThe point of it more is that if I want to take an `IEnumerable<T>` anyway, then it's a convenience to add params and take the arguments individually.\n\n\nNot important enough to prioritize time for the design soon. Let's make this X.X.\n\n\n# How to continue \n\nScan 7.X for remaining 7.3 items and ignore the rest for a bit.\n\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-10-25.md",
    "content": "﻿# C# Language Design Notes for Oct 25, 2017\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n\n\n## #98 \n\n## 34 and 35\n\n34 should bot be concurrent safe, just like the other compound assignment.\n\nBundle with 8.0, but could push out. Seems to align with nullable reference types\n# 32\n\nReconcile 32 with 1020\n\n\nCriteria:\n\n- Loose ends\n- External expectation\n\n# ref as iteration variable\n\nNot currently allowed, should probably have a proposal (Andy)\n\n# 185 keep in 3 to prioritize\n\n# 45\n\nPush out to 8.0 for realism, but still prioritize design time\n\n# 933, 1046, and uninitialized ref local\n\nThese should happen together in 7.3\n\n# 111 Punt to 8.X\n\n# 1020 946 945 keep\n\n# 882 pattern-related, goto 8.0\n\n# 435 \nKeep in 7.3, see if we can settle design\n\n# 190\n\nRelatively obvious design, with some gnarly bits (dynamic, conversion)\n\nUsability gap with tuples let's keep it.\n\n# 189\n\nLet is more important than from. It lets you use out variables\n\n``` c#\nfrom s in strings\nlet t = (b: int.TryParse(out var n), n)\nwhere t.b\nselect t.n\n```\nCould be\n``` c#\nfrom s in strings\nlet (b, i) = (int.TryParse(out var n), n)\nwhere b\nselect i\n```\n\nThere's a bit of design work, especially if we also want the from clause.\n\nWe could allow out vars but not the deconstruction, and it would still be useful.\n\nCould save dec for later. It's actually orthogonal. \n\nAction:\n\nCarve out deconstruction, push to 8.X\n\n# 187\n\nOn the brink, but keeping for now; need to be convinced of value\n\n# 185\n\nKeep pushing on it, got to get the train going on `Range`\n\n`x..y` does new Range(x, y) or Range.Create(x, y)\n\nConsider whether it should be a new kind of operator instead.\n\n# 104\n\nMicro-feature: Just allow `System.Enum` as a constraint\nMini-feature: allow `enum` as a constraint, translate to `System.Enum, struct`\n\nKeep this in, but it is very cuttable.\n\n# 98\n\nIt's a zero-conceptual-overhead feature. \n\nOriginal designers left in space between meanings for a purpose. But that's not so compelling to us anymore.\n\nBecause it touches overload resolution, it might be better aligned with a .0 release. But we're not compelled by that.\n\nLet's keep it, but again, it's cuttable.\n\n\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-11-06.md",
    "content": "﻿# C# Language Design Notes for Nov 6, 2017\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n# Roslyn 20870\n\nProtecting the client from unintended dependencies. But also protects from servicing. Today people going through reflection *know* they're being bad. Would this give enough sense that they are doing something special.\n\nIt would make consumers lazy about contacting the API owner about things they need exposed.\n\nIt would be an arms race - we would want the `IgnoreIgnore...` attribute to *really* protect things.\n\nPeople will still have expectations about dependencies even if it was \"their own fault\" by using this attribute.\n\n## Conclusion\nToo risky/fishy in too many ways. \n\n\n# Roslyn 17310\n\nThere is no good language level solution right now. This is better addressed with an analyzer, which can know specifically about SpinLock (for instance).\n\nIn time, when readonly struct declarations are added, as well as maybe the ability to declare individual struct members as readonly, *then* maybe we could start warn.\n\n## Conclusion\n\nNot at the language level\n\n\n# Roslyn 20450\n\nWe have sympathy. It feels like a corner that's cut. But it's quite expensive to implement, and has semantic dark corners (`List<>.First.Foo`).\n\n## Conclusion\n\nNot now.\n\n\n# Roslyn 20015\n\nWhen default-expressions are constant (according to the language) this is not interesting expressiveness - there's a literal you can use.\n\nWhen they are *not* it gets a bit more interesting - you might want to check that your custom struct is zero-initialized. But you can do that with equality. Even in recursive scenarios, you can just `var`-pattern it and check in `when` or `&&`.\n\nAdditionally there is some concern about the target type being clear enough for the `default` expression.\n\n## Conclusion\n\nNo.\n\n\n\n\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-11-08.md",
    "content": "﻿# C# Language Design Notes for Nov 8, 2017\n\n## Agenda\n\nWe went over the status of the prototype for nullable reference types, to address outstanding questions and make any last minute calls before release.\n\n1. Constructors\n2. Dotted names\n3. Default expressions\n4. Should we track null state for nonnullable ref types?\n5. Inferred types for method type inference\n6. Inferred nullability in hover tips\n7. Smaller things not yet done\n8. Unconstrained generics\n9. Other issues\n\n\n# Constructors\n\nCurrently the prototype warns on a constructor that doesn't directly initialize all fields, even if it has a `this(...)` constructor initializer. It should exempt such constructors completely, since it will have required the called constructors to fully initialize. \n\nWe may consider a more nifty analysis than that later, at least for private constructors, but it doesn't seem high priority for the prototype.\n\nIt's a warning per constructor. If it's on the implicit (default) constructor it goes on the class name. That's good.\n\nWe don't warn for the default constructor on structs. It's not really actionable, we think, since people can't write their own default constructor or add initializers to fields of structs. But this is worth revisiting later, probably in the context of Xtreme mode. \n\n\n# Dotted names\n\nNow work in the prototype, modulo a few bugs. (Not fully handling reassignment).\n\n\n# Default expressions\n\nShould `default(string)` be of type `string?` or should it yield a warning *in and of itself*, and be of the type `string` (the type it states).\n\nThis is a question that's related to whether `string s = null` as a local declaration yields a warning. \n\nWe're going to leave the current implementation, which makes `default(string)` be a `string?`.\n\nSimilar with `(string)null`. It's type is `string?`.\n\n\n# Should we track null state for nonnullable ref types?\n\nNot now. Worth thinking about for later, as a stop gap.\n\n\n# Inferred types for method type inference\n\nIn the current implementation, the best common type and method type inference don't pick up *inferred* nullability, but only *declared* nullability.\n\n``` c#\nvoid M(string? s)\n{\n    if (s == null) return;\n    var a = new[] { s }; // string?[], should be string[]\n}\n```\n\nWe can live with that as a known issue in the prototype.\n\n\n# Inferred nullability in hover tips\n\nCurrently shows declared nullability. Relatively big work item, won't be fixed in prototype. So we need to set expectations. \n\n\n# Smaller things not yet done\n\nSome warnings not given. That's alright, we'll give more in the future.\nNew constraints (`class?`, `object`) aren't added. That's not blocking.\nVariance: we'll deal with it when we get there.\n\n\n# Unconstrained generics\n\nNeed to revisit to see if the weirdness we do is the right weirdness. Based on design review feedback, it is ok if what we do is not consistent with the rest of the language; the higher order bit is that it is helpful, intuitive and not obnoxious.\n\n\n# Other issues\n\n- No switch in the prototype; warnings are always on. We need to design the command line switch.\n- Annotations for TryGet etc. still need to be designed.\n- How to update BCL with annotations. (Automatically?)\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-11-20.md",
    "content": "﻿# C# Language Design Notes for Nov 20, 2017\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n\n## Agenda\n\n\n# Recursive pattern matching\n\n## Grammar\n\nThe grammar splits out to a couple of cases so that the right things are optional etc. directly in the grammar.\n\nThat separation is also there in the representation of the implementation, currently. An alternative is to have a single production and call it out in prose. There are advantages to having a separated representation, in that your code can make more assumptions about what's there or not.\n\n## Names in deconstruction pattern\n\nWhat is the utility? Current proposal it's only to guarantee that you get the thing you say. It does not allow reordering or leaving out elements.\n\nThis pattern should by and large work like deconstruction. But it's plausible to have names here, even if we don't in deconstruction; the argument would be a symmetry with constructors, which are sometimes used with names and optional arguments.\n\n## Should the identifier be restricted from being a discard?\n\nSince it can be left out completely? No, it's probably good to allow the discard. For refactoring etc.\n\n## Matching via ITuple\n\nIt's \"too likely\" that the compiler would consider that a thing *may*\nimplement `ITuple`. \n\nWe'll restrict to static types `object`, `ITuple` and any type that derives from `ITuple` and has no deconstructors.\n\n`dynamic` is treated just like `object`. We don't go looking for deconstructors dynamically.\n\n\n## Syntactic ambiguity around parenthesized expression\n\nShould we even have single-element deconstruction patterns? \n\nCould require some other element to disambiguate, e.g. `(2) _`.\n\nThis would raise the cost of adding single-element tuples and deconstruction in the future, at least if they have a syntax *other* than parenthesized expressions (e.g., `(x,)`). \n\n``` c#\nswitch(my1DPoint)\ncase 1DPoint(0):\n...\ncase 1DPoint(var x):\n...\n```\n\nCompromise position: Allow a single one only if there is a type in front. It gives the obvious symmetry with a single-element constructor, without restricting the design space for future single-element tuples or pattern grouping constructs.\n\n## Cast ambiguity\n\nNow went away. It's a cast, or an error.\n\n## Short discard\n\nYes, allow `_` as a pattern in and of itself. It would not be allowed at the top level in an `is` expression. (That is allowed today, and designates the type `_`).\n\nIt actually means something different than `default` in a switch, because it gets an error if there are no cases left. That seems useful.\n\nSo: allow it everywhere except at the top level in an is-expression.\n\n## Colon or is?\n\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-11-27.md",
    "content": "﻿# C# Language Design Notes for Nov 27, 2017\n\n## Agenda\n\nWe went over the feedback on the nullable reference types prototype, and discussed how to address the top issues that people had found using the feature on their own source code.\n\n1. Interacting with existing, unannotated APIs\n2. Accommodating alternative initialization patterns\n3. Tracking nullable value types\n4. Tracking dotted names\n5. Special methods\n6. Filtering out nulls\n\n\n# Interacting with existing, unannotated APIs\n\nThe most pressing problem for people using the prototype, is when existing, unannotated APIs are treated as all non-nullable. While you can live with that, there ends up being too many places where you have to use `!` to silence warnings.\n\nLong term, of course the solution is for these APIs to evolve and to *get* annotations. That presents its own challenges: do people have to wait for them to update in place? Can we have a system of on-the-side annotations, either through reference assemblies or otherwise?\n\nShort term, though, it seems that we should probably distinguish \"legacy\" APIs, and simply not warn based on their signatures. The way to recognize them is to bake an attribute into *new* assemblies - then *old* ones are simply the ones without that attribute.\n\nThere's design work to decide what exactly it means to \"not warn on legacy signatures\": do they represent a third type state (\"between\" nullable and non-nullable)? Does it travel with type inference? Etc.\n\n\n# Accommodating alternative initialization patterns\n\nThe prototype warns when constructors do not initialize all non-nullable fields. However, this is too harsh for many usage patterns, where fields may be initialized by:\n\n- Initialization helpers called from constructors\n- Factory methods that call constructors\n- Object initializers, by convention\n- Set-up/tear-down methods in test frameworks\n- Reflection\n\nWe can try to do something more fancy to track initialization of fields through at least some of these. At the end of the day, there will be initialization that we just don't recognize, so there should also be a way to opt out of these warnings.\n\n\n# Tracking dotted names\n\nThe prototype ended up not supporting the tracking of null-state for dotted names, and that was definitely felt by several prototype users, which goes to show that we do indeed need this functionality, as we suspected.\n\n\n# Tracking nullable value types\n\nThere's some desire to have the same tracking of null-state for nullable *value* types. Not only could we allow you to dot through to the members of the underlying type (with some finagling to avoid breaking changes), but this would also be helpful when boxing the nullable value type.\n\n\n# Special methods\n\nCertain scenarios came up again and again, where utility methods or specific method patterns have special behavior regarding null. We need to design a general approach to this, where certain attributes on these methods can change their nullability behavior. Examples:\n\n- `String.IsNullOrEmpty(s)`: `s` is not-null when method returns false\n- `TryGet(out T x)`: `x` may-be-null when method returns false (even if `T` is non-nullable)\n- `FirstOrDefault()`: result may-be-null (even if element type is non-nullable)\n\nThere's design work needed.\n\n\n# Filtering out nulls\n\nIn this query it would be really good to know that the result is of non-null element type:\n\n``` c#\nvar query =\n    from s in nullableStrings\n    where s != null\n    select s;\n```\n\nFor query expressions we can maybe deal with this in the language. For the method syntax, it does not seem viable:\n\n``` c#\nvar query =\n    nullableStrings.Where(s => s != null);\n```\n\nHow would we know that the result is filtered by the lambda provided? \n\nIt's more likely that we can make a specialized `WhereNotNull` query method for this purpose.\n"
  },
  {
    "path": "meetings/2017/LDM-2017-11-29.md",
    "content": "﻿# C# Language Design Notes for Nov 29, 2017\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n# Match expression\n\nCurrent proposal:\n\n- Infix vs prefix `switch`\n- `switch` vs `match`\n- curlies or parens for body\n- `case` or not\n- arrows?\n- discards or defaults?\n- also need to remember when clauses\n\nIf it's too similar to switch statements, then it sets certain expectations. If it's too different, it's not utilizing existing intuition.\n\nShould it be a verb/command? Not many expression keywords are that (`select` is an exception, though).\n\n`case` is heavyweight, but helps visually separate the issues.\n\n``` c#\n            state = (state, action) switch (\n                (DoorState.Closed, Action.Open) => DoorState.Opened,\n                (DoorState.Opened, Action.Close) => DoorState.Closed,\n                (DoorState.Closed, Action.Lock) => DoorState.Locked,\n                (DoorState.Locked, Action.Unlock) => DoorState.Closed,\n                _ => state);\n\n            state = match (state, action) \n            {\n                (DoorState.Closed, Action.Open) => DoorState.Opened,\n                (DoorState.Opened, Action.Close) => DoorState.Closed,\n                (DoorState.Closed, Action.Lock) => DoorState.Locked,\n                (DoorState.Locked, Action.Unlock) => DoorState.Closed,\n                _ => state\n            };\n\n            state = switch (state, action)\n            {\n                case (DoorState.Closed, Action.Open): DoorState.Opened\n                case (DoorState.Opened, Action.Close): DoorState.Closed\n                case (DoorState.Closed, Action.Lock): DoorState.Locked\n                case (DoorState.Locked, Action.Unlock): DoorState.Closed\n                case _: state\n            };\n```\n\nThe last one is subject to ambiguity-like situations between expression and statement `switch`.\n\nWe should also consider nesting of match expressions.\n\nNo matter what syntax we choose, we'll get requests for doing more things in expressions. We can live with that.\n\nParens look too much like a list of *expressions*. \n\nArrows make it look like lambda expressions.\n\n## Decisions\n\nWe agree that we will not use the keyword `default`. You can use `_`, and in the rare case where that's defined, you can use `var _`.\n\nWe like curly braces for the grouping.\n\nThe rest is up in the air. We'll stay with the first version for now in the prototype, other than the curly braces.\n\n\n\n# Where and when can identifier appear?\n\n\n\n# Syntax for property patterns\n\nNot urgent\n\n``` c#\n\n```"
  },
  {
    "path": "meetings/2017/LDM-2017-12-04.md",
    "content": "﻿# C# Language Design Notes for Dec 4, 2017\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\nQOTD: \"Days since working around the JIT: 0\"\nQOTD: \"What's wrong with dangerous?\"\nQOTD: \"If we disallowed `Dangerous` in method names, Dangerous Dave wouldn't compile!\"\n\n# Foreach for Span and ReadOnlySpan\n\n`Span` and `ReadOnlySpan` implement the foreach pattern with `GetEnumerator()` etc., even though they don't implement the `IEnumerable<T>` interface. (Interesting aside, the `Current` property is ref-returning, which the compiler is quite happy with.)\n\nBut it's faster to iterate them like an array, by using the `Length` and the indexer. We want to allow that for spans as well. We would keep the enumerable around, which also allows write access to the elements of a `Span`.\n\nInteresting to consider opening up for a new `Length`/indexer `foreach` pattern, that's opted into e.g. with an attribute.\n\n## Conclusion\nDefinitely allow it as an optimization. The general case; not now, and maybe not ever. Better to limit it to compiler-known types, that are guaranteed to have equivalent semantics.\n\n\n# In vs value parameter ambiguity\n\nIf you have overloads\n\n``` c#\n        void M(in DateTime d) { }\n        void M(DateTime d) {}\n        \n        M(myDT); / ambiguity\n```\n\nOptions in tie breaker:\n\n1. Choose based on LValue vs RValue\n2. val preferred\n3. Do nothing\n\nHow would you legitimately end up in this situation:\n\n- Want to \"change\" to `in`, but must keep value for binary compat\n- But now you have source break\n\n\nWe currently do 3. We should do 2. 1 is too arbitrary.\n\nPeople might want to move existing calls to the `in` version, and we won't be helping them. But that's an analyzer.\n\nProblem with operators. They can't use `in` when applied, so can't move away from val behavior. Oh well.\n\n## Conclusion\n\nGo with 2. Roll out as bug fix.\n\n\n# Pattern-based fixed\n\nLots of types (especially new ones, like `Span`, `Memory` etc., but also `string`) would benefit from being `fixed`.\n\n`Span<T>` currently has a `DangerousGetPinnableReference` method for this. We can make this a pattern.\n\nIt's a thin layer of syntactic sugar.\n\n## Conclusion\n\nLet's do it. Extension methods are allowed (as always when we add new patterns). Let's aim for 7.3, but not super high pri.\n\n\n# this ref vs ref this\n\nWe allow `ref this` but not the other way around. That's wrong! We can't disallow `ref this`, but we should allow and prefer `this ref`.\n\n## Conclusion\n\nFix it. Go out as a bug fix.\n\n\n# Reachability, definite assignment and local functions\n\nThere's a bit of a mess around when captured variables in local functions are definitely assigned.\n\nThis is different from lambdas, because local functions take all calls into account.\n\nThe forthcoming ECMA spec changes the wording of these rules, so that they are not defined based on reachability.\n\nProposal: \n- Make beginning of local functions always reachable. (And lambdas, which is implemented but not spec'ed).\n- A captured local in a local function is considered definitely assigned if it's definitely assigned before every call of it.\n- That last one can be vacuously true.\n\n## Conclusion\n\nWe like this. It could give errors in a few cases that don't today (including the bug report). \n\nIs this an acceptable breaking change? In order to get an error, you'd have to have:\n- an unassigned local variable\n- an uncalled local function that uses it\n\nBoth are unlikely, undesirable and easily fixed. We'll check with compat council.\n\n\n# Equality operators on tuples\n\nNeeds to be defined by the language, in order to deal with long tuples, and to recursively apply `==` rather than `Equals`.\n\nIf somebody wrote their own `ValueTuple` *with* user defined equality, then this would break the use of that. That's not a supported scenario; you could get into the same kind of trouble with `Nullable<T>`.\n\nFor tuple literals, there is a tension between left-to-right evaluation and performance.\n\nIt seems that `t1 == t2` should mean the same as `t1 == (t2.Item1, t2.Item2)`. The upshot of the feature really is to deconstruct tuples (if they aren't already, by being tuple literals), then do point-wise comparison.\n\nWe will evaluate all operands left to right, recursively through tuple literals, and save to temps. We don't evaluate target-typed things, and we don't yet convert them.\n\nThen we do point-wise `==` (or `!=`, in element position order, separated by `&&` (Or for `!=`, `||`). This may involve conversions. We are ok with those happening \"late\", and conditionally (won't happen if previous comparison failed), because conversions aren't usually expected to have side effects.\n\nFor dynamic we think we can allow it by just converting the result of, e.g. `d == e` (where `d` is dynamic) to `bool`.\n\nConversion from tuples matter, but not to tuples. If I have a `Foo` and a tuple, and `Foo` converts to tuple, then that won't help you.\n\n## Conclusion\n\nWe think we have it, but will revisit during implementation.\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "meetings/2017/LDM-2017-12-06.md",
    "content": "﻿# C# Language Design Notes for Dec 6, 2017\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n## Agenda\n\n\n# Range\n\nSeveral arguments against a generic `Range<T>`, such as conversions between them.\n\nStep() should maybe be step with range\n\n# Operator `..`\n\n`op_Range` in IL, marked as special method.\n\nShould it be target typed?\n\nExample: `FloatRange`. If we don't supply it, no-one ever can, unless we make it target typed.\n\nConversion between ranges does not seem like a good idea: Even though it's technically possible, it might not make conceptual sense.\n\nTarget typing seems better. There's an issue with compat and ambiguity, where operator declarations on the operands and the result may clash. The proposal is to let the target type win. But that may not be necessary. The operator declared in the operands corresponds to the \"natural type\", and if there's an exact match to the target type, it would win. \n\nFor `IntRange` we get:\n\n``` c#\nIntRange r = 1 .. 10;\n```\n\nHere `..` is defined on the operand types, and when that one is applied, the natural type is `IntRange`, and that wins in overload resolution.\n\nFor `LongRange`:\n\n``` c#\nLongRange lr = 1 .. 10;\n```\n\nThat works just dandy with target typing, but if there's also a conversion from `IntRange` to `LongRange` then there seem to be two competing conversions. We probably don't want that, and need to think through if that's the case, and if so how to amend it.\n\n## Alternative 1\n\nLook for an instance method (which can be an extension method), and have declared conversions and no target typing. That would lead to N x N extension methods and N x N conversion methods having to be declared to get the same \"convenience\".\n\nBut for the situation of having `x .. y` and *not* a target type, it would be simpler, in that it wouldn't need the `..` operator to be retrofitted to existing types.\n\n## Alternative 2\n\nHave a generic `Range<T>`. A range expression produces a range of the best common type of the operands. It can be target typed to another `Range<S>`, as long as there's a conversion from the end points to `S`. Comparison is done by expanding to use of `<=`, which better be defined.\n\n\n\n# Wrap around\n\nLet's make sure the library side doesn't allow foreach to throw on the boundary (`int.MaxValue`) or wrap around infinitely.\n\n# Inclusive/exclusive\n\nFor floating point/non-enumerable, there's real expressiveness at stake. That's probably not the main scenario, though.\n\nProblem with exclusive: I create a range from Sunday to Saturday, I need a name for the thing outside the range. Also, what if I need `int.MaxValue` as the top element?\n\nProblem with inclusive: Going to array.Length. Slicing and windowing.\n\nEvidence in the Mono code base for instance, shows both prevalent, with a slight overweight of inclusive.\n\n\n\n# Range pattern"
  },
  {
    "path": "meetings/2017/README.md",
    "content": "# C# Language Design Notes for 2017\n\nOverview of meetings and agendas for 2017\n\n\n## Jan 10, 2017\n[C# Language Design Notes for Jan 10, 2017](LDM-2017-01-10.md)\n\n1. Discriminated unions via \"closed\" types\n\n\n## Jan 11, 2017\n[C# Language Design Notes for Jan 11, 2017](LDM-2017-01-11.md)\n\n1. Language aspects of [compiler intrinsics](https://github.com/dotnet/roslyn/issues/11475)\n\n\n## Jan 17, 2017\n[C# Language Design Notes for Jan 17, 2017](LDM-2017-01-17.md)\n\n1. Constant pattern semantics: which equality exactly?\n2. Extension methods on tuples: should tuple conversions apply?\n\n\n## Jan 18, 2017\n[C# Language Design Notes for Jan 18, 2017](LDM-2017-01-18.md)\n\n1. Async streams (visit from Oren Novotny)\n\n\n## Feb 21, 2017\n[C# Language Design Notes for Feb 21, 2017](LDM-2017-02-21.md)\n\nWe triaged some of the [championed features](https://github.com/dotnet/csharplang/issues?q=is%3Aopen+is%3Aissue+label%3A%22Proposal+champion%22), to give them a tentative milestone and ensure they had a champion.\n\nAs part of this we revisited potential 7.1 features and pushed several out.\n\n1. Implicit interface implementation in Visual Basic *(VB 16)*\n2. Delegate and enum constraints *(C# X.X)*\n3. Generic attributes *(C# X.0 if even practical)*\n4. Replace/original *(C# X.0 if and when relevant)*\n5. Bestest betterness *(C# 7.X)*\n6. Null-coalescing assignments and awaits *(C# 7.X)*\n7. Deconstruction in from and let clauses *(C# 7.X)*\n8. Target-typed `new` expressions *(C# 7.X)*\n9. Mixing fresh and existing variables in deconstruction *(C# 7.1)*\n10. Implementing `==` and `!=` on tuple types *(C# 7.X)*\n11. Declarations in embedded statements *(No)*\n12. Field targeted attributes on auto-properties *(C# 7.1)*\n\n\n## Feb 22, 2017\n[C# Language Design Notes for Feb 22, 2017](LDM-2017-02-22.md)\n\nWe went over the proposal for `ref readonly`: [Champion \"Readonly ref\"](https://github.com/dotnet/csharplang/issues/38).\n\n\n## Feb 28, 2017\n[C# Language Design Notes for Feb 28, 2017](LDM-2017-02-28.md)\n\n1. Conditional operator over refs (*Yes, but no decision on syntax*)\n2. Async Main (*Allow Task-returning Main methods*)\n\n\n## Mar 1, 2017\n[C# Language Design Notes for Mar 1, 2017](LDM-2017-03-01.md)\n\n1. Shapes and extensions (*exploration*)\n2. Conditional refs (*original design adopted*)\n\n\n## Mar 7, 2017\n[C# Language Design Notes for Mar 7, 2017](LDM-2017-03-07.md)\n\nWe continued to flesh out the designs for features currently considered for C# 7.1.\n\n1. Default expressions (*design adopted*)\n2. Field target on auto-properties (*yes*)\n3. private protected (*yes, if things work as expected*)\n\n\n## Mar 8, 2017\n[C# Language Design Notes for Mar 8, 2017](LDM-2017-03-08.md)\n\nWe looked at default interface member implementations.\n\n1. Xamarin interop scenario\n2. Proposal\n3. Inheritance from interface to class\n4. Overriding and base calls\n5. The diamond problem\n6. Binary compatibility\n7. Other semantic challenges\n\n\n## Mar 15, 2017\n[C# Language Design Notes for Mar 8, 2017](LDM-2017-03-15.md)\n\nTriage of championed features\n\n1. JSON literals\n2. Fixing of captured locals\n3. Allow shadowing of parameters\n4. Weak delegates\n5. Protocols/duck typing/concepts/type classes\n6. Zero and one element tuples\n7. Deconstruction in lambda parameters\n8. Private protected\n\n\n## Mar 21, 2017\n[C# Language Design Notes for Mar 21, 2017](LDM-2017-03-21.md)\n\nDiscussion of default interface member implementations, based on [this guided tour](https://github.com/dotnet/csharplang/issues/288).\n\n1. Concerns raised on GitHub and elsewhere\n2. Inheritance?\n3. Breaking name lookup on `this`\n4. Events\n5. Modifiers\n6. Methods\n7. Properties\n8. Overrides\n9. Reabstraction\n10. Most specific override\n11. Static non-virtual members\n12. Accessibility levels\n13. Existing programs\n\n\n## Mar 28, 2017\n[C# Language Design Notes for Mar 28, 2017](LDM-2017-03-28.md)\n\nDesign some remaining 7.1 features\n\n1. Fix pattern matching restriction with generics\n2. Better best common type\n\n\n## Mar 29, 2017\n[C# Language Design Notes for Mar 29, 2017](LDM-2017-03-29.md)\n\n1. Nullable scenarios\n2. `Span<T>` safety\n\n\n## Apr 5, 2017\n[C# Language Design Notes for Apr 5, 2017](LDM-2017-04-05.md)\n\n1. Non-virtual members in interfaces\n2. Inferred tuple element names\n3. Tuple element names in generic constraints\n\n\n## Apr 11, 2017\n[C# Language Design Notes for Apr 11, 2017](LDM-2017-04-11.md)\n\n1. Runtime behavior of ambiguous default implementation\n\n\n## Apr 18, 2017\n[C# Language Design Notes for Apr 18, 2017](LDM-2017-04-18.md)\n\n1. Default implementations for event accessors in interfaces\n2. Reabstraction in a class of default-implemented member\n3. `sealed override` with default implementations\n4. Use of `sealed` keyword for non-virtual interface members\n5. Implementing inaccessible interface members\n6. Implicitly implementing non-public interface members\n7. Not quite implementing a member\n8. asynchronous `Main`\n\n\n## Apr 19, 2017\n[C# Language Design Notes for Apr 19, 2017](LDM-2017-04-19.md)\n\n1. Improved best common type\n2. Diamonds with classes\n3. Structs and default implementations\n4. Base invocation\n\n\n## May 16, 2017\n[C# Language Design Notes for May 16, 2017](LDM-2017-05-16.md)\n\n1. Triage C# 7.1 features that didn't make it\n2. Look at C# 7.2 features\n3. GitHub procedure around new design notes and proposals\n4. Triage of championed features\n\n\n## May 17, 2017\n[C# Language Design Notes for May 17, 2017](LDM-2017-05-17.md)\n\nMore questions about default interface member implementations\n\n1. Conflicting override of default implementations\n2. Can the Main entry point method be in an interface?\n3. Static constructors in interfaces?\n4. Virtual properties with private accessors\n5. Does an override introduce a member?\n6. Parameter names\n\n\n## May 26, 2017\n[C# Language Design Notes for May 26, 2017](LDM-2017-05-26.md)\n\n1. Native ints\n\n\n## May 31, 2017\n[C# Language Design Notes for May 31, 2017](LDM-2017-05-31.md)\n\n1. Default interface members: overriding or implementing?\n2. Downlevel poisoning of ref readonly in signatures\n3. Extension methods with ref this and generics\n4. Default in operators\n\n\n## Jun 13, 2017\n[C# Language Design Notes for Jun 13, 2017](LDM-2017-06-13.md)\n\n1. Native-size ints\n2. Native-size floats\n\n\n## Jun 14, 2017\n[C# Language Design Notes for Jun 14, 2017](LDM-2017-06-14.md)\n\nSeveral issues related to default implementations of interface members\n\n1. Virtual properties with private accessors\n2. Requiring interfaces to have a most specific implementation of all members\n3. Member declaration syntax revisited\n4. Base calls\n\n\n## Jun 27, 2017\n[C# Language Design Notes for Jun 27, 2017](LDM-2017-06-27.md)\n\n1. User-defined operators in interfaces\n2. return/break/continue as expressions\n\n\n## Jun 28, 2017 \n[C# Language Design Notes for Jun 28, 2017](LDM-2017-06-28.md)\n\n1. Tuple name round-tripping between C# 6.0 and C# 7.0\n2. Deconstruction without `ValueTuple`\n3. Non-trailing named arguments\n\n\n## Jul 5, 2017\n[C# Language Design Notes for Jul 5, 2017](LDM-2017-07-05.md)\n\nTriage of features in the C# 7.2 milestone. They don't all fit: which should be dropped, which should be kept, and which should be pushed out?\n\n1. Static delegates *(8.0)*\n2. Native int and IntPtr operators *(7.X)*\n3. Field target *(anytime)*\n4. Utf8 strings *(8.0)*\n5. Slicing *(7.X)*\n6. Blittable *(7.2)*\n7. Ref structs *(7.2)*\n8. Ref readonly *(7.2)*\n9. Conditional ref *(7.2)*\n10. Ref extensions on structs *(7.2)*\n11. Readonly locals and params *(X.X)*\n12. ref structs in tuples *(don't)*\n13. Overload resolution tie breakers with long tuples *(use underlying generics)*\n\n\n## Jul 26, 2017\n[C# Language Design Notes for Jul 24 and 26, 2017](LDM-2017-07-26.md)\n\nWe started putting a series of stakes in the ground for nullable reference types, based on the evolving strawman proposal [here](https://github.com/dotnet/csharplang/issues/790). We're doing our first implementation of the feature based on this, and can then refine as we learn things from usage.\n\n1. Goals\n2. Nullable reference types\n3. Rarely-null members\n\n\n## Aug 7, 2017\n[C# Language Design Notes for Aug 7, 2017](LDM-2017-08-07.md)\n\nWe continued refining the nullable reference types feature set with the aim of producing a public prototype for experimentation and learning.\n\n1. Warnings\n2. Local variables revisited\n3. Opt-in mechanisms\n\n\n## Aug 9, 2017\n\n[C# Language Design Notes for Aug 9, 2017](LDM-2017-08-09.md)\n\nWe discussed how nullable reference types should work in a number of different situations.\n\n1. Default expressions\n2. Array creation\n3. Struct fields\n4. Unconstrained type parameters\n\n\n## Aug 14, 2017\n\n[C# Language Design Notes for Aug 14, 2017](LDM-2017-08-14.md)\n\nWe looked at the interaction between generics and nullable reference types\n\n1. Unconstrained type parameters\n2. Nullable constraints\n3. Conversions between constructed types\n\n\n## Aug 16, 2017\n\n[C# Language Design Notes for Aug 16, 2017](LDM-2017-08-16.md)\n\n1. The null-forgiving operator\n\n\n## Aug 23, 2017\n\n[C# Language Design Notes for Aug 23, 2017](LDM-2017-08-23.md)\n\nWe discussed various aspects of nullable reference types\n\n1. How does flow analysis silence the warning\n2. Problems with dotted names\n3. Type inference\n4. Structs with fields of non-nullable type\n\n\n## Oct 4, 2017\n\n[C# Language Design Review, Oct 4, 2017](LDM-2017-10-04.md)\n\nWe looked at nullable reference types with the reviewers, Anders Hejlsberg and Kevin Pilch.\n\n1. Overall philosophy\n2. Switches\n3. Libraries\n4. Dotted names\n5. Type narrowing\n6. The dammit operator\n7. Array covariance\n8. Null warnings\n9. Special methods\n10. Conclusion\n\n\n## Oct 11, 2017\n\n[C# Language Design Notes for Oct 11, 2017](LDM-2017-10-11.md)\n\nWe looked at the Oct 4 design review feedback for nullable reference types, and considered how to react to it.\n\n1. Philosophy\n2. Switches\n3. Dotted names\n4. Type narrowing\n5. Dammit operator type narrowing\n6. Dammit operator stickiness\n7. Array covariance\n8. Null warnings\n\n\n## Nov 8, 2017\n\n[C# Language Design Notes for Nov 8, 2017](LDM-2017-11-08.md)\n\nWe went over the status of the prototype for nullable reference types, to address outstanding questions and make any last minute calls before release.\n\n1. Constructors\n2. Dotted names\n3. Default expressions\n4. Should we track null state for nonnullable ref types?\n5. Inferred types for method type inference\n6. Inferred nullability in hover tips\n7. Smaller things not yet done\n8. Unconstrained generics\n9. Other issues\n\n\n## Nov 27, 2017\n\n[C# Language Design Notes for Nov 27, 2017](LDM-2017-11-27.md)\n\nWe went over the feedback on the nullable reference types prototype, and discussed how to address the top issues that people had found using the feature on their own source code.\n\n1. Interacting with existing, unannotated APIs\n2. Accommodating alternative initialization patterns\n3. Tracking nullable value types\n4. Tracking dotted names\n5. Special methods\n6. Filtering out nulls\n"
  },
  {
    "path": "meetings/2018/LDM-2018-01-03.md",
    "content": "﻿# C# Language Design Notes for Jan 3, 2018\n\nQuote of the Day: \"What about `CallerPoliticalAffiliationAttribute`?\"\n\n\n## Agenda\n\n1. Scoping of expression variables in constructor initializer\n2. Scoping of expression variables in field initializer\n3. Scoping of expression variables in query clauses\n4. Caller argument expression attribute\n5. Other caller attributes\n6. New constraints\n\n\n# Scoping of expression variables in constructor initializer\n\nShould an expression variable `x` introduced in a `this` or `base` initializer be available in the constructor body?\n\n``` c#\nC(int i) : base(out var x) { ... x ... }\n```\n\nIt feels natural and occasionally useful that `x` would be in scope in the body.\n\nAny reason not to allow it? Not at the language level. There's a design question as to how it's represented in `IOperation`, but that's not a language question.\n\n## Conclusion\n\nLet `x` be in scope in the whole constructor, including the body.\n\n\n# Scoping of expression variables in field initializer\n\nWhere should an expression variable `x` introduced in a field initializer be in scope?\n\n``` c# \nclass C\n{\n    int i = M(out int x)\n            .N(x), // here?\n        y = M(x);  // here?\n    int j = x;     // here?\n    int X => x;    // here?\n}\n```\n\nA number of options:\n\n1. Only in the same initializer expression\n2. In the whole field declaration, including initializers for subsequent fields\n3. In all subsequent initializers in the class declaration\n4. In the whole class body, including function members (so it would effectively become a private field if necessary)\n \nThere's something tempting about 4, especially considering the relatively loose scope rules we chose for expression variables inside statement lists.\n\n``` c#\nvoid M()\n{\n    int i = N(out int x);\n    int M() => x; // in scope here\n}\n\nclass C\n{\n    int i = N(out int x);\n    int M() => x; // why not here?\n}\n```\n\nAlso, if we ever do primary constructors, and want to allow statements interspersed with member declarations, we'll probably wish we did 4.\n\nHowever, there are also difficult questions with 4: can it be used before it is declared? Is it visible across partial classes? These are all questions that could be answered, but we are also a little uneasy making it so easy to \"accidentally\" declare an extra private field, in case some function members close over it.\n\nThat latter concern could be alleviated by reducing to option 3, but now the scope is weird, and most of the usefulness is gone. May as well reduce to 2 or 1 then.\n\n## Conclusion\n\nWe'll go with option 1. If you want to use expression variables to carry information between initializers, you'll instead have to do your initialization in the constructor body.\n\nThe script dialect will have to stay consistent, so declaration variables must be lifted to fields, and be visible in subsequent statements.\n\n\n# Scoping of expression variables in query clauses\n\nWhat should be the scope of an expression variable `x` that occurs in a query clause?\n\nIt seems desirable at first that the variables would carry over from clause to clause:\n\n``` c#\nfrom x in e\nwhere M(x, out var y)\nselect y\n```\n\nHowever, to do this we would need to perform much more semantic analysis of the query than we do today, before we lower. It feels out of touch with the syntactic flavor of queries today.\n\nInstead, a more reasonable approach may be to make it easier to carry multiple range variables forward from a `let` (and maybe `from`) clause, using deconstruction syntax:\n\n``` c#\nfrom x in e\nlet (m, z) = (M(x, out var y), y)\nselect z;\n```\n\n## Conclusion\n\nWe should allow expression variables in queries, but keep them scoped to the individual query clauses. In other words, they aren't range variables. They are normal variables scoped by the lambdas that we translate into.\n\n\n# Caller argument expression attribute\n\n[csharplang/issues/287](https://github.com/dotnet/csharplang/issues/287)\n\nThe [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.\n\nThere are solutions to that for API owners:\n\n1. Take a binary breaking change (that's probably what XUnit would do)\n2. Use different API names (won't be picked up automatically by old code)\n3. Change in ref assemblies only (might for `Debug.Assert`)\n\nIn summary, folks have a decent slate of options.\n\n## Conclusion\n\nFine to accept this one.\n\n\n# Other caller attributes\n\nWe are not comfortable with those just yet. We'd need to work on the details. For now we are suspicious of having a record of a lot of different information, and of the number of proposed ones in [csharplang/issues/87](https://github.com/dotnet/csharplang/issues/87).\n\n\n# Constraints\n\n[csharplang/issues/103](https://github.com/dotnet/csharplang/issues/103) and [csharplang/issues/104](https://github.com/dotnet/csharplang/issues/104) propose to allow the `Enum` and `Delegate` types as constraints. No special meaning, just stop disallowing them. That's a starting point. Adding keywords `enum` and `delegate` could be discussed later.\n\n[csharplang/issues/187](https://github.com/dotnet/csharplang/issues/187) proposes a contextual keyword `unmanaged`; we would represent it by putting a `ModReq` in the constraint of the parameter. It implies the `struct` constraint.\n\nReference assemblies are a problem: some tools produce reference assemblies that remove private fields from structs, which already leads to semantic problems in the compiler (definite assignment, allowing pointers to them), and now would lead to more. That's fundamentally not a language problem though.\n\n\n"
  },
  {
    "path": "meetings/2018/LDM-2018-01-10.md",
    "content": "﻿# C# Language Design Notes for Jan 10, 2018\n\n## Agenda\n\n1. Ranges and endpoint types\n \n\n# Ranges and endpoint types\nWouldn't it be nice to have a range type that work on any comparable? Possibly, but we're not eager to solve this right now.\n\nWe need to believe that our future selves can extend the language with some form of target typing, for instance. There's a burden on them (us) to be able to do that without a compat break (silent semantic change), e.g.: There's a type in the future that has conversions so that it would work one way in 7.3 and a different way in the future.\n\nWe probably want `..(int, int)` and `..(long, long)`. We want to treat those as usual operators, so they have to allow user defined conversions of the end points. We could consider blocking off normal conversions of the operands, but that's extremely distasteful.\n\nSo first tentative decision: There's `Range` (for ints) and `LongRange`. The `..` operators are built-in. There's an implicit conversion one way, and an explicit the other, also both built-in.\n"
  },
  {
    "path": "meetings/2018/LDM-2018-01-18.md",
    "content": "﻿# C# Language Design Notes for Jan 18, 2018\n\n## Agenda\n\nWe discussed the range operator in C# and the underlying types for it.\n\n1. Scope of the feature\n2. Range types\n3. Type name\n4. Open-ended ranges\n5. Empty ranges\n6. Enumerability\n7. Language questions\n\n# Scope of the feature\n\nThe scenario we are eager to address right now relates to indexing and slicing, where the elements of the range are contiguous integral indices into some data structure.\n\nWe want to design the language feature and API so that we address this scenario in the best possible way, without cutting off future support for range syntax in other scenarios, such as math, inclusion tests, etc., which require more generality.\n\n\n# Range types\n\nWe've talked about having a couple of types, say `Range` and `LongRange` representing general-purpose ranges over ints and longs, respectively. \n\nHowever a `Range` type that ranges over all ints might have a length that is greater than what an `int` can contain! We could represent the `Length` property with a `uint`, but then it doesn't interoperate well with all the `int`-based types and logic in the language and framework.\n\nAnd when we think about the core scenario, this pain would all be for naught: for indexing purposes, indices are always non-negative `int`s, and ranges of them would therefore never be longer than `int.MaxValue`.\n\nIt therefore seems that we should build a `Range` type specifically for indexing purposes, and have language support *only* for that, but in a way that we can generalize later. Specifically we can support conversion of `x..y` expressions only to `Range` for now, but open up for user-defined `..` operators later.\n\n## Conclusion\n\nDesign just an indexing-oriented `Range` type for now.\n\n# Type name\n\nShould the indexing-specific range type be called `IndexRange` or just `Range`? On the one hand it is a bit dangerous to use the good name for a special-purpose range type. On the other it is going to be *very* common, probably much more so than any other future range type. It is possible that we will someday have a `Range<T>` type that represents a more abstract mathematical notion of ranges. It will then be a bit odd for `Range` and `Range<T>` to be only loosely related to each other. \n\n## Conclusion\n\nWe can live with that risk. We think it is ok for this type to be called `Range`.\n\n\n# Open-ended ranges\n\nShould we allow open-ended range values, as represented by missing endpoints in the language syntax: `x..`, `..y` and `..`? It seems a significant loss of expressiveness if we don't. Scenarios for open-at-one-end are common, and scenarios for open-at-both-ends include multi-dimensional slicing, where we want a concise way to keep \"all of\" a given dimension: `tensor[.., ..1, ..]`.\n\nOpen-ended ranges are semantically different from just having `0` and `int.MaxValue` at the ends, because indexing/slicing APIs will require range arguments to be \"within range\" of the target data structure. Where `m..int.MaxValue` would therefore often yield an exception, an open-ended `n..` would just mean \"from `n` to the end, wherever that is\", and be legal as long as `n` is within range. Also, we can't just represent open-ended ranges as closed ones with the target data structure's min and max index substituted in, because range values can exist independently of a given target data structure.\n\nInternally, the `Range` type can e.g. use negative ints to represent open ends, so as not to waste space. This representation would not be visible from the outside though.\n\nCan we use nullable int in the constructor, to represent endpoints that may not be there? Then `null` means open in that end. We could have an `(int, int)` constructor overload for efficiency. Proposal for this to be written offline.\n\n## Conclusion\n\nYes, support open-ended ranges.\n\n# Empty ranges\n\nCan the `Range` type represent empty ranges? In that case, does the start point matter or not, or are all empty ranges the same? They might behave differently when you slice, depending of whether the start point is in range in the target data structure. (If not, they will throw).\n\nCan you index an empty array with an empty range? Yes. As long as it's in range; otherwise it throws. This is consistent with slices, spans and strings.\n\n## Conclusion\n\nIt's important to support empty ranges. The start point should matter even for empty ranges, in that indexing/slicing would throw if the start point of an empty range wasn't in range of the target data structure. \n\n# Enumerability\n\n`Range` should implement `IEnumerable<T>`, and needs to support the enumerable pattern of having a struct enumerator type. This is extra bulk in the type, but that's just how we do things.\n\nEnumeration on open ranges should probably throw.\n\n\n# Language questions\n\nGiven this there are a couple of questions on the language support, which we gathered here, but did not yet answer.\n\n## Should range expressions have `Range` as a natural type, or should they just convert to it?\n\nIf they have `Range` as a natural type, then you can infer `Range` as the type of a range expression: `var r = 3..5;`. And support for `foreach` naturally falls out: `foreach (var x in 3..5) { ... }`.\n\nHowever, this locks in `Range` as the \"primary\" range type for the language forever. It would mean that applicable overloads taking the `Range` type would always win over other overloads taking range expressions (once those are allowed).\n\nAlso, the `foreach` support based on this natural type wouldn't be very expressive: It wouldn't allow starting at negative numbers, or going backwards. \n\n## Other notations\n\nWe're fairly certain we want an inclusive `start..end` syntax. Presumably, open-ended ranges are expressed by leaving out one or the other endpoint.\n\nBut should there be other notations? In particular, it seems that a syntax for giving an index and a *count* would handle a common scenario; possibly *more* common. All current APIs are like that, and many (most?) use cases would take a given number of elements at a time.\n\nIt's not obvious what such a syntax should be, though. `start:count` and `start::count` both would have some ambiguity with existing syntax. \n\nAlso, at some point we might want to consider ranges that are exclusive of their endpoints. That's not a big deal with `Range` as the only target range type, where exclusive is just a question of `+1` or `-1`. But if at some point we start considering ranges of floats etc., inclusion or exclusion would need first class representation in the range types, and in the language's notation.\n\n"
  },
  {
    "path": "meetings/2018/LDM-2018-01-22.md",
    "content": "﻿# C# Language Design Notes for Jan 22, 2018\n\n## Agenda\n\nWe discussed the range operator in C# and the underlying types for it.\n\n1. Inclusive or exclusive?\n2. Natural type of range expressions\n3. Start/length notation\n\n\n# Inclusive or exclusive?\n\n``` c#\nvar numbers = ints[from..to];\n```\n\nShould this mean inclusive or exclusive of the element at `to`?\n\nNot many languages have *only* inclusive ranges. Apart from F#, they tend to either have exclusive ranges or have notations for both (at the upper end; the lower is always inclusive).\n\nPython uses exclusive ranges. A lot of people seem to be confused about it; it doesn't immediately gel with their intuition. The obvious advantage of course is that the collection's `Length` is directly allowed at the end:\n```\nvar s = a[0..a.Length];\n```\nIn foreach loops over ranges, if you use constant end points, again intuition seems to suggest inclusiveness:\n```\nforeach (var x in 1..100) { ... }\n\nforeach (var x in 0..100) { ... }\n```\n\nYou don't often use constants in practice, though, except as a zero lower bound. In fact, in F# it is often a bit of a pain to write a `for` loop for array iteration, for instance, because you need to subtract one at the end to avoid overrunning. \n\nLet's look at these four scenarios:\n\n1. Create a range, `incl`, that goes from `start` *through* `end`\n2. Create a range, `excl`, that goes from `start` *up to* `end` (but not including)\n3. Create a range, `rel`, that goes from `start` and has `length` elements\n4. Create an empty range, `emp`, that starts at 0.\n\nThis is what they will look like, given exclusive semantics, inclusive semantics, and a notation for `start:length` ranges:\n\n``` c#\n// Exclusive x..y\nRange incl = start..end+1;\nRange excl = start..end;\nRange rel  = start..start+length;\nRange emp  = 0..0;\n\n// Inclusive x..y\nRange incl = start..end;\nRange excl = start..end-1;\nRange rel  = start..start+length-1;\nRange emp  = 0..-1;\n\n// Relative x:l\nRange incl = start:end-start+1;\nRange excl = start:end-start;\nRange rel  = start:length;\nRange emp  = 0:0;\n```\n\nThe one that seems to have the least amount of computational gymnastics across the scenarios is the exclusive option. Also, the inclusive notation for an empty range is severely unappetizing! It is of course entirely possible that we have more than one syntax. \n\nOne idea is that when we start talking about scenarios outside of indexing, we simply have a different syntax; maybe one that is built in to language constructs for containment and iteration:\n\n``` c#\nbool b = x is in 3 to 5;\nforeach (var x in 0 to 100) { ... }\n```\n\n## Conclusion\n\nLet us go with `..` means exclusive. Since we've chosen to focus on the indexing/slicing scenario, this seems the right thing to do:\n* It allows `a.Length` as an endpoint without adding/subtracting 1.\n* It lets the end of one range be the beginning of the next without overlap\n* It avoids ugly empty ranges of the form `x..x-1`\n\n\n# Natural type of range expressions\n\nIf we allow `Range` to be the natural type of range expressions, the following will work:\n``` c#\nvar r = 4..6; // infer Range\n```\n\nOn the other hand, if we do this, `Range` will be forever tied to range expressions as the preferential type.\n\n## Conclusion\n\nWe're good with that. \n\n\n# Start/length notation\n\nWe may want an additional notation for specifying start and length. It can technically be added later, but if we want to do it we should try to do it now.\n\n\n"
  },
  {
    "path": "meetings/2018/LDM-2018-01-24.md",
    "content": "﻿# C# Language Design Notes for Jan 24, 2018\n\n## Agenda\n\n1. Ref reassignment\n2. New constraints\n3. Target typed stackalloc initializers\n4. Deconstruct as ref extension method\n\n# Ref reassignment\n\nProposal [here](https://github.com/agocke/roslyn/blob/4de95445af874269e74f9b022d83c89d85ec9669/docs/features/ref-reassignment.md).\n\nC# 7.0 added ref locals, but did not allow them to be reassigned with other refs. In C# 7.3 we are looking to allow that, and have a handle on the rules that need to be in place to make it safe.\n\n## Ref assignment expressions\n\nThe proposal adds a new ref-assignment expression of the form `r = ref v`. This makes `r` point to the storage location that `v` points to. The result of the expression is the variable designating that storage location. The variable can e.g. be evaluated or assigned to:\n\n``` c#\nwhile ((l = ref l.Next) != null) ... // linked list walk\n```\n\nThe linked list walk example shows why it is beneficial to have it be an expression form just like regular assignment, rather than just a statement form. Of course, just like with regular assignment, using it as an expression is easily overused; we think there is enough cultural awareness around this.\n\nInto the future we need to maintain a principle that expressions never start with `ref`. Therefore, `ref` in front of an expression is always part of an enclosing construct. This principle will help people (a little) when reasoning about these expressions.\n\n## Lifetimes\n\nThe compiler tracks lifetimes of variables, in order to make sure that a variable is not referenced by something that will outlast it. In C# 7.0 a ref local is simply created with the lifetime of the variable that it is initialized with.\n\nIn a ref assignment expression, the compiler maintains lifetime safety by requiring that the lifetime of the right-hand side is at least as long as the lifetime of the left-hand side.\n\n## Uninitialized ref locals\n\nWith ref reassignment it now becomes meaningful to allow ref (and ref readonly) locals to be left uninitialized at declaration. In that case what should be their lifetime? We can discuss that later.\n\n## Ref locals in looping constructs\n\nIteration variables declared in `foreach` and `for` loops can now be `ref`. In the case of `for` loops this only makes sense because ref reassignment is allowed.\n\nForeach iteration variables can never be reassigned in the body, and that is also the case for ref iteration variables: they cannot be ref reassigned.\n\n\n# New constraints\n\nLet's finalize the new forms of constraints.\n\n``` c#\nvoid M<T1, T2, T3>()\n    where T1: unmanaged\n    where T2: Enum\n    where T3: Delegate\n    {\n        \n    }\n```\n\n## Unmanaged\n\nIt should be called `unmanaged`, not some other word like `blittable`. F#, the runtime and the C# spec all use the term \"unmanaged\" for types that you can take a pointer to.\n\nIt can't be a keyword (that would be breaking) and not even a contextual keyword (in the sense that there's a syntactic context that determines it). Instead it needs to be semantically recognized, like `var`.\n\nJust like `var`, it can be escaped to make clear that you are using it as an identifier. If a type of that name is in scope, there's no way to get at the constraint meaning of it. So just like `var`, a devious person can declare an `unmanaged` type to prevent people from using the unmanaged constraint.\n\n\n## Delegate\n\nIt is useful to allow `System.Delegate` as a constraint, as it has several methods on it. It doesn't guarantee that the type argument would be a delegate type; it could be `Delegate` itself, or `MulticastDelegate`, etc. \n\nLet's just unblock `Delegate` and `MulticastDelegate` from being a constraint, and give it no special meaning. This is useful and *reduces* complexity in the language.\n\n## Enum\n\nSame for enum. We could imagine a special `enum` constraint that means `Enum + struct`, but instead let's just stop disallowing `System.Enum`. People should be allowed to manually write\n\n``` c#\nwhere T : struct, Enum\n```\n\nWe a special rule to allow `struct` and `Enum` together, since otherwise only interfaces are allowed to combine with the `struct` constraint.\n\n## Other non-sealed reference types?\n\nThere are a few other non-sealed reference types that are prevented from being used as constraints, e.g. `Array` and `ValueType`. While it is tempting to unblock them all, now that we're at it, let's not rock that boat until we have useful scenarios for it.\n\n\n# Target typed stackalloc initializers\n\n``` c#\nvar x = new int[] { 1, 2, 3 };               // allowed today\nvar z = stackalloc int[5];                   // z is int* for back compat\nSpan<int> zs = stackalloc int[5];            // target typed\nvar y = stackalloc int[] { 1, 2, 3 };        // should be allowed? y is int*\nSpan<int> ys = stackalloc int[] { 1, 2, 3 }; // should be allowed? y is Span<int>\n```\n\nThe `int*` is for back compat. In contexts other than this the natural type of `stackalloc` is `Span<T>`. That's a bit inconsistent, and there are probably other ways to skin the cat, but they would probably add more syntax and not reduce the inconsistency - just push it around. So we're good with this.\n\nShould we allow the element type to be inferred from the initializer, just as we do with array initializers? Yes.\n\n\n# Deconstruct as ref extension method\n\n``` c#\npublic static void Deconstruct(this int i, out int x, out int y);     // 1\npublic static void Deconstruct(this in int i, out int x, out int y);  // 2\npublic static void Deconstruct(this ref int i, out int x, out int y); // 3\n```\n\nCurrently 1 and 2 are eligible as deconstructors, whereas 3 is not. you could argue that it is an arbitrary and strangely specific limitation. On the other hand, 3 is probably never desirable, as a deconstructor should not wish to mutate its receiver! \n\nFixing this does not seem to add any value. Let's keep it the way it is.\n\n"
  },
  {
    "path": "meetings/2018/LDM-2018-01-31.md",
    "content": "﻿# C# Language Design for Jan 31, 2018\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n# Pattern-based fixed\n\nIf a type has a magic method of a certain name, which returns `ref` or `ref readonly`, you can `fixed` the type.\n\nIf you try to pin null or an empty array, you get a null pointer. It never throws. \n\nFor these new types, if it's a reference type we'll check first, and if it's null we'll return a null pointer. If the method wants to signal that there is nothing (e.g. an empty `ImmutableArray` struct), the proposal is to return a null ref. Those don't currently officially exist in the language, but you can manufacture one with unsafe code.\n\n\n## Extension methods\n\nThere are probably scenarios, such as adding the capability to an existing type based on an existing ref-returning member, or adding to certain constructions of a generic type.\n\nBut even because of consistency with how we've been doing pattern-based things for ages, we should allow it.\n\nFor string we want an instance method to win over the current way, but the current way to win over extension methods.\n\n\n# Ranges\n\nTerminology: say \"bounded/unbounded\" instead of \"open/closed\". \"Inclusive/exclusive\" for whether the endpoint is included.\n\n\n## Negative indices\n\nProposal to have negative indices:\n\n```c#\na[-5..-1] // Starts at length-5, excludes the last element\n```\n\nProposal for start/count syntax:\n\n``` c#\na[5..+10] // Starts at 5, goes to 15 (exclusive)\na[-10..+3] // Starts at length-10, goes to length-7 (exclusive)\n```\n\nIs it important to support collections with nonzero (positive) start index?\n\nShould the `Bind` method only take a length, not an index, for instance? Yes.\n\nThere might be the odd collection out there that's indexed, and doesn't start with 0. That's fine, but the feature is not for that. Those types wouldn't have methods that take ranges.\n\n## start/length notation\n\n`0..+-1`\n\n`-5..+3` // `-5..-2`\n`-5..+5` // `-5..`\n`-5..+7` // throw\n\n\n## lexing/syntax\n\nWe've been liking `:` for this, but it is highly ambiguous with many aspects of the language: ternary operator, named arguments, format specifiers in interpolated strings.\n\n``` c#\na[3..+7]\na[3.+7]\na[3.:7] // Not ambiguous   object o = b ? 3..: 7.: 9 ; \na[3..:7] // object o = b ? 3..: 7..: 9 ; find the range!\na[3:.7] // NO\na[3::7] // NO?\na[3:7] // NO\na[x:y] // NO\n```\n\nYou don't need elision on either end for this. You only use it if you want to give a length. And if you want to start from the beginning you may just use `..x`: length and end are the same.\n\n``` c#\n3..-x\nM(.:..)\n```\n\nColons only: ambiguous, and looks symmetric. `::` not as bad, only ambiguous with extern alias; realistic to semantically disambiguate.\nPlus: Looks like you are adding something, but clashes with unary +\n\n`.:` is the plan of record."
  },
  {
    "path": "meetings/2018/LDM-2018-02-05.md",
    "content": "﻿# C# Language Design Notes for Feb 2018\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\nIndex could be a type\n\nThen it's about syntax of how to express an Index that's either n from front or n from back.\n\nHow important is \"from end\"? It's definitely convenient, but its expressiveness is probably not super important.\n\nLots of problems with using \"-\", with overload resolution etc.\n\nLet's use \"^\" as a strawman. That takes away some of the ambiguity.\n\nThere's still a question as to how an overloadable \"^\" would work in the future. It would be a unary operator that returns something different than it takes. How would it be found, if it lives on the result type? There's target typing there, but it may not have a target type, or that may in turn come from overloaded operators. It would have to be handled similarly to conversion in some ways.\n\nA crazy idea: Use the existing `~` operator! It creates negative numbers, yes, but don't think of them as such. Think of them as integers from end. `~0` is `-1`, `~1` is `-2` etc. This is intriguing, because we'd need *no* extra language support, and just have a convention.\n\nQuite weird though!"
  },
  {
    "path": "meetings/2018/LDM-2018-02-07.md",
    "content": "﻿# C# Language Design Notes for Feb 7, 2018\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n# Tuple equality\n\nWe want to make it so that the `==` operator is delegated to the elements, but the choice of `&` operator shouldn't be up to the elements.\n\nWe can't think of this in terms of a user-defined `==` on the `ValueTuple<...>` overloads, since those don't have access to the specific `==` implementations of the type arguments.\n\n1. Same as `(tempA == tempC) && (tempB == tempD)`, taking whatever `&` operator eventually gets used.\n2. Same as `(bool)(tempA == tempC) && (bool)(tempB == tempD)` but only when there is an implicit conversion to `bool`\n2a. Same as 2 or `!(tempA == tempC).false && !(tempB == tempD).false`, so there are two ways to make the individual comparisons `bool`\n\nWe want to do 2a, so that we make every effort to turn the result of each comparison into bool. For `==` we would use the `false` operator, for `!=` we will use the true operator. But the `&` and `|` are applied to booleans.\n\nFor dynamic, let's look at what `if` does and probably do the same.\n\n\n# The fixed statement\n\nWe're adding support for a type to have a special method that returns a pinned ref.\n\n## Copy?\n\nShould that special method be executed on a copy or on an original l-value? We don't see good reasons to.\n- The method might want to change the state for the benefit of a future `fixed` or otherwise\n- Wasteful to copy big struct\n\n## Generics\n\nWe need to know if it's a struct or a class, to decide whether to copy (for the null check) or not (to preserve mutations in a struct).\n\nWe already solved this for `?.`. We can emit a check for whether the type is a reference type (check whether its default is null), and the JIT specializes.\n\n## Nullable\n\nNo lifting. You can do your own if you really want, but there is no way (for the compiler or user) to expose the value itself without copying. If you want to pin an specific nullable type you can, as long as an extension method is provided for it.\n\n## Ref extension methods\n\nAllow? Yes, same as for ref extension methods in general: Has to be called on a mutable l-value. For `in`, anything is fine.\n\n## Name of method\n\n`GetPinnableReference` is weird enough; we don't have to put \"Dangerous\" or something in the name.\n\n\n\n\n\n"
  },
  {
    "path": "meetings/2018/LDM-2018-02-14.md",
    "content": "﻿# C# Language Design Notes for Feb 14, 2018\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n\n# Ranges\n\n1. `Range`s are pairs of `Index`es, `Index`'es can be from beginning or end, `^` syntax or similar denotes from end\n2. `Range`s are pairs of `int`s, there's a convention of using ~x, that is, one's complement, for \"from end\"\n3. `Range`s are pairs of `Index`es, but the conversion from int uses the ~x convention rather than a new operator\n4. `Range`s are pairs of `int`s, all from beginning, but with a special bit for \"open at the end\"\n5. `Range`s are pairs of `int`s, all from beginning, with no notion of \"open\"\n\n\n1-3 hope to generalize to indexing in general, not just ranges.\n\n``` c#\ncoll[^x]; // option 1, from end\ncoll[~x]; // option 2-3, from end\n```\n\nFor people with existing indexers who want to add this, there are problems:\n\n- if you replace an `int` indexer with an `Index`, then you have a binary compat problem\n- if you add an overload, then option 2 and 3 would never pick that overload\n\nFor indexing, `^0` would mean \"length minus zero\", which would be out of range. So there's an irony where we do all this work to allow expressing 0 from end, which would not be a legal index.\n\nArguably, then, all of this bending-over-backwards is a consequence of wanting to express \"zero from end\" as the upper bound of an exclusive range.\n\nMaking it inclusive at the end makes `^0` or `~0` actually denote the last element. In which case, it's even more necessary to express \"zero from end\".\n\n`\"xxx|yyy|zzz\"`, you want to truncate based on the position of the pipe. You want to extract the `yyy`.\n\n``` c#\nvar startIndex = s.IndexOf(\"|\")+1;\nvar endIndex = s.IndexOf(startIndex, \"|\"); // -1 ?\nvar result = s.Substring(startIndex, endIndex-startIndex);\nvar result = s[startIndex..endIndex]\n```\n\nWhy should getting the end be easier than getting the beginning? Both should have to add/subtract one to get rid of the `|`. Or at least, so goes the argument for inclusive.\n\nThe empty range, on the other hand, is a very convincing argument for exclusive. `0..-1` is just really nasty.\n\nSpeculating about floating point ranges, having them inclusive-start, exclusive-end would actually likely be the best solution. They are imprecise by nature, so the only realistic way to get good adjacent \"buckets\" (where every element would be either in one or the others), is to not have symmetry between the endpoints on this.\n\n``` c#\nvar slice = myTensor[x1..x2, y1.:l, ^z1.., ..];\n```\n\nOnce you get multidimensional, everything \"from end\" gets really annoying to do manually, because even *getting* the end for a given dimension is quite involved.\n\nThere's a small design question around `^0..` - is it legal or not?\n\n- We're overwhelmingly slightly preferring exclusive.\n- We do think that the scenario of counting from end is important, at least for ranges\n- Unsure that its value extends enough to other indexing scenarios. \n\nExploring the hat options:\n\n1. Limit hat to range expressions\n2. Bake in Index to the language and return it from hat\n3. Conversion from expression to Index\n4. Typeless expression which gets meaning from range\n\n1 keeps our options open, but leads to a natural next request. 2 lets indices be computed independently. 3 leaves open betterness for the future, at the cost of not allowing `var i = ^x`. 4 is a semantic version of 1. Unclear if different things are allowed between the two.\n\nAdding the `Index` type and the `^` operator is heavy lifting for relatively limited gain. \n\nWould we add indexers to existing types that can index from-end? Maybe to some, probably not to arrays (for performance reasons). Probably not more or less depending on whether we use `~` or `^`.\n\nWe're still on the balance.\n\n"
  },
  {
    "path": "meetings/2018/LDM-2018-02-21.md",
    "content": "﻿# C# Language Design Notes for Feb 21, 2018\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n\n## Agenda\n\nVarious big and small issues around nullable reference types, preparing for upcoming prototypes\n\n\n# How are explicit casts interpreted?\n\n``` c#\n(object)null          // object?, with warning\n(object?)string.Empty // object\n(IEnumerable<object?>)new[]{string.Empty}    // IEnumerable<object> \n(IComparer<string?>)Comparer<object>.Default // IComparer<string>, with warning\n```\n\nFor the top two, there are two approaches you can think of:\n\n- nullability should be inferred from the expression\n- the cast represents an intent and we should honor it\n\nIt's to some degree a tension between existing code or the right design for new code.\n\nIf we were to infer nullability (rather than take it from the type), would nullability problems always be caught later on?\n\n``` c#\nobject o = ...;\nvar o = (object)...;\n\nclass X { object[] o; }\n```\n\nIf we make it more lax, then there's more of a disconnect between top-level nullability and nested nullability. \n\nIf we think of `?` not so much as a type thing but an observation on what's there, it doesn't seem so onerous to have it tracked locally.\n\nAnother approach: Have it be a different warning. Then you can switch it off separately, for legacy purposes.\n\nFor the casts:\n\n\n``` c#\n(string)null;   // A\nM((string)null);// B \nM((string?)x);  // C\nM((string?)F()) // D - F is unannotated, and I want to impose my understanding of what it is\nM((string)F())  // E - F is unannotated, and I want to impose my understanding of what it is\n```\n\nIn C you want to treat the argument as may-be-null, regardless of what is in x.\nIn B you could have a warning that is off in legacy code\n\nAssume M is generic, and we make type inference based on arguments. Then D and E both make sense - they influence the result type of M, maybe. We shouldn't wave these off, but they are in some sense separable. \n\nIn the prototype we could give you the choice. We could have it on by default, and the warning could tell you how to turn it off.\n\nC is either useless, or it means \"forget inferred nullability\". And it won't occur in old code.\n\nLet's expand B:\n\n``` c#\nM((string)y); // \n```\n\nSay this is legacy, and now M gets upgraded to take `string?`. And `y` is now possibly null. The warning on `(string)y` could be one of those that is turned off for legacy purposes.\n\nBetween two options:\n\nA: locals are implicitly nullable\nB: locals need explicit annotations like everything else, there's a concession to legacy\n\n\n\n\n\n"
  },
  {
    "path": "meetings/2018/LDM-2018-02-26.md",
    "content": "﻿# C# Language Design Notes for Feb 26\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n\"We introduced off-by-two errors!\"\n\n# Ranges\n\nPython has indexing from the end, as well as range endpoints from the end. The last element is -1.\n\nIn ranges, the only way to express \"to the end\" is then to omit the end point (since they're also exclusive).\n\nThere is no way to talk about the position at \"length\" in Python. We are concerned with that approach, because you can easily make an error where you compute \"distance from end\" into a variable as 0, then accidentally it means \"from beginning\" instead of \"from end\".\n\nThe benefit of `^x` and `~x` is that they can fully express the \"at index length\" index as `~0` or `^0`.\n\nPro `~`:\n* Just works\n* No new syntax or types\n\nAgainst:\n* No protection against bugs (accidentally using `-`)\n* Cannot add overloads that go from end\n* No documentation for whether the int indexer understands negative\n \nIf we do this just for `Range` (including maybe `^` syntax), then it's hard to add `Index` later.\n\nExisting types with indexers (e.g. arrays and strings) would be lots of work to evolve to make use of `Index` (or `Range` for that matter).\n\nCould the `int` conversion to `Index` also take negative numbers, but with the Python meaning? Then it would essentially \"subtract 1 from negative numbers\".\n\nThe problem with `~` is that it is off-by-one from Python. The `~` can only hide it so much, but if you look in the debugger, `~1` is `-2`!\n\nCurrent options:\n\n1. Do like Python: just live with \"0 from end\" not being expressible as a number; it's a special case (5)\n2. Use ~ (1)\n3. Add `Index` and `^` (6)\n4. Don't support \"from end\" (1)\n\nCould we disallow \"mixed\" ranges (one from beginning one from end)? That's not a reasonable restriction. `1..-1` strips off the double quotes, etc.\n\nWe're down to two options, 1 and 3. Let's take these through VB design as well, to see if we get new insights.\n\nMost likely to care are app developers, like web developers. Library authors will just be trading in Ranges that are already created.\n\n# Bestest betterness\n\n1. When gathering candidates, if one of them has inferred type arguments that do not satisfy constraints, we'll discard the candidate. This means you can overload on constraints!\n2. If you're in a static context, instance members are discarded, and vice versa. Only simple names in instance members will include both, as well as Color/Color situations\n3. Converting a method group to a delegate type, we consider a conversion where the return type is wrong, even though that conversion is an error. Methods with such parameters will also be weeded out.\n\nIn the first round this led to worse error messages (because we no longer pointed to the \"wrong\" method), but this has been fixed.\n\nThis has been done in a way to not affect type inference.\n\n\n# Fixed arrays"
  },
  {
    "path": "meetings/2018/LDM-2018-02-28.md",
    "content": "﻿# C# Language Design Notes for Feb 28, 2018\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\nParameters: Value parameters can be treated like locals, but we may not want to. Ref and out parameters need to be guarded by non-W warnings.\n\nIs it a problem that this can lead to two related warnings? Maybe a little bit, but it's actually mostly good. You can address the declaration of s2 in three different ways:\n\n* Make ns non-null before assigning\n* Put a question mark on s2\n* Turn of W warnings\nWould be weird if that last one introduced another warning!\n\nType inference:\n\nWe could have `var` always have `?`. \n\n``` c#\n    static T[] MakeStack<T>(T element)\n    {\n\n    }\n    static int GetLengthOfMiddleName(Person p)\n    {\n        string? middleName = p.MiddleName;\n\n        //return middleName.Length;\n        if (middleName is null) return 0;\n        var stack = MakeStack(middleName); // infer string[] or string?[]\n    }\n\n\n        bool b = false;\n        string s = null; // suppressible\n        var s2 =\n            //(b ? s : s);\n            Choose(b, s, s);\n        var l = s2.Length; // not suppressible\n\n```\n\nShould we have type inference depend on the declared or the flowed type state? We reiterated that discussion, but conclude (again) that it's the null state that counts. This maximally helps avoid unnecessary warnings on legacy code.\n\n## Cast and non-null\n\n``` c#\nvar s1 = \"Hello\"; // But I want to assign null later\nvar s2 = (string?)\"Hello\"; // Either disallowed, makes no difference or forgets null state\nvar? s3 = \"Hello\"; // Nullable but keeps the null state\n```\n\nSo `var?` would be more useful than casts for `var` scenarios (because you are declaring a variable whose null state matters later). For generic arguments it doesn't matter to keep the flow state, so `(string?)` cast works fine.\n\nIt's a little weird that `s2` and `s3` don't work quite the same way. They do today.\n\nStill, as a plan of record let's do this.\n\nSo we keep the casts, and tentatively keep `var?`.\n\n\n\n\n\n\n"
  },
  {
    "path": "meetings/2018/LDM-2018-03-14.md",
    "content": "﻿# C# Language Design Notes for Mar 14, 2018\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n# Indexing without pinning\n\nFixed size buffer is formally a pointer, but when we are indexing it we don't need to materialize it as a pointer. We could stop requiring that even when the container is movable, and let you index fixed buffers that are movable. \n\n## Conclusion\n\nDon't require fixed statement for indexing. Still unsafe operation. This not only makes the code a bit simpler, but can avoid significant overhead for pinning.\n\n# MVP Summit feedback\n\n# Records\n\nPeople are interested in getting rid of the boilerplate. Some just worry about member-wise repetition, others also about value semantics.\n\nCombines well with some (almost any!) sort of discriminated union feature to provide the value of F# and other functional languages, that you can see your whole data model on half a page.\n\n## Conclusion\n\nThis is important. We need to understand existing scenarios, and avoid a big cliff if you want to go advanced. We need to be super pragmatic.\n\nWe want both records and discriminated unions, and we succeed when both are independently useful but fit well together.\n\nThis is *not* a scenario for source generators. They may be able to address it, but for generally useful (not domain-specific) syntax like this, it should be a proper language feature.\n\n# Anonymous implementations\n\nLots of scenarios around adaptation and delegation. Implementing `IEquatable` and `IComparable`, or `IEqualityComparer` and `IComparer`.\n\nHas some interaction with records or primary constructors, in that the context for construction is ambient, and you might want e.g. constructor bodies directly in the body of the \"class\".\n\n## Conclusion\n\nIf we can make it nice enough we are not adverse to this, but it probably doesn't have the highest priority.\n\n\n# Async Disposal\n\nYeah do it.\n\nSome discussion more generally about easier alternatives to using. The simplicity of C++ RAII is attractive, maybe there are ways we can simplify, e.g. like F#'s use on variable declarations. Also defer statements.\n\n\n# Source generators\n\nLots of interest in that. This is not a language thing, it is more a Roslyn/tooling feature. Let's try to raise it with them.\n\n\n# Nullable\n\n## On-the-side annotations\n\nMostly useful during a transition period. May be a lot of work of only temporary importance. On the other hand, the lack of it may hinder adoption.\n\nWe should keep an open mind as to what such a feature would look like. But all versions we can think of have very significant challenges.\n\nNote that a library vendor can annotate their public surface area without dealing with their own warnings.\n\nThree phases:\n\n1. Annotate public surface area with intent\n2. Turning on warnings internally\n3. Annotating locals\n\nLevel 1 is a bit dangerous: you may be wrong about your intent if you don't check against your own source code. But it may be the least bad way of moving forward for a given library.\n\n## Adoption\n\nThere are challenges to adopting on existing code base that aren't there for new code.\n\n\n# Nullable constructors\n\nAnnoying when you initialize differently. Solution must be some combination of easier opt-out and more analysis.\n\nWe need to think about this more. This is when you trust someone else to initialize it, and you want to force them to do it with a non-null value.\n\nLazy isn't a problem, because the underlying field owns up to its nullability.\n\n# Warnings\n\nThere are certainly places where the same \"null\" leads to multiple dereferencing warnings. We could complain about only the first one. There may be other places where there are cascaded warnings. (Also the W warnings). We can probably satisfy most of these.\n\nWe have to keep an eye on common uses and make sure people have a decent experience.\n\n\nComing up:\n\nMore nullable (type parameters, special members/annotations)\nTriage\nRange\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "meetings/2018/LDM-2018-03-19.md",
    "content": "﻿# C# Language Design Notes for Mar 19, 2018\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n## Agenda\n\nTriage\n\n# 7.3 \n\nMoved undone 7.3 features to 8.0.\n\n# Allow default in deconstruction\n\nWe allowed for `==`, so it seems we should also allow it for assignment and initialization.\n\nShould probably not require `ValueTuple`, but that's more of a compiler thing.\n\n\n## Conclusion\n\nThe feature is a good idea. Even though it's simple, we should not rush it into 7.3. 8.0.\n\n``` c#\ncase Customer { MiddleName: \"\" or null }\n```\n\n# and, or and not patterns 1350\n`not` feels useful. `and` is hard to come up with scenarios for. `or` has more scenarios, but may be better served by a `in { 1, 2, 3 }` style pattern.\n\n``` c#\nif (x is not string s) { ... }\nelse { ... /* s */ }\n```\n\n`not` would cause definite assignment to \"flip\". Should `s` be disallowed in a `not` pattern. \n\nThe `{}` pattern for not null is a bit cryptic. `not null` would certainly be more direct.\n\n## Conclusion\n\nPunt to 8.x, when we know more of the rest of the pattern story.\n\n\n# partial type inference #1349\n\nWe've talked about this many times in the past, but couldn't settle on a syntax that was nice enough and worth its while.\n\nA 4th option: allow M\\<string>(...) to match an M with more type parameters. But that probably goes against intuition and would complicate overload resolution.\n\nFor 2: Just commas is known from typeof, so that concept is already in the language, though you can't mix \"there\" and \"not there\" today.\n\n## Conclusion\n\n8.X is when we'll look at it again.\n\n\n# Permit `t is null` for unconstrained type parameter #1284\n\nFor null we special case type parameters in all other kinds of places, so this is the only place where you can't.\n\nAlso, `t is 3`. We allow *type* patterns, but not constant patterns.\n\n## Conclusion\n\nAbsolutely should do this. Mark as 8.0.\n\n\n# Implicitly scoped using #114 #1174\n\nWe have sympathy for this syntactic sugar, and we'd be interested in allowing it. It seems related to similar features, such as \"defer\" statements (avoids nesting `try/finally`). \n\nAlso fits nicely with the work we already did with expression variable scoping.\n\nAlso namespace without curlies, where you just say `namespace X.Y;` and it's in force for the remainder of the file.\n\n## Conclusion\n\nDiscuss at 8.X. Could get pulled up to 8.0.\nLet's also put defer and namespace into 8.X for consideration then.\n\n# User-defined positional patterns\n\nA next step from recursive patterns.\n\n## Conclusion\n\nLet's revisit in 8.X when recursive patterns have played out.\n\n\n\n\n"
  },
  {
    "path": "meetings/2018/LDM-2018-03-21.md",
    "content": "﻿# C# Language Design Notes for Mar 21, 2018\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n## Agenda\n\nWe discussed various open questions around nullable reference types\n\n\n# The null-forgiving operator\n\n## Name\n\nNull-acquiescing\nNull-forgiving\nNull-silencing\nNull-quieting\nDarnit\n\n## What does it do?\n\nChanges top-level nullability to not-null, as well as silencing warnings even on nested nullability\n\n``` c#\nvoid M(string? ns, List<string?>? ln)\n{\n    string s = ns!; // silence and change nullability\n    var s2 = ns!; // silence and produce string\n    ln = null;\n    List<string>? l = ln!; // silence and change\n    var l2 = ln!;\n    // Idea 1\n    l! // change nullability at the top level\n    l<!> // idea: change nullability at the nested level\n    // Idea 2\n    (List<string>?!)ln; // I do a cast that should warn but ! silences it\n    List<string>? l3 = (!)ln; // Shorthand\n}\n```\n\nShould `!` only change top-level nullability, and not suppress nested diagnostics? Or the other way around? Is it a problem that it does both and \"suppresses too much\".\n\nSince we made affordances for legacy code, the need for passing `null!` for instance is less: unannotated APIs already suppress warnings.\n\nScenarios for `!` now that legacy APIs aren't a scenario:\n\n1. I'm in the middle of converting my own code; need them at the boundary\n2. The compiler can't figure it out, but I'm right\n\nGreat example of the latter:\n\n``` c#\nList<string?> strings;\nvar query = strings.Where(s => s != null).Select(s => s.Length); // What?? Why warning?\n```\nHere you can put the `!` in `s!.Length`, but what if you have\n\n``` c#\nvoid M(IEnumerable<string> source) { ... }\nList<string?> strings;\nM(strings.Where(s => s != null)); // What?? Why warning?\n```\n\nHere you need to suppress on the nested nullability, because you know better.\n\nCurrently you can say `!` at the end of the argument to set it right. Should that be a different syntax?\n\nWhat's the problem with `!` doing both jobs?\n\n``` c#\nvoid M(string? ns, List<string?>? ln)\n{\n    // I happen to know that if ln is not null, it doesn't contain nulls\n    List<string>? l = ln!; \n    _ = l.Count; // warning?\n}\n```\n\nNow `l.Length` is not warned on because `!` did \"too much\". We wanted it to silence warnings, but it also changed the null state.\n\nThe simplest fix with current semantics would be to cast to a nullable type:\n\n``` c#\n    List<string>? l = (List<string>?)ln!;  // or\n    var l = (List<string>?)ln!;\n```\n\nProposals:\n\n1. Change null state and suppress 4\n2. Two syntaxes 5\n3. Only suppress warnings 1\n4. Only change null-state 0\n\nApproachable and easy to use. They are all about telling the compiler to shut up when you know what you're doing.\n\nFor 3, the things we would make people do to change the null state would also be a hurdle.\n\nIf we separate it, one may be a temporary feature that will go away over time, once people have transitioned.\n\nWe're not going to settle this today. The prototype does \"1+\" which is even more lenient than 1.\n\n\n\n# Special methods\n\n# Hidden diagnostic"
  },
  {
    "path": "meetings/2018/LDM-2018-03-28.md",
    "content": "﻿# C# Language Design Notes for Mar 28, 2018\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\nRanges\n\n# Shipping a prototype\n\nWe would like to ship a prototype of ranges, in order to get feedback and settle the remaining decisions.\n\nWe would need to offer the Range type, maybe as a NuGet.\n\nBut it would also be nice to offer range-enhanced other types, like `Span<T>` and maybe arrays.\n\nMaybe the compiler can fake out special indexers in the prototype. Or we also add extension indexers.\n\nTying it to revs of .NET Core previews may be too sluggish, and fraught with dependencies.\n\nOr we create a wrapper type for Spans with the extra behavior, and smooth over the edges as best we can (implicit conversions etc)\n\n## Conclusion\n\nLet's do:\n\n1. A temporary \"language feature\" that's extension indexers based on method names\n2. Range support in the language\n3. A preview NuGet package with `Range`, associated types and \"extension indexers\" on known types\n\n\n# Which feature?\n\nWe have two options:\n\n1. Do like Python: just live with \"0 from end\" not being expressible as a number; it's a special case\n2. Add Index and ^\n\nThe first one is the more restrictive, and also the cheaper one (from both work and number of abstractions). This will help us understand whether people need the extra.\n\nBut not supporting \"from end\" is too restrictive; we have very good reason to believe people need that.\n\n\n# Nested stackalloc\n\nIssue #1412, trivial to implement in 8.0, where the stack-spilling machinery is there anyway for pattern matching.\n\n\n# Exhaustiveness in switch expressions\n\nShould non-exhaustiveness be an error or a warning? If warning, what should happen at runtime?\n\nFor now, it's a warning, and if you get there we throw a new exception type for this.\n\n"
  },
  {
    "path": "meetings/2018/LDM-2018-04-02.md",
    "content": "﻿# C# Language Design Review Apr 2, 2018\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n\n# C# 8.0\n\nTag with needs runtime support or ecosystem support\nProcess: make it more clear where we are. Help people understand when beating on a feature would be wasting their time.\n\n# Nullable\n\nMake sure we work backwards to understand how long it takes to build the whole experience.\n\n## Dotted names\n\nWe probably have a good level of invalidation.\n\n## Type strengthening\n\nBased on null state and `!`. Should definitely keep that.\n\n## !\n\nBecause `!` only applies \"right here\", it is ok to also silence warnings recursively. But we should not consider automatically flowing `!` on the given execution path then, because you may not always want to silence all warnings on the variable subsequently.\n\n## Unannotated assemblies\n\nMaybe there should be a warning that you are referencing unannotated assemblies.\n\n## Tracking non-null variables and \"W\" warnings\n\nUnderstand the motivation. This is ok.\n\n## Type parameters\n\nUnconstrained may be either nullable or nonnullable, so we have to be defensive. That's quite restrictive, but probably right.\n\n## Structural relationships\n\nIn TypeScript there are more type relationships because of structural types. We don't even get to first base here.\n\n# Ranges\n\n## Open\n\nSure about syntax? Should there be `*` instead?\n\n## From end\n\nIndexing from end is probably more common in Python than any ranges at all! Cutting that off with `-x` syntax is a shame.\n\nIf we weren't doing `^`, just do ranges with positive numbers. Solve the \"from end\" problem in general or not at all.\n\n## Conclusion\n\nIf indexing and multiple dimensions are in the core syntax, might as well do the whole enchilada. Optimize in compiler when using `^` on arrays and strings.\n\n\n"
  },
  {
    "path": "meetings/2018/LDM-2018-04-04.md",
    "content": "﻿# C# Language Design Notes for Apr 4, 2018\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n## Agenda\n\n# Design review follow-up\n\n## Ranges\n\nLet's flip what we prototype to implement the `Index` and `^` option.\n\n``` c#\n(Index) ^ i\n```\n\n## Nullable\n\nLet's start having the discussion on external annotation soon, bringing in the right people from BCL's etc.\n\nOne proposal for external annotations:\n\n``` c#\n[Nullable(typeof(MyClass))]\nclass C\n{\n    static object f1;\n    static object? f2;\n}\n```\n\nNice because it's source based.\n\nMay also use or mirror JetBrains' annotations. https://github.com/JetBrains/ExternalAnnotations\n\nOffer the capability just for BCL vs for general libraries?\n\n\n# Ordering of ref and partial keywords\n\nThere's a strict ordering around `ref` and `partial` preceding `struct`. We need to relax a bit, or a lot:\n\n1. `ref partial` and `partial ref` are both allowed, but need to be right before `struct`\n2. allow `ref` and `partial` anywhere in the modifier list\n\nLet's do 2, since that leads to a more consistent language. No reason to have special limitation on some modifiers, even though there might be guidance (and code style enforcement in the IDE) to put things in a certain order.\n\n# Patterns\n\nIn Roslyn, we would probably put deconstructors that only return the \"important\" data, whereas non-optional tokens would be left out. (We're essentially reinventing abstract syntax tree.) If we evolve the node, we can add another overload of the deconstructor with more out parameters.\n\nThe code gen is now roughly as efficient as what you would have written, though it doesn't know about testing `Kind` fields, of course (which actually isn't always more efficient).\n\n## Order of evaluation in pattern-matching\n\nGiving the compiler flexibility in reordering the operations executed during pattern-matching can permit flexibility that can be used to improve the efficiency of pattern-matching. The (unenforced) requirement would be that properties accessed in a pattern, and the Deconstruct methods, are required to be \"pure\" (side-effect free, idempotent, etc). That doesn't mean that we would add purity as a language concept, only that we would allow the compiler flexibility in reordering operations.\n\nIt may be a little disconcerting not to specify order of evaluation, but if patterns don't do what user code will do, they will be slower and will not be generally adopted/useful.\n\nPeople generally don't care what the spec says - they care if something changes release over release. So it's more important that the compiler doesn't change what it generates from version to version.\n\n### Conclusion\n\nWe're good with this. We don't want to slow down pattern matching just to guarantee order of evaluation when people do something side effecting where they shouldn't.\n\nWe'll make an effort to discover if changes to the compiler change the output of existing code. Then we'll have a discussion about whether that is warranted.\n\n## Range Pattern\n\nIf we have a range operator `1..10`, would we similarly have a range pattern? How would it work?\n\n``` c#\n    if (ch is in 'a' to 'z')\n    switch (ch) {\n        case in 'a' to 'z':\n```\n    \n### Conclusion\n\nWe like the idea, but are unsure about value yet, and probably want to pursue it in connection with `foreach` and `from` uses.\n\n\n## `var` deconstruct pattern\n\nIt would be nice if there were a way to pattern-match a tuple (or Deconstructible) into a set of variables declared only by their designator, e.g. the last line in this match expression\n\n``` c#\n    var newState = (GetState(), action, hasKey) switch {\n        (DoorState.Closed, Action.Open, _) => DoorState.Opened,\n        (DoorState.Opened, Action.Close, _) => DoorState.Closed,\n        (DoorState.Closed, Action.Lock, true) => DoorState.Locked,\n        (DoorState.Locked, Action.Unlock, true) => DoorState.Closed,\n        var (state, _, _) => state };\n```\n\n(Perhaps not the best example since it only declares one thing on the last line)\n\nThis would be based on some grammar like this\n\n``` antlr\nvar_pattern\n    : 'var' variable_designation\n    ;\n```\n\nwhere the _variable_designation_ could be a _parenthesized_variable_designation_, i.e. generalizing the current construct.\n\nTo make this syntactically unambiguous, we would no longer allow `var` to bind to a user-declared type in a pattern. Forbidding it from binding to a constant would also simplify things, but probably isn't strictly necessary.\n\nAt a recent LDM it was suggested that `var` could perhaps be used as a placeholder for an unknown type taken from context. But that would conflict with this usage because this usage changes the syntax of what is permitted between the parens (designators vs patterns).\n\nThis is implemented in the current prototype, in which `var` is now a contextual keyword.\n\n### Conclusion\n\nThis is a useful shorthand, and we already love it in C# 7.0 deconstructing declarations. We should have it here too, for symmetry and brevity.\n\n\n## ref/lvalue-producing pattern switch expression\n\nAs currently designed, the “switch expression” yields an rvalue.\n\n``` c#\n    e switch { p1 when c1 => v1, p2 when c2 => v2 }\n```\n@agocke pointed out that it might be valuable for there to be a variant that produces a ref or an lvalue.\n\n1.\tShould we pursue this?\n2.\tWhat would the syntax be?\n    `e switch { p1 when c1 => ref v1, p2 when c2 => ref v2 }`\n\nYou could argue that while the conditional (ternary) operator is often used in perf-sensitive code, and combining with `ref` was important there, it's less likely to see a combination of patterns and high-performance code.\n\n### Conclusion\n\nThis feels right, but is not all that important. Let's keep it on the back burner.\n\n## switching on a tuple literal\n\nIn order to switch on a tuple literal, you have to write what appear to be redundant parens\n\n``` c#\nswitch ((a, b))\n{\n```\n\nIt has been proposed that we permit\n\n``` c#\nswitch (a, b)\n{\n```\n\nThere are a couple of ways of doing it:\n\n1. Make the outer parens optional when there is a tuple literal\n2. Make the inner parens optional when there is a tuple literal\n3. It's a list that's part of the switch statement (and expression, when we get there)\n\n## Conclusion\n\nLet's do 1. This means that in certain cases switch statements will no longer have parentheses, so analyzers that expect that will have to adjust.\n\n"
  },
  {
    "path": "meetings/2018/LDM-2018-04-25.md",
    "content": "﻿# C# Language Design Notes for Apr 25, 2018\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n## Agenda\n\n\n# Warn on nullable ref type argument when T has `class` constraint\n\n``` c#\nstatic void F<T>(T t) where T : class { t.ToString(); /* no warning */ }\nF(maybeNull); // warning: string? does not satisfy 'class' constraint\nF<string?>(string.Empty); // warning: string? does not satisfy 'class' constraint\n```\n\nThis is a real danger, and we should be warning here.\n\nNote that in both cases the warning is about constraint checking: even in the second line we infer `string?` and it warns on constraint check.\n\nWe should probably have the error message say that this is because of nullability.\n\n\n# Warn on nullable reference type argument when T has non-nullable reference type or interface type constraint\n\n``` c#\nstatic void F<T>(T t) where T : IDisposable { }\nF(maybeNull); // warning: Stream? does not satisfy 'IDisposable' constraint\n```\nYes, warn for same reasons.\n\nWe also want to warn (or error) on inconsistent nullability in constraints. Specifically if one constraint is known to be non-nullable and another is known to be nullable.\n\nWhat about\n\n``` c#\nclass C<T, U, V> where T: class? where U : T, IDisposable where V : T, IDisposable?\n{\n    // Fine\n}\nclass D<T, U, V> where T: class where U : T, IDisposable where V : T, IDisposable?\n{\n    // Warn on V\n}\n```\n\n``` c#\n... where T : Node<T>?\n... where T : Node<T?> // both currently allowed, but not where T : Node<T?>?\n... where T : class, INode<T?>\n... where T : class?, INode<T>?\n```\n\n``` c#\nstatic void F<T>(T t) where T : IFoo<string?> { }\nIFoo<string> foo;\nF(foo); // warning, unless IFoo is covariant\n```\n\nAnother kind of clash:\n\n``` c#\ninterface IBar : IFoo<string> {}\nstatic void F<T>(T t) where T : IFoo<string?>, IBar { }\n```\n\nWe want to warn on this: maybe find shared base interfaces between the two constraints, and check if they have consistent nullability.\n\nOther, slightly more complex example, same conclusion: \n``` c#\ninterface IBar : IFoo<string?> {}\nstatic void F<T, U>(T t) where T : IFoo<U>, IBar where U : class{ }\n```\n\n\n# Allow nullable reference types and interface types as constraints \n\n`where T : Person?, IDisposable?`\n\nYes\n\n# Allow `class?` constraint\n\nYes\n\nHow do we express in metadata?\n\nLet's put top-level nullability as an attribute on the type parameter itself, rather than on the constraints. We can noodle more on this later.\n\n# Allow `object` constraint\n\n``` c#\nstatic void F<T>(T t) where T : object { }\nF(maybeNull); // warning: constraint violated\n```\n\n## Need to talk about relationship to value types soon\n\n``` c#\nint? i = null;\nobject o = i;\no.ToString();\n```\n\n# Allow `object?` explicitly?\n\nIt's the \"most general\" constraint that is implied by unconstrained generics. Today we disallow `object` because of that. \n\nWe don't know that this is a terribly useful restriction today, but we'll keep doing it (now with `object?`) unless we get evidence to the contrary.\n\n\n# Warn on dereference of T when T is unconstrained?\n\nYes, if a type parameter `T` can be instantiated with a nullable reference type, then we should track null state and warn on unguarded dereference.\n\nThe warning when occurring on unconstrained generics might suggest using the `object` constraint.\n\n\n# Warn on assignment to `object` of unconstrained `T`?\n\nYes. This can be a `W` (cosmetic) warning when the `object` variable is a local.\n\n\n# default(T) with unconstrained T\n\n``` c#\nT M<T>()\n{\n    T t = default(T); // W warning\n    return default(T); // safety warning\n}\n```\n\nThis is something completely safe. I don't want it to warn!:\n\n``` c#\nT M<T>()\n{\n    var t = default(T);\n    if (something) t = somethingelse;\n    if (t != null) WriteLine(t.ToString());\n}\n```\n\nThis could be an argument for allowing `T?` that is not about special methods. Or it is an argument against having the W warnings at all.\n\nLet's keep this example around and revisit. But for now, let's consider `default(T)` to be potentially null, and therefore warn on its unguarded use.\n\n\n# Annotations\n\nWe would like to deal with methods with special null semantics, such as string.IsNullOrEmpty, TryGetValue, Assert.NotNull, Object.Equals, Object.ReferenceEquals.\n\nWe'll come back to this later.\n"
  },
  {
    "path": "meetings/2018/LDM-2018-04-30.md",
    "content": "﻿# C# Language Design Notes for Apr 30, 2018\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n\n# Switch expressions\n\nCurrent syntax:\n\n``` c#\ne switch\n{\n    1 => \"one\",\n    2 => \"two\",\n    var x when x > 2 => \"too many\",\n    _ => \"too few\"\n}\n```\n\nNo `default` - instead use `_`.\n\nIf the compiler thinks there are cases you don't handle, it'll warn. If you actually don't handle a case we throw an exception (NRE for prototype, something else in the long run).\n\nAlso discussed:\n\n- use `match` instead of `switch`\n- keyword first, followed by parens, like `switch` statement\n- or without parens\n- optional implicit default at the end?\n\nThe current thing is nice for error recovery.\n\nThe lack of statements inside may be a frustration, but that's orthogonal. Let's leave it for now.\n\n## Exploration\n\nIs there a way to instead generalize the syntax from the conditional (ternary) operator? After all, semantically speaking this could be viewed as a general form: Conditional operators and switch expressions on bool are semantically equivalent.\n\n``` c#\ne\n    ? true => e1 \n    : false => e2\n```\n\nThe fact that you know the number of colons today means you can have fewer parentheses than you would get away with here.\n\n``` c#\ne ?\n    true => e1 ? x : y :\n    false => e2\n```\n\nIt's not in fact obvious whether there should be many `?`s and one `:`, or one `?` and many `:`s:\n\n``` c#\n// Interpret ? as following the tested expression, and : as a separator of test/result pairs\ne\n    ? 1 => \"one\"\n    : 2 => \"two\"\n    : var x when x > 2 => \"too many\"\n    : _ => \"too few\"\n\n// Interpret ? as introducing test/result pairs, and : as introducing the fallback result\ne\n    ? 1 => \"one\"\n    ? 2 => \"two\"\n    ? var x when x > 2 => \"too many\"\n    : \"too few\"\n```\n\nThe `=>` glyph is probably not right in a `?:` style syntax. It would have to be something else that more clearly signals pattern/result pairs.\n\n``` c#\ne\n    ? 1 -> \"one\"\n    ? 2 -> \"two\"\n    ? var x when x > 2 -> \"too many\"\n    : \"too few\"\n    ```\n    \n## Considering our options\n\n``` c#\n// Compromise - terser\ne ? { 1: \"one\", 2: \"two\", var x when x > 2: \"two many\", \"too few\" }\n\n// Formatted\ne ? \n{ \n    1: \"one\", \n    2: \"two\", \n    var x when x > 2: \"two many\", \n    \"too few\" \n}\n\ne switch \n{ \n    1: \"one\", \n    2: \"two\", \n    var x when x > 2: \"two many\", \n    \"too few\" \n}\n\n// Some of these in context of a var\nvar x = e\n    ? 1 -> \"one\"\n    : 2 -> \"two\"\n    : var x when x > 2 -> \"too many\"\n    : _ -> \"too few\";\n\nvar x = e ? \n{ \n    1: \"one\", \n    2: \"two\", \n    var x when x > 2: \"two many\", \n    \"too few\"\n};\n\nvar x = e switch \n{ \n    1: \"one\", \n    2: \"two\", \n    var x when x > 2: \"two many\", \n    \"too few\" \n};\n\n// Some of these as one-liners in a method call\n\nM(x switch { null => 0, _ => x.Length });   // 1\nM(x switch { null: 0, x.Length });          // 2\n\nM(x ? null -> 0 : _ -> x.Length);           // 3\nM(x ? { null: 0, x.Length });               // 4\n\nM(x ? null -> 0 : x.Length);                // 5\nM(x ? { null -> 0, x.Length });             // 6\n```\n\nArgument against 1:\n\n``` c#\nstrings.Select(x => x switch { null => 0, _ => x.Length });   // Lots of => with different meaning\n```\n\nArgument against `->`: Has meaning in unsafe code\n\nArgument against `:` as used in 4: Clashes with other uses of `:`. \n\nWhere input is an expression rather than a variable:\n\n``` c#\nM(e switch { null => 0, var x => x.Length });   // 1 - 0\nM(e switch { null: 0, var x: x.Length });       // 2 - 13 - 6\n\nM(e ? null -> 0 : var x -> x.Length);           // 3 - 1\nM(e ? { null: 0, var x: x.Length });            // 4 - 6  - 3\n\nM(e ? { null -> 0, var x -> x.Length });        // 6 - 0\n```\n\nWe might want to allow the last thing to be a default value without pattern, but not in the prototype.\n\n## Conclusion\n\nThe prototype will have version 2. We're saving for later whether the last clause should be able to leave off a pattern.\n\n\n# Property pattern\n\n``` c#\nif (e is { Name: \"Mads\", Employer: { ID: string id } }) { WriteLine(id); }          // 1 - Current\nif (e is { Name = \"Mads\", Employer = { ID = string id } }) { WriteLine(id); }       // 2\nif (e is { Name == \"Mads\", Employer == { ID == string id } }) { WriteLine(id); }    // 3\nif (e is { Name is \"Mads\", Employer is { ID is string id } }) { WriteLine(id); }    // 4\n```\n\n1 is what we have implemented, but it clashes a little with what we just decided for switch expressions.\n2 mirrors object initializers the most\n3 implies equality, but clashes in meaning with `==` elsewhere\n4 emphasizes `is` as a means for applying patterns\n\n``` c#\nvar result = person switch \n{ \n    { Name: \"Mads\", Employer: { ID: string id } }: id,\n    (_, id: var pid){ Name: \"Matt\" }: pid,\n    _: null\n};\n```\n\nThere's a clash but maybe it doesn't feel too bad. The second pattern with three different meanings of `:` is certainly not common.\n\n``` c#\nvar result = person switch \n{ \n    { Name is \"Mads\", Employer is { ID is string id } }: id,\n    (_, var pid){ Name is \"Matt\" }: pid,\n    _: null\n};\n```\n## Conclusion\nDecision: stay with `:` for prototype, remains open question though!"
  },
  {
    "path": "meetings/2018/LDM-2018-05-02.md",
    "content": "﻿# C# Language Design Notes for May 2, 2018\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n# Revisit syntax for switch expression\n\nWe got a lot of feedback on the decision to use `:` between pattern and result in each case of a switch expression, and we want to revisit it one more time before releasing the prototype.\n\n``` c#\nstate = (state, action) switch {\n    (DoorState.Closed, Action.Open)   => DoorState.Opened,\n    (DoorState.Opened, Action.Close)  => DoorState.Closed,\n    (DoorState.Closed, Action.Lock)   => DoorState.Locked,\n    (DoorState.Locked, Action.Unlock) => DoorState.Closed,\n    _                                 => state\n};\nstate = (state, action) switch {\n    (DoorState.Closed, Action.Open)   -> DoorState.Opened,\n    (DoorState.Opened, Action.Close)  -> DoorState.Closed,\n    (DoorState.Closed, Action.Lock)   -> DoorState.Locked,\n    (DoorState.Locked, Action.Unlock) -> DoorState.Closed,\n    _                                 -> state\n};\nstate = (state, action) switch {\n    (DoorState.Closed, Action.Open)   ~> DoorState.Opened,\n    (DoorState.Opened, Action.Close)  ~> DoorState.Closed,\n    (DoorState.Closed, Action.Lock)   ~> DoorState.Locked,\n    (DoorState.Locked, Action.Unlock) ~> DoorState.Closed,\n    _                                 ~> state\n};\nstate = (state, action) switch {\n    (DoorState.Closed, Action.Open)   : DoorState.Opened,\n    (DoorState.Opened, Action.Close)  : DoorState.Closed,\n    (DoorState.Closed, Action.Lock)   : DoorState.Locked,\n    (DoorState.Locked, Action.Unlock) : DoorState.Closed,\n    _                                 : state\n};\n```\n\nThere are pros and cons for all of these. In our previous decision we may have overemphasized one set of examples over another.\n\n`:`: Has an affinity to `switch` statements - it just removes the `case`. However, in `switch` statements, *statements* come after, whereas here, *expressions* do.\n`=>`: We have already put those elsewhere (expression bodied members) to say that you yield an expression as a result. However:\n1. Pain to do parsing magic for the last one, maybe. (Not a strong argument)\n2. precedence issues: if you had a `?:` in your pattern or `when` clause it would consume `=>` for a lambda\n3. Looks like a lambda but isn't one\n4. Will drive an expectation of a block body\n\nConclusion: We're undecided, but we will switch back to `=>` for the prototype.\n\n\n# Nullable special members\n\n``` c#\nstatic bool IsNullOrEmpty([NotNullWhenFalse] string? s) { }\n```\n\nShould use \"When\" in the name.\n\n``` c#\nstatic void AssertNotNull<T>([EnsuresNotNull] T? t) where T : class { }\n```\n\nNot necessarily for fatal methods. Could be a method that initializes a ref:\n\n``` c#\nstatic void EnsureNotNull([EnsuresNotNull] ref string? s) { if (s is null) s = \"\"; }\n```\n\nProbably needs \"Ensures\" here to signal difference from restriction on incoming. Maybe \"Ensures\" on all of them?\n\n``` c#\nclass Object\n{\n    [NullableEquals] public static bool ReferenceEquals(object? x, object? y) { }\n    [NullableEquals] public static bool Equals(object? x, object? y) { }\n    [NullableEquals] public virtual bool Equals(object? other) { }\n    [NullableEquals] public static bool operator==(object? x, object? y) { }\n}\n```\n\nFor operators and static binary methods on Object, the compiler can just know. For other user defined equalities we need an attribute. Also `IEqualityComparer` and `IStructuralEqualityComparer`, both generic and non. We probably still want to put the attribute on binary equality methods for clarity, but the behavior will be there regardless for the ones the compiler knows about.\n\nFor unary instance method equalities, the attribute should just be `[NotNullWhenTrue]` (since the receiver is inherently not null!). Again, for the ones the compiler knows about (`Object.Equals` and `IEquatable.Equals`), we should have the behavior regardless of the attribute, but we should probably put the attribute in anyway.\n\nFor *not* equal methods we may not need an attribute, since non-operator not-equalses are probably exceedingly rare.\n\nWe're a little concerned about int-returning comparers, since chasing in a compiler analysis whether their result is 0 is quite subtle. We're open to discussing it again.\n\nAs for `[NullableEquals]` on bool-returning binary equality comparisons, we should make it only work for exactly two parameters for now. If there are more parameters, it's not going to be clear that the first two are the ones being compared.\n\n`[NullEquality]` for now.\n\nWe think we know what it does but we should drill in later to be sure.\n\nFor the virtual method, first there is the concern about whether we can expect overrides to follow the contracts. \n\nAside: when we see `o.x` with an instance member, then we should know that after, o was not null. In general, should we consider scoping reasoning around throws to the nearest catch clause?"
  },
  {
    "path": "meetings/2018/LDM-2018-05-14.md",
    "content": "﻿# C# Language Design Notes for May 14, 2018\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n## Agenda\n\nWe discussed reactions and feedback from talk and booth at the BUILD conference.\n\n\n# Nullable\n\n## Special methods\n\nWe're on the right track\n\n## External annotations\n\nWe probably need them, we'll get back to it\n\n## Incoming values to public API\n\nThe feature doesn't help people remember to check non-null parameters for null. We could make it so that the null state of such parameters starts out as MaybeNull.\n\nThis would definitely help people follow the current practice of aggressively protecting against unwanted null parameters. If in the future callers become more \"reliable\" on average, due to widespread adoption of the feature, then this may seem too harsh.\n\nOf course this wouldn't help when somebody passes you a `string[]` with nulls in it. And unless the parameter is actually dereferenced (or passed as non-nullable) inside of the method, you'd still get no warning. This speaks to maybe having a separate analyzer to help you remember to check, instead of building it into the nullable feature?\n\n\"Public\" could be `public`, `protected` and `protected internal`, or could be more dialable. Oftentimes people use public without intending it to be an API. They may be forced to by some other circumstance: interface implementation, or databinding etc.\n\nIt's also a problem if multiple overloads leave the checking to just one of them, that they all delegate to. Now they will get warnings when they just pass on the parameter. \n\nThere are lots of people who do not do argument checking, but instead leave the parameter to NRE on first occasion. This would work against that pattern.\n\nThis rule feel somewhat more ad hoc than the other nullability rules, especially as it depends on accessibility.\n\n### Conclusion\n\nDefinitely worth discussing the scenario. There are many counterexamples to doing it like this, but it also seems reasonable to help people who want to do argument validation remember to do so. We're leaning to where this is an analyzer, not part of the feature itself.\n\n\n# Index and Range\n\nGenerally the approach was approved of. It deals with some of the limitations in Python, for instance. The full generality of index expressions (working outside of indexing, having a natural type) wasn't always completely appreciated, but also wasn't considered harmful. The `^` glyph is a bit foreign at first, but nothing worse than that.\n\n## Conclusion\n\nWe're on the right track.\n\n\n# Default interface member implementations\n\nSome reaction against it, where it just seems really wrong to put code inside of an interface. Also, many people don't have the problem of evolving interfaces: if those interfaces are only implemented in their own code bases, they can just fix things up. So the motivation doesn't really apply to them.\n\nThis is important if you are building public API, and also for consuming API from other languages, with Java and Swift interop in Xamarin being a prime example.\n\n## Conclusion\n\nWe still think this is an important feature.\n\n\n# Records and discriminated unions\n\nThe main motivation for people who ask for these features seems to be simply conciseness. Exhaustiveness checking is interesting, but not nearly as important.\n\nExhaustiveness is in fact not obvious:\n\n``` c#\nsealed class Animal\n{\n    sealed class Dog: Animal {}\n    sealed class Cat: Animal {}\n}\n\nint M(Animal a)\n{\n    return a switch \n    {\n        Cat c => 1,\n        Dog d => 2,\n    }\n}\nint M(Box<Animal> b)\n{\n    return b switch \n    {\n        Box(Cat c) => 1,\n        Box(Dog d) => 2,\n    }\n}\n```\nThese two switches may look exhaustive, but are actually missing null cases both of the `Box` and the `Animal`. To be exhaustive they should really be:\n\n``` c#\nint M(Animal a)\n{\n    return a switch \n    {\n        Cat c => 1,\n        Dog d => 2,\n        null  => 3\n    }\n}\nint M(Box<Animal> b)\n{\n    return b switch \n    {\n        Box(Cat c) => 1,\n        Box(Dog d) => 2,\n        Box(null)  => 3,\n        null       => 3\n    }\n}\n```\n\nWe probably want to have different exhaustiveness checking depending on whether `a` is `Animal` or `Animal?`. But that means that missing null cases can only yield warnings, just like nullability does, since we don't want nullability to have any semantic effects or yield errors.\n\n\n## Struct unions\n\nWe could work with the runtime to allow us to overlay different types inside of a struct. For unions where each variant is small, structs would probably be highly preferable from a performance perspective."
  },
  {
    "path": "meetings/2018/LDM-2018-05-21.md",
    "content": "﻿# C# Language Design Notes for May 21. 2018\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n# Target typed new\n\nThere's a PR for target typed `new` expressions\n\n```c#\nM(new (1));\n```\n\nWe generally like it, and have been interested in a feature like this for a while, but we're a bit concerned about the ways in which use of it can be brittle. In the code above, adding another constructor to a type (which one of the overloads takes) can now cause an ambiguity, or cause a different overload to be picked.\n\nIt's roughly as \"bad\" as adding another implicit conversion.\n\nWe could consider restrictions. We could do it only in initializers, which is a common request. But that's still a harsh restriction. We would probably soon be back to considering the general version of the feature.\n\nWe could warn (or have an analyzer warn) if there is more than one possible target parameter type among overloads corresponding to a target-typed `new` argument.\n\nWe could also take a similar approach as we do to out vars. There we don't even take the parameter type into account for betterness purposes. We're ambiguous if two overloads differ only on the type of an out parameter, regardless of whether one is \"better\" than the other. If we do this similarly, then folks wouldn't easily get silent changes when overloads are added: instead they'd get ambiguity errors, and would be forced to put in a type name, or otherwise disambiguate.\n\n## Conclusion\n\nWe would like to pursue this feature. Let's schedule a design meeting to make sure we have the design ironed out. We like the more restrictive approach to overload resolution, similar to out vars.\n\n\n# Return/break/continue expressions\n\nThis is a convenience. However, it risks a syntactic conflict with other potential futures, especially \"non-local returns\" (allowing a lambda to return from its enclosing method) and \"block expressions\" (allowing statements inside expressions). While we can imagine syntaxes for those that do not conflict, we don't want to limit the design space for them at this point, at least not for a feature that is merely \"nice to have\".\n\nAlso, while we've been talking about this in analogy with throw expressions, that isn't quite right. `throw` is a dynamic effect, whereas `return`, `break` and `continue` are statically bound control transfers with a specific target.\n\n## Conclusion\n\nWe're grateful for the pull request, but do not want to go forward with the feature at this point.\n\n\n# Async streams\n\n## Async foreach task consumption\n\nJust like foreach it will look for an interface or a pattern. Should the pattern require `Task<T>`, or be pattern-based all the way down?\n\n### Conclusion\n\nPattern all the way down. Same as with `await`.\n\n## Async foreach extension methods\n\n`foreach` doesn't allow extension methods for `GetEnumerator` etc. We would like to change that, but there are obscure potential breaking changes there. Should `foreach await` allow extension methods?\n\n### Conclusion\n\nLet's allow, and work to allow for synchronous `foreach` as well.\n\n## Async iterator lambdas\n\nWe don't do iterator lambdas today, and it's low priority to add it, though it's not really harmful. \n\n### Conclusion\n\nWe won't do it for async iterators either, until such time as we decide to do it for the synchronous ones.\n\n## When is it an iterator?\n\nIn synchronous iterators, the `yield` keyword is what makes it an iterator. The same for async iterators: the combo of the `async` modifier and the presence of the `yield` keyword makes it an async iterator. Whether you actually await is at most the subject of a warning, just as withe other async methods, and has no other bearing.\n\n## Pattern-based return type of async iterators?\n\nAsync methods no longer have to return `Task` and `Task<T>`, but can follow a pattern. We don't currently do a similar thing for iterators, but we should think about it, also for async iterators.\n\n## foreach await over dynamic\n\nBlock it. For synchronous foreach we resort to the nongeneric `IEnumerable`, but there is no nongeneric `IAsyncEnumerable`, and there won't be.\n\n"
  },
  {
    "path": "meetings/2018/LDM-2018-05-23.md",
    "content": "﻿# C# Language Design Notes for May 23, 2018\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n# Working with data\n\nCollections of data with heterogeneous types.\n\nIt's *not* objects, but decoupled from operations. \n\n- tuples\n- anonymous types\n- classes\n\nAll have a mutability issue, just different ways.\n\nModeling enumerated types is complex and doesn't provide exhaustiveness.\n\nAlso, you cannot efficiently switch over different types. You do tricks like visitors, abstract kind properties, etc. Performance, correctness and succinctness are all in conflict. Type patterns help, because they look good, but they are still not as efficient or as safe as they could be.\n\nTechnically speaking, mutability and value equality are a dangerous combo on classes. If the object mutates, its equality and hashcode change, meaning you could lose track of them in dictionaries, etc.\n\nOn the other hand, C# is mutable by default: should we bend over backwards to not support this combo?\n\nObject initializers aren't strictly necessary, but they jive well with `with` expressions, give a less positional view.\n\nObject initializers are really popular today, in that they are used a lot. But it's unclear whether they are because the declaration site doesn't provide constructors, and instead do the \"easy\" thing of just offering auto-properties.\n\nWithers: we keep talking about them for readonly data, but they might very well be useful on mutable data as well.\n\nThe \"data classes\" proposal puts weight on *not* being positional. It could even reorder members alphabetically in generated positional constructs such as constructors.\n\nSeparately, there is an idea of \"named tuples\". These are what have previously been proposed as \"records\". These are an evolution story for tuples.\n\nThis may be an overload of concepts. It may be that we can view them as aspects of the same feature; one may be an evolution of the other.\n\nDiscriminated syntax: Enum classes. Starts very simple, probably has ways of letting you grow up. That gets messy though, with the nesting, but we could use partial to separate things.\n\nKind fields must necessarily be unspeakable, and discoverable only by the compiler. Otherwise they can't be efficient.\n\nRecords and data classes are extensions of existing constructs. Enum classes are more of a new concept.\n\nWe kind of agree on the simple cases. It's how they grow up and fit into the existing world that's fraught with questions.\n\nInterestingly, you sometimes want your \"enums\" *not* to be exhaustive. This is the case when you expect it to evolve with more cases.\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "meetings/2018/LDM-2018-05-30.md",
    "content": "﻿# C# Language Design Notes for May 30, 2018\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n# Annotating parts of a project\n\nRoslyn starts out with about 2000 warnings. We may want to support nullable annotations for only a part of a project, so that you can gradually ease into them.\n\nThis touches on a core question: Are there separate opt-ins for *consuming* nullability (give me warnings please) and *producing* nullability (consider unannotated reference types to be non-nullable; \"URTANN\").\n\nIf we have a scoped \"URTANN\", then turning on warnings for the whole file would still have limited impact, until annotations start becoming abundant.\n\nBut we may also want to consider warnings to be turned on in a scoped way, at a certain granularity. Source files? Fine grained program elements? It might be better not having this, though, as it comes with the risk of introducing more problems (through annotation), without discovering it (because the consumption has warnings off).\n\n``` c#\nT M(string s) => M2(s); // No warning because s is oblivious\n\n[URTANN]\nT M2(string s) => ...\n```\n\nThe opt-in to warnings could be a \"fake\" error code that represents a category. We may not need a brand new dedicated command line option, but we're willing to go there.\n\n1. We agree that we are comfortable (for now at least) in opting in to the warnings at the whole project level only\n2. We agree that there should be a separate mechanism for opting in/out of non-null annotations (URTANN)\n3. We agree that URTANN should be attribute-based, and able to be applied (or unapplied, with a `false` argument) at multiple levels of program elements\n\nDecision:\n\nLet's have `URTANN(true)` implicit by default, unless you have another module-level URTANN. We can maybe auto-generate it if you don't have it already. It should be called `NonNullTypesAttribute(bool)`."
  },
  {
    "path": "meetings/2018/LDM-2018-06-04.md",
    "content": "﻿# C# Language Design Notes for Jun 4, 2018\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n\n# Nullable flow analysis\n\n``` c#\nstatic void F(object? x)\n    {\n        object y = null;\n        Action f = () => y = x; // warning?\n        if (x == null) return;\n        f();\n        y.ToString(); // warning?\n    }\n```\n\nA proposal is to take the most nullable the variable can be and use that state in a lambda that captures it.\n\n(This is only relevant for top-level nullability, as nested nullability is not tracked through flow.)\n\nThere's a slight concern that we could run into cycles, where \"the most nullable state\" depends on \"the most nullable state\". We think that it is not going to be an issue.\n\n``` c#\nM(string? x, string? y)\n{\n    Action f = () => y = x;\n    x = null;\n    //M1(f);\n    x = \"\";\n    M2(f);\n    y.Length;\n}\n```\n\nIt seems a shame that optimizing like this, by caching the delegate, could lead to more nullable warnings. We could imagine tracking delegates through locals and basing the analysis on where they are used (called or passed).\n\nEnvisioned safe tightenings:\n\n* Only care about null assignments that happen after the lambda becomes \"effective\"\n* If a lambda goes into a local variable, then it is only \"effective\" when that local variable is used\n* Such a local, when invoked directly, does not depend on future null states\n\nAnother option is to just be more loose about the whole thing, and allow there to be holes. Specifically we could assume that the lambda is executed either when it appears or not at all. The hole is that this does not accurately account for deferred execution.\n\nThinking about the effect of the lambda above on `y`, it can happen at any time after the lambda. So at any point after that, the null state of y would be a \"superposition\" of null states. So if a lambda makes a variable `MayBeNull`, it would be irreversibly `MayBeNull` for the remainder of the method. *Even right after a null check!* It's on perpetual lockdown!\n\nThis seems draconian. It feels stronger than our position on dotted names, which lets us assume that the null state remains stable between observing and using. That suggests we should be at least somewhat loose. We could maybe just assume that the lambda is conditionally executed at the point of capture, and we assume that mutations don't happen later.\n\nAside: lambdas that assign captured variables aren't as esoteric as they may seem. For instance, our whole ecosystem around analyzers relies on a recommended pattern that does that.\n\n## Conclusion\n\nWe analyze a lambda as if it is conditionally executed only at the point of capture into a delegate. It does rely on order of execution to an uncomfortable degree. Some of the refinements we've considered could be introduced later.\n\nFor instance, these two examples would behave differently if `y` comes in non-null and `x` comes in maybe-null:\n\n``` c#\nvoid M1(Action, ref string s);\nM1(() => y = x, ref y);\n\nvoid M2(ref string s, Action);\nM2(ref y, () => y = x);\n```\n\nSide note: There's a similar granularity issue with the nullability attributes, whether they should apply to parameters as soon as that parameter is encountered, or only after the whole argument list.\n\n\n# Local functions\n\nWhen a local function is captured into a delegate, we just do the same as for lambdas: assume a conditional execution at the point of capture.\n\nWhen local functions are called, abstractly speaking we should do the same as for definite assignment, where the *requirements* and the *effect* are inferred for each local function, and then applied in place where the function is called. The difficulty of course comes in when functions are recursive. For definite assignment, we can prove that a recursive analysis terminates, because of the monotony of definite assignment (you never become *un*assigned). Can we make a similar argument/proof for nullability?\n\n\n# Conditional attributes and special annotations\n\nLet's change `EnsuresTrueAttribute` to `AssertsTrueAttribute`, and always take them into account, even when the condition is false.\n\n\n"
  },
  {
    "path": "meetings/2018/LDM-2018-06-06.md",
    "content": "﻿# C# Language Design Meeting\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n## Agenda\n\nExpression trees\n\n# Scenario\n\n## Big data\n\nBing scenario, sending code from ad hoc queries would be too heavyweight through traditional compiling and sending of assemblies. Also it's not just execution but intense analysis, which feeds into where the query ends up running etc. Introspection.\n\nCurrently work around various limitations. Async calls may be part of the query, and there's a lot of code manipulation for that.\n\n## Machine learning and GPU \n\nare other important scenarios: capturing code for auto-differentiation (ML) or for translation to GPU executable code.\n\n# Restriction as a feature\n\nWould allowing more nodes remove a useful restriction, that people depend on today? For instance, most new nodes we add may not be sensible in EF. We've always had this problem, and been able to write something that fails at runtime.\n\nPartial solutions:\n- provide alternative factories with a pluggable builder pattern, driven by the target type (just like we now do for task-like types)\n- offer analyzers that are domain specific. \n\n\n\nProvider model: Probably not that unrealistic to implement your own factory. Plugging it through the language probably requires some extra work, but it seems doable. This would allow static checking of shape, and would give analyzers something to latch off of for further restriction of nodes.\n\nThe expression lambda rewriter today is nicely isolated in the Roslyn codebase and only ~1100 lines. \n\nThere's a further step we could take, which is to freeze current expression trees in time. Then whoever wants to understand new language features needs to use a new expression type.\n\n# Reduction\n\nExpression trees have been significantly expanded since the language tied into them. There is an extension story, where a node can be reducible. It then offers to translate into other nodes. This helps older providers still work, as well as lets you not have to do the work to implement all the nodes, only the irreducible ones.\n\nWe don't want to overdo reduction. We probably wouldn't reduce async lambdas to trees representing the state machine. That would overly commit us to some very specific implementation choices, and probably also leave performance opportunities on the table.\n\n# Philosophy\n\nIt's a big question whether we want to commit to expression trees following the language in perpetuity. But we don't need to commit to that. As long as we feel an upgrade is useful.\n\n# Extending existing nodes\n\nThis is not just about adding new nodes, but also expanding existing ones with new expressiveness. We'd have to be careful to keep generating old factory method calls for existing situations.\n\n# Bart's experiment\n\ngithub.com/bartdesmet/ExpressionFutures/tree\n\nInherits and shadows `System.Linq.Expressions.Expression`.\n\nSupports dynamic, async. Needed some hacks because it is a separate library, if it goes into the BCL it would have access to the right things.\n\nSupports null-conditional, discard.\n\nStatements are generally supported up to C# 6.0.\n\nSince these are a shadow library over System.Linq.Expressions, there's an updated Roslyn compiler that also understands those.\n\n# Plan\n\nWhat we would like to do:\n* Use factory methods as the well-defined interface between compiler and API\n* Feel good about incrementally improving without having to do all of the language at once\n* Add provider model/builder pattern for other factories\n* Get to a prioritized list of specific language constructs to start supporting\n* Evolve compiler and API together for specific constructs\n* Checkin with existing providers such as EF to ensure compat story is good, and their scenarios are taken care of\n\nFor now, let's mull it over for a couple of months, pursue information, crisp up the plan. Only after a while will we be able to free up compiler resources.\n\n"
  },
  {
    "path": "meetings/2018/LDM-2018-06-25.md",
    "content": "﻿# C# Language Design Notes for Jun 25, 2018\n\n***Warning: These are raw notes, and still need to be cleaned up. Read at your own peril!***\n\n## Agenda\n\n1. Target-typed new-expressions\n\n\n# Target-typed new-expressions\n\n## Syntax\n\n``` c#\nC c = new (...){ ... };\n```\n\nYou can leave off either the constructor parameters `(...)` or initializer `{ ... }` but not both, just as when the type is in.\n\n## Conversion\n\nThis will only work if a) we can determine a unique constructor for `C` through overload resolution, and b) the object/collection initializer binds appropriately.\n\nBut are these errors part of *conversion* or part of the expression itself? It doesn't matter in a simple example like this, but it matters in overload resolution.\n\n## Overload resolution\n\nThere are two philosophies we can take on what happens when a target-typed new-expression is passed to an overloaded method.\n\n### \"late filter\" approach\n\nDon't try to weed out overload candidates that won't work with the new-expression, thus possibly causing an ambiguity down the line, or selecting a candidate that won't work. If we make it through, we will do a final check to bind the constructor and object initializer, and if we can't, we'll issue an error.\n\nThis reintroduces the notion of \"conversion exists with errors\" which we just removed in C# 7.3.\n\n### \"early filter\" approach\n\nConsider arguments to constructor, as well as member names in object initializer, as part of applicability of a given overload. Could even consider conversions to members in object initializer. The question is how far to go.\n\n### Trade-off\n\nThe \"early filter\" approach is more likely to ultimately succeed - it weeds out things that will fail later before they get picked. It does mean that it relies more on the specifics of the chosen target type for overload resolution, so it is more vulnerable to changes to those specifics.\n\n``` c#\nstruct S1 { public int x; }\nstruct S2 {}\n\nM(S1 s1);\nM(S2 s2);\n\nM(new () { x = 43 }); // ambiguous with late filter, resolved with early. What does the IDE show?\n```\n\nAdding constructors to the candidate types can break both models. Adding fields, properties, members called `Add`, implementing `IEnumerable` can all potentially break in the early filter model.\n\n``` c#\nM2(Func<S1> f);\nM2(Func<S2> f);\nM2(() => new () { x = 43 });\n\nS1 Foo() => new () { x = 43 };\n```\n\nEven if we did late filtering, this would probably work (i.e. the `S2` overload would fail), because \"conversion with error\" would give an error in the lambda, which in itself rules out the overload.\n\nWe're having a hard time thinking of practical scenarios where the difference really matters. Only if we go to the \"extremely early\" position where the expression could contribute even to type inference. We've previously considered:\n\n``` c#\nM<T>(C<T> c);\nM(new C (...) { ... });\n```\n\nWhere the type arguments to `C` could be left off and inferred from the `new` expression. This would take it a bit further and allow\n\n``` c#\nM (new (...) {...});\n```\n\nIn that same setup, contributing to type inference from the innards of an implicit `new` expression.\n\n## Conclusion\n\nWe are good with late checking for now. This does mean that we reintroduce the notion of conversion with errors.\n\n## Breaking change\n\nAs mentioned this introduces a new kind of breaking change in source code, where adding a constructor can influence overload resolution where a target-typed new expression is used in the call.\n\n## Unconstructible types\n\nThat said, we could define a set of types which can never be target types for `new` expressions. That is not subject to the same worries as the discussion above, where the innards of the `new` expression could potentially affect overload resolution. These are overloads where no implicit `new` expression could ever work.\n\nCandidates for unconstructible types:\n\n* Pointer types\n* array types\n* abstract classes\n* interfaces\n* enums\n\nTuples *are* constructible. You can use `ValueTuple` overloads.\nDelegates are constructible.\n\n## Nullable value types\n\nWithout special treatment, they would only allow the constructors of nullable itself. Not very useful. Should they instead drive constructors of the underlying type?\n\n``` c#\nS? s = new (){}\n```\n\n### Conclusion\nYes\n\n## Natural type\n\nTarget-typed new doesn't have a natural type. In the IDE experience we will drive completion and errors from the target type, offering constructor overloads and members (for object initializers) based on that.\n\n## Newde\n\nShould we allow stand-alone `new` without any type, constructor arguments or initializers?\n\nNo. We don't allow `new C` either.\n\n## Dynamic\n\nWe don't allow `new dynamic()`, so we shouldn't allow `new()` with `dynamic` as a target type.\n\nFor constructor parameters that are `dynamic` there is no new/special problem."
  },
  {
    "path": "meetings/2018/LDM-2018-07-09.md",
    "content": "﻿\nLDM July 9th, 2018\n-------------------\n\n_QOTD: \"Yeah, it's easy if you do it in a shi**y way\"_\n\n## Agenda\n\n1. `using var` feature\n   1. Overview\n   2. Tuple deconstruction grammar form\n   3. `using expr;` grammar form\n   4. Flow control safety\n\n2. Pattern-based Dispose in the `using` statement\n\n3. Relax Multiline interpolated string syntax (`$@`)\n\n# `using var` Feature\n\n**Motivation**\n\nProposal: https://github.com/dotnet/csharplang/pull/1703\n\nIt's a common problem that multiple `using` statements can require successive\nnesting, causing what is mostly linear code to have the \"down and to the\nright\" problem, where increasing indentation makes the code less readable,\nnot more. One way people try to solve this is using the\n\n```C#\n{\n    using (expr1)\n    using (expr2)\n    using (expr3)\n    { ... }\n}\n```\n\nsyntax, but that has two problems. First, many style guidelines prohibit\n\"braceless\" usings, but make an exception for this specific case. Second, if\nthere is any intervening code required between the `using` expressions, this\nsyntax form is not allowed.\n\n**Objections**\n\nObjections to this feature fall mainly in two categories. Either there is\nworry about determinism and ordering, or that this feature isn't sufficiently\ngeneral to encompass the scenarios we would consider making the feature\n\"worth it.\"\n\nThe determinism concern is that refactoring from the `using (...) {...}` form\ncould unintentionally lengthen the liveness scope to the entire method,\ninstead of just to the closing brace of the using. The ordering concern is\nthat nesting provides very clear ordering semantics, and the \"stacked using\"\nform also has a clear ordering, since there cannot be any code in between\neach `using`. This isn't necessarily true for using-variables. It's possible\nthat both of these concerns could be mitigated by better refactoring and\nanalysis tools.\n\nThe generality concern is mainly around the `using (expr) { ... }` statement\nform, which doesn't have an equivalent using-variable form in the current\ndesign.\n\n**Conclusion**\n\nIt's worth it. The concerns are valid, but don't seem bad enough to block the feature.\n\n## Tuple deconstruction grammar form\n\nThe first question was about the proposed grammar. The current design is a\nnew type of statement (`local-using-declaration`). There are two potential\nholes in the grammar: no space for tuple deconstructions and no `using expr;`\nform.\n\nFor deconstruction, we came up with a number of potential forms:\n\n```C#\n    (using var x, using var y) = M(); // Form 0\n    using (x, y) = M();               // Form 1\n    using (var x, var y) = M();       // Form 2\n    using var (x, y) = M();           // Form 3\n    using var t = M();                // Form 4\n```\n\nOf these, only (4) would be legal in the current proposal. Of the remaining\nforms, form (0) seemed the clearest. There was consensus that this implied\nthe declaration of two new variables, each of which was independently\ndisposed, in the style of\n\n```C#\nusing var x = M1(), y = M2();\n```\n\nIt was not immediately clear whether the tuple itself was disposed in form\n(0). This was a common complaint with the rest of the forms as well: it is\nunclear what the semantics of each statement is. Is the tuple itself being\ndisposed? Is disposal distributed over the elements? Both? Some tuple\ndeconstructions also happen in \"reverse\" order of the tuple elements'\nlexical ordering. If dispose is distributed, what order are the elements\ndisposed in?\n\nThis also raised the question of nested declarations in the initializer, e.g.\n\n```C#\nusing var x = M1(out var y)\n```\n\nIs `x` the only `using` variable? Or is `y` one as well?\n\n\n**Conclusion**\n\nLet's continue with the proposal as-is. Form (4) works and should work. There\nmay be compelling scenarios to open up the syntax to tuple deconstructions,\nbut we don't have a convincing argument yet. We also don't have a clear rule\nfor prohibition. For nested declarations, they are not declared as `using`\nvariables.\n\n## `using expr` grammar form\n\nThese concerns dovetailed into discussion of the `using expr;` form, because some of these grammar\nforms may compose. For example, since `var (x, y)` is an expression in C#, the following could be\na potentially legal statement with no modification:\n\n```C#\nusing var (x, y) = M();\n```\n\nIn this case `var (x, y) = M()` would be the `expr` in `using expr;`.\n\nThis form seems desirable to round out the feature, but it isn't clear how it fits into the language.\nThe previous decision seems to imply we don't want `using` deconstructions, but it isn't clear what\nrule we would use to prohibit them, in a principled sense. The feature also has some integration\nconcerns. `using (expr);` is already a legal construct in the C# language with different semantics,\nalthough the compiler gives a warning about it today. There is some concern that `using expr;` and\n`using (expr);` are too close grammatically and that the syntax effectively rules out parenthesized expressions.\n\nFinally, there were questions about grammatical ambiguity with possible\nfuture language features. If C# were to allow statements on the top level, a\n`using System;` line could either be a using-directive if `System` is a\nnamespace, or a using-statement if `System` is a type. The same problem could\noccur if we were to allow using-directives at the statement level. This\ndoesn't seem very bad since we already have similar ambiguities with `Color\nColor` rules and resolve them properly during semantic analysis. These\nambiguities are also probably present for using-directive aliases.\n\nThere were a couple proposals to try to deal with some of these problems:\n\n1. Any expression that declares variables is disallowed as a `using expr;`\n\n2. Hold off on `using expr;` for now.\n\n3. Allow `_` as a discard for `using var _ = expr;`\n        - Or `using _ = expr;`\n\n**Conclusion**\n\nThis is a blocking issue that we must decide on for C# 8.0. Either we should\ndisallow this form entirely or find some principle to use to reject the\nconstructions we find confusing. However, we think this problem is solvable\nand shouldn't block continued work on the feature.\n\n## Flow control safety\n\nThe last design issue was safety in the presence of `goto` and similar flow\ncontrol features (e.g., local functions). The existing spec notes that backward\nflow control is not a problem, but what about forward flow control? For example,\n\n```C#\n{\n    goto target;\n    using var x = new FileStream(...);\ntarget:\n    var y = x;\n    return;\n}\n```\n\nIn the previous example, this is an error, because `x` is not definitely assigned.\nIn fact, all uses in this category, where flow is manipulated to skip over the\nvariable definition before a read, are safe because the variable will not be\ndefinitely assigned. In addition, because `using` variables are read-only, it also\ncannot be assigned later.\n\nOne case which the spec does not currently handle is\n\n```C#\n{\n    goto target;\n    using var x = new FileStream(...);\ntarget:\n    return;\n}\n```\n\nHere `x` is never read, so there would be no definite assignment errors. However,\nthere is an implicit read of the variable at the end of the variable lifetime, which\ncould be a read of an unassigned variable.\n\n**Conclusion**\n\nA new line to the spec should be added saying that, if the end of a `using` variable's\nlifetime is reachable, that variable must be definitely assigned at that point.\n\n*Open question*\n* [ ] This needs more precise language. The spec does not have reachability at \"points\".\n      What do we mean when we say the end of a block is \"reachable\"?\n\n# Pattern-based `using` statement \n\nWe like the feature. Main question: what type of pattern do we look for? As a general\nguideline, we don't want to have another special case pattern. However, it seems like\nwe have multiple styles already.\n    \n  - `GetAwaiter` doesn't allow `params` or optional parameters\n  - LINQ does\n\nDo we want `using` to be like `await` or like LINQ?\n\nAlso, do we require `void` return type? Most of the patterns today have\nstrict requirements on return type, but they also usually consume the return\ntype. `using` does not.\n\n**Conclusion**\n\nKeep the spec as is: `Dispose` must be parameter-less in instance-form,\n`void`-returning, and accessible. This allows for extension methods, but\nnot optional parameters or `params`.\n\n# Multiline interpolated string syntax\n\nIt's hard to remember which is the correct syntax: `$@\"\"` or `@$\"\"`. The\nproposal is to allow either.\n\n**Conclusion**\n\nNo objections."
  },
  {
    "path": "meetings/2018/LDM-2018-07-11.md",
    "content": "\n# C# Language Design Notes for Jul 11, 2018\n\n## Agenda\n\n1. Controlling nullable reference types with feature flags\n1. Interaction with NonNullTypesAttribute\n1. Feature flag and 'warning waves'\n1. How 'oblivious' null types interact with generics\n1. Nullable and interface generic constraints\n\n# Nullable feature flag\n\nA nullable feature flag has been proposed that turns on the new\nwarnings for the nullable reference type feature. A feature flag\nis proposed because new warnings could be generated for existing\ncode, so the developer must opt-in to the new warnings. \n\nThe question is: what does the feature flag do, exactly?\n\nBinding and emit are unaffected by feature flag, so code will not behave any\ndifferently with it enabled. If the feature is on you get nullability\nwarnings. If the feature is *off* and you annotate a reference type with '?',\na warning is produced that the feature is disabled, and the IDE should offer\nto turn the feature on. Without a warning, a developer could think they are\nusing the feature because they've annotated their references, but in fact\nno warnings are being provided.\n\n**Question**: What if a developer wants to annotate their public API, but they\ndon't want to consume the feature in their own code?\n\n**Answer** There are two options:\n  - Turn the feature on and disable all the nullable warnings\n  - OR turn feature off and suppress the warning about the feature being off\n\n## Interaction with NonNullTypesAttribute\n\nRelated to the feature flag, a NonNullTypes attribute is proposed that decides\nhow unannotated types are interpreted by the compiler. If `NonNullTypes(true)`\nis present, unannotated types are assumed to be non-null. If it is absent\nor `NonNullTypes(false)` is present, then unannotated types are \"oblivious\"\nand don't produce warnings.\n\nHow do the attribute and the feature flag interoperate? Two independently\nvarying variables:\n    - Assembly is annotated\n    - Warnings are produced\n\nHere are the possibilities:\n\n|             | Warning          | No warning                   |\n|-------------|------------------|------------------------------|\n| Annotated   | C# 8 feature on  | C# 8 feature off w/ suppress |\n| Unannotated | N/A              | C# 7                         |\n\nEach of these seem reasonable. \n\nQ: What about external annotations?\n\nA: Don't know enough about their design yet to decide\n\n**Conclusion**\n\nProposal accepted.\n\n\nFor the `NonNullTypes` attribute, do we block it for older compilers?\n\n  - We usually don't poison new feature attributes for older compilers\n  (e.g., `dynamic`, `params`). We just provide errors in new compilers.\n  - This has not been a problem in the past\n\n--\n\n# Nullable references and warning waves\n\nQ: Do we want to include the nullable references in Warning waves? Would\n\"v8\" include all nullable warnings?\n\n  - If the feature flag affects the `NonNullTypes` context, it doesn't\n    just impact warnings\n  - The benefit of warning waves is that tooling support wouldn't need\n    to be customized for this feature\n\nProposal: If you use the feature, it updates the warning wave and sets the\n`NonNullTypes` setting. \n\nConcern: If so, when you get the new warning wave, now you get nullable *and*\nall the other warnings. If you only want one set but not the other, there's\nno way to split them out.\n\n**Conclusion**\n\nDon't connect nullable warnings to warning waves\n\n# 'Oblivious' types and generic parameters\n\nQ: Does `M<T?>` require `T` to be a non-nullable reference or value type?\n\nA: Yes.\n\nIf there's a mix of generic types where `T` is oblivious or non-oblivious,\nsay\n\n\n## Generic substitution\n\nThe question is what to do about the following cases:\n\n|             | List<T!> | List<T~>                                             | List<T?>      |\n|-------------|----------|------------------------------------------------------|---------------|\n| T = string! |          | C#7: `List<T> F<T>(T t);` <br> C#8: `var s = F(“”);` | List<string?> |\n| T = string~ |  C#8: `List<T> F<T>(T t);` <br> C#8: `var s = F(obliviousString);` |  |\n C#8: `List<T?> F<T>(T? t);` <br> C#8: `var s = F(obliviousString);` | | \n| T = string? | `List<string?>` | C#7: `List<T> F<T>(T t);` <br> C#8: `var s = F(nullString);`\n\nNote that the previous table uses a shorthand that is not meant to be actual C# syntax.\n`T!` means non-null reference type, `T~` means oblivious type, and `T?` means nullable type. `T?`\nis the only syntax which is actually expected to appear in valid C# programs.\n\nFor\n\n```C#\nList<T?> F<T>(T? t);\nvar s = F(obliviousString);\n```\n\nDecision: Type parameter wins. `s` is a nullable string.\n\nFor \n\n```C#\nList<T> F<T>(T t)\nvar s = F(obliviousString)\n```\n\nIs `s` oblivious? Does this \"flow\" oblivious all over?\n\n**Proposal**: \"Collapse\" oblivious types as soon as possible\n\nSo the previous type substitution, is `List<string!>`. Even outside of type\nsubstitution, oblivious types won't be inferred, so in \n`var s = obliviousString;`, `s` would be inferred as `string!`, not an\noblivious type.\n\n**Conclusion**\n\nProposal accepted.\n\nFor \n\n```C#\nList<T> F<T>(T t)\nvar s = F(nullString);\n```\n\nThe substitution is the argument type. `s` is a nullable string.\n\n# Nullable and generic constraints\n\nFirst, it is decided that `T?` requires `T` be known as a reference type.\n\nNotably, an interface constraint alone is not sufficient. \n\nWhat does the following do?\n\n```C#\nvoid M1<T>(T t) where T : I, T : class?\n```\n\nThis is a warning or error, because `T : I` implicitly means that `I` is\na non-nullable type and `class?` is a nullable reference type. The\nconstraints are contradictory. There are two fixes. Either\n\n```C#\nvoid M1<T>(T t) where T : I?, T : class?\n```\n\nto make `T` a nullable reference type. Or\n\n```C#\nvoid M1<T>(T t) where T : I, T: class\n```\n\nand now `T` is a non-nullable reference type."
  },
  {
    "path": "meetings/2018/LDM-2018-07-16.md",
    "content": "﻿# C# Language Design Notes for Jul 16, 2018\n\n## Agenda\n\n1. Null-coalescing assignment\n   1. User-defined operators\n   1. Unconstrained type parameters\n   1. Throw expression the right-hand side\n1. Nullable await\n1. Nullable pointer access\n1. Non-nullable reference types feature flag follow-up\n\n# Null-coalescing assignment\n\nThis feature has the syntax `??=` and only assigns the left-hand side of the\nassignment if the left-hand side evaluates to null.\n\n## User-defined operators\n\nThe proposal reads, `if (x == null) x = y;`\n\n**Conclusion**\n\nThis should instead read `if (x is null) x = y;`. The difference is in the\noperators: null-coalescing assignment, like the null-coalescing operator,\ndoes not consider user-defined operators like `==`. The spec also states that\nthe semantics are equivalent to `x = x ?? y`, but that should instead be `(x\n?? (x = y))`. If `x` is not null, the assignment is never performed.\n\n\n## Result type of the expression\n\nOther assignments have the type of the left-hand side e.g., `(x = y)` has the\ntype of `x`, not `y`. This has the convenient property that any assignment\nexpression can be replaced with the variable being assigned. However, there\nmay be some value in \"transforming\" the type to non-nullable when possible.\nFor instance, `(x ??= y)` could evaluate to a non-null type if `y` is\nnon-null, since we know that the null-coalescing assignment cannot produce\nnull. This is how the existing null-coalescing operator works. The\nnull-coalescing operator also specifies that, in `x ?? y`, the conversion to\na non-nullable version of `x` is preferred if it is available.\n\n**Conclusion**\n\nLet's favor the semantics of assignment. The return type should be the type of `x`.\n\n## Null-coalescing assignment on unconstrained type parameters\n\nNull coalescing currently isn't allowed on type parameters, so the proposal\ncurrently doesn't allow it either.\n\n**Conclusion**\n\nThis is a hole in null-coalescing as well. Both features should be allowed\non unconstrained type parameters.\n\n## Throw expression on the right-hand side\n\nShould the following be allowed: `a ??= throw new Exception`? `throw`\nexpressions are only allowed in certain places right now, so we would have to\nexplicitly add support. It makes more sense if the feature is equivalent to\n`a = a ?? b` where `b` is a `throw`, than `a ?? (a = b)`.\n\n**Conclusion**\n\nNot supported\n\n# Logical boolean compound assignment\n\nAlso proposed are the features `&&=` and `||=`. Should these features live\nin the same proposal or be split out on their own?\n\n**Conclusion**\n\nSplit them out. These features are potentially much more complicated because\nuser-defined conversions for `true`, `false`, `&`, and `|` could come into play.\n\n# Null-conditional await, foreach\n\n`await?` is proposed, which would only await the task-like target if it is\nnon-null and evaluate to null otherwise. A new syntax would be needed here\nbecause the result produces a different type. `await` will currently always\nhave the \"unwrapped\" type from the task-like target, whereas `await?` would\nneed to make that type nullable in the case that it is not already. An\nanalogous feature is proposed for `foreach?`.\n\nIn favor of the feature, it may be more useful with nullable reference types\nand more nullable Task-like things. On the other hand, it could lead to more\nuse of nulls in places that some of the design team considers code smells,\nlike widespread use of null Tasks or IEnumerable.\n\n**Conclusion**\n\nProbably not in C# 8, but maybe later. It may still have value, but probably\nnot as much as other features.\n\n\n# Nullable pointer access expressions\n\nThe proposal includes `?->` and `?[]`. It purposefully leaves out `*?` as\nbeing confusing as a prefix operator.\n\n**Conclusion**\n\nWe don't love it. Not planned for any release. We may consider an external\ncontribution.\n\n# Non-nullable reference type feature flag follow-up\n\nWe followed-up on the feature flag design from [last Wednesday's\nLDM](LDM-2018-07-11.md). The main concern was making the language semantics\naffected by a non-language option, namely a compiler flag. It was proposed\nthat the NonNullTypes attribute could effectively cover the same information\nas the feature flag and the attribute together.\n\nProposal:\n\n* `[NonNullTypes(true)]`: Warnings are on and unannotated types are non-nullable\n* `[NonNullTypes(false)]`: Warnings are on but unannotated types are oblivious\n* `<no attribute>`: Warnings are off and unannotated types are oblivious\n\nThe biggest benefit: if the warning opt-in is in source code, the nullable\nwarnings are not a breaking change. It's also noted\nthat this is similar to how CLS compliance already works with the\nCLSCompliant attribute.\n\nOne downside is that there is no way to turn the warnings off once there is a\n`NonNullTypes` attribute anywhere in the code. A solution is to provide a\n`Warnings` property on the type which lets the user configure warnings. This\nproperty would be true by default, but the user could override it e.g.,\n`[NonNullTypes(true, Warnings = false)]`. Also, it's unclear how this would\nwork in environments like scripting. In normal compilations it's easy to find\nsomewhere to put an attribute, but that's not necessarily the case in\nscripts.\n\n**Conclusion**\n\nAccepted with some notes:\n\n* `[NonNullTypes]` means `[NonNullTypes(true)]`\n* To prevent upgrading from C# 7 to C# 8 being a breaking change, we should\npoison the `[NonNullTypes]` attribute using `ObsoleteAttribute` (like `ref`\nstructs), but provide a better message\n* `?` in a context where there is no attribute or [NonNullTypes(false)] should be\na warning since the user is probably misunderstanding how to use the feature. `!`\nis still useful even if unannotated types are oblivious, so it is only a warning\nif there is no `NonNullType` present at all\n"
  },
  {
    "path": "meetings/2018/LDM-2018-08-20.md",
    "content": "# C# Language Design Notes for August 20, 2018\n\n## Agenda\n\nNullable open issues:\n\n1. Remaining questions on [suppression operator](https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fdotnet%2Froslyn%2Fissues%2F28271&data=02%7C01%7C%7C6defe1e21ab54cce8d0008d606be5d23%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636703812006445395&sdata=DAdh5dev1mnr%2F5zxtvuJVcHP%2Bzewrzz4z9iuGkl%2BUHg%3D&reserved=0) (and possibly cast)\n2. Does a dereference update the null-state?\n3. Null contract attributes\n4. Expanding the feature\n5. Is T? where T : class? allowed or meaningful?\n6. Typing judgments containing oblivious types\n7. Unconstrained T in List\\<T> then `FirstOrDefault()`. What attribute to annotate `FirstOrDefault`?\n\n# Discussion\n\n# Remaining questions on suppression operator\n\n## 1.1 Suppression of nested nullability\n\n*Q: Should `!` suppress warnings for nested nullability?*\n\nThere's a question here about the interplay of casting and the `!` operator,\nsince they do somewhat similar things. The problem with the current design is\nthat neither casting nor `!` give any warnings/errors at either compile time\nor runtime for nested nullability. We think it would be useful to have at\nleast one mechanism that provides more safety around nullable.\n\n**Conclusion**\n\nThe user should get a warning if you cast away nested nullability. No warning\nif you use '!'. This provides a safety mechanism for casts and still allows\nfor an \"I Know Better\" command, which was the primary motivation for `!`.\n\n## 1.2 Meaningless `!` operators\n\n*Q: Should `nonNull!` result in a warning for unnecessary `!`?*\n\n**Conclusion**\n\nThese constructs are meaningless, but unlikely to do something the user\ndidn't want. No compiler warnings for `!!...` or `nonNull!`. Maybe an IDE\nfeature.\n\n## Result of `obliviousValue!`\n\n**Conclusion**\n\nTop-level non-null, suppressed warnings for nested.\n\n# Dereference of nullable types\n\nConsider the following example:\n\n```C#\nstring? x = y;\nvar z = x.Substring(1);\n...\n```\n\n**Conclusion**\n\nThere's clearly a problem with this example that will generate a warning: `x`\nis a nullable reference type, but it's being dereferenced without a null\ncheck. The first question is: what is the type of `x` after the call? The\nanswer is non-nullable `string`, but the more detailed answer is this results\nin a split state. The specification recognizes that dereferencing a null\nvalue results in a NullReferenceException, so state should be split into\nexceptional and non-exceptional flow.\n\nTo spell it out in a more detailed example:\n\n```C#\ntry\n{\n    string? x = y;\n    var z = x.Substring(1);\n    ...\n}\ncatch\n{\n    ...\n}\n```\n\nAfter the `Substring` call, `x` is non-nullable, but in the catch block, `x`\nis nullable, as there was a potential NullReferenceException if `x` was null.\nAdditionally, like other flow control warnings, we will only provide a warning\nabout dereference of nullable type once. So if `x` is dereferenced again in\nthe catch block, another warning will not be produced.\n\n## Null contract attributes\n\nWe've started building a list of attributes that are useful for annotating\nexisting code to note when null or non-null types are produced. For instance,\n`string.IsNullOrEmpty()` will always be true if the receiver was null. It would\nbe useful to mark this method with an attribute which can indicate this to the\ncompiler, so\n\n```C#\nif (!x.IsNullOrEmpty())\n{\n    ...\n}\n```\n\nshould let the compiler know that `x` is not null within the `if` block.\n\n*Q: Do we want to do a larger review of all these attributes?*\n\n**Conclusion**\n\nLet's take all the current attributes and start prototyping. We'll adapt\nas we move forward.\n\n## Expanding the feature\n\nWe have two potential extensions here.\n\nThe first is possibly allowing a `!` annotation on a parameter *name*, which\nindicates that the compiler should produce a dynamic null check on entry to\nthe method. For instance, a method `void M(string s!) { }` would not only\nindicate that `s` is meant to be a non-nullable reference type if the\nnullable reference type feature is fully enabled, it would also insert code\nat the beginning of the method to throw an `ArgumentNullException` if `null`\nis passed anyway.\n\nThe second is how to treat nullable value types. There are two extensions we\nare considering for nullable value types. The first is about extending the\nanalysis. This is as simple as extending flow analysis to update null state\nof nullable value types based on information of null checks. For instance,\naccessing `.Value` on a `Nullable<T>` could produce a warning if the value\nwas accessed without checking for null first. An even more advanced extension\nwould allow `Nullable<T>` values to be accessed without going through `.Value`\nif the variable is proved to not be null.\n\n**Conclusion**\n\nJared's going to write up a proposal on the compiler-inserted dynamic checks.\n\nFor `Nullable<T>`, we agree with extending the analysis. We're not sure about\nthe silent call of `.Value` or automatic conversion.\n\n## `class?` constraint\n\n*Q: Is `void M<T>(T? t) where T : class?` allowed?*\n\n**Conclusion**\n\nRule: you can only use `?` on types you know to be non-nullable.\n\n`T : class?` is possibly nullable, so you can't use `T?`.\n\n## Typing judgments containing oblivious types\n\nMainly comes down to the type of `x` in `var x = oblivious;`.\n\nWe need more time for this. Return later.\n\n## Annotating `List<T>.FirstOrDefault()`\n\n*Q: Unconstrained T in `List<T>` then `FirstOrDefault()`. What attribute is\n*used to annotate `FirstOrDefault`?*\n\n**Conclusion**\n\n[MaybeNull], since `T` is unconstrained and could either be a nullable or\nnon-nullable type. More information may be available after type substitution.\n"
  },
  {
    "path": "meetings/2018/LDM-2018-08-22.md",
    "content": "# C# Language Design Notes for August 22, 2018\n\n# Agenda\n\n1. Target-typed new\n1. Clarification on constraints with nullable reference types enabled\n\n# Discussion\n\n## Target-typed new\n\nProposal: https://github.com/dotnet/csharplang/blob/master/proposals/target-typed-new.md\n\n*Question: Should target-typed `new` be allowed for tuple types?*\n\nWe currently don't allow the constructor syntax `new (int, int)(0, 0)`.\nShould we allow `(int, int) t = new(0, 0)`? Would this mean the same thing as\na tuple literal, or a call to a constructor on System.ValueTuple? This would\nalso expose some of the differences between ValueTuple and tuple types, in\nthat there is no constructor for a tuple type with greater than 7 elements.\n\nDecision: Let's allow it, as long as that doesn't require a lot of extra\nwork. The meaning would be to call the underlying System.ValueTuple\nconstructors. This would expose differences in tuples with a lot of elements,\nbut this seems like a very rare and unimportant case.\n\n*Question: Allow `throw new()`? It would convert to bare `Exception` by the spec.*\n\nDecision: Disallow. Fundamentally, we don't like this stylistically.\n\n*Question: Allow `new()` with user-defined comparison and arithmetic operators?*\n\nDecision: Allow.\n\n\n## Generic constraints with nullable reference types\n\n*Question: In the following snippet, is `U` a non-nullable reference type?*\n\n```C#\nvoid M<T, U>() where T : class, U : T` {}\n```\n\nAnswer: Yes\n\n*Question: In the following snippet, is `I` a non-nullable reference type?*\n\n```C#\ninterface I {}\nvoid M<T>() where T : I {}\n```\n\nAnswer: Yes\n\n*Q: Do we want to warn for redundant constraints?*\n\nA: We don't currently. Let's stay with that decision for now."
  },
  {
    "path": "meetings/2018/LDM-2018-09-05.md",
    "content": "# C# Language Design Notes for September 5, 2018\n\n## Agenda\n\n1. Index operator: is it a unary operator?\n1. Compiler intrinsics\n\n# Discussion\n\n## Index operator\n\nThere are multiple questions here:\n\n1. Is the operator syntactically a unary operator?\n1. Is it a user-definable operator?\n1. Does it have the same precedence as other unary operators?\n1. Do members which do not exist implicitly exist anyway as an intrinsic?\n1. Does it have overloads? Is `^^1` allowed? That would imply that there's an\n   overload which takes an index.\n\nFollow-up: is `..` a binary operator?\n\n**Conclusion**\n\nAgreed that it's syntactically a unary operator. Also agreed that it is a\nsemantically treated as a unary operator that it is not user-definable. Right\nnow, we don't see a great need to add a second overload. There is a single\noverload for `int`.\n\nWe're not strictly defining `..` as a binary operator right now. It has its\nown syntactic form.\n\nAlso, we're renaming '^' to the \"hat\" operator.\n\n## Compiler intrinsics\n\nProposal: https://github.com/dotnet/csharplang/blob/master/proposals/intrinsics.md\n\nThere is contention between using `void*` and some stronger typing, either a\ndelegate or some kind of function pointer syntax. The benefit of using a\npointer type is that it is always unsafe, which this feature requires if\nthere are no allocations (because an appdomain could unload and cause the\ninvocation to point to arbitrary memory).\n\nFor `calli`, there's a worry about moving the typing from the point of\nretrieving a function pointer to the declaration of the target and calling\nconvention. The `extern` declaration, specifically, is disliked.\n\nDoes this only work for managed code or also for native code? Do we have to\ncare about the calling convention?\n\n**Conclusion**\n\nWe'd probably be willing to accept this in some form. We think the current\nproposal needs some work.\n\nSome thoughts/suggestions:\n\n1. Don't allow instance `&receiver.M` form -- only types for instance methods\n   e.g., `&TypeName.M`.\n1. Drop the separate declaration for the `calli` invocation. A special calling\n   form like `_calli_stdcall(args, f)` is suggested. We don't like signature\n   being declared somewhere other than the method definition or at the call site.\n1. Would like the calling convention, if used, present at the call site."
  },
  {
    "path": "meetings/2018/LDM-2018-09-10.md",
    "content": "# C# Language Design Notes for September 10, 2018\n\n## Agenda\n\n1. Nullability of constraints in inheritance and interface implementation\n2. Static local functions\n\n# Discussion\n\nQOTD: *Don't open your mind so much the language falls out*\n\n## Nullability of constraints in overriding\n\nIn C# we don't allow override methods to re-specify generic constraints.\nThe question then is how to treat constraints that are inherited from\na base method with a different `NonNullTypes` attribute. For example:\n\n```C#\n// Assembly 1\n[NonNullTypes(true)]\nclass Base\n{\n    virtual void M<T>() where T : C?\n    { }\n}\n\n---\n// Assembly 2\n\n[NonNullTypes(false)]\nclass Derived : Base\n{\n    override void M<T>()\n    { }\n}\n```\n\nDoes using `T` as a non-null type produce a warning, even though we've said\n`[NonNullTypes(false)]` in the derived class?\n\n**Conclusion**\n\nWhen the base context is `true` and the derived is `false`, suppress related\nwarnings. When the base is false and the derived is true, treat unannotated\nconstraints as oblivious.\n\n\n### Inheritance and explicit interface implementation\n\nSimilar to the above case, there's a question about how \"sticky\" nullability\nis through interface implementation and inheritance. For instance, the following\nclass uses a constructed inherited member to explicitly implement an interface.\nDoes nullability on the type parameters have to match?\n\nHere is the correct implementation:\n\n```C#\ninterface I1<T>\n{\n    void M<U>() where U : T\n}\n\nclass C : I1<C?>\n{\n    void I1<C?>.M<X>() {}\n}\n```\n\nAnd what if you remove the question mark in the explicit implementation?\n\n```C#\nclass C : I1<C?>\n{\n    void I1<C>.M<X>() {}\n}\n```\n\n**Conclusion**\n\nIf the member and the implementing type share the same `NonNullTypes` context,\nthe annotations must match, so the example directly above that mismatches\n`C?` with `C` would be an error stating that the class `C` does not implement\nthe interface `I1<C?>`.\n\nIf the `NonNullTypes` context differs and the context on the outside is\n`false` and the inside is `true`, there is no error or warning about the\nmismatch, but a warning that `?` is disallowed in `NonNullTypes(false)`\ncontext. If the context on the inside is `false` and the `outside` is true,\nthere is also no error or warning, this time because the interior context\ncauses `C` to be treated as oblivious, which can match with `C?`.\n\n## Static local functions\n\nProposal: https://github.com/dotnet/csharplang/issues/1565\n\nWe like this proposal. One potentially confusing part is that static local\nfunctions cannot capture local variables, even in containing static methods.\nThis is appropriate for the design, and we intend to keep it, but acknowledge\nthat it may be confusing at first.\n\n**Q & A**\n\n*Q:* If the proposal is accepted we would allow two states to be enforced: all\ncapturing is allowed and no capturing is allowed. Do we want to allow \nintermediate states with something like capture lists?\n\n**A:** No, this is as far as we go.\n\n*Q:* Should we allow attributes too? That could be useful for related scenarios,\nlike P/Invoke.\n\n**A:** Yes, we liked the idea originally, but it didn't make C# 7.0. We'd like\nto finalize support for this.\n\n*Q:* Should we relax shadowing rules? This isn't strictly related to the\nproposal, but it seems like the restriction is more draconian with static local\nfunctions because you cannot capture variables and instead have to come up with\nnew names if they are being passed as arguments.\n\n**A:** We dislike differing shadowing behavior between static and non-static\nlocal functions. We're warm to the idea of allowing all local function parameters\nshadow locals in parent scopes. We're also interested in allowing shadowing in\nlambdas. We would like to see a separate proposal on this to document the details.\n\n*Q:* Can static local functions capture type parameters?\n\n**A:** Yes.\n\n*Q:* Do we want to allow \"static lambdas\"? \n\n**A:** The value seems much lower since lambdas are usually much shorter. It's\nalso a more intrusive syntax inline to the call. Rejected."
  },
  {
    "path": "meetings/2018/LDM-2018-09-19.md",
    "content": "\n# C# Language Design Notes for September 19, 2018\n\n## Agenda\n\nTriage:\n\n1. XML doc comment features\n2. New `foreach` pattern using `Length` and indexer\n3. Object initializers for `readonly` members\n4. `readonly` struct methods\n5. `params Span<T>`\n6. Nullable reference type features on `Nullable<T>`\n\n## Discussion\n\n### XML Doc and related features\n\nProposals:\n\n- https://github.com/dotnet/csharplang/issues/313\n- https://github.com/dotnet/csharplang/issues/1766\n- https://github.com/dotnet/csharplang/issues/1767\n- https://github.com/dotnet/csharplang/issues/1768\n- https://github.com/dotnet/csharplang/issues/315\n- https://github.com/dotnet/csharplang/issues/320\n- https://github.com/dotnet/csharplang/issues/401\n- https://github.com/dotnet/csharplang/issues/1764\n- https://github.com/dotnet/csharplang/issues/1765\n\nWe're not very excited about designing features in doc comments, primarily\nbecause a lot of design work depends more on tooling ecosystem than language\ndesign. It seems like there's a lot of coordination that should happen\noutside LDM before we look at it inside LDM. Most of the features aren't\nuseful without a near-term guarantee of tooling support.\n\n**Conclusion**\n\nWe need the tooling and ecosystem designers and owners to weigh in before\nwe're ready to move forward. Specifically, we need a fully fleshed out,\ndetailed proposal for exactly what the total work is and a timeline for\ncompletion. Once that's in place, we should consider all the XML doc comment\nchanges at once. We're moving this into an `X.0` release, since we think the\ntooling changes merit a major release and we are blocked on external work.\n\n### New `foreach` pattern using `Length` and indexer\n\nProposal: https://github.com/dotnet/csharplang/issues/1424\n\nThere are a bunch of options around signaling support for this feature\nwithout incurring a breaking change, including using an attribute, using a\nnew interface, considering a new pattern (including the ref/ref-readonly\nvariants). `foreach` already has a lot of different variants, so any change\nhas to fully account for all the possibilities.\n\nIt's also notable that we've seen LINQ performance as a concern for quite a\nwhile and we haven't ruled out doing something for that. If we add a new\ninterface for LINQ we might want to use the same interface as a trigger for\nnew optimizations here. We almost certainly wouldn't want to create a\nduplicate interface.\n\n**Conclusion**\n\nWe don't like this specific proposal, but will continue to look at features\nin this area.\n\n### Readonly object initializers\n\nProposal: https://github.com/dotnet/csharplang/issues/1684\n\n**Conclusion** \n\nA lot of crossover with records proposals here. This seems like more of a special\ncase -- let's see if we can make a generalization work before we go this route.\n\n### `readonly` functions on structs\n\nProposal: https://github.com/dotnet/csharplang/issues/1710\n\nFirst concern is ordering restrictions of the \"readonly\" modifier. It can\nalso indicate a \"readonly ref\" return type, so we need to make sure it's not\nambiguous.\n\nThere's also another option: do we allow explicit receivers so the user could\nspecify `void M(in this S s)` and explicitly declare the variables which are\nreadonly?\n\n**Conclusion**\n\nWe're interested. Let's keep the design as-is for now.\n\n### `params Span<T>`\n\nProposal: https://github.com/dotnet/csharplang/issues/1757\n\nThis would be especially interesting if the CLR implements a new feature for\nstack allocating an array of reference types.\n\n**Conclusion**\n\nLet's keep it in C# 8. A lot of stuff to work out here.\n\n### Add nullable reference type features to nullable value types\n\nProposal: https://github.com/dotnet/csharplang/issues/1865\n\nLet's look at this for 8.0 if only to make sure doing it later is not\na breaking change."
  },
  {
    "path": "meetings/2018/LDM-2018-09-24.md",
    "content": "\n# C# Language Design Notes for September 24, 2018\n\n## Agenda\n\nF#/C# combined LDM\n\nTwo primary goals:\n\n1. What new C# features are going to require work to get F# support?\n2. How can the design of C# features play well with the broader .NET environment?\n\n## Discussion\n\nFirst, which proposed C# 8.0 features may need interop work in F#?\n\n- [**Nullable reference types**](https://github.com/dotnet/csharplang/issues/36)\n  - This is by far the top priority\n  - F# will need to recognize C# nullability attributes and possibly\n    emit them itself\n- [`params Span<T>`](https://github.com/dotnet/csharplang/issues/1757)\n  - Consumption is probably more important than production\n  - Need to make sure F# compiler doesn't choke on a ParamArrayAttribute on\n    a type other than array\n- [Slicing/Range](https://github.com/dotnet/csharplang/issues/185)\n  - There should probably be a way to convert from F# to C# range/index\n- [Records](https://github.com/dotnet/csharplang/issues/39)\n  - Significant work if this actually makes it into C# 8.0\n- [UTF8 string literals](https://github.com/dotnet/csharplang/issues/184)\n  - Probably more work in language parity, specifically on F# usage of the\n    UTF8 string type itself\n- [Default interface methods](https://github.com/dotnet/csharplang/issues/52)\n  - As currently spec'd, F# should at least be able to implement interfaces\n    with default implementations\n  - Open question as to how much consumption or production will be supported\n    in F# if C# goes ahead with the current design\n- [Pattern-based using](https://github.com/dotnet/csharplang/issues/1174)\n  - We think F# already supports this. No work to do here\n- [Async streams (IAsyncEnumerable)](https://github.com/dotnet/csharplang/issues/43)\n  - Probably need a helper method to convert from `IAsyncEnumerable` to F# AsyncSeq,\n    but since `Task` doesn't yet have first-class support, this is not the highest\n    priority\n- [Native-sized integers](https://github.com/dotnet/csharplang/issues/435)\n  - Possibly some codegen support for whatever we do here\n- [Readonly members on structs](https://github.com/dotnet/csharplang/issues/1710)\n  - Probably no work on the consumption side, but work would be required if\n    F# wanted to allow declaring them\n\nSecond, how should interop with other .NET languages impact C# language design?\n\n### Nullable reference types\n\nThis is both the biggest item and also the most likely to ship in C# 8.0.\nRight now, there's no mechanism for other types to be treated with the same\nnullability rules provided via the C# nullable reference type feature.\nSpecifically, there's the question of how F#'s `Option` type will\ninter-operate with C# nullable reference types. At the moment we don't have\nany design to let arbitrary types to be treated as \"nullable\" wrappers, but\nwe do have a proposal to allow the `Nullable<T>` type to opt-in to nullable\nreference type behaviors (https://github.com/dotnet/csharplang/issues/1865).\nWe're considering broadening this to other nullable wrapper types. This\nmay also affect our future discriminated union design.\n\nThe other question is if we want to explore a different way of representing\nnullable reference types in the CLR. Right now the proposal is to do this\nentirely using attributes and not treat these as different types in C#. If\nwe did want to treat them as different types, CLR work should be considered.\n\n### Default implementations in interfaces\n\nWe went very far down one specific design strategy (traits). Let's come up\nfor air and see if we want to explore any other points in the design space.\nWe should also take into account our proposals around type classes\n(https://github.com/dotnet/csharplang/issues/110).\n\n### Discriminated unions\n\nIt's not on the list for C# 8.0, but when we get around to it we should\nexplore code generation strategies with the CLR to see how we could get the\nmost efficient type switching implementation. F# also notes that they don't\nencourage using discriminated unions in public APIs due to the risk of\nbreaking changes from exhaustiveness checking. We should consider whether we\nwant the same restriction or provide some support for versioned discriminated\nunions."
  },
  {
    "path": "meetings/2018/LDM-2018-09-26.md",
    "content": "# C# Language Design Notes for September 26, 2018\n\n## Agenda\n\nWarning waves\n\n## Discussion\n\nMotivation: Right now we consider adding a new warning to existing code to be\na breaking change. We want a way to add diagnostics without it being a\nbreaking change.\n\nSolution: Some mechanism to opt-in to breaks (\"warning waves\").\n\nFor warning project levels, we consider \"latest\" to be the most common setting\naside from \"none\". Most people who want all possible warnings will target\n\"latest\", and will only choose an earlier warning level number when the get\na new warning that they can't fix at the moment for some reason.\n\nNegatives: Seemingly unrelated warnings are grouped into a bundle that may be\nconfusing. However, enabling individual warnings seems both a pain for users\nto do every update, and very difficult for discovery (where do users find the\nlist of new warnings?)\n\nWhen you haven't enabled the warning wave, we still want the diagnostics to\nappear, but we want them to be suppressed such that the IDE and tooling can\nsee them, but the user does not (normally). Exactly what type of suppression\nwe use is to be solved.\n\n### Q & A\n\nOne problem we'd like to address with warning waves is definite assignment\nof structs with private members where, due to various compiler bugs, the\nstruct appears to be definitely assigned when it is not. \n\n*Q: Definite assignment diagnostics are always errors right now -- should we allow \"error waves\" as well?*\n\n**A:**\n\nNo, for now. Let's see if we can provide warnings for some of these issues\nwithout producing errors.\n\n*Q: Should warning waves be per-SyntaxTree or per-Compilation?*\n\n**A:**\n\nPer-Compilation for now. The SyntaxTree level may be an interesting feature\nbut there are no scenarios compelling enough right now that merit the\nadditional complexity.\n\n*Q: Is the command line option case sensitive or case insensitive?*\n\n**A:** Case-insensitive.\n\n*Q: How does the IDE get access to info on the warning waves?*\n\n**A:**\n\nThe compiler should provide an API to get a list of all warning IDs in a\nparticular wave. The IDE should also pull from the compiler resources to\nfind the description for each particular warning. The compiler also needs\nto know which warning versions are valid. We also need an API for getting\nwhich warning wave a particular warning is part of, if any. Warnings in\nnew language features are never part of a warning wave.\n\n*Q: What's the bar for adding a warning to a warning wave? Is it the same\nas whether or not we would have created a diagnostic if we were doing\nthe feature for the first time now?*\n\n**Conclusion**\n\nNo. This will still cause users to do extra work, so we need to make sure\nthat each warning we're adding is worth the change. We should also consider\nhow much work will go into a particular warning wave and avoid overwhelming\nthe user. Based on feedback we can dial the severity back and forth.\n\nHowever, we should introduce high-impact changes as soon as possible to make\nit clear what kind of breaks users are signing up for.\n\n*Q: Do we want a \"major\" flag for upgrading language version only with major\nversion?*\n\n**Conclusion**\n\nNo.\n\n*Q: Which warnings do we put in?*\n\n**Conclusion**\n\nLet's do prioritization later, but don't spend too much time deciding exactly\nwhich one. In general, the system for adding warnings should go through LDM.\n\n*Q: What are the version numbers?*\n\n**Conclusion**\n\nWe aren't sure yet. \"7.3.1\"? \"8.0.0\"? Jared proposes Git SHA.\n\n**Notes:**\n\n1. `csc /warnversion:` with no warnversion could list all the possible\nwarning versions with all of the diagnostic ids in each warnversion and the\ntitle of that warning.\n\n2. No warning waves is `/warnversion:none`. All warnings is\n`/warnversion:all`.\n"
  },
  {
    "path": "meetings/2018/LDM-2018-10-01.md",
    "content": "﻿# C# Language Design Notes for Oct 1, 2018\n\n## Agenda\n\n1. Nullable type inference\n2. Type parameters and nullability context\n\n\n# Nullable type inference\n\nGeneric type inference is also used to determine \"best common type\", e.g. in anonymously typed arrays, finding the inferred return type of lambdas with multiple returns, etc. \n\nType inference roughly proceeds as follows:\n\n1. Gather up all the types of the constituent expressions (some, e.g. `null`, may not have a type to contribute)\n2. Among those, gather the ones to which all the constituent expressions have an appropriate implicit conversion\n3. If these are all identity convertible to each other, construct the result from them\n\nThis third step is a little cryptic. Most of the time, when types are identity convertible to each other, they are the *same* type. But there are two exceptions in the language today:\n\n- `object` and `dynamic` are identity convertible to each other\n- Tuple types with pairwise identity convertible element types are identity convertible, regardless of element names\n\nIn step 3 above, in places where the identity convertible types differ by `object` vs `dynamic`, choose dynamic. Where they differ by tuple element names, have the tuple element be unnamed.\n\nThis is all relevant to nullable reference types, because we are about to introduce a third way in which non-identical types can be identity convertible to each other:\n\n- Identity conversion between reference types is determined without regard to their nullability (though if the conversion is performed, it may lead to a warning)\n\nThis means we need to say how to construct the result of type inference with regard to nullability of reference types. Where the identity convertible types differ by nullability, we'll determine the nullability based on the variance of the type's position:\n\n- **Covariant**: A type is in a covariant position if it is\n    - a top level type,\n    - a type argument to a covariant type parameter of a generic type in a covariant position\n    - a type argument to a contravariant type parameter if a generic type in a contravariant position\n- **Contravariant**: A type is in a contravariant position if it is:\n    - a type argument to a contravariant type parameter of a generic type in a covariant position\n    - a type argument to a covariant type parameter if a generic type in a contravariant position\n- **Invariant**: A type is in an invariant position if it is:\n    - a type argument to an invariant type parameter\n    - a type argument to a type parameter of a generic type in an invariant position\n\nFor a given type position in the result type, we'll always pick among the nullabilities present in that position, with one exception.\n\n- In a covariant position pick nullable if present, otherwise oblivious if present, otherwise nonnullable\n- In a contravariant position pick nonnullable if present, otherwise oblivious if present, otherwise nullable\n- In an invariant position:\n    - if both nullable and nonnullable are present, then yield a warning and pick oblivious (this is the one exception)\n    - otherwise if either nullable or nonnullable is present, pick that one\n    - otherwise pick oblivious\n    \nThis leads to nice and symmetric rules, where nullable and nonnullable are treated equally, and oblivious isn't too infectious. As far as we can tell, the rules are associative and can be expressed in a pairwise manner, without causing order dependence. If oblivious had dominated nullable and nonnullable in the invariant case, that would have thwarted associativity.\n\nThe one thing that's a little odd is where nullable and nonnullable clash in an invariant position. Ideally this would lead to an error, but we only want to allow nullability to lead to warnings, not errors, so we need to have some answer for what comes out. Oblivious seems the right choice, in that we've already warned that something is wrong, and it will lead to suppression of further warnings caused by that. What's odd about it is that oblivious normally comes from legacy code that's explicitly opted out of the nullability feature. This is the only place where it can occur in new code that is all \"opted in\".\n\n\n# Type parameters declared and used in different nullability contexts\n\nAllowing a more granular in-file choice between nullability contexts (whether nullable annotations are on or off) leads to new kinds of situations. For instance, a type parameter can be declared in an \"off\" context (oblivious to nullability) but used in an \"on\" context. This is the topic of [Roslyn issue 30214](https://github.com/dotnet/roslyn/issues/30214).\n\nThe context where the type parameter is declared determines whether it should be sensitive to the nullability implications of its constraints. In the example in the issue, the type parameters are oblivious, and should not lead to nullability diagnostics, because they are declared in a \"legacy\" context.\n"
  },
  {
    "path": "meetings/2018/LDM-2018-10-03.md",
    "content": "﻿# C# Language Design Notes for Oct 3, 2018\n\n## Agenda\n\n1. How is the nullable context expressed?\n2. Async streams - which interface shape?\n\n\n# Nullability context\n\nIn order to accommodate \"null-oblivious\" legacy source code while it is under transition, we want to allow regional changes to the context for how nullability is handled. There are actually two interesting \"nullability contexts\":\n\n1. Annotation context: should an unannotated type reference in the context be considered nonnullable or oblivious?\n2. Warning context: If null annotations are violated within the context, should a warning be given?\n\nWe have learned the hard way that we cannot use regular attributes due to circularities in binding. Essentially, modifying semantics with attributes is a bad idea not just from a \"moral\" perspective, but, as it turns out, a technical one: you need to do binding to understand the attributes. If the attributes themselves affect binding (as these would), well hmmm.\n\nThis is causing us to rethink the context switching experience. We have three general candidate ideas for describing regional changes to the nullability context:\n\n1. A new modifier\n2. A \"fake\" or pseudo-attribute\n3. Compiler directives\n\nWe don't have even a strawman-level idea for good modifier keywords, so we are going to drop that one from the discussion. For the two others, there are strawman proposals below for the purposes of discussion.\n\n\n\n## Pseudo-attributes\n\nThe idea is to keep the currently implemented attribute-based user experience, but discover the attributes specially, in an earlier phase of the compiler, rather than through normal binding (where it is too late).\n\nNullable annotations and warnings are controlled by the same attribute, `[NonNullTypes]`. It has a positional boolean parameter that controls annotations, and defaults to true. It has an additional named boolean parameter that controls warnings and defaults to true.\n\nThe attributes override each other hierarchically, and can be applied at the module, type and member levels at least.\n\nHere is an example where nullable annotations are turned off for some members, and warnings are turned off for another member:\n\n``` c#\n[module:NonNullTypes]\n\npublic class Dictionary<TKey, TValue> : ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable, IDictionary<TKey, TValue>, IReadOnlyCollection<KeyValuePair<TKey, TValue>>, IReadOnlyDictionary<TKey, TValue>, ICollection, IDictionary, IDeserializationCallback, ISerializable\n{\n    public Dictionary() { }\n    public Dictionary(IDictionary<TKey, TValue> dictionary) { }\n    public Dictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection) { }\n    public Dictionary(IEqualityComparer<TKey>? comparer) { }\n    [NonNullTypes(false)] public Dictionary(int capacity) { }\n    [NonNullTypes(false)] public Dictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer) { }\n    [NonNullTypes(false)] public Dictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer) { }\n    public Dictionary(int capacity, IEqualityComparer<TKey>? comparer) { }\n    [NonNullTypes(warn = false)] protected Dictionary(SerializationInfo info, StreamingContext context) { }\n}\n```\n\nSome consequences of the attribute being \"fake\":\n\n- argument expressions would have to be literals\n- there's generally a trade off between expressiveness and effort\n- maybe we wouldn't even be able to allow the named parameter\n- What are implications to the semantic model in the Roslyn API? Should you be able to tell the difference?\n\n\n## Directives\n\nThe idea is to control nullable annotations and warnings as separate `#`-prefixed compiler directives that apply lexically to all source code until undone by another directive:\n\n- `#pragma warning disable null` and `#pragma warning restore null` for turning warnings off and on (simply using the `null` keyword as a special diagnostic name for the existing feature)\n- `#nonnull disable` and `#nonnull restore` for turning nullable annotations off and on (reusing the `disable` and `restore` keywords from pragma warnings)\n\nHere is the same example as above, using the directives approach:\n\n\n``` c#\npublic class Dictionary<TKey, TValue> : ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable, IDictionary<TKey, TValue>, IReadOnlyCollection<KeyValuePair<TKey, TValue>>, IReadOnlyDictionary<TKey, TValue>, ICollection, IDictionary, IDeserializationCallback, ISerializable\n{\n    public Dictionary() { }\n    public Dictionary(IDictionary<TKey, TValue> dictionary) { }\n    public Dictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection) { }\n    public Dictionary(IEqualityComparer<TKey>? comparer) { }\n \n#nonnull disable\n    public Dictionary(int capacity) { }\n    public Dictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer) { }\n    public Dictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer) { }\n#nonnull restore\n \n    public Dictionary(int capacity, IEqualityComparer<TKey>? comparer) { }\n \n#pragma warning disable null\n    protected Dictionary(SerializationInfo info, StreamingContext context) { }\n#pragma warning restore null\n}\n```\n\nA consequence:\n- Might require a compiler switch for the global opt-in - which we were happy to get rid of when we first adopted the attribute approach.\n\n\n## Discussion\n\nThe purpose of the feature is to toggle *contextual information* for a region of code: a) whether unannotated type references in the region should be interpreted as nonnullable, and b) whether warnings should be yielded for violations of nullable intent within the region.\n\nIt is uncommon for attributes to affect context. Modifiers sometimes do (unsafe, checked/unchecked), and directives sometimes do (#pragma warning). Attributes usually directly affect the entity to which they are attached, rather than elements (declarations, expressions, etc.) within it.\n\nIt is also uncommon - and usually considered undesirable - for attributes to affect semantics. In fact, it is affecting semantics that is causing the problem in the first place, because attributes also *depend* on semantics.\n\nSyntactically, directives stand out from the syntax, and generally indent to the left margin. They are *about* the source code, not part of it. Attributes are enmeshed with the code itself, and stand out less. Which signal do we want to send? \"The rules of the game have changed in this region of source code\" vs \"This class or member is special with regards to nullability\"?\n\nAttributes are syntactically limited in their *granularity* – they can only apply to certain nodes in the syntax tree. Directives are free to appear between any two tokens (as long as there are line breaks between them), including at both a smaller scale (in between statements and expressions) and a larger scale (around multiple types or even namespaces) than attributes. They can also modify top-level non-metadata constructs such as using aliases.\n\nWherever we *infer* obliviousness for a specific declaration, directives would let you make that same declaration explicitly (albeit awkwardly), whereas attributes would generally be unable to.\n\nOn the other hand, in practice your desired granularity would often be at the member or type level, where attributes would do just fine. The ability of directives to turn off and then on *at different syntactic nesting levels* is just weird, and hardly useful. Maybe the natural prevention attributes provide against such anomalies is a good thing. Then again, other directives already have this ability, and that doesn’t seem to cause trouble in practice.\n\nInside of method bodies, change of the warning context seems more likely than the annotation context.\n\nAttributes are the means by which we would have to encode the context in metadata regardless. So using attributes in syntax would be more direct than having to come up with a scheme for generating attributes from weirdly placed directives. While changing context around a using alias or in the middle of a member body wouldn’t need to have direct metadata effects, the same is not the case for a context change inside, say, a constraints clause. We would need to either invent an encoding scheme, or error on such places.\n\nDirectives would more likely allow editor-config integration.\n\nAttributes would maybe complicate the semantic model.\n\nFinally, \"pseudo-attributes\", recognized specially by the compiler, are a new concept to the language. Is it worth it? In practice, though, the seams are mostly not going to show: a user won’t generally need to worry that it’s not a regular attribute. Conversely, `#nonnull` would be a new directive: Is it worth it?\n\n## Conclusion\n\nGiven all this, we are in favor of the directive approach. We will start from the strawman and refine over the coming weeks.\n\n\n\n# Async streams\n\nThe idea behind async streams is to make them analogous to synchronous `IEnumerable<T>`s, allowing them to be consumed by `foreach` in asynchronous methods, and produced by `yield return`ing asynchronous iterator methods. The natural shape of the `IAsyncEnumerable<T>` interface is therefore simply a straightforwardly \"async'ified\" version of `IEnumerable<T>`, like this:\n\n``` c#\npublic interface IAsyncEnumerable<out T>\n{\n    IAsyncEnumerator<T> GetAsyncEnumerator();\n}\n\npublic interface IAsyncEnumerator<out T> : IAsyncDisposable\n{\n    ValueTask<bool> MoveNextAsync();\n    T Current { get; }\n}\n\npublic interface IAsyncDisposable\n{\n    ValueTask DisposeAsync();\n}\n```\n\nThis works well. The main difference (other than `Async` occurring in names) is that `MoveNextAsync` is asynchronous, so that you need to await it to learn if there is a next value, and before `Current` can be assumed to contain that value. Just as the semantics of `foreach` can be described (and *is* described in the language spec) as an expansion to a while loop, `foreach await` is an almost identical expansion, except with some `await`ing going on.\n\nIt is also generally quite efficient. The use of `ValueTask` instead of `Task` allows implementers (including the ones produced from iterators by the compiler) to avoid any allocations during iteration time, storing any state needed to track the asynchrony alongside the iteration state in the enumerator object that implements `IAsyncEnumerator<T>` (which can often in turn be shared with the implementation of `IAsyncEnumerable<T>` itself). Thus, the number of allocations needed to iterate an `IAsyncEnumerable<T>` will typically be zero, and occasionally (in the case of concurrent iterations) one (for a second enumerator that can't be shared with the enumerable).\n\nOne problem remains, performance-wise, and it is shared with the original synchronous `IEnumerable<T>`: It requires *two* interface calls per loop iteration, whereas with clever tricks that could be brought down to \"usually one\" in cases where the next value is most often available synchronously. The best `IAsyncEnumerator<T>` design we can come up with that satisfies those properties is the following:\n\n``` c#\npublic interface IAsyncEnumerator<out T> : IAsyncDisposable\n{\n    ValueTask<bool> WaitForNextAsync();\n    T TryGetNext(out bool success);\n}\n```\n\nHere the `TryGetNext` method can be used to loop synchronously through all the readily available values. Only when it yields `false` do we need to fall back to an outer loop that awaits calls to `WaitForNextAsync()` until more data is available.\n\nIn the degenerate case where `TryGetNext` always yields `false`, this is not faster: you fall back to the outer loop and always have two interface calls. However, the more often `TryGetNext` yields true, the more often we can stay in the inner loop and skip an interface call.\n\nThe interface has several drawbacks, though:\n\n- It is meaningfully different from the synchronous `IAsyncEnumerator<T>`\n- `TryGetNext` is unidiomatic, in that it switches its success result and its value result, in order to allow the type parameter to be covariant, making it annoying to manually consume\n- The meaning of the two methods is less intuitively clear\n- The double loop consumption is more complicated\n\nIt's a dilemma between simple and fast. The performance benefit of the fast version can be up to 2x, when most elements are available synchronously, and the work in the loop is small enough to be dominated by the interface calls. But it really is a lot harder to use manually. While that doesn't matter when you use `foreach` and iterators, there are still enough residual scenarios where you really need to produce or consume the interface directly. An example is the implementation of `Zip`.\n\nThere are ways to have the two approaches coexist. If we support both of them statically, we'd end up exploding e.g. async LINQ with vast amounts of surface area. That'd be terrible and confusing.\n\nBut there's also a dynamic approach. Already today, many LINQ query operators are implemented to do type checks on their inputs to see if they support a faster implementation. For instance, `Count` on an array can just access the `Length` instead of iterating to count the elements.\n\nSimilarly we could have a fast async enumerator interface that generally lives under the hood. But implementations of e.g. LINQ methods can type check for the fast interface and use it if applicable. The code generated for foreach could even do that too, though that probably leads to complicated code. We can also generate iterators that implement both interfaces.\n\n## Conclusion\n\nWe want to stick with the simple `IEnumerator<T>`-like interface in general. We'll keep the \"fast under the hood\" option in our back pocket and decide after the first preview whether to apply that, but the surface area that people see and trade in should be the simple, straightforward \"port\" of `IEnumerator<T>` to \"async space\".\n\n"
  },
  {
    "path": "meetings/2018/LDM-2018-10-10.md",
    "content": "\n# C# Language Design Notes for Oct 10, 2018\n\n_QOTD: C# has a long and proud tradition of being oblivious_\n\n## Agenda\n\n1. Pattern matching open questions\n\n## Discussion\n\nAll questions are in [this issue](https://github.com/dotnet/csharplang/issues/1054)\n\n### Short discard diagnostics\n\n**Conclusion**\n\nWe've taken breaking changes like this before, but there's more risk to\nthis one because this code is legal all the way back to C# 1.0. This will\nnot be an error -- an underscore in a case block with a constant `_` in\nscope will match the constant. A warning wave warning should be added\nto make matching a constant named `_` a warning.\n \n### Nullable reference types vs switch analysis\n\nIn general, the nullable analysis computes very similar information to\nswitch exhaustiveness. It would be strange if the switch produced\ninformation contrary to the nullable analysis. There are some fundamental\nlanguage semantic problems with making switch (and pattern) exhaustiveness\nand nullable analysis depend on each other. One possibility may be to\nperform the analysis for both of these situations simultaneously. We don't\nthink that the exhaustiveness analysis doesn't affect the nullable analysis\ndirectly. Alternatively, we can phrase exhaustiveness as exclusive of\nnullable reference types and let the null analysis handle switch\nexhaustiveness for null specifically. Nullable value types would be handled\nas part of traditional exhaustiveness.\n\n**Conclusion**\n\nLet's explore the separation of exhaustiveness between null and non-null, st.\nall exhaustiveness warnings do not consider null, and warnings related to null\nare delayed until nullable analysis.\n\nAlso, regardless of whether or not we generate a warning for the following case,\n`i` is not definitely assigned at the end:\n\n```C#\nint i;\nswitch (s)\n{\n    case string t: i = 0; break;\n}\nConsole.WriteLine(i); // is i definitely assigned?\n```\n\n### Permit optionally omitting the pattern on the last branch of switch expr\n\n**Conclusion**\n\nRejected.\n\n### Should exhaustiveness affect definite assignment?\n\n**Conclusion**\n\nConfirmed the current behavior.\n\n### Switch expression as statement expression\n\n**Conclusion**\n\nWe like it. Not sure it will make it for C# 8.0.\n\n### Single-element positional deconstruction\n\n**Conclusion**\n\nWe need to think about 1-tuples again."
  },
  {
    "path": "meetings/2018/LDM-2018-10-15.md",
    "content": "\n# C# Language Design Notes for Oct 15, 2018\n\n## Agenda\n\n1. [Function pointers](https://github.com/dotnet/csharplang/blob/master/proposals/function-pointers.md)\n2. [Readonly struct members](https://github.com/dotnet/csharplang/issues/1710)\n3. Syntax for async streams\n\n## Discussion\n\n### Function pointers\n\nWe're leaning towards no names. The encoding and scoping of the naming seems\nlike it could be a problem. Not having names is not a new problem and it does\nnot seem worse than far more common things like tuples. We many consider a\nricher augmentation of aliasing in general, which would help not only\nfunction pointers, but all the places where you may want to alias an existing\ntype.\n\nSyntax: we played around with multiple funcptr type syntaxes. We haven't\nsettled on a syntax yet, but we have been convinced by Jared that the\n`Func<a,b>*` syntax is unworkable. If we later introduce a new structural\nfunction pointer type and syntax, we could evolve the current syntax to\nsupport the new syntax.\n\n*Q: Do we want the '&' when converting a method group to a `funcptr`?*\n\nOne argument is that it's extra syntax at the place where the feature is\nleast unsafe (at the declaration), instead of the place where's it's most\nunsafe (at the invocation). However, it is similar to syntax for other\npointer types in the language and \"feels right\" when you see it. Let's keep\nit.\n\n**Conclusion**\n\nWe like this approach a lot more than the previous attempt. The main item\nleft is to make sure the syntax is unambiguous.\n\n### Readonly struct members\n\nWe discussed this feature back when we added \"readonly\" for struct\ndefinitions and decided we might consider it later. It is now later.\n\nLooking back on the language, we feel the silent copying of structs to avoid\nmutation is a bit of a wart. One thing stopping us from providing a warning\nis the lack of this feature, since sometimes you cannot mark a struct\nreadonly just to avoid the copy. This feature would fill out the space enough\nthat we could consider a warning wave or an analyzer to warn about silent\nstruct copies.\n\nExamined a few syntaxes for this:\n\n- An attribute ([ReadonlyMethod]?)\n- `readonly` at the end\n- `readonly` at the beginning\n- Allow the explicit `this` parameter and let it be passed by `in`\n\n**Conclusion**\n\nWe like the feature and think the syntax should be a `readonly` modifier at\nthe beginning of the method, along with the other modifiers.\n\n### Syntax of `foreach await`/`using await`\n\n`foreach await (...)` or `foreach async (...)` or `async foreach (...)`?\n\nIn the past we've followed the pattern that there's always an explicit\n`await` in the code if we're awaiting. There's some debate on what sounds\nbest.\n\n**Conclusion**\n\n`await foreach (...)` and `await using (...)`.\n"
  },
  {
    "path": "meetings/2018/LDM-2018-10-17.md",
    "content": "\n# C# Language Design Notes for Oct 17, 2018\n\n## Agenda\n\n1. Open issues with default interface methods\n2. Target typed new with default constructors on structs\n\n## Discussion\n\n### Issues in default interface methods\n\nLink: https://github.com/dotnet/csharplang/issues/406\n\n#### Diamond inheritance\n\nWe've come down to two options: pick an implementation somewhat arbitrarily,\nor produce a runtime exception. The positive about picking one is that we\nmore strongly provide the guarantee that adding a default method\nimplementation will not \"break\" the application. The minus is that there's no\nguarantee that the method we actually picked is the correct one.\n\nIt's also noted that adding a virtual method to a base class can implement an\ninterface in the derived class, but you can get the same result just through\ncurrent language behavior:\n\n```C#\ninterface IFoo { void M() { impl; } }\nclass Derived : Base, IFoo {}\n\nclass Base : Base0\n{\n    public virtual void M() {} // added later\n}\n\nclass Base0 : IFoo\n{\n    void IFoo.M() { }\n}\n```\n\n**Conclusion**\n\nWe're going to throw a runtime exception (we want a new exception type) when\nthere is a runtime diamond and there is no unique most derived\nimplementation. We've decided that the exception will be thrown at method\nresolution time, so the exception would be thrown when taking a delegate to\nthe target method, rather than when the delegate is invoked. We should note\nin documentation when this kind of change could be a source or binary\nbreaking change.\n\nWe'd like to have some method to provide static verification, as long as we\ncan provide a tool that has access to the runtime environment (like the IL\nlinker).\n\n#### Permit partial in interface?\n\nPartial methods, in addition to the partial type?\n\n**Conclusion**\n\nYes, with the same restrictions as in classes.\n\n#### `Main` in an interface?\n\nNo reason why not.\n\n#### Confirm that we support public non-virtual methods\n\nYes, we'll support it.\n\n#### Does an `override` in an interface introduce a new member?\n\nNo override keyword in interfaces. This should resolve all listed questions.\n\n#### Properties with a private accessor\n\nWe say that private members are not virtual, and the combination of virtual and private is disallowed. But what about a property with a private accessor?\n\n``` c#\ninterface IA\n{\n    public virtual int P\n    {\n        get => 3;\n        private set => { } \n    }\n}\n```\n\nIs this allowed? Is the `set` accessor here `virtual` or not? Can it be overridden where it is accessible? Does the following implicitly implement only the `get` accessor?\n\n``` c#\nclass C : IA\n{\n    public int P\n    {\n        get => 4;\n        set { }\n    }\n}\n```\n\nIs the following presumably an error because IA.P.set isn't virtual and also because it isn't accessible?\n\n``` c#\nclass C : IA\n{\n    int IA.P\n    {\n        get => 4;\n        set { }\n    }\n}\n```\n\nThe first example looks valid, while the last does not. This is resolved\nanalogously to how it already works in C#.\n\n#### Warning for struct not implementing default method?\n\nThis seems like something more suited for an analyzer. It also seems like this\nwarning could be noisy, since it would fire even if the default interface method\nis never called and no boxing will ever occur.\n\n#### When are interface static constructors run?\n\nOn the desktop CLR, static methods on interfaces currently run the static\nconstructor on entry if it has not already been run. It's proposed that we adopt\nthe same behavior for instance methods.\n\n**Conclusion**\n\nStatic constructors are also run on entry to instance methods, if the static\nconstructor was not `beforefieldinit`, in which case static constructors are\nrun before access to the first static field.\n\n### Target-typed new()\n\nCan you use new() on anything that has a valid constructor? Like `int`? Or a\ntuple?\n\n**Conclusion**\n\nYes.\n"
  },
  {
    "path": "meetings/2018/LDM-2018-10-22.md",
    "content": "# C# Language Design Notes for Oct 22, 2018\n\n## Agenda\n\nDiscuss two records proposals: \n\n1. [The existing old\none](https://github.com/dotnet/csharplang/blob/master/proposals/records.md)\n\n2. [The data classes\nproposal](https://github.com/dotnet/csharplang/pull/1667)\n\n## Discussion\n\n### \"Nominal\" records.\n\nNominal is more resilient to reordering or adding members. Part of the\nmotivation here is the experience from CompilationOptions in Roslyn, which we\naccidentally broke a couple of times.\n\nThe classes that nominal records would replace are often mutable, just so\nthat object initializers can work. Nominal are proposed to facilitate object\ninitializers even for immutable ones. The trick for allowing that is a\npattern that uses an underlying builder struct. The proposal would emit\nerrors or warnings on object initializers that neglect to initialize\nproperties which aren't declared with an initializer.\n\nWe think that object initializers are not just the result of \"lazy\" API\ndesign, but an initialization pattern that folks actually prefer. With many\ndata elements it certainly has a better tooling experience. The presence of\nan accessible constructor with a (well recognized) builder at the end would\nbe what allows an object initializer to work. It's a bit similar to params.\n\nFor inheritance, you would make a builder per layer of inheritance, which\ngets a little ugly. It might be an argument for making them unspeakable. The\nproposal for builders being \"striped\" also builds the structure of the\ninheritance hierarchy into the public surface area, so that changing the\nhierarchy would be breaking under the hood.\n\nAll alternatives that we can think of also have pretty horrendous downsides.\n\n#### Fields\n\nThe proposal translates them into ref-returning getter-only properties, and\nsticks them in the builder. This would break reflection compared to today. VB\ndoesn't have ref returns, so it's interesting how it deals with them when it\nencounters them. We need to make sure that this wouldn't degrade the VB\nexperience.\n\n- [ ] Open Issue: does it break anything else?\n\n#### Equality\n\nMutable data members in classes should generally not participate in equality\nand hash code by default. Otherwise, there's the risk that the item gets\nadded to a hash table, then its hash code value changes when one of the\nmembers gets mutated.\n\n*Q: does this feature buy us enough to be worth the cost?*\nMaybe not just for compat, because most people won't rewrite old code the new\nway. It's the value to new code that's most important. That said, this is an\nimportant opportunity for cleanup that would help people not accidentally\nbreak themselves or their customers when they evolve.\n\n### Positional records\n\nShould we reserve the `class C(X x, Y y, Z z)` syntax for primary\nconstructors? First idea is that `data` as a modifier is necessary to make it\na positional record. But then adding data changes the meaning of the\nparameter list quite radically.\n\n### \"Positional\" vs. \"Nominal\"\n\nThe positional proposal is syntactic sugar for something that people to a\nlarger degree do today. The nominal is maybe more something that they wish\nthey could do, but don't have the expressiveness to do yet.\n\nThe positional proposal produces With methods that are so nice it might not\neven be worth it to put a with expression syntax on top. For the nominal\nproposal, because of the builders, you really want a syntax on top, or it\ngets unsightly.\n\nSummary of benefits of nominal over positional records:\n\n- Object initializer syntax (could possibly be added to positional)\n- Binary\ncompat from version to version when you move to records (positional can't) \n- Source compat\n\n**Conclusion**\n\nThere are many components of the proposals that don't quite yet feel like\nthey click together, but we should keep working on that.\n\n### Discriminated unions:\n\nThe record syntax will probably affect discriminated union design. That\ndoesn't mean we shouldn't keep exploring records.\n\nDiscriminated unions will also probably face the public/private API dichotomy\nbeing explored in records: if you ever want to add more cases, you break\nevery consumer's exhaustiveness check.\n"
  },
  {
    "path": "meetings/2018/LDM-2018-10-24.md",
    "content": "\n# C# Language Design Notes for Oct 24, 2018\n\n## Agenda\n\n1. [Adding Nullable Reference Type features to Nullable Value Types](https://github.com/dotnet/csharplang/issues/1865)\n2. Open issues with pattern matching \n\n## Discussion\n\n### Tracking null state for `Nullable<T>`\n\nNote that the proposed null tracking would not warn on `GetValueOrDefault`,\nwhich is legal on null values.\n\n*Q: Do we want to prohibit `!` on assigning to a `Nullable<T>`?*\n\n`Nullable<T>` is fully type-safe and the analysis is precise. The only cases\nwe can't prove are complicated uses/checks that the compiler can't prove. If\nwe force the user to rewrite their code such that the compiler can prove\nsafety, we may not need `!`.\n\n**Conclusion**\n\nLet's extend the tracking for nullable reference types to `Nullable<T>`. \n\nFor banning, `!`, we're worried this is too restrictive and there still may\nbe places where you want the \"easy out\" of `!`.\n\nNote: For the flow analysis, we will consider a value type that is accessed\nas though it were non-null to be non-null thereafter. There is no situation\nfor the reverse for value types. We will never treat a non-Nullable value\ntype as a Nullable value type, regardless of how you treat it.\n\n### Using nullable values as non-nullable values\n\n*Q: Would we regard the new uses of the underlying members as implicitly turning\non nullable warnings?*\n\n**A:** Yes, probably.\n\nPros:\n- It's more convenient\n- It's safe because you'll get a warning\n\nCons:\n- The checking is not precise, because we allow `!`\n- Type analysis is less precise, but easier to understand. We adopted the\n  flow analysis mainly because we had back compat concerns with existing\n  null checking code for reference types. Here we don't have to deal with\n  backwards compatibility.\n- This would also contravene the information provide the declaration site.\n  This figures into seeing the annotation at the declaration vs the use site\n\n**Conclusion:**\n\nWe're not going to do this.\n\n### Pattern matching open issues\n\n#### Is a pattern permitted to match a pointer type?\n\nYou can't explicitly match a pointer because you can't write a pointer type\nas a pattern (`*` is used for multiplication in this context).\n\nHowever, it would be weird to make an exception for discard and `var`, so it\nwill be allowed for those use cases.\n\n*Q: What about `ptr is null`? Or `ptr is {}`?*\n\nAllow `ptr is null`. No `ptr is {}` or anything else.\n\n#### ITuple vs unconstrained type parameter\n\nLet's keep it an error for now. We may relax the restriction later.\n\n### Matching ITuple in the presence of extension Deconstruct\n\nThis has some similarities in dynamic/static lookup conflicts in\nGetEnumerator/IEnumerable. Currently, if we see a struct GetEnumerator that\ndoesn't match the pattern we provide an error, even if there is a valid\nIEnumerable interface underneath. Here the Deconstruct is an extension\nmethod, so the analogy is not perfect.\n\nUsing the Deconstruct method seems more consistent with what we do for\ninstance methods, although this would be different based on whether or not\nthe extension method is in scope.\n\nHowever, it seems difficult to actually implement the check for extension\nDeconstruct, because it's not clear whether none of the extension Deconstruct\nmethods match because they are not meant for the given receiver, or if they\nwere simply incorrectly written.\n\nIf we disregard Deconstruct, this would create a difference between the\nbehavior for instance Deconstruct methods and extension Deconstruct methods.\n\n**Conclusion**\n\nNone. Let's look at the implementation in more detail and come back with a\nproposal."
  },
  {
    "path": "meetings/2018/LDM-2018-10-29.md",
    "content": "\n# C# Language Design Notes for Oct 29, 2018\n\n## Agenda\n\n[Source-level opt-in to nullable reference types](https://github.com/dotnet/csharplang/issues/1939)\n\n## Discussion\n\n### Philosophy of specification\n\nTo start off we discussed the proposal in the broader context of specifying\nnullability as a feature in the language specification. The proposal talks\nabout \"nullable contexts\" but we also need to decide what a \"context\" implies.\n\nTwo basic approaches:\n\n1. Specify all the details in the language spec, including annotations.\n2. Specify very loosely: \"'?' means the programmer expects the value may be\n   null. The absence means the programmer does not expect the value to be null.\"\n\nWhere we land on this spectrum decides how prescriptive we need to be about\nthe warnings produced and exactly what conditions produce them.\n\nFirst question: how much does the spec act as the intermediary of conforming\ncompiler implementations? One argument is that warnings are not decisions\nabout legal programs, so the requirements are softer than other areas of the\nspec. On the other hand, warnings often make a big difference when trying to\nport from one compiler to another, regardless of how much they matter to the\nspec. In the past, presence of warnings has been a major factor in porting\nfrom `msc` to `csc` and vice versa.\n\nHowever, the Roslyn analyzer public API could be seen as part of the warning\nsurface which is entirely at the compiler level, and creates far more burden\non other C# compiler implementations than any spec addition.\n\nAn elaboration of (2) is that we could think about the entire feature, aside\nfrom the new syntax for `?` and `!` as a \"built-in analyzer\" for the compiler\nthat isn't strictly specified by the language, but also therefore cannot\naffect the semantics of the language.\n\n**Conclusion**\n\nWe're actually going to end up somewhere in a spectrum between (1) and (2),\nbut we're interested in leaning more towards (2). \n\n### Annotation vs Warning context\n\n*Q: Do we want to provide warnings about `?` when the annotation context is\n*disabled?*\n\nSimilarly, do we want to emit metadata that treats these as nullable types\nto users of the library?\n\nIf we don't warn, this would allow you to easily add `?` for use in other\nareas of the code where the context is enabled, letting you easily annotate\nyour code over time.\n\nOn the other hand, there's no way to go the other direction, indicating that\nparameters are non-nullable and that nullable types should not be passed.\n\nThe original motivation was about a new user using the feature and you annotate\none parameter of your method:\n\n```C#\nvoid M(string arg1, string? arg2)\n```\n\nWithout a pragma setting the non-null context, `arg1` is oblivious, but `arg2`\nis nullable. The user may not realize that `arg1` is not non-nullable because\nthey don't have a pragma. The warning is a feedback system to let a user know\nthat they only part of the nullable feature enabled.\n\n**Conclusion**\n\nWarn about `?` when annotation context is off. Regardless of the annotation\ncontext, the type is considered nullable and will generate warnings if used\nby a consumer in a warning-enabled context. Similarly, metadata will persist\nthe nullable type and the consumer will consider the type nullable.\n\n*Q: Do we warn on `!` when the warning context is off?*\n\nFirst item -- even with the proposal, it's not clear what it means for a warning\ncontext to be on or off. Does disabling the warning mean that the warning context\nis off?\n\n**Conclusion**\n\nDon't warn about `!`, regardless of context.\n\n### Scenarios\n\nThere's some argument that (5) and (6) may be more important/common than (3)\nand (4), but that doesn't mean the conclusions change.\n\n**Conclusions**\n\nWe like the `#nullable ...` directive, but we're not sure about the\n`#pragma warning nullable ...`. Let's keep it for now, but we're not settled on\na specific definition.\n\nNote: the proposal has the current syntax wrong. The proposal lists the syntax\nfor configuring a diagnostic as\n\n```C#\n#pragma warning CS4321 restore\n```\n\nbut it is actually\n\n```C#\n#pragma warning restore CS4321\n```\n\nThis was not intentional and the proposal should not be read as flipping the\nID order. In the proposal, `nullable` is meant to stand in for the diagnostic\nidentifier, effectively acting as a reserved diagnostic ID."
  },
  {
    "path": "meetings/2018/LDM-2018-10-31.md",
    "content": "\n# C# Design Review Notes for Oct 31, 2018\n\nThis was a review with the full design team (including Anders) to see how the\nwhole release is shaping out.\n\n## Discussion\n\n### Nullable\n\n#### Flow analysis to turn a non-nullable type to nullable\n\nThe question is whether flow analysis can cause types to become nullable if a\nvalue of non-nullable type is compared to null.\n \n```C#\nvoid M(string x)\n{\n   if (x == null)\n   {\n       // is x now treated as ‘string?’ here?\n   }\n}\n```\n\nThis is an issue that TypeScript has dealt with. There's some worry that most\nof the warnings will be produced not at the place with the problem. We should\nbe careful that we're not going to annoy the user.\n\n#### Flow analysis and refactoring\n\nFlow analysis constrains refactoring because something may be tested null by\nflow analysis, but if you pass to a new method, the flow analysis is lost. For\nexample: \n\n```C#\nclass C\n{\n    string? Prop1 { get; }\n    string? Prop2 { get; }\n}\n\nclass C2\n{\n    void M1(C c)\n    {\n        if (c.Prop1 != null && c.Prop2 != null)\n        {\n            M2(c);\n        }\n    }\n\n    void M2(C c)\n    { \n        // The null checking from M1 is lost here and M2 has to\n        // check again for null to avoid a warning\n        c.Prop1.Equals(...)\n    }\n}\n```\n\n#### `!` on parameters\n\nVery different behavior depending on where `!` appears -- maybe too many\nmeanings.\n\n#### Treatment of lambdas\n\nFor\n\n```C#\nvoid M()\n{\n    int? x = null;\n    Action a = () => x = 0;\n    a();\n    // What's the null state of `x` here?\n}\n```\n\nTreating the delegate conversion as executing the method is unsafe, but\nnot doing so is conservative and will warn on valid checking. TypeScript\nhas also hit this and there's no easy answer."
  },
  {
    "path": "meetings/2018/LDM-2018-11-05.md",
    "content": "\n# C# Language Design Notes for Nov 5, 2018\n\n## Agenda\n\n1. Where can #nullable go?\n2. Open issues with pattern matching\n\n## Discussion\n\n### Where can you put `#nullable`?\n\n*Q: Does `#nullable` appear in metadata in any way?*\n\nIt may be useful to minimize the amount of extra metadata by putting it on\ncontainers (like types) and letting the context flow down. However, this\nbecomes complex when considering things like `partial`. In general, we don't\nwant to let the implementation decide the language support and we would\nprefer to limit things only if it improves the language experience, not makes\nimplementation easier.\n\nInstead, we'll start by where it makes sense to allow `#nullable` for the\nlanguage.\n\n*Q: If we were to allow it anywhere, where does it span?*\n\nOne proposal is the last token in the type syntax. So\n\n```C#\nDictionary<string,\n#nullable disable\n    string>\n#nullable enable\n```\n\nspecifies the nullable context for the second `string` and the context for\n`Dictionary<string, string>`.\n\n*Q: If we believe that the least restrictive version is a reasonable design, what\nmakes sense from an implementation perspective?*\n\nBasing the context on the end type token is a reasonable design for\nimplementation. If we decide that this causes significant extra metadata to\nbe generated, we can provide optimizations at emit time without changing the\nsemantics of the language.\n\n**Conclusion**\n\nBasing the nullable context on the last token in the pragma region actually\nmakes a lot of sense. Let's go ahead with that as the current plan.\n\nFor warnings, we would base it entirely on diagnostic locations, which is\nwhat we do for pragma suppression right now.\n\n### Misc. Nullable\n\n*Proposal: Do not allow nullable on the right of a using alias*\n\nAccepted.\n\n*Q: What about `typeof` and `nameof`?*\n\nSame behavior as nullable value types (allowed in `typeof`, not in `nameof`).\n\n### Pattern matching\n\n#### Deconstruction and ITuple\n\n*Proposal:*\n\n1. If the type is a tuple type (any arity >1; see below) then use tuple semantics\n2. If the type has no accessible instance Deconstruct and satisfies the `ITuple`\n   deconstruct constraints, use `ITuple` semantics\n3. Otherwise attempt `Deconstruct` semantics (instance or extension)\n\nArguments against:\n\n- Exhaustiveness gets better with an extension Deconstruct\n- Different behavior between pattern matching and deconstruction\n  - But the extension and ITuple implementation should be semantically equivalent\n- Boxes in the case of no instance Deconstruct and an explicit ITuple implementation\n  - But pattern matching boxes anyway for everything except a concrete value type\n\nArguments for:\n\n- We don't have to add complex rules about which extensions are applicable\n\n\n*Alternative Proposal:*\n\n1. If the type is a tuple type (any arity >1; see below) then use tuple semantics\n2. If \"binding\" a Deconstruct invocation finds one or more applicable methods,\n   use Deconstruct.\n3. If the type satisfies the `ITuple` deconstruct constraints, use `ITuple`\n\n**Conclusion**\n\nWe like the alternative more, but very slightly.\n\n#### Pattern matching with 0 and 1 elements\n\n*Proposal:*\n\nPermit pattern-matching tuple patterns with 0 and 1 elements (appropriately\ndisambiguated as previously decided)\n\n```C#\nif (e is ()) ...\n\nif (e is (1) _) ...\nif (e is (x: 1)) ...\nif (e is (1, 2)) ...\n```\n\nThe primary concern here is that these disambiguations are impossible in deconstructing\ndeclarations and deconstructing assignments. However, we think that's a fine limitation,\nsince there are simple workarounds in all of those contexts. Pattern matching, however,\nhas no such workaround.\n\n**Conclusion**\n\nAccepted.\n\n*Proposal:*\n\nConsider `System.ValueTuple` and `System.ValueTuple<T>` to be tuple types. No syntax changes.\n\n**Conclusion**\n\nAccepted."
  },
  {
    "path": "meetings/2018/LDM-2018-11-14.md",
    "content": "\n# C# Language Design Notes for Nov 14, 2018\n\n## Agenda\n\n1. Base call syntax for default interface implementations\n2. Switch exhaustiveness and null\n\n## Discussion\n\n### Default interface implementations\n\nExample of base calls:\n\n```C#\ninterface I1 { void M(); }\ninterface I2 { void M(); }\ninterface I3 : I1, I2 { void I1.M() { } void I2.M() { } }\ninterface I4 : I1, I2 { void I1.M() { } void I2.M() { } }\ninterface I5 : I3, I4\n{\n    void I1.M()\n    {\n        base<I3>(I1).M();\n        base<I4>(I1).M();\n    }\n    void I2.M()\n    {\n        base<I3>(I2).M();\n        base<I4>(I2).M();\n    }\n}\n```\n\nQ: Should we even allow the programmer to call explicit implementations?\n\nIn existing C# code this is not allowed since all explicit implementations\nare private. You can always call by casting to the interface if the interface\nis not re-implemented, but there's no way to do this via a base call.\n\nHowever, there's no way to use overriding default interface implementation in\nC# 8.0 *except* for explicit implementation, so not allowing it would basically\nnot allow the scenario.\n\nJava does allow this scenario, so full compat would require us to add the feature.\n\nQ: What type of dispatch would we use in the runtime?\n\nOne way is to constrain to the interface, then do a virtual dispatch for a\nparticular method. This probably would require additional (fairly expensive)\nruntime work.\n\nQ: What does the syntax need to express?\n\nOne problem is for `I3`, where by signature `M` is ambiguous because it's not\nclear whether you mean `I1.M` and `I2.M`. The syntax would need to specify both\nthat the `I3` implementation is requested *and* whether or not to choose `I1.M` or\n`I2.M`.\n\nOne other option is to just not provide a way of disambiguating `M`. If there's an\nambiguity you can't call any particular `M`.\n\n**Conclusion**\n\nLet's do the simplified form. If the `M` being called is ambiguous, it's illegal to\ncall such a method. The only configuration we're considering is which base to look\nfor the method.\n\n#### Syntax\n\n```C#\nnamespace N {\n    interface I1<T> { int M(string s) => s.Length; }\n}\nclass C : I1<T>\n{\n    int I1.M(string s)\n    {\n        // Options:\n        base<N.I1<T>>.M(s);\n        base(N.I1<T>).M(s);\n        N.I1<T>.base.M(2);\n        base{N.I1<T>}\n        base:N.I1<T>.M(s);\n        base!N.I1<T>.M(s);\n        base@N.I1<T>.M(s);\n        base::global::N.I1<T>.M(s);\n        base.(N.I1<T>).M(s);\n        (base as N.I1).M(s); // base isn't an expression, so this isn't legal today\n        ((N.I1)base).M(s); // same here\n        base.N.I1.M(s);  // clash with a member on base, doesn't allow for qualified name\n        N.I1.M(s); // this is currently a static call on I1, can't work\n    }\n}\n```\n\nWe think the forms that take advantage of `base` not being an expression are\ntoo clever and would just be confusing. `N.I1.base.M(2)` is possibly tricky\nfor human readability since `base` is in the middle and is harder to notice\nwithout coloration.\n\nOne problem with `base(N.I1).M(s)` is if we want to add \"invocation\" operators\nto the language, that would disallow invoking your base.\n\n`base::N.I1<T>.M(s)` has some history in the language.\n\n**Conclusion**\n\nDecided on `base(N.I1<T>).M(s)`, conceding that if we have an invocation\nbinding there may be problem here later on.\n\n\n### Switch exhaustiveness and null\n\nCurrent design: warning about not handling all inputs *except* null.\n\nQ: What happens when the switch actually doesn't match what was given at\ncompile time?\n\n**Proposal**:\n\nA new `MatchFailureException` that extends `ArgumentException`. This allows\nthe compiler to use an existing exception for down-level support. There's\nno data, just a message.\n\n**Conclusion**\n\nThe base should be `InvalidOperationException`, not `ArgumentException`. If\nthe argument being switched on can be trivially boxed into object, we'll add\nit as an argument to the `MatchFailureException`. Otherwise, just fill in\n`null`."
  },
  {
    "path": "meetings/2018/LDM-2018-11-28.md",
    "content": "\n# C# LDM notes for Nov 28, 2018\n\n1. Are nullable annotations part of array specifiers?\n2. Cancellation of async-streams\n\n# Discussion\n\n## Nullable array specifiers\n\nDue to history, the syntax for array specifiers is actually \"outside-in\",\ni.e. the first set of `[]` actually refers to the outermost array. For the\nelements themselves, you always specify the `?` directly after the element\ntype name, so `string?[][]` works regardless of interpretation.\n\nFor specifying the nullability of the \"innermost\" vs \"outermost\" arrays, it\nseems like we have two possibilities for describing nullability here:\n\n1. `string[]?[] a`\n2. `string[][]? a`\n\nEither of these could specify that the *innermost* array is null. Here are full\nexamples of the meaning of approaches (1) and (2) with a type declaration:\n\n```\nstring?[][] a; new string?[3][] // 1. Array nullable string, 2. likewise\nstring[]?[] a; // 1. Nullable array of array of string, 2. Array of nullable array of string\nstring[][]? a; // 1. Array of nullable array of string, 2. Nullable array of array of string\n```\n\nIf we look at instantiation, rather than type declaration, the two approaches look\nlike:\n\n1. \n\n```\nnew string?[3][]\nnew string[3]?[] // invalid\nnew string[3][]?\n```\n\n\n2.\n\n```\nnew string?[3][]\nnew string[3][]? // invalid\nnew string[]?[3]\n```\n\nThere's also one more option that's a hybrid. Because of array covariance and\nnullable covariance, assigning an array of non-nullable arrays to an array of\nnullable arrays does not generate warnings. Declarations would like (2), but\ninstantiation would actually disallow `?` completely:\n\n3.\n\n```\nstring?[][] a = new string?[3][];\n// string[]?[] a = new string[]?[3]; // disallow ? in new\nstring[]?[] a = new string[3][];\nstring[][]? a = new string[3][];\n```\n\nThere are essentially two mental models of multi-dimensional arrays that have\nserved people writing multi-dimensional array code: the way the code actually\nworks, and a \"type nesting\" model that is mostly non-observable in the\ncurrent language. When choosing between options 1 and 2/3, we have a decision\nto either preserve how multi-dimensional arrays actually \"work\", regardless\nof whether or not it's confusing, or try to accommodate how we might prefer\nthey work and how people may actually think they work.\n\nOption (1) is attractive not only because it's how the feature currently\nworks, but also because Option 2/3 would involve changing the order of the\nrank specifier specifically for nullable multi-dimensional arrays, so code\nthat previously used `new string[3][]` would now be written `new\nstring[]?[3]`, changing not just the location of the `?`, but also the\nlocation of `3`.\n\nOne reason to go with accommodation is to make nullability specifically more\nsimilar to how it works in other places in the language. Generally, to make a\ntype nullable, you add a `?` to the end. This would not be the case with the\nexisting multi-dimensional array model.\n\nIf most people are adopting existing code with jagged arrays, Option 2/3 may\nmake it easier to adopt the rules common in other areas of the language to\nmake the warnings go away. Since we don't provide nullability warnings for\neverything but assigning null as the innermost array, the nullability of the\ninnermost array matters a little less.\n\n\n**Decision**\n\nLet's stick with the current implementation (1). People may have incorrect\nmental models which have served them sufficiently until now, but we don't\nyet see sufficient motivation for complicating the language.\n\n\n## Cancellation of async streams\n\n### CancellationToken in the IAsyncEnum* interfaces\n\nThe first question is what kind of support for cancellation we want to put\ninto the interface itself. The primary proposal here is changing the\nsignature of `IAsyncEnumerable<T>` to take an optional CancellationToken:\n\n```C#\nIAsyncEnumerable<T>\n{\n    IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken token = default);\n}\n```\n\nThe user's implementation of the interface could then provide a mechanism to\npass a CancellationToken during construction, and we could provide an\nextension method `IAsyncEnumerable<T> WithCancellationToken<T>(this\nIAsyncEnumerable<T> e, CancellationToken token)` that could wrap an existing\n`IAsyncEnumerable<T>` with a cancellable one.\n\n### Async iterators and `await foreach`\n\nFor the new language features there are two potential scenarios to support.\n\nThe first is allowing the user to pass in their own token for consumption\ni.e., cancellation during an `await foreach`.\n\nThe second scenario is allowing the user to consume a CancellationToken\nduring production i.e., when writing an async iterator.\n\n#### Consumption\n\nMost proposals center around some extra syntax for `await foreach` that\nallows a CancellationToken to be passed e.g.,\n\n```C#\nawait foreach (var x in e, cancellationToken)\n{\n    ...\n}\n```\n\nIf we allow specifying the cancellation token during enumeration, passing\nthe cancellation token when calling the generated iterator is probably the\nwrong place to pass it, as you should put it in through enumeration.\n\n#### Production\n\nA user scenario is the user is writing an iterator and wants to react to\na cancellation token that can in as a parameter. For example,\n\n```C#\nasync IAsyncEnumerable<int> M(..., CancellationToken token = default)\n{ ... }\n```\n\nIf we're writing an iterator, the main feature we would need to support is\nputting the CancellationToken into the generated iterator and specifically\nconnect it to a CancellationToken provided to the method.\n\nOne way of supporting this would have a special \"value\"-like keyword that\nrefers to an implicit cancellation token that's used in the generated\nenumerable. An even more maximalist proposal would allow implicit\nCancellationTokens that can be added to the end of *any* method, and if a\nCancellationToken is passed anywhere then it can be implicitly threaded\nthrough. This is a much larger feature.\n\nAnother way of providing a CancellationToken could be specifying that a\nparticular parameter that is the special CancellationToken, e.g.\n```C#\nIAsyncEnumerable<int> M(..., [Cancellation]CancellationToken token = default)`\n```\n\nWhichever way the custom token is specified, the token would be stored in the\n`IAsyncEnumerable` state machine, and if another token is passed to\n`GetEnumeratorAsync` then we would also store that and decide if we create a\ncombined token for both, or override the original token provided.\n\n**Decision**\n\n1. Change `IAsyncEnumerable<T>.GetAsyncEnumerator()` to `IAsyncEnumerable<T>.GetAsyncEnumerator(CancellationToken token = default)` and\nprovide a `WithCancellation` extension method.\n\n2. In the constructed iterator state machine, `GetEnumerator` should\nthrow if the given CancellationToken is cancelled. It's not decided exactly\nwhere or how often we will check for cancellation.\n\n3. Do nothing more, right now. Revisit the production and consumption sides\nof this before shipping."
  },
  {
    "path": "meetings/2018/LDM-2018-12-03.md",
    "content": "\n# C# LDM notes for Dec 3, 2018\n\n## Agenda\n\n1. `using` declaration open issues\n2. Return type of `Range` indexer on array and FX types\n\n## Discussion\n\n### `using` declaration open issues\n\n*Q: Do we want to reserve '_' to mean discard in a `using` e.g., `using var _\n*= ...;`?\nThis would let the user set the scope for an expression without creating an\nidentifier.*\n\n**Conclusion**\n\nYes, this seems useful.\n\n#### Deconstruction\n\n*Q: Do we want to allow a deconstruction in the declaration e.g., `using var\n(x, y) = GetResources()`?*\n\nWe noted that this could mean two different things: the outer tuple is\ndisposed, then deconstructed, or the elements are deconstructed, then each\nis disposed.\n\n**Conclusion**\n\nThis seems too complicated for the marginal benefit. Rejected.\n\n#### `goto` and using declarations\n\nExample:\n\n```C#\ngoto label;\nusing var x = ...;\nlabel:\n    ...\n```\n\nCan you `goto` past a `using` declaration? Can you `goto` before a `using`\ndeclaration? Can you `goto` in the same block, but not past the `using`? Can\nyou even have labels and `using var` in the same block?\n\n**Conclusion**\n\nYou definitely can't `goto` \"past\" a using var. That would be similar to\njumping \"into\" a try-finally.\n\nWe could allow jumping \"out\" of a `using var`, but we're concerned it may\nbe confusing, since there may not be a syntactical indication that the\ndisposal is executed.\n\nWhen `goto`ing a label in the same statement list as a `using var`, the\n`goto` must not have a `using var` syntactically between the `goto` and\nthe label.\n\n#### Extension `Dispose()` and `Nullable<T>`\n\n*Q: Should an extension `Dispose()` method be called if the receiver is null?*\n\nNo, the behavior is defined as `item?.Dispose()`, and so `Dispose()` will not\nbe called for `null` values.\n\n*Q: For a value of type `S?` and extension methods `Dispose(this S? s)` and\n`Dispose(this S s)`, which is called?*\n\nSame resolution as above: the behavior is defined as `value?.Dispose()`, so\nwe do the same thing as `item?.Dispose()` (which picks `Dispose(this S s)`).\n\n\n### Return values of Range indexers\n\nProposals:\n\n1. Add indexers that return the same types (string returns a string, array returns\n   an array, Span returns a Span, etc.)\n2. Don't add indexers that allocate/copy, add overloads to do slicing with ranges\n3. Add indexers that return Span\\<T>\n4. Add indexers that return Memory\\<T>\n5. Do nothing\n\n(3) and (2) are initially attractive because they automatically produce the\nfastest possible behavior with no allocation. Essentially, users are in a pit\nof success from a performance perspective. \n\nThere are two main problems with this: \n\n1. Span is not considered \"general purpose\" and can be quite difficult to use.\n   Not being able to store the value in a field or convert it to an interface\n   is difficult.\n2. Span and Memory are very new types and most code doesn't use them. Users\n   would often be forced to coerce into another type anyway. This is particularly\n   bad for strings, where almost all operations are only available on the `string`\n   type.\n\nThe opposing proposal is (1). The theory is that users are more likely to be able\nuse that they pass in. For many users, the additional allocation and copying will\nnot be prohibitive. For performance sensitive users, instead of passing arrays\naround directly, they can proactively convert to Span or Memory and all subsequent\nindexing operations will be 0-allocation.\n\nThe main problem with (1) is performance-sensitive users are essentially in a\npit of failure in this proposal. The short syntax makes the indexers\nattractive, but likely to harm performance.\n\nIt was also noted that indexers are generally not supposed to hide expensive\nor complicated operations, according to .NET coding guidelines. However,\nRange indexers are fundamentally new operations (they even return a different\ntype -- a collection instead of an element) and it's not clear we should\nnaively apply the same standards for existing indexers to Range indexers.\n\n**Conclusion**\n\nSettled on (1), with overloads for `AsSpan(Range r)` that return a `Span<T>`.\nThis should reduce the work necessary to go directly from a Span-compatible\ntypes to Span slices.\n\nCoreFX Proposal: https://github.com/dotnet/designs/pull/48\n\n*Q: Do we want to allow Range/Index indexers on multidimensional arrays? They\nare currently prohibited.*\n\n**Conclusion**\n\nUndecided. We need to discuss this in another LDM.\n"
  },
  {
    "path": "meetings/2018/LDM-2018-12-05.md",
    "content": "\n# C# LDM notes for Dec 5, 2018\n\n## Agenda\n\nTracked nullable states, their correspondence to source and the rules they follow in flow analysis\n\n## Proposal\n\nSince we are treating nullable analysis as a conventional lattice data flow analysis,\nwe'd like to define the lattice.\n\nHere are the states based on current implementation:\n\n* Unknown\n* NotAnnotated\n* Annotated\n* NotNullable\n* Nullable\n\nThe goal is to get to a concrete specification that defines how the flow state\naffects the language and how flow states interact.\n\nThe first task is to decide how the annotations and the nullable context\ninteract to define the flow state. At the moment, the context of where the\nvariable is *defined* decides what the state of the variable is in, when it\nis used in a method. However, there is a proposal to use the context *of the\nmethod* to define the state the variable is in.\n\nThere are now new proposed states, which are now split between states used in\nflow analysis, and states used as semantic annotation.\n\nSemantic states:\n\n* Nullable\n* Oblivious\n* NotAnnotated\n\nFlow states:\n\n* \"Can be null\" (true or false)\n\nConsequences:\n\nWhen reading a field we compute the flow state as follows:\n\n* `Nullable` -> `true`\n* `Oblivious` -> `false`\n* `NotAnnotated` -> `true` only if a type parameter that could be nullable,\n  else `false`\n\nWhen writing a field we warn as follows:\n\n* `NotAnnotated`, `true` -> warn if the RHS can be null when the variable (or\n   type) can't (i.e., take into account both being related type parameters)\n\n## Discussion\n\n*Q: What warnings do we produce for the following?*\n\n```C#\nvoid M<T>(T p1) where T : class?\n{\n    p1 = p1; // p1 may be null, but we don't produce a warning because\n             // the T could be nullable\n}\n```\n\nThe consequence is:\n\n```C#\nvoid M<T>(T p) where T : class?\n{\n    p = null; // This DOES produce a warning, because there's a conversion\n              // from `null` to T and we don't know that T is nullable\n}\n```\n\nAlso:\n\n```C#\nvoid M<T>(T p) where T : class?\n{\n    if (p == null) // <- this is fine\n    {\n        T x = p; // <- this also doesn't give a warning because\n                 // there is no conversion\n    }\n}\n```\n\nAnd:\n\n```C#\nvoid M(string p1)\n{\n    if (p1 == null)\n    {\n        string x = p1; // W warning? -> Yes\n    }\n}\n```\n\n\nBetween the current state and the new proposal, what's the behavior of the following?\n\n```C#\n#nullable disable\nvar t = M(new object()); // What is T inferred as?\n...\n#nullable enable\nt.Value = null; // warning?\n...\n\nBox<T> M<T>(T t) => new Box(t);\n```\n\nCurrent: `Box<T>` is inferred as `Box<object!>`, warning\nNew proposal: `Box<T>` is inferred as `Box<object~>`, so no warning\n\n\n```C#\nvoid M<T>(T x) \n{\n    if (x == null) throw;\n    var y = x;\n    var z = M(y); // What is the inferred type?\n    z.Value = null; // warning?\n}\n...\nBox<T> M<T>(T t) => new Box(t);\n```\n\nCurrent implementation: `Box<T2>` is `Box<T!>`, warning\nNew proposal: `Box<T2>` is inferred as `Box<T>`, no warnings\n"
  },
  {
    "path": "meetings/2018/LDM-2018-12-12.md",
    "content": "\n# C# LDM notes for Dec 12, 2018\n\n## Agenda\n\n1. Open issues with async streams\n2. Pattern dispose\n\n## Discussion\n\n### Cancellation in GetAsyncEnumerator\n\nWe previously decided that GetAsyncEnumerator takes a CancellationToken.\nWhen do we check if it's been cancelled?\n\nOur design for cancellation in the user code itself is to have the user\nwrite the core logic for their IAsyncEnumerable using an IAsyncEnumerator\niterator method. The user can manually check for cancellation inside the\niterator body.\n\n```C#\nclass C : IAsyncEnumerable\n{\n    IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken token)\n    {\n        ...\n        token.ThrowIfCancelled();\n        ...\n    }\n}\n```\n\n*Q: Do we want to generate any checks manually? One option is to check the\ncancellation token on every MoveNext call.*\n\nThis comes down to: where is it most useful to request cancellation?\n\nThe most important place to include the cancellation token is in the await\ncalls themselves. This isn't compiler generated code at all -- if the\nexpressions being awaited need a CancellationToken the user will need to\npass it themselves. Other places, like every entry to MoveNextAsync, will\nbe called regularly, but will only be able to cancel synchronous code,\ninstead of the long-running async operation.\n\n**Conclusion**\n\nThe compiler will not generate checks for cancellation for now. If we\nget user feedback that it's important, we will revisit this decision.\n\n### Pattern binding\n\nWhich pattern do we want the compiler to recognize for GetAsyncEnumerator?\n\nBinding options for some expression target of a `foreach`, `e`:\n\n1. `e.GetAsyncEnumerable()`\n2. `e.GetAsyncEnumerable(default(CancellationToken))`\n\nOne of the primary drawbacks for (1) is that all users must make their\nCancellationToken parameters optional. This may be a problem for implementors\nwho consider it very important to have a CancellationToken.\n\n**Conclusion**\n\nWe will attempt to bind the call\n`e.GetAsyncEnumerable(default(CancellationToken))` and if it succeeds and has\na conforming return type, the pattern binds successfully.\n\n### Recognizing an iterator\n\nConsider the following:\n\n```C#\nclass Program\n{\n    static async IAsyncEnumerable<string> M()\n    {\n        throw new NotImplementedException();\n    }\n}\n```\n\nAs currently designed, this is illegal. `async` methods must either return\na Task-like type or return `IAsyncEnumerable/IAsyncEnumerator` and contain\na yield statement. This is neither.\n\nThe proposal is to produce an error. There are a number of fixes:\n\n1. Add a `yield` in the body.\n2. Remove the `async`.\n\n**Conclusion**\n\nAdd an error, undecided on the error message.\n\n### When we start recognizing pattern Dispose, do we call it in foreach?\n\nCertainly, it seems very important for the feature. Since a ref struct\ncannot implement interfaces, pattern Dispose is the only way to implement\ndisposal.\n\nThere are a number of possible breaking changes:\n\n1. A pattern enumerable type did not implement IDisposable, but had a\n   Dispose method. This method would now be call.\n2. If there are two Dispose extension methods, that will now produce\n   an ambiguity and thus a compilation error.\n\n**Conclusion**\n\nLet's narrow the pattern-based Dispose change down to ref structs only.\nThis means every other type will be required to implement IDisposable."
  },
  {
    "path": "meetings/2018/README.md",
    "content": "# C# Language Design Notes for 2018\n\nOverview of meetings and agendas for 2018\n\n\n## Jan 3, 2018\n[C# Language Design Notes for Jan 3, 2018](LDM-2018-01-03.md)\n\n1. Scoping of expression variables in constructor initializer\n2. Scoping of expression variables in field initializer\n3. Scoping of expression variables in query clauses\n4. Caller argument expression attribute\n5. Other caller attributes\n6. New constraints\n\n\n## Jan 10, 2018\n[C# Language Design Notes for Jan 10, 2018](LDM-2018-01-10.md)\n\n1. Ranges and endpoint types\n\n\n## Jan 18, 2018 \n[C# Language Design Notes for Jan 18, 2018](LDM-2018-01-18.md)\n\nWe discussed the range operator in C# and the underlying types for it.\n\n1. Scope of the feature\n2. Range types\n3. Type name\n4. Open-ended ranges\n5. Empty ranges\n6. Enumerability\n7. Language questions\n\n\n## Jan 22, 2018\n[C# Language Design Notes for Jan 22, 2018](LDM-2018-01-22.md)\n\nWe continued to discuss the range operator in C# and the underlying types for it.\n\n1. Inclusive or exclusive?\n2. Natural type of range expressions\n3. Start/length notation\n\n\n## Jan 24, 2018\n[C# Language Design Notes for Jan 24, 2018](LDM-2018-01-24.md)\n\n1. Ref reassignment\n2. New constraints\n3. Target typed stackalloc initializers\n4. Deconstruct as ref extension method\n\n## July 9, 2018\n[C# Language Design Notes for July 9, 2018](LDM-2018-07-09.md)\n\n1. `using var` feature\n   1. Overview\n   2. Tuple deconstruction grammar form\n   3. `using expr;` grammar form\n   4. Flow control safety\n2. Pattern-based Dispose in the `using` statement\n3. Relax Multiline interpolated string syntax (`$@`)\n\n## July 11, 2018\n[C# Language Design Notes for July 11, 2018](LDM-2018-07-11.md)\n\n1. Controlling nullable reference types with feature flags\n1. Interaction with NonNullTypesAttribute\n1. Feature flag and 'warning waves'\n1. How 'oblivious' null types interact with generics\n1. Nullable and interface generic constraints\n\n## July 16, 2018\n[C# Language Design Notes for July 16, 2018](LDM-2018-07-16.md)\n\n1. Null-coalescing assignment\n   1. User-defined operators\n   1. Unconstrained type parameters\n   1. Throw expression the right-hand side\n1. Nullable await\n1. Nullable pointer access\n1. Non-nullable reference types feature flag follow-up\n\n##  August 20, 2018\n\n[C# Language Design Notes for August 20, 2018](LDM-2018-08-20.md)\n\n1. Remaining questions on [suppression operator](https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fdotnet%2Froslyn%2Fissues%2F28271&data=02%7C01%7C%7C6defe1e21ab54cce8d0008d606be5d23%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636703812006445395&sdata=DAdh5dev1mnr%2F5zxtvuJVcHP%2Bzewrzz4z9iuGkl%2BUHg%3D&reserved=0) (and possibly cast)\n2. Does a dereference update the null-state?\n3. Null contract attributes\n4. Expanding the feature\n5. Is T? where T : class? allowed or meaningful?\n6. Typing judgments containing oblivious types\n7. Unconstrained T in List\\<T> then `FirstOrDefault()`. What attribute to annotate `FirstOrDefault`?\n\n## August 22, 2018\n\n[C# Language Design Notes for August 22, 2018](LDM-2018-08-22.md)\n\n1. Target-typed new\n1. Clarification on constraints with nullable reference types enabled\n\n## September 5, 2018\n\n[C# Language Design Notes for September 5, 2018](LDM-2018-09-05.md)\n\n1. Index operator: is it a unary operator?\n1. Compiler intrinsics\n\n## September 10, 2018\n\n[C# Language Design Notes for September 10, 2018](LDM-2018-09-10.md)\n\n1. Nullability of constraints in inheritance and interface implementation\n2. Static local functions\n\n## Sep 19, 2018\n\n[C# Language Design Notes for September 19, 2018](LDM-2018-09-19.md)\n\nTriage:\n\n1. XML doc comment features\n2. New `foreach` pattern using `Length` and indexer\n3. Object initializers for `readonly` members\n4. `readonly` struct methods\n5. `params Span<T>`\n6. Nullable reference type features on `Nullable<T>`\n\n## Sep 24, 2018\n\n[C# Language Design Notes for September 24, 2018](LDM-2018-09-24.md)\n\nCombined C#/F# LDM\n\n1. What new C# features are going to require work to get F# support?\n2. How can the design of C# features play well with the broader .NET environment?\n\n## Sep 26, 2018\n\n[C# Language Design Notes for September 26, 2018](LDM-2018-09-26.md)\n\n1. Warning waves\n\n## Oct 1, 2018\n\n[C# Language Design Notes for Oct 1, 2018](LDM-2018-10-01.md)\n\n1. Nullable type inference\n2. Type parameters and nullability context\n\n## Oct 3, 2018\n\n[C# Language Design Notes for Oct 3, 2018](LDM-2018-10-03.md)\n\n1. How is the nullable context expressed?\n2. Async streams - which interface shape?\n\n## Oct 10, 2018\n\n[C# Language Design Notes for Oct 10, 2018](LDM-2018-10-10.md)\n\n1. Pattern matching open questions\n\n## Oct 15, 2018\n\n[C# Language Design Notes for Oct 15, 2018](LDM-2018-10-15.md)\n\n1. Readonly methods in structs\n2. Intrinsics update with function pointers\n3. Finalize syntax for async-streams. Per [last notes](https://github.com/dotnet/csharplang/blob/95c9267d0d54a9984086ca327b1f892790e6c2cf/meetings/2017/LDM-2017-08-30.md#syntax-options), the current tentative syntax is `foreach await (var x in ...) ...`.\n\n## Oct 17, 2018\n\n[C# Language Design Notes for Oct 17, 2018](LDM-2018-10-17.md)\n\n1. [Open issues](https://github.com/dotnet/csharplang/issues/406) with default interface methods\n1. target typed new with default constructors on structs\n\n## Oct 22, 2018\n\n[C# Language Design Notes for Oct 22, 2018](LDM-2018-10-22.md)\n\nDiscussion of records proposals:\n\n1. [The existing old one](https://github.com/dotnet/csharplang/blob/master/proposals/records.md)\n2. [The data classes proposal](https://github.com/dotnet/csharplang/pull/1667)\n\n## Oct 24, 2018\n\n- [Adding Nullable Reference Type features to Nullable Value Types](https://github.com/dotnet/csharplang/issues/1865)\n- Open issues with pattern matching\n\n## Oct 29, 2018\n\n[C# Language Design Notes for Oct 29, 2018](LDM-2018-10-29.md)\n\n- [Source-level opt-in to nullable reference types](https://github.com/dotnet/csharplang/issues/1939)\n\n## Oct 31, 2018\n\n[C# Language Design Notes for Oct 31, 2018](LDM-2018-10-31.md)\n\n- *Design review*\n\n## Nov 5, 2018\n\n[C# Language Design Notes for Nov 5, 2018](LDM-2018-11-05.md)\n\n1. Where can #nullable go?\n2. Open issues with pattern matching\n\n## Nov 14, 2018\n\n[C# Language Design Notes for Nov 14, 2018](LDM-2018-11-14.md)\n\n1. Base call syntax for default interface implementations\n2. Switch exhaustiveness and null\n\n## Nov 28, 2018\n\n[C# Language Design Notes for Nov 28, 2018](LDM-2018-11-28.md)\n\n1. Are nullable annotations part of array specifiers?\n2. Cancellation of async-streams\n\n## Dec 3, 2018\n\n[C# Language Design Notes for Dec 3, 2018](LDM-2018-12-03.md)\n\n1. `using` declaration open issues\n2. Return type of `Range` indexer on array and FX types\n\n## Dec 5, 2018\n\n[C# Language Design Notes for Dec 5, 2018](LDM-2018-12-05.md)\n\n- Tracked nullable states, their correspondence to source and the rules they follow in flow analysis\n\n## Dec 12, 2018\n\n[C# Language Design Notes for Dec 12, 2018](LDM-2018-12-12.md)\n\n- Async-streams misc. questions\n- Compat issue with Dispose pattern in `foreach`\n\n# Upcoming meetings\n\n## Dec 17, 2018\n\n- Review the [Nullable Reference Types Specification](https://github.com/dotnet/csharplang/blob/master/proposals/nullable-reference-types-specification.md)\n\n## Recurring topics\n\n- *Triage championed features*\n- *Triage milestones*\n- *Design review*\n"
  },
  {
    "path": "meetings/2019/LDM-2019-01-07.md",
    "content": "\n# C# Language Design Notes for January 7th, 2019\n\n## Agenda\n\nNullable:\n\n1. Variance in overriding/interface implementation\n2. Breaking change in parsing array specifiers \n\n## Discussion\n\n### variance in overriding/interface implementation\n\nIssues: https://github.com/dotnet/roslyn/issues/23268, https://github.com/dotnet/roslyn/issues/30958\n\nWe currently don't support overriding or inheritance with co/contravariance in nullability.\n\nOverriding: we mostly take the signature from the overriding member, not the base.\n\nWe could allow nullability variance and then use the most derived implementation.\n\nThe problem is if we don't provide a warning on further derivation, another deriver can\n\"re-loosen the contract.\"\n\nThere doesn't seem to be any problem with an interface implementation, because the safety is provided\nin the actual code.\n\nNote: if you override an object-returning method with a dynamic-returning method, we currently\nuse the dynamic return on callsites, which is a parallel to how nullable works.\n\nOptions:\n\n1. Keep stringent invariant rule\n2. Allow safe variation on interface implicit implementation only\n3. Allow on overrides also, check against base override\n\n**Conclusion**\n\nGeneral agreement on (3). Possibly change tuple names to operate similarly\n(use the base's override as the authoritative signature). We will also use\nthe same rules for explicit interface implementation.\n\n### Breaking change in parsing array specifiers\n\nIssue: https://github.com/dotnet/roslyn/issues/32141\n\n```C#\na ? x is A[][] ? b : c\n            // ^ Is this a nullable annotation or part of a ?:\n```\n\nOptions:\n\n1. Keep decision find another solution for ambiguity\n    a. always prefer ternary for back compat, use parens for new meaning in `is`/`as`\n2. Change array decision\n   a. `?` is a type constructor that's applicable to arrays\n   b. Alternate syntax: `?` inside brackets: `a[?][,]` and `a[][,?]`\n\nOne of the main problems with changing the array is: `new string[3][];` In\nthis example, `3` refers to the outer array size, but if we make `string[][]?`\nmean \"top-level nullable,\" there's either an inconsistency between the\nquestion mark location (`new string[3]?[]` means *inner* array is nullable)\nor we swap the location of the rank (`new string[]?[3]`).\n\n**Conclusion**\n\nLet's try to stick with our original design, and add tie breakers to parsing\nto prefer ternary in any ambiguity. Right now we know of problems with array\ntypes in `is` and `as`. There may be more expressions which can end with an\narray type, which we will address as we find them.\n\n*Update: This decision was revised in the Jan. 9th meeting.*"
  },
  {
    "path": "meetings/2019/LDM-2019-01-09.md",
    "content": "\n# C# Language Design Notes for Jan. 9th, 2019\n\n## Agenda\n\n1. GetAsyncEnumerator signature\n2. Ambiguities in nullable array type syntax\n2. Recursive Patterns Open Language Issues https://github.com/dotnet/csharplang/issues/2095\n\n## Discussion\n\n### Async streams GetAsyncEnumerator revisited\n\nDiscussed over email as well.\n\nProposal: bind `e.GetAsyncEnumerator()` and use the result, including methods\nwith optional parameters or `params` and extension methods.\n\nWe like the simple bind accepting optional parameters and `params`, but\nextension methods are a problem. We have a number of different features that\nhave backwards compatibility constraints preventing them from preferring extension\nmethods over interface implementation. In addition, the design of extension methods\nis always as a last resort and we prefer code directly from the type (including\ninterface implementation).\n\n**Conclusion**\n\nBind a lookup, but without extension methods. After looking for the interface,\nconsider extension methods. Follow-up issue to deal with the difference with\nsimple `foreach`, which always looks for a zero-parameter method and doesn't\nconsider extension methods.\n\n*Q: What about [Caller...] attributes?*\n\n**A**: Let's do what we did for LINQ, which has to do roughly the same thing.\n\n### Obsolete \n\nDo we respect the obsolete attribute in lookups in foreach, async foreach,\nand pattern dispose?\n\n**Conclusion**\n\nYes.\n\n### Ambiguities in nullable array types (again)\n\nExample:\n\n`if (o is string[][]?(var e0, var e1, var e2) s)`\n\nThis is now ambiguous because the token after the `?` is not helpful in\nresolving the ambiguity.\n\n1. Keep the order, but address using lookahead\n2. ? is a type constructor (reverse the order of brackets and question marks)\n3. reverse the order of ?'s only\n4. Introduce Array\\<T>\n```C#\nArray<int[]?>\nnew Array<int[]?>(3)\nnew Array<int[]?> { new[] {1}, null, new [] {2, 3 }}\n```\n5. Don't allow nullability in jagged arrays\n\n**Conclusion**\n\nLet's try (2) and see how it works.\n\n### Should SwitchExpressionException capture an unreified tuple input?\n\nYes, we think so.\n\n### Rename deconstruct pattern to positional pattern?\n\nYes. The extra developer work required is worth it.\n\n### Permit trailing comma in a switch expression?\n\n```C#\ne switch {\n    1 => true,\n    2 => false,\n}\n```\n\nYes, permit optional commas anywhere there are curly braces, including\nswitch expressions, property patterns, etc.\n\n### Warnings for non-nullable fields that are not explicitly initialized\n\nScenarios that result in unnecessary warnings:\n\n* Initialization helpers called from other constructors\n* Factory methods that call constructors\n* Object initializers\n* Chained constructors\n* Set-up/tear-down methods in test frameworks\n* Reflection\n\nOptions:\n\n0. Do nothing, keep the current behavior\n1. Don't track initialization.\n2. No warnings for private constructors\n3. No warnings for constructors that call methods that might modify `this`\n4. Track initialization debt with the class only, reporting warnings at\npublic entry points.\n5. Track initialization debt across classes (and assemblies), reporting\nwarnings where the object is constructed\n\n**Conclusion**\n\nLet's keep option 0 for now. We're worried about silently hiding legitimate\nwarnings or that options 4 and 5 are too complicated or expensive to implement."
  },
  {
    "path": "meetings/2019/LDM-2019-01-14.md",
    "content": "\n# C# Language Design Notes for January 14th, 2019\n\n## Agenda\n\n1. Generating null-check for `parameter!`\n\n## Discussion\n\n### Generating null-check for parameter!\n\nProposal: https://github.com/dotnet/csharplang/pull/2144\n\n*Q: Allow on unconstrained generic parameters?*\n\n**A**: Not a lot of reason to disallow it. `is` currently doesn't work on\nunconstrained type parameters, but we view that as a limitation we'd like to\nlift.\n\n*Q: Where is the null check for constructors?*\n\nBefore or after the base/this calls? Syntactically, it's consistent to leave\nit in the constructor body, after the base/this calls. However, this could\ncause us to do more work before the exception is eventually thrown.\n\n**A**: In the case where the base/this call would throw anyway, there's not\nmuch difference. But in the case that the base/this are null-safe, putting\nthe check in the body just delays the exception, which provides little value.\nThe null check should be the first statement in the method. In general, the\nnull check should be performed as soon as possible.\n\n*Q: Is there a warning for `void M(string? param!)`?*\n\n`string?` suggests that the method gracefully accepts null, but the feature\nimmediately throws, which doesn't count.\n\nHowever, when overriding you may have a `string?` as your base, but your\noverride only accepts non-nullable `string`.\n\n**A**: Yes. In the case where a user is warned about violating the OHI\ncontract, the correct decision is to silence the OHI warning, keeping\nconsistency between the implementation and signature of the method.\n\n*Q: Where is the null check for iterators?*\n\n**A**: Null check in the stub method, as soon as possible (before the yield).\n\n*Q: Can you put it on lambda parameter names?*\n\n**A**: Yes, as long as there are no problems in the syntax. If there\nare ambiguities with simple lambda parameter syntax, it can be allowed only\nin parenthesized form.\n\n#### Syntax\n\nThere's a feature in TypeScript where you can put a `!` after a field name\nand that field will be exempt from checking that the field is assigned in\nthe constructor.\n\nThere's concern that `field!` syntax look a lot like `param!` but they would\ndo almost the opposite thing: `field!` would ignore nulls, while `param!`\nwould throw on null.\n\nAn alternative would be `void M(string! param)` but it's very strange to put\nthe `!` next to the type but not be part of the type and not be allowed\nalmost anywhere else that a type is allowed.\n\nOptions:\n\n1. Solve both\n\n   a. `M(string S!)`, `public string! s`\n\n   b. `M(string! S)`, `public string s!`\n1. Solve parameters\n\n   a. `M(string s!)`\n\n   b. `M(string! s)`\n\n1. Solve initialization\n\n   a. `public string s!`\n\n   b. `public string! s`\n\n1. Do nothing\n\n**Conclusion**\n\nLet's try to do (2a), only `void M(string param!)`, as described by Jared."
  },
  {
    "path": "meetings/2019/LDM-2019-01-16.md",
    "content": "\n# C# Language Design Notes for Jan. 16th, 2019\n\n## Agenda\n\n1. Shadowing in lambdas\n2. pattern-based disposal in `await foreach`\n\n## Discussion\n\n### Shadowing in nested functions\n\n*Q: Allow shadowing for all lambdas as well?*\n\n**A**: Yes.\n\n*Q: Allow shadowing with range variables in LINQ queries?*\n\n```C#\n// char c;\nvar q = from c in s\n        from c2 in s\n        where c != ' '\n        select c;\nvar q2 = s\n    .SelectMany(c => s, (c, c2) => new { c, c2 })\n    .Where(_x => _x.c != ' ')\n    .Select(_x => _x.c);\n```\n\n`c` and `c2` can't be named the same because they are equivalent to two\nparameters being named the same. However, should the new `c` be able to\nshadow the local `c`?\n\n**A**: Let's look at the implementation and decide based on the complexity.\n\n### Pattern-based disposal in `await foreach`\n\n`WithCancellation` and `ConfigureAwait` both return a custom type that does\nnot implement the interface, just the pattern. `await foreach` does not pick\nit up because it does not have pattern-based disposal and the type cannot\nimplement the `IAsyncDisposable` type because it does not produce a `ValueTask`\nreturn for disposal.\n\nProposals:\n\n1. Just allow pattern-based disposal for `IAsyncDisposable`. Only allow\n   pattern-based disposable for `IDisposable` in ref structs.\n\n   a. For `await foreach`, use the pattern, then dynamically check for\n   interface and use it if present.\n\n   b. For `await foreach`, use the pattern, then statically check for the\n   interface and use it if present.\n\nThe dynamic check in (1a) is used because in C# 1.0 the non-generic `IEnumerator`\ndid not implement IDisposable.\n\nThe next question is whether to consider extension methods. The standard pattern\nwe've previously settled on is:\n\n1. Check for pattern\n2. Check for interface\n3. Check for extension methods\n\nCan we use this pattern for `IAsyncDisposable`? The primary question is whether\nto consider extension methods.\n\n**Conclusion**\n\nLet's do 1b. We do not have a non-generic `IAsyncEnumerator` that doesn't\nimplement `IAsyncDisposable`, so the dynamic check is unnecessary.\n\nWe will not consider extension methods for `IAsyncDisposable` or\n`IDisposable` (on ref structs). We will consider extension methods for\n`IAsyncEnumerable` and `IEnumerable`.\n"
  },
  {
    "path": "meetings/2019/LDM-2019-01-23.md",
    "content": "\n# C# Language Design Meeting for Jan 23, 2019\n\n## Agenda\n\n Function pointers ([Updated proposal](https://github.com/dotnet/csharplang/blob/master/proposals/function-pointers.md))\n\n## Discussion\n\n### Creation of a function pointer to a managed method\n\nThe proposal is `&Class.Method` to produce a function pointer. The question\nis whether `&Class.Method` is target-typed, whether it has a natural type\nwhen there's only one member in the method group, or both.\n\nTarget-typing is useful because, like with delegates, it allows you to select\na unique method out of a method group with multiple incompatible overloads.\n\nNatural type is useful because it allows things like `var` and `void*`.\n\n**Conclusion**\n\nLet's start by only doing target-typing. Also, the section \"better function\nmember\" is not necessary without the natural typing.\n\n### DllImport CallingConvention?\n\nThere is actually a stub that the compiler calls for P/Invoke with DllImport\nthat is always done using the managed calling convention, so there's no\nreason for function pointers to use the DllImportAttribute.\n\nNativeCallback is intended for the scenario where you want to avoid the stub\noverhead.\n\n### NativeCallableAttribute\n\nLet's look at this in more detail.\n\n### Syntax\n\n```C#\n1. func* managed int(string)\n2. func*(string)->int\n3. func* managed (string)->int\n4. func* managed (string)=>int\n5. managed int(string)*\n   5a. int(string)*\n6. managed int(string)\n7. managed (string)->int\n8. delegate* int(string)\n9. func int(string)*\n10. delegate int(string)*\n```\n\n**Conclusion**\n\nWe're not sure about all the potential ambiguities here. Let's look at (5a),\npossibly disambiguating with the calling convention.\n\n### Things to clarify in spec\n\n* What does the CLR do if you try to call a method that has a modreq/modopt in\n  the signature, but the `calli` has the signature without the modreq/modopt?"
  },
  {
    "path": "meetings/2019/LDM-2019-02-13.md",
    "content": "# C# Language Design for February 13th, 2019\n\n## Agenda\n\nNullable Reference Types: Open LDM Issues https://github.com/dotnet/csharplang/issues/2201\n\n## Discussion\n\n### Track assignments through `ref` with conditional expressions\n\nWhat is the nullability of `ref` variables when assigned through conditional expressions?\n\n```cs\nstring? x = \"\";\nstring? y = \"\";\n(b ? ref x : ref y) = null;\nx.ToString(); // warning?\ny.ToString(); // warning?\n```\n\n```cs\nstring? x = null;\nstring? y = null;\n(b ? ref x : ref y) = \"\";\n```\n\nOne option is to assume nullability after a `ref` has been taken to a variable. However,\nthat would mean that a `ref` variable declared non-nullable could become nullable, which\nseems too heavy-handed.\n\nSimilarly, disabling flow analysis for variables which are taken as the target of a `ref`\nfeels like violating our model, which is largely based on flow analysis.\n\nAlias analysis, on the other hand, seems to complicated and any reliable implementation\nwould be too difficult for users to understand.\n\n**Conclusion**\n\nLet's reach a middle ground. Assignment between any two identifiers copies\nthe state and is then tracked separately. This is also true for `ref` locals.\nSo,\n\n```C#\nstring? x = \"\";\nstring? y = \"\";\n(b ? ref x : ref y) = null;\nx.ToString(); // warning\ny.ToString(); // warning\n```\n\nBut the equivalent using `ref` locals does not.\n\n```C#\nstring? x = \"\";\nstring? y = \"\";\nif (b)\n{\n    ref string? rx = ref x;\n    rx = null;\n}\nelse\n{\n    ref string? ry = ref y;\n    ry = null;\n}\nx.ToString(); // no warning\ny.ToString(); // no warning\n```\n\n### Nullability of conditional access with unconstrained type parameters\n\nWhat is the nullability of `x?.F()`?\n\n```cs\nclass C<T, U>\n    where T : U\n    where U : C<T, U>?\n{\n    static void M(U x)\n    {\n        U y = x?.F();\n        T z = x?.F();\n    }\n    T F() => throw null;\n}\n```\n\nThis question seems interesting even without the type parameters and also\ncontains a nested question about reachability.\n\nIs the `null` case of `?.` reachable even if the expression is non-nullable?\nAnd if it is, what is the null state of the LHS?\n\n```C#\nstring x = \"\";\nx?.ToString(); // warning?\n```\n\n**Conclusion**\n\nThe `null` case of `?.` is always reachable, meaning the result is always\nmaybe null e.g.,\n\n```C#\nvar y = x?.M(); // y is maybe null here, if possible\n```\n\nMoreover, the LHS is considered maybe null in the null branch, so by normal\nflow analysis, after the expression is evaluated a variable on the LHS will\nbe considered maybe null.\n\n```C#\nstring x = \"\";\nx?.ToString(); // warning that x is maybe null\n```\n\n### `!` operator on L-values\n\nWhere is `!` allowed?\n\n* `M(out x!);` (note this also definitely assigns to `x` through the `!`)\n\n* `M(out (x!));`\n\n* `M(out (RefReturning()!));`\n\n* `x! = y;`\n\n* `M(out string x!);`\n\nCurrent implementation is to allow in `out` scenarios, but disallow in assignment scenarios.\n\nWe dislike allowing it in regular assignment. We like allowing it in simple\n`out` parameters. We're ambivalent on `M(out string x!)`, but it's\nnot easily representable in the syntax model and is very similar to the\nrelated feature `parameter!`, with the opposite meaning.\n\n**Conclusion**\n\nOnly allow `!` in simple `out` parameters with no declaration.\n\n### `is` nullability in `false` case\n\nSee [dotnet/roslyn#30297](https://github.com/dotnet/roslyn/issues/30297)\n\n```cs\nstring s = string.Empty;\nif (!(s is object)) { s.ToString(); /* could warn? */ }\nif (!(s is string)) { s.ToString(); /* could warn? */ }\n```\n\nThere are variants of this scenario with `string!` and `string~`. Should `is`\nupdate the nullability in both branches or should the one branch be treated\nas unreachable?\n\nThe problematic code is probably more like:\n\n```C#\nvoid M(string s)\n{\n    if  (s is IComparable t)\n    {\n    }\n    s.ToString(); // warning\n}\n```\n\nHere the user may not have meant to do a null check, but gets the\nside-effects of doing so anyway.\n\n**Conclusion**\n\nIt seems important to respect a deliberate null check from the\nuser, even if the input variable is non-nullable. As a next step we\nneed to define exactly which tests we think are \"deliberate\" null\nchecks. For instance, `x is null` is certainly a null check, but\npattern matching may or may not be a *deliberate* null check, even\nif the code contains a null check.\n"
  },
  {
    "path": "meetings/2019/LDM-2019-02-20.md",
    "content": "# C# Language Design Notes for Feb 20th, 2019\n\n## Agenda\n\n- Nullable Reference Types: Open LDM Issues https://github.com/dotnet/csharplang/issues/2201\n\n## Discussion\n\nThere are variants of this scenario with `string!` and `string~`. The question is whether we should learn in both branches, or whether we should treat one branch as unreachable.\n\n### 'Deliberate' Tests for Nullability\n\nThis is a continuation of the discussion from the [last meeting](LDM-2019-02-13.md).\n\nProposal: divide into \"pure\" and \"not-pure\" null checks. The \"pure\"\nnull checks will affect both branches, but the \"not-pure\" will only\naffect one branch. Precisely: when a \"pure\" check is used, the\nnullability state is split for both branches, while a non-pure check\ndoes not have a \"maybe-null\" state after split.\n\nProposed deliberate checks:\n\n    1. `x == null`\n\n    2. `x != null`\n\n    3. `(Type)x == null`\n\n    4. `(Type)x != null`\n\n    5. `x is null`\n\n    6. `s is string` (when the type of `s` is `string`)\n\n    7. `s is string s2` (when the type of `s` is `string`)\n\n    8. `s is string _` (when the type of `s` is `string`)\n\n\nOther checks:\n\n    1. `x is string`\n\n    2. `x is string s`\n\n    3. `x is C { Property = 3 }`\n\n    4. `TryGetValue` (`[NotNullWhenTrue]`)\n\n    5. `string.IsNullOrEmpty(s)` (`[NotNullWhenFalse]`)\n\n    6. `x?.ToString() != null`\n\nFollow up question: What about `?.` and related operators (e.g., `??`)?\n\nAn example would be\n\n```C#\nvoid M(string s)\n{\n    if (s?.ToString() == null)\n    {\n        // is `s` maybe null?\n    }\n}\n```\n\nA corresponding rewrite would be:\n\n```C#\nvoid M(string s)\n{\n    if (s == null || s.ToString() == null)\n    {\n        // s would be maybe-null after this point\n    }\n}\n```\n\n**Conclusion**\n\nPure:\n\n    1. `x == null`\n\n    2. `x != null`\n\n    3. `(Type)x == null`\n\n    4. `(Type)x != null`\n\n    5. `x is null`\n\n    6. `s is string` (when the type of `s` is `string`)\n\n\nAll conditional access (`?.`, `??`) included\n\nNot-Pure\n\n    1. `x is string`\n\n    2. `x is string s`\n\n    3. `x is C { Property = 3 }`\n\n    4. `TryGetValue` (`[NotNullWhenTrue]`)\n\n    5. `string.IsNullOrEmpty(s)` (`[NotNullWhenFalse]`)\n\n    7. `s is string s2` (when the type of `s` is `string`)\n\n    8. `s is string _` (when the type of `s` is `string`)\n\nSwitch statement/expression: switch statement treated as\nessentially the equivalent of an `if/else` rewrite. No\ndecisions for the switch expression yet."
  },
  {
    "path": "meetings/2019/LDM-2019-02-25.md",
    "content": "\n# C# Language Design Notes for Feb 25th, 2019\n\n## Agenda\n\nSemantics of `base()` calls in default interface implementations and classes\n\n## Discussion\n\nThe exact semantics of `base()` are still unresolved. Consider\nthe following legacy `base` call.\n\n```C#\nclass A \n{\n    virtual void M() {}\n}\n\nclass B : A \n{ \n    // override void M() { }\n}\n\nclass C : B\n{\n    override void M() => base.M();\n}\n```\n\nThe behavior for `base` is to find the \"nearest\" implementation and call\nthat implementation using a direct call, meaning if B.M is uncommented it\nwill be called, while if it commented out then A.M will be called. Notably,\nif `B` is uncommented at compile time, but at runtime the `B.M` override is\nnot present *the runtime will call A.M.* This is because the runtime will\ncontinue looking through base classes for a matching signature if the target\nmethod is not present.\n\nMost importantly, the runtime *does not* yet have this behavior for `base()`\ncalls in interface implementations. This is because there could be multiple\npaths to search down and the current IL encoding does not provide a root\ndefinition to search towards.\n\nFor example,\n\n```C#\ninterface IA\n{\n    void M();\n}\ninterface IB : IA\n{\n    void IA.M() // If this gets removed, the IC.M call will fail\n    {\n        base(IA).M();\n    }\n}\ninterface IC : IB\n{\n    void IA.M() => base(IB).M();\n}\n```\n\nAt the moment, we do not have the time to implement an entire new IL form\nfor `base()` calls, so we have to implement a behavior in absence of that\nfeature.\n\nChoices:\n\n1. No `base()` call\n2. `base()` call can only target the original definition of the method\n3. `base(T).M()` call is a direct call to `T` and an error if the method\ndoesn't exist\n4. `base(T)` starts searching in `T`, but in the compiler looks at the bases\nfor a unique, most derived implementation.\n\nFor feature evolution, we then have three more choices later.\n\n1. Stay as-is\n2. New opcode/behavior for `base()`\n3. New opcode/behavior for `base.` and `base()`\n\n**Conclusion**\n\nFor the first choice, let's do (3). The emitted code will be a direct call to\nthat method. It is expected that the runtime will throw an exception if an\nimplementation is not present in that type. For binding, in classes the\nsignature used will be the closest override, while for interfaces the\nsignature will be the member definition."
  },
  {
    "path": "meetings/2019/LDM-2019-02-27.md",
    "content": "\n# C# Language Design Meeting for Feb. 27, 2019\n\n## Agenda\n\n1. Allow ObsoleteAttribute on property accessors\n2. More Default Interface Member questions\n\n## Discussion\n\n### Allow ObsoleteAttribute on property accessors\n\nObsoleteAttribute, ConditionalAttribute, and CLSCompliantAttribute are\ncurrently disallowed on property accessors. VB allows the first three, but\nprovides a warning for `ClSCompliant`.\n\nThe question is whether or not to loosen this restriction.\n\nAllowing `Conditional` seems very dangerous because the \"arguments\" to the\nmethod are not evaluated if the condition is false. Logically, this would\nimply that the right-hand side in a property assignment expression is not\nevaluated, but this seems very likely to lead to bugs and confusion.\n\nWe don't see a reason to disallow `Obsolete` or `Deprecated`, and don't\nparticularly care about `CLSCompliant`.\n\n**Conclusion**\n\nAllow the change for `Obsolete` and `Deprecated`. Leave everything else\nas-is.\n\n\n### Collision of lookup rules and decisions for `base()`\n\nExample:\n\n```C#\ninterface I1\n{ \n    void M(int) { }\n}\n\ninterface I2\n{\n    void M(short) { }\n}\n\ninterface I3\n{\n    override void I1.M(int) { }\n}\n\ninterface I4 : I3\n{\n    void M2()\n    {\n        base(I3).M(0) // What does this do?\n    }\n}\n```\n\nThe tricky part here is that both `M(short)` and `M(int)` are applicable to\n`M(0)`, but lookup rules also say that if we find an applicable member in a\nmore derived interface, we ignore members from the less derived interfaces.\nCombined with the rule that overrides are not found during lookup, when\nlooking in `I3` the first thing we find is `I2.M`, which is applicable,\nmeaning that `I1.M` does not appear in the list of applicable members.\n\nSince we concluded in the previous meeting that an implementation\n*must* exist in the target type, and `I2.M` is the only applicable\nmember, the call `base(I3).M(0)` as written is an error, because `I2.M` does\nnot have an implementation in `I3`.\n\n**Conclusion**\n\nThe decision from the previous meeting is affirmed and we conclude that the\nlookup rules will not be changed. It's not clear what the new lookup rules\nwould be and it would be difficult to find when to apply them. In general,\nwe think having a single set of lookup rules will reduce confusion in an\nalready complicated feature area.\n\n### Semantics of `base(T).Member`\n\nWe also affirm that for `base(T).Member`:\n\n* `T` can be a class or interface\n* All members are available on `base(T).Member` including fields\n* A definition or implementation must exist in `T`\n\n*Aside: The compiler will never emit a call to a member in metadata\nthat is inaccessible.*\n\nThis decision essentially falls out of existing binding rules for the given\nexpression.\n\n### Accessibility in interfaces\n\nWe previously agreed to support at least `protected`, `private`, and `public`.\n\nWhat about `internal`, `protected internal`, or `private protected`?\n\nIn addition, what is the meaning of `protected`?\n\n**Conclusion**\n\nAllow all accessibility. `protected` specifically seems useful for compatibility\nwith other languages which allow it, and to allow interfaces to create helper\nmethods for their derived implementations.\n\nThere are seem to be two possible definitions of `protected`: `protected`\nmembers are visible only in deriving interfaces, or `protected` members are\nvisible in both deriving interfaces and implementing classes.\n\nThe preferred definition is `protected` members being visible in all deriving\ninterfaces and implementing classes.\n\n### Accessibility of overriding interface members\n\nThere are two issues here: what is the language rule around calling\noverriding implementations via `base` and how to implement that rule via\naccessibility in the CLR.\n\nWe like the rule that you should always be able to call an overriding\nimplementation through `base()` as long as you can see the definition.\n\nThe problem is that the obvious implementation (copying the accessibility of\nthe definition) doesn't quite work with `InternalsVisibleTo` (which is\ntechnically not described in the language).\n\nProposal 1:\n\nIf the implementing member is in the same assembly as the\ndefinition we can copy the accessibility.\n\nProposal 2:\n\nFor all explicit interface implementations, emit the `protected`\naccessibility.\n\n**Conclusion**\n\nThe language rule is confirmed.\n\nWe think Proposal 2 works with the language rules, is simple, and doesn't\nexpose anything that we would regret. Let's go with that."
  },
  {
    "path": "meetings/2019/LDM-2019-03-04.md",
    "content": "\n# C# Language Design Notes for March 4th, 2019\n\n## Agenda\n\n1. Nullable user studies\n2. Interpolated string and string.Format optimizations\n\n## Discussion\n\n### The 'default loophole'\n\n`var y = default(SomeStructWithNonNullableFields);`\n\nFor the above, no warning is produced. The same is true for other `default`\nexpressions. Is that OK?\n\n**Conclusion**\n\nLet's continue to track the nullability of the fields and not produce a\nwarning. If we were to produce a warning it seems likely that we would\nproduce warnings that are fundamentally unactionable because the user doesn't\ncontrol the struct definition.\n\n### User study for nullable design\n\nToday we went over the results from some user studies which simulated\nupgrading a code base with the non-nullable reference types design enabled.\n\nThere were 5 sessions, with two simple, but non-trivial, code bases:\n\n1. Telegram bot API\n2. Jil, a JSON serializer\n\nProblems: \n\n- People had a fair amount of problems with member definitions, rather than\n  bodies\n    - We haven't published much information on how nullable interacts with\n      definitions\n\n    - Interface implementation and overriding are hard to fix since there\n    are multiple places that need to change for every nullability change\n\n- Object initializer pattern is a persistent problem and the warnings\n  don't seem to be providing much value\n\n- Constructor chaining is also a problem, where fields are piecewise initialized\n\n  - Worse, when looking at the diagnostic, it was hard to get to the member,\n    but when you're at the member, it's hard to verify this one was the\n    problem because the diagnostic also does not occur\n\n  - Almost everyone expected the warnings to be on the field/property\n\n- Nullable value types are a problem because they assumed that the problems\n  were in nullable reference types, but the problems/solutions were subtly\n  different\n\n- Diagnostic quality: generics were confusing, especially with tuples\n\n- Code fixes\n\n  - People definitely want code fix to/from a nullable reference\n\n  - They want a \"fix-all\" but it's not clear what that is\n\n    - Some people wanted to see all the warnings, but then narrow down,\n      especially via a code fix\n\n- Some people looked at the process as \"satisfying the compiler\" and others\n  looking at \"code hygiene\" or \"possible bugs\"\n\n   - There were at least a few null-safety bugs and no one found them\n     in the time allotted, but probably would have\n\n   - People who used the feature for overall code hygiene were more\n     excited about using the feature\n\n### `params` and string interpolation\n\nWe discussed a new proposal for improving the performance of certain\nstring.Format calls and interpolated string expressions.\n\nProposal: https://github.com/dotnet/csharplang/blob/master/proposals/format.md\n\nSummary:\n\nUsing certain APIs, especially `params` and `string.Format`, can be a source\nof large performance problems. For certain projects (MSBuild) that are\n\"string manipulation\" programs, this can even be the main performance\nbottleneck for those programs.\n\nUnfortunately, these APIs are also very convenient and, in many cases, the\npreferred way of accessing certain string manipulation functionality in the\n.NET framework. We'd like it if these features could be less heavyweight.\n\nProposals:\n\n1. Allow `params` to have any of the types `Span<T>/ReadOnlySpan<T>/IEnumerable<T>`\n\nAdvantages:\n\n- The callee cannot stash the parameter, so we can re-use an allocation\n\n    - Sometimes users do this themselves because it's demonstrably more efficient\n\nConsequences:\n\nOverload resolution needs to change. New tie breaking rules:\n\n- `ReadOnlySpan<T>`\n\n- `Span<T>`\n\n- `T[]`\n\n- `IEnumerable<T>`\n\n2. Allow any standard `Format` overload resolution for interpolated strings\n\nThis feature builds on (1). If interpolated strings could use new `Format`\noverloads that have `ReadOnlySpan<T>` arguments, interpolated strings could\nshare in the performance improvements.\n\n3. `ValueFormattableString`\n\nSupport new `ValueFormattableString` type as a target of a string\ninterpolation.\n\nThis would be a breaking change when people upgrade to the new framework with\nthe new type, but the older compiler always chooses the `string` overload (because\nit doesn't understand `ValueFormattableString`) and whenever they upgrade the\ncompiler the call suddenly changes to `ValueFormattableString`. If those two\nmethods do anything different, that would be a breaking change.\n\nThis feature also does not support using a custom type instead of\n`ValueFormattableString`. That could be desirable for a number of different\nscenarios, but would probably make the backwards compatibility constraints\neven more difficult.\n\nWe should carefully evaluate the tradeoffs in this feature and see what we\ncan do to enable the most scenarios without taking unacceptable breaks.\n\n3. `stackalloc` the `Span` for `params`\n\nIt's not possible for C# to generally predict whether or not it's OK to\nstackalloc arguments. We're interested in enabling this functionality if\nprovided with a \"maybe stackalloc\" helper from the runtime, and we'd like to\nkeep that possibility open, but we will not do anything here until such a\nfeature is available."
  },
  {
    "path": "meetings/2019/LDM-2019-03-06.md",
    "content": "\n# C# Language Design Meeting for March 6th, 2019\n\n## Agenda\n\nOpen issues:\n\n1. Pure checks in the switch expression\n2. Nullable analysis of unreachable code\n3. Warnings about nullability on expressions with errors\n4. Handling of type parameters that cannot be annotated\n5. Should anonymous type fields have top-level nullability?\n6. Element-wise analysis of tuple conversions\n\n## Discussion\n\n### Pure checks in switch expression\n\nExample:\n\n```C#\nvoid M(object x)\n{\n    _ = x switch\n    {\n        1 => x.ToString(),\n        {} => x.ToString(), // is this a \"pure\" null test?\n    }\n}\n```\n\nThe original proposal was that certain tests, like `is {}` are \"pure\" null\nchecks because there is no reason to perform such a test unless you are\nchecking if the input is null. The switch expression was not decided, but it\nmay be confusing to have a pattern check for null in an `is` expression, but\nnot produce the same nullable semantics for the same pattern in `switch`.\n\nHowever, it's possible that the user didn't intend `{}` to be a null test in\nthe previous example, but just a \"catch-all\" case. If we use the original\ninterpretation of \"pure null test\" then this would not meet the bar, as there\nis a meaning which could not be a null test. However, this would produce\na different meaning for `{}` in an `is` expression, as opposed to a `switch`.\n\n**Conclusion**\n\n`{}` is proving contentious as a \"pure\" null check in a switch. One\nalternative which we can all agree on is removing `{}` as a pure null check\nin the `is` expression, as well. This would remove the problem of consistency\nall together.\n\n### Nullable analysis of unreachable code\n\n```C#\nstatic void M(bool b, string s)\n{\n    var t = (b || true) ? s : null;\n    t.ToString(); // warning?\n}\n```\n\n**Conclusion**\n\nDiagnostics will not be produced because of nullability analysis on\nexpressions which are non-nullable. This conforms to what we do for definite\nassignment, where everything is treated as defintely assigned in unreachable\ncode.\n\nWe accept a proposed rule where all expressions which are unreachable are\nnon-nullable (even `null`), in service of the above principle.\n\n### Warnings about nullability on expressions with errors\n\nShould we provide warnings about nullability in cases where one of the\nsymbols being considered has an error, like a variable which was declared\nbut never initialized?\n\n**Conclusion**\n\nWe will not provide nullable diagnostics on symbols with errors, because we\ndo not know exactly how the types will be altered to remove the errors, so\nthe warnings may not be useful and are less important than the errors already\nreported.\n\n### Handling of type parameters that cannot be annotated\n\n`e?.M()` used a statement is fine and we shouldn't care about the return type.\nSimilarly, `e ?? M()`.\n\nThe main unfortunate case is `default`, and the most annoying case is probably\nimplementing code like `GetFirstOrDefault()` where the only way to implement\nit is to suppress the warning. Moreover, if the method is annotated with\n`MaybeNull` it seems like you have to mention that the value could be null\ntwice: once in the signature of the method, and once in the body.\n\n**Conclusion**\n\nWe like the list as is. We considered using annotations like `MaybeNull` in\nthings like `return` statements, but aren't willing to go that far right now.\nMore broadly, we may want to consider whether the annotations should apply to\nthe implementer of a method, instead of just the users of the method, but we\nare not going to do so now.\n\n### Should anonymous type fields have top-level nullability?\n\n```C#\nstatic T Identity<T>(T t) => t;\n\nstatic void F(string x, string? y)\n{\n    var a = new { x };\n    a.x.ToString();           // ok\n\n    a = new { x = y };        // warning?\n    a.x.ToString();           // warning\n\n    Identity(a).x.ToString(); // warning?\n}\n```\n\nOur primary concern here is LINQ query expression, which functionally produce\nanonymous types that are then consumed through further functions.\n\n**Conclusion**\n\nYes, we want to track the inferred type of the anonymous type, so for\n\n```C#\nvoid M(string x, string? y)\n{\n    var a = new { x };\n\n    a = new { x = y };\n}\n```\n\n`a` would be of type `{ string! x }` and the subsequent assignment would\nproduce a warning.\n\n### Element-wise analysis of tuple conversions\n\nWe discussed the behavior of nested nullability in tuple expressions for\nthe following example:\n\n```C#\n// current behavior:\nstatic T Id<T>(T t) => t;\nstatic void M(string? x, string y)\n{\n    (string, string) t = (x, y); // warning: (string?, string) mismatch\n    t.Item1.ToString();          // warning: Item1 may be null\n    var x = Id(t); // what is the inferred type of x?\n\n}\n```\n\nThe warnings are present regardless of the design. The only question is if\nthe type of `x` is `(string, string)` or `(string?, string)`. If tuples\nbehaved like the underlying `ValueTuple`, the inferred type would be\n`(string, string)` since the tracking of the `Item1` field does not change\nthe type of the container.\n\nHowever, if we pretended that the elements of the tuple were individual\nlocal variables, we would infer `(string?, string)` because the tracked state\nof a local variable is used in type inference.\n\n**Conclusion**\n\nThe inferred type is `(string, string)`. Aside from difficulties in nailing\ndown exactly what the semantics of \"tracked like locals\" means (presumably it\nwouldn't apply to tuple fields of a second type?) there is a simplicity to\nmaking tuples, constructed types, and anonymous types behave roughly\nidentical through type inference.\n\n\n"
  },
  {
    "path": "meetings/2019/LDM-2019-03-13.md",
    "content": "\n# C# Language Design Meeting for March 13, 2019\n\n## Agenda\n\n1. Interface \"reabstraction\" with default interface methods\n2. Precedence of the switch expression\n3. `or` keyword in patterns\n4. \"Pure\" null tests and the switch statement/expression\n\n## Discussion\n\n### Interface reabstraction\n\nWe previously specified our intent to permit reabstraction, where you could\nmark a derived implementation as \"abstract\" and force further implementors to\nprovide an implementation.\n\nWe allow this in interfaces, so one argument for allowing is simply\nmaintaining feature parity with classes, as we do in many other areas.\n\nAnother argument is that it would be very useful in interfaces because you\nwould be able to provide an interface with a stronger contract than the base\nimplementation. For instance, if you were implementing an interface that has\na method which sorts a list, and you would like to provide an implementation\nwhich requires a sort with a stronger contract, like a stable sort, then you\nwould want to mark the sort implementation as abstract. It may not be\npossible to write an implementation yourself and the implementation in the\nbase may not be suitable because it doesn't implement the stronger contract\n(e.g., it implements an unstable sort).\n\nThere's an open question of how this would be implemented in the runtime and\nhow expensive it would be.\n\n**Conclusion**\n\nThe feature seems reasonable and if there were an easy, cheap implementation\nwe would probably take it. However, we don't know if that's possible. We'll\ntake a work item to investigate and see if it's feasible. We'd also like this\nto work for classes, but don't see it as strictly required if only interfaces\nare possible.\n\n### Precedence of the switch expression\n\nIt's currently at the same precedence of the relational operators (like `<`,\nor `is` and `as`). There are some problems with this precedence, though. For\nexample,\n\n```C#\nx = e switch { .. } + 1 // syntax error\n```\n\nThis is because the `+` binds tighter than the switch, so this `switch ({ ...\n} + 1)`.\n\n*Relational* precedence is also weird because of the following:\n\n```C#\nx = a + b switch { ... } // this is `(a + b) switch { ... }`\nx = a & b switch { ... } // this is `a & (b switch { ... })`\n```\n\nIf we were to change to *primary expression* precedence, it would be `(b\nswitch {...})` for both examples.\n\nOne question is what happens with `await`: what does `await e switch { ... }`\ndo?\n\nIf we look at the `switch` expression as similar to the conditional expression,\nthis would produce `(await e) switch { ... }`. More broadly, the switch looks\na like a more complex conditional expression, so allowing expressions that\nare allowed on the left hand side of the conditional could be desirable for\nthe switch as well. So, `a + b switch { ... }` is `(a + b) switch { ... }`.\n\nHowever, one major difference between the conditional and the `switch` is that\nthe switch can have expressions with arbitrary type, but conditional requires\na `bool`, which allows for more complex expressions.\n\nHere are some examples that may motivate the decision:\n\n```C#\n\nx + e switch {} * y\n\n((x + e) switch {}) * y\n\n_ = await e switch { ... };\n\n_ = a ?? (b switch {\n            ...\n          });\n\n_ = (a ?? b) switch {\n            ...\n            };\n\n_ = a ?? b switch {\n        ...\n        };\n\n_ = 1 + o switch { int i => i, _ => 0 };\n\n_ = a && b ? c : d;\n\n_ = a ? b : d ? e : f;\n\n_ = (string)s switch { ... };\n\n_ = -x switch { ... };\n\n_ = await x switch { ... };\n```\n\nLooking at the examples, it's seeming like the space makes a big difference\nin readability. When there's a space between the operands, it's less obvious\nwhat the switch applies to, so binary operators are more ambiguous between\n`a ?? (b switch { ... })` and `(a ?? b) switch {...}`. However, the parenthesis\nfor the first example look a bit stranger than the second, and some people\nfeel that it looks more natural to the switch to bind to only `b`.\n\nThere's also a fairly strong feeling that the unary operators, like `-` and\ncast, should bind more strongly.\n\n**Conclusion**\n\nIt seems like a new precedence level between unary and multiplicative is the\nright fit. For places where either interpretation could be possible\n(`await`), this doesn't feel like an unreasonable decision. For places where\none interpretation seems preferred (other unary operators and binary\noperators) this choice fits for both.\n\n### Patterns with `or`\n\nShould we make\n\n```C#\nswitch (e)\n{\n    case X or:\n}\n```\n\na warning on `or` as an illegal variable name? This would assist parsing\nbecause we would not have to do any parsing lookahead to figure out if\nthis is a designation, vs an `or` pattern (that doesn't exist yet).\n\n**Conclusion**\n\nUnfortunately, we already shipped this, so it would be a breaking change.\nSince we can resolve this through lookahead, we don't think this example is\nsevere enough to warrant a new warning. If we see something more complicated\nto resolve, we may reconsider.\n\n### Where to produce warnings for \"null test\" in switch\n\n```C#\nswitch (s)\n{\n    case null when s.Length == 1:\n        break;\n    case null when M(s = \"foo\"):\n        break;\n    case _ when s.Length == 2:\n        break;\n}\n```\n\nWe have decided `null` is a \"pure\" null test and we will update the null\nstate for `s`. The question is where we update that state:\n\n1. To the entry of the switch and all previous cases?\n2. To the branch of the switch only?\n2. Just to the forward paths of the flow analysis?\n\nOne problem with relying just on the flow analysis is that disjoint checks\ncould be reordered and affect the diagnostics produced, even though the bug\nwould be present regardless of the ordering, since the check would actually\nbe verifying the nullability of the input, which is immutable across the\nswitch arms.\n\nThe other problem is what variable state to update. If we copy values from\nthe switch and test against the copy, that would be a separate state that\nwould need to be tracked, since the original expression could be modified\nwithin the switch.\n\n**Conclusion**\n\nLet's look at only using forward flow propagation, but define the ordering as\nlooking at the patterns of each arm in order, then use the following flow\ngraph. Notably, if there was no declared variable for the switch expression,\nwe will synthesize one."
  },
  {
    "path": "meetings/2019/LDM-2019-03-19.md",
    "content": "\n# C# LDM Notes for Mar 19, 2019\n\n## Agenda\n\nMVP Summit Live LDM w/ Q&A\n\nTopics:\n\n1. Records\n2. \"Extension interfaces\"/roles\n3. Macros\n4. IAsyncEnumerable\n5. \"Partially automatic\" properties\n6. More integration with reactive extensions\n\n## Discussion\n\nWe grouped the discussion into topics to try to maintain a bit of shared\nstate in the discussion.\n\n### Records\n\n*Q: How \"extensible\" will the design be? Could the user provide some sort of\ntemplate that the compiler would implement for their record, more than the\nequality and data access features we are initially thinking of?*\n\nWe're not clear on what kind of templating we could offer, but there are two\nproblems we foresee with generalizing the feature:\n\n1. Even simple equality is actually a bit tricky to write and be correct for\n   subtyping.\n2. Generalized templating is tricky to do in a type safe way. One alternative\n   is something like hygenic macros, but we're not willing to go that far in\n   the language at the moment. We definitely are not interested in allowing\n   for custom syntax forms.\n\n*Q: Do we not want inheritance? If that's the only thing blocking records?*\n\n1. Inheritance isn't the main thing blocking records. It's mostly lack of\n   design time to work out the last few issues, namely what the simplest\n   syntax means, support for nominal and structural construction, and\n   incorporating the design with discriminated unions.\n\n1. We think inheritance is important for \"extensible\" records and it's hard to\n   add later.\n\n*Q: Will record syntax be supported for structs?*\n\nYes, almost certainly. We're also looking into discriminated unions for structs\nas well, although it's more difficult because the size of the struct is more\ncomplicated.\n\n*Q: Deep vs shallow immutability? Value-equality is more natural if there's\ndeep immutability, since two things which may be value equal originally may\nnot be so if a nested value is changed, but the top level equality is only\ncalculated shallowly.*\n\nNot currently on the table, records will only have shallow immutability be\ndefault, if they are immutable by default. We probably have no mechanism\nto figure out if equality is broken, either, because the language doesn't\ncurrently have a good way of reasoning about this transitevely.\n\n\n### Extension interfaces/roles\n\n*Q: Is this duck typing?*\n\nMaybe, it depends on what you mean by duck typing. It's certainly a way\nto implement an interface after the type has been defined. One of the\ndesign goals can be phrased, \"here's a class, here's an interface, let's make\nthem fit together\", but it's not restricted to what's stated in the class,\nbecause we feel there's often a small gap between the interface and class that\nneeds to be filled out.\n\nIt's also not the case that any type which structurally matches the interface\n\"magically\" implements the interface -- all our current designs are nominal\nand explicit. This is partially because it fits with how C# works as a whole,\nbut also that interface implementation is a CLR language concept that isn't\nas loose as some other duck typing designs.\n\n*Q: Constructors on interfaces?*\n\n(Meaning no body, just for the constraint)\n\nIt's not currently a part of \"static members on interfaces\" and it\nseems very similar to proposals to extend the `new()` constraint?\n\nWhen we looked at it in the past we thought the cost/value prop is probably\nquestionable as a standalone feature, but maybe as part of the broader\ninterface feature. The biggest mark against it is there's a workaround\nof using a delegate that returns the given interface, which generally\nworks pretty well.\n\n\n*Q: What scope would the \"extension interfaces\" be in?*\n\nWe'll probably import most of the scoping rules of extension methods.\n\n*Q: What about extension fields? Using ConditionalWeakTable?*\n\nThis consequences are subtle and we'll probably favor having the user\ndo this explicitly if that's what they mean.\n\n*Q: Scala-like \"implicit\" parameters?*\n\nWe looked at it, but we're concerned it may be too subtle.\n\n### General metaprogramming\n\n*Q: Source generators?*\n\nWe tried a maximal approach for source generators, but the tooling was not\nable to keep up. There may be something here, but we're not going to do\nanything until we can guarantee investment across the whole stack.\n\n*Q: Can we skip the tooling?*\n\nThere isn't really a difference between generated C# and standard C#, so\nthere's no clear line to \"cut off\" the tooling. It's not the author that\nwe're primarily worried about, it's all of the downstream users, who are\nstrongly expecting current features to continue to work.\n\n*Q: What are new languages the LDM looks to for ideas?*\n\nWe generally look at everything we can find, and the LDM has people with\ntheir own interests, so we tend to have a mix of perspectives.\n\nSome examples:\n\nWe've looked at Rust and Go for perf-centric designs and \"zero-cost abstraction\"\nideas.\n\nWe look at Scala for lot's of ideas on merging functional and OO. They're not\nnecessarily the language we want to be, but they've traveled a lot of the\nsame ground.\n\n### IAsyncEnumerable\n\n*Q: How does ConfigureAwait/Cancellation work?*\n\nRight now we have ConfigureAwait and WithCancellation methods for\nIAsyncEnumerable that allow you to add functionality at the `await foreach`\nsite, e.g.\n\n`await foreach (var x in iasyncenum.ConfigureAwait(false))`\n\nWhat we don't currently have a mechanism for is flowing a token from the\n`foreach` to the generated awaits in the iterator method. For instance,\n\n```C#\nvar iasyncenum = IterMethod(token);\nawait foreach (var x in iasyncenum)\n{\n    ...\n}\n\nIAsyncEnumerable<int> IterMethod(CancellationToken token)\n{\n    yield return 0;\n    token.ThrowIfCancelled();\n    await Task.Delay(1);\n    yield return 1;\n}\n```\n\nNote that you can flow a token through manually, but then you must control\ncalling the iterator and executing the foreach -- there's no way to pass\na new cancellation token during the `await foreach`.\n\nThere's some feedback that this could be useful, so we'll take another\nlook at it.\n\n*Q: Plans to add an ability to await an event?*\n\nWe're not quite sure how this would work. In general, libraries have\nsome support for this pattern, so we don't see a huge need right now.\n\n*Q: Plans to support \"partially automatic\" properties that let you\naccess the generated backing field?*\n\nThere's been some talk about allowing a field to be declared inside\nthe property that's only accessible there, e.g.\n\n```C#\npublic int Property\n{\n    private int _field;\n    get => _field;\n    set { _field = value; }\n}\n```\n\nWe haven't had a full discussion about this idea yet.\n\n### More integration with Reactive Extensions in the language?\n\nFor instance, IObservable?\n\nOur current view is that `IAsyncEnumerable` is the mechanism to link Rx into\nthe language. The problem with stronger language integration is that it will\nrequire configuration for various buffering/back-pressure options. We think\nthat's better solved by library authors and hope that the current design\nwill strike a good balance.\n"
  },
  {
    "path": "meetings/2019/LDM-2019-03-25.md",
    "content": "# C# Design Review Notes for Mar 25, 2019\n\n## Agenda\n\nWe brought in the design review team to look at some of our recent and open decisions in C# LDM.\n\n1. Nullable reference types: shipping annotations\n2. Pattern-based indexing with `Index` and `Range`\n3. Cancellation tokens in async streams\n\n\n# Nullable reference types: shipping annotations\n\nUp until recently we were planning to add a new type of file, a \"sidecar\" file, that could be an external source for describing nullability annotations for existing libraries. This has some significant advantages: It works \"down-target\", and it can get you nullability without breaking open files that are not maintained, or that you do not have access to.\n\nOn the other hand, this would be a new file format that we'd need to understand in all compilers (not just C#), and plumb through extensive amounts of tooling. If we're lucky, lack of nullability annotations is mostly a temporary, transitional problem. But a new file format would be a new permanent layer of complexity that would be around forever. The fix might be worse than the problem.\n\nWe therefore recently decided to drop sidecar files, at least for now. The review team agreed with this. Instead we should double down on annotating the .NET Core libraries themselves.\n\nTo this point, we consider it highly plausible that we will not get all the annotations done for the .NET Core release timeframe (though feedback was that we should try!). Instead we are going to have to roll them out over a period of time, maybe a year after initial release.\n\nFeedback is that we should message clearly that our core libraries won't be done with this transition, and that new warnings are likely to hit with every release until we are. We expect the warnings to be broadly useful, but if folks can't live with the churn they should opt out.\n\nWe're better off focusing on quality than quantity of annotations we ship in each go-around. Once shipped, it's important that we don't change our minds, much as with other surface area.\n\nWe'd prefer not to add too much user-facing mechanism for this, because again, some day we'll be done, but the mechanism can't be removed.\n\nThat said, we can consider features for more granular opt-out, instead of just \"don't give nullable warnings.\" E.g. we could have attributes that say \"treat a given imported member, type or namespace as null-oblivious when accessing in my code.\"\n\nWe do have more local \"fixes\": there's `!` and pragmas. It's a delicate balance, though. The more you drive opt-outs into details of the code, the more likely you are to accidentally leave them in place, and the harder it is going to be to eventually remove them.\n\n\n# Pattern-based indexing with `Index` and `Range`\n\nAdding indexers to existing types to consume the `Index` and `Range` types is too invasive, and we are planning to embrace a more pattern-based approach. For `Index` the compiler can synthesize the behavior from int-based indexers and access to a `Length` or `Count` property. For `Range` there is typically no existing behavior, except in recently added types that have a `Slice` method. If we base a pattern for `Range` indexing on `Slice`, then people can add extension methods to existing types.\n\nBoth patterns are open to some compile time optimizations, when the `Index`es and `Range`s are directly given to the indexers as index and range expressions. In those cases we won't necessarily need to construct the `Index` and `Range` values but can take compiler shortcuts in terms of the constituent expressions.\n\nThe reviewers were supportive of this direction and we will go forward with it.\n\n\n# Cancellation tokens in async streams\n\nIn the current state of design, there is no way for an `async` iterator method to get hold of the `CancellationToken` that the consumer passed to the enumerator.\n\nWe discussed options for \"naming\" the cancellation token in the body of the iterator. There could either be a specially marked parameter (the value of which gets supplanted on each enumeration of the `IAsyncEnumerable`), or a magic variable that's automatically in scope, similar to `value` in a property setter.\n\nWe agreed on the latter approach, using the variable name `cancellationToken`. This is the name most commonly used when cancellation tokens are passed as parameters.\n"
  },
  {
    "path": "meetings/2019/LDM-2019-03-27.md",
    "content": "\n# C# LDM Notes for Mar 27, 2019\n\n## Agenda\n\n1. Switch expression syntax\n\n1. Default interface implementations\n\n    1. Reabstraction\n\n    2. Explicit interface abstract overrides in classes\n\n    3. `object.MemberwiseClone()`\n\n    4. `static int P {get; set}` semantics\n\n    5. `partial` on interface methods\n\n2. `?` on unconstrained generic param `T`\n\n## Discussion\n\n### Switch expression syntax\n\nConfirmed that we like\n\n```C#\ne switch\n{\n    a => b,\n    c => d,\n}\n```\n\n### Default interface methods\n\n#### Reabstraction\n\nImplement the interface method with an abstract in an interface, forcing\nre-implementation of deriving interfaces.\n\nWe previously wanted to see a cost for handling it in the runtime and we\nknow have a proposal for that: https://github.com/dotnet/coreclr/pull/23313\n\nGiven that, do we want to allow reabstraction?\n\n**Conclusion**\n\nAssuming the proposed approach, it seems cheap enough. The only question is\nif the metadata approach is one we want to add to metadata. Right now we're\ngoing to say yes to the feature, assuming that the runtime teams can produce\nthe feature. We also want to put this under the runtime feature flag to\nprevent exposure to older compilers. We should also do the same for features\nlike static members in interfaces.\n\n#### Explicit interface abstract overrides in classes\n\nAllow abstract interface implementions in a class as well? Not an abstract\nclass method implementing an interface method.\n\n**Conclusion**\n\nNo, we don't see any great use cases.\n\n#### Is `object.MemberwiseClone()` accessible in an interface?\n\nIn principle, maybe yes, but this member seems particularly problematic.\nLet's say protected members of object are not accessible.\n\n#### Is `static int P { get; set; }` is an auto-property with a compiler-generated backing field?\n\nThis seems consistent with the idea that `static` means `sealed` by\ndefault, but a little strange given that the same syntax without\n`static` implies virtual for instance members.\n\nThe main problem will be if we allow `static` virtual/abstract members to be\ndeclared in future versions of the language, where this rule doesn't\nnecessarily make sense.\n\n**Conclusion**\n\nLet's keep the current semantics for now `static int P {get; set;}` -- this\ndeclares a static auto-property. The same goes for static field-like events.\n\nWe may revisit this entire area in the future.\n\n#### Confirm that `partial` implies `private` and no access modifier is permitted?\n\n**Conclusion**\n\nConfirmed.\n\n### Nullable reference types\n\nRight now we don't allow the `?` annotation for type parameters that\nwe don't know to be non-nullable. There are numerous customer scenarios\nwhere people want to do this and are prohibited.\n\nProposal: `T?` is similar to the constraint `object?`, where T remains\nessentially unconstrained.\n\n```C#\nclass C<T>\n{\n    T? M(T p1, T? p2)\n    {\n        if (p2 != null)\n            M(p1, null); // error on the `null` because T may be `int`\n        if (p2 != null)\n            M(p1, default); // OK, because if T is `int`, default is valid\n    }\n}\n```\n\nThe goal is to provide value to the consumer that they must deal with null.\n\nA use case would be\n\n```C#\nIEnumerable<T> FilterNull<T>(IEnumerable<T?> e)\n{\n    foreach (var i in e)\n    {\n        if (i != null)\n        {\n            yield return e;\n        }\n    }\n}\n```\n\nThis would make `T?` a replacement for the `MaybeNullAttribute` and would\nprovide value for places you could not use the `MaybeNullAttribute`, like\nnested inside generic types. Moreover, attributes are not required to be\npropagated for overrides or interface implementations, so it's very possible\nfor implementations to drop requirements of their abstract specification.\n\n**Conclusion**\n\nIt does seem like our current approach has significant limitations. We want\nto look more closely at the customer scenarios, especially around overriding\nand interface implementation to decide what more we want to do."
  },
  {
    "path": "meetings/2019/LDM-2019-04-01.md",
    "content": "\n# C# Language Design Notes for April 1st, 2019\n\n## Agenda\n\n1. Pattern-based Index/Range translation\n\n2. Default interface implementations: Is object.MemberwiseClone() accessible in\nan interface?\n\n## Discussion\n\n### Index and Range patterns\n\nThe current design for Index has a high implementation overhead for\ntypes that currently have `int` indexers and all of the implementations\nsum to delegation to the `int` indexer. Also, full support can only be\nadded by type authors because there are no \"extension indexers\" in the\nlanguage. There's also a small overhead for using the Index type, as\nopposed to doing a \"direct\" translation into the `int` indexer.\n\nRange is similar to the previous.\n\nProposal: contextual conversions for Index and Range members\n\nIn short, there would be a new contextual language-defined conversion\nfrom `Index` to `int` for any instance member where the receiver is\n\"indexable\".\n\nOne significant limitation is the conversion could be more applicable than\nexpected, meaning that a member could be called with an Index that takes an\nint, but the member does not intend to be called with an Index, e.g. a member\nthat takes a length, not a index, could be called with a System.Index type\ndue to the containing type being \"indexable\".\n\nThe \"contextual\" conversion also seems very complicated, especially\ngiven that C# is already very complicated.\n\n*Q: Why only support extensions only up to the type already being\n*\"indexable\"? Could we add support for an extension Count() or similar?*\n\n**A**: Adding general collection functionality is broader than just a different form\nof indexing. That seems like an instance of a more general problem in C#.\nThere are other proposals, like roles, that provide the general purpose\nextensibility needed for the above.\n\n*Q: What if Count is implemented slowly or improperly?*\n\n**A**: This is a violation of the framework design guidelines. Count should\nbe cheap and O(1). We're willing to double down on this guideline.\n\n**Range**\n\nNote: the Slice method is preferred to the Range indexer if the Slice is\npresent.\n\nThis does violate the general principle we have that exact type matches are\nalways preferred over anything else and it makes adding a Slice method a\nbreaking library change, since it will be preferred over the Index indexer.\nIt would also allow a library to add an extension Slice to override the type's\nimplementation, which is generally not desired.\n\nThe general argument of recognizing Slice seems useful and allows people to\nadd extension support for slicing, which we like.\n\nNote: multi-dimensional arrays are not supported for either\n\n#### Alternative Proposal\n\nWe like the general approach of the prior proposal, but think adding contextual\nconversions is a step too far. Contextual conversions would be both difficult\nfor the implementation and for the user to understand.\n\nFor Index, if a type is \"indexable\" (has a Count or Length, and an indexer\nthat takes an `int`) then a synthetic indexer will be added to the type that\ntakes an Index and implements a translation to the indexer.\n\nFor Range, we do the same thing, but for \"rangeable types\". A type is\n\"rangeable\" if it has a Count or a Length, and a Slice(int,int) method.\n\n*Q: Is the 'indexable' pattern based on the constructed type or the original\ndefinition?*\n\nUnknown, revisit later.\n\n*Q: Do we want to support Slice(Range) or Slice(int)?*\n\nProbably not -- not worth the complexity.\n\nNote: for the counter-proposal, the length should only be evaluated once, and\nafter the arguments are evaluated.\n\nWarning or error for writing your own Range indexer?\n\n**Conclusion**\n\nWe think the first proposal went too far, but think the alternative is workable.\nLet's try to flesh out more of the details of that proposal and then consider it\nagain for inclusion in C# 8.\n\n\n### Revisit `object.MemberwiseClone()`\n\nThere are two things we'd like to consider: potential uses for the feature\nand consistency with the rest of the language rules.\n\nExample of use case:\n\n```C#\ninterface IPoint\n{\n    public int X { get; protected set;}\n    public int Y { get; protected set;}\n\n    public IPoint WithX(int x)\n    {\n        var tmp = MemberwiseClone();\n        tmp.X = x;\n        return tmp;\n    }\n}\n```\n\nOne argument also levelled against the feature is that it may be unexpected\nthat an interface could call MemberwiseClone(). A counter argument is that it\nmay be unexpected if a base class calls MemberwiseClone, but that is the\ncurrent behavior in classes.\n\nOn the other hand, many people may have an impression that interfaces and\nclass are essentially different type hierarchies and they meet at the\nimplementation. There is also another protected member, the destructor, which\nis on object and is questionable to provide to the interface itself.\n\n**Conclusion**\n\nThe only thing we strongly agree upon is that many of the members of object\nshould not have been there in the first place. Beyond that, we aren't\nparticularly swayed by either the advantages of having the access or the\ndangers of misuse. We'll slightly prefer our earlier decision: protected\nmembers of object are not accessible in interfaces."
  },
  {
    "path": "meetings/2019/LDM-2019-04-03.md",
    "content": "\n# C# Language Design Notes for Apr. 3, 2019\n\n## Agenda\n\n1. Ambiguous implementations/overrides with generic methods and NRTs\n2. NRT and `dynamic`\n\n## Discussion\n\n### Ambiguous implementations/overrides with generic methods and NRTs\n\n```C#\ninterface I\n{\n    void Foo<T>(T value) where T : class;\n    void Foo<T>(T? value) where T : struct;\n}\n\nclass C : I\n{\n    void I.Foo<T>(T? value) { }\n}\n```\n\nThis was valid code in C# 7 and would always match the Nullable\noverload because T? could only mean Nullable\\<T>. Now, however, `T?`\nis ambiguous. The ambiguity also cannot be fixed because we do not\nallow you to write the constraints.\n\nPossible fixes:\n\n1. The existing code means the same thing as before, namely that `T?` always means `Nullable<T>`.\nIf you would like to use the nullable class form, we allow exactly one constrain on the\noverride/implementation: `where T : class`.\n\n2. Same as (1), but also allow the constraint `where T : struct`.\n\n3. No new syntax, do matching in two passes. First, look if the old form (`where T : struct`) is\npresent and use it if present. Second, expand to look for both forms if no match was found.\n\nThese fixes would address the problem where we currently just choose the \"first\" one. Note that\nthis is not the only situation where you observe ordering dependence for OHI, but it also appears\nthat that ordering dependence appears in the CLR, so we're not considering this fix to address\nall of the complexity here, just to not make things worse.\n\n\nOption 4: When you are trying to match an implementation against two signatures, you prefer the\none that, for each type parameter, if it has any `T?` instantiations, each of those type\nparameters has `struct` constraints. In other words, for each place where the overriding member\nhas a `?`, we look for a signature that has a struct type parameter in at least the same places\nas every other candidate.\n\nFollow-on question: why not allow implementations and overrides to specify constraints? The\nbiggest problem is that C# does not allow you to specify certain constraints when you actually\nneed to in order to correctly override. VB solves this problem by allowing anything, specifically\nfor OHI (overriding, hiding, and interface implementation). We could also allow a *subset* of\nconstraints to be specified, but we would have to define what we mean by subset.\n\nThe main problem we have with (4) is we're worried that the preference rule would be confusing.\nFundamentally, allowing a bare `T?` to mean either `Nullable<T>` or nullable reference based on\ncontext of what is defined in the base is worrying.\n\n**Conclusion**\n\nWe like option 2. This would maintain backwards compatibility and is a\nsimple explanation for what `T?` means in OHI.\n\n### Dynamic invocation and nullable warnings\n\nDo we want to report or track nullability for values of type `dynamic`?\nIn some dynamic scenarios we don't know the nullability, but the simple\nassignment of null to a local of dynamic type must be null.\n\nIt seems like there could be value in providing at least some null tracking.\nFor a method which simply returns a `dynamic?` we could produce a maybe null\ndynamic value. For invocations, we could always produce a `dynamic!` that\nis not maybe null. This seems like a reasonable middle ground.\n\n**Conclusion**\n\nLet's track nullability for `dynamic`. Tracking dynamic values seems somewhat useful. We would do\nthe same value-based flow analysis as we do for other types. Some scenarios with `dynamic` would\nnot produce warnings, but if a warning is produced it seems likely to indicate a real problem.\n\n### Dynamic invocation of static methods with dynamic arguments\n\nFor static methods, we currently do no type checking for the dynamic\narguments, but we do check if any of the candidates are possible. Would\nwe provide null checking in addition to this? For all argument types, including\nthe dynamic arguments?\n\n**Conclusion**\n\nSince we already do some validation for static invocations, and we can provide\nsome useful static information here, it sounds good to do it if possible.\n\n### Nullability of return type of dynamic static invocations\n\nWe currently do no checking on the return type (the return type is always\ndynamic, even if all the candidates return void). Adding nullability does not\nseem useful given the lack of checking that we already do.\n\n**Conclusion**\n\nThe return type is always `dynamic!`."
  },
  {
    "path": "meetings/2019/LDM-2019-04-15.md",
    "content": "\n# C# Language Design Notes for Apr. 15, 2019\n\n## Agenda\n\n1. CancellationToken in iterators\n2. Implied nullable constraints in nullable disabled code\n3. Inheriting constraints in nullable disabled code\n4. Declarations with constraints declared in #nullable disabled code\n5. Result type of `??=` expression\n6. Use annotation context to compute the annotations?\n7. Follow-up decisions for pattern-based Index/Range\n\n## Discussion\n\n### Proposal for CancellationToken in iterator method\n\nThe proposal is that we allow a parameter of type CancellationToken\nto an iterator to be decorated with an attribute that specifies\nthat the parameter is to be used in the state machine for cancellation\nif none is provided.\n\n**Conclusion**\n\nApproved. We will also allow the token in WithCancellation to override the token provided to the\niterator. We will mitigate potentially surprising behavior by making the attribute named\n`DefaultCancellation` or similar.\n\n### Implied constraints of type parameters in #nullable disabled code\n\nConsider the following declaration:\n\n```C#\n#nullable disable\ninterface I\n{\n    T M<T>(T arg);\n}\n```\n\nIf you provide an implementation,\n\n```C#\n#nullable enable\nclass A : I\n{\n    public T M<T>(T arg) where T : object\n    {\n    }\n}\n```\n\nthis will provide a warning because currently the implied constraint on `I.M<T>` is `object?`.\nThe proposal is that the implicit constraint should instead be \"oblivous `object`\", meaning that\nan implicit interface implementation will not provide a warning, and an explicit interface\nimplementation will inherit the oblivious constraint.\n\n**Conclusion**\n\nYes, the implied constraint in a disabled context is oblivious. We previously did not consider\ncontext when deciding the implicit constraint, but seeing this example, we have decided\ndifferently for disabled context.\n\n### Inheriting constraints in #nullable disabled code\n\n```C#\n#nullable enable\npublic class A\n{\n    public virtual void F2<T>(T y) where T : class?\n    {\n    }\n}\n\nclass B : A\n{\n#nullable disable\n    public override void F2<U>(U y)\n    {\n        ...\n    }\n}\n```\n\nWhat is the implied constraint for the type parameter `U`?\n\n**Conclusion**\n\nThe constraint is inherited from the definition, which is `class?`. Since you cannot write a new\nconstraint in the override, there's no point in doing anything but inheriting.\n\n### Declarations with constraints declared in #nullable disabled code\n\n```C#\n#nullable disable\nclass A<T1, T2, T3> where T2 : class where T3 : object\n{\n    #nullable enable\n    void M2()\n    {\n        T1 x2 = default; // warning?\n        T2 y2 = default; // warning?\n        T3 z2 = default; // warning?\n    }\n}\n```\n\nProposal 1: The declarations using the type parameters are treated as unconstrained. All lines\nrequire a warning by previous decisions.\n\nProposal 2: The declarations using the type parameters are treated as oblivious. None of the\nlines produce warnings.\n\n**Conclusion**\n\nProposal 2 seems to fit with the philosophy of oblivious, where we do not provide warnings and\ntrust the user to know the correct nullability of their types. Proposal 2 accepted.\n\n### Result type of `??=` expression\n\nRight now the result type of `??=` is always the type of the LHS of the assignment. This is\nconsistent with all other assignment operators in the language. However, there's been some desire\nfor a closer analogy to the `??` instead of to the assignment operators.\n\nThat change would mean the following:\n\n```C#\nint? b = null;\nvar c = b ??= 5;\n// b is int?\n// c is int\n```\n\n**Conclusion**\n\nWe will accept the design change to be closer to the behavior of `??`. This means that we will no\nlonger maintain the principle that an assignment can be replaced with the variable being assigned\nin an expression context. While that is unfortunate, we think the use cases are good enough to\njustify the drawback. The result of the `??=` expression will be the result of an implicit\nconversion from the RHS to the underlying type of the LHS, if one exists. Spec note: if possible\nit would be cleaner to specify this in terms of `??`.\n\n### Use annotation context to compute the annotations?\n\nThe current LDM decisions have a tentative decision to prohibit inferring oblivious in type\ninference, as a part of the principle that type inference does not infer \"unspeakable\" types.\n\nThe proposal is that we change the spec to remove this requirement. We do not seem to have any\ndefinitive examples of where this rule would reduce confusion or provide a lot of value, and it\nseems to be fairly complicated both to implement and also to spec the results of all of the\nsituations in which oblivious states can enter into type inference.\n\n**Conclusion**\n\nWhile the principle is valuable, it doesn't seem to carry over to this area completely.\nIt's agreed that we will remove this part of the spec and keep our current implementation.\n\n### Follow-up decisions for pattern-based Index/Range\n\nA small note that there were the following changes or refinements for pattern-based Index/Range:\n\n- All members in the pattern must be instance members \n- If a Length method is found but it has\nthe wrong return type, continue looking for Count \n- The indexer used for the Index pattern must\nhave exactly one int parameter \n- The Slice method used for the Range pattern must have exactly\ntwo int parameters - When looking for the pattern members, we look for original definitions, not\nconstructed members\n"
  },
  {
    "path": "meetings/2019/LDM-2019-04-22.md",
    "content": "# C# Language Design Notes for April 22, 2019\n\n## Agenda\n\n1. Inferred nullable state from a finally block\n2. Implied constraint for a type parameter of a partial?\n3. Target-typed switch expression\n4. DefaultCancellationAttribute and overriding/hiding/interface implementation\n\n## Discussion\n\n### Nullable Reference Types\n\n#### Inferred nullable state from a finally block\n\nSee https://github.com/dotnet/roslyn/issues/34018\n\n> I don't think our current inference design interacts with finally blocks well:\n\n```C#\nC? c = null;\ntry\n{\n    c = SomeNonNullComputation;\n}\nfinally\n{\n    if (c != null) c.Cleanup();\n}\nc.Operation(); // undeserved warning\n```\n\n> We infer from c != null that c might be null. That inference leaks out to the enclosing construct. The result is a warning when c is used after the try-finally statement. This will be a common pain point.\n\n> I don't think indirect inferences from inside a finally block should leak out to the enclosing context. An inference from an actual assignment in the finally block should indeed leak out, though.\n\n\nThis problem is partially caused by the limitations of the flow analysis being non-monotonic\nand our simple path-independent analysis that uses the conservative result of a union\nof the end of the try and the end of the finally, which doesn't distinguish between\ndifferent paths through the try-finally.\n\nProposal:\nModify the analysis so that inferred branches do not modify the state outside of the\nfinally. Thus, the state from the inferred `else` will not propagate out of the `finally`.\n\n**Conclusion**\n\nWe're a little worried about the additional computational complexity of path-dependent\nflow analysis, and if `finally` is the only place it would improve precision, it seems\nto be of limited value. The proposal will fix a rather obvious flaw in the existing\nanalysis, is relatively simple, and will probably not make other scenarios significantly\nworse. Accepted.\n\n### Implied constraint for a type parameter of a partial?\n\nSee https://github.com/dotnet/csharplang/issues/2450\n\n> What is the implied type parameter constraint in\n\n```C#\n#nullable disable\npartial class C<T> { }\n#nullable enable\npartial class C<T> { }\n```\n\n> If there were only the first declaration, the constraint would be \"oblivious object\". If there\nwere only the second declaration, the constraint would be \"nullable object\".\n\n> Is this an error?\n\nWe've been moving code to CoreFX recently and we've hit cases where we can't necessarily move all\nof the partials to use nullable at the same time, so an error could make things much more\ndifficult.\n\nProposal: We already have rules about merging two type declarations with differing nullability\nfor type inference. The rule about invariants seems to fit well for this situation. The merged\nresult will be the same as the one produced for type inference.\n\nQ: Will a warning be produced if constraints don't match? Where will it be produced?\n\nQ: Will an error be produced if the conflict is two different annotations in enabled code?\n\nQ: Would the proposal apply only to partial types? Or to partial methods as well?\n\n**Conclusion**\n\nWe like the proposal to use the invariant matching from type inference and merging. A mismatch\nbetween two non-oblivious candidates produces an error. No warnings are produced.\n\nFor partial methods, the constraints must match and we produce the same warnings/errors as we would with mismatched parameter types.\nFor the result, we use the implementation signature inside the implementation, and the\ndeclaration signature for the callers.\n\n### Target-typed switch expression\n\nIt seems like we would like this to work:\n\n```C#\nbyte M(bool b) => b switch { false => 0, true => 1 };\n```\n\nProposal:\n\n1. If there is a common type, that is the natural type of the switch expression.\n2. There is also a new implicit conversion from expression, to type `T` if every\n   expression type in the arms can convert to `T`.\n\n\nUnfortunately, we cannot do the same thing for the conditional expression:\n\n```C#\nvoid M(byte b) { }\nvoid M(long l) { }\n\nvoid Test(bool b) => M(b ? 1 : 0);\n// The above calls M(long l). If we use the above proposal for ?:\n// then it will call M(byte b) because byte\n// is a \"better\" overload than long\n```\n\nHowever, we could do a modification: the target typing exists only when the\nconditional expression does not have a natural type. \n\n**Conclusion**\n\nProposal accepted for the switch expression; do it before shipping C# 8.0. We also like the\nmodification to the conditional expression. We would like to do it in C# 8.0 if possible, but if\nnot we will not tie the switch expression changes to the conditional expression changes.\n\n### DefaultCancellationAttribute and overriding/hiding/interface implementation\n\nProposal: produce a warning if the attribute is placed anywhere aside from a parameter with type\nCancellationToken on an async iterator method. That means that abstract methods would have a\nwarning.\n\n**Conclusion**\n\nAccepted. \n\nAlso,\n\n- We will not warn on applying the attribute to multiple CancellationToken parameters\ninside an async iterator.\n\n- We *will* warn if there is at least one CancellationToken parameter\nto an async iterator and none of the parameters have the attribute applied."
  },
  {
    "path": "meetings/2019/LDM-2019-04-24.md",
    "content": "# C# LDM Notes for April 24, 2019\n\n## Agenda\n\n1. MaybeNull and related attributes\n\n## Discussion\n\nThere are two proposals on the table:\n- https://github.com/cston/csharplang/blob/MaybeNull/proposals/MaybeNull.md\n- https://gist.github.com/MadsTorgersen/e94bc6802b96ce9cc65bc3dd39b7f6a2\n \nThe proposals are primarily focused on providing nullable information for the caller of methods\nwhere certain nullable contracts are outside the ability of our current annotation syntax to\nexpress.\n\nWe've also gathered the following information on nullable contracts as they currently\nexist in CoreFX:\n\n> We’ve annotated most of corelib at this point.  I just quickly went through looking at some of the ~600 TODO-NULLABLE follow-up comments we have for examples of public API signatures that are currently less-than-correct and that would benefit from further ability to annotate/attribute.  I did not include things that just impact locals or fields or other non-API stuff.\n\n> Generic methods or method on generic type that might return default(T), e.g.\n\n> - Array.Find<T>(T[] array, Predicate<T> match).  Returns default(T) if there isn’t a match.\n> - Lazy<T>.ValueForDebugDisplay.  Returns default(T) if the Lazy<T> hasn’t yet been initialized.\n> - Marshal.PtrToStructure<T>(IntPtr).  If you pass in IntPtr.Zero, you’ll get back default(T).\n\n> Generic methods accepting an unconstrained T with argument that should not be null\n \n> - Marshal.GetFunctionPointerForDelegate\n\n> Try- methods on generic type that outs default(T), e.g.\n\n> - ConcurrentQueue<T>.TryDequeue(out T)\n> - IProducerConsumerCollection<T>.TryTake(out T)\n> - WeakReference<T>.TryGetTarget(out T target)\n> Try- methods with non-generics, e.g.\n> - Version.TryParse\n> - Semaphore.TryOpenExisting\n\n> Try- methods that return a struct wrapper around a reference type that’ll be non-null if returning true\n\n> - MemoryMarshal.TryGetArray(…, out ArraySegment<T>)\n\n \n\n> Interfaces where T should be nullable on some methods but non-nullable on others, e.g.\n\n> - IEqualityComparer<T>: Equals(T x, T y) should have nullable arguments, but GetHashCode(T obj) should have a non-nullable argument\n\n \n\n> Fields/properties of type T that start life as default(T), and maybe become default(T) again\n\n> - AsyncLocal<T>.Value\n> - ThreadLocal<T>.Value\n> - StrongBox<T>.Value \n\n> Array slots that need to be settable to default(T)\n\n> - Pretty much every collection we have, nulling out a slot when an element is removed\n\n> Methods where whether the return value can be null is impacted by whether an argument is null\n\n> - RegistryKey.GetValue\n> - Path.GetFullName\n> - Path.ChangeExtension\n> - Path.GetExtension\n> - Path.GetFileNameWithoutExtension\n> - Convert.ToString(string?)\n> - Delegate.Combine\n\n \n\n> Methods where whether the return value can be null is impacted by whether an argument is true/false\n> - Type.GetType(…, bool throwOnError)\n\n \n\n> Methods where one argument will be non-null if another is non-null\n> - Volatile.Write\n> - Interlocked.Exchange\n> - Interlocked.CompareExchange (this one’s more complicated still)\n\n \n\n> Methods that accept an delegate<object?> and object?, but where the argument to Action<object?> will be non-null iff the object? is non-null\n> - Task.Factory.StartNew\n> - ExecutionContext.Run\n> - SynchronizationContext.Post\n> - CancellationToken.Register\n> - ThreadPool.QueueUserWorkItem\n> - Task ctor\n> - IValueTaskSource.OnCompleted\n\n \n\n> Ref arguments that will be non-null upon return\n> - Array.Resize(ref T[]);\n> - LazyInitializer.EnsureInitialized(ref T) (this one’s complicated if T is a nullable value type)\n\n\nThe first question is whether or not the annotation of the method\nchanges, e.g.\n\n```C#\npublic static class Enumerable\n{\n    [return: MaybeNull]\n    public static T FirstOrDefault<T>(this IEnumerable<T> src) {...}\n\n    public static T Identity<T>(T t) => t;\n}\n```\n\nHere `FirstOrDefault<string>` does not produce a `string?`, but the flow state of values returned\nfrom calls is a string with a MaybeNull state. Following through, for\n`Identity(FirstOrDefault<string>(...))`, the inferred type of `T` for `Identity<T>` would be\n`string?` because the flow state is used to construct the annotation of the substituted type\nargument.\n\nAs written, if you were to provide a `FirstOrDefault<string>` override for an analogous\n`FirstOrDefault<T>` instance method, you could not write `string?` for the return type, despite\nthe `MaybeNull` attribute.\n\nThe proposal does not attempt to address modifying what the methods accept, only\nwhat they produce, meaning that providing `MaybeNull` on a parameter does not\nindicate that the input can be nullable.\n\nHowever, we think `MaybeNull` may be common or impactful enough to consider syntax, like allowing\n`T?` on an unconstrained type parameter or `T : object?`, to express `MaybeNull`. Importantly,\nthis would not address all the patterns we've found while annotating CoreFX, like\n`Interlocked.CompareExchange` or `Debug.Assert`.\n\nThe other problem is that the list of attributes which are needed to represent all\npatterns is unbounded for all the code, but even the set of attributes needed for\njust what we know is common is quite large.\n\n**Conclusion**\n\nWe think the best approach right now is to try to address ~80% of the common cases\nusing a mixture of attributes and special casing for extremely complicated contracts\nlike `Interlocked.CompareExchange`.\n\nFor `MaybeNull` and `T?` specifically, we are conflicted between the potential value\nthat `T?` can provide, especially in annotating nested types, and the additional\ncomplexity in both language and implementation. One thing we're particularly worried\nabout is the design work in adopting `T?` and revisiting some previous decisions.\nWe're going to examine that work and if it's low in comparison to the `MaybeNull`\nattribute work, there's substantial support for implementing the feature. If we do,\nimplement `T?`, we do not want to include the `MaybeNull`, specifically."
  },
  {
    "path": "meetings/2019/LDM-2019-04-29.md",
    "content": "\n# C# LDM for April 29, 2019\n\n## Agenda\n\n1. Default interface implementations and `base()` calls\n2. Async iterator cancellation\n3. Attributes on local functions\n\n## Discussion\n\n### Default interface implementations and `base()` calls\n\nThe way `base.` works in classes, if the base implementation that was present at compile\ntime is removed at rune time, the CLR will search for the next implementation in the\nhierarchy and use that instead. For example,\n\n```C#\nclass A\n{\n    public virtual void M() { }\n}\nclass B : A\n{\n    public override void M() { }\n}\nclass C : B\n{\n    public override void M() { base.M(); }\n}\n```\n\nif `B.M` is not present at run time, `A.M()` will be called. For `base()` and interfaces, this is\nnot supported by the runtime, so the call will throw an exception instead. We'd like to add\nsupport for this in the runtime, but it is too expensive to make this release.\n\nWe have some workarounds, but they do not have the behavior we want, and are not the\npreferred codegen. Our implementation for C# is somewhat workable, although not exactly what we\nwould like, but the VB implementation would be much more difficult. Moreover, the implementation\nfor VB would require the interface implementation methods to be public API surface.\n\n#### Conclusion\n\nCut `base()` syntax for C# 8. We intend to bring this back in the next major release.\n\n### Async iterator cancellation\n\nWe’ve discussed but not settled on a behavior for when you have:\n\n```C#\nIAsyncEnumerable<T> enumerable = SomeIteratorAsync(ct1);\nIAsyncEnumerator<T> enumerator = enumerable.GetAsyncEnumerator(ct2);\n```\n\nIn some cases, the answer is easy:\n\n * If ct1 == ct2, it doesn’t matter, use ct1.\n\n * If ct1 == default, use ct2.\n\n * If ct2 == default, use ct1.\n\nBut it leaves the hard case, where `ct1 != default && ct2 != default && ct1 != ct2`. There are several options for how to handle that:\n\n1. Use ct1, ignore ct2.\n1. Use ct2, ignore ct1.\n1. Throw from GetAsyncEnumerator (the point at which we can see both).\n1. Use a new ct3 that combines ct1 + c2 (it’ll be canceled when either is canceled).\n\nThe current bits do (2).\n\nThere was previous support for (3).\n\nBut in our most recent discussion, (4) seems useful.\n\nPros for (4):\n\n* It’s intuitive and explainable. No matter what token you pass where, the implementation will respect it. Canceling a token will request cancellation of the enumeration, regardless of where you pass it.\n\n* It composes naturally. The code creating the iterator can pass a token. The code enumerating the iterator can pass a token. Both are respected.\n\n* Code reviews / debugging will be easier. In our experience diagnosing production hangs, in multiple cases it was because some code in the Azure SDK didn’t pass along a CancellationToken it was supposed to. Once we knew where to look, it was very obvious just from looking at the source that the CancellationToken passed into method A wasn’t passed to method B. If we do (1) or (2), it’ll be very difficult to spot such issues, as the developer will correctly be passing along the token, but the compiler-generated implementation will ignore it, in code not visible anywhere.\n\nCons for (4):\n\n* Compiler-generated code. There’s more of it, with an additional BCL dependency (CancellationTokenSource).\n\n* Slightly larger object size. The state machine will need a CancellationTokenSource field that represents the combined source. The field (but not the instance) will be necessary even in the common case where there’s only one token and combining isn’t necessary.\n\n* More work in GetAsyncEnumerator. In the case where either or both tokens are default, it would just add one or two comparisons. In the case where both are non-default and need to be combined, it’d involve some allocation and additional work, but pay-for-play.\n\n#### Conclusion\n\nAgreed on (4). Produce an error if you have the EnumeratorCancellationAttribute on more than one\nCancellationToken. Warn if you have a CancellationToken parameter with no attribute.\n\n\n### Triage\n\nRemainder of time left over for triaging C# 8.0 features.\n\nNew tentative scheduling: https://github.com/dotnet/csharplang/projects/4\n\n\n### Attributes on local function parameters\n\nWe realized that attributes are not permitted on local function parameters,\nwhich means that you cannot use the `EnumeratorCancellation` attribute in\nlocal function iterators.\n\n**Conclusion**\n\nAllow attributes on local function parameters and type parameters."
  },
  {
    "path": "meetings/2019/LDM-2019-05-13.md",
    "content": "# C# Language Design Meeting for May 13th, 2019\n\n## Agenda\n\n1. Close on desired rules for warning suppressions and `#nullable` interacting\n\n## Discussion\n\n### Warning suppressions and `#nullable` interacting\n\nThe question is what project-level and source-level controls to expose for users to have a pleasant onboarding experience with the nullable feature. We previously leaned towards more flexibility, but want to consider streamlining the design in light of early feedback.\n\nWe considered two dimensions of control: (1) whether the types are annotated or not (ie. what is the meaning of `string`?), and (2) whether nullability warnings are produced. \n\nAt the project-level at least, all four permutations of those options (disable, enable, annotations-only, and warnings-only) are useful. \n\n| -            | Annotations on | Annotations off |\n| ------------ | -------------- | --------------- |\n| Warnings on  | enable         | warnings        |\n| Warnings off | annotations    | disable         |\n\n\nAnnotations-only are useful for library authors who want to provide annotations for their APIs before they are ready to review their code. \nWarnings-only are useful for application consumers who want to benefit from annotations provided by libraries, but are not ready to annotate their own APIs. \nBoth options offer a stepping stone towards enabling the feature fully.\n\n#### The need for both project-level and source-level controls\n\nOur starting model included the four settings at the project-level (`enable`, `disable`, `annotations` and `warnings`), as well as in source (with `#nullable (enable | disable | restore) [ warnings | annotations ]`).\n\nWe observed that, in source, existing warnings cannot be enabled, they can only be suppressed. We considered whether this model could work for nullability warnings too. We don't think so: it creates a significant hurdle to adoption in existing projects. It is much easier to opt-in a few files than to opt-out all but a few files in a project.\n\nFor nullability annotations, we considered the converse: should the only way of enabling nullability annotations be in source?\nAlthough this avoids language semantics (the meaning of `string`) being affected by compilation options, it seems undesirable in the long-term. We don't want every file to require some opt-in with `#nullable enable` in new or fully migrated projects.\n\n**Conclusion**: It is useful to control both nullable annotations and warnings at the project-level and in source.\n\n#### Clarifying the interactions\n\nA scenario was brought to light by the BCL team: when updating library, it is useful to temporarily disable nullability warnings at the project-level. This could be solved with the existing `/NoWarn` option, if it were extended to support `/NoWarn:nullable` (where `nullable` is a shorthand for the set of all nullable warnings, including the W-warning/`8600`).\n\nWe iterated on this, trying to clarify how `#nullable enable warnings` would interact with `#pragma warning ...`.\n\nTwo alternatives emerged: \n1. `#nullable enable warnings` and `#pragma warning enable nullable` could be synonyms,\n2. `#nullable enable warnings` could be controlling an independent flag that combines with the suppressed/unsuppressed state of a warning to determine whether the warning is produced at a certain position in source.\n\nThe first design doesn't offer a very clear mental model when it comes to the order of precedence of various controls (project-level defaults, project-level `/NoWarn`, `#nullable ...` and `#pragma warning ...`).\nIt also makes it harder to enable and disable all but a few nullability warnings: if you suppress one warning, then use `#nullable disable` and `#nullable enable` on a code block, you must re-iterate the suppression.\n\nLet's now spell out the second design:\n\n1. There is a nullable warning context as a separate \"bit\". It can be set by default at project-level, and overridden with `#nullable` directives. It needs to be on to get nullable warnings at a given point in the source.\n\n2. Individual warnings continue to be able to be individually disabled at the project-level with `/NoWarn` and disabled or restored in source with `#pragma warning ...`.\n\n3. Additionally there is a \"virtual warning identifier\", `nullable` that can be used in `/NoWarn` at the project level, and that individually disables all warnings related to the nullable feature.\n\nThis design allows common cases to be expressed simply:\n- enable nullable warning context at the project-level with `<Nullable>` set to `enable` or `warnings`, then adjust in source with `#nullable` directive,\n- enable nullable warning context in source with `#nullable` directive,\n- `/NoWarn` continues to suppress warnings, including all nullable warnings using the `nullable` virtual identifier and the W-warning with `8600`, except when a specific warning is enabled in source with `#pragma warning enable <id>`.\n\n**Conclusion**: \nWe're going to pursue the second design, based on \"nullable warning context\" bit. \nWe tentatively decided to remove support for the `nullable` group from the `#pragma warning ...` directive.\n\n#### Names of options\n\nWe considered some alternative naming schemes, to try and clarify the options:\n`warnings`/`annotations`\n`warningsOnly`/`annotationsOnly`\n`analysisOnly`/`annotationsOnly`\n\n**Conclusion**:\nThere is a strong desire to use the same labels for the project-level (`<Nullable>...</Nullable>`) and source-level (`#nullable enable ...`) settings.\nWe decided to keep the current names for now: `warnings` and `annotations`. We plan to revisit that.\n\n#### Removing support for `#pragma warning enable ...` \n\nThe `enable` verb in the `#pragma warning` directive seems a general feature, orthogonal to the nullable feature. We feel we need to review it and confirm how it interacts with various mechanisms for suppressing warnings.\n\n**Conclusion**:\nWe will leave this feature for now and revisit it later, including the `nullable` group identifier.\n\n#### Removing support for `safeonly` group identifier\n\nIs the recent decision to remove `safeonly` and `safeonlyWarnings` still holding, despite some concerns raised?\n\n**Conclusion**:\nYes, `safeonly` is okay to remove at this point. `/NoWarn:8600` has the same effect.\n\n\n\n\n\n"
  },
  {
    "path": "meetings/2019/LDM-2019-05-15.md",
    "content": "\n# C# Language Design Meeting for May 15th, 2019\n\n## Agenda\n\n1. Refining nullability signatures in APIs \n\n## Proposal: Refining nullability signatures in APIs \n\nThis proposes a set of language-level mechanisms (mainly in the form of attributes) that would provide for accurate annotation of the large majority of CoreLib members, and also eliminate a good number of warnings in the CoreLib implementations. \n\nThe names of attributes need to undergo API review. The attributes count as “nullable annotations” (with the exception of the Flow attributes that aren’t directly related to nullability) and yield a warning if applied where the annotation context is disabled. They are part of the contract of the member, and as such they need to be respected “covariantly” by overrides and implementations that are also in an enabled annotation context. That is: an override can loosen a restriction or tighten a promise, not the other way around. \n\n### Simple pre- and postconditions \n\nThese are applied to an input and output, and specify an “override” to the type, in that they may limit to not-null or extend to maybe-null regardless of what the type says. These alone can take care of the bulk of CoreLib TODOs regarding imprecise signatures. \n\nIt is important that both preconditions and postconditions are separately expressible, with individual attributes, since some annotatable entities are both input and output (e.g. ref parameters, fields and properties), and it is common in CoreLib for a restriction to apply only to the input or to the output. \n \n#### Simple preconditions \n\nThese apply to anything that takes input: value, in and ref parameters, fields, properties, indexers, etc: \n\n- `[AllowNull]`:  Allows null as the input, even if the type disallows it \n- `[DisallowNull]`: Disallows null as the input, even if the type allows it \n\nOn invocation, preconditions are applied after any generic substitution, and are affected by the null-state of the input. `[AllowNull]` prevents any top-level nullability warning on the input, whereas `[DisallowNull]` emits a warning if the input state is “may be null”. \n\nInternally to the member, the preconditions may affect the initial null-state of the input (parameter, value variable, etc). \n \n#### Simple postconditions \n\nThese apply to anything that yields output: out parameters, return values, fields, properties, indexers, etc: \n\n- `[MaybeNull]`: The output may be null, even if the type disallows it\n- `[NotNull]`: For outputs (`ref`/`out` parameters, return values), the output will not be null, even if the type allows it. For inputs (by-value/`in` parameters) the value passed is known not to be null when we return.\n\nOn invocation, postconditions are applied after generic substitution, and affect the null state of the output. `[MaybeNull]` changes the null state of the output to “may be null”, whereas `[NotNull]` changes it to “not null”.  \n\nInternally to the member, returning or assigning a value to an output element thus annotated may get or avoid warnings based on the null-state of the value. \n\n**Examples of simple pre- and post-conditions**\n\n```csharp\npublic class Array \n{ \n    // [AllowNull] on a non-nullable ref to express that nulls may be passed in, \n    // but that nulls will not come out. \n    public static void Resize<T>([AllowNull] ref T[] array, int newSize); \n \n    // Alternatively, [NotNull] on a nullable ref to express that nulls \n    // may be passed in but will not be passed out. \n    public static void Resize<T>([NotNull] ref T[]? array, int newSize); \n} \n \npublic class Array \n{ \n    // Result can be default(T) if no match is found \n    [return: MaybeNull] \n    public static T Find<T>(T[] array, Predicate<T> match); \n} \n\npublic class TextWriter \n{ \n    // [AllowNull] on the setter of a non-nullable property to say that \n    // the setter accepts nulls even though the getter will never return null. \n    public virtual string NewLine \n    { \n        get => …; \n        [AllowNull] \n        set => …; \n    } \n \n    // Alternatively, [NotNull] on the getter of a nullable property to say that \n    // the getter returns non-null even though the setter accepts null. \n    public virtual string? NewLine \n    { \n        [NotNull] \n        get => …; \n        set => …; \n    } \n} \n \npublic class StrongBox<T> \n{ \n    // Public field that defaults to default(T) \n    public [MaybeNull] T Value; \n \n    public StrongBox() {} \n} \n \npublic class ThreadLocal<T> \n{ \n    // Even when T is non-nullable, the getter will return default(T) \n    // when accessed on a thread where a value hasn’t been set. \n\n    [MaybeNull] \n    get => … \n    set => … \n} \n \npublic interface IEqualityComparer<in T> \n{ \n    // Regardless of the nullability of T, GetHashCode doesn’t \n    // allow nulls, but Equals does (whether [AllowNull] is needed \n    // on the equals parameters is debatable). \n    bool Equals([AllowNull] T x, [AllowNull] T y); \n    int GetHashCode([DisallowNull] T obj); \n} \n \ninternal static void SafeHandleHelper \n{ \n    // Null shouldn’t come in, but null can (and will) come out. \n    public static void DisposeAndClear([DisallowNull] ref SafeHandle? handle); \n} \n```\n\n### Value nulls \n\nThere are places in CoreLib where only reference nulls need be prevented, but the large majority will throw on both value and reference nulls. It is not worth the complexity to distinguish these two cases; instead [DisallowNull] always prevents both value and reference nulls. The negative impact on the few places that can handle value nulls (such as IEqualityComparer.GetHashCode) is minimal. \n \n### Nonnullable constraint \n\nFor generic dictionary-like types in CoreLib, input elements of the key type should never be null. It is possible to use `[DisallowNull]` in most places where the key type is given as input, but it doesn’t work everywhere (e.g. doesn’t transfer to composed-in types, such as the key collection), and it diminishes the user value, because warnings aren’t yielded on generic instantiation with a null-unsafe key type, but only when members are called that take it as an input. \n \nFor this reason, there should be a generic constraint, `nonnull`, that prevents the type argument from being nullable. Like the `[DisallowNull]` it applies to both nullable value types and nullable reference types, and yields a nullability warning when violated. While technically “correct”, we think object would be confusing as the name of the constraint, because it puts readers in mind of reference types.  Additionally, since the nullable reference types feature is purely a manifestation of the language, the constraint should not result in an IL constraint that the runtime enforces, and since object is a type and types used as constraints are emitted to the IL as a constraint the runtime is aware of, it’s strange to use object but then not have it emitted.  It should instead be nonnull and not be emitted as a base type constraint. \n \nExamples of non-nullable constraint:\n\n```csharp\npublic static class Marshal \n{ \n    // The method fills in the provided instance from the pointer, and thus \n    // T shouldn’t be null. \n    public static void PtrToStructure<T>(IntPtr ptr, T structure) \n        where T : nonnull \n \n    // Alternatively, [DisallowNull] could be used. \n    public static void PtrToStructure<T>(IntPtr ptr, [DisallowNull] T structure) \n} \n \n// TKey on Dictionary, IDictionary, ConcurrentDictionary, etc. should not be null \npublic class Dictionary<TKey, TValue> : \n    IDictionary<TKey, TValue>, \n    IDictionary, IReadOnlyDictionary<TKey, TValue>, \n    ISerializable, \n    IDeserializationCallback \n    where TKey : nonnull \n```\n\n### Unconstrained “T?” \n\nBecause nullability can be expressed on both input and output (with `[AllowNull]` and `[MaybeNull]`) in the few cases in CoreLib where it is needed in both directions it can be expressed using both attributes together. There is therefore no real need for the ability to say `T?` on an unconstrained `T`. Conversely, having unconstrained `T?` doesn’t obviate the need for `[AllowNull]` and `[MaybeNull]`, as they are needed for single-directional scenarios. \n \nHaving `T?` would allow for the elimination of some warnings in generic code, notably around propagation and storage of `default(T)` values. However we consider that a separate potential improvement that could be added to the language later.  \n\n### Interdependent postconditions \n\nThere is a long and varied list of APIs where the nullability of an input or output depends on other input or output of a method in various ways. It is not reasonable to express all of these patterns with attributes. Some are common patterns and should be expressed as attributes. Some occur on a short list of very commonly used members, and can be hardcoded into the compiler. A remaining long and thin tail will have to be left inexpressible. \n \n#### Conditional postconditions \n\nThese are applied to parameters of bool-returning methods, and express that a given nullability applies to the parameter only when the method returns a given value. \n \n- `[MaybeNullWhen(bool)]`: If the method returns the `bool` value, the parameter may be null, even if the type disallows it \n- `[NotNullWhen(bool)]`: If the method returns the `bool` value, the parameter will not be null, even if the type allows it \n \nThese can be applied to both input and output (i.e. to all kinds of parameters) because they may represent either a test on input, or an assignment to output. \n \nOn the outside these are realized by affecting the conditional null-state (not null when true/false) after the invocation of the member. On the inside the conditional nature cannot be faithfully enforced. Instead, the most lenient of the two states is enforced unconditionally.  \n \nThe core libraries only have examples of `[MaybeNullWhen(false)]` and `[NotNullWhen(true)]` but we should offer all four combinations for generality and symmetry. \n \nExamples of conditional postconditions:\n \n```csharp\npublic class Version \n{ \n    // If it parses successfully, the Version will not be null. \n    public static bool TryParse( \n        string? input, \n        [NotNullWhen(true)] out Version? Version); \n} \n \npublic static class Semaphore \n{ \n    // Not just for parsing… \n    public static bool TryOpenExisting( \n        string name, \n        [NotNullWhen(true)] out Semaphore? result); \n} \n \npublic class Queue<T> \n{ \n    // With unconstrained generics, we use the inverse \n    public bool TryDequeue([MaybeNullWhen(false)] out T result) \n} \n \n \npublic static class MemoryMarshal<T> \n{ \n    // It applies as well with constrained generics. \n    public static bool TryGetMemoryManager<T, TManager>( \n        ReadOnlyMemory<T> memory, [NotNullWhen(true)] out TManager? manager) \n        where TManager : MemoryManager<T> \n} \n \npublic class String \n{ \n    // Not just for outs… also relevant to inferrig nullability of \n    // input arguments based on the return value. \n    public static bool IsNullOrEmpty([NotNullWhen(true)] string? value) \n} \n```\n \n#### Nullness dependencies between inputs and outputs \n\nAnother common pattern is an output being non-null if a particular input is non-null.  We can codify that with another attribute: \n \n- `[NotNullIfNotNull(string)]`: Applied to a return, ref, or out to indicate that its result will be non-null if the parameter specified by name is non-null \n \nOn the outside, these attributes are realized by giving the annotated output a not-null state if the input specified by name is not-null. On the inside this does not realistically seem enforceable. \n \nExamples of dependencies between inputs and outputs:\n \n```csharp\nclass Path \n{ \n    [return: NotNullIfNotNull(nameof(path))] \n    public static string? GetFileName(string? path); \n} \n \nclass RegistryKey \n{ \n    [return: NotNullIfNotNull(nameof(defaultValue))] \n    public object? GetValue(string name, object? defaultValue) \n} \n \nclass Interlocked \n{ \n    public static T Exchange<T>([NotNullIfNotNull(nameof(value))] ref T location1, T value) where T : class? \n} \n \nclass Volatile \n{ \n    public static void Write<T>([NotNullIfNotNull(nameof(value))] ref T location, T value) where T : class? \n \n    [return: NotNullIfNotNull(nameof(location))] \n    public static T Read(ref T location); \n} \n \nclass Delegate \n{ \n    [return: NotNullIfNotNull(nameof(a))] \n    [return: NotNullIfNotNull(nameof(b))] \n    public static Delegate? Combine(Delegate? a, Delegate? b) \n} \n```\n \n#### Equality postconditions \n\nCertain members are equality tests on their inputs, and if the result is true (or, in the case of `!=`, false) the nullability of the two parameters is equal. \n \nBetween the language and CoreLib, there is a small fixed set of equality methods and operators, and people are unlikely to add new ones. Therefore it is not worth creating attributes for these, and they should instead be hardcoded into the compiler. \n \nExamples of equality:\n- `Object.ReferenceEquals`\n- `Object.Equals` \n- `IEqualityComparer<T>.Equals` \n- `EqualityComparer<T>.Equals` \n- `IEquatable<T>.Equals `\n \n#### CompareExchange \n\nOf the remaining members with special null behavior, the one that sees by far the most use is Interlocked.CompareExchange. It’s nullability contract is way too complex to reasonably express through attributes, but should be hardcoded into the compiler due to the amount of usage that the method sees. \n \nThere are two relevant overloads: \n \n```csharp\npublic static extern object? CompareExchange( \n    ref object? location1, object? value, object? comparand); \n \npublic static T CompareExchange<T>( \n    ref T location1, T value, T comparand) where T : class? \n``` \n\nThe most important case to infer here: \nIf comparand is a constant null and value is non-null, location will be non-null on return. \n \nThat covers the very common case of lazy initialization: \n \n```csharp\nif (_lazyValue == null) Interlocked.CompareExchange(ref _lazyValue, new Value(), null); \nreturn _lazyValue; \n```\n \nAdditionally as a bonus: \n\nIf `location1` and value are both non-null on enter, `location1` and the result value will be non-null on return. \n\n### Flow attributes \n\nSince nullability analysis is affected by control flow, it is valuable to signal when a method affects control flow, even if it is not directly related to nullability of the method’s inputs and outputs. Specifically, if a method does not return, unconditionally or conditionally, the compiler can benefit from this information to reduce unnecessary warnings. \n\n- `[DoesNotReturn]`: Placed on the method. Code after the call is unreachable \n- `[DoesNotReturnIf(bool)]`: Placed on a bool parameter. Code after the call is unreachable if the parameter has the specified bool value \n \nExamples of flow attributes:\n \n```chsarp\npublic static class Environment \n{ \n    [DoesNotReturn] \n    public static void FailFast(string message); \n} \n \npublic class ExceptionDispatchInfo \n{ \n    [DoesNotReturn] \n    public void Throw(); \n} \n \ninternal static class ThrowHelper \n{ \n    [DoesNotReturn] \n    public static void ThrowArgumentNullException(ExceptionArgument arg); \n} \n \npublic static class Debug \n{ \n    public static void Assert([DoesNotReturnIf(false)] bool condition); \n} \n```\n \n## Discussion\n\nThe guiding priorities for this proposal are how the attributes:\n1. affect the caller,\n2. affect OHI,\n3. affect the implementer.\n\nThere is a desire for the attributes to also affect the implementation side (for example, `[MaybeNull]` on a method return would mean fewer warnings on return statements), but we did not focus on that as much.\n\n### Simple pre- and postconditions\n\nThere is some redundancy for non-generic cases. For example, you could use `[AllowNull] string` or `string?`. We'll need to provide some guidance.\n\nOpen question: should those attributes be applied to properties or to accessors?\n\n### `nonnull` constraint\n\nThe `nonnull` constraint cannot be combined with a `struct` constraint, because `struct` constraint already implies non-null.\n\n`T?` is only allowed if `T` is constrained to `class`, a class type, or `struct`.\n`T?` is disallowed if `T` is constrained to `class?` or `nonnull`.\n\n### Conditional postconditions \n\nNote that `[MaybeNullWhen(false)]` and `[NotNullWhen(true)]` are different in generic case (see `TryDequeue<string>` in examples).\n\n### Nullness dependencies between inputs and outputs\n\nWe cannot use `nameof` in `[NotNullIfNotNull(nameof(parameter))]`, because the parameter is only in scope inside the method body.\nIn overrides, implementers will have to use the parameter name of the implementation (`[NotNullIfNotNull(\"overriddenParameter\")]`), not of the overridden method.\n\nOpen question: what if the name passed to this attribute doesn't match a parameter name? Is that an error or warning?\n\n### Equality postconditions\n\nIf an equality returns true and one of the parameters has non-null state, then we can set the state of the other parameter to non-null.\nWe'll need to revisit the rules for recognizing an equality method. We may be able to use a more general pattern, instead of a list of well-known members.\nWe should also consider whether nullability analysis of an equality should account for a `null` literal \n\n### Flow attributes\n\nOpen question: would we also need a `[DoesNotReturnWhenNull(nameof(parameter))]`?\n"
  },
  {
    "path": "meetings/2019/LDM-2019-07-10.md",
    "content": "\n# C# LDM Notes\n\n## Agenda\n\n1. Empty switch statement\n1. `[DoesNotReturn]` attribute\n1. Revisiting the `param!` null-checking feature\n\n## Discussion\n\n### Empty switch expression\n\nShould the empty switch expression (`expr switch { }`) be an error?\n\n**Conclusion**\n\nWe can't really find a reason to disallow this.\n\n### DoesNotReturn\n\nThe current design for the `DoesNotReturnAttribute` indicates that the method annotated with it\nis unreachable after a call to it for the purpose of flow analysis.\n\nThe questions are:\n\n  1. Confirm that it only implies unreachability for nullability\n  2. Confirm the name, which doesn't mention nullability\n\n**Conclusion**\n\nYes to both questions. If we want to add general-case unreachability later we will do it through\na different mechanism. That would require altered code generation (to ensure both verifiability\nand that the code after is truly unreachable) and is out of scope for the current feature set.\n\n### `param!`\n\nWe previously discussed the `param!` feature, which is meant to insert a `throw`\nif the parameter is null.\n\nWe'd like to confirm some of the details.\n\nIllegal placement:\n\nWe think there should be diagnostics for the follow constructs:\n\n- Warning for default parameter value being null (e.g. `void M(string p! = null)`)\n- Error on an out parameter\n- Error on methods without bodies\n    - Including the declaration part of a partial\n- Warning if the type of the parameter is a nullable reference type or nullable value type\n- No place to put `!` on the property setter\n\nSemantics:\n\n- Should work with `notnull` constraint\n- Confirmed that the null checks should be the first possible code\n    - Including before field initializers, iterator kick-off, constructor chaining\n- Do we want to use a well-known helper instead of `throw`?\n    - CoreFX uses throw helpers, so it wouldn't be able to use the feature\n\nSyntax:\n\nIt was previously mentioned that the syntax could be confusing because `!` has different meanings\nin expressions or parameter names. Do we want to change the syntax?\n\nHere are some syntax options we discussed:\n\n1. `T p!`\n2. `T p!!`\n3. `T! p`\n4. `checked T p`\n6. `nonnull T p`\n\nWe can't decide on a syntax right now. There are concerns that some of the\nproposed syntaxes are too verbose and remove the purpose of the feature. There's\nalso a possible follow-on proposal: right now the `!` syntax already has meaning\nin an expression context, but if we used a different syntax, like `!!`, we could\nalso add a \"null-checked expression\" which does the same thing for expressions\nthat it does for parameters. These ideas are interesting enough that we think\nwe should hold the feature for the next C# version and discuss these possibilities\nmore.\n\n**Conclusion**\n\nSome revisions to the feature and some open questions. We want the feature in\nsome form and are committed to resolving these questions for the next release."
  },
  {
    "path": "meetings/2019/LDM-2019-07-17.md",
    "content": "\n# C# LDM Notes for July 17, 2019\n\n## Agenda\n\n1. [Nullability of events](https://github.com/dotnet/roslyn/issues/34982)\n2. Triage\n\n## Discussion\n\n### Field-like events\n\nThis discussion was spurred by the current implementation, which treats\nfield-like events as fields, meaning non-nullable unless annotated, and\nrequiring initialization in the constructor if non-nullable.\n\nBased on design decisions around our non-nullable field warnings and the current\nannotation implementation of events, we recognized a potential problem. For almost\nevery event, the behavior would be nullable, but it seems laborious to require every\nevent to be annotated with nullable, when that is the usage for almost every event.\n\nIt was also noted that field-like events also imply multiple pieces of generated code: a backing\nfield, which can only be directly accessed in the containing type, and generated add/remove\naccessors that can be accessed everywhere. Notably, the nullability of the generated field must\nbe compatible with, but not identical to to the generated accessors.\n\nPossibilities:\n\n1. What you write is what you get\n - Both the event and field have the declared type, and if it's nonnullable, you're forced to initialize in the constructor\n2. The backing field is always nullable\n - Would not allow assigning an empty delegate in the constructor and then invoking without a null check\n3. Force implementing manually\n4. Use attributes, perhaps [MaybeNull]\n5. Events are always nullable\n    - This is (2), but the += and -= are also nullable\n\nNotably, the `+=` and `-=` generated for field-like events *is* null safe, in that you can pass\nnull as a delegate argument and it does not produce a null reference exception.\n\nEven though it's painful, (1) seems to be attractive because it doesn't heavily special\ncase events, and `EventHandler?` accurately reflects the nullability of the event, in that\nit allows nullable handlers to be subscribed, and invoking the event could cause a null\nreference exception. A problem is that unassigned non-null events as currently implemented\nproduce a warning that complains about the event being unassigned, when in almost all situations\nthe proper fix is to declare the event type as nullable.\n\n(2) would match the usage of almost all fields, but at the expense of inconsistency, since we\nusually require `?` to annotate nullable items, and events would be special-cased to be nullable\nby default. It would also disallow the pattern of assigning an empty delegate in the constructor.\n\n**Conclusion**\n\nFor most users, making events nullable seems like the right behavior.\n\n(5) would address this in the simplest way, but\nwe really don't like the inconsistency of making types nullable without a '?'. \n\n(1) allows events to be annotated as nullable, which is what we expect most people should do.\n\nWe're sticking with (1). Current behavior is confirmed.\n\n\n## Triage for the rest of the meeting\n\n### Support XML doc comments on local functions\n\nIt's especially frustrating that XML doc comments in local functions are an error. It also seems\nuseful in larger methods where you want to see the contract for a local function in intellisense.\n\nHowever, the second reason is also a good reason to allow XML doc comments for locals.\n\n**Conclusion**\n\nInterested, but we want to see what the possibilities are on other locals.\n\n\n### Warn on obsoleting overrides of non-obsolete members\n\nIt might be useful, but is low value. Since it would be a new warning, this is blocked on warning\nwaves.\n\n**Conclusion**\n\nWe will revisit when we get warning waves.\n\n### Proposals for ConfigureAwait with context\n\nConfigureAwait and related issues have been brought up many times. We think it's worth addressing,\nand should look at possible designs.\n\n**Conclusion**\n\nLet's look it for a future major release.\n"
  },
  {
    "path": "meetings/2019/LDM-2019-07-22.md",
    "content": "\n# C# LDM Notes for July 22, 2019\n\n## Agenda\n\n1. Discuss the [new records proposal](https://github.com/dotnet/csharplang/blob/856c335cc584eda2178f0604cc845ef200d89f97/proposals/recordsv2.md)\n\n## Discussion\n\nWe started by going over the proposal.\n\nA few comments and clarifications:\n\n#### Optional and required initialization\n\nThe proposal doesn't mention what we consider a problem in existing\nC# object initializer code: there's no way to specific that members are\nrequired or optional. Most notably, a class has no way to force an object\ninitializer to set a member, and no diagnostics will be reported if it is\nskipped.\n\nThe new proposal would produce an error if an `initonly` member is not\nset either in the constructor, in an initializer, or in the object initializer.\nA suggested implementation would be to emit an attribute that indicates whether\na member initialization is required or optional, but we do not mandate a specific\nimplementation strategy.\n\n### Verification\n\nThe philosophy behind the proposed \"initonly\" verification rules are that we're broadening the\nCLR's rules slightly. In the CLR, `initonly` (which is termed `readonly` in C#) makes the claim\nthat the end of the constructor is the publish boundary for a type, so `initonly` fields are\nsettable until the constructor finishes, at which point the object is published. We're widening\nthis slightly, by creating rules that ensure that even after the constructor has finished, values\ncan be set before the item is actually published either via a store or a method call.\nAs long as these rules could be efficiently written for a theoretical verifier,\nwe don't strictly need to have an implementation concurrent with the feature.\n\n### With-constructor\n\nIt also looks like some of the compilicated codegen around the body of the `With` constructor may be unnecessary. The default implementation may be completely\nsatisfied by `object.MemberwiseClone()`. However, a With-constructor would likely\nstill be necessary, as `object.MemberwiseClone()` is protected, and we would like\nto allow for customizability.\n\n### Mutability and code generation\n\nFor classes, it would also be good to warn if mutable members are included in a `data` class,\nbecause structural equality is dangerous in the presence of mutability (e.g., if a class is\nchanged after being added to a dictionary, it can \"disappear\" from the dictionary).\n\n### Primary constructors and attributes\n\nThe proposed use for primary constructors is short and simple data types. It\nwas noted that many serialization frameworks require a large set of attributes\nto specify serialization details. \nFor the primary constructor feature, it's an open question of how attributes will\nwork. There is a proposal for putting\nattributes on the parameters with an additional target, e.g.\n\n```C#\ndata class C([property: MyAttribute]int X);\n```\n\nHowever, this harms the concision of the feature and may mean that primary constructors are not\nas useful for serialized types.\n\n### Criticisms of new proposal vs original\n\nOne major difference between the new proposal and the old proposal is that it implies the\nexistence of a record without a primary constructor. The original motivation for this was to\navoid encoding the constructor's positional API (constructors are dependent on argument order)\ninto record construction and use. Thus, to differentiate the two proposals we can refer to them\nas \"nominal\" records (records V2) and \"positional\" records (records V1).\n\n* Primary constructors as a whole: it's not clear if the pieces are actually that useful outside of\nthe records proposal.\n\n* Primary constructors + initialization. If people like object initializers, one\npossible solution is what is proposed here. Another possible solution is to make an object\ninitializer for positional records as a simple syntactic transformation to a record constructor.\n\n* Source/Binary compatibility. Positional records do not solve the problems\nof adding or re-ordering members, but it is solvable by manually writing\nback-compat constructors when adding members.\n\n* Use cases: it seems like the common case for a few fields (like the\nUserInfo example) would be more the positional record case. Instead, the\ncommon case for nominal records would be big records, like Roslyn's\nCompilationOptions.\n\n* Validation: there's no way to validate the consistency of the whole object\nin this proposal. For instance, many records have requirements that if one field\nis set, another is set as well, or that they have compatible values. Unfortunately,\nthis is also true of \"positional\" records, since the With-ers would set values\nafter the construction of the copy completes, meaning that no validation run in\nthe constructor would validate the \"With\"-ed members. One way to add this functionality would be\nto enforce a call to a well-known validation method after construction is done."
  },
  {
    "path": "meetings/2019/LDM-2019-08-26.md",
    "content": "﻿# C# Language Design Notes for Aug 26, 2019\n\n## Agenda\n\nTriage of newly championed issues. Features that we may consider are placed in the milestone where we will look at them again. Listed here by target milestone.\n\n# Milestone 8.X\n\nWe are unsure if there will be an 8.1 release or we will go straight to C# 9.0. In the latter case we will triage this bucket and move things to 9.0 or later.\n\n## #883 Zero and one-element tuples\n\nWe don't have a good syntax for one-tuples.\n\nBut in deconstruction and pattern matching there is less of a syntax problem.\n\nWhat does `(3)` mean? It is a constant 3. If you want a tuple literal, you can just give it a name - that is unambiguous. `(_: 3)` might become the common pattern, though `_` isn't a discard for tuple element names.\n\nCould consider splitting the feature and doing only one-element tuples in literals and deconstruction.\n\n\n# Milestone 9.0\n\nThis is the next major release (as C# 8.0 is a done deal at this point). Putting features in this milestone doesn't mean that we will do them here! It just means that we will consider them in this timeframe - possibly to be rejected or pushed out at that point.\n\n## #146\n\nThere'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.\n\n## #812\n\nCould work with conjunctive patterns. An alternative would be a range-like syntax.\n\n## #1792, #1793, #1502\n\nLet's keep ironing out annoying limitations in this space\n\n## #1881\n\nShould think also of UTF8\n\nFor `Memory<char>` etc we would probably continue to require you to go through `Span<char>` etc.\n\n## #2585\n\nFits well with a \"math\" push, and should align with that.\n\n\n# Milestone X.0\n\nThese would be major features, and we don't expect to consider them for C# 9.0.\n\n## #339\n\nThis is a very fundamental feature, and we're not sure we have compelling scenarios. Possibly the next thing to look at after \"type classes\" in the advanced type features category.\n\n## #1047\n\nThis is probably in pattern matching's future somewhere, though we won't be ready for it in 9.0.\n\n## #538\n\nProbably requires runtime work, and the scenarios don't currently justify that.\n\n## #2545 (Blocked)\n\nWe keep not moving on this. We'd need a good understanding with EF\n\n\n# Milestone X.X\n\nThese would be minor features which we don't expect to consider until after 9.0.\n\n## #2608\n\nFine, but doesn't rise to priority\n\n\n# Rejected\n\n## #301\n\nThis is subsumed by \"extension everything\" and the other proposals in that ilk. We do understand and support the scenario, but don't want the specific feature.\n\n## #1033\n\nRejected. The assignment should happen explicitly in the body, and the compiler can warn if you forget.\n\n## #1586\n\nIt shipped and it's in unsafe. We're ok with it.\n\n\n\n## #2383\n\nThe language is what it is at this point, and it is not worth doing work to \"fix\" it. However we should add a warning wave warning on the initializers saying they won't ever be called.\n\n\n\n\n\n"
  },
  {
    "path": "meetings/2019/LDM-2019-08-28.md",
    "content": "\n# C# Language Design Notes for Aug 28, 2019\n\n## Agenda\n\n1. Triage\n\n## Discussion\n\n### Hiding with optional parameters\n\nIf you define a method with optional parameters with the same name as a method\nin a base class, we do not provide a warning that the method is hiding the method\nin the base class, and if you put the `new` keyword, that provides a warning. Do\nwe want to provide a warning in a warning wave that the method is hiding and some\nmechanism of silencing the warning (presumably allowing `new`).\n\n**Conclusion**\n\nIf warning waves are here, we're comfortable taking this. \n\n###  `params Span<T>` and string formatting\n\nThere are a lot of important performance implications here. We think it should be\ndone soon, for the latest major release.\n\n**Conclusion**\n\nAgreed, next major release. (C# 9.0)\n\n### Allow `sizeof` in safe code\n\nThere have been requests for this over the years, but we're not sure of the\nactual value of the feature.\n\n**Conclusion**\n\nRejected, until we hear compelling use cases.\n\n### `Tail return` recursive calls\n\nWe could do \"immediate\" recursion (directly calling the containing method) without\ndepending on the runtime because we could implement it using compiler rewrites, but\nit does seem like we would want to support mutual recursion or even just tail-dispatch.\nThis would require us to either accept the limitations in the CLR where a `tail` is\nnot always done in constant space, or require a CLR feature that guarantees constant space\n\nHowever, we've done without tail calls for a quite a long time and there are some workarounds.\n\n**Conclusion**\n\nLet's talk about this later, for a C# 10.0.\n\n### Variant method overrides\n\nWe previously pushed out overrides with variance (covariant returns, contravariant parameters) due\nto requiring quadratic stubs to be emitted for the runtime. Now we can explore runtime changes to\nsupport variance directly, where the runtime would allow overrides to differ with \"compatible\"\nsignatures, instead of exact matches, which is what is required right now.\n\n**Conclusion**\n\nThere's a lot of existing use cases for this feature, and there's some feeling that it may be \nrequired for the records feature. Discussion with the runtime says that it would not be\nvery expensive, and is tractable for the next major release. We're scheduling this for C# 9.0.\n\n### Exponentiation operator (`**`)\n\nThis seems to be the major missing mathematical operator in C#. We like it as part of a broader\nimprovement to mathematical generalization that we're planning in the \"shapes\" proposals.\n\n**Conclusion**\n\nC# 10.0, matched up with shapes.\n\n### `base(T)` with runtime changes\n\nThis is a follow-up feature for C# 8.0, so we'd like to do it as quickly possible.\n\n**Conclusion**\n\nNext major release, C# 9.0.\n\n### Switching on `ReadOnlySpan<char>` with constant strings\n\nWe aren't ready to commit resources to it, since we haven't found blocking issues, but we'd\ntake the improvement whenever it's ready.\n\n**Conclusion**\n\nAny time.\n\n### Permit a fixed field to be declared inside a readonly struct\n\nWe'd like to address performance issues soon if they're impactful enough.\n\n**Conclusion**\n\nKeep it in C# 9.0, pending confirmation of performance impact.\n\n### Safe fixed-size buffers\n\nThis one has some compelling perf scenarios, but we don't have a clear design nailed down.\n\n**Conclusion**\n\nWe'd like to take in a major release, but we need a solid design first.\n\n### Comparison, `and`/`or`/`not` patterns\n\nThese seem useful and they are most useful with the `and`/`or` patterns.\n\n**Conclusion**\n\nThis doesn't seem very big and we think it could fit in any release. C# 9.0 for now. Same\nfor `and`/`or` patterns.\n\n### Dictionary Literals\n\nInitialization of collection data structures, including immutable data structures, is a\nknown issue, in both performance and ergonomics. This proposal doesn't really address\nthese problems and special cases Dictionary<K,V>, even though we know the problem also\nexists for other types.\n\n**Conclusion**\n\nThe proposal in its current form is rejected. We'd rather try to address more problems\nin a single feature, potentially after the records feature, which has proposals around\ninitialization of immutable types.\n\n### No-arg constructor/non-defaultable value types\n\nWe're not very excited about it, but there are valid use cases. We previously pulled\nthe feature because there was a runtime bug that did not call the constructor in certain\ncases. That bug has now been fixed.\n\n**Conclusion**\n\n\n### Target-typed conditional expression\n\nWe know it's useful and we have a design that we think would work.\n\n**Conclusion**\n\nWe would like to do this for C# 9.0\n\n### Surrogate pairs in Unicode-escaped code points in identifiers\n\nThe language spec already says this is allowed.\n\n**Conclusion**\n\nIf we have a viable implementation, we'll take it whenever.\n\n###  Permit conditional operation with `int?` and double operands\n\nThis is separate from target-typing because it would change the common type algorithm,\nbut it also interacts with the target-typing, so we probably need to do them together.\n\n**Conclusion**\n\nDiscuss before C# 9.0"
  },
  {
    "path": "meetings/2019/LDM-2019-09-04.md",
    "content": "\n# C# Language Design Meeting for September 4, 2019\n\n## Agenda\n\n1. `[AllowNull]` on properties\n\n## Discussion\n\n[https://github.com/dotnet/roslyn/issues/37313](https://github.com/dotnet/roslyn/issues/37313)\n\n### AllowNull and flow analysis\n\nSome questions have come up concerning `AllowNull` and property analysis, like in the following example:\n\n```C#\nclass Program\n{\n    private string _f = string.Empty;\n\n    [AllowNull]\n    public string P\n    {\n        get => _f;\n        set => _f = value ?? string.Empty;\n    }\n\n    static void Main(string[] args)\n    {\n        var p = new Program();\n        p.P = null; // No warning, as expected\n        Console.Write(p.P.Length); // unexpected warning\n    }\n}\n```\n\nThe tricky part here is that we are tracking flow state for properties, meaning if `null` is stored in a\nproperty, we treat that property as having a null state. Although there is an attribute, the flow state\nof the variable wins, meaning that we think there is a `null` inside `P`, even though the stated type\nis `string`. Similarly, if you invert the attribute and use `[NotNull]` on a `string?`, the flow state\nwill win again.\n\nThere a couple ideas to address the problem, including\n\n  1. Don't flow-track non-nullable fields/properties.\n  2. Have `[AllowNull]` suppress both the warning, and suppress setting the flow state to `null`\n  3. Have the `[NotNull]` attribute suppress the flow state (which it currently doesn't), and require\n     the property be written with a nullable type (`string?`) and have `[NotNull]` on the getter.\n  4. Stop tracking when any nullability attributes are present on properties.\n\n\n2 and 3 are somewhat related and we could do both, in theory. The main problem is that it greatly\ncomplicates the user's understanding of when flow tracking is enabled, and there are also potentially\ndownstream affects for type inference if we allow the rule for (2) to apply to parameters.\n\nFor (1) it seems plausible, since we would still have a warning on assigning a null to a non-nullable\nmember. This would remove the flow-based subsequent warnings, but the user would still be warned at\nthe point where the problem happens. However, it doesn't seem to solve the problem for generics, e.g.\n\n```C#\nclass C<T> where T : new()\n{\n    private T _f = new T();\n\n    [AllowNull]\n    public T P\n    {\n        get => _f ?? throw new Exception();\n        set\n        {\n            if (value is null)\n            {\n                throw new Exception();\n            }\n            return _f;\n        }\n    }\n}\n```\n\nHere the generic property `P` cannot be marked nullable because it is unconstrained.\n\nHowever, 2 & 3 also have a problem around `MaybeNull`. If a property is annotated `MaybeNull`, then\nthe attribute would override the state, meaning that a null check is useless. If you check for null\nit would not matter, because when you read the property again, the attribute would override the state\nand the result would still be maybe null.\n\nAn idea to address this is a combination of (4) and (3), where we have special attribute behavior\nfor properties, and in that case `NotNull` has precedence over nullable state, but nullable state\nhas precedence over `MaybeNull`. In addition, `AllowNull` modifies the state transition to use\nthe declared state if the input is null, while it otherwise uses the non-null state.\n\n**Conclusion**\n\nThe proposal starting point is:\n\nNotNull wins over tracked state, which wins over MaybeNull.\nAllowNull transforms an incoming maybe null state to the declared state.\n\nThere's an action item to go investigate how this will play into the rest nullability, and an open\nquestion of whether to treat fields like properties, or like local variables."
  },
  {
    "path": "meetings/2019/LDM-2019-09-11.md",
    "content": "\n# C# Language Design Meeting for Sep. 11, 2019\n\n## Agenda\n\n## Discussion\n\n### Nullable attributes and flow state interaction\n\nWe started this discussion with an email with a proposal based on follow-up research from the\nprevious meeting.\n\n### Attribute interaction proposal\n\n> Allowed inputs and outputs:\n> \n> First of all, I’ll try to make rules based only on “allowed inputs” and “allowed outputs” of a\n> property. I’ll use shorthands ?, ! and T for “nullable”, “nonnullable” and “unknown – depends on\n> T” respectively.\n> \n> For all the different sensible combinations of attributes, here are the “allowed inputs” and “allowed outputs”:\n\t\n\n> |                            | Allowed input | Allowed output |\n> |----------------------------|---------------|----------------|\n> | string                     | !             | !              |\n> | [AllowNull]string          | ?             | !              |\n> | [NotNull]string?           | ?             | !              |\n> | [MaybeNull]string          | !             | ?              |\n> | [DisallowNull]string?      | !             | ?              |\n> | string?                    | ?             | ?              |\n> | [DisallowNull][NotNull]T   | !             | !              |\n> | [NotNull]T                 | T             | !              |\n> | [AllowNull][NotNull]T      | ?             | !              |\n> | [DisallowNull]T            | !             | T              |\n> | T                          | T             | T              |\n> | [AllowNull]T               | ?             | T              |\n> | [DisallowNull][MaybeNull]T | !             | ?              |\n> | [MaybeNull]T               | T             | ?              |\n> | [AllowNull][MaybeNull]T    | ?             | ?              |\n\n> There should be no surprises to anyone there. Now let’s use these to define the different behaviors around properties:\n> Ordering of states:  T is stricter than ? and ! is stricter than both T and ?.\n> This is a measure of relative permissiveness of states.\n\n> Initial state: The initial state of a property is its allowed output.\n> This corresponds to us knowing nothing about the property yet, beyond what it tells us through a combination of its type and its postconditions.\n\n> State after null check:\n> \n> - On the non-null branch of a null check the state of the property is !.\n> - On the null branch of a pure null check the state of the property is ?.\n> - Elsewhere the state of the property is unchanged.\n> \n> These rules reflect the general benefit of a null check, as well as the overriding effect of a pure null check even of a nonnull property.\n\nNote that this rules out \"dangerous\" properties, meaning properties that may change outside the\nscope of the nullable analysis, as in fields which may be changed by a different thread, and thus\nthe null check is unreliable. We don't consider this scenario to be in scope of our current\ndesign and if we decide to address this, we must create a new attribute or some other mechanism.\n \nThere's also some problem with the state after null checks, namely that the type may not support\nthe `?` state. For instance, in the following unconstrained generic,\n\n```C# \nT M<T>(T t)\n{\n    if (t != null)\n        t.ToString();\n    return t;\n}\n```\n\nwe should not produce a warning on the return, since the state should match the legal state of\n`T`, which is `T`, not `?`. Similarly, for non-Nullable value types, the state cannot be `?`\nafter a null check, since the value cannot be null. The rule should use the `T` state.\n\n> State after assignment:\n> \n> The state of the property after an assignment is\n> \n>  - Its initial state if the state of the assigned value is at least as strict as the allowed input, but no stricter than the allowed output\n>  - The state of the assigned value otherwise\n> \n> This rule reflects that a property is expected to “take care of things” when the state of an assigned value is valid as input but not as output. It does so by assuming that the resulting state in such situations is something that’s valid as output.\n> \n> This is probably the only rule that would differ from the rules for fields, which would continue to always use the state of the assigned value.\n\n> Warnings on assignment: A warning is yielded if the state of the assigned value is less strict than the allowed input.\n> This is the same rule as all other input positions.\n\n\nWe like this new \"state after assignment\" rule and think it can be implemented now.\n\nHowever, when looking into the solution, we found that this is the current behavior for properties when annotated:\n\n```C#\nusing System;\nusing System.Diagnostics.CodeAnalysis;\n\n#nullable enable\n\nclass C<T> where T : class?\n{\n    public C(T x) => f = x;\n    T f;\n                T P1 { get => f;        set => f = value; }\n    [AllowNull] T P2 { get => f;        set => f = value ?? throw new ArgumentNullException(); }\n    [MaybeNull] T P3 { get => default!; set => f = value; }\n\n    void M()\n    {\n        P1 = null; // Warning\n        P2 = null; // No warning\n        P3 = null; // Warning\n\n        f = P1;    // No warning\n        f = P2;    // No warning\n        f = P3;    // BUG?: No warning!\n    }\n}\n```\n\nThat last line does not look right. Similar to `default(T)`, you could be producing a\npotentially nullable value, when the substituted type may not permit it. We think\nthe three state domain outlined above will solve the problem, but that would\nbe too extensive to change to perform in such a short period of time.\n\nAlternative: whenever you introduce a value (by calling\na property or a method), that produces a generic type annotated with `[MaybeNull]`\nin a substituted generic method, that would produce a warning. This\nmatches our current behavior for `default(T)`.\n\nFor example,\n\n```C#\nT M<T>()\n{\n    _ = (new List<T>).FirstOrDefault(); // this would now produce a warning\n}\n```\n\n**Conclusion**\n\nLet's implement the \"state after assignment\" rule as defined and implement the\n\"Alternative\" proposal outlined above. We will consider updating to use the\n\"three state domain\" above later, which may have some further changes. A sample\nof the expected behavior follows:\n\nNon-Generic\n\n```C#\n\nusing System;\nusing System.Diagnostics.CodeAnalysis;\n\nclass Widget {\n    string _description = string.Empty;\n\n    [AllowNull]\n    string Description {\n        get => _description;\n        set => _description = value ?? string.Empty;\n    }\n\n    static void Test(Widget w) {\n        w.Description = null; // ok\n        Console.WriteLine(w.Description.ToUpper()); // ok\n\n        if (w.Description == null) {\n            Console.WriteLine(w.Description.ToUpper()); // warning\n        }\n    }\n}\n```\n\nGeneric\n\n```C#\nusing System;\nusing System.Diagnostics.CodeAnalysis;\n\nclass Box<T> {\n    T _value;\n\n    [AllowNull]\n    T Value {\n        get => _value;\n        set {\n            if (value != null) {\n                _value = value;\n            }\n        }\n    }\n    \n    static void TestConstrained<U>(Box<U> box) where U : class {\n        box.Value = null; // ok\n        Console.WriteLine(box.Value.ToString()); // ok\n\n        if (box.Value == null) {\n            Console.WriteLine(box.Value.ToString()); // warning\n        }\n    }\n\n    static void TestUnconstrained<U>(Box<U> box, U value) {\n        box.Value = default(U); // 'default(U)' always produces a warning when U could be a non-nullable reference type\n        Console.WriteLine(box.Value.ToString()); // ok\n\n        box.Value = value; // ok\n        Console.WriteLine(box.Value.ToString()); // ok\n\n        if (box.Value == null) {\n            Console.WriteLine(box.Value.ToString()); // warning\n        }\n    }\n}\n```\n\n\n\n## More triage\n\n### Top-level statements and member declarations\n\nWe have a variety of different use cases and experimental products (C# Interactive Window,\nJupyter projects, try.net, etc) that use the current \"C# scripting\" language, which is already\neffectively a dialect of C#. There's a fair amount of concern that if adoption continues, we may produce a fracturing of the C# language.\n\nHowever, adding top-level statements and reconciling scripting in C# proper would be an expensive\nfeature, in both design and implementation. It also doesn't directly impact many of the designs\nwe're currently considering.\n\nBut there is also significant cost to doing nothing. We have not considered the semantic for many\nfeatures in C# 8, or even if they should work in scripting (`using` declarations, notably). There\nis a significant ongoing cost here, either in considering all our designs for the scripting\ndialect, or in risk that not doing design/implementation work will cause bad experiences for\nproducts using the C# scripting code.\n\n**Conclusion**\n\nWe'll schedule this for 9.0, to at least examine options.\n\n### Primary constructors\n\nThis occupies the same design space as records, which is scheduled for 9.0, so\nwe at least need to consider this feature while implementing records.\n\n**Conclusion**\n\nMoving to 9.0.\n\n### Negated-condition if statement\n\nIssue #882\n\nThis overlaps significantly with a \"is not\" pattern. We're not confident this\nfeature has significant value, after the \"is not\" pattern is implemented.\n\n**Conclusion**\n\nMove to X.X to consider after \"is not\" has shipped and see if there are significant\nuse cases that are not addressed by the \"is not\" pattern.\n\n### Allow `default` in deconstruction\n\nIssue #1394\n\nThe primary use case is `(x, y, z) = default;` instead of naming each variable\nindividually. There are some issues around the written specification, specifically\non what target typing `default` has.\n\n**Conclusion**\n\nFrom a consistency perspective it seems like this should work, regardless of the\ncomplexity in details of the specification. We'll take this Any Time whenever we have a solid\nspecification and implementation.\n\n### Partial type inference\n\nIssue #1349\n\nNothing that's related to type inference is a tiny feature, but this is pretty\nsmall as type inference changes are concerned. We think the hardest problem will\nbe agreeing on the syntax. Agreed that it could be useful, though.\n\n**Conclusion**\n\nWe'll take this Any Time.\n\n### Declaration expressions\n\nIssue #973\n\nSomewhat related is \"sequence expressions\". This is useful for declaring variables inline in an\nexpression. There are places where statements are not possible, and this requires\nrefactoring.\n\n**Conclusion**\n\nWe don't think there's value in half measures here. We think going all the way to sequence\nexpressions may have value, but then declaration expressions do not.\n"
  },
  {
    "path": "meetings/2019/LDM-2019-09-16.md",
    "content": "\n# C# Language Design Meeting for September 16, 2019\n\n## Agenda\n\n1. UTF-8 strings (https://github.com/dotnet/corefxlab/issues/2350)\n2. Triage\n\n## Discussion\n\n### UTF-8 Strings\n\nMotivation: UTF-8 is everywhere, and converting to and from the .NET native string type (UCS2/UTF-16),\ncan be expensive and confusing.\n\n#### Language impact\n\n**Literals**\n\nCurrent proposal is to emit the data as UTF-16, and use a runtime helper to project to UTF-8. The\nmain question for the language is if this encoding limits the usability in some way, and whether\nit blocks us off from introducing an optimal strategy later. There are two things to consider: the\ncost in the compiler, and the cost to the language. At the moment we don't see anything that would\nbe considered a breaking change in the language.\n\n**Enumeration**\n\nThe proposal doesn't include any default enumeration. It's worth considering if this violates C#\nuser expectations. There are different forms of enumeration available by calling properties, but\nnone of them are the default. Should there be a default?\n\nOne problem is that users who see enumeration may expect indexing, which is not cheap, and does\nnot match expectations. Another problem is that there is almost always a better operation than\nenumerating a UTF-8 string. It seems like adding this more likely to encourage a user to write a\nbug, or inefficient code, than to help them.\n\n**Why language support**\n\nThe main advantages of language support are:\n\n* O(n) string concatenation (calling utf8string.Concat with all `n` arguments)\n* String literals\n\n**Target-typing**\n\nTarget-typing of existing string literals is possible but produces \"bad\" behavior for seemingly\nthe most common scenario:\n\n```C#\nvoid M(string s) { ... }\nvoid M(Utf8String s) { ... }\n\nM(\"some string\"); // This would call the `string` version, because backwards compatibility requires\n                  // \"\" always be a `string` first, and a `Utf8String` second\n```\n\n**Syntax**\n\nAs always, there's debate about the syntax. The \"u\" prefix is somewhat unsatisfying because UTF-8,\nUTF-16, UCS-2, *and* `unsigned` all begin with \"u\". The same complaints hold for the proposed\n`ustring` contextual keyword. However, there are no enthusiastically favored alternatives.\n\nIn addition, the value of the `ustring` contextual keyword seems questionable. If the brevity is\nimportant, then it seems important enough that the framework could call it `ustring` or `utf8`.\nOne argument is that Utf8String could be a new \"primitive\" type, and we should add a keyword for\nall primitive types. However, this is not proposed as a primitive type at the same level, so that\nweakens support. In addition, the original aliases were all added at the inception of the language,\nso we have no precedence for adding either primitive types or aliases.\n\n**Conclusion**\n\nWe think the feature is valuable and probably worth some language support. We think a literal syntax\n(like the \"u\" prefix) is good, but we don't like target typing. We're also not convinced of the need\nfor a contextual keyword.\n\n### More triage\n\n#### Null parameter checking\n\nIssue #2145\n\nASAP, 9.0\n\n### CallerArgumentExpression\n\nIssue #287\n\nWe could potentially use this to implement \"Null parameter checking\" as a method call, instead of\nnew syntax. Thus, consider for 9.0.\n\n### Relax ordering constraints about modifiers (especially `ref` and `partial`)\n\nIssue #946\n\n9.0\n\n### Zero- and one-element tuples\n\nIssue #883\n\nIn terms of language value, zero- and one-element tuples are different features. Zero-element\ntuples are most useful as a unit type, which is not necessarily the unit type we would choose\nto standardize on (e.g. against System.Void), while one-element tuples are simply useful as a\nwrapper type and don't have an obvious competitor.\n\nWe need to revisit the decisions here. Moving to X.X\n\n### Mix declarations and variable in deconstruction\n\nIssue #125\n\nNot an urgent feature, but useful for completeness. On the other hand, it's always very clear\nwhether or not the deconstruction is using existing variables, or creating new ones.\n\nAny time\n\n### Discard for lambda parameters\n\nIssue #111\n\nAny time"
  },
  {
    "path": "meetings/2019/LDM-2019-09-18.md",
    "content": "\n# C# Language Design Meeting for September 18th, 2019\n\n## Agenda\n\nTriage:\n\n1. Proposals with complete designs:\n\n    - https://github.com/dotnet/csharplang/issues/1888 Champion \"Permit attributes on local functions\"\n    - https://github.com/dotnet/csharplang/issues/100 Champion \"Target-typed new expression\"\n\n2. Target typing and best-common-type features: \n\n    - https://github.com/dotnet/csharplang/issues/2473 Proposal: Target typed null coalescing (??) expression\n    - https://github.com/dotnet/csharplang/issues/2460 Champion: target-typed conditional expression\n    - https://github.com/dotnet/csharplang/issues/881 Permit ternary operation with int? and double operands\n    - https://github.com/dotnet/csharplang/issues/33 Champion \"Nullable-enhanced common type\"\n\n## Discussion\n\n### Attributes on local functions\n\nIssue #1888\n\nThe only major concern about the feature is whether or not the attributes are guaranteed to be emitted to\nthe lowered method, assuming there is a lowered method. For all current lowering strategies, there is a\nspecific place to put the attributes. The proposal is that we always emit attributes for our current\nscenarios, but don't guarantee in the language that all attributes will survive rewriting.\n\nThere is one exception to the above, which is static local functions. Static local functions are specified\nto always emit a static method with the same signature as the local function (although there are bugs about\nthis today). Attributes on static local function would have a similar guarantee, meaning that they are always\nemitted to the lowered methods, on the exact same parameters they were applied to.\n\n**Conclusion**\n\nProposal accepted, attributes will be allowed on local functions. `extern` will also be allowed on\nstatic local functions, and will be a valid P/Invoke target.\n\n### Target-typed new\n\nIssue #100\n\nWe like the feature and already have a design. However, we want to do a quick review that we still like the\ndesign, taking into account all the changes we've made to the language since it was proposed.\n\n**Conclusion**\n\nAccepted, pending review.\n\n### Target-typed conditional expression and nullable-enhanced common type\n\nIssue #2460 and issue #33\n\nThe main problem is that providing a target-typing for the switch expression\nmay have made issue #33 a breaking change. In general, additional target-typing\n(on top of a natural type) works by calculating the target type if there is no\nviable natural type. By allowing more natural types, it reduces the ability to\nuse target-typing, which may allow more resulting types than the natural type\ninference.\n\nOverload resolution is a good example. If you have two methods\n\n```C#\nvoid M(int? x) { ... }\nvoid M(short? y) { ... }\n```\n\nand a call `M(e switch { ... => 1, ... => null })`, when we do overload resolution\nwe consider the target type for the `switch`, which consists of the target type\nfor each of the candidates. For target type, `short` is a better target for `int`.\nIf we improved the natural type, then the natural type of `1` would be `int`. Then,\nif we improve the natural type of `e switch { ... => 1, ... => null}` to be `int?`,\nthen a different overload (`M(int? x)`) will be chosen.\n\nThere's also a pretty clear trade-off here. Target-typing may allow more viable\ntypes, but it falls over in the presence of type inference or if the target is\nso broad as to be useless (like if the target-type is `object`).\n\nAdditionally, the proposal for target-typing the conditional expression (`?:`) will have\ndifferent semantics from the target-typing for the switch expression, to avoid a breaking change.\nIt may be desirable to unify the behavior of things like `?:` and switch expression, even if that\nmeans that the switch expression would be more limited, due to the backwards compatibility\nconstraints of `?:`.\n\n**Conclusion**\n\nLet's do some work to see if we can alter the interaction of target-typing and common type\ninference to add the proposed new common types without introducing breaking changes with\ntarget-typing. The hope is that such a rule could be general enough to apply to other potential\nbreaks in the future (in case we find more potential improvements to common type).\n\nIn addition, we would like to know the effect of changing switch expressions to prefer the common\ntype, if one exists. We hope that any difference would be uncommon in practice, but it would be\nuseful to know if there are common instances where this would break. This would be used to decide\nif we would adjust the behavior of the switch expression to match the proposed behavior for the\nconditional expression.\n"
  },
  {
    "path": "meetings/2019/LDM-2019-10-21.md",
    "content": "\n# C# Language Design Meeting for Oct. 21\n\n## Agenda\n\n1. Records\n2. Init-only members\n3. Static lambdas\n\n## Discussion\n\nWe'd like to make some progress on records, in both design and implementation. One development in\nour view of records is to consider them not as a feature in and of itself, but a shorthand for a\nset of features aimed at working with a collection of data. Specifically, we have a proposal to\nconsider a guiding principle: a record should only be capable of generating code that the user\ncould write themselves.\n\nTo that end, we can look at the set of features we're considering incorporating into records, and\ndifferentiate between them based on the uncertainty of their design. The features which may have\ngenerated behavior are:\n\n1. Automatic structural equality\n\n2. With-ers (per type?)\n\n3. Object initializers for readonly (per member)\n\n4. Primary constructors + deconstruction\n\nSome features, like with-ers and object initializers, have many open issues. Some\nfeatures, like generation of structural equality, have widely agreed upon semantics,\nonce the set of members that are part of the structure are decided.\n\nIt's proposed that we take a subset of the features, namely primary constructors and structural equality, and consider them to have designs ready for implementation. Primary constructors still have open semantic questions, especially around their meaning outside of a records, but all of the proposed records specify some type of primary constructor with very similar semantics. An example of the common semantics would be the following,\n\n```C#\ndata class Person(string Name, DateTime Birthday);\n```\n\nwhich would generate two record members, `Name` and `Birthday`, structural equality on those two\nmembers, and a corresponding constructor/deconstructor pair. The `data` modifier, as well as the\nprimary constructor, are not necessarily final syntax, but the semantic decisions downstream of\nthis stand-in don't heavily depend on the specific form of syntax chosen and could be easily\nchanged.\n\n**Conclusion**\n\nThis looks like a reasonable starting point. Records and the components should\ndefinitely be designed together, to ensure they fit together well, but it's worth\nhighlighting the more settled pieces as we go.\n\n#### Init-only\n\nA brief discussion of the init-only fields feature. One clarification: the \ninit-only properties would be allowed to have setters. Those setters can be\nexecuted in the object initializer, or in the constructor of the object. There\nis a proposal to allow them also to be set in the constructors of base types,\nwhich has no opposition at the moment.\n\nThere's also a problem with \"required\" init-only members as currently proposed.\nThe current design specifies that \"required\" init-only members (members without\nan initializer) would produce an error on the construction side if the member\nis not initialized in an object initializer.\n\nFor example,\n\n```C#\nclass Person\n{\n    public initonly string Name { get; }\n}\n\nvoid M()\n{\n    var person1 = new Person() { Name = \"person1\" }; // OK\n    var person2 = new Person(); // Error, Name was not initialized\n}\n```\n\nUnfortunately, the proposed emit strategy for `initonly` members would only provide\nan error in source, not in metadata. If a consumer compiled against a previous\nimplementation of a type, and a required `initonly` member was added, no error would\nbe provided if the consumer were not recompiled. Instead, the member would silently\nbe set to the default value.\n\nA simple alternative is to drop \"required\" `initonly` members entirely. Setting an initonly\nmember would be optional, as it is for public readonly members today, and if it is not set it\nwould retain its default value. The recommendation for adding required members would be the same\nas it is today: use a constructor parameter, which cannot be skipped.\n\nWe could also attempt to repair the situation by lowering the required `initonly`\nmembers into constructor parameters, but this seems undesirable for many reasons,\nincluding that it's complex to implement, it risks creating collisions with\nconstructor overloads with the same type, it creates a mismatch in the number of\nparameters between source and IL, etc. It does not seem worth going down this path.\n\n\n### Static lambdas\n\nStatic lambdas were elided mostly for time reasons and we're interested in bringing\nthem back. The main hang-up on the syntax is adding modifiers before the lambda\nsyntax, but we already crossed that bridge with `async`.\n\nThe only semantics question is whether or not a static lambda guarantees that the\nemitted method will be static in metadata. This is true for static local functions,\nbut there are some important scenarios, like `extern` local functions, which depend\non that and could not be implemented for lambdas. In addition, there have been\nnumerous performance improvements in lambdas and local functions that have taken\nadvantage of their unspecified metadata characteristics, and at least one significant\nperformance optimization for lambdas would be lost by requiring them to be static.\n\n\n**Conclusion**\n\nThe `static` keyword will be allowed on lambdas and it will have the same capturing rules as\nstatic local functions. It will not require that the lambda be emitted as static.\n"
  },
  {
    "path": "meetings/2019/LDM-2019-10-23.md",
    "content": "\n# C# Language Design Meeting for Oct. 23, 2019\n\n## Agenda\n\n1. New primitive types (`nint` and `nuint`)\n\n## Discussion\n\n### Native int\n\nProposal: https://github.com/dotnet/csharplang/issues/435 \n\n#### Static members\n\nThe current spec states that `nint` and `nuint` are reserved keywords in a type context but there\nare contexts, like qualified names, that allow types but are not type contexts. Since `nint` and\n`nuint` have static members, we want users to be able to access them, so they should be allowed\nin qualified names.\n\n#### IntPtr members\n\nA follow-up question is what to do about existing members on the underlying IntPtr\ntype. There are some members, like Add and Subtract, which may be misleading because\nthey are not equivalent to `+` and `-` due to over/underflow checking.\n\nThere are two views here. On the one hand, the proposal to use IntPtr means that\nsome implementation details for IntPtr will inevitably leak through. Since users\nwill sometimes want to use an IntPtr as an `nuint` to do pointer arithmetic, any\nmethods on IntPtr may be useful and this would just be making barriers.\n\nOn the other hand, `nint` is being added as a type for conceptually different reasons. It\nshouldn't be assumed that everything that applies to IntPtr should be applicable to `nint`.\nThere's a follow-up question as whether we would exclude everything on IntPtr except for an\ninclude list, or include everything except for an exclude list. These may seem very different,\nbut after more thought it's likely they're very similar. Since the framework would probably very\nrarely add new members to IntPtr after the language change (like with System.Int32), what we pick\nnow is probably what will be present for a very long time, and anything new would probably be\ndone with consultation from the language team.\n\nOur tentative conclusion is that we should exclude some members. The following\nare questionable:\n\n* Zero (use the `0` literal)\n* Size (use sizeof)\n* Add, Subtract (part of the point of this type is to use \"proper\" C# arithmetic)\n* ToInt32, ToInt64, ToPointer (use the language-defined conversions)\n\n#### Signed bitwise operations\n\nUnfortunately, IntPtr is \"signed\" but is often used to represent pointers, which are unsigned\naccording to framework guidelines. In the current design, IntPtr has an identity conversion to\n`nint`, which could cause the unfortunate scenario\n\n```C#\nIntPtr M(IntPtr p)\n{\n    nint x = p;\n    x >> 1;\n    return x;\n}\n```\n\nThis would use signed `>>`, which is probably incorrect if the value is assumed to be an unsigned\npointer. This is not currently a problem with IntPtr because IntPtr does not define any bitwise\noperators.\n\nUnfortunately, keeping an identity conversion is an important part of compatibility. We would\nlike to support users who are currently using IntPtr, but would like to use `nint`, to go from\n`IntPtr[]` to `nint[]`. Without an identity conversion, we don't see how this would be possible\nin the language today.\n\nAdding an entirely new concept in the language to support this without identity conversions is\nprobably not worth it. Unless we can find a simple improvement to the design, we will probably\nhave to accept this behavior.\n\n#### Overriding, hiding, and implementation (OHI)\n\nSince IntPtr and nint are the same CLR underlying type, they will be regarded as having the same\nsignature. The compiler is able to see the difference. Should we regard them as identical for the\npurposes of OHI? This is similar to scenarios like tuple names, which are represented as\nattributes and thus not visible as part of the CLR type. However, in OHI we provide an error if\ntuple names change in an override because this could be the source of a bug (e.g., if the names\nwere accidentally swapped). In this case we think IntPtr and `nint` are similar enough that we\nshould regard the OHI behavior similar to `dynamic`/`object`, where it is allowed.\n\nFor use as an enum underlying type, we think `nint`/`nuint` should be allowed as long as it's not\ntoo much implementation work. The legal values would be the same as the valid constants for the\nunderlying.\n\nFor sizeof, we think it should be supported in unsafe code, just like `sizeof(IntPtr)`, but with\nno special behavior in safe code.\n"
  },
  {
    "path": "meetings/2019/LDM-2019-10-28.md",
    "content": "\n# C# Language Design Notes for Oct. 28, 2019\n\n## Agenda\n\n1. Discard parameters in lambdas and other methods\n1. Enhancing the common type algorithm\n\n## Discussion\n\n### Discard parameters\n\nWe wanted to talk about discard parameters in lambdas, and also potential expansions into other\nparameter lists like in local functions and regular methods.\n\nThe first hurdle is whether any form of this feature is worth the complexity. The simplest case\nis lambdas, because the parameter names are not visible to the caller so they are only visible to\nthe implementation. The alternative to discards is to give throw-away names, like\n`_1`, `_2`, and `_3`, or to use anonymous method syntax (`delegate { }`) to ignore\nall parameters.\n\nAs for value, this is a fairly commonly requested requested feature ever since we introduced\ndiscards. The cost is increased complexity in the language (understanding that discards are legal\nas lambda parameters), but there's also an argument that not having the feature causes more\ncomplexity in the language. Specifically, the anonymous method syntax is almost entirely obsolete\ncompared to the lambda syntax, but is still commonly used in this exact scenario. If usage of\nthis feature decreases the usage of anonymous method syntax, that could be a decrease in required\nunderstanding of the language.\n\nFor discards in local functions and method parameter lists, the cost/value ratio is not nearly as\nclear. The fundamental limitation is that parameter names for methods and local functions are\nalways public surface area to the caller. We find the cost in complexity in resolving these\nquestions higher than the feature is currently worth. If we find that it becomes a highly desired\nfeature later, we would reconsider this decision.\n\nLastly, we had a question of how the scoping would work regarding `_` in both\nthe enclosing scope and inner scope of lambdas.\n\n```C#\nvoid M()\n{\n    int _ = 0;\n    Action<int, int> a = (_, _) =>\n    {\n        _ = 1; // Is this a discard, or does it capture the local above?\n    };\n}\n```\n\nWe considered various options, like making `_` always be a discard in a lambda body when the\nlambda parameters are discards, but we have a different precedent for non-lambda\nscopes like the following:\n\n```C#\nvoid M()\n{\n    int _ = 0;\n    {\n        _ = 1; // This assigns to the variable _\n    }\n}\n```\n\nWe decided a better alternative to making complex scoping rules to prevent confusing code is to\npush for a warning wave to make using `_` as an identifier a warning. Essentially, if the\nabove behavior is confusing, the confusing aspects are best resolved by always using `_` as a\ndiscard, rather than special language rules.\n\nThe scoping behavior is confirmed that multiple `_`s in a lambda parameter list are discards.\nThere are no other modifications to variable scopes i.e., they are not introduced in the lambda\nbody scope, but they also hide nothing from the enclosing scope).\n\n### Common Type Specification\n\nProposal: https://github.com/dotnet/csharplang/issues/2823\n\nThis is revisiting a previous design question around whether to improve the common type\nspecification and also to target type various expressions. In the last discussion we wanted more\ninvestigation on the impacts of adding target-typing and the consequences to improving the common\ntype algorithm in the future.\n\nAfter investigation, there's a proposal to resolve questions about changing common type inference\nby looking back to an earlier rule: never infer a type that was not one of the input types. This\nis a rule that mainly comes from where to draw the line on complexity of type inference.\n\nThis is a simple rule, but it's arguable that there are certain enhancements that don't open up\nto question the entire space of inference, but still satisfy simple requests, like assuming that\nnull and simple integer types can be inferred as nullable. This would be similar to the language\nspecification for nullable lifting operations on binary operators.\n\nHowever, that still leaves the fundamental problem we approached in the beginning: improving\ninference is a breaking change after target-typing is introduced. The proposal introduced is to\nnot improve type inference in the future and consider this an acceptable outcome, given that\ntarget typing would satisfactorily resolve most of the examples given, and potentially in a\nclearer way than improving the common type algorithm. This would also have the property of\npreserving the original constraint of the common type algorithm, where no type is inferred that\nisn't present in any of the inputs.\n\nThe biggest drawback here is that the switch expression and conditional expression would behave\ndifferently. The conditional expression would have to preserve the common type algorithm for all\nplaces it succeeds, for backwards compatibility.\n\nOne possible way out of this is to separate the notion of common type for backwards\ncompatibility, namely in overload resolution, and the inferred type, as the type used for `var`,\nwhere no target type is available. If feasible, this would resolve the issue mentioned at the\nprevious meeting, where we would be unable to improve type inference without creating breaking\nchanges in overload resolution.\n\n**Conclusion**\n\nOverall, we're in favor of adding target-typing for these expression forms. We should consider if\nthere's anything more we would like to do to make the switch and conditional expressions more\nsimilar."
  },
  {
    "path": "meetings/2019/LDM-2019-10-30.md",
    "content": "\n# C# Language Design Meeting Notes for Oct. 30, 2019\n\n## Agenda\n\n1. Function pointer syntax\n2. Enhancing Common Type Algorithm (again)\n\n## Discussion\n\n### Function pointer syntax\n\nProposal: https://github.com/dotnet/csharplang/issues/2917\n\nWhile exploring syntax for function pointers, it turns out that parsing\nthe previously proposed syntax, namely\n\n```C#\nfunc*(int, int)\n```\n\ncan feature exponential parsing behavior in the case of nested function\npointers.\n\nAn alternative is proposed using a generic-style syntax. E.g.,\n\n```C#\nfunc*<void>\ncdecl*<int, void>\n```\n\nThe proposed changes employ `*<` as being unambiguous in the language today. One suggestion is to\nuse the same trick, but with a minor modification: `func` would always be the first token, and\nthe calling convention would be the second token e.g.,\n\n```C#\nfunc cdecl*<int, void>\n```\n\nand the set of calling conventions would evolve as the set of CLR-supported\ncalling conventions evolve.\n\nThere are a couple features which aren't mentioned, and we're not sure if we\nneed to support them, and how we would do so.\n\nMainly, we don't know whether certain features, like attributes, require definitions of named\nfunction pointers, instead of anonymous function pointer types. The runtime has proposed using\nattributes to express configuration, like suppressing native/managed transition.\n\nThe current syntax doesn't have a place to put attributes, so if we wanted to support that\ndesign, we would have to have some definition to place attributes. This would be similar to\ndelegate definitions, where you can define a delegate with a name and attributes, and then refer\nto the delegate type by name.\n\nHowever, the current runtime implementation doesn't support declaring tokens for the function\npointer, so there's no official mechanism to attach attributes to a function pointer. A follow-up\nquestion is to ensure that the spec allows us to put the calling convention in the signature\nduring emit as part of the function pointer type.\n\nWe brainstormed a bunch of possible syntaxes (some more serious than others):\n\n```C#\ndelegate managed *int(int, long)\n\ndelegate managed *List<T>(int, long)\n\ndelegate * List<T> managed(int, long)\n\ndelegate<managed> * List<T>(int, long)\n\ndelegate * managed List<T>(int, long)\n\ndelegate managed int *(int, long)\n\ndelegate managed*<int, long, void>\n\ndelegate *<int, long, void>\n\ndelegate* managed<int, long, void>\ndelegate*<int, long, void>\n```\n\n**Conclusion**\n\nThe new syntax is agreed to be unambiguous, as far as we can see. We agree on three\nmodifications:\n\n    1. The optional calling convention should always have a prefix.\n    2. Putting the `*` near the prefix is better, as it makes the function pointer\n       more recognizable.\n    3. `delegate` is a better prefix, as it is already a keyword.\n\nOur final decision is\n\n```C#\n'delegate*' optional_calling_convention '<' type < type , ... > , return_type '>'\n```\n\n### Enhancing Common Type Specification follow-up\n\nProposal: https://github.com/dotnet/csharplang/issues/2823 \n\nThe previous proposal was to add target-typing as a fallback to existing features,\nlike the conditional expression, and do no more work on enhancing the common type\nalgorithm.\n\nThis would solve certain problems and not others. In the case where the conditional expression\nhas a common type, but that type is not the one you want (e.g., `b ? 1 : 2`, but you wanted the\nresult to be a `byte`), target typing would not solve this.\n\nAt the same time, not having all possible improvements doesn't seem to impact the\ndecision for nullable, specifically. We already have special language knowledge\nand handling of nullable and when language algorithms fail to introspect and find\nthe \"obvious\" solution, this feels worse than more general failures.\n\n**Conclusion**\n\nNone today. We ran out of time and would like to talk about it more.\n"
  },
  {
    "path": "meetings/2019/LDM-2019-11-11.md",
    "content": "\n# C# Language Design Meeting for Nov. 11, 2019\n\n## Agenda\n\n1. Confirm removal of warning calling a method that returns `[MaybeNull]T`\n2. Allow interpolated string constant\n3. Enhancing the Common Type Specification\n4. Type pattern\n5. Simple name binding with target types\n\n## Discussion\n\n### Calling a method that returns `[MaybeNull]T`\n\nWe previously proposed this as a safety warning, since the value of `T` could be nullable,\nsimilar to `default(T)`. The approach of warning on all uses turns out to be more annoying than\nwe thought, producing multiple false positives.\n\nThere are a couple steps to improving it. First, we'd like to not warn if the expression is\nreturned in a method that is also annotated to return `[MaybeNullT]`. This would require us to\nuse the information from the nullable attributes (or at least `[MaybeNull]`) inside the method.\nWe also have to implement a three flow state design for nullable analysis, since it's not good\nenough to know whether the flow state is maybe null or not null (since all unconstrained generics\nare already considered maybe null), we need to know if the state is maybe null, even if the\nsubstituted generic does not allow null.\n\n**Conclusion**\n\nConfirmed that the warning can be removed. This will make it likely that we will produce more\nwarnings in the case that all of these component parts are working, but we're hoping that almost\nall of these warnings will be real safety issues, not false positives.\n\n### Interpolated string constant\n\nhttps://github.com/dotnet/csharplang/issues/2951\n\nThe simplest form of this proposal is to just allow constant strings with `$` in front of them.\nFor example,\n\n```C#\nconst string s = $\"abc\";\n```\n\nThis doesn't really seem very useful, except in refactoring where you had an interpolated string,\nand made it constant, and it happened to not have any substitution.\n\nA more useful version would allow constant interpolated strings if all of the substitutions are\nconstant strings.\n\n**Conclusion**\n\nSeems reasonable. We'll put it in \"any time\". @agocke to champion.\n\n### Enhancing the Common Type Specification (again)\n\nhttps://github.com/dotnet/csharplang/issues/2823\n\nWe discussed a number of improvements, notably using target-typing as a fallback when there is no\ncommon type. The idea to improve target-typing for nullable seems interesting, but we need a more\ndetailed proposal to examine. There's a worry that this will significantly complicate type\ninference, which needs investigation.\n\nThere are a few associated questions, namely:\n\n1. Do we improve the common type algorithm to not find a common type if all the component\ntypes cannot be converted to it? (e.g., `1` and `null` would have no common type)\n\n2. Do we allow improve common type inference for the cases where there is no target type (e.g.,\nwhen assigned to `var` or a method that takes a generic `T`)\n\n3. Do we allow target typing when the common type is not convertible to the target? (e.g.,\n`byte b = cond ? 1 : 2` would fall back to target typing because `int` is not convertible to\n`byte`)\n\nThere's also the behavioral difference between the old expressions which have target-typing as a\nfallback, and the switch expression, which currently prefers the target-typing if one exists.\nSome of the questions above, including (3), would make the two behaviors be very similar, in that\ntarget-typing would be present in the few cases that rely on it.\n\n**Conclusion**\n\nWe agree to the following changes:\n\n1. Target-typing as a fallback for the old expressions (array creation, conditional expression, et al.)\n\n2. We want target-typing to succeed in the case where the common type does not convert to the\ntarget-type\n\n3. We want to change switch expression to use the natural type if it converts to the target-type,\nand only use target-typing if the natural type does not convert to the target.\n\nWe want to continue to investigate improvements to the common type algorithm, including changes\nto support nullability.\n\n### Type patterns\n\nhttps://github.com/dotnet/csharplang/issues/2925\n\nThe first proposal is to simplify some existing constructs and add some simplification to some\ncurrent behavior by creating a simple \"type pattern\" without a variable introduction.\n\n```C#\nvoid M(object o1, object o2)\n{\n    var t = (o1, o2);\n    if (t is string) // This is currently legal and we would just change the spec to say that this\n                     // is a type pattern, although the `is` would prefer a type in an ambiguity\n                     // to preserve backwards compatibility\n    if (t is (int, string)) // This would now be legal as a tuple pattern, containing two type patterns\n    switch (t)\n    {\n        case string: // this would now work, but would be the inverse of `is`, preferring a constant\n                     // for backwards compatibility\n    }\n}\n```\n\nThis has broad agreement as a good change, and multiple LDM members have been frustrated that the\nswitch statement and expressions often require a `_` in these places.\n\n**Conclusion**\n\nThe first proposal, allowing simple type patterns, is broadly useful right now. Accepted for the\nC# 9.0 milestone.\n\n### Name lookup for binding simple names with known target type\n\nhttps://github.com/dotnet/csharplang/issues/2926\n\nThe second proposal is to adjust binding with a known target type, so you could say\n\n```C#\nclass Outer\n{\n    public class Inner1 : Outer {}\n    public class Inner2<T> : Outer {}\n}\n\nint M1(Outer o) => o switch\n{\n    Inner1 _ => 0, // Binds to Outer\n    Inner2<int> _ => 1;\n}\n```\n\nor even\n\n```C#\nColor x = b ? Red : Greed;\nvar y = b ? Color.Red : Greed;\n```\n\n**Conclusion**\n\nThis change feels especially natural in switch statements and expression with enums. It seems\nuseful in the other contexts as well. The extension to nested classes would be particularly\nrelevant to a discriminated union based off of nested classes. \n\nThere's a lot here in the binding changes. Let's sit on it a bit and take a look with a\ndiscriminated unions proposal. Triaged to C# 9.0 to match discriminated unions.\n"
  },
  {
    "path": "meetings/2019/LDM-2019-11-13.md",
    "content": "\n# C# Language Design Meeting for Nov. 13th, 2019\n\n## Agenda\n\n1. Discriminated unions\n2. Improved analysis of `[MaybeNull]T`\n\n## Discussion\n\n### Initial discriminated union proposal\n\nhttps://github.com/dotnet/csharplang/blob/master/proposals/discriminated-unions.md\n\nQuestions around some restrictions:\n\n1. Why can't you have constructor parameters on the enum class type?\n    - No real reason, except worries about inheritance aside from members\n        - Keeping inheritance syntactically close by is considered a feature of the proposal,\n          since the user can easy analyze what all the possible children of the root are\n    - Syntax for the base call in value members would have to be specified\n\n2. How `partial` do we want to allow things? There's good reason to put all the members together\n\n3. Are records short enough syntax that we don't need the \"simple\" type syntax?\n\n    - Regardless of brevity, if members are required to explicitly inherit from the root this seems\n      like purely useless work, since doing otherwise would be an error\n\n4. What if you want to define just regular nested classes, that don't inherit from the root type?\n\n5. Scoping for nested enum class members? The proposal for altering binding wouldn't help with\n   nested members, because it only applies to simple names.\n\n```C#\nenum class Expr\n{\n    enum class BinaryOperator\n    {\n        Add(Expr left, Expr right),\n        Multiply(Expr left, Expr right)\n    }\n}\n\nExpr M(Expr left, Expr right)\n{\n    return Add(left, right); // error, no name \"Add\" found under Expr\n}\n\nint M(Expr e) => e switch\n{\n    Add _ => 0, // error, no name Add found under Expr\n}\n```\n\nThere's also a proposed alternate syntax that would let you put everything directly into the enum\nclass:\n\n```C#\nenum class Color\n{\n    Red,\n    Greed; // semicolon delimiting end of enum class cases, and start of regular members\n\n    public static int HelperField;\n    public static int HelperProperty => 0;\n    public int HelperMethod() => 0;\n}\n```\n\n\n## Improved analysis of `[MaybeNull]T`\n\nProposal: https://github.com/dotnet/csharplang/issues/2946\n\nThe new proposed abstract domain for nullable analysis would be:\n\n```C#\nenum\n{\n    NotNull,\n    MaybeNull,\n    MaybeNullEvenIfNotNullable\n}\n```\n\n\nIf we improve analysis of `MaybeNull` inside the method, do we want to push the new functionality\nthrough for all the nullable attributes at the same time? This seems useful from a consumer\nperspective, in that you get the different warnings all at the same time, but there's also the\nsimple question of resources and scheduling.\n\nSimilarly, if we do improve `MaybeNull` analysis in the body of the method, do we need to improve\nthe analysis in other places, like overriding, at the same time? Or are we OK with a piecemeal state\nwhere `MaybeNull` is enforced in the method body but not in overriding? Or where we enforce `MaybeNull`\nin overriding, but not other attributes like `DisallowNull`?\n\nA broader question is how common `MaybeNull` is in general. Our experience in the .NET Core mscorlib\nis that there are only 10 occurrences of `MaybeNull`, and even when broadening to LINQ, there are at\nmost a few dozen occurrences, mostly in places that may return a `default` value. In comparison,\n`NotNullIfNotNull` has ~30 occurrences in mscorlib.\n\nOn the other hand, `default(T)` is very common and is an instance of `MaybeNull` in a sense. This implies\nthat the flow state of `MaybeNull` is particularly important.\n\nAn additional question is whether or not to revive the `T?` proposal to deal with the historical problems\naround `MaybeNull` annotations on locals and other places where attributes are not permitted.\n\n**Conclusion**\n\nWe think improving any aspect of the attributes can be considered independently and we will not\nrequire the changes to ship together. We think that proposal is good. Accepted.\n\nNo statement on `T?`. We will schedule a discussion soon to get a permanent decision on the proposal.\n"
  },
  {
    "path": "meetings/2019/LDM-2019-11-18.md",
    "content": "\n# C# LDM for Nov. 18th, 2019\n\n## Agenda\n\n1. More patterns\n\n## Discussion\n\n### More patterns\n\nParenthesized patterns:\n\n- What about ambiguity with a potential 1-tuple pattern?\n\n    - There was a previous ambiguity here with a parenthesized constant expression,\n      so matching a 1-tuple pattern requires resolving ambiguity, for example by adding\n      tuple names: `x is (Item1: var tupleVal)`\n\nRelational patterns:\n\nWe don't love the syntax. The problem is really that we're using a binary operator in\na unary context. On the other hand, it's useful in that it's easy to adjust for closed\nor open bounds by adjusting the inclusiveness of the operator.\n\nThe other shaky part of the syntax is support for user-defined operators. One of the\nfundamental parts of pattern matching is that the semantics are well-understood, meaning\nthat the switch expression expects certain things must be true, like that checks must return\nthe same value for the same inputs and can be called any number of times. We have a few patterns\nthat execute user-defined code, but it seems more likely that they're usually safe (property\ngetters and Deconstruct).\n\nFor `==` and `!=` specifically, they seem redundant and likely to cause confusion when there is a\nuser-defined operator that is not supported. Consensus is to remove support in relational patterns.\n\nThe other confusing part is conversion, where the input type does not statically contain a built-in\nthe binary operator. For instance,\n\n```C#\nobject o = (short)1;\n_ = o switch\n{\n    < 3 => 0, // This would be false, since `o` is a short, not an int, and the\n              // unconverted '3' is an `int`\n};\n```\n\nThis is already how constant patterns work, so there may be some confusion here already, but we're\nworried about broadening the problem by adding the `not` pattern in combination with the relational\noperators. For example, if you match `not < 3`, this would evaluate to true, but not because the\nvalue is not less than three, but because it is not an int. This would mean that `>= 3` and `not < 3`\nwould be different, since the type check can play into the check.\n\nHowever, we don't have any better approaches, and the hope is that this will be a relatively rare\noccurrence. If the input pattern has a statically known built-in operator this would not be a concern.\n\nThe proposal states that the input type of the expression must contain a conversion that is not a boxing\nconversion. However, we do support constant pattern checks for unconstrained type parameters, so we\nneed to change the proposal to allow unconstrained type parameters as well.\n\n### Pattern combinators\n\nThe proposal contains three breaking changes:\n\n    - `not` is considered a type in C# 8 and a pattern in C# 9.\n\n    - `and` and `or` are allowed as variable names in C# 8, but are pattern combinators in C# 9\n\nAn important question is whether these are allowed and how they are breaking. Changing behavior is\nprobably a bridge too far. We would consider providing an error in the old scenarios and forcing\ndisambiguation.\n\nWe'll need more discussion on the breaking changes and how we can mitigate them.\n"
  },
  {
    "path": "meetings/2019/LDM-2019-11-25.md",
    "content": "# C# Language Design Notes for Nov 25, 2019\n\n## Agenda\n\n1. Allow `T?` where `T` is a type parameter that's not constrained to be a value or reference type\n\n# \"Unconstrained\" `T?`\n\nIn C# 8.0 we entertained the possibility of allowing `T?` on type parameters `T` that are unconstrained, or constrained only in a way that they can still be instantiated with both value and reference types.\n\nThe idea was to accurately express the type of `default(T)`. To this end, `T?` would end up being the same as `T`, except when `T` is instantiated with a nonnullable reference type `C`, in which case `T?` is `C?`. The reason is that for non-nullable reference types `C`, `default(C)` is still null, and hence of the type `C?`, not `C`.\n\n`T?` would, for instance, allow the return type of methods like `FirstOrDefault()` to be better expressed:\n\n``` c#\npublic T? FirstOrDefault<T>(this IEnumerable<T> src);\n```\n\nIn the generic context where `T` is in scope, the meaning of `T?` would be \"may be null, even when `T` is not nullable\". The expression `default(T)` would no longer warn, but the type of it would be `T?`, and assigning `T?` to `T` *would* warn.\n\nIn the end we decided not to allow `T?` due to a couple of problems which we'll get back to below. Instead we addressed many of the scenarios with the addition of nullable attributes such as `[MaybeNull]`, which can be used to annotate e.g. the `FirstOrDefault()` method:\n\n``` c#\npublic [return:MaybeNull] T FirstOrDefault<T>(this IEnumerable<T> src);\n```\n\n## Recent changes\n\nDefault values keep causing grief, and we've recently [(Nov 13)](https://github.com/dotnet/csharplang/blob/master/meetings/2019/LDM-2019-11-13.md#improved-analysis-of-maybenullt) decided on some changes to handle them:\n\n1. Add a third null-state next to \"not null\" and \"maybe null\", which is \"maybe null *even* when the type doesn't allow\", and make that the null state of `default(T)` for an unconstrained type parameter `T`, as well as results of method calls etc. (such as `FirstOrDefault`) that were annotated with `[MaybeNull]`\n2. Remove the \"W warning\" on assignment of such values to locals of type `T`, but instead subsequently track the new state *for* those locals, which may subsequently lead to warnings if used unsafely\n3. Remove warnings when producing such values as a result (e.g. return value) that is itself annotated as `[MaybeNull]`\n\nPut together, these three eliminate most of the friction around the use of `default(T)` and `[MaybeNull]`. However, they also get very close to the previously proposed semantics of allowing `T?` on unconstrained `T`. We could take this two ways:\n\n1. Since we mostly succeeded in addressing the problem without `T?`, it further reduces the need for it.\n2. This shows that \"the type of `default(T)`\" is an important concept that should be properly reified in the language instead of tricks with attributes.\n\n## Taking another look at \"unconstrained\" `T?`\n\nThe main arguments in favor of a syntax for \"the type of `default(T)`\" even with the above changes are:\n\n1. By adding \"it\" as a tracked null state, we're already half embracing it, but by leaving it inexpressible as a type we need to fall back on \"tricks\" to make use of it\n2. `[MaybeNull]` doesn't help when \"the type of `default(T)`\" is needed in a constructed (array, generic, tuple, ...) type\n\nThe use of the syntax `T?` to mean \"the type of `default(T)`\" as two significant problems as well, which ultimately led us to not embrace it for C# 8.0:\n\n1. Its meaning is different from the meaning of `T?` when `T` is constrained to be a value type.\n2. Overrides cannot restate their constraint, and `T?` in those today always means the value type kind.\n\n## Problem 1: `T?` and `T?` mean different things\n\nThe first problem is not technical, but one of perception and language regularity. Consider:\n\n```\npublic T? M1<T>(T t) where T : struct;\npublic T? M2<T>(T t);\n\nvar i1 = M1(7); // i1 is int?\nvar i2 = M2(7); // i2 is int\n```\n\nThe declaration of `M1` is legal today. Because `T` is constrained to a (nonnullable) value type, `T?` is known to be a nullable value type, and hence, when instantiated with `int`, the return type is `int?`.\n\nThe declaration of `M2` is what's proposed to allow. Because `T` is unconstrained, `T?` is \"the type of `default(T)`\". When instantiated with `int` the type of `default(int)` is `int`, so that is the return type.\n\nIn other words, for the same provided `T` these two methods have *different* return types, even though the only difference is that one has a constraint on `T` but the other does not.\n\nThe cognitive dissonance here was a major part of why we didn't embrace `T?` for unconstrained `T`.\n\n## Problem 2: pseudo-\"unconstraint\" in overrides for disambiguation\n\nIn C# overrides of generic methods cannot re-specify constraints, but must inherit them from the original declaration. Before C# 8.0, when `T?` appeared in signatures of such overrides, it was always assumed to mean the nullable value type `Nullable<T>`, because what else could it mean?\n\nIn C# 8.0 `T?` acquired the possible second meaning of nullable reference type. In order to disambiguate the search for the original declaration, we reluctantly introduced the ability to specify \"pseudo-constraints\" on the overrides: When `T` was a type parameter constrained to be a reference type, you can now say so by adding `where T: class` to the declaration. If you want the default assumption of it being constrained to a value type to be made explicit, you can also optionally specify `where T: struct`.\n\nThese helper constraints are only there to help find the right declaring method up the inheritance chain (which may be overloaded). The *actual* constraint that's emitted into generated code is still the one that's inherited from the original declaration, once that one has been identified. Thus, only `class` and `struct` can be used as constraints on an override.\n\nNow here comes a third `T?`, the defining characteristic of which is that it is *not* constrained to be either a reference or value type. To distinguish it from the other two in an override of a generic method, we would need a third \"constraint\" that is actually an *unconstraint* - that specifically says that it is *not* constrained!\n\n## Solutions\n\nWe have two general approaches to address these problems (beyond the ever-present solution of giving up on the feature):\n\n1. Live with problem 1, and try to explain things as best we can. Find a syntax to express the \"unconstraint\" of problem 2.\n2. Use a different syntax than `T?` to express \"the type of `default(T)`\".\n\n## Solution 1\n\nA brain storm for solution 1 syntaxes yielded:\n\n``` c#\noverride void M1<[Unconstrained]T,U>(T? x)           // a\noverride void M1<T,U>(T? x) where T: object?         // b\noverride void M1<T,U>(T? x) where T: unconstrained   // c\noverride void M1<T,U>(T? x) where T:                 // d\noverride void M1<T,U>(T? x) where T: ?               // e\noverride void M1<T,U>(T? x) where T: null            // f\noverride void M1<T,U>(T? x) where T: class|struct    // g\noverride void M1<T,U>(T? x) where T: class or struct // h\noverride void M1<T,U>(T? x) where T: cluct           // joke\n```\n\nOf these we have a vague preference for c, expressing explicitly that there is *not* a constraint, closely followed by b, which is the most general constraint one could state. None of the others resonated.\n\n## Solution 2\n\nA brain storm for solution 2 syntaxes yielded:\n\n``` c#\nvoid M1<T,U>(default(T) x) // X\nvoid M1<T,U>(default<T> x) // Y\nvoid M1<T,U>(T?? x)        // Z\n```\n\nSolutions X and Y try to be explicit about the type meaning \"the type of `default(T)`\", but run the risk of implying \"the result *is* `default(T)`\". Solution Z is mostly just the shortest `?`-like token we could think of that isn't `?`.\n\nWe unanimously preferred Z. `??` can be read as *may be* (`?`) nullable (`?`). \n\n## Conclusion\n\nComparing the two approaches we do favor solution 2, adopting the syntax `T??` to mean \"the type of `default(T)`\" (when `T` is unconstrained). We do think that this is the best solution, because it addresses both problems, is terse, and looks reasonable. We will move ahead with prototyping and fleshing it out.\n\nWe would probably only allow it to be used at all on type parameters `T` that are not constrained to be either value or reference types. That way you can never use either `??` or `?` on the same thing.\n\n"
  },
  {
    "path": "meetings/2019/LDM-2019-12-11.md",
    "content": "\n# C# Language Design Meeting for Dec. 11, 2019\n\n1. Design review feedback\n\n## Discussion\n\nWe got feedback from the design review that we shouldn't try to conflate too many problems. If\nwe want to make it easier to support structural equality, we should see if it's possible to\naddress directly, without requiring the other features of records. One suggestion was to take\ninspiration from `VB`, which allows the `key` modifier to be added to VB anonymous types to\nindicate structural equality with the members used as the keys.\n\nWe took that advice and looked at a sketch of what that could look like:\n\n```C#\nclass C\n{\n    public key string Item1 { get; }\n    public string Item2 { get; }\n}\n```\n\nThe `key` modifier would be used to control generated equality, such that all members marked\n`key` would be compared for equality in an `Equals` override (using the same pattern as in the\noriginal records proposal).\n\nThe above code sample certainly looks simple, but unfortunately it's not sufficient for\nreal-world code. Both `Item1` and `Item2` are `get`-only autoproperties, meaning that as-is there\nis no way to initialize those members. A working example looks more like:\n\n```C#\nclass C\n{\n    public key string Item1 { get; }\n    public string Item2 { get; }\n    public C(string item1, string item2)\n    {\n        Item1 = item1;\n        Item2 = item2;\n    }\n}\n```\n\nThis is significantly longer than the original sample, grows with the number of properties, and\nis repetitive. The latter is particularly problematic, as repetitive boilerplate is often a source\nof hard-to-see bugs or typos.\n\nWorse, we've seen that when construction becomes laborious, users resort to making their types\nmutable instead of writing out the constructor, e.g.\n\n```C#\nclass C\n{\n    public key string Item1 { get; set; }\n    public string Item2 { get; }\n}\n```\n\nThis is unfortunate in most code, but it's worrying when combined with structural equality. When\nused in Dictionaries, mutable types with structural equality are an anti-pattern because the hash\ncode of the type changes, causing the type to \"disappear\" from the Dictionary. It's one thing if\nthe user opts-in to this risk, knowing that they need to be careful, and a completely different\nsituation if the language encourages a dangerous pattern.\n\n**Conclusion**\n\nThis is an interesting design point that we think we'll incorporate. We've also agreed that we\nhave a hard design requirement: if we provide a feature for easy structural equality, we must\nprovide a more convenient syntax for constructing immutable types in the same release. To do\notherwise would be to effectively make a trap for users.\n\n## Nominal vs Positional\n\nWe also continued to explore the space of nominal vs. positional records. An insight from the\nprevious discussion is that nominal vs. positional records are really about improving syntax\nfor type construction. Positional records are about taking the existing type construction,\nconstructors, and giving them a shorter syntax. Nominal records are about identifying some\nweaknesses of the existing construction system and providing a new feature to support them. In\nboth cases, though, the proposed features shorten construction by avoiding repeating the member\ndeclarations and the assignments.\n\nWe also had the following notes, in no particular order:\n\n* For positional constructors, it's important to consider primary constructors. We have one\nproposal for primary constructors, but have not had a discussion on whether we want them, and if\nthe syntax is worth taking away from the record syntax.\n\n* If the `initonly` keyword is required, even for common cases, this is about\nas expensive syntax-wise as a setter. It may be a few more characters, but it\nkeeps things on one line, as opposed to the multi-line constructors that are\nrequired right now.\n\n* There's an opposition between evolving existing data types and picking and choosing features when\nyou need them, but also providing a simple syntax for the most common case. Certainly positional\nrecords solve a common case. The question is how common that case is.\n\n* Positional records use existing initialization strategy (construction) which is fairly\nwell-understood. The initonly feature, by contrast, will force us to reexamine some assumptions.\nFor instance, constructors take all inputs at once, meaning that you can enforce requirements\nbetween them at construction time. `initonly` overrides properties after construction, and\none-by-one, so it's not possible, or not obvious, how to provide this functionality.\n\n* There are mixed feelings on the requirements of what features will be available individually, and\nwhich are separable. Some people feel that addressing the most common case is sufficient for\nproviding the value of the feature, namely that there can be a single \"record\" which provides\nimmutable construction and value equality, and that is the only way to access these features.\nOthers think that the features need to be adoptable independently: existing types need to be able\nto adopt generated equality without adopting immutable construction, while immutable construction\nneeds to be available without structural equality.\n\nOne conclusion is that no proposal will solve all record-related problems. This is fine. We also\nhave general agreement that there should be a convenient shorthand for the combination of most or\nall of the features (simple immutable construction, structural equality, etc.). Notably we don't\nall agree on whether or not structural equality will be the most common type of equality for\nrecords, but the shortest record form may include structural equality for other language design\nreasons."
  },
  {
    "path": "meetings/2019/LDM-2019-12-16.md",
    "content": "\n# C# Language Design Notes for Dec. 16, 2019\n\n## Agenda\n\n1. Switch expression as a statement expression\n2. Triage\n\n## Discussion\n\n### Switch expression as a statement expression\n\nhttps://github.com/dotnet/csharplang/issues/2860 \n\nThe proposal being discussed is whether to allow the switch expression without a discard:\n\n```C#\n_ = a switch\n{ \n    ...\n};\n// becomes\na switch \n{ \n    ...\n};\n```\n\nOne of the against is that it makes for a confusing decision in the language as to whether you\nuse a switch expression or switch statement. Right now the guidance is simple: if you are in a\nstatement context, use a statement. If you have an expression context, use a switch expression.\nNow, for a statement, you could use either a switch statement, or a switch expression in\nstatement form. It's not clear which.\n\nOne way of resolving this is that these are two parallel features that provide similar features\nin a slightly different syntax and semantics. Then the answer simply becomes, use whichever one\nyou like better. If the new switch expression form includes exhaustiveness checking, that would\nbe a reason to use or not to use it, aside from the syntax differences. Similarly, the switch\nstatement ability to `goto` another case is a reason to use that form. However, if we accept\nthat, the switch expression feels artificially limited. To provide a satisfactory parallel\nfeature we have to augment the switch expression to allow for statements in the switch arms. Then\nthere is a potential new set of features: block in switch expressions.\n\nOn the other hand, this feels like feature creep. The original proposal was quite simple: allow\nusers to elide `_ =` and remove the requirements for the arms to have a common type. While we may\nwant to have a number of different new features for switch expression to make it comparable to\nthe switch statement, there's value in doing the feature as-is, and adding those features later.\nThis is contingent on us being fairly confident that the new features can be added without\nbreaking changes, but there's a fair amount of confidence that we know where we would go with the\nfeature. This perspective would require us to keep certain behaviors to ensure that the switch\nexpression keeps its differences from the switch statement. For instance, the new switch\nexpression-as-statement would have to check exhaustiveness if we see it as a strict improvement\nfor the switch expression.\n\nLastly, we all find the proposed switch expression-as-statement requiring a semicolon i.e.,\n\n```C#\na switch\n{\n    b => ...,\n    c => ...\n}; // semicolon required\n```\n\nas being extremely ugly.\n\n**Conclusion**\n\nRejected as-is. We'd be interested in a new proposal on this topic, addressing many of the\nconcerns that we brought up today.\n\n### Triage\n\n#### Definite assignment of private reference fields\n\n**Conclusion**\n\nAccepted for warning waves v1, wherever that is triaged.\n\n#### Remove restriction on yielding a value in the body of a try block\n\nAlso for async iterators.\n\nIssue #2949\n\n**Conclusion**\n\nAccepted, Any Time.\n\n#### Generic user-defined operators\n\nIssue #813\n\n**Conclusion**\n\nThere's no syntax in the invocation to specify the type arguments, in case inference doesn't\nsucceed, and we think almost any syntax in the invocation location would be ugly. In addition, we\ndon't have a lot of examples of why this would be significantly better than alternatives (like\nwriting a method).\n\nRejected.\n\n#### Support for method argument names in `nameof`\n\nIssue #373\n\nIt looks like there's a significant breaking change if we allow the parameter names to be in\nscope generally.\n\n```C#\nconst int p = 3;\n[Attribute(Property = p)]\nvoid M(int p) { }\n```\n\nIf we just allow `nameof` to have special scoping to allow the names in the method declaration to\nbe in scope, then there's no language breaking change. The scoping rules would prefer names in\nthe method header (including type parameters) over rules in the rest of the program.\n\n**Conclusion**\n\nAccepted, Any Time."
  },
  {
    "path": "meetings/2019/LDM-2019-12-18.md",
    "content": "\n# C# Language Design Meeting for Dec. 18, 2019\n\n## Agenda\n\n1. Nullable issues\n\n    a. Pure null checks\n\n    b. Consider `var?`\n\n## Discussion\n\n### Pure null checks\n\nWe have the following syntax which semantically check for null in the language:\n\n* `e is null`\n* `e == null`\n* `e is {}`\n* `e is object`\n\nHowever, for nullability we have a separate notion of a \"pure\" null check that\ncauses a null branch to appear, even if the variable being tested was declared\nnot null, or vice versa.\n\nAn example of why this would matter is\n\n```C#\nvar current = myLinkedList.Head; // assume Head is nullable oblivious/unannotated\nwhile (current is object)\n{\n    ...\n    current = current.Next; // assume oblivious\n}\ncurrent.ToString(); // only warns if `is object` is a pure null test\n```\n\nWe previously established that all \"pure\" null checks contain the word `null` in them, meaning\nthat only `e is null` and `e == null` are pure null checks today. There is a proposal that we\nshould unify all forms that are semantically equivalent, regardless of syntax.\n\nThere is also a proposal to expend this even to places which are not \"pure\" checks, i.e.\nthey have semantic effect larger than just checking for null. For instance, we could\nalso check `e is object o`, which also introduces a variable `o`. We came up with\nthe following list of potential checks:\n\n```\ne is null       // pure\n\ne is object     // Proposed\ne is [System.]Object // Proposed\ne is object _\ne is object x\n\ns is string        // s denotes expr of static type string\ns is string x\no is string x\n\ne is {}          // Proposed\ne is {} _\ne is {} x\n\ne == null       // pure\ne != null       // pure\n\ne is not null   // pure\ne is not object // etc...\n```\n\nAll parties argue that other positions are confusing as to why something is a pure\nnull check and something else, that's very similar, is not. It seems like drawing\nany particular line will always imply that something similar could be confusing.\n\nOne difference between versions that check between a semantically pure null check, i.e. a piece\nof syntax that has no other meaning than testing for null, is that if there is a pure null check\nthen any warning is definitely a bug in user code: either the check is superfluous, or there is\nan actual safety issue. If the check is not pure, there may not be a bug, because the check may\nnot actually be superfluous and this may be a spurious warning.\n\nGiven that the pure null checking is useful, it's mainly about finding the right balance between\nhelping the user find bugs in their code and finding a set of rules that are also easily\nunderstandable. The main argument against broadening beyond our current rule is that \"pure checks\ncontain the word 'null'\" is a simple rule, and adding warnings in an update is a heavy way to\naddress the issue.\n\nOn the other hand, we have changed nullable warnings multiple times already, plan to\ndo it again, and have warned people that nullable warnings may be in flux for a time.\nIf the feature is also meant to react to user intent, and if we believe `x is object`\nis intended by the user to be a null check, then making it a pure null check would\nbe correctly responding to user intent.\n\nWe could also decide based on whether or not we want to suppress certain patterns. If\nwe believe `x is object` or `x is {}` aren't good ways to test for null, then making\nthem not pure null checks would encourage users not to use it. This did not seem a\ncompelling position for anyone in LDM.\n\n**Conclusion**\n\nWe agree that we should broaden the set of pure null checks. We agree that `x is object` should\nbe a pure null check. Moreover this should be based on the type in the `is` expression, meaning\nthat any type `T` that binds to `System.Object` in `x is T` would be a pure null check. We also\nagree that `x is {}` is a pure null check.\n\nNone of `x is object _`, `x is object o`, `x is {} _`, or `x is {} o` are pure null checks.\n\n### `var?`\n\nAt this point we've seen a large amount of code that requires people spell out the\ntype instead of using var, because code may assign `null` later.\n\nAn example,\n\n```C#\nvar current = myLinkedList.Head; // annotated not null\nwhile (current is object)\n{\n    ...\n    current = current.Next; // warning, Next is annotated nullable, but current is non-null\n}\n```\n\nOne way to deal with this is to allow `var?`,\n\n```C#\nvar? current = myLinkedList.Head;\n// now current is nullable, but the flow state is non-null\ncurrent.ToString(); // no warning, because the flow analysis says it's not null\n```\n\nThis would let people express that the think the variable may be assigned null later on.\n\nOn the other hand, we could just permit these assignments when using `var`, and use flow analysis\nto ensure safety.\n\n```C#\nvar current = myLinkedList.Head;\ncurrent = null; // no warning because var is nullable\ncurrent.ToString(); // warning, the flow state says this may be null\n```\n\nThis would allow users to be explicit when they want to make sure not to assign\nnull to a type, but they have to spell out the type.\n\n**Conclusion**\n\nMake `var` have a nullable annotated type and infer the flow type as normal."
  },
  {
    "path": "meetings/2019/README.md",
    "content": "\n# C# Language Design Notes for 2019\n\nOverview of meetings and agendas for 2019\n\n## Dec 18, 2019\n\n[C# Language Design Notes for Dec 18, 2019](LDM-2019-12-18.md)\n\n1. Pure null checks\n2. `var?`\n\n## Dec 16, 2019\n\n[C# Language Design Notes for Dec 16, 2019](LDM-2019-12-16.md)\n\n1. Switch Expression as a Statement Expression (continued) (Neal, Fred)\n2. Triage\n\n## Dec 11, 2019\n\n[C# Language Design Notes for Dec 11, 2019](LDM-2019-12-11.md)\n\n1. Design review feedback\n\n## Dec 9, 2019\n(not yet transcribed)\n- https://github.com/dotnet/csharplang/issues/2850 Proposed changes for pattern-matching (continued) (Neal)\n- https://github.com/dotnet/csharplang/issues/2860 Switch Expression as a Statement Expression (Neal)\n\n## Dec 4, 2019 (Design Review)\n(not yet transcribed)\n\n## Nov 25, 2019\n\n[C# Language Design Notes for Nov 25, 2019](LDM-2019-11-25.md)\n\n1. Revisit unconstrained `T?` (Mads, Jared)\n\n## Nov 20, 2019\n(not yet transcribed)\n- https://github.com/dotnet/csharplang/issues/2911 Utf8 String Literals (Neal)\n- https://github.com/dotnet/csharplang/issues/2850 Proposed changes for pattern-matching (continued) (Neal)\n\n## Nov 18, 2019\n\n[C# Language Design Notes for Nov. 18, 2019](LDM-2019-11-18.md)\n\n1. Proposed changes for pattern-matching\n\n## Nov 13, 2019\n\n[C# Language Design Notes for Nov 13, 2019](LDM-2019-11-13.md)\n\n1. Discriminated unions\n2. Improve analysis of `[MaybeNull]T` values\n\n## Nov 11, 2019\n\n[C# Language Design Notes for Nov 11, 2019](LDM-2019-11-11.md)\n\n1. Confirm removal of warning calling a method that returns `[MaybeNull]T`\n2. Allow interpolated string constant\n3. Enhancing the Common Type Specification\n4. Type pattern\n5. Simple name binding with target type\n\n## Oct 30, 2019\n\n[C# Language Design Notes for Oct 30, 2019](LDM-2019-10-30.md)\n\n1. Function Pointer syntax\n2. Enhancing the Common Type Specification\n\n## Oct 28, 2019\n\n[C# Language Design Notes for Oct 28, 2019](LDM-2019-10-28.md)\n\n1. Discard parameters in lambdas and other methods\n1. Enhancing the common type algorithm\n\n## Oct 23, 2019\n\n[C# Language Design Notes for Oct 23, 2019](LDM-2019-10-23.md)\n\n1. New primitive types \n\nhttps://github.com/dotnet/csharplang/issues/435\n\n## Oct 21, 2019\n\n[C# Language Design Notes for Oct 21, 2019](LDM-2019-10-21.md)\n\n1. Records\n2. Init-only members\n3. Static lambdas\n\n## Sep 18, 2019\n\n[C# Language Design Notes for Sep 18, 2019](LDM-2019-09-18.md)\n\nTriage:\n\n1. Proposals with complete designs:\n\n    - https://github.com/dotnet/csharplang/issues/1888 Champion \"Permit attributes on local functions\"\n    - https://github.com/dotnet/csharplang/issues/100 Champion \"Target-typed new expression\"\n\n2. Target typing and best-common-type features: \n\n    - https://github.com/dotnet/csharplang/issues/2473 Proposal: Target typed null coalescing (??) expression\n    - https://github.com/dotnet/csharplang/issues/2460 Champion: target-typed conditional expression\n    - https://github.com/dotnet/csharplang/issues/881 Permit ternary operation with int? and double operands\n    - https://github.com/dotnet/csharplang/issues/33 Champion \"Nullable-enhanced common type\"\n\n## Sep 16, 2019\n\n[C# Language Design Notes for Sep 16, 2019](LDM-2019-09-16.md)\n\n- Support for Utf8 strings\n- Triage remaining features out of the [8.X milestone](https://github.com/dotnet/csharplang/issues?q=is%3Aopen+is%3Aissue+milestone%3A%228.X+candidate%22)\n\n## Sep 11, 2019\n\n[C# Language Design Notes for Sep 11, 2019](LDM-2019-09-11.md)\n\n1. Close https://github.com/dotnet/roslyn/issues/37313\n2. Triage new proposed [9.0 features](https://github.com/dotnet/csharplang/issues?q=is%3Aopen+is%3Aissue+no%3Amilestone+label%3A%22Proposal+champion%22)\n2. Finish triaging away [8.X milestone](https://github.com/dotnet/csharplang/issues?q=is%3Aopen+is%3Aissue+label%3A%22Proposal+champion%22+milestone%3A%228.X+candidate%22)\n\n## Sep 4, 2019\n\n[C# Language Design Notes for Sep 4, 2019](LDM-2019-09-04.md)\n\n1. AllowNull on properties https://github.com/dotnet/roslyn/issues/37313\n\n## Aug 28, 2019\n\n[C# Language Design Notes for Aug 28, 2019](LDM-2019-08-28.md)\n\n1. Triage language features\n\n## Jul 22, 2019\n\n[C# Language Design Notes for July 22, 2019](LDM-2019-07-22.md)\n\n1. Discuss the [new records proposal](https://github.com/dotnet/csharplang/blob/856c335cc584eda2178f0604cc845ef200d89f97/proposals/recordsv2.md)\n\n## Jul 17, 2019\n\n[C# Language Design Notes for July 17, 2019](LDM-2019-07-17.md)\n\n1. [Nullability of events](https://github.com/dotnet/roslyn/issues/34982)\n\n1.  Triage, see https://github.com/dotnet/csharplang/projects/4\n    - Triage championed features https://github.com/dotnet/csharplang/projects/4#column-4649189\n    - Triage milestones\n\n## Jul 10, 2019\n\n[C# Language Design Notes for July 10, 2019](LDM-2019-07-10.md)\n\n1. Empty switch statement\n1. `[DoesNotReturn]` attribute\n1. Revisiting the `param!` null-checking feature\n\n## May 15, 2019\n[C# Language Design Notes for May 15, 2019](LDM-2019-05-15.md)\n\n- Close on nullable attributes (Mads and Steve)\n\n## May 13, 2019\n[C# Language Design Notes for May 13, 2019](LDM-2019-05-13.md)\n\n- Close on desired rules for warning suppressions and `#nullable` interacting\n\n## Apr 29, 2019\n\n[C# Language Design Notes for Apr 29, 2019](LDM-2019-04-29.md)\n\n1. Default interface implementations and `base()` calls\n2. Async iterator cancellation\n3. Attributes on local functions\n\n## Apr 24, 2019\n\n[C# Language Design Notes for Apr 24, 2019](LDM-2019-04-24.md)\n\nMaybeNull and related nullable reference type attributes\n\n## Apr 22, 2019\n\n[C# Language Design Notes for Apr 22, 2019](LDM-2019-04-22.md)\n\n1. Inferred nullable state from a finally block\n2. Implied constraint for a type parameter of a partial?\n3. Target-typed switch expression\n4. DefaultCancellationAttribute and overriding/hiding/interface implementation\n\n## Apr 15, 2019\n\n[C# Language Design Notes for Apr 15, 2019](LDM-2019-04-15.md)\n\n1. CancellationToken in iterators\n2. Implied nullable constraints in nullable disabled code\n3. Inheriting constraints in nullable disabled code\n4. Declarations with constraints declared in #nullable disabled code\n5. Result type of `??=` expression\n6. Use annotation context to compute the annotations?\n7. Follow-up decisions for pattern-based Index/Range\n\n## Apr 3, 2019\n\n[C# Language Design Notes for Apr 3, 2019](LDM-2019-04-03.md)\n\n1. Ambiguous implementations/overrides with generic methods and NRTs\n2. NRT and `dynamic`\n\n## Apr 1, 2019\n\n[C# Language Design Notes for Apr 1, 2019](LDM-2019-04-01.md)\n\n1. Pattern-based Index/Range translation\n\n2. Default interface implementations: Is object.MemberwiseClone() accessible in\nan interface?\n\n\n## Mar 27, 2019\n\n[C# Language Design Notes for Mar 27, 2019](LDM-2019-03-27.md)\n\n1. Switch expression syntax\n\n1. Default interface implementations\n\n    1. Reabstraction\n\n    2. Explicit interface abstract overrides in classes\n\n    3. `object.MemberwiseClone()`\n\n    4. `static int P {get; set}` semantics\n\n    5. `partial` on interface methods\n\n2. `?` on unconstrained generic param `T`\n\n## Mar 25, 2019\n\n[C# Design Review Notes for Mar 25, 2019](LDM-2019-03-25.md)\n\nWe brought in the design review team to look at some of our recent and open decisions in C# LDM.\n\n1. Nullable reference types: shipping annotations\n2. Pattern-based indexing with `Index` and `Range`\n3. Cancellation tokens in async streams\n\n## Mar 19, 2019\n\n[C# Language Design Notes for March 19, 2019](LDM-2019-03-19.md)\n\nWe held a live LDM during the MVP summit with some Q&A about C# 8 and the future\n\nTopics:\n\n1. Records\n2. \"Extension interfaces\"/roles\n3. Macros\n4. IAsyncEnumerable\n5. \"Partially automatic\" properties\n6. More integration with reactive extensions\n\n## Mar 13, 2019\n\n[C# Language Design Notes for March 13, 2019](LDM-2019-03-13.md)\n\n1. Interface \"reabstraction\" with default interface implementations\n2. Precedence of the switch expression\n3. `or` keyword in patterns\n4. \"Pure\" null tests and the switch statement/expression\n\n## Mar 6, 2019\n\n[C# Language Design Notes for March 6th, 2019](LDM-2019-03-06.md)\n\n1. Pure checks in the switch expression\n2. Nullable analysis of unreachable code\n3. Warnings about nullability on expressions with errors\n4. Handling of type parameters that cannot be annotated\n5. Should anonymous type fields have top-level nullability?\n6. Element-wise analysis of tuple conversions\n\n## Mar 4, 2019\n\n[C# Language Design Notes for March 4, 2019](LDM-2019-03-04.md)\n\n1. Nullable user studies\n2. Interpolated string and string.Format optimizations\n\n## Feb 27, 2019\n\n[C# Language Design Notes for Feb 27, 2019](LDM-2019-02-27.md)\n\n1. Allow ObsoleteAttribute on property accessors\n2. More Default Interface Member questions\n\n## Feb 25, 2019\n\n[C# Language Design Notes for Feb 25, 2019](LDM-2019-02-25.md)\n\n- Open issues in default interface methods (https://github.com/dotnet/csharplang/issues/406). \n    - Base calls\n    - We currently have open issues around `protected`, `internal`, reabstraction, and `static` fields among others.\n\n## Feb 20, 2019\n\n[C# Language Design Notes for Feb 20, 2019](LDM-2019-02-20.md)\n\n- Nullable Reference Types: Open LDM Issues https://github.com/dotnet/csharplang/issues/2201\n\n## Feb 13, 2019\n\n[C# Language Design Notes for Feb 13, 2019](LDM-2019-02-13.md)\n\n- Nullable Reference Types: Open LDM Issues https://github.com/dotnet/csharplang/issues/2201\n\n## Jan 23, 2019\n\n[C# Language Design Notes for Jan 23, 2019](LDM-2019-01-23.md)\n\nFunction pointers ([Updated proposal](https://github.com/dotnet/csharplang/blob/master/proposals/function-pointers.md))\n\n## Jan 16, 2019\n\n[C# Language Design Notes for Jan 16, 2019](LDM-2019-01-16.md)\n\n1. Shadowing in lambdas\n2. Pattern-based disposal in `await foreach`\n\n## Jan 14, 2019\n\n[C# Language Design Notes for Jan 14, 2019](LDM-2019-01-14.md)\n\n- Generating null-check for `parameter!`\nhttps://github.com/dotnet/csharplang/pull/2144\n\n## Jan 9, 2019\n\n[C# Language Design Notes for Jan 9, 2019](LDM-2019-01-09.md)\n\n1. GetAsyncEnumerator signature\n2. Ambiguities in nullable array type syntax\n2. Recursive Patterns Open Language Issues https://github.com/dotnet/csharplang/issues/2095\n\n## Jan 7, 2019\n\n[C# Language Design Notes for Jan 7, 2019](LDM-2019-01-07.md)\n\nNullable:\n\n1. Variance in overriding/interface implementation\n2. Breaking change in parsing array specifiers\n\n"
  },
  {
    "path": "meetings/2020/LDM-2020-01-06.md",
    "content": "\n# C# Language Design Meeting for Jan. 6, 2020\n\n## Agenda\n\n1. Use attribute info inside method bodies\n1. Making Task-like types covariant for nullability\n1. Casting to non-nullable reference type\n1. Triage\n\n## Discussion\n\n### Use attribute info inside method bodies\n\nExamples:\n\n1.\n\n```C#\nbool TryGetValue<T>([MaybeNullWhen(false)]out T t)\n{\n    return other.TryGetValue(out t); // currently warns\n}\n```\n\n2.\n\n```C#\n[return: MaybeNull]\nT GetFirstOrDefault<T>()\n{\n    return null; // currently warns\n}\n```\n\n3.\n\nOverriding/implementation\n\n```C#\nclass A<T>\n{\n    [return: MaybeNull]\n    virtual T M();\n}\n\nclass B : A<string>\n{\n    override string? M(); // warns about no [MaybeNull]\n}\n```\n\nWe don't have a complete design here, but some cases have an intuition about the correct\nbehavior. In overriding, specifically, we need a specification for what it means for an\nannotation to be \"compatible\" with each of the attributes. On the other hand, it's not clear what\nthe behavior of `MaybeNullWhenTrue` should be in all cases.\n\n**Conclusion**\n\nWe'd like to do this if the return on investment seems worth it, but to fully evaluate\nwe need a proposal of the work.\n\n### Making Task-like objects nullable covariant\n\nThis is a pretty common pain-point, and it's not the first time we special-cased variance,\nspecifically `IEquatable<T>` is treated as nullable contravariant. It's unfortunate that the CLR\ndoesn't have capability to make `Task<T>` full covariant, but handling even nullable alone would\nbe useful. Moreover, if we later get the capability to mark `Task<T>` covariant, this would not\nharm the effort.\n\nWe also think that there may be some special cases introduced for overload resolution where we\nconsider `Task<T>` as covariant already. If we could reuse that knowledge, that would be useful.\n\n**Conclusion**\n\nLet's see if we can dig up the overload resolution changes for Task-like types and try to adapt\nthe same rule for making Task-like types nullable covariant.\n\n### Casting to non-nullable reference type\n\nExample:\n\n```C#\nBoundNode? node = ...;\nif (node.Kind == BoundKind.Expression)\n{\n    var x = (BoundExpression)node; // warning if node is nullable\n}\n```\n\nThe question is if this warning is valuable, or annoying. We've hit this most often in Roslyn\nwhen using the pattern `(object)x == null` to do a null check while avoiding the user-defined\nequality check. This is annoying in the Roslyn codebase, but not very common outside it. On the\nother hand, there's feeling that when doing the BoundNode to BoundExpression check, which is less\ncommon in Roslyn but more common generally, there's agreement that the warning is useful in\nmaking the type annotated with the most accurate representation of the null state.\n\n**Conclusion**\n\nKeep the warning, no change. We think the warning is valuable for the non-null-check cases. Newer\nversion of C# have features that address the null check problem and Roslyn should move to use `x\nis null` or similar.\n\n## Triage\n\nThree related proposals: #3037, #3038, #377.\n\nThese all deal with the general problem of statements in expressions, especially statements in\nswitch expressions, and switch expression form in statements.\n\nThey don't necessarily require each other, but they fit a lot of the same syntax and semantic\nspace, so we should consider them all together.\n\nThere's also a sketch for how we could unify the syntax forms of all of three proposals, with\npotential syntax changes.\n\n**Conclusion**\n\nWe agree that all of these proposals are addressing important scenarios, and some improvement\nhere is valuable. We're not sure where we want to go with generalized statements-in-expressions\nvs. adding special syntax forms for switch expression/statement.\n\nWe're mainly concerned that if we do switch expression blocks, we want to make sure that the we\ndon't block a future generalization to all expressions. We need to find a generalization that we\nlike, reject a generalization and accept this syntax, or put these improvements on the\nback-burner if we think that a generalization is possible, we just haven't found it.\n\nAccepted for C# 9.0 investigation.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-01-08.md",
    "content": "\n# C# Language Design Meeting for Jan. 8, 2020\n\n## Agenda\n\n1. Unconstrained type parameter annotation\n2. Covariant returns\n\n## Discussion\n\n### Unconstrained type parameter annotation T??\n\nYou can only use `T?` when is constrained to be a reference type or a value type. On the other\nhand, you can only use `T??` when `T` is unconstrained.\n\nThe question is what to use for the following:\n\n```C#\nabstract class A<T>\n{\n    internal abstract void F<U>(ref U?? u) where U : T;\n}\nclass B1 : A<string>\n{\n    internal override void F<U>(ref U?? u) => default; // Is ?? allowed or required?\n}\nclass B2 : A<int>\n{\n    internal override void F<U>(ref U?? u) => default; // Is ?? allowed or required?\n}\nclass B3 : A<int?>\n{\n    internal override void F<U>(ref U?? u) => default; // Is ?? allowed or required?\n}\n```\n\nOur understanding is that this would be:\n\n```C#\nabstract class A<T>\n{\n    internal abstract void F<U>(ref U?? u) where U : T;\n}\nclass B1 : A<string>\n{\n    internal override void F<U>(ref U?? u) => default; \n    // We think the correct annotation is\n    //  void F<U>(ref U? u) where U : class\n    // because the type parameter is no longer unconstrained. The `where U : class`\n    // constraint is required, as U? would otherwise mean U : struct\n}\n// We may want to allow U?? even in the above case, so\nclass B1 : A<string>\n{\n    internal override void F<U>(ref U?? u) => default; // allowed?\n    // This would not require the `where U : class` constraint because `U??` cannot\n    // be confused with `Nullable<U>`\n}\nclass B2 : A<int>\n{\n    internal override void F<U>(ref U?? u) => default;\n    // The correct annotation is\n    //  void F<U>(ref U u)\n    // We could allow\n    //  void F<U>(ref U?? u)\n    // although it would be redundant\n}\nclass B3 : A<int?>\n{\n    internal override void F<U>(ref U?? u) => default;\n    // The correct annotation is\n    //  void F<U>(ref U u)\n    // We could allow\n    //  void F<U>(ref U?? u)\n    // although it would be redundant\n```\n\nIn the above, we're wondering whether we should allow `??` without warning even in cases where\nthere's existing syntax to represent the semantics. One benefit is that you could write\n\n```C#\nabstract class A<T>\n{\n    internal abstract F<U>(ref U?? u) where U : T;\n}\nclass B1 : A<string>\n{\n    internal override F<U>(ref U?? u) { }\n}\n```\n\nSince the override cannot be confused with `U?`, there's no need for the `where U : class`. On the\nother hand, the benefit seems marginal and it's not needed to represent the semantics. It could\nalso be added later.\n\n**Conclusion**\n\nWe like the syntax `??` to represent the \"maybe default\" semantics. We think that `??` should be\nallowed in the cases where we have other syntax to represent the semantics. A warning will be\nprovided and hopefully a code fix to move the code to the \"more canonical\" form. The syntax `??`\nis only legal on type parameters in a nullable-enabled context.\n\nWe considered using the `?` syntax the represent the same semantics, but ruled it out for a couple reasons:\n\n1. It's technically difficult to achieve. There are two technical limitations in the compiler.\nThe first is design history where a type parameter ending in `?` is assumed to be a struct. This\nhas been true in the compiler all the way until nullable reference types in the last release. The\nsecond problem is that many pieces of C# binding are very sensitive to being asked if a type is a\nvalue or reference type and asking the question can often lead to cycles if asked before the answer\nis absolutely necessary. However, `T?` means different things if `T` is a struct or unconstrained, so\nfinding the safe place to ask is difficult.\n\n2. Unresolved design problems. In overriding `T?` means `where T : struct`, going back to the beginning of\n`Nullable<T>`. This already caused problems with `T? where T : class` in C# 8, which is why we introduced\na feature where you could specify `T? where T : class` in an override, contrary to past C# design where\nconstraints are not allowed to be re-specified in overrides. To accommodate overloads for unconstrained\n`T?` we would have to introduce a new type of explicit constraint meaning *unconstrained*. We don't have\na syntax for that, and don't particularly want one.\n\n3. Confusion with a different feature. If we use the `T?` syntax, the following would be legal:\n\n```C#\nclass C\n{\n    public T? M<T>() where T : notnull { ... }\n}\n```\n\nwhat you may think is that `M` returns a nullable reference type if `T` is a reference type, and a nullable\nvalue type if `T` is a value type (i.e., `Nullable<T>`). However, that's *not* what this feature is. This\nfeature is essentially *maybe default*, meaning that `T?` may contain the value `default(T)`. For a reference\ntype this would be `null`, but for a value type this would be the zero value, not `null`.\n\nMoreover, this seems like a useful feature, that would be ruled out if we used the syntax for something else.\nConsider a method similar to `FirstOrDefault`, `FirstOrNull`:\n\n```C#\npublic static T? FirstOrNull<T>(this IEnumerable<T> e) where T : notnull\n```\n\nThe benefit is that there is a single sentinel value, `null`, and that the full set of values in a struct\ncould be represented. In `FirstOrDefault`, if the input is `IEnumerable<int>` there is no way to distinguish\na non-empty enumerable with first value of `0`, or an empty enumerable. With `FirstOrNull` you can distinguish\nthese cases in a single call, as long as `null` is not a valid value in the type.\n\nDue to CLR restrictions it is not possible to implement this feature in the obvious way, so this feature may\nnever be implemented, but we would like to prevent confusion and keep the syntax available in case we ever\nfigure out how we'd like to implement it.\n\n### Covariant returns\n\nWe looked at the proposal in #2844.\n\nThere's a proposal that for the following\n\n```C#\ninterface I1\n{\n    object M();\n}\ninterface I2 : I1\n{\n    string M() => null;\n}\n```\n\n`I2.M` would be illegal as it is, because this is an interface *implementation*, not an\n*override*. Interface implementation would not change return types, while overriding would. Thus\nwe would allow\n\n```C#\ninterface I1\n{\n    object M();\n}\ninterface I2 : I1\n{\n    override string M() => null;\n}\n```\n\nwhich would allow the return type to change. However, it would override *all* `M`s, since\nexplicit implementation is not allowed.\n\n**Conclusion**\n\nWe like it in principle and would like to move forward. There may be some details around\ninterface implementation vs. overriding to work out."
  },
  {
    "path": "meetings/2020/LDM-2020-01-15.md",
    "content": "\n# C# Language Design Meeting for Jan. 15th, 2020\n\n## Agenda\n\n1. Working with data\n2. Record feature breakdown\n\n## Discussion\n\n### Working with data\n\nAs we discuss records, we want to go over a design document we produced a number of years ago\ncalled \"working with data.\" This document lays out how, when we design features, we inherently\nexpress a \"path of least resistance,\" which consists of the features that seem easiest or\nshortest to use to accomplish a given problem.\n\nLink: https://github.com/dotnet/csharplang/issues/3107\n\nThe document argues that, as we find particular patterns to be more effective at building\nsoftware, we should make the forms we find to be more effective simpler or shorter to express in\nthe language. We should not \"change\" our opinions, meaning make old syntax illegal, but we should\n\"level the playing field\" by making other forms simpler.\n\nThe conclusion of the design document is that we should favor\n\n    1. Immutable members in records by default\n    1. Any features from records that we separate should not make the simple syntax longer\n\n### Record feature breakdown\n\nWe've also been working on breaking down the individual features\nof records and determining how independent they can or should be.\n\nNotes: https://github.com/dotnet/csharplang/issues/3137\n\nThere seem to be the following somewhat separable parts of records\n\n1. Value-based equality\n2. Construction boilerplate\n3. Object initializers\n4. Nondestructive mutation\n5. Data-friendly defaults\n\n#### Value equality\n\nIt's been proposed that a `key` modifier could be applied to signal that value-based equality is\nbeing generated based on the members which have it. This works in many cases,\nbut if the absence of the `key` modifier means inherited equality, we're not sure\nthat's the semantics we want. It would also not allow value-based equality to be\n\"specified\" in the base class in some sense, enforcing value equality for the deriving\ntype. Whether this is valuable or blocking is an open question.\n\n#### Construction boilerplate\n\nCreating a constructor to assign members of a container is one of the largest sources\nof repetitive boilerplate, e.g.\n\n```C#\npublic class Point\n{\n    public int X { get; }\n    public int Y { get; }\n    public Point(int x, int y)\n    {\n        X = x;\n        Y = y;\n    }\n}\n```\n\nYou can imagine various points on this spectrum to simplify the boilerplate,\n\n```C#\npublic class Point\n{\n    public key int X { get; }\n    public key int Y { get; }\n    public Point(X, Y); // name matching and type absence implies initialization\n}\n```\n\nWhich removes the duplication of naming the same elements multiple times or,\n\n```C#\npublic class Point(X, Y)\n{\n    public key int X { get; }\n    public key int Y { get; }\n}\n```\n\nWhich removes the constructor name duplication and we could go further to remove\nproperty name duplication,\n\n```C#\npublic class Point(\n    public key int X { get; }\n    public key int Y { get; }\n);\n```\n\nGoing all the way to the original position deconstruction\n\n```C#\npublic class Point(int X, int Y);\n```\n\nWhere we pick a point in this space seems to correspond to the perceived benefits\nof the orthogonality of the feature. If the construction shorthand is useful for\nmany scenarios outside of the record scenarios, it's practical to expand it.\n\n### Object initializers\n\nOne benefit to object initializers is that they don't refer to a constructor directly,\nonly to the properties. This sidesteps a weakness in C#, where constructor initialization in inheritance requires repetition. Without constructors the simple\nrelation\n\n```C#\npublic abstract class Person\n{\n    public string Name { get; }\n}\npublic class Student : Person\n{\n    public string ID { get;}\n}\n```\n\nhas no repetition. Each class states only the properties that are essential, and\nfor derived classes all the base properties are inherited without repetition.\nOnce you add constructors this breaks down\n\n```C#\npublic abstract class Person\n{\n    public string Name { get; }\n    public Person(string name)\n    {\n        Name = name;\n    }\n}\npublic class Student : Person\n{\n    public string ID { get; }\n    public Student(string id, string name)\n      : base(name)\n    {\n        Id = id;\n    }\n}\n```\n\nNow the derived classes have to repeat everything from the base, causing brittleness\nalong the boundary. If we were to imagine some improvement to object initializers,\nthen defining a constructor would not be required.\n\nOn the other hand, this also removes one of the main benefits for having a constructor,\nnamely that you can validate the whole state of the object before producing it."
  },
  {
    "path": "meetings/2020/LDM-2020-01-22.md",
    "content": "\n# C# Language Design Notes for Jan. 22, 2020\n\n## Agenda\n\n1. Top-level statements and functions\n2. Expression Blocks \n\n## Discussion\n\n### Top-level statements and functions\n\nhttps://github.com/dotnet/csharplang/issues/3117\n\nThree main scenarios:\n\n1. Simple programs are simple -- remove the boilerplate for Main\n\n2. Top-level functions. Members outside of a class.\n\n3. Scripting/interactive. Submission system allows state preservation across evaluations.\n\nUnfortunately, some of these proposals interact in difficult ways.\n\nIf you write\n\n```C#\nint x = ...;\n```\n\nis `x` now a global mutable variable for the entire program? Or is it a\nlocal variable in a generated Main method?\n\n#### Proposal: Simple programs\n\nThe proposal is to prioritize (1) and (3) and remove boilerplate, while\nenabling use in scripting/interactive scenarios.\n\nTo address (1), we would allow a single file in the compilation to contain top-level statements,\nand any file to contain top-level local functions, which would be in scope in all files, but it\nwould be an error to refer to them.\n\nThere's wide consensus that (1) is very useful. There's the case of small programs, where you\nreally just want to write a few statements and not have to write the boilerplate of classes and\nMain. It's also a very large learning burden in that just to write \"Hello, World\" requires\nexplaining methods, classes, static, etc.\n\n(3) is also important partly because there are a number of products and scenarios\ncurrently using the scripting system. We should keep that in mind to make sure that\nwe don't prevent a large number of use cases from ever using the new system.\n\nWe think (2) is interesting and worth considering. It may not be the highest priority,\nbut we need to make sure we don't rule it out entirely. We also think that if we add\n(1) it seems likely that some people would want (2) much sooner.\n\nIf we do want to make space for (2) we should make sure to look at lookup rules very carefully.\nThe C# lookup rules are very complicated and including new ones for top-level members could\ninclude subtle ways that change new code.\n\nWhen we designed scripting we had experience that copying back-and-forth from interactive and the\nmain program is very useful and important. Because the syntax used here is similar to local\nfunctions and it's not currently proposed that accessibility modifiers are legal, this would\ncreate a difference when copying code between standard C# and the interactive dialect, since\npresumably those declarations would now be illegal.\n\n#### Block expressions\n\nhttps://github.com/dotnet/csharplang/issues/3137\n\nWe're revisiting the earlier discussions and there is a proposal for how we could\nmake blocks legal as expressions. The proposed precedence would be the lowest\npossible, so many ambiguities or breaking changes would be avoided.\n\nExamples:\n\n```C#\nvar x = { ; 3 };    // int x = 3\nvar x = { {} 3 };   // int x = 3\n```\n\nNote that a final expression is required, so the `'` or `{}` are necessary as \"starting\nstatements\".\n\nThe 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.\n\nSomething which was brought up before is whether to use a \"trailing expression\" to\nproduce a value, or introduce some sort of statement to produce the evaluation\nexpression. If we used a `break e;` syntax, the above could look like\n\n```C#\nvar x = { break 3; };\n```\n\nOne problem is turning the block into a lambda, where `break` would have to be changed to\n`return`. On the other hand, if this code were introduced directly into the method, `return`\nwould actually produce different, valid semantics. `break e;` would be an error in both contexts,\ninstead of producing different code.\n\nThe precedence doesn't have agreement. Some people think that the precedence is\nstill too high and that we should almost always require a parenthesized wrapper\nexpression, except in specific cases where we think it's clear. Other people think\nthat this is too low and they want to use them in more places.\n\n**Conclusion**\n\nWe don't think we have enough information about the restrictions we're working under. One way to\nmake progress would be to construct a list of the potential ambiguities in using the `{}` as an\nexpression term."
  },
  {
    "path": "meetings/2020/LDM-2020-01-29.md",
    "content": "\n# C# Language Design for Jan. 29, 2020\n\n## Agenda\n\nRecord -- With'ers\n\n## Discussion\n\nIn this meeting we'd like to talk about Mads's write-up of the \"With-ers\" feature, as it relates\nto records. Multiple variations have been proposed, but the suggestion generally takes the form\nof a `with` expression that can return a copy of a data type, with selective elements changed.\n\nWrite-up: https://github.com/dotnet/csharplang/issues/3137\n\nThe first thing we learned is that the fundamental problem we're trying to solve is\n\"non-destructive mutation.\"\n\nThere 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. \n\n1. Direct copy. We might call this \"copy-and-update\" because we copy the new data type exactly,\nthen update the new type with required changes. The basic implementation would be to use\nMemberwiseClone, and then overwrite select properties.\n\n2. Create a new type. we call this \"constructing through virtual factories.\" If the type supports\na constructor, this approach would call the constructor using the new values, or the existing\nones if nothing new is given. The construction would be virtual so that derived types would not\nlose state when called through the base type.\n\nThere are advantages and disadvantages to each proposal.\n\n(1) is simple but seemingly dangerous. There are often internal constraints to a type which must\nbe preserved for correctness. Usually this is enforced through the type constructor and\nvisibility of modification. That would not necessarily be available here.\n\n(2) does construction similar to conventional construction today, so it doesn't introduce as many\nsafety concerns. On the other hand, the contract looks a lot more complicated. To make the\nfeature seem simple on the surface, it looks like we imply a lot of implicit dependency. For\nexample,\n\n```C#\npublic data class Point(int X, int Y);\nvar p2 = p1 with { Y = 2 };\n```\n\nWould generate\n\n```C#\npublic class Point(int X, int Y)\n{\n    public virtual Point With(int X, int Y) => new Point(X, Y);\n}\nvar p2 = p1.With(p1.X, 2);\n```\n\nThe first requirement is that an auto-generated `With` method must have a primary constructor, in\norder to know which constructor to call. Alternatively, we could have a `With` method generated\nfor every constructor, although that would require a syntax to signal that `With` methods should\nbe generated in the absence of a primary constructor.\n\nThe compiler also needs to know that the `X` and `Y` parameters of the `With` method correspond\nto particular properties, so it can fill in the defaults in the `with` expression. Otherwise we\nwould need some way of signifying which of the parameters are meant to be \"defaults\":\n\n```C#\npublic class Point(int X, int Y)\n{\n    public virtual Point With(bool[] provided, int X, int Y)\n    {\n        return new Point(provided[0] ? X : this.X, provided[1] ? Y : this.Y);\n    }\n}\nvar p2 = p1.With(new bool { false, true}, default, 2);\n```\n\nWe also need to figure out which `With` method to call at a particular call site. One way is to\nconstruct an equivalent call and perform overload resolution. Another way would be to pick a\nparticular `With` method as primary, and always use that one in overload resolution.\n\nThis also has some of the same compatibility challenges that we've seen in other areas.\nParticularly, if you add members to the record, there will be a new `With` method with a new\nsignature. This would break existing binaries referencing the old `With` method. In addition, if\nyou add a new `With` method, the old one would still be chosen by overload resolution, if\noverload resolution is performed, as long as unspecified properties in the `with` expression are\ndefault values.\n\nOn the other hand, this is also a general problem with backwards compatibility overloads. We'll\nneed to investigate whether we want to add a general purpose mechanism for handling backwards\ncompatibility and if we want to introduce a special case for With-ers specifically.\n\nWhat all of the above interdependency implies is that we need a significant amount of syntax or\n\"hints\" about what to do during autogeneration. We previously expressed interest in providing\northogonality for as many of the \"record\" features as possible. A conclusion is that\nauto-generated With-ers require or suggest many of syntactic and semantic components of records\nthemselves. When we try to separate the feature entirely, we require user opt-in to specify the\n\"backing\" state of the With-er. This seems to imply that auto-generation should\nnot be a general, orthogonal feature, but a specific property of records.\n\nHowever, we don't have to give up orthogonality entirely. The requirements for auto-generated\nWith-ers doesn't imply anything about manually written With-ers. Auto-generation seems possible\nin records because the syntax ties the state to the public interface. Manual specification looks\njust like the components of records that can be written explicitly in regular classes, like\nconstructors themselves. If we do want to pursue this avenue, we should try to limit\nthe complexity of the pattern as much as possible. It's not too bad if it's fully\ngenerated by the compiler, but it can't be very complicated if we want users to write\nit themselves."
  },
  {
    "path": "meetings/2020/LDM-2020-02-03.md",
    "content": "\n# C# LDM for Feb. 3, 2020\n\n## Agenda\n\nValue equality\n\n## Discussion\n\nWe split our discussion between two proposals, which end up being very\nsimilar.\n\n### 'key' equality proposal\n\nhttps://github.com/dotnet/csharplang/pull/3127\n\nQ: Is comparing `System.Type`s slow? Does it require reflection?\n\nA: `typeof` does not require reflection and comparing `Type`s is fast.\n\nQ: Why use a KeyEquals method?\n\nA: To signify that value equals is used and delegate to the base equality,\nwhen the base opts-in to value equality. By having a well-known signature\nin metadata, no special attributes are required for derived types to discover\nthe pattern.\n\nQ: Is KeyEquals necessary? Can we use `EqualityContractOrigin` to figure\nout that the type implements value equality?\n\nA: Yes, that seems like it should work.\n\n*Discussion*\n\nThere's some concern that modifying the public surface area of the type\nitself without any type of modifier is too much magic. If we have some\nsort of modifier that goes on the type, in addition to the \"key\" members,\nit would be clear that the type implements value equality from the type\ndeclaration, in addition to the member declarations.\n\nThis dovetails into records as a whole in that it would allow the feature sets to be separable.\nIf a type could have value equality or be a record, the features could be combined to produce a\nvalue record, or the value equality could be left off to allow a record with reference equality.\nThere's some disagreement on whether this is a positive or a negative. If you view a record as\nappropriately having value equality, this is a negative, or vice versa.\n\n### 'value' equality proposal\n\nhttps://github.com/dotnet/csharplang/issues/3137\n\nThe most visible difference here is that `value` is the name of the modifier, instead of `key`.\nThis more accurately reflects the term \"value equality\", but it's unfortunate that we already\nhave the term \"value type\" which has a completely different meaning in the language.\n\nAt the moment the proposal also doesn't include the \"extra\" members, like a strongly\ntyped Equals, the `==`/`!=` operators, and `IEquatable` interface implementation.\n\nThere's an open question as to whether this feature is preferred for a discriminated\nunion scenario or not. We have two examples in Roslyn of discriminated unions, our\nsymbol tree and our bound tree, and they have almost completely different equality\ncontracts. "
  },
  {
    "path": "meetings/2020/LDM-2020-02-05.md",
    "content": "\n# C# LDM for Feb. 5, 2020\n\n## Agenda\n\n1. Dependent nullability attribute\n2. Null checking in unconstrained generics\n\n## Discussion\n\n### Nullability\n\nDependent calls:\n\nWe'd like to be able to support patterns like:\n\n```C#\nif (x.HasValue)\n{\n    x.Value // should not warn when HasValue is true\n}\n```\n\nWe would add attributes to support these use cases: `EnsuresNotNull` and `EnsuresNotNullWhen` (to parallel the existing `NotNull` attributes). The\nproposal as stands is to name the fields or properties and that would be\nthe inputs and outputs for the flow analysis. We propose that the lookup\nrules for resolving the names in these instances would be similar to the\nrules for the `DefaultMemberAttribute`.\n\nThis could also be used for helpers in constructor initialization, where today constructors which\nonly call `base` are required to initialize all members, even if a helper initializes some of the\nmembers.\n\nThere's a follow-up question: should you be able to specify that members of the parameter are\nnot-null after the call? For example,\n\n```C#\nclass Point\n{\n    public object? X;\n}\nstatic void M([EnsuresNotNull(nameof(Point.X))]Point p) { ... }\n```\n\nWe could also allow it for nested annotation\n\n```C#\nclass Point\n{\n    public object? X;\n}\nclass Line\n{\n    public Point P1;\n    public Point P2;\n}\nstatic void M([EnsuresNotNull(\"P1.X\", \"P1.Y\")]Line l) { ... }\nstatic bool M([EnsuresNotNullWhen(true, \"P1.X\", \"P1.Y\")]Line l) { ... }\n```\n\nThe nested names could also be used for return annotations.\n\nHowever, we're not sure this is worth it. We see the usefulness in theory,\nbut we're not sure how often it would actually be used. If we want to leave\nthe space for later, we could produce an error when writing an attribute with\nan unsupported string form.\n\nSimilarly, if we don't want to support referring to members of types through\nthe parameters, as in the first example, we can also provide an error for these\nscenarios. Or, we could say that the initial proposal is qualitatively different\nfrom all these scenarios:\n\n```C#\n[MemberNotNull(nameof(X))]\nvoid M() { }\n```\n\nFor the situations in parameters and return types we are referring to the target the attribute is\nbeing applied to, while the original proposal is returning to the containing type, somewhat\nunrelated to the location of the attribute.\n\nWe're also not sure exactly what the name or shape of these attributes would\nlook like. We think this could be valuable, but we'd like to decide with\nthe full context of other attributes we're considering.\n\n**Conclusion**\n\nWe see the usefulness of the original scenario, but the broadening we're not sure\non the return on investment. Let's support the original scenario through a new\nattribute, `MemberNotNull`, that only has members as valid attribute targets to start.\n\nIf we find users still hit significant limitations without the parameter and return\ntype support, we can consider broadening in a future release.\n\n### Pure non-null check in generic\n\n```C#\npublic T Id<T>(T t)\n{\n    if (t is null) Console.WriteLine();\n    return t; // warn?\n}\n```\n\nThe question here is whether we should consider `T` to move to `MaybeDefault` after\nchecking for `null`. We never do this today.\n\nThe scenario where a \"pure\" null check would come into play is:\n\n```C#\npublic T Id<T>(T t) where T : notnull\n{\n    if (t is null) Console.WriteLine();\n    return t;\n}\n```\n\nIt appears that this does not warn today, which looks like a bug. The analogous\nscenario for `T??` is\n\n```C#\npublic T ID<T>(T t)\n{\n    if (t is default) Console.WriteLine();\n    return t;\n}\n```\n\nHowever, this is illegal as there is no way to check if `T` is `default(T)`.\n\n**Conclusion**\n\nThe original scenario should not warn."
  },
  {
    "path": "meetings/2020/LDM-2020-02-10.md",
    "content": "\n# C# Language Design for Feb. 10, 2020\n\n# Agenda\n\nRecords\n\n# Discussion\n\nWe're continuing our attempt to draw out the dependencies and individual features inside records.\n\nWhen going through the list, what stands out is:\n\n- Looking at `with`, we need to figure out what's mentionable in the `with` expression.\n\n- We need to figure out exactly what we want for how primary constructors fit into records\n\nThere are a number of positives and negatives of primary constructors. On the negative side,\na non-record primary constructor seems to consume syntactic space that could be used for\nrecords. If we think that records are the overwhelmingly common scenario, then it seems like\nusing the shortest syntax for the most common feature is useful. On the positive side, primary\nconstructors alone seem to support a simpler way of writing private implementation details.\nSeparate from the value as a whole, there's some desire to have a special keyword just for\nrecords. That is, even if we didn't do primary constructors, it could be valuable to have\nan explicit modifier, like `data` to signify that this type has special behavior.\n\nOne possible pivot is to eliminate some composition syntax entirely, by creating a new type\nof declaration, `record`, e.g.\n\n```C#\nrecord Point(int X, int Y);\n```\n\nThis would be equivalent to the syntax that we've been discussing with `data`, namely\n\n```C#\ndata class Point(int X, int Y);\n```\n\nbut since the `class` keyword is implied by default, the most common scenario would be\njust about as short as the shorter `class Point(int X, int Y)` form.\n\n**Conclusion**\n\nAfter taking everything into account, we think having an new keyword for records is good both for\nleaving space for non-record primary constructors, and also to serve as a clear signifier of\nrecord semantics.\n\n"
  },
  {
    "path": "meetings/2020/LDM-2020-02-12.md",
    "content": "\n# C# Language Design for Feb 12, 2020\n\n## Agenda\n\nRecords\n\n## Discussion\n\n### Value equality\n\nProposal: use the `key` keyword previously mentioned, but also\nrequire it on the type declaration as well, e.g. \n\n```C#\nkey class HasValueEquality\n{\n    public key int X { get; }\n}\n```\n\nThere are a number of things we could pivot on\n\n```C#\nkey class HasValueEquality1 { public key int X { get; } }\nclass HasValueEquality2 { public key int X { get; } }\nkey class HasValueEquality3 { public key X { get; } }\nclass HasValueEquality4 : IEquatable<HasValueEquality4> { public int X { get; } }\n```\n\n----\n\n```C#\nrecord Point1(int X); // Implies value equality over X\nrecord Point2a(int X); // Implies inherited equality\nkey record Point2b1(int X); // Implies value equality over X\nkey record Point2b2a(int X); // Implies \"empty\" value equality\nkey record Point2b2b(key int X); // Implies value equality over X\n\n\nkey class Point3a(int X); // implies record + value equality over X\ndata class Point3b(int X); // implies record with inherited equality\n```\n\n#### Equality default\n\nWe originally considered adding value equality on records both because it's difficult to\nimplement yourself and it fits the semantics we built for records in general. We want to validate\nthat these things are still true, and new considerations, namely whether it is the appropriate\ndefault for records and whether it should be available to other types, like regular classes.\n\nWe left off in the previous discussion asking whether value equality is not just\nan inconvenient default, but actively harmful for key scenarios for records. Some examples\nwe came up with are either classes with large numbers of members, where value equality may\nbe unnecessary and slow, and circular graphs, where using value equality could cause\ninfinite recursion.\n\nThese do seem bad, but it's not obvious that these scenarios either fit perfectly with the\ncanonical record, or if the consequences are necessarily worse than default reference equality.\nCertainly producing infinite recursion in object graphs is bad, but silently incorrect behavior\ndue to inaccurate reference equality is also harmful, in the same sense. It's also easier\nto switch from value equality to reference equality than it is to switch from reference equality\nto value equality, due to the complex requirements in a value equality contract.\n\n**Conclusion**\n\nValue equality seems a reasonable default, as long as they are immutable by default, and that\nthere is a reasonable way to opt-in to a different equality.\n\n#### Separable value equality\n\nGiven that we like value equality as a default, we have to decide if we want a separable equality\nfeature as well. This is important for the scenario:\n\n```C#\nrecord Point1(int X)\n{\n    public int X { get; }\n}\n```\n\nif there's a separate `key` feature, we need to decide if the substituted property should\nrequire, allow, or disallow the `key` modifier, e.g.\n\n```C#\nrecord Point1(int X)\n{\n    public key int X { get; }\n}\n```\n\nWe also need to decide what such a \"separable\" equality feature would look like, and if it has a\ndifference between records and other classes. We could add a `key` feature for non-records, and\ndisallow `key` entirely in records. The members of a record equality would then not be\ncustomizable.\n\nThe individual `key` modifiers on non-records seem deceptively complicated.\n\nA common case is \"opt-in everything\". `key` modifiers wouldn't improve much on this, as they\nwould be necessary on every element. On the other hand, there are often computed properties that\nmay be seen as part of \"everything\", but not part of the equality inputs. The plus of record\nprimary constructors is that they identify the \"core\" inputs to the type.\n\nIndividual `key` modifiers also do not help with the large custom classes that are written today\nwhere it's easy to forget to add new members to equality. With a `key` modifier you can still\nforget to add the modifier to a new member.\n\nThese decisions play into records as a whole because they affect the uniformity of record and\nnon-record behavior. If records are defined by their \"parameters\", namely in this syntax the\nprimary constructor parameters and identically named properties, then no other members should\nbe a part of the equality. However, that would imply members in the body are not automatically\nincluded. For regular classes, it seems backwards. Members are not generally included, they have\nto be added specifically. \n\nOn the other hand, if we prioritize uniformity, general members in record bodies would be included\nin equality, which would harm a view of records as consisting primarily of the \"record inputs.\""
  },
  {
    "path": "meetings/2020/LDM-2020-02-19.md",
    "content": "\n# C# Language Design for Feb. 19, 2020\n\n## Agenda\n\nState-based Value Equality\n\n## Discussion\n\nProposal: https://github.com/dotnet/csharplang/issues/3213\n\n* We haven't decided (yet) to add support for value equality on all\n  classes (separate from records)\n\n* The behavior is actually that all fields _declared_ in the class are\n  members in the value equality, not all fields in the class (since inherited fields are not\n  included)\n\n    * Inheritance would be implemented using the previously described\n      proposals using the `EqualityContract` property\n\n* Records wouldn't behave differently, except that they have `value` by\n  default\n\n* The main difference with how records work in other places is that the semantics\nof a record is otherwise decided by the members of the primary constructor, while in this\nproposal the members of the record primary constructor have no special contribution to the value\nequality semantics\n\n* There's an evolution risk where we want to provide more complex things, like deep\nequality, but these features don't support enough complexity to add it. Instead, we end up just\nadding more keywords or more attributes. Consider array fields. The default equality is reference\nequality, but sequence equality isn't particularly rare. How would users customize that?\nA new keyword? Attribute? Writing Equals manually?\n\n  * Turns out we're finding a lot of customization pivots. String comparison is another one.\n    If we want to support all these scenarios attributes could be better. If we could use\n    attributes to supply an EqualityComparer that would be almost completely customizable.\n\n  * If equality is this complicated, should we only support simple generated equality for\n  records? Can we leave more complicated scenarios to tooling, like source generators?\n\nRecord equality: use the \"primary\" members or use all fields?\n\n* Using all the fields is consistent with how structs work\n\n* Using the \"primary\" members mirrors how the generation of `With` or other things\n  generated by a record with a primary constructor\n\n* There does seem to be a possibility that after you get to a certain size, positional\n  records are less useful. In that case we want a path to the nominal record. If we do want the\n  nominal path, it's generally desirable that we want as little \"record\" syntax as possible.\n  If we choose the struct \"use all the fields\" approach, then we could use exactly the\n  same mechanism for both the \"nominal\" and the \"positional\" records.\n\n* The nominal record syntax that has been floated is\n\n```C#\nrecord Point { int X; int Y; }\n```\n\nwhich generates\n\n```C#\nrecord Point\n{\n    public int X { get; init; }\n    public int Y { get; init; }\n}\n```\n\nAside from the shorthand for properties, this generates Equals, GetHashCode and some form\nof \"With\", which doesn't seem much different from proposals for a separable value equality. Is\nthere really much point in separating these proposals?\n\n* One completely opposite possibility: bypass the question by prohibiting private members in the\npositional record entirely\n\n**Conclusion**\n\nNo hard decisions yet. Leaning slightly towards using \"all declared fields\" as the metric for\nvalue equality. There's some support for the \"no private fields approach.\"\n"
  },
  {
    "path": "meetings/2020/LDM-2020-02-24.md",
    "content": "\n# C# Language Design for Feb. 24, 2020\n\n## Agenda\n\n1. Nominal records proposal\n\n## Discussion\n\n### Nominal records\n\nhttps://github.com/dotnet/csharplang/issues/3226 \n\nWe've been trying to leave space open for something we're calling \"nominal records\" where the\nconcept is that we establish some new system for constructing types based on names, instead of\nthe order of parameters in a constructor.\n\nHere we have a refreshed nominal records proposal to examine and consider.\n\nThe proposal says:\n\n> The main thing you lose out on with nominal construction is a centralized place - the\nconstructor body - for validation. Property setters can have member-wise validation, but\ncross-member holistic validation is not possible. However, for a feature such as records that is\nfor data not behaviors, that seems to be a particularly small sacrifice.\n\nWe don't necessarily agree that this is a small restriction, and there may be some way to add\nsupport for it.\n\nWhen it comes to the `With` we do need to decide what members are copied over in non-destructive\nmutation. One strategy is to use the \"surface area\" of the object, which is defined as the\nconstructor parameters, along with the public fields and properties that have some sort of\n\"setter\".\n\nAlternatively, we could copy over the state of the object. This would be equivalent to the use\nof the `MemberwiseClone` approach as we discussed in previous design meetings.\n\n**Conclusion**\n\nThere are many details to work out, but there's consensus that we want to investigate adding\nnominal records in the future.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-02-26.md",
    "content": "\n# C# Language Design Meeting for Feb. 26, 2020\n\n## Agenda\n\nDesign Review\n\n## Discussion\n\nToday is a design review, where we collect the design team, selected emeritus\nmembers, and a number of broad ecosystem experts to provide some \"in-the-moment\"\nfeedback to our current designs and their directions.\n\nToday we presented more of our thoughts on the top-level statements/\"simple programs\"\nfeatures and records.\n\n### Simple Programs \n\nWe have a prototype of simple programs. As per the existing spec, you can have\ntop-level functions among all files, and other statements in a single file.\n\nCollected feedback, not in any particular order:\n\n* Supporting local functions in files other than the top-level statement file doesn't\n  seem useful and could cause confusion. If there's a local function defined in a file\n  only with classes, it would appear that that function would be in scope for the\n  classes, according to C# lexical scoping conventions. However, since these are defined\n  as *local functions*, not top-level methods, it would be an error to use them inside\n  the class. Moreover, even if that confusion is resolved, there doesn't seem to be a\n  compelling reason to allow it in the first place. Because these functions are not\n  accessible from anything except the main statement file, it would be most likely to\n  want to put the functions in that file, next to the uses. The only benefit from allowing\n  local functions in separate file may be as a helper file that is linked into other\n  compilations. However, wrapping these utility functions in a class so they can be used\n  in more places seems like a small burden with big benefits. Once wrapped in a class,\n  these functions are simply methods like in C# today.\n\n* Mixing classes and statements in the same file could generate some confusion. The existing\n  design is that classes can see the variables created by statements, but it would be illegal\n  to reference them. This keeps the option open to allow access later. However, this could be\n  a confusing middle ground. To simplify the situation we could require only statements in the\n  top-level in one file (forcing all types to be declared in separate files). However, there is\n  interest in using utility classes in the top-level statements, perhaps especially with a\n  forthcoming records feature that provides simple, short syntax for declaring new types.\n\n* Many of these features mirror what we already have in CSX. It's good that our\n  current designs are similar and allow these constructs in more places, but since the semantics of\n  this design have subtle differences from CSX this would effectively create a third dialect of C#.\n  There's some desire to unify these worlds, but it's difficult. CSX is designed to allow all\n  values to be persisted, which is important for the scripting \"submission\" system, but this makes\n  a number of types of statements illegal that we have support for in the current design, like\n  ref locals. It also creates a burden for new designs, where statements need to be explicitly\n  designed for both CSX and C#. For example, the new `using var` declaration form is nonsensical\n  under the CSX design and probably should be illegal. Since the current 'simple programs' design\n  effectively treats statements like they are part of a method body, there's a cleaner semantic\n  parallel with C#, meaning less special-casing.\n\n### Records\n\nHere we presented a variety of different pieces of designs we have been thinking about.\n\n#### Nominal Record\n\nFeedback:\n\n* One of the biggest drawbacks of the current writeable-property style in C#, where types are\n  declared with public mutable properties that are then initialized using object initializers,\n  is that author can't enforce that certain properties are always initialized. It would be a\n  big disappointment if any \"nominal records\" feature that we built couldn't support this feature.\n\n* With the design as-is there's no way to validate the whole state of the object. However, that's\n  also true of the object-initializer style currently in use, and this doesn't seem to be as a big\n  of a problem for current users.\n\n#### Value Equality\n\n* Positive feelings on generating `.Equals(T)` and implementing `IEquatable<T>`, mixed feelings\n  on generating the `==` and `!=` operators.\n\n* If we opt-in the whole class using `value class`, we also need an opt-out for individual members.\n  Regular classes also often have somewhat specialized equality requirements, like wanting to compare\n  certain lists as sequence-equal, or compare strings ignoring case. This observation points to a\n  lot more customization points for value equality on general classes than value equality on records.\n\n* Using value equality on mutable state is seems dangerous if the type is used in a dictionary,\n  but despite the danger, other languages (Java, Go) have value equality for common types, like\n  lists, that can be easily added to a dictionary.\n\n* We don't currently have a robust mental model for what it means to be a \"value class.\" Is \"value\n  class\" a separable concept from \"implementing value equality,\" which people often do today? Or\n  is it not a different type of class, but simply a modifier signaling an implementation detail,\n  namely that the compiler generates value equality automatically. If we think of value equality\n  as a public contract, how does that change our view of existing code? Classes can currently\n  override Equals, but we don't distinguish what *kind* of Equals they provide. That isn't a\n  language concept, in a sense, but a part of the documentation.\n\n### Nominal Records\n\n* When using the `with` expression on nominal records, the generated parameter-less `With` method\n  looks a lot like `Clone`. It does little aside from return a new object with a shallow copy of\n  the state. If `With` is essentially Clone, why not use one of the existing forms of Clone that we\n  already have?\n\n  * ICloneable is deprecated and MemberwiseClone is protected. Maybe we should just call the method\n  Clone(), but not override or implement any of the other framework uses.\n\n* This feature looks a lot like structural typing from other languages, like Javascript's \"spread\"\n  operator, but that is not the feature we're currently trying to build. This is feature is still\n  about declaring new types, not providing some compatibility between existing types.\n\n* We spent a lot of time talking about validation and \"validators\", a very recent concept that was\n  floated as an alternative to constructors, executing after the `with` expression.\n\n  * There's some general concern about having no capability of validation, but no consensus on\n    exactly how validators should work.\n\n  * If validators work against the copied fields of the object, that seems to imply that the\n    fields are the state being operated on. On the other hand, only certain members can be\n    mentioned in the `with` expression. Why wouldn't those be the things that are copied? Instead\n    of all the state?\n\n\n\n"
  },
  {
    "path": "meetings/2020/LDM-2020-03-09.md",
    "content": "\n# C# Language Design for March 9, 2020\n\n## Agenda\n\n1. Design review\n2. Records\n\n## Discussion\n\n### Simple Programs\n\nIn the design review we covered the \"simple programs\" feature. A big piece of feedback is that\nthey didn't like the \"middle ground\" we had carved out with local functions. Right now we have\nlocal functions that can exist both in the top-level statement \"file\" and also across other\nfiles. Because the design allows only local functions at the top level, those functions are only\naccessible from and can only access the statements in the \"top-level statement file.\"\n\nThe feedback was that this would be an unfortunate design point. Organizing local functions in\nother files, when they can't be accessed by other files, is a big problem. There are two places\nwe could go with this. We could either pull back and allow many of these forms only in the\n\"top-level statement file.\" Or we could go the other way and allow more functionality at the top\nlevel, like allowing truly top-level members, including functions and variables, that can be\ndeclared and referenced from everything in the program.\n\nAllowing full top-level members is attractive but opens a lot of questions. The most important is\ntop-level variables. By allowing top-level variables and giving them the C# default of\nmutability, we would effectively be enabling mutable global variables. There is collective\nagreement that in everything but the smallest programs this is a bad programming practice and we\nshouldn't encourage it.\n\nWe could try to pivot on syntactic differences. One major difference between local variables and\nfunctions and member-level variables and functions is that members allow accessibility modifiers.\nTop-level statements could be, by default, local variables. Accessibility modifiers, `public`,\n`private`, `internal`, et al., could differentiate between top-level and local variables.\nHowever, this feels like it may be too subtle a design point, relying too much on minor syntactic\ndecisions to decide things like scoping.\n\nThe biggest takeaway is that this is a complex topic with a lot possibilities. Maybe we could try\nto carve out a small portion to make some progress, without committing to a narrow design for the\nentire space of \"top-level members.\" We generally like this approach, but CSX makes things\ndifficult. Since the existing design focuses on local variables and local functions,\ncompatibility with any sort of submission system is a problem. Fundamentally, we would need to\ndecide which pieces of state in a C# program are \"transient,\" in that they cannot be referenced\nfrom a new submission, and which are \"preserved.\"\n\nThe value still seems important enough to move forward. There's general agreement that top-level\nstatements are useful. Some people think they are useful in the simple form already presented,\nwhile other people want to see this as the starting point for a full feature, and these views are\nroughly compatible.\n\nIf we move forward with our subset, we need to flesh out the mental model for how it works.\nSpecifically, it's important to note why top-level variables and functions would be inaccessible\nfrom inside classes. One way to think about this is the difference between instance and static.\nWhen you're in a static context, all the instance variables are visible, but not accessible. You\ncould also model it as the statements are directly inserted into Main (which is true).\n\n**Conclusion**\n\nWe'd like to move forward with the prototype with the modification that top-level statements can\nonly appear in one file. Symbols declared in these statements would be visible, but an error to\naccess inside classes. All the top-level statements are treated as if they were inside an async\nMain method.\n\n### Value equality\n\nWhen we discussed records in the design meeting we brought up value equality for records and a\nproposal for extending to regular classes. A big shift was that records should have an easy\nglobal automatic value equality, while general classes should never have a global opt-in.\n\nThis seems contradictory, but if records have a set of default semantics that naturally fit value\nequality, then having it enabled by default is suitable. Value equality plays particularly well\nwith immutability. Since records strongly support immutable programming, supporting value\nequality is natural. For arbitrary classes, however, it's not clear at all how value equality\nshould behave. Opt-ing in either all or only some members seems to have downsides for many class\nexamples.\n\nWe're not ruling out value equality for regular classes, but for the future we'd like to examine\nspecifically how we'd like value equality to work for records. This could impact how and when we\nbring generated value equality to conventional user classes."
  },
  {
    "path": "meetings/2020/LDM-2020-03-23.md",
    "content": "\n# C# Language Design Meeting for March 23rd, 2020\n\n## Agenda\n\n1. Triage\n2. Builder-based records\n\n## Discussion\n\n### Triage\n\n#### Generic constraint `where T : ref struct`\n\nProposal: #1148\n\nThis is a very complicated area. It's probably not good enough to add this generic constraint,\nbecause things like default interface methods create a boxed `this` parameter. It's likely that\nwe would need runtime support to make this safe.\n\nThis is somwewhat related to the designs in the shapes/roles proposal in that it's about using\nthe \"shape\" of an interface, possibly with more restrictions than interfaces themselves. Since\nboth proposals may require runtime changes it would be valuable to batch up those changes\ntogether.\n\n##### Conclusion\n\nPush to at least C# 10.0. Should be considered in concert with the shapes/roles proposals.\n\n#### Improve overload resolution for delegate compatibility\n\nProposal: #3277\n\nThis is a parallel to changes we previously made to betterness where we remove overloads\nthat will later be considered invalid, to be removed from the overload resolution candidate\nlist in the beginning. This functionally will cause more overload resolution calls to succeed,\nsince invalid candidates will be removed and this will prevent overload resolution ambiguitiy.\n\n##### Conclusion\n\nTentatively added to C# 9.0. We'd like this proposal for function pointers, so if we were to\nimplement this for function pointers and correct overload resolution for delegates at the same\ntime, that would be desirable.\n\n#### Allow GetEnumerator from extension methods\n\nProposal: #600\n\nFirst thing is to confirm that there's no compat concern. When we tried to extend the behavior\nfor `IDisposable` we ran into a problem because `foreach` *conditionally* disposes things which\nmatch the `IDisposable` pattern. This means that if anything starts satisfying the pattern which\ndidn't before, an existing method may be newly called. If we ever conditionally use the `foreach`\npattern this would probably also be a breaking change.\n\n##### Conclusion\n\nWilling to accept it any time, as long as we confirm that it's not a breaking change.\n\n### Builder-based records\n\nWhen discussing records we've had various\ndesigns 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.\n\nWe have a proposal from a community member, @HaloFour, that lays out another example implementation strategy that we're using for discussion.\n\nhttps://gist.github.com/HaloFour/bccd57c5e4f3261862e04404ce45909e\n\nThere are certainly some advantages to this structure:\n\n* Uses existing valid C# to implement the pattern, making it compatible with existing compilers. If\nwe avoid usage of features like `ref struct` and `in`, it could be compatible for even older\nconsumers, since this would be binary compatible with C# 2.0 metadata.\n\n* Allows the type being built to always see the whole set of property values being initialized,\nmeaning that the author of the type can validate the new state of the object.\n\n* No new runtime support for any features (e.g., does not require covariant returns)\n\nThere are also some disadvantages.\n\nPerformance could be a problem. For classes, the biggest concern is stack size. Currently,\ninitializing a class with an object initializer only requires a single pointer on the class and\nthen each member is initialized separately, the initializer values don't all need to be on the\nstack simultaneously. If we use a struct builder, the entire builder needs to be on the stack\nbefore initialization.\n\nFor structs, there is the extra stack space cost, but having a builder also effectively doubles\nthe metadata size of the every struct. It's also potentially harder for the CLR to optimize the\ninitialization and remove dead stores through the double-struct passing. If we go forward with\nthis approach we should consult the JIT for their perspective.\n\nWe're also not sure that this approach fully eliminates all brittleness in adding/changing fields\nand properties across inheritance, especially if the inheritance is split across assemblies and\nonly one author is recompiled, or they are recompiled in a different order. If we can find a way\nto close those holes, or limit the feature to prevent these situations, that could be an\nimportant mitigating factor.\n\n#### Conclusion\n\nThere's a difficult balance here. Some members are focused on about performance, some prioritize\necosystem compat, and others prioritize \"cleanliness\" of design, in different directions. Almost\neveryone has a different priority and prefers different approaches for different reasons. We need\nto discuss things more and reduce some of the unknowns.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-03-25.md",
    "content": "\n# C# Language Design Meeting for March 25, 2020\n\n## Agenda\n\n1. Questions around the new `nint` type\n\n2. Target-typed new\n\n## Discussion\n\nIssue #3259\n\n### LangVersion\n\nTHe question is what the behavior of the compiler should be when seeing an `nint`\ntype in `langversion` C# 8. Our convention is that the compiler never preserves\nold *behavior* for older language versions. For instance, we do not preserve the\ncode for older code generation strategies and switch to that with the language\nversion flag. Instead, `langversion` is meant to be guard rails, providing\ndiagnostics when features are used that aren't available in older versions of the\nlanguage.\n\nThere are a few options we could take.\n\n1. Make an exception for `nint`, allowing them to be seen and compiled like an\n`IntPtr` in `langversion` C# 8.\n\n2. Make a wider divergence between `nint` and `IntPtr`. Adding a `modreq` to\nthe emitted `IntPtr` type would make them effectively unusable by older language\nversions and other languages.\n\n3. Preserve the behavior, as long as no new semantics are used. For instance,\nusing the arithmetic operators on `nint` and on `IntPtr` have different semantics.\nIt would be an error to use any of these operators in older language versions.\n\n**Conclusion**\n\nWe think (3) is the best balance.\n\n### `IntPtr` and `nint` operators\n\nWe have two proposals:\n\n1. Remove built-in identity conversions between native integers and underlying types and add explicit conversions.\n\n2. Remove `nint` operators when using the `IntPtr` type\n\n**Conclusion**\n\n(1) is a little too harsh. Let's do (2).\n\n### Behavior of constant folding\n\nThe concern is platform dependence.\n\nIn the following example\n\n```C#\nconst nint m = int.MaxValue;\nconst nint u1 = unchecked(m + 1);\n      nint u2 = unchecked(m + 1);\n```\n\nif the machine is 32-bit, then the result overflows. If the machine is 64-bit, it does not.\n\nWhile it's possible in the existing language to produce constant-folded values which are\nundefined, we don't think that behavior is desirable for nint.\n\nThe main contention is what to do in a `checked` context if we know the value will overflow\n32-bits. We could either produce an error, saying that this will overflow on some platforms,\nor produce a warning and push the calculation to runtime, warning that the calculation may\noverflow at runtime (and produce an exception).\n\n**Conclusion**\n\nWhenever we can safely produce a constant value under 32-bits, we do constant folding. Otherwise,\nthe result is non-constant, and under `checked`, the code produces a warning and the result\nis non-constant.\n\n### Interfaces on `nint`?\n\nShould interfaces on `IntPtr` and `nint` match? Or should `nint` only accept a certain set of\ncompiler-validated interfaces on `IntPtr`?\n\n**Conclusion**\n\nWe trust that interfaces will only be added to `IntPtr` with recognition that those interfaces\nalso affect `nint`. We'll make all interfaces on `IntPtr` available on `nint`, with `IntPtr`\noccurrences substituted for `nint`.\n\n## Target-typed `new`\n\nhttps://github.com/dotnet/csharplang/blob/master/proposals/target-typed-new.md\n\nClarification about library evolution: if a user uses `new()`, adding a constructor to a type\ncan produce an ambiguity. Similarly, if a method is called with `new()` that can produce an\nambiguity if more overloads of that method is added. This is analogous with `null` or `default`,\nwhich can convert to many different types and can produce ambiguity.\n\nThe spec currently specifies that there are a list of types where target-typed new is allowed. To\nsimplify, we propose that we specify that target-typed new should produce a fully-typed `new` and\nthe legality of that expression is defined elsewhere. This does make `new()` work on enums, which\nis currently proposed as illegal because it may be confusing. However, `new Enum()` is legal\ntoday, so we think that it should be allowed for target-typed `new` simply because of\nconsistency.\n\nThere's some debate on what it should do for nullable value types. On the one hand, the rule\n\"new() is just shorthand for writing out the type on the left,\" implies that the result should be\n`null`. On the other hand, the nullable lifting rules would imply that the base type of the\ntarget should be the underlying type, not the nullable type. Overall, we think that `new`ing the\nunderlying type makes the most sense, both because it's the most useful (we already have a\nshorthand for `null`) and because it's likely what the user intended.\n\nFor `dynamic`, we will not permit it simply because `new dynamic()` is also illegal.\n\nFinal thought: many thanks to @alrz for the great contribution!\n"
  },
  {
    "path": "meetings/2020/LDM-2020-03-30.md",
    "content": "\n# C# Language Design Meeting for March 30, 2020\n\n## Agenda\n\nRecords\n\n1. Builders vs init-only\n\n2. Possible conflicts with discriminated unions\n\n3. Value equality\n\n## Discussion\n\n### Builders vs. init-only\n\nWe discussed more of the tradeoffs of using builders vs using an \"init-only\" feature for records,\nand looked into requirements for other languages, including VB and F#. Based on our current\ndesigns, the work needed to consume the new features for \"init-only\" seem fairly small.\nRecognizing the `modreq` and allowing access to init-only members, and calling any necessary\n\"validator\" on construction, are pretty simple features for VB. VB already has the syntactic\nrequirements for the feature (object initializers), and we'd like to keep it possible for VB to\nconsume major changes in the API surface, if not write those new features. F# is undergoing\nactive development and changes are certainly viable there. Because the scope of changes is more\nopen-ended in F#, it's possible it could feature more implementation work.\n\nNotably, most of the features associated with \"init-only\" and \"validators\" do not require a new\nruntime, only a new compiler version. The new compiler version is necessary to recognize safety\nrules (validators must always be called after constructors, if they exist), but they don't use\nany new features in the CLR. The only feature potentially requiring runtime features is\noverriding a record with another record, which could potentially require covariant returns.\n\nThe remaining differences seem to come down to whether you can \"see\" the whole object during\ninitial construction (as opposed to validation). If you can see the whole object immediately,\nthat makes writing a `With` method that avoids a copy if all the values are identical very\nstraightforward. However, this could be done for \"init-only\" as well, by moving this semantic to\nthe `with` expression, optionally comparing the arguments to the `With` expression with the\nvalues on the receiver object and avoiding calling With if they are identical. Therefore we don't\nthink we're actually ruling anything out by going down the \"init-only\" route.\n\nThere are advantages in going down the \"init-only\" route instead. The performance for structs\nis probably better and more optimizable, and the IL pattern seems clearer and less bloated.\n\n**Conclusion**\n\nWe like the \"init-only\" IL better. Given the path forward for other languages and compatibility\nwith many runtimes, we think it's a better future as an IL pattern.\n\n### Conflicts with discriminated unions\n\nThere was a general question if these decisions could impact a future discriminated unions feature.\nWe don't have a lot in mind, but if we do end up building a discriminated union made of the records\nfeature, there is one component we may want to reserve. Discriminated unions often have a set of simple\ndata members. For instance, if we wrote a Color enum as a discriminated union, it could look like.\n\n```C#\nenum class Color\n{\n    Red,\n    Green,\n    Blue\n}\n```\n\nIf we reduce these to records, it may look like:\n\n```C#\nabstract class Color\n{\n    public class Red() : Color;\n    public class Green() : Color;\n    public class Blue() : Color;\n}\n```\n\nThe problem is: since those classes are effectively singletons, we'd like for the instances to be\ncached by the compiler, to avoid allocations. However, we don't currently have a syntax in C# that\nmeans \"singleton.\" Scala uses the \"empty record\" syntax to mean singleton. We need to decide if we'd\nlike to reserve that syntax ourselves, or find some other solution.\n\n### Value equality\n\nWe've decided that we want value equality by default for records. We need to settle on what that\nmeans. The primary proposal on the table is shallow-field-equality, namely comparing all fields\nin the type via EqualityComparer. This would match the semantic we have decided on for \"Withers,\"\nwhere the shallow state of the object is copied, similar to MemberwiseClone.\n\nThere's a large segment of the LDM that thinks doing anything except for field comparison is\nproblematic because it introduces far too many customization points for the record feature.\nAlmost all custom equality would have to deal with sequence equality and string equality, which\nare already very different mechanisms. There's a proposal that we could provide further\ncustomization via source generators, which could allow almost any customization.\n\nA follow-up to that is: why have value equality by default at all? Why not use source generators\nfor all value equality? One problem with that is that we want the simplest records to be very\nshort. The other problem is that we effectively have to pick an equality (C# will inherit one if\nyou don't). We previously decided that value equality is a non-controversial default -- if it's\nwrong it's probably not worse than when reference equality is wrong, and it's often better.\nStruct-like field-based equality is a simple and familiar version of value equality.\n\nWe also need to decide on value-equality as a separable feature for regular classes. Some people\nlike the idea of a separate feature and would be fine even with the constrained version that only\ncompares fields. Others don't think this feature meets the hurdles for a new language feature. If\nwe don't have customization options, it may be rarely used, and it seems possible that a source\ngenerator version could be the much more popular version. It's also worth noting that, as a\nseparable feature, we don't need to add separable equality now.\n\n**Conclusion**\n\nNo separable value equality for non-records, right now. Default record equality is defined as\nfield-based shallow equality."
  },
  {
    "path": "meetings/2020/LDM-2020-04-01.md",
    "content": "\n# C# Language Design Meeting for April 1, 2020\n\n## Agenda\n\n1. Function pointer calling conventions\n\n2. `field` keyword in properties\n\n## Discussion\n\n### Function Pointers\n\nThere are a few open issues and proposals for generalization of function pointers based on\nnew runtime features.\n\nhttps://github.com/dotnet/csharplang/issues/3324\n\n#### NativeCallableAttribute\n\nThe attribute already exists in the CLR, and allows for specifying a calling convention other than\n`managed` (which means that it can't be called from C#, but could be used from function pointers).\n\nThe question is what level of support we want to provide in the language for this attribute.\n\nSince the runtime behavior is to crash if the method is called incorrectly (meaning, invoked at\nall from C# if not through a function pointer), we almost certainly want to recognize the\nattribute's existence and provide errors for incorrect usage.\n\nWe considered more restrictions than the ones mentioned in the issue (only usable in function\npointers, parameters must be blittable, must be static) like restricted accessibility or special\nsyntax. The consensus is that is too much work for a small feature.\n\n**Conclusion**\n\n`NativeCallableAttribute` should be recognized and the restrictions are accepted, with the\naddition that generics are also prohibited in the method and all containing types, recursively,\nand delegate conversion is also prohibited.\n\n#### Supporting extra calling conventions\n\nThe existing proposal mandates that the only the existing calling conventions are supported. We\npreviously said we'd consider new calling conventions when they were proposed by the runtime. We now\nhave proposals about some likely new calling convention from the runtime.\n\nThe 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\nstarting with `CallConv` in a particular namespace, and passing through Unicode lower-case mapping.\n\n**Conclusion**\n\nAccepted.\n\n#### Attributes on function pointer types\n\nThe syntax is getting a bit verbose, but allowing an extra axis for customization seems like the\nsimplest extension of function pointers that provides the level support that the runtime may need\nin the future.\n\nCurrently our favored syntax is:\n\n```C#\ndelegate* cdecl[SuppressGCTransition, MyFuncAttr]<void> ptr;\n```\n\nThe attribute-like syntax would be turned into the `modreq`s on the function pointer type that\nwould be used by the runtime to encode special calling behavior. These would also effectively be\ndifferent types at the C# level and would not have implicit conversions between them.\n\n**Conclusion**\n\nAccepted, assuming there are no problems in implementation.\n\n### `field` keyword in properties\n\nOver the years there have been many requests for similar features, e.g.\nhttps://github.com/dotnet/csharplang/issues/140\n\nMaybe the simplest version is that there is a contextual identifier, e.g. `field`, which refers\nto an implicit backing field of the property. This seems useful, but a big limitation is that the\nbacking field of the property must have the same type as the property. If lazy initialization is\na common case, that seems likely to require differing property types, as the backing field would\noften be nullable, but the initialized field would be not nullable.\n\nOn the other hand, biting off too much in a single feature may delay simple scenarios\nunnecessarily. Should we try to address the simplest scenarios first, and leave more complex\nscenarios for later? In this case we probably need to find what scenarios are served by that\ndesign. Two things that are recognized are simple validation, e.g.\n\n```C#\npublic int PositiveValue\n{\n    get => field;\n    set\n    {\n         if (value < 0)\n            throw new ArgumentException(\"Cannot be negative\")\n        field = value;\n    }\n}\n```\n\nand registration like `INotifyPropertyChanged`\n\n```C#\npublic int P\n{\n    get => field;\n    set\n    {\n        PropertyChanged();\n        field = value;\n    }\n}\n```\n\nLet's confirm that these scenarios are the ones most commonly requested and that they aren't\naddressed or modified by any of the other scheduled language features, e.g. source generators for\nINotifyPropertyChanged. From there we can discuss the specific proposal with a better\nunderstanding of the problem and solution space."
  },
  {
    "path": "meetings/2020/LDM-2020-04-06.md",
    "content": "\n# C# Language Design Notes for April 6th, 2020\n\n## Agenda\n\nInit-only members\n\n## Discussion\n\nWe have a proposal to dive into: https://github.com/jaredpar/csharplang/blob/init/proposals/init.md\n\n* The proposal notes that you can set `init` fields of the base type during construction, similar\n  to `readonly`. This is not how `readonly` works today, only the declaring type can set readonly\n  fields\n\n* The proposal allows `init` on class and struct declarations as a shorthand for `init` on types.\n  This is different from how `readonly` struct works today, where there is no syntactic shorthand,\n  `readonly` simply adds the additional requirement that all instance fields are marked `readonly`.\n\n* For the runtime: does this feature prohibit runtime restrictions on setting `readonly` instance\n  fields in the future? Put simply: yes. To avoid breaking C#, the runtime would be required to\n  either respect the proposed `InitOnlyAttribute`, or restrict optimizations to not alter the code\n  for these features.\n\n* Use in interfaces: the proposal prohibits it, but the following example seems useful:\n\n  ```C#\n  interface I\n  {\n      int Prop { get; init set; }\n  }\n\n  public void MyMethod<T>() where T : I, new()\n  {\n      var t = new T() {\n          Prop = 1\n      };\n  }\n  ```\n\n* Signature compatibility: should `init` properties be compatible with mutable ones? That is, should\n  removing `init` in favor of a bare `set` be binary-compatible? This impacts our decisions for how\n  we think about safety in older compilers:\n\n  * If we use a modreq to prevent other compilers from unsafely using a `setter`, that affects the\n    signature of the method, and would make the above a breaking change\n\n  * If we want accept that older compilers are not a problem (C#, VB, and F# will all be updated),\n    perhaps we don't need to specially guard this at all\n\n  * We could use attributes to mark *and* guard, by using the `Obsolete` attribute. `ref struct`s\n    use this guard by having an Obsolete attribute with a reserved message, that is ignored by\n    compatible compilers.\n\n### Accessors\n\nShould we allow three accessors: `get, set, init`? A big problem here is that you can end up\ncalling instance members in a constructor that invoke the setter, not the initter, for a\nproperty. This means that there are few, if any, invariants that hold for init vs. set, and\nweakens the feature significantly.\n\n### Syntax\n\n`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\nwith properties, where `readonly` isn't allowed at all, and the shorter `init` keyword seems more similar to\n`get` and `set`\n\n  * Usage of `init` as a modifier: there are a number of different meanings here, and similarities\n  between `readonly` and `init` is separating the more places we use it. For instance, if `init` is\n  allowed as a member modifier, it seems similar to `readonly` on members, but they actually do\n  different things. Moreover, `readonly` on types means that all instance fields and methods are\n  `readonly`, while `init` on types would only mean `init` on fields, not on methods.\n\n  * What are the uses for `init` methods, aside from helper methods? Could they be used in collection initializers?\n\n### Required Initialization\n\nThe proposal in this doc is that required initialization is also an important feature for setters. We're\ngoing to leave that discussion for a future meeting. As proposed, nullable warnings are not modified for\n`init` members.\n\n**Conclusions**\n\nNo `init` on types. No agreement on syntax. We probably have to talk about more of the use cases.\nWe've decided that having three different accessors is not helpful. Settled that we will place a\n`modreq` on all `init` setters.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-04-08.md",
    "content": "\n# C# Language Design for April 8, 2020\n\n## Agenda\n\n1. `e is dynamic` pure null check\n2. Target typing `?:`\n3. Inferred type of an `or` pattern\n4. Module initializers\n\n## Discussion\n\n### `e is dynamic` pure null check\n\nWe warn that doing `e is dynamic` is equivalent to `e is object`, but `e is object` is a pure\nnull check, while `e is dynamic` is not. Should we make `is dynamic` a pure null check for\nconsistency?\n\n**Conclusion**\n\nYes.\n\n### Target-typing `?:`\n\nThe simplest example where we have a breaking change is\n\n```C#\nvoid M(short)\nvoid M(long)\nM(b ? 1 : 2)\n```\n\nPreviously this would choose `long`, because the expressions are effectively typed separately,\nand when inferring `1 : 2` we would choose `int`, and then rule out `short` during overload\nresolution as invalid.\n\nTarget-typing converts each arm in turn to find the best possible type, selecting `short` instead\nof `long`. That means the first overload is selected instead with target-typing.\n\nIt's hard to easily avoid this breaking change. The obvious mechanism, running overload\nresolution twice, is problematic because having multiple arguments with `conditional` expressions\nproduces exponential growth in the number of passes of overload resolution.\n\n**Conclusion**\n\nLet's talk about this again in a separate meeting. Since whatever we choose here will probably\nbe the final decision (any further changes will be breaking), we want to be sure we're making the\nbest choice.\n\n### Inferred type of an `or` pattern is the common type of two inferred types\n\n```C#\nobject o = 1;\nif (o is (1 or 3L) and var x)\n    // what is the type of `x`?\n```\n\nThe problem here is that the existing common type algorithm allows conversion that are forbidden\nin pattern matching. In the above case we would choose `long`, because `3L` is a long, and `1`\ncan be converted to `long`. However, in pattern matching the widening conversion from `int` to\n`long` is illegal.\n\nThe proposal is to narrow the set of conversions only to implicit reference conversions or\nboxing conversions. Why this could be useful is the example\n\n```C#\nclass B { }\nclass C : B { }\nif (o is (B or C) and var x)\n    // x is `B`\n```\n\nA follow-up question is about ordering. The proposed rules only infer types mentioned in\nthe checks, meaning that the following\n\n```C#\nif (o is (Derived1 or Derived2 or Base { ... }) and var x)\n```\n\nlooks like this today\n\n```C#\n((Derived1 or Derived2) or Base)\n\n-> ((object) or Base)\n\n-> (object)\n```\n\nOn the other hand, if the example were parameterized in the opposite way,\n\n```C#\n(Derived1 or (Derived2 or Base))\n\n-> (Derived1 or (Base))\n\n-> (Base)\n```\n\nSo the ordering seemingly matters if the `or` pattern is a simple binary expression.\n\nThe first question is if\n\n```C#\nif (o is (Derived1 or Derived2 or Base { ... }))\n```\n\nshould produce `Base`, and the second question is if parenthesizing affects this, e.g. explicitly saying\n\n```C#\nif (o is ((Derived1 or Derived2) or Base { ... }))\n```\n\nproduces `object`.\n\n**Conclusion**\n\nWe're not seeing a lot of scenarios that depend on these features, but not doing it feels like\nleaving information on the table. Functionally, the compiler can infer a stronger type, so why\nnot do so? The proposed modified common type algorithm is accepted.\n\nWe also think that type narrowing for the `or` operation should use all the `or` operations\nin a series as the arguments to the common type algorithm.\n\n### Module Initializers\n\nProposal: https://github.com/RikkiGibson/csharplang/blob/module-initializers/proposals/module-initializers.md\n\nThere are a few places where module initializers today. The most common is a shared resource\nthat is used by multiple types, but the program would like to initialize the shared resource\nbefore the static constructors of the types are run.\n\nThe question for the implementation is to how to indicate where the code for the module\ninitializer will go, and how the compiler will recognize it.\n\nThe proposal provides a mechanism to identify the module initializer via an attribute on the module\nthat points to a type, and type contains a static constructor that acts as the module initializer.\nFrom a conceptual level, this seems more complicated than necessary. Can we put the attribute on the\ntype or, even the method, that holds the code for the module initializer?\n\nIf we go that route, why require the code be in the static constructor at all? Can any static method\nbe a target? One reason why we may prefer a static constructor is that if the emitted module initializer\ncalls the target static constructor method, it's easy to insert code before that method is invoked\nby writing a static constructor for the containing type. On the other hand, even static constructor\ncan have code inserted before them, for example with static field initializers.\n\nThe last question is whether to allow only one module initializer method, or allow multiple and specify\nthat the compiler will call them in a stable, but implementation-defined order.\n\n**Conclusion**\n\nLet's let any static method be a module initializer, and mark that method using a well-known attribute.\nWe'll also allow multiple module initializer methods, and they will each be called in a reserved, but\ndeterministic order."
  },
  {
    "path": "meetings/2020/LDM-2020-04-13.md",
    "content": "# C# Language Design for April 13, 2020\n\n## Agenda\n\n1. Roadmap for records\n2. Init-only properties\n\n\n# Roadmap for records\n\nWe 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?\n\nTwo demanding aspects of records that are certainly important but can probably be done later are:\n\n1. Primary constructors (allowing positional parameters directly on record types)\n2. Inheritance to and from record types\n\nSo a proposal is to split those off in the first iteration of implementation.\n\n## Decision\n\nWe do need to get those right to ultimately ship the feature! However, we want to start by building a version of records that:\n* Is nominal only (no primary constructor)\n* Inherits from object and can't be inherited from\n* Special-cases `with` expressions to `With` methods rather than rely on a \"Factory\" feature\n* Fully implements value equality\n\nFor 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.\n\nIn subsequent iterations we will\n* Add support for inheritance to records\n* Add primary constructors to records\n* Generalize the `With` implementation to use factories\n* Decide on and embrace defaults (`public` by default?) and abbreviations\n\nOn parallel tracks we will work on:\n* Factory methods\n* Validators?\n* Mandatory properties?\n* Primary constructors as a general feature?\n\n\n# Init-only members\n\nInit-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.\n\n## Should we have init-only fields? \n\nReadonly 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.\n\nWe 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.\n\nAllowing 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.\n\n### Decision\n\nLet's allow init-only property setters (and validators, if and when we add them) to assign to `readonly` fields of the same object. \n\nLet'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.\n\n## Syntax\n\nShould 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?\n\nShorter 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).\n\n### Decision\n\n`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`.\n\n## Init-only indexers\n\nIndexers also have `set` accessors. Should they also be allowed to declare an `init` accessor instead?\n\n### Decision\n\nIt makes perfect sense, is somewhat useful, would be more regular in the language, and has straightforward semantics. Let's do it.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-04-15.md",
    "content": "﻿# C# Language Design Notes for Apr 15, 2020\n\n## Agenda\n\n1. Non-void and non-private partial methods\n2. Top-level programs\n\n# Non-void, non-private partial methods\n\nProposal: https://github.com/dotnet/csharplang/issues/3301.\n\nCurrently, 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.\n\nWith 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.\n\nThe 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.\n\nMain 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.\n\nOne 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.\n\nAnother 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?\n\n## Decision\n\nDespite 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.\n\nOn 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.\n\n# Top-level statements\n\nProposal: https://github.com/dotnet/csharplang/blob/master/proposals/Simple-programs.md\n\nWe took a look at the currently implemented semantics to make sure we are happy with them. A couple of questions came up:\n\n## Expressions at the end\n\nPart 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.\n\n### Decision\n\nWe are ok with this remaining distance, and would prefer not to have a notion of \"expression at the end produces result\" in C#.\n\n## Shadow and error\n\nThe 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.\n\n### Decision\n\nThis 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.\n\n## Args\n\nCurrently 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.\n\nFor 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.\n\nThere are ideas to:\n- add a new API that looks more like `args` (e.g. `Something.Args`) and behaves the same way\n- 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.\n\n### Decision\n\nWe think this is important to pursue further, but aren't going to hold up the feature for it.\n\n## Await triggers a different signature\n\nIn 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.\n\nAn 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.\n\n### Decision\n\nWe stick with the current design.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-04-20.md",
    "content": "\n# C# Language Design Meeting for April 20, 2020\n\n## Agenda\n\nRecords:\n\n1. Factory methods\n\n## Discussion\n\nThe proposal at its core is to allow certain methods to opt-in to certain language semantics\nthat are only currently valid at construction, namely object initializers, collection\ninitializers, and the new `with` expression (although that expression is legal on only certain\nfactory methods).\n\nPossible extension of the feature: allow initializer forms everywhere, but only allow `init`\nproperties to be initialized when the method is marked with `Factory`. However, almost all uses\nof this syntax would be a mutation of the receiver, and it may not be clear that the initializer\nsyntax produces a mutation.\n\nAs to whether `null` should be a valid return: most people think no. Since almost all initializer\nforms dereference the receiver, this is essentially creating a very obscure way of producing\nexceptions. In addition, all struct values should be permitted, as they are all safe. `default`\nshould be legal if the target type is known to be a struct. We have not considered what the\nbehavior should be for unconstrained generics.\n\nThere also some concerns about the syntactic extensions. First in that this would make `identifier {\n... }` a valid syntactic form in most situations. This may not be syntactically ambiguous today,\nbut we have a lot of different features, like `block expressions`, which share some syntactic\nsimilarity. Even if there is no syntactic ambiguity, some people are still concerned that the feature\nwill be too opaque. One way to remedy this would be to require the `new` keyword for this form as well.\nSo the new syntax would be:\n\n```C#\nvar s = new Create() { Name = \"Andy\" };\n```\n\nThere could be some naming ambiguity here because `Create` could be either a factory method or a\ntype name. We would have to preserve the interpretation as a type here for compatibility.\n\nThere's a broader question of how or if we'd like a general initializer feature. There's some\nquestion of whether the feature is useful enough to deserve the complexity at all, using any\nadditional syntax. Alternatively, we could embrace the syntax requiring the `new` keyword.\n\nOne important piece of history is that initializers are not meant for mutating existing state,\nonly for mutating new objects. This doesn't necessarily conflict with allowing initializers on\nany object, but the reason here is not that the language is suggesting using object initializers\nfor arbitrary mutation, but that convention alone is good enough to promote use on \"new\" objects\nonly.\n\nRegardless of the extensions of the feature, we certainly need to implement something for\nrecords. The core feature requirement here is for the `with` expression, which needs to assign to\n`init` fields. We can head two directions: special case the `Clone` method, or build a more general\nfeature. This is a spectrum, where one end may be a new syntactic form specific to just the Clone\nmethod, and the other end could be a `Factory` attribute that could be applied to any method.\n\n### Conclusion\n\nRight now we're more concerned with what to do for records. In the meantime, let's not support\nuser-written Clone methods. A Clone method will be generated for a record with an unspeakable type\nand the SpecialName flag. The `with` expression will look for exactly that method name. We intend\nto decide for C# 9 how that method will be written in source. We'll consider broader `Factory`\nscenarios later.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-04-27.md",
    "content": "\n# C# Language Design Meeting for April 27, 2020\n\n## Agenda\n\n1. Records: positional\n\n## Discussion\n\nThe starting point for positional records is how it fits in with potential\n\"primary constructor\" syntax. The original proposal for primary constructors\nallowed the parameters for primary constructors to be visible inside the class:\n\n```C#\nclass MyClass(int x, int y)\n{\n    public int P => x + y;\n}\n```\n\nWhen referenced, `x` and `y` would be like lambda captures. They would be in\nscope, and if they are captured outside of a constructor, a private backing\nfield would be generated.\n\nOne consequence of this design is that the primary constructor must *always*\nrun. Since the parameters are in scope throughout the entire class, the primary\nconstructor must run to provide the parameters. The proposed way of resolving\nthis is to require all user constructors to call the primary constructor, instead\nof allowing calls to `base`. The primary constructor itself would be the only\nconstructor allowed (and required) to call `base`.\n\nThis does present a conundrum for positional records. If positional records support\nthe `with` expression, as we intended for all records, they must generate two constructors:\na primary constructor and a copy constructor. We previously specified that the copy\nconstructor works off of fields, and is generated as follows\n\n```C#\nclass C\n{\n    protected C(C other)\n    {\n        field1 = other.field1;\n        ...\n        fieldN = other.fieldN;\n    }\n}\n```\n\nThis generated code violates the previous rule: it doesn't call the primary constructors.\nOne way to resolve this would be to change the codegen to delegate to the primary constructor:\n\n```C#\nrecord class Point(int X, int Y)\n{\n    protected Point(Point other) : Point(other.X, other.Y) { }\n}\n```\n\nThis is almost identical, except that the primary constructor may have side-effects, or the\nproperty accessors may have side-effects, if user-defined. We had strong opinions against using\nthe accessors before because of this -- we couldn't know if the properties were even\nauto-properties and whether we were duplicating or even overwriting previous work.\n\nHowever, we note that violating the rule for our generated code shouldn't be a problem in\npractice. Since the new object is a field-wise duplicate of the previous object, if we assume\nthat the previous object is valid, the new object must be as well. All fields which were\ninitialized by the primary constructor _must already be initialized_. Thus, for our code\ngeneration it's both correct and safer to keep our old strategy. For user-written constructors\nwe can require that they call the primary constructor, but because the user owns the type, they\nshould be able to provide safe codegen. In contrast, because the compiler doesn't know the full\nsemantics of the user type, we have to be more cautious in our code generation.\n\nThis doesn't really contradict with our goal of making a record representable as a regular class.\nA mostly-identical version can be constructed via chaining as described above. The only\ndifference is in property side effects, which the compiler itself can’t promise is identical, but\nif it were written in source then the user could author their constructor to behave similarly.\n\nProperty side-effects have an established history of being flexible in the language and the\ntooling. Property pattern matching doesn't define the order in which property side effects are\nevaluated, doesn't promise that they even will be evaluated if they’re not necessary to determine\nwhether the pattern matches, and doesn't promise that the ordering will be stable. Similarly, the\ndebugger auto-evaluates properties in the watch window, regardless of side effects, and the\ndefault behavior is to step over them when single stepping. The .NET design guidelines also\nspecifically recommend to not have observable side effects in property evaluation.\n\nWe now have a general proposal for both how positional records work, and how primary constructors\nwork.\n\nPrimary constructors work like capturing. The parameters from the primary constructor are visible\nin the body of the class. In field initializers and possibly a primary constructor body, they are\nnon-capturing, namely that use of the parameter does not capture to any fields. Everywhere else\nin the class, the parameters are captured and create a private backing field.\n\nPositional records work like primary constructors, except that they also generate public\ninit-only properties for each positional record parameter, if a member with the same signature\ndoes not already exist. This means that in field initializers and the primary constructor body,\nthe parameter name is in scope and shadows the properties, while in other methods the parameter\nname is not in scope. In addition, the generated constructor will initialize all properties with\nthe same names as the positional record parameters to the parameter values, unless the\ncorresponding members are not writeable.\n\n#### Conclusion\n\nThe above proposals are accepted. Both positional records and primary constructors are accepted\nwith the above restrictions. In source, all non-primary constructors in a type with a primary\nconstructor must call the primary constructor. The generated copy constructor will not be\nrequired to follow this rule, instead doing a field-wise copy. The exact details of the scoping\nrules, including whether primary constructors have parameters that are in scope everywhere, or\nsimply generate a field that is in scope and shadows the parameter, is an open issue.\n\n### Primary constructor bodies and validators\n\nWe do have a problem with some syntactic overlap. We previously proposed that our original\nsyntax for primary constructor bodies could be the syntax for a validator. However, there\nare reasons why you may want to write both. For instance, constructors are a good way to\nprovide default values for init-only properties that may be overwritten later. Validators\nare still useful for ensuring that the state of the object is legal after the init-only.\nIn that case we need two syntaxes that can be composed. The proposal is\n\n```C#\nclass TypeName(int X, int Y)\n{\n    public TypeName\n    {\n        // constructor\n    }\n\n    init\n    {\n        // validator\n    }\n}\n```\n\nTo mirror the keyword used for init-only properties, we could use the `init` keyword\ninstead. This would also hint that validators aren't *only* for validating the state,\nthey can also set init-only properties themselves. To that end, we have a tentative name:\nfinal initializers.\n\n#### Conclusion\n\nAccepted. `type-name '{' ... '}'` will refer to a primary-constructor-body and `init '{' ... '}'` is\nthe new \"validator\"/\"final initializer\" syntax. No decisions on semantics.\n\n### Primary constructor base calls\n\nGiven that we have accepted the following syntax for primary constructors and primary constructor bodies,\n\n```C#\nclass TypeName(int X, int Y)\n{\n    public TypeName\n    {\n\n    }\n}\n```\n\nhow should we express the mandatory base call? We have two clear options:\n\n```C#\nclass TypeName(int X, int Y) : BaseType(X, Y);\n\nclass TypeName(int X, int Y) : BaseType\n{\n    public TypeName : base(X, Y) { }\n}\n```\n\nWe mostly like both. The first syntax feels very simple and it effectively moves the \"entire\"\nconstructor signature up to the type declaration, instead of just the parameter list. However,\nwe don't think that class members would be in scope in the argument list for this base call\nand there are some rare cases where arguments to base calls may involve calls to static private\nhelper methods in the class. Because of that we think the second syntax is more versatile and\nreflects the full spectrum of options available in classes today.\n\n#### Conclusion\n\nBoth syntaxes are accepted. If prioritization is needed, the base specification on the primary\nconstructor body is preferred.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-05-04.md",
    "content": "# C# Language Design for May 4, 2020\n\n## Agenda\n\nDesign review feedback\n\n## Discussion\n\nWe had a design review on 2020-04-29 to bring our latest designs to the full review team and get\nfeedback. Today we went over the feedback and how it would affect our design.\n\n### Final initializers\n\n    - Design review said it was very complicated, when do I use an initializer vs a constructor?\n\nA possible fix would be to try to run initializers *before* constructors, instead of after. The\nmain problem is that this is not where object initializers (using setters) run today. It would be\nvery distasteful to have `init-only` setters run at a different time from regular setters, and\nworse to subtly run the setters at a different time just because of the presence of a different\n`init-only` field.\n\nThis is a difficult piece of feedback to reconcile, because it doesn't present a clear direction.\nHowever, we're not sure we need to finish the design for final initializers now. We still think\nthe scenarios are useful, but there are many scenarios which don't rely on those semantics. One\nof the most important scenarios that we were worried about was how to copy a type that had\nprivate fields that should not be copied. One proposal was to write a final initializer which\neither resets certain fields, or `throw`s if the state is invalid. Our proposed alternative for\nthis situation is to write your own copy constructor, which sets up the appropriate state for the\ncopy.\n\nHowever, final initializers do address a significant shortfall in existing scenarios, namely that\nthere's no way to validate a whole object in a property setter (or initter). In that sense we do\nhave many existing issues, separate from our records designs, which would be addressable with the\nfeature. There is also no way to validate an object after a `with` expression since necessarily.\n\n### Factory methods\n\nThe review team agreed about the necessity of \"factory\" semantics in the `with` expression, namely\nthat the with expression essentially requires a `virtual` Clone method to work correctly through\ninheritance, but was not convinced that the feature was generally useful.\n\nWe're also not convinced that it's generally useful, but limiting `with` to only be usable on a\nrecord is a significant change from where we were before, where records are currently fully\nrepresentable as regular classes.\n\nWe need to consider if we are willing to live with this limitation, or need a way of specifying\nthe appropriate `Clone` method in source.\n\n### Structs as records\n\nCan every struct be a record automatically? We don't need a `Clone` method, because structs\nalready copy themselves and they already implement value equality (albeit sometimes\ninefficiently). If we take this stance, would we want to explicitly design records as \"struct\nbehavior for classes?\" If that's true, we would seek to use the behavior of structs as a template\nfor records.\n\n### Positional records\n\nThe feedback was negative about making a primary constructor parameters different from positional\nrecord parameters. The proposal during the design meeting was that primary constructors would see\nparameters as \"captured\" in the scope of the class, while records would generate public\nproperties for each parameter. This is a big semantic divergence, as expressions like\n`this.parameter` would be legal in the body of a positional record, but illegal in the body of a\nclass with a primary constructor. One way of shrinking the semantic gap would be to always\ngenerate members based on primary constructor parameters, but in regular classes those members\nwould be private fields, while in records they would be public init-only properties. Even this\nsemantic difference was perceived as too inconsistent.\n\nWe have two proposals to unify the behavior inside and outside of records. On one end, we could\ntry to view primary constructors as a syntactic space to contain more elements. By default,\nprimary constructors would be simple parameters, which could be closed over in the class body. By\nallowing member syntax in the parameter list, the user would have more control over the\ndeclaration. For instance,\n\n```C#\npublic class Person(\n    public string Name { get; init; }\n);\n```\n\nwould generate a public property named `Name` instead of simply a parameter and the property\nwould be implicitly assigned in the constructor.\n\nOn the other hand, we could _always_ make public properties, abandoning the idea of\nprimary-constructor-parameters-as-closures. In this formulation,\n\n```C#\nclass C(int X, int Y);\n```\n\nwould generate two properties, X and Y. If this is made into a record e.g., `data class C(int X,\nint Y)`, then the same record members would be synthesized as in a nominal record.\n\nWe did not settle on a conclusion, but have a rough sense that having a primary constructor\nalways generate properties is preferred.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-05-06.md",
    "content": "# C# LDM for May 6, 2020\n\n## Agenda\n\n1. `if (e is not int i)`\n2. Target-typed conditional\n3. Extension GetEnumerator\n4. `args` in top-level programs\n\n## Discussion\n\n### `if (e is not int i)`\n\nhttps://github.com/dotnet/csharplang/issues/3369 \n\nThere are broader features that we'd to consider here as well, for instance allowing\nsome declarations below `or` patterns. However, this should be compatible with broader\nchanges and is easy to implement right now.\n\n#### Conclusion\n\nAccepted for C# 9. Further elaborations will be considered, assuming the schedule could\naccept it.\n\n### Target-typed conditional\n\nWe still unfortunately have a breaking change here with\n\n```C#\nM(b ? 1 : 2, 1); // calls M(long, long) without this feature; ambiguous without this feature\n\nM(short, short);\nM(long, long);\n```\n\nAs always, breaking changes are very worrying, unless we are confident that almost no real-world\ncode would be broken. If the breaking change results in an ambiguity instead of silent different\ncodegen, that is substantially better, as people would at least know that the compiler changed\nbehavior. At the moment, we only think that this change could result in new ambiguities, not\ndifferent behavior.\n\n#### Conclusion\n\nWe'll do some more investigation, try to find code that would be broken, and see if we can accept\nthe change.\n\n### Extension GetEnumerator\n\nhttps://github.com/dotnet/roslyn/issues/43147 \n\nConclusions:\n\nNo objections to the proposals as written.\n\n### `args` in Top-Level programs\n\nIf the top-level statements are logically inside a `Main` method, it would be very useful to have\naccess to the command line arguments for the program. You can access these via\n`Environment.GetCommandLineArgs()`, but it's unfortunate that this is both different from the\nAPIs in Main, and `Environment.GetCommandLineArgs()` includes the program name, and `args` in\nMain does not.\n\nIf we want to do something, we could have a magic variable named `args` (similar to `value` in\nsetters) or a property in the framework called `Args` (e.g. `Environment.Args`).\n\nIn favor of the property, fewer language-level changes means fewer things that people have to\nlearn.\n\nIn favor of the `args` magic variable, it's simpler to use than a property (since the property\nwould either have to qualified with a type name, or a `using static` would have to be added) and\na language feature for the inputs (command line args) mirrors the language feature for the output\n(returning an `int` that turns into the process exit code).\n\n#### Conclusion\n\nWe'll go with the `args` magic variable. We still need to decide on the scope: either equivalent\nto top-level locals, which are visible in all files but inaccessible, or only in scope in\ntop-level statements. If we make it visible in all files we would only add the variable if there\nis at least one top-level statement in the program."
  },
  {
    "path": "meetings/2020/LDM-2020-05-11.md",
    "content": "\n# C# Language Design Meeting for May 11, 2020\n\n## Agenda\n\nRecords\n\n## Discussion\n\nToday we tried to resolve some of the biggest questions about records,\nnamely how to unify the semantics of nominal records and positional\nrecords, and what are the key scenarios that we are trying to resolve\nwith records.\n\nThe main inconsistency is that the members `record class Person(string FirstName, string\nLastName)` are very different from the members in `class Person(string firstName, string\nlastName)`. One way of resolving this is to unify the meaning of the declaration in the direction\nof primary constructors. In this variant, the parameters of a primary constructor always capture\nitems by default.\n\nTo produce public init-only properties like we were exploring, we would require an extra\nkeyword, `data`, that could be generalizable. So a record which has two public init-only\nmembers would be written\n\n```C#\nrecord Person(data string FirstName, data string LastName);\n```\n\nThis would allow a generalizable `data` keyword that could be applied even in regular\nclasses, e.g.\n\n```C#\nclass Person\n{\n    data string FirstName;\n    data string LastName;\n    public Person(string first, string last)\n    {\n\n    }\n}\n```\n\nThe worry here is that we're harming an essential motivation for records, namely a short syntax\nfor immutable data types. In the above syntax, `record` alone does not mean immutable data type,\nbut instead only value equality and non-destructive mutation. A problem with this is that value\nequality is dangerous for mutable classes, since the hash code can change after being added to a\ndictionary. This was why we were previously cautious about adding a general feature for value\nequality. One option to discourage misuse would be to provide a warning for any non-immutable\nmember in a record class.\n\nThe other problem is, frankly, it's not that short. Aside from some duplication of intent by\nrequiring both `record` and `data` modifiers, it also requires applying the `data` modifier to\neach member, so the overhead grows larger as the type does.\n\nAlternatively, we could go in the complete opposite direction: limit customizability by making\nrecords all about public immutable data.\n\nFor instance, nominal records could also have syntax abbreviation\n\n```C#\nrecord Person { string FirstName; string LastName; }\n```\n\nand we could avoid confusion by prohibiting other members entirely.\n\nThis would look at lot more like positional records, e.g.\n\n```C#\nrecord Person(string FirstName, string LastName);\n```\n\nand we could introduce further restrictions on those by also disallowing other members\nin the body, or even disallowing primary constructors entirely.\n\nDisallowing all members inside of records is draconian, but not entirely without precedence.\nEnums work the same way in C# and members are added via extensions methods. That's not a ringing\nendorsement since we've considered proposals for allowing members in enums before, but it also\ndoesn't put it outside the realm of possibility for C#, especially in earlier forms.\n\nThe main drawback of the simplest form is the risk that we might have trouble evolving the\nfeature to fit all circumstances. If we wanted to allow a user to define private fields, the\nsyntax with no accessibility modifier now means \"public init-only property\" so we might not\nbe able to add support for private fields at all, or we might have to use a syntactic distinction\nthat requires a `private` accessibility, which is a subtle change.\n\n### Conclusion\n\nWe largely prefer the short syntax for records. A nominal record would look like\n\n```C#\nrecord class Person { string FirstName; string LastName; }\n```\n\nThis would create a class with public `init-only` properties named `FirstName`\nand `LastName`, along with equality and non-destructive mutation methods.\n\nSimilarly,\n\n```C#\nrecord class Person(string FirstName, string LastName);\n```\n\nwould create a class with all of the above, but also a constructor and Deconstruct.\n\nWe have yet to confirm whether `record` disallows private fields entirely, or if it\njust changes the default accessibility."
  },
  {
    "path": "meetings/2020/LDM-2020-05-27.md",
    "content": "\n# C# Language Design Meeting for May 27, 2020\n\n## Agenda\n\n1. Records -- syntax\n\n## Discussion\n\n### Syntax Questions\n\nWe got significant feedback that `record` is a better name than `data` for indicating\na `record`. There are two syntaxes we've been considering here:\n\n    1. `record class Person { ... }`\n    2. `record Person { ... }`\n\nThe main difference here is that (2) has less obvious space for a `struct` token, which\nraises the question of whether \"record structs\" are a feature we want to enable.\n\nThere are a couple arguments for why records would be useful for structs. The first is\nthat \"value behavior\" is a general feature that could be useful for both structs and classes.\nValue equality exists for structs today, but it is potentially slow in the runtime implementation.\n\nThe second is that the syntax provided for classes is also useful for structs. The positional\nsyntax specifically seems attractive because it has a lot of similarity to tuples and allows a\nform of \"named tuple.\"\n\n```C#\nrecord struct Point(int X, int Y);\n```\n\nOn the other hand, we could improve the performance of equality, completely separate from records.\nFor instance, the compiler could add equality methods if they are not present. We also do not necessarily\nneed to address structs first. Since structs already have many features of records they are, in a sense,\n\"less far behind\" than classes in record features. It makes sense to concentrate first on classes and\nconsider augmentations for structs in a future update.\n\nSo to return to the original question, we have to decide if we want to move forward with option (2), which\nis a new form of declaration. Notably, this is a breaking change for certain scenarios e.g.,\n\n```C#\nrecord M(int X, int Y) { ... }\n\nclass C\n{\n    record M(int X, int Y) { ... }\n    partial record M(int X, int Y);\n}\n```\n\nAll of these are currently method declaration syntax. In C# 9 this would be a record declaration\nwith a positional constructor and a body. Normally we would never consider this kind of change,\nbut since we started shipping with .NET Core we do not automatically upgrade language version\nunless the target framework is the newest one (i.e., NET 5).\n\n#### Conclusion\n\nDo not support structs for now. They already support many features of records and we can add\nmore, time permitting.\n\nThe accepted proposal is that the syntax, `<modifiers> <attributes> 'record'` followed by\n`identifier` and either '(', '{', or '<' would be contextually parsed as a record declaration\nonly if the language version is C# 9.\n\n### Short-property syntax\n\nWe previously agreed that, to unify the syntax forms in the positional and nominal declaration, we\nwould allow fields in nominal records with no modifiers to instead be interpreted as public auto-properties.\nAfter looking at feedback and exploring some of the related issues, we've decided that's not the best approach.\n\nThere are a few proposals on the table:\n\n    1. Leave positional records the same, do not provide special syntax for nominal records.\n\n```C#\npublic record Point(int X, int Y);\npublic record Point\n{\n    public int X { get; init; }\n    public int Y { get; init; }\n}\n```\n\n    2. Unify the declaration forms in favor of nominal records, allowing property declarations in the\n    record parameter list\n\n```C#\npublic record Point(\n    public int X { get; init; },\n    public int Y { get; init; }\n)\npublic record Point\n{\n    public int X { get; init; },\n    public int Y { get; init; }\n}\n```\n\n    3. Keep positional records the same, provide a new modifier (e.g., `data` or `init`) for members\n    which means \"public init-only property\"\n\n```C#\npublic record Point(int X, int Y);\npublic record Point\n{\n    data int X;\n    data int Y;\n}\n```\n\n    4. Provide the new modifier from (3), and require it in both types of records\n\n```C#\npublic record Point(data int X, data int Y);\npublic record Point\n{\n    data int X;\n    data int Y;\n}\n```\n\nAfter discussion, we prefer (3). Positional records already seem to have enough syntactic distinction and\nthe `data` keywords seem superfluous in this position. It also makes the shortest syntax form match up\nwith the most common use case.\n\nHowever, we do think some further keyword is necessary for nominal records. Looking too much like existing\nfields seems like it would be too confusing, especially if we want to also allow fields in records.\n\nInstead, we're considering leaving positional records to generate public auto-properties by default, partly\nbecause they are already a significantly different syntax that cannot be confused with existing language\nconstructs, and providing a new mechanism for positional records.\n\n#### Conclusion\n\nKeep positional records the same, provide a `data` modifier for fields which means \"public\ninit-only property\"\n\n```C#\npublic record Point(int X, int Y);\npublic record Point\n{\n    data int X;\n    data int Y;\n}\n```\n\n"
  },
  {
    "path": "meetings/2020/LDM-2020-06-01.md",
    "content": "\n# C# Language Design for June 1, 2020\n\n## Agenda\n\nRecords:\n\n1. Base call syntax\n2. Synthesizing positional record members and assignments\n3. Record equality through inheritance\n\n## Discussion\n\n### Record base call syntax\n\nWe'd like to reconsider adding a base call syntax to a record declaration, i.e.\n\n```antlr\nrecord_base\n    : ':' class_type argument_list?\n    | ':' interface_type_list\n    | ':' class_type argument_list? interface_type_list\n    ;\n```\n\nThe main question is how the scoping of the parameters from the record positional\nconstructor interact with the base call syntax and the record body.\n\nWe would definitely like the parameters to be in scope inside the base call. For the record body,\nit's proposed that the parameters of the primary constructor are in scope for initializers, and\nthe primary constructor body (if we later accept a proposal for such syntax). The parameters\nshadow any members of the same name. The parameters are not in scope outside of these locations.\n\nTo unify the scoping behavior between the base call and the body, we propose that members of the\nbody are also in scope in the base call syntax. Instance members would be an error in these locations\n(similar to how instance members are in scope in initializers today, but an error to use), but\nthe parameters of the positional record constructor would be in scope and useable. Static members\nwould also be useable, similar to how base calls work in ordinary constructors today.\n\n**Conclusion**\n\nThe above proposals are accepted.\n\n### Synthesized positional record members\n\nA follow-up question is how to do generation for auto-generated positional properties. We need\nto decide both 1) when we want to synthesize positional members and 2) when we want to initialize\nthe corresponding members. The affect is most clearly visible in the example below, where the\ninitialization order will affect what values are visible at various times during construction,\nnamely whether the synthesized properties are initialized before or after the `base` call.\n\n```C#\nrecord Person(string FirstName, string LastName)\n{\n    public string Fullname => $\"{FirstName} {LastName}\";\n    public override string ToString() => $\"{FirstName} {LastName}\";\n}\n\nrecord Student(string FirstName, string LastName, int Id)\n    : Person(FirstName, LastName)\n{\n    public override string ToString() => $\"{FirstName} {LastName} ({ID})\";\n}\n```\n\nFirst we discussed when to synthesize members, namely when an \"existing\" member will prevent\nsynthesis. A simple rule is that we synthesize members when there is no accessible, concrete\n(non-abstract) matching member in the type already, either because it was inherited or because it\nwas declared. The rule for matching is that if the member would be considered identical in signature,\nor if it would require the `new` keyword in an inheritance scenario, those members would \"match.\" This\nrule allows us to avoid generating duplicate members for record-record inheritance and also produces the\nintuition that we should err on the side of not synthesizing members when they could be confused with\nan existing member.\n\nSecond, we discussed when and in what order assignments were synthesized from positional record\nparameters to \"matching\" members. A starting principle is that in record-record inheritance we don't\nwant to duplicate assignment -- the base record will already assign its members. In that case, we could\nchoose to assign only members synthesized or declared in the current record. That would mean\n\n```C#\nrecord R(int X)\n{\n    public int X { get; init; }\n}\n```\n\nwould initialize the `X` property to the value of the constructor parameter even though the property\nis not compiler synthesized. However, we would have to decide if it is synthesized before or after\nthe `base` call. In essence, the question is how we de-sugar the assignments. Is `record Point(int X, int Y);`\nequivalent to\n\n```C#\nrecord Point(int X, int Y) : Base\n{\n    public int X { get; init; } = X;\n    public int Y { get; init; } = Y;\n}\n```\n\nor\n\n```C#\nrecord Point(int X, int Y) : Base\n{\n    public int X { get; init; }\n    public int Y { get; init; }\n    public Point\n    {\n        this.X = X;\n        this.Y = Y;\n    }\n}\n```\n\nNote that today property and field initializers are always executed before the `base` call, while\nstatements in the constructor body are executed afterwards and we are disinclined to change that\nfor record initializers.\n\nLooking at the examples as a whole, we think using the initializer behavior is good -- it's easy\nto understand and more likely to be correct in the presence of a virtual call in the base class,\nbut it makes things significantly more complicated if we synthesize it even for user-written\nproperties. Is the initializer synthesized even if there's already an initializer on the property?\nWhat if the user-written property isn't an auto-property?\n\n**Conclusion**\n\nWe think it's much clearer if we simplify the rules to only initialize synthesized properties.\nEffectively, if you replace the synthesized record property, you also have to write the initialization,\nif you want it. In the case that the property is not already declared, e.g. `record Point(int X, int Y);`\nthe equivalent code is\n\n```C#\nrecord Point(int X, int Y)\n{\n    public int X { get; init; } = X;\n    public int Y { get; init; } = Y;\n}\n```\n\n### Equality through inheritance\n\nWe have a number of small and large questions about how records work with inheritance.\n\nQ: What should we do if one of the members which we intend to override, like object.Equals and\n   object.GetHashCode, are sealed?\n\nA: Error. This is effectively outside of the scope of automatic generation.\n\nQ: Should we generate a strongly-typed Equals (i.e., `bool Equals(T)`) for each record declaration? What\n   about implementing `IEquatable<T>`?\n\nA: Yes. Implementing `IEquatable<T>` is very useful and would require a strongly-typed equals method. We\n   could explicitly implement the method, but we also think this is useful surface area. If we broaden\n   support to structs, this would prevent a boxing conversion, which has a significant performance impact.\n   Even for classes this could avoid extra type checks and dispatch.\n\nQ: Should each record declaration re-implement equality from scratch? Or should we attempt to dispatch\n   to base implementations of equality?\n\nA: For the first record in a type hierarchy, we should define equality based on all the accessible fields,\n   including inherited ones, in the record. For records inheriting from a class with an existing\n   `EqualityContract`, we should assume that it implements our contract appropriately, and delegate comparing\n   the EqualityContract itself and the base fields to the base class.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-06-10.md",
    "content": "\n# C# LDM for June 10, 2020\n\n## Agenda\n\n1. \"Roles\"\n\n## Discussion\n\nExploration of previous proposal: #1711\n\nThis is a topic that we've explored before which we're reviving for further consideration and discussion.\n\nWe have a \"role\" proposal, but it's more of a starting point for a final design. There are a number of\ndifferent problems we can presumably solve here, but it seems like we have some intersecting features that\nmight address multiple problems simultaneously.\n\nThere are many tradeoffs to consider in these designs. One of the most well-known is sometimes called\n\"incoherence,\" where the ability to implement an interface in two ways on the same type effectively causes\nthe two implementations to \"cross\" each other in ways that can be hard to predict. For instance, if two\npeople implemented `IEquatable<T>` on the same third-party type, and both added it to a dictionary, if they\nused different `GetHashCode` implementations then the same member could be added twice, and each consumer\nwouldn't see the implementation used by other consumers.\n\nAnother tradeoff is the ability to use the role as a type, namely refer to it in a type position. This\nis often desirable, but has some tradeoffs in type equivalence (see SML modules for alternative notions\nof type equivalence through functors).\n\nThe Roles proposal as a whole seems very powerful, but there are many big questions here. The biggest,\nmost pressing question is: what problems do we think are the most important and how big a feature do\nwe need to address them? Providing a way to abstract over different numeric abstractions is a concrete\nscenario, but it may not need the fully generalized mechanism. Allowing existing types to conform\nto an abstract after definition is also powerful and has many possible use cases, but how flexible\ndo we need to make that mechanism? Can it only be used in generics? Can you implement abstractions\ndefined in other compilations on types defined in other compilations?\n\nThe performance concerns are also very real. We have a few mechanisms for abstraction in the language\ntoday, but a lot of those mechanisms come with performance costs like allocation that make them\nunusable in performance-sensitive scenarios. We would like more zero-cost abstractions if possible,\nbut we're not sure what functionality we could provide in those circumstances and whether the features\nwould fit well into the existing ecosystem."
  },
  {
    "path": "meetings/2020/LDM-2020-06-15.md",
    "content": "\n# C# Language Design Meeting for June 15, 2020\n\n## Agenda\n\n1. `modreq` for init accessors\n\n1. Initializing `readonly` fields in same type\n\n1. `init` methods\n\n1. Equality dispatch\n\n1. Confirming some previous design decisions\n\n1. `IEnumerable.Current`\n\n## Discussion\n\n### `modreq` for init accessors\n\nWe've confirmed that the modreq design for `init` accessors:\n\n    - The modreq type `IsExternalInit` will be present in .NET 5.0, and will be recognized if\n    defined in source\n\n    - The feature will only be fully supported in .NET 5.0\n\n    - Usage of the property (including the getter) will not be possible on older compilers, but\n    if the compiler is upgraded (even if an older framework is being used), the getter will be\n    usable\n\n### Initializing `readonly` fields in same type\n\nWe previously removed `init` fields from the design proposal because we didn't think it was\nnecessary for the records feature and because we didn't want to allow fields which were\ndeclared `readonly` before records to suddenly be settable externally in C# 9, contrary to\nthe author's intent.\n\nOne extension would be to allow `readonly` fields to be set in an object initializer only inside\nthe type. In this case you could still use object initializers to set readonly fields in\nstatic factories, but because they would be a part of your type you would always know the intent\nof the `readonly` modifier. For instance,\n\n```C#\nclass C\n{\n    public readonly string? ReadonlyField;\n\n    public static C Create()\n        => new C() { ReadonlyField = null; };\n}\n```\n\nOn the other hand, we may not need a new feature for many of these scenarios. An init-only\nproperty with a private `init` accessor behaves similarly.\n\n```C#\nclass C\n{\n    public string? ReadonlyProp { get; private init; }\n\n    public static C Create()\n        => new C() { ReadonlyProp = null; };\n}\n```\n\n**Conclusion**\n\nWe still think `readonly` fields are interesting, but we're not sure of the scenarios yet.\nLet's keep this on the table, but leave it for a later design meeting.\n\n### `init` methods\n\nWe previously considered having `init` methods which could modify `readonly` members just\nlike `init` accessors. This could enable scenarios like \"immutable collection initializers\",\nwhere members can be added via an `init` Add method.\n\nThe problem is that the vast majority of immutable collections in the framework today would be\nunable to adopt this pattern. Collection initializers are hardcoded to use the name `Add` today\nand almost all the immutable collections already have `Add` methods that are meant for a different\npurpose -- they return a copy of the collection with the added item.\n\nIf we naively extend `init` to collection initializers most immutable collections wouldn't be able\nto adopt them because they couldn't make their `Add` methods `init`-only, and no other method name\nis allowed in a collection initializer. In addition, some types, like ImmutableArrays, would be\nforced to implement init-only collection initializers very inefficiently, by declaring a new array\nand copying each item every time `Add` is called.\n\n**Conclusion**\n\nWe're still very interested in the feature, but we need to determine how we can add it in a way\nthat provides a path forward for our existing collections.\n\n### Equality dispatch\n\nWe have an equality implementation that we think is functional, but we're not sure it's the most\nefficient implementation. Consider the following chain of types:\n\n```C#\nclass R1\n{\n    public override bool Equals(object other)\n        => Equals(other as R1);\n    public virtual bool Equals(R1 other)\n        => !(other is null) &&\n           this.EqualityContract == other.EqualityContract\n           /* && compare fields */;\n}\nclass R2 : R1\n{\n    public override bool Equals(object other)\n        => Equals(other as R2);\n\n    public override bool Equals(R1 other)\n        => Equals(other as R2);\n\n    public virtual bool Equals(R2 other)\n        => base.Equals((R1)other)\n           /* && compare fields */;\n}\nclass R3 : R2\n{\n    public override bool Equals(object other)\n        => Equals(other as R3);\n\n    public override bool Equals(R1 other)\n        => Equals(other as R3);\n\n    public override bool Equals(R2 other)\n        => Equals(other as R3);\n\n    public virtual bool Equals(R2 other)\n        => base.Equals((R1)other)\n           /* && compare fields */;\n}\n```\n\nThe benefit of the above strategy is that each virtual call goes directly\nto the appropriate implementation method for the runtime type. The drawback\nis that we're effectively generating a quadratic number of methods and overrides\nbased on the number of derived records.\n\nOne alternative is that we could not override the Equals methods of anything\nexcept our `base`. This would cause more virtual calls to reach the implementation,\nbut reduce the number of overrides.\n\n**Conclusion**\n\nWe need to do a deep dive on this issue and explore all the scenarios. We'll come\nback once we've outlined all the options and come up with a recommendation.\n\n### Affirming some previous decisions\n\nProposals for copy constructors\n\n    - Do not include initializers (including for user-written copy constructors)\n\n    - Require delegation to a base copy constructor or `object` constructor\n\n        - If the implementation is synthesized, this behavior is synthesized\n\nProposal for Deconstruct:\n\n    - Doesn't delegate to a base Deconstruct method\n\n    - Synthesized body is equivalent to a sequence of assignments of member\n      accesses. If any of these assignments would be an error, an error is produced.\n\nIt's also proposed that any members which are either dispatched to in a derived record\nor expected to be overridden in a derived record will produce an error for synthesized\nimplementations if the required base member is not found. This includes if the base\nmember was not present in the immediate base, but was inherited instead. For some situations\nthis may mean that the user can write a substituted implementation for that synthesized\nmember, but for the copy constructor this effectively forbids record inheritance, since\nthe valid base member must be present even in a user-defined implementation.\n\n**Conclusion**\n\nAll of the above decisions are upheld.\n\n### Non-generic IEnumerable\n\nCurrently in the framework `IEnumerable.Current` (the non-generic interface) is annotated to\nreturn `object?`. This produces a lot of warnings in legacy code that `foreach` over the result\nwith types like `string`, which is non-nullable. We have two proposals to resolve this:\n\n    - Un-annotate `IEnumerable.Current`. This will keep the member nullable-oblivious and no warnings\n    will be generated, even if the property is called directly\n\n    - Special-case the compiler behavior for `foreach` on `IEnumerable` to suppress nullable warnings\n    when calling `IEnumerable.Current`\n\n**Conclusion**\n\nOverall, we prefer un-annotation. Since this interface is essentially legacy, we feel that\nproviding nullable analysis is potentially harmful and rarely beneficial.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-06-17.md",
    "content": "\n# C# Language Design Meeting for June 17, 2020\n\n## Agenda\n\n1. Null-suppression & null-conditional operator\n1. `parameter!` syntax\n1. `T??`\n\n## Discussion\n\n### Null-suppression & null-conditional operator\n\nIssue #3393\n\nWe generally agree that this is uninintended and unfortunate, essentially a spec bug. The\nonly question is whether to allow `!` at the end of a `?.`, as well as in the \"middle\". In\nsome sense\n\n### `parameter!` syntax\n\nThis has been delayed because we haven't been able to agree on the syntax. The main contenders\nare\n\n```C#\nvoid M(string param!)\nvoid M(string param!!)\nvoid M(string! param)\nvoid M(string !param)\nvoid M(checked string param)\nvoid M(string param ?? throw)\nvoid M(string param is not null)\nvoid M(notnull string param)\nvoid M(null checked string param)\nvoid M(bikeshed string param)\nvoid M([NullChecked(\"Helper\")] string param)\n/* contract precondition forms */\nvoid M(string param) Requires.NotNull(param)\nvoid M(string param) when param is not null\n```\n\nThe simplest form, `void M(string param!)` is attractive, but looks very similar to the null\nsuppression operator. The biggest problem is that you can see them as having very different\nmeanings -- `!` in an expression silences nullable warnings, while `!` on a parameter does the\nopposite, it actually produces an exception on nulls. However, the result of both forms is a\nvalue which is treated by the compiler as not-null, so there is a way of seeing them as similar.\n\nMoving it to the other side of the parameter name, `!param`, would resolve some of the similarity\nwith the null suppression operator, but it also looks a lot like the `not` prefix operator. There's\nslightly less contradiction in these operators, but it still features a bit of syntactic overloading.\n\n`string!` has a couple problems, including a suggestion that it's a part of the type (which it would not\nbe), and that sometimes you may want to use the operator on nullable types, like `AssertNotNull` methods.\nIt also wouldn't be usable in simple lambdas without types.\n\n`checked` suggests integer over/underflow more than nullability.\n\n`param!!` has some usefulness that we could provide a corresponding expression form -- `!`\nsuppresses null warnings, while `!!` actually checks for null and throws if it is found. On the\nother hand, it also reads a bit strangely, especially since we're adding a new syntax form\ninstead of trying to reuse some forms we already have. On the other hand, the fact that it's\ndifferent enough to look different, while also short enough to be used commonly has a lot in\nfavor of it. In general we historically have a bias towards making new things strongly\ndistinguished from existing code, but shortly after introducing the feature we tend to wish that\nthings were less verbose and didn't draw as much attention in the code. On the other hand, the\nnullable feature has a rule that it should not affect code semantics, while the purpose of this\nfeature is to affect code semantics. `param!!` could be seen as being too similar to other things\nin the nullable feature, but to some people it also stands out because of the multiple operators.\n\nWe did a brief ranked choice vote and came up with the following ranking, not as definitive, just to\nmeasure our current preferences:\n\n1. `void M(string param!!)`\n2. `void M(nullcheck string param)`\n3. `void M([NullChecked(Helper)] string param)`\n\nMany people don't have strong opinions, so we don't have a clear winner coming out.\n\n**Conclusion**\n\nWe're getting closer to consensus, but we need to discuss this more and consider some of the\nlong-term consequences, as well as impact on other pieces of the language design.\n\n### `T??`\n\nUnfortunately there are multiple parsing ambiguities with `T??`:\n\n```C#\n(X??, Y?? y) t;\nusing (T?? t = u) { }\nF((T?? t) => t);\n```\n\nThis has left us looking back to the original syntax: `T?`. The original reason we rejected this\nwas that there could be confusion that `T?` means \"maybe default,\" so that the type is nullable\nif it's a reference type, but not nullable if it's a value type.\n\nIf we want to allow the `T?` syntax anyway, we need some syntax to specify that, for overrides,\nwe want the method with no constraints (unconstrained). This is because constraints cannot\ngenerally be specified in overrides or explicit implementations, so previously `T?` always meant\n`Nullable<T>`, but now it may not. We added the `class` constraint for nullable reference types,\nbut neither `T : class` nor `T : struct` help if the `T` is unconstrained. In essence, we need a\nconstraint that means unconstrained. Some options include:\n\n```C#\noverride void M1<[Unconstrained]T,U>(T? x)           // a\noverride void M1<T,U>(T? x) where T: object?         // b\noverride void M1<T,U>(T? x) where T: unconstrained   // c\noverride void M1<T,U>(T? x) where T:                 // d\noverride void M1<T,U>(T? x) where T: ?               // e\noverride void M1<T,U>(T? x) where T: null            // f\noverride void M1<T,U>(T? x) where T: class|struct    // g\noverride void M1<T,U>(T? x) where T: class or struct // h\noverride void M1<T,U>(T? x) where T: cluct           // joke\noverride void M1<T,U>(T? x) where T: default         // i\n```\n\n**Conclusion**\n\nThe `default` constraint seems most reasonable. It would only be allowed in overrides and\nexplicit interface implementations, purely for the purpose of differentiating which method\nis being overridden or implemented. Let's see if there are other problems."
  },
  {
    "path": "meetings/2020/LDM-2020-06-22.md",
    "content": "\n# C# Language Design Meeting for June 22, 2020\n\n## Agenda\n\n1. Data properties\n\n1. Clarifying what's supported in records for C# 9\n\n    - Structs\n\n    - Inheritance with records and classes\n\n## Discussion\n\n### `data` properties\n\nWe've been working on an implementation for data properties and have some questions about\nmodifiers, which are currently not allowed.\n\nThere are some modifiers that could be legal, like `new`, `abstract`, `virtual`, and `override`.\nSome of these, especially `new` and `override` would probably prevent `data` properties from\nbeing used at all, since a warning would be generated if there's a matching member in the base\nthat requires either `override` or `new`.\n\nHowever, the point of data properties was to be brief. Adding modifiers would potentially cloud\nthe purpose of the feature. The syntactical abbreviation isn't strictly required because the\nequivalent property can always be written explicitly:\n\n```C#\ndata int X;\n\n// versus\n\npublic int X { get; init; }\n```\n\n\n**Conclusion**\n\nBased on where we are in the schedule for C# 9, we probably will not have time to respond to feedback.\nTherefore, we're planning on putting this feature into preview and not shipping it with C# 9. For now,\nlet's allow the following modifiers: `public`, `new`, `abstract`, `virtual`, and `override`. This will\nprovide an option for allowing `data` properties to interact more smoothly with other constructs in C#,\nwhile maintaining some of the simplicity. We'll see how it feels in prototypes to gauge whether we went\ntoo far, or not far enough.\n\n### Struct records\n\nWe're not sure how much space we have for structs in C# 9, but we do think structs are an\ninteresting design point. We previously proposed that structs could support a variety of record\nbehaviors without being a record. One idea would be to automatically implement `IEquatable<T>`\nfor all structs, but this has a lot of potential negative impact for the runtime and the\necosystem: effectively every struct would add a large number of members which could seriously\nbloat metadata.\n\nAn alternative would be to work with the runtime to try to provide a runtime-generated form of\n`IEquatable<T>`. If it's cheap enough, we may be able to provide `IEquatable<T>` for structs as\na as-necessary addition to all structs. However, this is a potentially very large change. Even\nsmall costs could add up, and even small semantic changes could impact someone.\n\nOverall, the modification of arbitrary struct semantics just seems too risky. Something as simple\nas testing a struct for an implementation of `IEquatable<T>` could be a breaking change, and with\na change this big, it's almost certain to be breaking for someone.\n\n**Conclusion**\n\nAltering the semantics of all structs as-is is out. We're leaning towards a real \"record struct\"\ndeclaration.\n\n### Inheritance between records and classes\n\nWe currently have a restriction that records cannot inherit from classes and classes cannot\ninherit from records. We should confirm that this restriction is acceptable for C# 9.\n\n**Conclusion**\n\nWe definitely see scenarios for expanding this, but we think the restriction is fine for the\nfirst version of records. Based on feedback and example scenarios, we can reconsider these\nrestrictions and also the expected semantics.\n\n### `with` expressions on non-records\n\nThis encompasses:\n\n1. Finding some way to define a compatible `Clone` for user-defined classes\n\n1. Anonymous types\n\n1. Tuples\n\nCompatibility for `Clone` in user-defined classes is the most difficult of these items because it\nrelies on a new language feature for requiring that a new object is returned from the Clone\nmethod.\n\nAnonymous types are very simple, we can retroactively define them as record types.\n\nTuples would be simple to special-case in the language, but it's probably more consistent to\ndecide the semantics for struct records first, and then update the definition of\nSystem.ValueTuple to support them.\n\n**Conclusion**\n\nAnonymous types can be updated at any time, everything else should wait until after C# 9.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-06-24.md",
    "content": "# C# Language Design Meeting for June 24th, 2020\n\n## Agenda\n\n1. [Confirming Function Pointer Decisions](#Confirming-Function-Pointer-Decisions)\n1. [Parameter Null Checking](#Parameter-Null-Checking)\n1. [Interface `static` Member Variance](#Interface-`static`-Member-Variance)\n1. [Property Enhancements](#Property-Enhancements)\n\n## Quote of the Day\n\n\"It feels a little bit like we're playing code golf here\"\n\n## Discussion\n\n### Confirming Function Pointer Decisions\n\nhttps://github.com/dotnet/roslyn/issues/39865#issuecomment-647692516\n\nThere are a few open questions from a previous [LDM](LDM-2020-04-01.md) and a followup email chain\nthat need to be confirmed before they can be implemented. These questions center around calling\nconvention type lookup and how identifiers need to be written in source. The grammar we had roughly\nproposed after the previous meeting is:\n\n```antlr\nfunc_ptr_calling_convention\n   : 'managed'\n   | 'unmanaged' ('[' func_ptr_callkind ']')?\n\nfunc_ptr_callkind\n  : 'CallConvCdecl'\n  | 'CallConvStdcall'\n  | 'CallConvThiscall'\n  | 'CallConvFastcall'\n  | identifier (',' identifier)*\n```\n\n##### Calling Convention Lookup\n\nWhen attempting to bind the `identifier` used in an unmanaged calling convention, should this follow\nstandard lookup rules, such that the type must be in scope at the current location, or is using a\nform of special lookup that disregards the types in scope at the current location? The types valid\nin this location are a very specific set: they must come from the `System.Runtime.CompilerServices`\nnamespace, and the types must have been defined in the same assembly that defines `System.Object`,\nregardless of the binding strategy used here, so it's really a question of whether the user has to\ninclude this namespace in their current scope, adding a bunch of types that they are generally not\nadvised to use directly, and whether they can get an error because they defined their own calling\nconvention.\n\n##### Conclusion\n\nGiven the specificness required here, we will use special name lookup.\n\n##### Required identifiers\n\nThe previous LDM did not specify the required syntax for the identifiers quite explicitly enough for\nimplementation, and specified that identifiers should be lowercase while also having upper case\nidentifiers in some later examples. The following rules are proposed as the steps the compiler will\ntake to match the identifier to a type:\n\n1. Prepend `CallConv` onto the identifier. No casemapping is performed.\n2. Perform special name lookup with that typename in the `System.Runtime.CompilerServices` namespace\nonly considering types that are defined in the core library of the program (the library that defines\n`System.Object` and has no dependencies itself).\n\nWe also reconsidered the decision from the previous LDM on using lowercase mapping for the identifier\nnames. There is convention for this in other languages: C/C++, for example, use `__cdecl` or similar\nas their calling convention specifiers, and given that this feature will be used for native interop\nwith libraries doing this it would be nice to have some parity. However, this would introduce several\nissues with name lookup: existing special name lookup allows us to modify the `identifier` specified\nin source, but it does not allow us to modify the names of the types we're matching against, which\nwe would need to do here. There is certainly an algorithm that could be specified here, but we overall\nfelt that this was too complicated for what was a split aesthetic preference among members.\n\n##### Conclusion\n\nThe proposed rules are accepted. As a consquence, the identifier specified in source cannot start\nwith `CallConv` in the name, unless the runtime were to add a type like `CallConvCallConv`.\n\n### Parameter Null Checking\n\nWe ended the [previous meeting](LDM-2020-06-17.md) on this with two broad camps: support for the `!!`\nsyntax, and support for some kind of keyword. Email discussion over the remainder of the week and\npolling showed that a clear majority supported the `!!` syntax.\n\n#### Conclusion\n\nWe will be moving forward with `!!` as the syntax for parameter null checking:\n\n```cs\npublic void M(Chitty chitty!!)\n```\n\n### Interface `static` Member Variance\n\nhttps://github.com/dotnet/csharplang/issues/3275\n\nWe considered variance in `static` interface members. Today, for co/contravariant type parameters\nused in these members, they must follow the full standard rules of variance, leading to some\ninconsistency with the way that `static` fields are treated vs `static` properties or methods:\n\n```cs\npublic interface I<out T>\n{\n    static Task<T> F = Task.FromResult(default(T)); // No problem\n    static Task<T> P => Task.FromResult(default(T));   //CS1961\n    static Task<T> M() => Task.FromResult(default(T));    //CS1961\n    static event EventHandler<T> E; // CS1961\n}\n```\n\nBecause these members are `static` and non-virtual, there aren't any safety issues here: you can't\nderive a looser/more restricted member in some fashion by subtyping the interface and overriding\nthe member. We also considered whether this could potentially interfere with some of the other\nenhancements we hope to make regarding roles, type classes, and extensions. These should all be\nfine: we won't be able to retcon the existing static members to be virtual-by-default for interfaces,\nas that would end up being a breaking change on multiple levels, even without changing the variance\nbehavior here.\n\nWe also considered whether this change could be considered a bug fix on top of C# 8, meaning that\nusers would not have to opt into C# 9 in order to see this behavior. While the change is small and\nlikely very rarely needed, we would still prefer to avoid breaking downlevel compilers.\n\n#### Conclusion\n\nWe will allow `static`, non-virtual members in interfaces to treat type parameters as invariant,\nregardless of their declared variance, and will ship this change in C# 9.\n\n### Property Enhancements\n\nIn a [previous LDM](#LDM-2020-04-01.md) we started to look at various enhancements we could make\nto properties in response to customer feedback. Broadly, we feel that these can be addressed by\none or more of the following ideas:\n\n1. Introduce a `field` contextual keyword that allows the user to refer to the backing storage of\nthe property in the getter/setter of that property.\n    * In this proposal, we can consider all properties today as having this `field` keyword. As\n    an optimization, if the user does not refer to the backing field in the property body, we\n    elide emitting of the field, which happens to be the behavior of all full properties today.\n    * Of the proposals, this allows the most brevity for simple scenarios, allowing some lazily-fetched\n    properties to be one-liners.\n    * This proposal does not move the cliff far: if you need to have a type differing from the\n    type of the property, or multiple fields in a single property, then you must fall back to a full\n    property and expose the backing field to the entire class.\n    * There are also questions about the nullability of these backing properties: must they be\n    initialized? Or should we provide a way to declare them as nullable, despite the property\n    itself not being nullable?\n    * There was also concern that this is adding conceptual overhead for not enough gain: education\n    would be needed on when backing fields are elided and when they are not, complicated by the\n    additional backcompat overhead of ensuring that `field` isn't treated as a keyword when it\n    can bind to an existing name.\n2. Allow field declarations in properties.\n    * Conveniently for this proposal, a scoping set of braces for properties already exists.\n    * This addresses the issue of properties backed by a different storage type: if you have a\n    property that uses a `Lazy<T>` to initialize itself on first access, for example.\n    * This also allows users to declare multiple backing fields, if they want to lock access\n    to the property or combine multiple pieces of information into a single type in the public\n    surface area.\n    * In terms of user education, this is the simplest proposal. Since a set of braces already\n    exists, the education is just \"There's a new scope you can put fields in.\"\n3. Introduce a delegated property pattern into the language.\n    * There have been a few proposals for this, such as #2657. Other languages have also adopted\n    this type of feature, including Kotlin and Swift.\n    * This is by far the most complex of the proposals, adding new patterns to the language and\n    requiring declaration of a whole new type in order to remove one or possibly 2 fields from\n    a general class scope.\n    * By that same token, however, this is the most broad of the proposals, allowing users to\n    write reusable property implementations that could be abstracted out.\n\nThe LDM broadly viewed these proposals as increasing in scope: the `field` keyword allows the most\nbrief syntax, but forces users off the cliff back to full class-scoped fields immediately if their\nuse case is not having a single backing field of the same type. Meanwhile, property-scoped fields\ndon't allow for and encourage creating reusable helpers, like delegated properties would.\n\nWe also recognize that regardless of what decisions we make today, we're not done in this space.\nNone of these proposals are mutually exclusive, and we can \"turn the crank\" by introducing one, and\nthen adding more in a future release. There is interest among multiple LDM members in adding some\nform of reusable delegated properties or property wrappers, and adding one of either the `field`\nkeyword or property-scoped fields does not preclude adding the other in a later release. Further,\nall of these proposals are early enough that we still have a bunch of design space to work through\nwith them, while designing ahead enough to ensure that we don't add a wart on the language that we\nwill regret in the future.\n\n#### Conclusion\n\nA majority of the LDM members would like to start by exploring the property-scoped locals space.\nWe'll start by expanding that proposal with intent to include in C# 10, but will keep the other\nproposals in mind as we do so.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-06-29.md",
    "content": "# C# Language Design Meeting for June 29th, 2020\n\n## Agenda\n\n1. [Static interface members](https://github.com/Partydonk/partydonk/issues/1)\n\n## Procedural Note\n\nFor the past few years, the LDM notes have been compiled by the wonderful Andy Gocke (@agocke).\nAndy is taking the next step in his career and moving to be the lead of the CLR App Model team\nas of today, and as such will be moving to LDT emeritus status, joining the ranks of our other\nformer LDT members who form our advisory council. We thank him for all his hard work during his\ntime as notetaker, collating the sometimes inane rambling of the LDM in a set of readable\narguments and decisions.\n\nAt this point Fred Silberberg (@333fred) will be the new LDM notetaker. While I'll try to keep\nup much of the same spirit as Andy, I am not going to try to match his exact style or formatting,\nso there could be some changes in the exact formatting of the notes. I'll additionally apologize\nin advance as the notes inevitably end up delayed in the first few weeks as I settle in. And now,\non to the meeting notes!\n\n## Quote of the Day\n\n\"So we spent these last 10 years making it so we can come back to this. We actually never forgot,\n[.NET Core] has all been a ploy to get statics into interfaces.\"\n\n## Discussion\n\nToday @abock and @migueldeicaza presented their work on Partydonk over the past year, bringing\nabstract interface members to C# and the Mono runtime in a proof of concept. I did not take notes\non the specific slides: all of that material is available publicly on the partydonk repo\n[here](https://github.com/Partydonk/partydonk/blob/master/Generic%20Math/Generic%20Math%20in%20.NET%20-%20Contractual%20Static%20Interface%20Members%20in%20CSharp.pdf).\n\nOverall, the LDT members had a very positive reception to this work: in particular, they arrived\nat many of the same conclusions @CarolEidt had in her exploration of this space 10 years ago:\nmuch of the runtime work falls out from allowing `abstract static` in CIL and emitting constrained\ncalls to such members during compilation. From a language perspective, there's still a bit of work\nto do. `override` on `abstract` static members defined in interfaces isn't particularly nice from\na regularity with instance members perspective. We will also have to do design work around explicit\nimplementations: it could all fall out from existing rules, but will need a critical eye to make\nsure that the consequences of explicitly implementing an abstract member, and what that really means.\n\nThe existing code uses a `TSelf` generic parameter in what could be considered kind of an unfortunate\nsyntax:\n\n```cs\ninterface INumeric<TSelf> where TSelf : INumeric<TSelf>\n{\n    abstract static TSelf Zero { get; }\n    abstract static TSelf operator +(TSelf a, TSelf b);\n}\n```\n\nThe `TSelf : where TSelf : INumeric<TSelf>` was suggested in the past to help the prototype make\nprogress without blocking on associated types, but it's ugly and proliferates through the entire\ntype hierarchy if left unchecked. A much better solution would be to formally introduce associated\ntypes into the language, something that we've discussed in LDM before and has some support. We should\ntake those into account here: if we introduce this entire type hierarchy, then in the next C# release\nintroduce a `TSelf` associated type it would leave an annoying blemish on the language. In particular,\nwe need to make sure we have a good roadmap for all components involved here: the compiler, the runtime,\nand the core libraries. Nonvirtual static members in interfaces have already shipped with C# 8, so we\ncan't get that back and declared them virtual members of the interface.\n\nWe do still have a few language questions: today, you cannot create user-defined operators that involve\ninterfaces, because doing so would subvert the type system. However, some numeric applications seem\nlike they would want to be able to do this for constants (see `IExpressibleByIntegerLiteral` and\n`IExpressibleByFloatLiteral` in the presentation). If we allow this for the `TSelf` parameter, it seems\nlike these concerns should be obviated: you're not converting to an interface type, you're converting to\na concrete type and specifying that said conversion must be available for any implementations of the\ninterface. Additionally there's an interesting correspondance issue: today, any members that are part\nof the interface contract are available on an instance of the interface. However, with static methods,\nthe interface itself doesn't provide them: types that implement the interface provide them, but not the\ninterface itself. We can certainly come up with new rules to cover this, but we will need to do so.\n\nSome other miscellaneous topics that came up:\n* We could use this system to specify constructors with multiple parameters of a specific type. Static\ninterface members could be implemented by a type calling `new`, which would allow us to improve on the\nsimple `new()` that we have today.\n* Existing language built-in operators would need to be considered to satisfy the constraints of the\nnumeric interfaces.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-07-01.md",
    "content": "# C# Language Design Meeting for July 1st, 2020\n\n## Agenda\n\n1. [Non-defaultable struct types and parameterless struct constructors](#Non-defaultable-struct-types-and-parameterless-struct-constructors)\n2. [Confirming unspeakable `Clone` method implications](#Confirming-unspeakable-Clone-method-implications)\n\n## Quote of the Day\n\n\"I did not say implications, I said machinations [pronounced as in British English]. I used a big word.\"\n\"You mispronounced machinations [pronounced as in American English], which is why I'm just ignoring you.\"\n\n## Discussion\n\n### Non-defaultable struct types and parameterless struct constructors\n\nProposal: https://github.com/dotnet/csharplang/issues/99#issuecomment-601792573\n\n#### Parameterless struct constructors\n\nWe discussed both proposals for allowing default struct constructors and for having a feature to allow differentiating between\n`struct` types that have a valid `default` value, and types that do not.\n\nFirst, we looked at parameterless constructors. Today, `struct`s cannot define their own custom parameterless constructors, and\na previous attempt to ship this feature in C# 6 failed due to a framework bug that we could not fix.\n\n```cs\npublic struct S\n{\n    public readonly int Field = 1; // Field is set by the default constructor\n}\n\npublic void M<T>()\n{\n    var s = (S)Activator.CreateInstance(typeof(T));\n    Console.WriteLine(s.Field);\n}\n```\n\nIn .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\ncall the parameterless constructor of a struct if one is present, and since we now tie language version to the target platform\nthere will be no supported scenario with this bug.\n\nWhile there was general support for this scenario in the LDM, we spent most of the time on the second part of the proposal and\ndid not come away with a conclusion for parameterless constructors. We will need to revisit this in context of a reworked defaultable\ntypes proposal and make a yes/no conclusion on this feature.\n\n#### Non-defaultable struct types\n\nThe crux of this proposal is that we would extend the tracking we introduced in C# 8 with nullable reference types, and extend it\nto value types that opt-in, holes and all. From a type theory perspective, the idea is that by applying a specific attribute, a\nstruct type can indicate that `default` and `new()` are _not_ the same value in the domain of its type. In fact, if the struct does\nnot provide a parameterless constructor, `new()` wouldn't be in the domain of the struct at all. This attribute would further opt the\nstruct's `default` value into participating in \"invalid\" scenarios in the same way that `null` is part of the domain of a reference\ntype, but is considered invalid for accessing members directly on that instance. This played well with our previous design of `T??`,\nif we were to allow the `??` moniker on types constrained to `struct` as well as unconstrained type parameters. However, as `??`\nhas been removed from C# 9 due to syntactic ambiguities (notes [here](LDM-2020-06-17.md#T??)), that part of the proposal will have\nto be reworked. Not having `??` makes the feature much harder to explain to users, and we'll run into issues with representation in\nnon-generic scenarios.\n\nOne thing that is clear from discussion is that non-defaultable struct types will need to have some standardized form of checking\nwhether they are the default instance. `ImmutableArray<T>`, for example, has an `IsDefault` property, as do most of the existing\nstruct types in Roslyn that cannot be used when `default`. We would want to be able to recognize this pattern in nullable analysis,\njust like we do today with the `is null` pattern. Since the attribute and pattern would be new, we could declare it to be whatever\nwe desire, and the libraries will standardize around that if they want to participate.\n\nGenerics also present an interesting challenge for non-defaultable value types. Today, the `struct` constraint implies new:\n\n```cs\npublic void M<T>() where T : struct\n{\n    var y = new T(); // Perfectly valid\n}\n```\n\nIf we were to enable non-defaultable struct types, this would change: `new()` is not necessarily valid on all struct types because\nnon-defaultable struct types have explicitly opted to separate `default` and `new()` in their domain, and might not have provided\na value for `new()`, meaning that it would return `default`. From an emit perspective, this is further complicated: for the above\ncode, the C# compiler _already_ emits a `new()` constraint. C# code cannot actually specify both the `struct` constraint and the\n`new()` constraint at the same time today, but in order to actually emit the combination of these constraints for this feature\nwe would have to introduce a new annotation on the type parameter to describe that it is required to have a parameterless `new()`\nthat provides a valid instance of the type.\n\n`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\nperformance-focussed areas, but is very hard to represent in C# because it would require a hard guarantee that a struct with a\n`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\nneed to not be possible to default in any fashion. This proposal could overlap with that feature: the guarantees provided here are\nno stronger than the guarantees given with nullable reference types, which is to say easy to break: arrays of these structs would\nstill be filled with `default` on creation, for example, even if the type wasn't annotated with a `??` or hypothetical other sigil.\nWe 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\"\ndefaultness guarantee in the language.\n\nFinally, there was some recognition and discussion around how this issue is very similar to another long standing request from\nlibraries like Unity: custom nullability. The idea is that with C#, among the entire value domain of a type we recognize and have\nbuilt language support for one _particular_ invalid value: `null`. However, this isn't the only invalid value that a value domain\nmay have. Unity objects have backing C++ instances, and they override the `==` operator to allow comparison with `null` to also\nreturn true if the backing field has not yet been instantiated. While the C# object itself is not `null` in this case, it _is_\ninvalid, and should be treated as such. However, this doesn't play well with other operators in C#, such as `?.`, `??`, and\n`is null`. These all special-case a particular invalid value, `null`, and don't play well with other invalid values, leading\nlibraries like Unity to encourage users to write code that does not take advantage of modern idiomatic C# features. This issue is\nvery similar to the non-defaultable structs issue: we'd like to recognize a particular value in the domain of a struct type as\ninvalid. It might be better to implement this as a general invalid value pattern that any type, struct or class, can opt into.\n\n#### Conclusion\n\nFor both of these issues, we need to take more time and rethink them again, especially in light of the removal of `??`, which\nthe non-defaultable struct type proposal relied on heavily. A small group will explore the space more, particularly the more\ngeneral invalid object pattern, and come back with a rethought proposal. The guiding principle that this group should keep in\nmind from the current proposal is \"Users should be able to change something from a class to a struct for performance without\nsignificant redesign due to having to handle an invalid `default` struct value.\"\n\n### Confirming unspeakable `Clone` method implications\n\nBefore we ship unspeakable `Clone` methods for `with` expressions, we wanted to make sure that we've worked through the\nconsequences of doing so, and are sure that the language will be able to continue to evolve without breaking scenarios that\nwe are enabling with this feature. In particular, in the face of a general factory pattern that users can use to extend record\ntypes, or even potentially expand what is today a record type into a full blown type without breaking their customers, we\nmight need to emit both the unspeakable `Clone` method and a factory method in the future. A guiding principle for record design\nhas been that whether something is a record is an implementation detail. Therefore whatever future method we add that will allow\na regular class type to participate in a `with` expression will likely have to emit this method as well.\n\nWe also considered whether we should take any measures right now to try and keep our design space open in records for adding a\nuser-overridable `Clone` method. We could try emitting the method now, and modreq it so that it cannot be directly called from\nC# code, or we could just block users from creating a `Clone` method in a record entirely.\n\n#### Conclusion\n\nWe're fine with the unspeakable name being a feature of records forever going forward. We will also reserve `Clone` as a member\nname in records to ensure that our future selves will be able to design in this space.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-07-06.md",
    "content": "\n# C# Language Design Meeting for July 6th, 2020\n\n## Agenda\n\n1. [Repeated attributes on `partial` members](#repeated-attributes-on-partial-members)\n2. [`sealed` on `data` members](#sealed-on-data-members)\n3. [Required properties](#required-properties)\n\n## Quote of the Day\n\n\"Is there a rubber stamp icon I can use here?\"\n\n## Discussion\n\n### Repeated attributes on `partial` members\n\nhttps://github.com/dotnet/csharplang/pull/3646\n\nToday, when we encounter attribute definitions among partial member definitions, we merge these attributes, applying attributes multiple\ntimes if there are duplicates across the definitions. However, if there are duplicated attributes that do not allow multiples, this merging\nresults in an error that might not be resolvable by the user. For example, a source generator might copy over the nullable-related\nattributes from the stub side to the implementation side. This is further exacerbated by the new partial method model: previously, the\nprimary generator of partial stubs was the code generator itself. WPF or other code generators would generate the partial stub, which the\nuser could then implement to actually create the implementation. These generators generally wouldn't add any attributes, and the user could\nadd whatever attributes they wanted. However, the model is flipped for the newer source generators. Users will put attributes on the stub in\norder to hint to the generator how to actually implement the method, so either the generator will have never copy attributes over (possibly\ncomplicating implementation), or it will have to be smart about only copying over attributes that matter. It would further hurt debugability\nas well; presumably tooling will want to show the actual implementation of the method when debugging, and it's likely that the tooling won't\nwant to try and compute the merged set of attributes from the stub and the implementation to show in debugging.\n\nWhat 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\nmembers view the stub as a hint that something like this method exists, and the implementation provides the final source of truth. This group\nwould expect that, if we were designing again, all attributes would need to be copied to the implementation and attributes on the stub would\neffectively be ignored. The other segment of the LDT viewed partial methods in exactly the opposite way: the stub is the source of truth, and\nthe implementation had better conform to the stub. This reflects these two worlds of previous source generators vs current generators: for the\nprevious 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\ncreating the stubs, so that's the source of truth.\n\nWe also briefly considered a few ways of enabling the attribute that keys the generator to be removed from the compiled binary, so that it\ndoes 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\ndon't see anything in this feature conflicting with source-only attributes. We also don't see anything in this feature conflicting with\nfuture expansions to partial members, such as partial properties.\n\n#### Conclusion\n\nThe proposal is accepted. For the two open questions:\n\n1. We will deduplicate across partial types as well as partial methods if `AllowMultiple` is false. This is considered lower priority if a\nfeature needs to be cut from the C# 9 timeframe.\n2. We don't have a good use-case for enabling `AllowMultiple = true` attributes to opt into deduplication. If we encounter scenarios where\nthis is needed, we can take it up again at that point.\n\n### `sealed` on `data` members\n\nIn a [previous LDM](LDM-2020-06-22.md#data-properties), we allowed an explicit set of attributes on `data` members, but did not include\n`sealed` in that list, despite allowing `new`, `override`, `virtual`, and `abstract`. `sealed` feels like it's missing, as it's also\npertaining to inheritance.\n\n#### Conclusion\n\n`sealed` will be allowed on `data` properties.\n\n### Required properties\n\nhttps://github.com/dotnet/csharplang/issues/3630\n\nIn C# 9, we'll be shipping a set of improvements to nominal construction scenarios. These will allow creation of immutable objects via\nobject initializers, which has some advantages over positional object creation, such as not requiring exponential constructor growth\nover object hierarchies and the ability to add a property to a base class without breaking all derived types. However, we're still\nmissing one major feature that positional constructors and methods have: requiredness. In C# today, there is no way to express that a\nproperty 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\nneed to be initialized during object creation: any that aren't initialized are defaulted today. The nullable feature will issue warnings\nfor initialized fields inside the declaration of a class, but there is no way to indicate to the feature that this field must be initialized\nby the consumer of the class. This goes further than just the newly added `init`: mutable properties should be able to participate in this\nfeature as well. In order for staged initialization to feel like a true first-class citizen in the language, we need to support requiredness\nin the contract of creating a class via the feature.\n\nThe LDM has seemingly universal support of making improvements here. In particular, the proposed concept of \"initialization debt\" resonated\nstrongly with members. It allows for a general purpose mechanism that seems like it will extend natural to differing initialization modes.\nWe categorized the two extreme ends of object initialization, both of which can easily be present in a single nominal record: Nothing is\ninitialized in the constructor (the default constructor), and everything is initialized in the constructor (the copy constructor). The next\nquestion is how are these initialization contracts created: there's some tension here with the initial goal of nominal construction.\n\nFundamentally, initialization contracts can be derived in one of two ways: implicitly, or explicitly. Implicit contracts are attractive at\nfirst glance: they require little typing, and importantly they're not brittle to the addition of new properties on a base class, which was\nan important goal of nominal creation in the first place. However, they also have some serious downsides: In C# today, public contracts for\nconsumers are always explicit. We don't have inferred field types or public-facing parameter/return types on methods/properties. This means\nthat any changes to the public contract of an object are obvious when reviewing changes to that type. Implicit contracts change that. It\nwould 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\nbase type, and suddenly all uses of `with` on that type are now broken.\n\nWe 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\nany fields that the initer or setter for that property initializes can be considered part of the \"constructor body\" for the purposes of\ndetermining if a field has been initialized. Fields should be able to be required as well. This could extend well to structs: currently,\nstruct constructors are required to set all fields. If they can instead mark a field or property as required then the constructor wouldn't\nhave to initialize it all.\n\nOne way of implementing initialization debt would be to tie it to nullable: it already warns about lack of initialization for not null\nfields when the feature is turned on. We're still in the nullable adoption phase where we have more leeway on changing warnings, so we\ncould actually change the warning to warn on _all_ fields, nullable or not. This would effectively be an expansion of definite assignment:\nlocals 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\ncould essentially make all fields required when nullable is enabled, regardless of their type. Then, C# 10 could add a feature to enable\nskipping the initialization of some members based on whether the consumer must initialize them. This is also not really a breaking change\nfor structs: they're already required to initialize all fields in the constructor. However, it would be a breaking change for classes, and\nwe worry it would be a significantly painful one, especially with no ability to ship another preview before C# 9 releases. `= null!;` is\nalready a significant pain point in the community, and this would only make it worse.\n\nWe came up with a few different ways to mark a property as being required:\n* A keyword, as in the initial proposal, on individual properties.\n* Assigning some invalid value to the field/property. This could work well as a way to be explicit about what fields a particular\nconstructor would require, but does leave the issue about inherited brittleness.\n* Attributes or other syntax on constructor bodies to indicate required properties.\n\nWe like the idea of some indication on a property itself dictating the requiredness. This puts all important parts of a declaration together,\nenhancing readability. We think this can be combined with a defaulting mechanism: the property sets whether it is required, and then a\nconstructor can have a set of levers to override individual properties. These levers could go in multiple ways: a copy constructor could\nsay that it initializes _all_ members, without having to name individual members, whereas a constructor that initializes one or two specific\nmembers could say it only initializes those specific members, and inherits the property defaults from their declarations. There's still\nopen questions in this proposal, but it's a promising first start.\n\n#### Conclusion\n\nWe have unified consensus that in order for staged initialization to truly feel first-class in the language, we need a solution to this issue,\nbut we don't have anything concrete enough yet to make real decisions. A small group will move forward with brainstorming and come back to\nLDM with a fully-fleshed-out proposal for consideration.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-07-13.md",
    "content": "# C# Language Design Meeting for July 13th, 2020\n\n## Agenda\n\n1. [Generics and generic type parameters in aliases](#Generics-and-generic-type-parameters-in-aliases)\n2. [\"closed\" enum types](#\"closed\"-enum-types)\n3. [Allow `ref` assignment for switch expressions](#Allow-`ref`-assignment-for-switch-expressions)\n4. [Null suppressions nested under propagation operators](#Null-suppressions-nested-under-propagation-operators)\n5. [Relax rules for trailing whitespaces in format specifier](#Relax-rules-for-trailing-whitespaces-in-format-specifier)\n6. [Private field consideration in structs during definite assignment analysis](#Private-field-consideration-in-structs-during-definite-assignment-analysis)\n7. [List patterns](#list-patterns)\n8. [Property-scoped fields and the `field` keyword](#Property-scoped-fields-and-the-field-keyword)\n9. [File-scoped namespaces](#file-scoped-namespaces)\n10. [Allowing `ref`/`out` on lambda parameters without explicit type](#Allowing-ref/out-on-lambda-parameters-without-explicit-type)\n11. [Using declarations with a discard](#Using-declarations-with-a-discard)\n12. [Allow null-conditional operator on the left hand side of an assignment](#Allow-null-conditional-operator-on-the-left-hand-side-of-an-assignment)\n12. [Top level statements and functions](#Top-level-statements-and-functions)\n13. [Implicit usings](#implicit-usings)\n\n## Quote of the day\n\n\"It does actually seem like this pattern is the 98% case...\"\n\"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...\"\n\"Not fair, I was going to say that.\"\n\n## Discussion\n\nThis meeting was issue triage. There will not be much detail on any particular issue, just a general summary\nof the LDM's feeling and the milestone that we triaged to.\n\n### Generics and generic type parameters in aliases\n\nhttps://github.com/dotnet/csharplang/issues/1239\n\nIn general, we want to make improvements in this area. We should also be open to making other enhancements\nin this space, such as allowing tuple syntax on the right side, or allowing C# keywords like `int`. There's\nalso a set of features that we should investigate in parallel, such as globally-visible aliases or publicly-\nexported aliases.\n\n#### Conclusion\n\nTriaged for C# 10 for now so that we can look at the space hollistically in the near term.\n\n### \"closed\" enum types\n\nhttps://github.com/dotnet/csharplang/issues/3179\n\nThis is a solution to the very common complaints around enum usage, particularly in switch expressions and other\nexhaustiveness scenarios. It will also work well with DUs, and we should make sure that whatever syntax we use\nthere works well with closed or sealed enum types as well.\n\n#### Conclusion\n\nTriaged for C# 10 to look at in coordination with DUs.\n\n### Allow `ref` assignment for switch expressions\n\nhttps://github.com/dotnet/csharplang/issues/3326\n\nWe like this proposal. You can already do this with ternaries, and it's odd that you can't do this with switch\nexpressions as well. It's not high priority, but we'd be happy to see it in the language. Like ternaries, the\nref version would not be target-typed.\n\n#### Conclusion\n\nTriaged for Any Time.\n\n### Null suppressions nested under propagation operators\n\nhttps://github.com/dotnet/csharplang/issues/3393\n\nThis will be a breaking change, so we need to get it in as soon as possible.\n\n#### Conclusion\n\nC# 9 timeframe. We need to make a syntax proposal and approve it.\n\n### Relax rules for trailing whitespaces in format specifier\n\nhttps://github.com/dotnet/csharplang/issues/3414\n\nIn reading this proposal, we're unsure whether the request was for _ignoring_ trailing spaces in format specifiers,\nor allowing them and including them in the format specifier. We think that either way this is interpreted, it will\nbe confusing: trailing spaces are allowed in front of an interpolated expression and mean nothing, but for things\nlike `DateTime`, spaces are valid parts of a format specifier and will be respected in the output. We think that\neither behavior here would be confusing, with no clear indication on which the user wants.\n\n#### Conclusion\n\nRejected.\n\n### Private field consideration in structs during definite assignment analysis\n\nhttps://github.com/dotnet/csharplang/issues/3431\n\nThis is a bug from the native compiler that had to be reimplemented in Roslyn for compat, but it's always been\none of the prime candidates for a warning wave (and is already supported as an error in the compiler via the strict\nfeature flag). There is some contention whether it should be a warning or an error in this wave. There is also a\nconcern that this will combine with the `SkipLocalsInit` feature in C# 9 to expose an uninitialized memory hole in\nC# with no use of `unsafe` or `System.Unsafe` required.\n\n#### Conclusion\n\nWe need to look at this ASAP to make sure that we don't unintentionally expose unsafety in the language without\nuser intention. We'll schedule this for next week.\n\n### Remove restriction that optional parameters must be trailing\n\nhttps://github.com/dotnet/csharplang/issues/3434\n\nIt's possible to define such methods in metadata with the correct attribute usage _and_ call them from C# today.\nThis would just be about removing the restriction from _defining_ them in C#.\n\n#### Conclusion\n\nTriaged for Any Time.\n\n### List patterns\n\nhttps://github.com/dotnet/csharplang/issues/3435\n\nWe have an open proposal that with a prototype. We like the general direction it takes, but we need to have more\ndetailed design review of it and possibly make a few different decisions. This is a direction we want to take\npattern matching in future releases, so we'll continue iterating on this.\n\n#### Conclusion\n\nTriaged into C# 10 for design work.\n\n### Property-scoped fields and the `field` keyword\n\n* https://github.com/dotnet/csharplang/issues/133\n* https://github.com/dotnet/csharplang/issues/140\n\nWe've started doing design work around both of these issues. We should continue doing that.\n\n#### Conclusion\n\nTriaged into C# 10.\n\n### File-scoped namespaces\n\nhttps://github.com/dotnet/csharplang/issues/137\n\nThis has been a large request for a long time that reflects the default of almost every single C# file written.\nThere's still some design work to do, particularly in how that will affect `using` statements, but it's work\nthat we should take on.\n\n#### Conclusion\n\nTriaged into C# 10.\n\n### Allowing `ref`/`out` on lambda parameters without explicit type\n\nhttps://github.com/dotnet/csharplang/issues/338\n\nWe've heard this request a few times, and while we don't see any particular issue with this, it's not a priority\nfor the team at this point. If a spec/implementation was provided we'd likely accept it but won't go out of our\nway to add it unless something else changes here.\n\n#### Conclusion\n\nTriaged to Any Time.\n\n### Using declarations with a discard\n\nhttps://github.com/dotnet/csharplang/issues/2235\n\nThere's still some open design questions here, particularly around possibly ambiguous syntaxes. We need to keep\niterating on this to find a design that we like.\n\n#### Conclusion\n\nTriaged for X.X, pending a new proposal.\n\n### Allow null-conditional operator on the left hand side of an assignment\n\nhttps://github.com/dotnet/csharplang/issues/2883\n\nInitial discussion shows a big LDT split on whether `?.` should be able to effectively a conditional ref. We\nwould need to discuss further, but aren't ready to outright approve or reject the feature.\n\n#### Conclusion\n\nTriage to X.X for future discussion.\n\n### Top level statements and functions\n\nhttps://github.com/dotnet/csharplang/issues/3117\n\nThis is part 2 of the work we started in C# 9 with top-level statements: designing free-floating functions that\ncan sit on the top level without any containing type. We need to continue examining this context of scripting\nunification, which we plan to continue doing on an ongoing basis.\n\n#### Conclusion\n\nTriage into C# 10 for ongoing discussion.\n\n### Implicit usings\n\nhttps://github.com/dotnet/csharplang/issues/3428\n\nThis is another issue arising of discussions on top-level statements and using C# as a scripting language:\nattempting to make the language more brief by specifying common imports on the command line or as part of\nthe project file is certainly one way to remove boilerplate. However, it's a controversial feature that often\ndraws visceral reactions. We need to discuss this more and figure out if it's a feature we want to have in C#,\ntaking into account our increased focus on scripting-like scenarios. It's worth noting that CSX has a limited\nform of this support already, and implementing this in C# proper would bring us one step closer to unifying the\ntwo dialects.\n\n#### Conclusion\n\nTriage to C# 10 for discussion.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-07-20.md",
    "content": "# C# Language Design Meeting for July 20th, 2020\n\n## Agenda\n\n1. [Finishing Triage](#finishing-triage)\n    a. [Extend with expression to anonymous type](#Extend-with-expression-to-anonymous-type)\n    b. [Required properties](#Required-properties)\n    c. [Shebang support](#shebang-support)\n2. [Private reference fields in structs with `SkipLocalsInit`](#Private-reference-fields-in-structs-with-`SkipLocalsInit`)\n\n## Quote of the Day\n\n\"If you go get a beer from the fridge or wherever you keep them and drink it right now, I'll refund you.\"\n\n## Discussion\n\n### Finishing Triage\n\n#### Extend with expression to anonymous type\n\nhttps://github.com/dotnet/csharplang/issues/3530\n\nWe don't see any reason why we couldn't extend `with` expressions to handle anonymous types, and we universally support\nthe idea. We do see room for further improvement as well. Struct types should be generally possible to `with`, and in\nparticular tuples should feel first class here. Some other ideas for future improvements that we'll need to keep in mind\nwhen designing anonymous types is an ability to specify a `withable` constraint: perhaps that's a thing we could do via\ntypeclasses, but if that's a thing that should be specifiable then we'll want to make sure that whatever we do for structs\nand anonymous types works well with it.\n\n##### Conclusion\n\nTriaged into C# 10 for discussion with the other `with` enhancements\n\n#### Required properties\n\nhttps://github.com/dotnet/csharplang/issues/3630\n\nA smaller group is currently fleshing this proposal out in the direction of initializer debt, and is looking to talk more\nabout it in the next few months.\n\n##### Conclusion\n\nTriaged for C# 10.\n\n#### Shebang support\n\nhttps://github.com/dotnet/csharplang/issues/3507\n\nThis is part of the next step in the C# scripting discussion. In particular, this proposal details just one, very small\npiece of the puzzle here, namely the ability have a C# file startup an environment. There is significantly more work to\nbe done in the language and tooling to effectively modernize the loose-files support for C#. Today, C# code has a core\nconcept that cs files themselves do not contain information about the runtime environment. They don't specify the target\nruntime, nuget dependencies, where tools can be found, or anything else similar (beyond some `#ifdef` blocks). Supporting\nthis would be intentionally eroding this aspect, which we need to make sure we're doing with intention and design. There\nis support among LDT members for this scenario, so we'll continue to look at.\n\n##### Conclusion\n\nTriaged into C# 10 for discussion. We acknowledge that we may well not ship anything in this space as part of C# 10, but\nwe want to start discussing possible futures here in the coming X months, not X years.\n\n### Private fields in structs with `SkipLocalsInit`\n\nhttps://github.com/dotnet/csharplang/issues/3431\n\nProposal 1: https://github.com/dotnet/roslyn/issues/30194#issuecomment-657858716\nProposal 2: https://github.com/dotnet/roslyn/issues/30194#issuecomment-657900257\n\nThis topic was brought up last week when we realized there was a potential hole in `SkipLocalsInit` with definite\nassignment, where we realized it's possible to observe uninitialized memory via private fields. When importing metadata,\nthe native compiler ignored private fields, including private fields in structs, and did not require them to be considered\ndefinitely assigned before usage. This behavior was preserved when we implemented Roslyn, as attempting to break it was\ntoo large of a change for organizations to adopt. Both of these proposals ensure that, with `SkipLocalsInit` on a method,\nit's considered an error to not definitely assign here, which was fine with LDM as this is a new feature and cannot break\nanyone. We then looked at the differences between the two proposals, namely whether the definite assignment diagnostic\nshould be a warning or an error when users opt into to a new warning wave. We found the arguments around incremental\nadoption compelling: we don't want users to be blocked off from adopting new warning waves and making their code at least\na little safer by issuing errors that cannot be ignored. If users want to ensure that these warnings are fixed in their\ncode, they can use `warnAsError` to turn these specific warnings or all warnings into errors, as you can today.\n\n#### Conclusion\n\nProposal 1 has been chosen:\n\n1. If a method has the [SkipLocalsInit] attribute, or the compilation has the \"strict\" feature enabled, we use the strong\nversion of analysis for its body. Otherwise\n2. If a sufficiently high /warnversion (>= 5) is enabled, we run the strong version of analysis, and\n  a. If it reports no diagnostics, we are done.\n  b. If it reports diagnostics, we run the weak version of analysis. Errors that are common to the two runs are reported\n  as errors, and errors only reported by the strong version are downgraded to a warning.\n3. Otherwise we run the weak version of analysis.\n\n### Future record direction\n\nSee https://github.com/dotnet/csharplang/issues/3707 for the full list. We briefly went through the list here to gauge\nsupport from LDT members on the various proposals. We didn't get particularly in depth on any one part, but some\nhighlights:\n\n* `init` fields and methods - We rejected these in 9, deciding to wait for community feedback. We believe this is still\nthe right decision, and want to hear user scenarios before proceeding further.\n* Final initializers - We briefly entertained the idea of having an `init { }` syntax to guarantee that a block is called\nafter a method. This was later rejected as too complicated after design review. Like `init`, we need to get a better\nhandle on the user scenarios.\n* Required members - We have broad support for doing something in this space.\n* Factores - We have broad support for doing something in this space.\n* User-defined cloning - Will likely need to be designed hand-in-hand with factories\n* Cross-inheritance between records and non-records - part of the initial record goal was that `record` is pure syntactic\nsugar. If that's still a goal, then we need to do more work here.\n* Generalized primary constructors - Mixed support here. We need to do more design work.\n* Primary constructor bodies - Might be done for the former. We need to flesh this out so we can determine how to apply\nattributes to record constructors.\n* Discriminated unions - We need to determine whether this will be a simple syntactic shorthand for a general sealed type\nhierarchy feature, or if this will be the only way to declare such hierarchies.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-07-27.md",
    "content": "# C# Language Design Meeting for July 27th, 2020\n\n## Agenda\n\n- [Improved nullable analysis in constructors](#Improved-nullable-analysis-in-constructors)\n- [Equality operators in records](#Equality-operators-in-records)\n- [`.ToString()` or `GetDebuggerDisplay()` on records](#ToString-or-DebuggerDisplay-on-record-types)\n- [W-warnings for `T t = default;`](#W-warnings-for-`T-t-=-default;`)\n\n## Quote of the Day\n\n\"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.\"\n\n![Delectable Tea or Deadly Poison](delectable_tea_2020_07_27.png)\n\n## Procedural Note\n\nLDM is going on August hiatus as various members will be out. We'll meet next on August 24th, 2020.\n\n## Discussion\n\n### Improved nullable analysis in constructors\n\nhttps://github.com/dotnet/csharplang/blob/master/proposals/nullable-constructor-analysis.md\n\nThis proposal is a tweak to the nullable warnings we emit today in constructors that would bring these warnings more in line with\nbehavior for `MemberNotNull`, as well as addressing a few surprising cases where you do not get a deserved nullable warning today.\nThis code, for example, has no warnings today:\n```cs\npublic class C\n{\n    public string Prop { get; set; }\n    public C() // we get no \"uninitialized member\" warning, as expected\n    {\n        Prop.ToString(); // unexpectedly, there is no \"possible null receiver\" warning here\n        Prop = \"\";\n    }\n}\n```\nWe consider this to be possible to retrofit into the nullable feature, as we're still within the nullable adoption phase. After\nC# 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\n(which would heavily complicate the implementation). Additionally, even though we're still within the nullable adoption phase,\nthis is a relatively big change in warnings that could result in lots of new errors in codebases that have heavily adopted nullable.\nWe also considered whether there could be any interference here with C# 10 plans around required properties or initialization debt.\nThere does not appear to be, as this would effectively be the initialization debt world where a constructor is required to set all\nproperties in the body, and any relaxation of this by requiring properties to be initialized at construction site will play well.\n\n#### Conclusion:\n\nWe 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\nat that point.\n\n### Equality operators in records\n\nhttps://github.com/dotnet/csharplang/issues/3707#issuecomment-661800278\n\nWe've talked briefly about equality operators in records prior to now, but we never ended up making any firm decisions, so now we\nneed to make an intentional decision about records before we ship as doing so after would be a breaking change. The concern is that,\nbecause class types inherit a default equality operator from simply being a class, we'll get into a scenario where a record's `Equals`\nmethod could return `true`, and the `==` operator returns false. Most standard .NET \"values\" behave in this fashion as well: `string`\nbeing the most common example.\n\nThere are some interesting niggles, however, particularly with `float` and `double` values. For example,\nthis code:\n```cs\nvar a = (float.NaN, double.NaN);\nSystem.Console.WriteLine(a == a); // Prints false\nSystem.Console.WriteLine(a.Equals(a)); // Prints true\n```\nThis happens because the `==` operator and the `Equals` method for floats and doubles behave differently. The `==` operator uses IEEE\nequality, which does not consider `NaN` equal to itself, while `Equals` uses the CLR definition of equality, which does. When combined\nwith `ValueTuple`, this makes for an interesting set of behaviors, as `ValueTuple` doesn't have its own definition of the `==` operator.\nRather, the compiler synthesizes the set of `==` operators on the component elements of the tuple. This means that for generic cases,\nsuch as `public void M<T>((T, T) tuple) { _ = tuple == tuple; }`, you get an error when attempting to use `==` on the tuple, since `==`\nis not defined on generic type parameters. `ValueTuple` is a particularly special case here though. The compiler special cases knowledge\nof the implementation, which is not generalizable across inheritance hierarchies with record types. In order for an implementation to do\nmemberwise `==` across all levels of a record type, there will have to be hidden virtual methods to take care of this, and it gets more\ncomplicated when you consider that a derived record type could introduce a generic type parameter field that can't be `==`'d. We feel\nthat attempting to get too clever here would end up being unexplainable, so if we want to implement the operators, it should just\ndelegate to the virtual `Equals` methods we already set up.\n\nNext, we considered whether we should implement `==` operators on all levels of a record inheritance hierarchy, or just the top level.\nWith 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\neventual goal is to enable records and classes to inherit from each other, and that point if every level didn't provide its own\nimplementation it could end up being possible to break assumptions. Further, attempting to trim implementations of `==` and `!=` would\nend up resulting in complicated rules that don't feel necessary: adding the operators isn't going to bloat metadata size, will potentially\nallow eliminating of some levels of equality method calls, and future proofs ourselves.\n\nFinally, we looked at whether the user will be able to provide their own implementation of `==` and `!=` operators, and if we'd error\non this or allow it and not generate the operators ourselves in this case. We feel that allowing this would complicate records: there\nare existing extension points into record equality that can be overridden as needed, and we want to have a stronger concept of `Equals`\nand `==` being the same. If there are good user scenarios around allowing this, we can consider it at a later point.\n\n#### Conclusion\n\nWe will generate the `==` and `!=` operators on every level of a record hierarchy. These implementations will not be user-overridable,\nand they will delegate to `.Equals`. The implementation will have this semantic meaning:\n```cs\npubic static bool operator==(R? one, R? other)\n    => (object)one == other || (one?.Equals(other) ?? false);\npublic static bool operator!=(R? one, R? other)\n    => !(one == other);\n```\n\n### `ToString` or `DebuggerDisplay` on record types\n\n#### Initial proposal\n\n1. `record` generates a ToString that prints out its type name followed by a positional syntax: Point(X: 1, Y: 2).\n(issue: disfavors nominal records)\n2. `record` generates a ToString that does the above and also appends nominal properties by calling ToStringNominal:\n`FirstName: First, LastName: Last`, and assembles the parts into `Person { FirstName: First, LastName: Last, ID: 42 }`.\n\n#### Discussion\n\nThe initial proposal here is to add a `ToString` method that would format a record type by their positional properties, and have a\nseparate method for creating a string from nominal properties named something like `ToStringNominal`. The initial reaction was that\nthis seemed overly complicated: there should just be one method that does \"the right thing<sup>tm</sup>\". There's further question\nabout whether having a `ToString` or `DebuggerDisplay` would be useful: depending on the properties of the record type, it could end\nup doing more harm than good (if the properties were lazy, for example). Additionally, when a `ToString` is provided it's often domain\nspecific, 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\ncommon scenarios in which a `ToString` would be useful:\n\n* Viewing in the debugger. This could be done with just a `DebuggerDisplay` attribute, or users can just expand the object to view the\nproperties of it as you can today.\n* Viewing in test output. Using an equality test, for example, will usually print the objects if they were not equal to each other,\nand it would be useful if that was actually meaningful, particularly for these value-like class types.\n* Logging output. This is a very similar case to the previous.\n\nWe also considered whether we should implement this via source generators. However, it feels very similar to equality: we have a\nsensible default there, and anyone who wants to customize (this field should be excluded, this one should use sequence equality)\ncan either write it manually or use a source generator. The same arguments apply here: we can provide a sensible default that will\nenable short syntax, and anyone who wants to get custom behavior can override this.\n\nAfter considering _whether_ to do this feature, we looked at what properties would be included in such a feature. How, would they\nbe formatted, and which ones are considered? The initial proposal was for positional only, with a separate method for nominal\nproperties. We felt that this was too complicated and likely not to be the right defaults: it totally disadvantages nominal records\nand makes the implementation more complicated. The options we considered are:\n\n* The same members as .Equals. This means all fields of a class, translating auto-generated backing fields to their properties for\ndisplay names. This would make explaining what appears in the `ToString` simple: it's the equality members, full stop.\n* The positional members and `data` members of a record. We feel that this is too restrictive, especially since `data` members will\nnot be shipping in final form with C# 9: they'll still be under the preview language version.\n* The fields and properties of a record type with some accessibility, accessibility to be determined next. We believe that it's very\nunusual for a `ToString` to display `private` fields, which the other proposal would do.\n\nWe leaned towards just doing the fields and properties of a type, with some accessibility. Finally, we looked at what accessibility\nto use by default for these:\n\n* All members not marked `private`. This means that things that not relevant to a consumer of the type, such as `protected` fields,\nshow up in the `ToString`, and violates encapsulation principles.\n* All `public` and `internal` members. This propsal has some of the same issues as the previous one: you could making an `internal`\ntype that implements a `public` interface, and it would be odd if the final user sees that internal state.\n* At least as accessible as the record itself. This would mean that if the `record` was `internal`, then internal members would be\nshown. If the record was `public`, then only `public` members would be shown. This doesn't solve any of our issues with the previous\nproposal, and adds a behavioral difference between making a type `public` or `internal`.\n* Only `public` members. This is what the positional constructor will generate by default, and it feels like the most natural state\nto choose. This ensures that encapsulation isn't violated, and records with lots of `internal` or `private` state that want to\ndisplay these in a `ToString` are likely not really records anyway. If the user really wants to change this, they can customize it\nas they choose.\n\nConclusion:\n\nWe'll have a generated `ToString`, that will display the public properties and fields of a `record` type. We'll come back with a\nspecific proposal on how this will be implemented at a later point.\n\n### W-warnings for `T t = default;`\n\nJust after we initially shipped C# 8, we made a change to warn whenever `default` was assigned to a local or property of type `T`,\nor when a default was cast to that type. There was no way to silence this warning without using a `!`, so we reverted the change.\nHowever, now that we are shipping `T?`, there is an actual syntax that users can write in order to express \"this location might\nbe assigned default\". We know from experience that this is something that users already do a lot, so making a change here would be\npretty breaking, even for the nullable rollout phase of the first year. Further, as we know that if the `!` is the only way to get\nrid of this warning then we'll get lots of feedback from users, we believe that we can't unconditionally warn here: you can only\nget 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\nyou would only get it when you opt into the warning wave. An important thing to consider with doing this as a warning wave implies\nthat it should be separate error code from 8600: we've previously told people that if they don't want to annotate all their local\nvariables with `?`s, then they should disable that warning and all the rest of the warnings will be actual safety warnings. This\nwould add another warning to that list to disable. We could make it memorable as well, but one of the key aspects in warning waves\nis 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\nwarning without turning off all the existing 8600 warnings. All that being said, there's also a serious backcompat concern here,\nas introducing the warning when upgrading to C# 9 under the existing error code could cause people to hold off on upgrading at all.\n\n#### Conclusion\n\nWe'll add a new warning here, under a warning wave.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-08-24.md",
    "content": "# C# Language Design Meeting for July 27th, 2020\n\n## Agenda\n\n- [Warnings on types named `record`](#warnings-on-types-named-record)\n- [`base` calls on parameterless `record`s](#base-calls-on-parameterless-records)\n- [Omitting unnecessary synthesized `record` members](#omitting-unnecessary-synthesized-record-members)\n- [`record` `ToString` behavior review](#record-tostring-behavior-review)\n    - [Behavior of trailing commas](#behavior-of-trailing-commas)\n    - [Handling stack overflows](#handling-stack-overflows)\n    - [Should we omit the implementation of `ToString` on `abstract` records](#should-we-omit-the-implementation-of-tostring-on-abstract-records)\n    - [Should we call `ToString` prior to `StringBuilder.Append` on value types](#should-we-call-tostring-prior-to-stringbuilder.append-on-value-types)\n    - [Should we try and avoid the double-space in an empty record](#should-we-try-and-avoid-the-double-space-in-an-empty-record)\n    - [Should we try and make the typename header print more economic](#should-we-try-and-make-the-typename-header-print-more-economic)\n- [Reference equality short circuiting](#reference-equality-short-circuiting)\n\n## Quote of the Day\n\n\"He was hung up on his principles!\"\n\n\"I painted my tower all ivory.\"\n\n## Discussion\n\n### Warnings on types named `record`\n\nWe previously discussed warning in C# 9 when a type is named `record`, as it will need to be escaped in field\ndefinitions in order to parse correctly. This is a breaking change being made in C# 9, but we didn't explicitly\nrecord the outcome of the warning discussion. We also discussed going further here: we could make lower-cased\ntype names a warning with the next warning wave, under the assumption that lowercase names make good keywords.\nFor example, we could start warning on types named `async` or `var`. Those who want to forbid usage of those\nfeatures in their codebase have a solution in analyzers.\n\n#### Conclusion\n\nWe will warn on types named `record` in C# 9. Further discussion will need to happen for lowercase type names\nin general, as there are globalization considerations, and we feel that disallowing `record` might be a good\nsmoke test for reception to the idea in general.\n\n### `base` calls on parameterless `record`s\n\nWe have a small hole in records today where this is not legal, and there is no workaround to making it legal:\n\n```cs\nrecord Base(int a);\nrecord Derived : Base(1);\n```\n\nThe spec as written today explicitly forbids this: \"It is an error for a record to provide a `record_base`\n`argument_list` if the `record_declaration` does not contain a `parameter_list`.\" However, there is good\nreason to allow this, and while this design may have fallen out of the principles that were set out given\nthat a default constructor for a nominal record is not recognized as a primary constructor, this seems to\nviolate principles around generally making record types smaller. Further, with the spec as written today\nit's not possible to work around this issue by giving `Derived` an empty parameter list, as parameter lists\nare not permitted to be empty.\n\nA solution to this problem is relatively straightforward: we make the default constructor of a nominal record\nthe primary constructor, if no other constructor was provided. This seems to mesh well with the existing rules,\nand seems to work well with future plans for generalized primary constructors. We could consider 2 variants of\nthis: requiring empty parens on the type declaration in all cases, or only requiring them in cases where the\ndefault constructor would otherwise be omitted (if another constructor was added in the `record` definition).\n\n#### Conclusion\n\nWe'll allow empty parens as a constructor in C# 9. We're also interested in allowing the parens to be omitted\nwhen a default constructor would otherwise be emitted, but if this doesn't make it in C# 9 due to time\nconstraints it should be fine to push back to v next.\n\n### Omitting unnecessary synthesized `record` members\n\nSome record members might be able to be omitted in certain scenarios if they're unneeded. For example, a\n`sealed` `record` that derives from `System.Object` would not need an `EqualityContract` property, as it\ncan only have the one contract. We could also simplify the implementation of `ToString` if we know there\nwill be no child-types that need to call `PrintMembers`.\n\nHowever, despite leading to simplified emitted code for these types, we're concerned that this will cause\nother code to become more complicated. We'll need to have more complicated logic in the compiler to handle\nthese cases. Further, source generators and other tools that interact with records programmatically will\nhave to duplicate this logic if they need to interact with record equality or any other portion of code that\n\"simplified\" by this mechanism. We further don't see a real concern for metadata bloat in this scenario,\nas we aren't omitted fields from the record declaration.\n\n#### Conclusion\n\nThere are likely more downsides than upsides to doing something different here. We'll continue to have this\nbe regular.\n\n### `record` `ToString` behavior review\n\nNow that we have a proposal and implementation for `ToString` on record types, we'll go over some standing\nquestions from initial implementation review. Prior art for this area in C# that we found relevant was\n`ToString` on both tuples and anonymous types.\n\n#### Behavior of trailing commas\n\nThere is a proposal to simplify the implementation of `ToString` by always printing trailing commas after\nproperties. This would remove the need for some bool tracking flags for whether a comma was printed as\npart of a parent's `ToString` call. However, no prior art (in either C# or other languages) that we could\nfind does this. Further, it provokes a visceral reaction among team members as feeling unfinished, and that\nit would be the first bug report we get after shipping it.\n\n##### Conclusion\n\nNo trailing commas.\n\n#### Handling stack overflows\n\nThere is some concern that `ToString` could overflow if a record type is recursive. While this is also true\nof equality and hashcode methods on records, there is some concern that `ToString` might be a bit special\nhere, as it's the tool that a developer would use to get a print-out of the record to find the cyclic element\nin the first place. There's examples in the javascript world of this being a pain point. However, any\nsolution that we come up with for records will have limitations: it wouldn't be able to protect against\nindirect cycles through properties that are records but not records of the same type, or against cycles\nin properties that are not records at all. In general, if a user makes a record type with a cyclic data\nstructure, this is a problem they're going to have to confront already in equality and hashcode.\n\n##### Conclusion\n\nWe will not attempt any special handling here. We could consider adding a `DebuggerDisplay` with more special,\nreflective handling at a later point in time if this proves to be a pain point, but we don't think it's\nworth the cost in regular `ToString` calls.\n\n#### Quoting/escaping values\n\nToday, records do not attempt to escape `string`s when printing, which could result in potentially confusing\nprinting. However, we do have concerns here. First, none of our prior art in C# does this escaping. Second,\nthe framework also does not escape `ToString()` like this. Third, there's a question of what _type_ of\nescaping we should do here. Would we want to print a newlines as the C# version, `\\n`, or the VB version?\nFurther, we already have some handling the expression evaluator and debugger for regular strings and\nanonymous types, to ensure that the display looks good there. Given that this is mainly about ensuring\nthat records appear well-formatted in the debugger, it seems like the correct and language-agnostic approach\nis to ensure the expression evaluator knows about record types as well.\n\n##### Conclusion\n\nWe won't do any quoting or escaping of string record members. We should make the debugger better here.\n\n#### Should we omit the implementation of `ToString` on `abstract` records\n\nWe could theoretically omit providing an implementation of this method on `abstract` record types as it\nwill never be called by the derived `ToString` implementation. On the face of it, we cannot think of a\nscenario that would be particularly helped by including the `ToString`, however we also cannot think of\na scenario that would be harmed by including it, and doing so would make the compiler implementation simpler.\n\n##### Conclusion\n\nKeep it.\n\n#### Should we call `ToString` prior to `StringBuilder.Append` on value types\n\nThe concern with directly calling `Append` without `ToString` on the value being passed is that for\nnon-primitive struct types, this will cause the struct to be boxed, and the behavior of `Append` is\nto immediately call `ToString` and pass to the `string` overload.\n\n##### Conclusion\n\nDo it.\n\n#### Should we try and avoid the double-space in an empty record\n\nThe implementation currently prints `Person {  }` for an empty record. This provokes immediate \"unfinished\"\nreactions in the LDT, similar to the trailing commas above.\n\n##### Conclusion\n\nShould we remove it? YES! YES! YES! YES!\n\n#### Should we try and make the typename header print more economic\n\nToday, we call `StringBuilder.Append(nameof(type))` and `StringBuilder.Append(\"{\")` immediately after\nas 2 separate calls, which is another method call we could drop if we did it all in one. We feel that this\nis sufficiently outside the language spec as to be a thing a compiler could do if it feels it appropriate.\nFrom the compiler perspective, however, it could actually be bad change, as it would increase the size of\nthe string table, which is known to be an issue in some programs, while getting rid of one extra method call\nin a method not particularly designed to be as fast as possible in the first place.\n\n##### Conclusion\n\nUp to implementors. However, we don't believe it to be a good idea or worth any effort.\n\n### Reference equality short circuiting\n\nToday, we have a slight difference between the equality operators `==`/`!=` and the implementation of the\n`Equals(record)` instance method, in that the former compare reference equality first, before delegating\nto the `Equals` method. This ensures that `null` is equal to `null` as a very quick check, and ensures we\nonly have to compare one operand to `null` explicitly in the implementation of the operators. The `Equals`\ninstance member then does not check this condition. However, this means that the performance characteristics\nof these two members can be very different, with the operators being an order of magnitude faster on even\nsmall record types since it has to do potentially many more comparisons. The proposal, therefore, is to\ncheck reference equality in the `Equals` instance member as well, as the first element.\n\n#### Conclusion\n\nWe will do this. We'll keep the reference equality check in the operators as well to ensure that `null == null`,\nand add one at the start of the instance method. It does mean that the `==` operators will check reference\nequality twice, but this is an exceptionally quick check so we don't believe it's a big concern.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-09-09.md",
    "content": "# C# Language Design Meeting for September 9th, 2020\n\n## Agenda\n\n1. [Triage issues still in C# 9.0 candidate](#triage-issues-still-in-C#-9.0-candidate)\n2. [Triage issues in C# 10.0 candidate](#Triage-issues-in-C#-10.0-candidate)\n\n# Quote(s) of the Day\n\n\"Don't even mention I was here.\"\n\n\"I have lots of strong opinions, I'm just judicious with how I distribute them.\"\n\n# Discussion\n\n## Triage issues still in C# 9.0 candidate\n\nTo 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\nthis point, and moved their corresponding issues to the [9.0 milestone](https://github.com/dotnet/csharplang/milestone/18).\n\n### Null propagation expression does not allow `!` as a nested operator form\n\nhttps://github.com/dotnet/csharplang/issues/3393\n\nWe 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\ngiven 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,\nand it will stay in C# 9.0 candidate for now.\n\n### [Proposal] Improve overload resolution for delegate compatibility\n\nhttps://github.com/dotnet/csharplang/issues/3277\n\nWe 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\nas it can be implemented and tested in a single PR, so we'll move this to any time.\n\n### Interface static method, properties and event should ignore variance\n\nhttps://github.com/dotnet/csharplang/issues/3275\n\nThis 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\ncandidate.\n\n### Records-related issues\n\nhttps://github.com/dotnet/csharplang/issues/3226\nhttps://github.com/dotnet/csharplang/issues/3213\nhttps://github.com/dotnet/csharplang/issues/3137\n\nThese 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\nproposals out into separate issues for 10 or later and close/move these.\n\n### Primary Constructors\n\nhttps://github.com/dotnet/csharplang/issues/2691\n\nWe 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.\n\n### Proposal: Target typed null coalescing (`??`) expression\n\nhttps://github.com/dotnet/csharplang/issues/2473\n\nWhen 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\nalready 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\nNever milestone.\n\n### Champion: Simplified parameter null validation code\n\nhttps://github.com/dotnet/csharplang/issues/2145\n\nWe didn't quite get the code gen for this one finished up. Moving to 10.0 candidate.\n\n### Champion: relax ordering constraints around `ref` and `partial` modifiers on type declarations\n\nhttps://github.com/dotnet/csharplang/issues/946\n\nWe 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.\nWe'd accept a contribution if a community member wanted to loosen the restriction, thus moved to Any Time.\n\n### Champion \"Nullable-enhanced common type\"\n\nhttps://github.com/dotnet/csharplang/issues/33\nhttps://github.com/dotnet/csharplang/issues/881\n\nWe 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.\nGiven 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\nmet with these, and they are moved to Likely Never.\n\n### Proposal: improvements to nullable reference types\n\nhttps://github.com/dotnet/csharplang/issues/3297\n\nThis 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\njust the things actually implemented for this release.\n\n## Triage issues in C# 10.0 candidate\n\nWe 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\nto 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.\n\n###  Proposal: Exponentiation operator\n\nhttps://github.com/dotnet/csharplang/issues/2585\n\nWe 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\nfor 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.\n\n### Champion \"Type Classes (aka Concepts, Structural Generic Constraints)\"\n\nhttps://github.com/dotnet/csharplang/issues/110\n\nWe 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\nwe 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\nlabeling 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.\n\n### generic constraint: where T : ref struct\n\nhttps://github.com/dotnet/csharplang/issues/1148\n\nThis 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\n`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.\n\n### Champion \"CallerArgumentExpression\"\n\nhttps://github.com/dotnet/csharplang/issues/287\n\nWhile 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.\n\n### Champion \"Allow Generic Attributes\"\n\nhttps://github.com/dotnet/csharplang/issues/124\n\nA 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\nimplementation 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.\n\n###  C# Feature Request: Allow value tuple deconstruction with default keyword\n\nhttps://github.com/dotnet/csharplang/issues/1358\n\nThis 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.\n\n### Expression Blocks/Switch Expression and Statement Enhancements\n\nhttps://github.com/dotnet/csharplang/issues/3086\nhttps://github.com/dotnet/csharplang/issues/3038\nhttps://github.com/dotnet/csharplang/issues/3087\nhttps://github.com/dotnet/csharplang/issues/2632\n\nWe 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\ncan proceed with implementation. Move to 10.0 Working Set.\n\n### Champion: Name lookup for simple name when target type known\n\nhttps://github.com/dotnet/csharplang/issues/2926\n\nWe 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.\n\n### Proposal: \"Closed\" type hierarchies\n\nhttps://github.com/dotnet/csharplang/issues/485\n\nThis needs to be designed in concert with discriminated unions, so we'll move it to 10.0 Working Set.\n\n###  Championed: Target-typed implicit array creation expression `new[]`\n\nhttps://github.com/dotnet/csharplang/issues/2701\n\nThis 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\nspecifically. 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.\n\n### Champion: `base(T)` phase two\n\nhttps://github.com/dotnet/csharplang/issues/2337\n\nWhile 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\nhear customer asks for it.\n\n###  Champion \"defer statement\"\n\nhttps://github.com/dotnet/csharplang/issues/1398\n\nLDM 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\nhere 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.\nAdditionally, there is significant negative community sentiment about this feature, much more than we usually get for participation on any particular csharplang issue. As a\nresult, we are moving this feature to Likely Never, and if we see similar significant outcry to the rejection we can reconsider this.\n\n###  Five ideas for improving working with fixed buffers\n\nhttps://github.com/dotnet/csharplang/issues/1502\n\nThis will be part of the previously-mentioned forthcoming ref fields proposal. Move it to 10.0 Working Set.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-09-14.md",
    "content": "# C# Language Design Meeting for September 14th, 2020\n\n## Agenda\n\n1. [Partial method signature matching](#partial-method-signature-matching)\n2. [Null-conditional handling of the nullable suppression operator](#null-conditional-handling-of-the-nullable-suppression-operator) \n3. [Annotating IEnumerable.Cast](#annotating-ienumerable.cast)\n4. [Nullability warnings in user-written record code](#nullability-warnings-in-user-written-record-code)\n5. [Tuple deconstruction mixed assignment and declaration](#tuple-deconstruction-mixed-assignment-and-declaration)\n\n## Quote of the Day\n\n- \"Now with warning waves it's a foam-covered baseball bat to hit people with\"\n\n## Discussion\n\n### Partial method signature matching\n\nhttps://github.com/dotnet/roslyn/issues/45519\n\nThere 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\nand 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,\n`dynamic`/`object` do not have to match, we warn when there are unsafe nullability conversions, and other differences are allowed (including parameter\nnames). We could lean on a warning wave here and make our implementation more consistent with the following general rules:\n\n1. If there are differences in the CLR signature, we error (as we cannot emit code at all!)\n2. If there are differences in the syntactic signature, we warn (even for safe nullability changes).\n\nWhile we like this proposal in general, we have a couple of concerns around compatibility. Tuple names erroring is existing behavior, and if we loosen\nthat 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\ncompile with the C# 8 compiler. This complicates implementation, and to make it simple we lean towards just leaving tuple name differences as an error.\nWe 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\nimplementation 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,\nor the must both be nullable unaware.\n\nWe 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.\nHowever, we believe that this would result in a complicated user experience and would make the mental model harder to understand.\n\n#### Conclusion\n\n1. We will keep the existing error that tuple names must match.\n2. We will keep the existing warnings about unsafe nullability differences.\n3. We will add a new warning wave warning for all other syntactic differences between partial method implementations.\n    a. This includes differences like parameter names and `dynamic`/`object`\n    b. This includes nullability differences where both contexts are nullable enabled, even if the difference is supposedly \"safe\" (accepting `null`\n       where it is not accepted today).\n    c. If nullability differs by enabled state (one part is enabled, the other part is disabled), this will be allowed without warning.\n\n### Null-conditional handling of the nullable suppression operator\n\nhttps://github.com/dotnet/csharplang/issues/3393\n\nThis 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\non 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\nthe behavior here. We have made a grammatical proposal for adjusting how null-conditional statements are parsed, and there was general agreement that this\nproposal 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\nbe a null suppression inside the term, just not at the end. A better name would be `null_conditional_operations_no_final_suppression`.\n\n#### Conclusion\n\nAccepted, with the above rename. Will get a compiler developer assigned to implement this ASAP.\n\n### Annotating IEnumerable.Cast\n\nhttps://github.com/dotnet/runtime/issues/40518\n\nIn .NET 5, the `Cast<TResult>` method was annotated on the return to return `IEnumerable<TResult?>`, which means that regardless of whether the input\nenumerable can contain `null` elements, the returned enumerable would be considered to contain `null`s. This resulted in some spurious warnings when\nupgrading 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\nreasons:\n\n1. There is no way to express that the nullability of one type parameter depends on the nullability of another type parameter.\n2. 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\n   inference to make writing code in this scenario better.\n\nGiven this, we have a few options:\n\n1. 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\n   considering with `Where`, but it feels like a bad solution as it's not generalizable.\n2. 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\n   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\n   implementation. We're concerned that this could make the docs appear to lie, which we think would also give a bad experience.\n3. 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\n   to help users, and spurious warnings get suppressed. It also matches the behavior of `IEnumerator.Current`, and means that the behavior of `foreach`\n   loops over such a list behave in a consistent manner.\n\n#### Conclusion\n\nThe BCL will make `Cast` and a few related APIs an oblivious API.\n\n### Nullability warnings in user-written record code\n\nThe question here is on whether we should warn users when manually-implemented methods and properties for well-known members in a `record` should warn\nwhen nullability is different. For example, if their `Equals(R other)` does not accept `null`. There was no debate on this.\n\n#### Conclusion\n\nwe'll check user-defined `EqualityContract`, `Equals`, `Deconstruct`, ... methods on records for nullability safety issues in their declaration. For\nexample, `EqualityContract` should not return Type?.\n\n### Tuple deconstruction mixed assignment and declaration\n\nhttps://github.com/dotnet/csharplang/issues/125\n\nWe've discussed this feature in the past (https://github.com/dotnet/csharplang/blob/master/meetings/2016/LDM-2016-11-30.md#mixed-deconstruction), and\nwe 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\nmoving forward with the feature.\n\n#### Conclusion\n\nLet's try and get this into C# 10.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-09-16.md",
    "content": "# C# Language Design Meeting for September 14th, 2020\n\n## Agenda\n\n1. [Required Properties](#required-properties)\n2. [Triage](#triage)\n\n## Quote of the day\n\n- \"It's my version of thanks Obama, thanks C#\"\n\n## Discussion\n\n### Required Properties\n\nhttps://github.com/dotnet/csharplang/issues/3630\n\n[Presentation](./Required_Properties_2020_09_16.pdf)\n\nMost of the time today was used hearing a presentation about a proposal for required properties. This presentation was intended\nas a high-level overview of the issue required properties are attempting to solve, and to illustrate a few approaches that could\nbe taken for implementing these. Notes were not taken to the slide content itself, as the slides are linked above.\n\nOverall, the LDM is a bit leary about the implementation complexity of runtime-verification methods. One approach that wasn't on\nthe slides, but is a possible approach, is introducing validators and letting type authors do the verification themselves. This\nmay end up resulting in type authors conflating nullability and requiredness for most simple implementations, but for the common\nscenarios this may be just fine. We were unable to find just one implementation strategy that stuck out as \"this is the right thing\nto do.\" Instead, each implementation strategy had a set of tradeoffs, particularly around the implementation complexity of tracking\nwhether a property has been initialized.\n\nOne thing that we noted from the presentation is that any method of introducing required properties is going to mean that types with\nthese contracts on their empty constructors will not be able to be used in generic scenarios `where T : new()`, as the empty constructor\nis required to set some amount of properties. The presentation also did not cover how to do additive or subtractive contracts: ie, a\nfuture factory method `MakeAMads` might want to specify \"Everything from the normal `Person` constructor except `FirstName`\", whereas\na copy constructor would want to specify \"You don't have to initialize anything\". Some work has started on designing this scenario,\nbut it needs some more work before it's in a state to get meaningful feedback.\n\nA read of the room found that most of the LDM was leaning towards compile-time only validation of required properties. It does mean\nthat upgrading binary versions without recompiling can leave things in an invalid state, but the implementation strategies for\ngetting actual runtime breaks are very complex and we're not sure they're worth the tradeoff. The next step in design will be to\ncome back with a more concrete syntax proposal for how required properties will be stated, and how constructors will declare their\ncontracts.\n\n### Triage\n\nWe only had time left to triage 1 issue:\n\n#### Proposal: Permit trailing commas in method signatures and invocations\n\nhttps://github.com/dotnet/csharplang/issues/391\n\nThis is a longstanding friction point in the language that has mostly positive sentiment on csharplang. We're also fairly confident\nthat it wouldn't break any possible language features other than omitted arguments, which the LDM is not particularly interested\nin pursuing. That being said, the general gut reaction of most LDM members is something along the lines of \"This looks wrong.\" We\ncertainly acknowledge that, despite some syntactic misgivings, this can be a very useful feature, particularly for source generators\nand refactorings, as well as for just simply reordering parameters in a method call or definition. There are a couple of open issues\nwe'd need to resolve as well:\n\n* What would happen with param arrays?\n* Would tuple declarations be allowed to have trailing commas? This proposal actually seems like a natural way to allow oneples into\nthe language, in a similar style to Python, where the oneple must have a trailing comma.\n\n\n##### Conclusion\n\nTriage 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.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-09-23.md",
    "content": "# C# Language Design Meeting for September 23rd, 2020\n\n## Agenda\n\n1. General improvements to the `struct` experience\n\n## Quote of the day\n\n- \"This makes C# developers queasy. Refs can never be null! The runtime says that's not true, the C# type system is a lie.\"\n\n## Discussion\n\nMost 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).\nWe 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\nproposal, as we did not have long discussions about the merits of the feature itself.\n\n* The general driving principles of this proposal are to ease friction points in the language around structs. Today we have `Span<T>`, which is\na 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\nrules 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\naround. 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\ngenerally agrees with this goal.\n* 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,\neven private fields, appear in reference assemblies and similar locations to ensure that the compiler can correctly determine lifetimes.\n* The rules around returning a ref to a ref parameter are not especially intuitive. We acknowledge that they are necessary given the lifetime\nrules today with methods returning a `Span`, but we could introduce a `CapturesAttribute` or something similar to indicate that a `ref` parameter\nis captured by the method, and thus allow passing it directly as a `ref` to `new Span<T>`.\n    * 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\n    lifetimes line up. While this workaround is viable, we're somewhat worried it won't be straightforward enough of a solution.\n* 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\nnew 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\na friction point for users, we can revisit.\n* One scenario this spec does not consider is `ref` assignment in an object initializer, which is still part of the object construction phase.\nThis should be allowable, and we need to update the draft specification to address this case.\n* `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\nto observe a `default` ref struct that has a `null` `ref`. While the runtime does have an `Unsafe.IsNullRef` helper method, it feels unnatural that\ncode 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\neverywhere, in much the same way that `null` ends up everywhere. We may need to think more about this problem.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-09-28.md",
    "content": "# C# Language Design Meeting for September 28th, 2020\n\n## Agenda\n\n1. [Warning on `double.NaN`](#warning-on-double.nan)\n2. [Triage](#triage)\n    1. [Proposal: more improvements to nullable reference types](#proposal-more-improvements-to-nullable-reference-types)\n    2. [Proposal: Required Properties](#proposal-required-properties)\n    3. [Proposal: Extend with expression to anonymous type](#proposal-extend-with-expression-to-anonymous-type)\n    4. [Proposal: Shebang (#!) Support](#proposal-shebang--support)\n    5. [Proposal: List Patterns](#proposal-list-patterns)\n    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)\n    7. [Proposal: \"Closed\" enum types](#proposal-closed-enum-types)\n    8. [Top-level functions](#top-level-functions)\n    9. [Primary Constructors](#primary-constructors)\n    10. [Champion: Simplified parameter null validation code](#champion-simplified-parameter-null-validation-code)\n    11. [Proposal: Support generics and generic type parameters in aliases](#proposal-support-generics-and-generic-type-parameters-in-aliases)\n    12. [Support for method parameter names in nameof](#support-for-method-parameter-names-in-nameof)\n\n## Quote of the day\n\n- \"On a rational basis I have nothing against this\"\n\n## Discussion\n\n### Warning on `double.NaN`\n\nhttps://github.com/dotnet/roslyn/issues/15936\n\nWe have an existing FxCop warning (CA2242) for invalid comparisons to `double.NaN`. We could consider bringing\nthat warning into the compiler itself as in a warning wave. However, as this analyzer is now shipped with the\n.NET 5 SDK, is on by default, and deals more with API usage than with the language itself, it would also be fine\nto leave it where it is.\n\n#### Conclusion\n\nRejected. Leave the warning where it exists today.\n\n### Triage\n\nToday, we got through half the remaining issues in the C# 10.0 Candidate milestone\n\n#### Proposal: more improvements to nullable reference types\n\nhttps://github.com/dotnet/csharplang/issues/3868\n\nWe have a few open topics in improvements to nullable reference types for the C# 10.0 timeframe. We're currently\ntracking LINQ improvements, Task-like type covariance, and uninitialized fields and constructors. This last point\nwill likely be handled in conjunction with the proposals for required properties and initialization debt. The\nfirst two can be broken out to specific issues for the 10.0 timeframe.\n\n##### Conclusion\n\nFile separate issues for the first two bullets, and triage into the 10.0 working set.\n\n#### Proposal: Required Properties\n\nhttps://github.com/dotnet/csharplang/issues/3630\n\nWe've already started talking about this one.\n\n##### Conclusion\n\nTriage into the 10.0 working set.\n\n#### Proposal: Extend with expression to anonymous type\n\nhttps://github.com/dotnet/csharplang/issues/3530\n\nThis proposal extends anonymous types to allow `with` expressions to change them, which we like a lot. In a way,\nthis extension makes anonymous types practically just anonymous _record_ types, as they have the rest of the properties\nof a record already: value equality, ToString, etc. It also fits in well with the idea of generally extending `with`\nexpressions to be more broadly applicable. Since anonymous types cannot be exposed as types in a public API, generating\nnew `init` members and the `with` clone method is a non-breaking change. New compilations can take advantage of the\nfeatures, and old compilations don't get affected by them.\n\nAs part of discussing this issue, we hit upon the idea of additionally allowing `new { }` to be target-typed. If a `new`\nexpression that did not have `()` is assigned to something that matches its shape (such as a record with the correct)\nproperty names, we could just allow that new expression to be treated as the target-type constructor, rather than as\ncreating a new anonymous type. If the target-type is `object` or `dynamic`, it will still result in an anonymous object\nbeing created, and there may be some tricks to figuring out generic inference, but we think it might be a path forward\ntowards making target-typed new more regular with the rest of the language (a complaint we have already heard). A future\nproposal for that will be filed.\n\n##### Conclusion\n\nTriage into C# 10.0 working set for consideration with the rest of the `with` extensions.\n\n#### Proposal: Shebang (#!) Support\n\nhttps://github.com/dotnet/csharplang/issues/3507\n\nWhile could eventually be an interesting proposal, the tooling is not there currently, and we feel the discussion around\ndeveloper ergonomics in .NET 6 will shape our discussions in this area.\n\n##### Conclusion\n\nTriaged into X.0, and if the .NET tooling looks to add `dotnet run csfile`, we can consider again at that point.\n\n#### Proposal: List Patterns\n\nhttps://github.com/dotnet/csharplang/issues/3435\n\nWe like continuing to enhance the pattern support in C#, and are in general positive about this proposal. However, the\nsomewhat-fractured nature of .NET here works to our detriment, not just in the `Count` vs `Length` property names, but\nin the general collection type sense. It would be nice to support `IEnumerable`, for example, which does not meet the\ndefinitions set out in the proposal. Another consideration would be dictionary types: we don't have support for a\ndictionary initializers specifically today, so having a decomposition step without a composition step would be odd, but\nthey would be a useful pattern nontheless. We also would like to see if we can find a way to make the syntax use braces\nrather than square brackets to mirror collection initializers, though that will be difficult due to the empty property\npattern.\n\n##### Conclusion\n\nWe'll spend design time on this in the C# 10 timeframe, though it may not make the 10.0 release itself. Triaged into the\n10.0 working set.\n\n#### Proposal: Add ability to declare global usings for namespaces, types and aliases by using a command line switch\n\nhttps://github.com/dotnet/csharplang/issues/3428\n\nThis is, in many ways, a language-defining issue. The proposal itself is small, but it reflects the LDT's thinking of\nfuture C# directions as a whole. It is also very divisive, both in the LDT and in the greater community, with a small\nmajority (both in the LDT and in the csharplang community) in favor of the feature. It introduces a level of magic to\nthe language that has been somewhat resisted in the past. Additionally, there is concern that there is no one set of\n\"base usings\" that should be automatically included in files: a console app might only want to include `System`, while\nan ASP.NET app might want to include a bunch of namespaces for various routing properties, controllers, and the like.\n\n##### Conclusion\n\nWe'll discuss this more in the 10.0 timeframe. There could be interactions around the theme of developer QoL in the .NET\n6 timeframe.\n\n#### Proposal: \"Closed\" enum types\n\nhttps://github.com/dotnet/csharplang/issues/3179\n\nThis proposal is linked to discriminated unions, in that it's a another type of closed hierarchy that C# does not support\ntoday.\n\n##### Conclusion\n\nTriage into 10.0 working set, to be discussed with DU's and closed type hierarchies in general.\n\n#### Top-level functions\n\nhttps://github.com/dotnet/csharplang/issues/3117\n\nThis is the follow-up work from C# 9 that we did not conclude in the initial push for top-level statements in C#,\nnamely in allowing globally-accessible functions in C# to float at the top level without a containing class. One\nconcern with generalizing this feature is that we have 20 years of BCL design that does not account for top-level\nfunctions, in addition to other well-known and used libraries. For consistency, these libraries would likely not\nuse this new feature, which would relegate this feature to minimal usage. While many LDT members like the feature\nin general, and would likely introduce it if we were redesigning C# from the ground up, we don't believe that the\nfeature belong in the C# we have today. We will continue to investigate whether top-level functions defined today\n(which are local functions to the implicit `Main` method) should be callable from within the current file, in order\nto have better compat with CSX. However, the overall feature is rejected.\n\n##### Conclusion\n\nRejected.\n\n#### Primary constructors\n\nhttps://github.com/dotnet/csharplang/issues/2691\n\nWe have a proposal for this, and we are mostly in agreement that we should see this through.\n\n##### Conclusion\n\nTriage into 10.0 working set.\n\n#### Champion: Simplified parameter null validation code\n\nhttps://github.com/dotnet/csharplang/issues/2145\n\nWe have an implementation of this mostly ready. It was done in such as way as to be usable by the BCL, and will\npotentially save 7K+ lines of code there. Let's get it in.\n\n##### Conclusion\n\nTriage into 10.0 working set.\n\n#### Proposal: Support generics and generic type parameters in aliases\n\nhttps://github.com/dotnet/csharplang/issues/1239\n\nWe like the idea of improving aliases in general, and this could come into play when we talk about the previously-mentioned\nglobal usings. There are multiple possible flavors here though: there's simple aliases like we have today, that are\nfreely convertible back to the underlying type, and then there are true opaque aliases that are not freely convertible\nback to the underlying type. Ideally, these latter aliases would be zero cost, which will likely require some work in\nconjunction with the runtime. Additionally, while we like the idea of making improvements here, we have a lot on the C# 10\nplate currently, and think it would fit in better with the type enhancements we hope to make after 10.\n\n##### Conclusion\n\nTriaged into X.0.\n\n#### Support for method parameter names in nameof\n\nhttps://github.com/dotnet/csharplang/issues/373\n\nWe like this, and have the start of an implementation.\n\n##### Conclusion\n\nTriaged into 10.0 working set.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-09-30.md",
    "content": "# C# Language Design Meeting for September 30th, 2020\n\n## Agenda\n\n1. `record structs`\n    1. [`struct` equality](#struct-equality)\n    2. [`with` expressions](#with-expressions)\n    3. [Primary constructors and `data` properties](#primary-constructors-and-data-properties)\n\n## Quote of the Day\n\n- \"... our plan of record\"\n- \"haha badum-tish\"\n\n## Discussion\n\nOur conversation today focused on bringing records features to structs, and specifically what parts should apply\nto _all_ structs, what should apply to theoretical `record` structs (if that's even a concept we should have), and\nwhat should not apply to structs at all, regardless of whether it's a `record` or not. The table we looked at is\nbelow, followed by detailed summaries of our conversations on each area. We did not come to a confirmed conclusion\non primary constructors/data properties this meeting, but we do have a general room lean, which has been recorded.\n\n|Feature                           |All structs   |Record structs|No structs|\n|----------------------------------|--------------|--------------|----------|\n|Equality                          |--------------|--------------|----------|\n|- basic value equality            | X (existing) |              |          |\n|- == and strongly-typed `Equals()`|              |      X       |          |\n|- `IEquatable<T>`                 |              |      X       |          |\n|- Customized value equality       |      X       |              |          |\n|`with`                            |--------------|--------------|----------|\n|- General support                 |      X       |              |          |\n|- Customized copy                 |              |explicit error|    X     |\n|- `with`ability abstraction       |              |      ?       |          |\n|Primary constructors              |--------------|--------------|----------|\n|- Mutability by default           |              |              | leaning  |\n|- Public properties               |              |   leaning    |          |\n|- Deconstruction                  |              |   leaning    |          |\n|Data properties                   |--------------|--------------|----------|\n|- Mutability by default           |              |              | leaning  |\n|- Public properties               |              |   leaning    |          |\n\n### `struct` equality\n\n`record`s in C# 9 are very `struct` inspired in their value equality: all fields in `record` a and b are compared\nfor equality, and if they are all equal, then a and b are also equal. This is the default behavior for all `struct`\ntypes in C# today, if an `Equals` implementation is not provided. However, this default implementation is somewhat\nslow, as it uses reflection. We've talked in the past about potentially generating an `Equals` implementation for\nall struct types that would have better performance. However, we are definitely very concerned about potential size\nbloat for doing this, particularly around interop types. Given those concerns, we don't think we can generate such\nmethods for all struct types. We then considered whether hypothetical `record` structs should get this implementation.\nHowever, generating a good implementation of equality for structs almost seems like it's not a C# language issue at\nall. More than just C# runs on the CLR, and it would be a shame if there was incentive to use a particular language\nbecause it generates a better equality method. Further, since we can't do this for all `struct` types, it means we\nwould inevitably have to educate users that \"`record struct`s generate better code for equality, so you may just\nwant to make your `struct` a `record` for that reason alone\", which isn't great either. Given that, we'd rather work\nwith the runtime team to make the automatic `Equals` method better, which will benefit not just all C# structs,\nbut all `struct` types from all languages that run on the CLR.\n\nNext, we looked at whether we should expose new equality operators and strongly-typed `Equals` methods on `struct`\ntypes, as well as implementing `IEquatable<T>`. We again came to the conclusion that, for all existing `struct`\ntypes, it would be too costly in metadata (and a potential breaking change for exposing a strongly-typed `Equals`\nmethod or `IEquatable<T>`) to do this for all types. However, we do think that a gesture for opting into this\ngeneration would be useful. Given that, we considered whether it was useful to have these be more granular gestures,\nie if a type could just opt-in to generating `IEquatable<T>` without the equality features. For these scenarios, we\nfeel that the need just isn't there, and that it should be an all-or-nothing opt-in.\n\nFinally on this topic, we considered customized `Equals` implementations. This is a fairly simple topic: all structs\nsupport customizing their definition of `Equals` today, and will continue to do so in the future.\n\n#### Conclusion\n\nAll structs will continue to use the runtime-generated `Equals` method if none is provided. Making a `struct` a\n`record` will be a way to opt-in to new surface area that uses this functionality. We will work with the runtime\nteam to hopefully improve the implementation of the generated `Equals` methods in future versions of .NET.\n\n### `with` expressions\n\nWe considered whether all structs should be copyable via a `with` expression, or just some subset of them. On the\nsurface, this seems a simple question: all structs are copyable today, and we even have a dedicated CIL instruction\nfor this: `dup`. It seems trivial to enable this for any location where we know the type is a `struct` type, and\njust emit the `dup` instruction. Where this becomes a more interesting question, though, is in the intersection\nbetween all structs and any potential for customization of the copy behavior. We have plans to enable `with`\nas a general pattern that any class can implement through some mechanism, and if structs can customize that behavior\nit means that a struct substituted for a generic type `where T : struct` will behave incorrectly if that behavior\nwas customized. Additionally, if we extend `with`ability as a pattern and allow it to be expressed via some kind of\ninterface method, would structs be able to implement that method? Or would it get an automatic implementation of\nthat method?\n\nAn important note for structs is that, no matter what we do here with respect to `with`, structs are fundamentally\ndifferent than classes as they're _already_ copied all the time. Unless someone is ensuring that they always pass\na struct around via `ref`, the compiler is going to be emitting `dup`s all the time. While we could design a new\nruntime intrinsic to call either `dup` or the struct's clone method if it exists, struct cloning behavior has long-\nestablished semantics that we think users will continue to expect.\n\n#### Conclusion\n\nAll `struct` types should be implicitly `with`able. No `struct` types should be able to customize their `with`\nbehavior. Depending on how we implement general `with` abstractions, `record` structs might be able to opt-in to them,\nbut will still be unable to customize the behavior of that abstraction.\n\n### Primary constructors and `data` properties\n\nFinally today, we considered the interactions of primary constructors, data properties, and structs. There are two\ngeneral ideas here:\n\n1. `struct` primary constructors should mean the same thing as `class` primary constructors (with whatever behavior\nwe define later in this design cycle), and `record struct` primary constructors should mean the same thing as\n`record` primary constructors (public init-only properties), or\n2. `record struct` primary constructors should mean public, mutable fields.\n\nOption 1 would provide a symmetry between record structs and record class types, while option 2 would provide a\nsymmetry between record structs and tuple types. In a sense, a record struct would just become a strongly-named tuple\ntype, and have all the same behaviors as a standard tuple type. You could then opt a record struct into being\nimmutable by declaring the whole type `readonly`, or declaring the individual parameters `readonly`. For example:\n\n```cs\n// Public, mutable fields named A and B\nrecord struct R1(int A, int B);\n\n// Public, readonly fields named A and B\nreadonly record struct R2(int A, int B);\n```\n\nA key point in the mutability question for structs is that mutability in a struct type is nowhere near as bad as\nmutability in a reference type. It can't be mutated when it's the key of a dictionary, for example, and unless\nrefs to the struct are being passed around the user is always in control of the struct. Further, if a ref is passed\nand it is saved elsewhere, that's a copy, and mutation to that copy doesn't affect the original. As always, we also\nhave easy syntax to make something readonly in C#, while not having an easy syntax for making it mutable. On the other\nhand, the shortest syntax in a class record type is to create an immutable property, and it might be confusing if\nwe had differing behaviors between record classes and record structs.\n\nWe did not come to a conclusion on this topic today. A general read of the room has a _slight_ lean towards keeping\nthe behavior consistent with record classes, but a number of members are undecided as there are good arguments in\nboth directions. We will revisit this topic in a future meeting after having some time to mull over the options here.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-10-05.md",
    "content": "# C# Language Design Meeting for October 5th, 2020\n\n## Agenda\n\n1. [`record struct` primary constructor defaults](#record-struct-primary-constructor-defaults)\n2. [Changing the member type of a primary constructor parameter](#changing-the-member-type-of-a-primary-constructor-parameter)\n3. [`data` members](#data-members)\n\n## Quote of the Day\n\n- \"The problem with people who voted for immutable by default is that they can't change their opinion. #bad_dad_jokes\"\n\n## Discussion\n\n### `record struct` primary constructor defaults\n\nWe picked up today where we left off [last time](LDM-2020-09-30.md#primary-constructors-and-data-properties), looking at what\nprimary constructors should generate in `record struct`s. We have 2 general axes to debate: whether we should generate mutable\nor immutable members, and whether those members should be properties or fields. All 4 combinations of these options are valid\nplaces that we could land, with various pros and cons, so we started by examing the mutable vs immutable axis. In C# 9, `record`\nprimary constructors mean that the properties are generated as immutable, and consistency is a strong argument for preferring\nimmutable in structs. However, we also have another analogous feature in C#: tuples. We decided on mutability there because it's\nmore convenient, and struct mutability does not carry the same level of concern as class mutability does. A struct as a\ndictionary key does not risk getting lost in the dictionary unless it itself references mutable class state, which is just as\nmuch 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\nlikely that we still would have had the fields be mutable. A number of C# 7 features centered around reducing unnecessary struct\ncopying, such as `readonly` members and ref struct improvements, and reducing copies in large structs by `with` is still a\nuseful goal. Finally, we have a better story for making a `struct` fully-`readonly` with 1 keyword, while we don't have a similar\nstory for making a `struct` fully-mutable with a similar gesture.\n\nNext, we examined the question of properties vs fields. We again looked to our previous art in tuples. `ValueTuple` can be viewed\nas an anonymous struct record type: it has value equality and is used as a pure data holder. However, `ValueTuple` is a type\ndefined in the framework, and its implementation details are public concern. As a framework-defined pure data holder, it has no\nextra behavior to encapsulate. A `record struct`, on the other hand, is not a public framework type. Much like any other user-\ndefined `class` or `struct`, the implementation details are not public concern, but the concern of the creator. We have real\nexamples in the framework (such as around the mathematics types) where exposing fields instead of properties was later regretted\nbecause it limits the future flexibility of the type, and we feel the same level of concern applies here.\n\n#### Conclusion\n\nPrimary constructors in `record struct`s will generate mutable properties by default. Like with `record` `class`es, users will\nbe able to provide a definition for the property if they do not like the defaults.\n\n### Changing the member type of a primary constructor parameter\n\nIn C# 9, we allow `record` types to redefine the property generated by a primary constructor parameter, changing the accessibility\nor the accessors. However, we did not allow them to change whether the member is a field or property. This is an oversight, and\nwe should allow changing whether the member is a field or property in C# 10. This will allow overriding of the default decision\nin the first section, giving an ability for a \"grow-up\" story for tuples into named `record struct`s with mutable fields if the\nuser wishes.\n\n### `data` members\n\nFinally today, we took another look at `data` members, and what behavior they should have in `record struct`s as opposed to\n`record` `classes`. We had previously decided that `data` members should generate `public` `init` properties in `record` types;\ntherefore, the crucial thing to decide is if `data` should mean the same thing as `record` would in that type, or if the `data`\nkeyword should be separated from `record` entirely. In C# today, we have very few keywords that change the code they generate\nbased on containing type context, and making `data` be dependent on whether the member is in a `struct` or `class` could end up\nbeing quite confusing. On the other hand, if `data` is \"the short way to create a nominal record type\", then having different\nbehavior between positional parameters and `data` members in a `struct` could also be confusing.\n\n#### Conclusion\n\nWe did not reach a decision on this today. There are 3 proposals on the table:\n\n1. A `data` member is `public string FirstName { get; set; }` in `struct` types, and `public string FirstName { get; init; }` in\n`class` types.\n2. A `data` member is `public string FirstName { get; init; }` in all types.\n3. We cut `data` entirely.\n\nWe'll come back to this in a future LDM.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-10-07.md",
    "content": "# C# Language Design Meeting for October 7th, 2020\n\n## Agenda\n\n1. [`record struct` syntax](#record-struct-syntax)\n2. [`data` members redux](#data-members-redux)\n3. [`ReadOnlySpan<char>` patterns](#readonlyspanchar-patterns)\n\n## Quote of the Day\n\n- \"And we're almost there (famous last words, I'll knock on something)\"\n- \"What about `record delegate`... does `record interface` make sense... I'll go away now\"\n\n## Discussion\n\n### `record struct` syntax\n\nFirst, we looked at what syntax we would use to specify `struct` types that are records. There are two possibilities:\n\n```cs\nrecord struct Person;\nstruct record Person;\n```\n\nIn the former, `record` is the modifier on a `struct` type. In the latter, `struct` is the modifier on `record` types.\nWe also considered whether to allow `record class`.\n\n#### Conclusion\n\nBy unanimous agreement, `record struct` is the preferred syntax, and `record class` is allowed. `record class` is\nsynonymous with just `record`.\n\n### `data` members redux\n\nWith `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\n`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\nsingle line, much like positional records. This is not a goal of brevity just for brevity's sake: in discriminated unions,\nlisting many variants as nominal records is a design goal, and single-line declarations are particularly useful for this case.\nMany languages with discriminated unions based on inheritance introduce short class-declaration syntax for use in union\ndeclarations, and that was a defining goal for where `record` types would be useful.  \nAnother area worth examining is the original proposal for the `data` keyword. In the original proposal, primary constructors\nwould have meant the same thing in `record` types as well non-`record` types, and `data` would have been used as a modifier\non the primary constructor parameter to make it a public get/init property. `data` applied to a member, then, would have been\na natural extension and reuse of that keyword. With the original scenario gone, there are a few concrete scenarios we think\nare highly related to, and will influence, the `data` keyword:\n\n1. Use as a single-line in a discriminated union. While this is motivating, it's worth considering that, at least to some LDT\nmembers, anything more than 2 properties as `data` members doesn't look great, and would perhaps work better as a multi-line\nconstruct, which will line up visually. This seems a reasonable concern, so `data` may not be the solution we're looking for.\n2. Use in required properties, as it seems likely that we will need some keyword to indicate that a property is a required\nmember in a type. While `data` could be orthogonal to some other required property keyword, it's likely there will be at least\nsome interaction as we'd likely want `data` to additionally imply required. It's also possible that we could have just a single\nkeyword to mark a property required, and it gives you what we believe are the useful defaults for such a property.\n3. Use in general primary constructors as a way to say \"give me the same thing a `record` would have for this parameter\". This\nwould be somewhat resurrecting the original use case for the keyword, as we could then retcon `record` primary constructors\nas implying `data` on all parameters for you, but you can then opt-in to them in regular primary constructors as well. `data`\nmembers in a class, then, would again become a natural reuse and extension of the keyword on a primary constructor parameter.\n\n#### Conclusion\n\nWe'll leave `data` out of the language for now. Our remaining motivating scenarios are things that will be worked on more in\nC# 10 cycle, and absent clearer designs in those spaces the need and design factors for `data` are too abstract. Once we work\nmore on these 3 scenarios, we'll revisit `data` and see if a need for it has emerged.\n\n### `ReadOnlySpan<char>` patterns\n\nhttps://github.com/dotnet/csharplang/issues/1881\n\nWe have a community PR to implement the Any Time feature of allowing constant strings to be used to pattern match against\na `ReadOnlySpan<char>`. This would be acknowledging special behavior for `ReadOnlySpan<char>` with respect to constant strings,\nbut we already have acknowledged special behavior for `Span` and `ReadOnlySpan` in the language, around `foreach`. We also\nconsidered whether this could be a breaking change, but we determined it could not be one: `ReadOnlySpan` cannot be converted\nto `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\nof that pattern match must be `ReadOnlySpan<char>`. There were two open questions:\n\n#### Should we allow `Span<char>`\n\nThe question is if `Span<char>` should also be allowed as well as `ReadOnlySpan<char>`. All of the same arguments about\ncompat apply to `Span<char>`. We also considered whether `Memory`/`ReadOnlyMemory` should be allowed inputs. Unlike `Span`/`ReadOnlySpan`,\nthough, there are backcompat concerns with `Memory` that cannot be overlooked, as they are not ref structs. It is very\neasy to obtain a `Span`/`ReadOnlySpan` from a `Memory`/`ReadOnlyMemory`, however, so the need isn't as great.\n\n##### Conclusion\n\n`Span<char>` is allowed. `Memory<char>`/`ReadOnlyMemory<char>` are not.\n\n#### Is this specific to `switch`, or can it be any pattern context\n\nThe original proposal here just mentioned `switch`. However, the implementation allows it to be used in any pattern context,\nsuch as `is`.\n\n##### Conclusion\n\nAllowed in all pattern contexts.\n\n\n#### Final Notes\n\nWe also discussed making sure that switching on a `Span`/`ReadOnlySpan` is as efficient for large switch statements as switching\non 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\nnumber of string comparisons necessary. This method is added to the `PrivateImplementationDetails` class in an assembly, and we\nshould 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\nthan allocations would be from just doing a substring and matching with that.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-10-12.md",
    "content": "# C# Language Design Meeting for October 12th, 2020\n\n## Agenda\n\n1. General improvements to the `struct` experience (continued)\n\n## Quote of the Day\n\n- \"Only 5 people are going to use it...\"\n- \"We said that about function pointers too.\"\n\n## C# Community Ambassadors\n\nWe have been taking a look at https://github.com/dotnet/csharplang/discussions/3878, which is around how to help community\nproposals into better shape to be looked at by LDM. We largely agree with the points raised, which is that most community\nissues are in a state that isn't quite good enough to be sponsored by an LDT member, but also not controversial or generally\ndiscouraged enough to be outright rejected. Our move to enabling discussions on the repo itself was the first step in this\ndirection: discussions are more free-form, allow multiple branching conversations, and we view them as having less requirements\ntowards creating one. The next step we're taking today is nominating a few community members to become ambassadors to the\ncommunity: @jnm2, @YairHalberstadt, and @svick. This role will be focussed around helping triage incoming issues and\ndiscussions, helping community members get their proposals into a state that can realistically be looked at by LDT members\nand potentially championed, and helping with deduplication as it is noticed. We're starting very small with this experiment:\nif it proves successful, we can consider expanding the list to more members of the csharplang community, of which there are\nseveral deserving candidates. As part of this, we're tentatively hoping to review promising community proposals at a more\nregular cadence, hopefully monthly.\n\nCommunity ambassadors are not members of the LDT and do not have the ability to champion issues. They will help us look at\ndeserving community proposals, and we value their input, as we value the input of the general community here.\n\n## Discussion\n\nToday, we finished going through the fixed fields proposal, found [here](https://github.com/dotnet/csharplang/blob/master/proposals/low-level-struct-improvements.md).\n[Previously](LDM-2020-09-23.md), we made it through the `Provide ref fields` section of the specification. Today, we\nfinished going through the rest. Again, most the conversation was dedicated to the specification itself, but there were\na few points brought up that will be updated in the specification later:\n\n* `ThisRefEscapes` is defined very narrowly in this proposal, not allowed on any virtual methods (including methods from\ninterfaces). In our initial investigations, we don't see a huge need for allowing it on interface methods. We can consider\nthis in the future if it ends up being a friction point, but will need a good amount of work around ensuring that OHI is\ncorrectly respected.\n* We considered the issue of whether we should use syntax for `ThisRefEscapes` and `DoesNotEscape`, and nearly-unanimously\ndecided on using attributes. Attributes allow us to have a more descriptive name that users are less likely to accidentally\nuse. Further, all this attribute is controlling is a `modreq`, not the actual implementation of the method. We have existing\nattributes such as `SpecialNameAttribute` that control emit flags like this, so it's not unprecedented.\n* The syntax for fixed buffer locals is actually quite generally attractive: it would be nice if we could remove the requirement\nfor specifying `fixed` in fields. It would further simplify the language: we even have parser code that parses this form today\nso that we can give nicer errors to people coming from C/C++. It would further resolve an ambiguity: in the proposal today, old-\nstyle fixed-size buffers are differentiated from new-style by whether or not the field is in an unsafe context: by omitting the\nfixed, we have a completely different syntax that is unambiguous.\n* We don't believe there is any real motivating scenario for either fixed multi-dimensional arrays or fixed jagged arrays of a\nspecific inner length. Jagged arrays of this form would work: `int[] array[10]`, where you have a fixed buffer of array references,\nbut allocating the inner array as part of the containing structure itself isn't currently seen as an important scenario.\nMultidimensional arrays today need to call into CLR helper methods today and are generally slower. We can think about this later\nif a scenario comes up.\n* We might want to make \"inline array\" a first-class type in the CLR. This would allow for things such as substituting in type\nparameters. This will largely be driven by the CLR design here.\n\n"
  },
  {
    "path": "meetings/2020/LDM-2020-10-14.md",
    "content": "# C# Language Design Meeting for October 14th, 2020\n\n## Agenda\n\n1. [Triage](#triage)\n    1. [Repeated Attributes in Partial Members](#repeated-attributes-in-partial-members)\n    2. [Permit a fixed field to be declared inside a readonly struct](#permit-a-fixed-field-to-be-declared-inside-a-readonly-struct)\n    3. [Do not require fixing a fixed field of a ref struct](#do-not-require-fixing-a-fixed-field-of-a-ref-struct)\n    4. [params Span<T>](#params-spant)\n    5. [Sequence Expressions](#sequence-expressions)\n    6. [utf8 string literals](#utf8-string-literals)\n    7. [pattern-based `with` expressions](#pattern-based-with-expressions)\n    8. [Property improvements](#property-improvements)\n    9. [File scoped namespaces](#file-scoped-namespaces)\n    10. [Discriminated Unions](#discriminated-unions)\n    11. [Efficient params and string formatting](#efficient-params-and-string-formatting)\n    12. [Allow omitting unused parameters](#allow-omitting-unused-parameters)\n2. [Milestone Simplification](#milestone-simplification)\n\n## Quote of the Day\n\n- \"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\"\n\n## Discussion\n\n### Triage\n\n#### Repeated Attributes in Partial Members\n\nhttps://github.com/dotnet/csharplang/issues/3658\n\nWe 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\nto make it work. Triaged into the working set.\n\n#### Permit a fixed field to be declared inside a readonly struct\n\nhttps://github.com/dotnet/csharplang/issues/1793\n\nThis is part of the feature we discussed Monday. Triage into the working set.\n\n#### Do not require fixing a fixed field of a ref struct\n\nhttps://github.com/dotnet/csharplang/issues/1792\n\nWe 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\nimplementation 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\nthis 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.\nUntil then, we don't think the implementation cost is worth it. Triaged to the backlog.\n\n#### params Span<T>\n\nhttps://github.com/dotnet/csharplang/issues/1757\n\nWe like this feature. We'll need to carefully design the overload resolution rules such that it wins out over existing params arrays. Libraries\ncan then intentionally opt-in by introducing `Span<T>` overloads, just like they can introduce any new overload today that causes a change in\nbehavior when recompiled. Triaged into the working set.\n\n#### Sequence Expressions\n\nhttps://github.com/dotnet/csharplang/issues/377\n\nRelated 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,\nso this is triaged into the working set with the others.\n\n#### utf8 string literals\n\nhttps://github.com/dotnet/csharplang/issues/184\n\nWe 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\nwould 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\ninto the backlog.\n\n#### pattern-based `with` expressions\n\nhttps://github.com/dotnet/csharplang/issues/162\n\nThis 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\ndo 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\nis a scenario we need to keep in mind as we generalize.\n\n#### Property improvements\n\nhttps://github.com/dotnet/csharplang/issues/133\nhttps://github.com/dotnet/csharplang/issues/140\n\nWe've discussed these recently in LDM. We're moving forward with design, starting with #133. Triaged into the working set.\n\n#### File scoped namespaces\n\nhttps://github.com/dotnet/csharplang/issues/137\n\nTriaged into the working set. We'll need to come up with a more complete proposal than we have currently, particularly considering how it will\ninteract with top-level statements, but it doesn't seem too difficult.\n\n#### Discriminated Unions\n\nhttps://github.com/dotnet/csharplang/issues/113\n\nThis 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\non 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.\n\n#### Efficient params and string formatting\n\nhttps://github.com/dotnet/csharplang/issues/2302\n\nInterpolated strings are a pit of failure in certain scenarios, such as logging, where formatting costs are incurred up front even if they're\nnot 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\nhow it will function yet.\n\n####  Allow omitting unused parameters\n\nhttps://github.com/dotnet/csharplang/issues/2180\n\nWe had some initial questions around the metadata representation of discards: should the be nameless, for example? We generally like proposals\nthat put discards in more places, and we're willing to look at a complete proposal if one is presented. Triaged to any time.\n\n### Milestone Simplification\n\nToday, 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\non 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\nintention 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\nwe 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,\nwe're simplifying our milestones to be more clear about what the state of things is:\n\n* 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\nof C#, but it will get design time during the upcoming release.\n* 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\ncommunity are welcomed on these proposals, the cost of the design work and implementation review on these features is too high for us to consider\ncommunity implementation until we are ready for it.\n* 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\nimplementation. 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\nand just need implementation work. Those that need a specification still need to be presented during LDM for approval of the spec, but we are\nwilling to take the time to do so at our earliest convenience.\n* Likely Never is the set of proposals that the LDM has reject from the language. Without strong need or community feedback, these proposals will\nnot be considered in the future.\n* Numbered milestones are the set of features that have been implemented for that particular language version. For closed milestones, these are\nthe set of things that shipped with that release. For open milestones, features can be potentially pulled later if we discover compatability or\nother issues as we near release.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-10-21.md",
    "content": "# C# Language Design Meeting for October 21st, 2020\n\n## Agenda\n\n1. [Primary Constructors](#primary-constructors)\n2. [Direct Parameter Constructors](#direct-parameter-constructors)\n\n## Quote of the Day\n\n- \"Hopefully Seattle doesn't wash into the ocean\"\n\n## Discussion\n\n### Primary Constructors\n\nhttps://github.com/dotnet/csharplang/discussions/4025\n\nWe started today by examining the latest proposal around primary constructors, and attempting to tease out the possible\nbehaviors of what a primary constructor could mean. Given this sample code:\n\n```cs\npublic class C(int i, string s) : B(s)\n{\n    ...\n}\n```\n\nthere are a few possible behaviors for what those parameters mean:\n\n1. Parameter references are only allowed in initialization contexts. This means you could assign them to a property, but\nyou couldn't use them in a method that runs after the class has been initialized.\n2. Parameter references are allowed throughout the class, and if they're referenced from a non-initialization context then\nthey are captured in the type, but are not considered fields from a language perspective. This is the proposed behavior in\nthe linked discussion.\n3. Parameter references are automatically captured to fields of the same name.\n\nWe additionally had a proposal in conjunction with behavior 1: You can opt in to having a member generated by adding an\naccessibility to the parameter. So `public class C(private int i)` would generate a private field `i`, in addition to having\na constructor parameter. This is conceivably not tied to behavior 1 however, as it could also apply to behavior 2 as well.\nIt would additionally need some design work around what type of member is generated: would `public` generate a field or a\nproperty? Would it be mutable or immutable by default?\n\nTo try and come up with a perferred behavior here, we started by taking a step back and examining the motivation behind\nprimary constructors. Our primary (pun kinda intended) motivation is that declaring a property and initializing it from\na constructor is a boring, repetitive, boilerplate-filled process. You have to repeat the type twice, and repeat the name\nof the member 4 times. Various IDE tools can help with generating these constructors and assignments, but it's still a lot\nof boilerplate code to read, which obscures the actually-interesting bits of the code (such as validation). However, it is\n_not_ a goal of primary constructors to get to 1-line classes: we feel that this need is served by `record` types, and that\nactual classes are going to have some behavior. Rather, we are simply trying to reduce the overhead of describing the simple\nstuff to let the real behavior show through more strongly.\n\nWith that in mind, we examined some of the merits and disadvantages of each of these:\n1. We like that parameters look like parameters, and adding an accessibility makes it no longer look like a parameter. There's\ndefinitely a lot to debate on what that accessibility should actually do though. There are some concerns that having the\nparameter not be visible is non-obvious to users: to solve this, we could make then visible throughout the type, but have it\nbe an error to reference in a location that is not an initialization context (and a codefix to add an accessibility to make\nit very easy to fix). This allows users to be very explicit about the lifetime of variables.\n2. This variation of the proposal might feel more natural to users, as the variable exists in an outer \"scope\" and is therefore\nvisible to all inner scopes. There is some concern, however, that silent captures could mean that the state of a class is no\nlonger visible: you'll have to examine all methods to determine if a constructor parameter is captured, which could be suboptimal.\n3. This the least flexible of the proposals, and wasn't heavily discussed. It would need some amount of work to fit in with the\ncommon autoprop case, where the others could work without much work (either via generation or by simple assignment in an\ninitializer for the autoprop).\n\nIn discussing this, we brought another potential design: we're considering primary constructors to eliminate constructor boilerplate.\nWhat if we flipped the default, and instead generated a constructor based on the members, rather than generating potential members\nbased on a constructor. A potential strawman syntax would be something like this:\n```cs\n// generate constructor and assignments for A and B, because they are marked default\npublic class C\n{\n    default public int A { get; }\n    default public string B { get; }\n}\n```\nThere are a bunch of immediate questions around this: how does ordering work? What if the user has a partial class? Does this\nactually solve the common scenario? While we think the answer to this is no, it does bring up another proposal that we\nconsidered in the C# 9 timeframe while considering records: Direct Parameter Constructors.\n\n## Direct Parameter Constructors\n\nhttps://github.com/dotnet/csharplang/issues/4024\n\nThis proposal would allow constructors to reference members defined in a class, and the constructor would then generate a matching\nparameter and initialization for that member in the body of the constructor. This has some benefits, particularly for class types:\n\n* Many class types have more than one constructor. It's not briefer than primary constructors declaring members for a class with\njust one constructor, but it does get briefer as you start adding more constructors.\n* We believe, at least from our initial reactions, that this form would be easier to understand than accessibility modifiers on the\nparameters.\n\nThere 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\nthe name of the parameter, then old code won't be able to adopt this for properties, as properties will almost certainly have different\ncasing than the parameters in languages with casing. This isn't something we can just special case for the first letter either: there\nare many examples (even in Roslyn) of identifiers that have the first two letters capitalized in a property and have them both lowercase\nin a parameter (such as `csharp` vs `CSharp`). We briefly entertained the idea of making parameter names match in a case-insensitive\nmanner, but quickly backed away from this as case matters in C#, working with casing in a culture-sensitive way is a particularly hard\nchallenge, and wouldn't solve all cases (for example, if a parameter name is shortened compared to the property).\n\nWe also examined how this feature might interact with the accessibility-on-parameter proposal in the previous section. While they are\nnot mutually exclusive, several members of the LDT were concerned that having both of these would add too much confusion, giving too\nmany ways to accomplish the same goal. A read of the room found that we were unanimously in favor of this proposal over the accessibility\nproposal, and there were no proponents of adding both proposals to the language.\n\nFinally, we started looking at how initialization would work with constructor chaining. Some example code:\n\n```cs\npublic class Base {\n    public object Prop1 { get; set; }\n    public virtual object Prop2 { get; set; }\n    public Base(Prop1, Prop2) { Prop2 = 1; }\n}\n\npublic class Derived : Base\n{\n    public new string Prop1 { get; set; }\n    public override object Prop2 { get; set; }\n    public Derived(Prop1, Prop2) : base(Prop1, Prop2) { }\n}\n```\n\nGiven this, the question is whether the body of `Derived` should initialize `Prop1` or `Prop2`, or just one of them, or neither of them.\nThe simple proposal would be that passing the parameter to the base type always means the initialization is skipped, but that would\nmean that the `Derived` constructor has no way to initialize the `Prop1` property, as it can no longer refer to the constructor parameter\nin the body, and `Base` certainly couldn't have initialized it (since it is not visible there). There are a few questions like this that\nwe'll need to work out.\n\n## Conclusions\n\nOur conclusions today are that we should pursue #4024 in ernest, and come back to primary constructors with that in mind. Several members\nare not convinced that we need primary constructors in any form, given that our goal is not around making regular `class` types have only\none line. Once we've ironed out the questions around member references as parameters, we can come back to primary constructors in general.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-10-26.md",
    "content": "# C# Language Design Meeting for October 26st, 2020\n\n## Agenda\n\n1. [Pointer types in records](#pointer-types-in-records)\n2. [Triage](#triage)\n    1. [readonly classes and records](#readonly-classes-and-records)\n    2. [Target typed anonymous type initializers](#target-typed-anonymous-type-initializers)\n    3. [Static local functions in base calls](#static-local-functions-in-base-calls)\n\n## Quote of the Day\n\n- \"And I specialize in taking facetious questions and answering them literally\"\n\n## Discussion\n\n### Pointer types in records\n\nToday, you cannot use pointer types in records, because our lowering will use `EqualityComparer<T>.Default`, and pointer\ntypes are not allowed as generic type arguments in general. We could specially recognize pointer types here, and use a\ndifferent equality when comparing fields of that type. We have a similar issue with anonymous types, where pointers are\nnot permitted for the same reason (and indeed, Roslyn's code for generating the equality implementation is shared between\nthese constructs). We would also need consider every place record types can be used if we enabled this: for example, what\nwould the experience be when attempting to pattern deconstruct on a record type, as pointer types are not allowed in patterns\ntoday? It also might not be a good idea to introduce value equality based on pointer types to class types, as this is not\nwell-defined for all pointer types (function pointers, for example). Finally, the runtime has talked several times about\nenabling pointer types as generic type parameters, and if they were to do so then the rules for this might fall out at that\ntime.\n\n#### Conclusion\n\nTriaged to the Backlog. We're not convinced this needs to be something that we enable right now, and may end up being resolved\nby fallout from other changes.\n\n### Triage\n\n#### readonly classes and records\n\nhttps://github.com/dotnet/csharplang/issues/3885\n\nThis proposal would allow marking a class type `readonly`, ensuring that all fields and properties on the type must be `readonly`\nas well. Several familiar questions were immediately raised, namely around the benefit. `readonly` has a very specific benefit\nfor struct types, around allowing the compiler to avoid defensive copies where they would otherwise be necessary. For\n`readonly` classes, there is no clear similar advantage. We might not even emit such information to metadata, and the main\nbenefit would be for type authors, not for type consumers. There is also some concern about whether this would be confusing to\nusers, particularly if this does not apply to an entire hierarchy. If you depend on a non-Object base type that has mutable,\nthen the benefits of using `readonly` are not as clear, even for a type author. Similarly, if a non-`readonly` type can inherit\nfrom a `readonly` type, that means that any guarantees on the current type aren't very strong, as mutation can occur under the\nhood anyway. `readonly` in C# today always means shallow immutability, so there is an argument to be made that this level of\nhierarchy-mutability is not too different.  \nWe also looked at the question of whether this feature should just be analyzer. There is certainly argument for that: particularly\nif there is no hierarchy impact, it seems a perfect use case for an analyzer. However, this is a case where we allow the keyword\non one set of types, while not allowing it on a different set of types. Further, unlike many such proposals, we already have a\nC# keyword that is perfect for the scenario.\n\n##### Conclusion\n\nTriaged into the Working Set. We'll look at this with low priority, and particularly try to see what the scenarios around\nhierarchical enforcement look like, as those were more generally palatable to LDT members.\n\n#### Target typed anonymous type initializers\n\nhttps://github.com/dotnet/csharplang/issues/3957\n\nThis is a proposal to address some cognitive dissonance we have with object creation in C#: you can leave off the parens if you\nhave an object initializer, but only if you specify the type. While it does save 2 characters, that is not a primary motivation\nof this proposal. There are grow-up stories for other areas we could explore in this space as well: we could allow F#-style\nobject expressions, for example, or borrow from Java and allow anonymous types to actually inherit from existing types/interfaces.\nHowever, we have a number of concerns about the compat aspects of doing this, where adding a new `object` overload can silently\nchange consumer code to call a different overload and create an anonymous type. In these types of scenarios, it might even be\nimpossible to determine if the user made an error: if they typed a wrong letter in the property name, for example, we might be\nforced to create an anonymous type silently, instead of erroring on the invalid object initializer.\n\nWe also briefly considered more radical changes to the syntax: for example, could we allow TS/JS-style object creation, with\njust the brackets? However, this idea was not very well received by the LDM.\n\n##### Conclusion\n\nTriaged into the Backlog. While we're open to new proposals in this space that significantly shift the bar (such as around new\nways of creating anonymous types that inherit from existing types), we think that this proposal could end up conflicting with\nany such future proposals and should be considered then.\n\n#### Static local functions in base calls\n\nhttps://github.com/dotnet/csharplang/issues/3980\n\nThis is a proposal that, depending on the exact specification, would either be a breaking change or have complicated lookup rules\ndesigned to avoid the breaking change. It also requires some deep thought into how the exact scoping rules would work. Today,\nlocals introduced in the `base` call are visible throughout the constructor, so we would have to retcon the scoping rules to\nwork something like this:\n\n1. Outermost scope, contains static local functions\n2. Middle scope, contains the base clause and any variables declared there\n3. Inner scope, contains the method body locals and regular local functions.\n\nThis also raises the question of whether we should stop here. For example, it might be nice if `const` locals could be used as\nparameter default values, or if attributes could use names from inside a method body. We've had a few proposals for creating\nvarious parts of a \"method header\" scope (such as https://github.com/dotnet/csharplang/issues/373), we could consider extending\nthat generally to allow this type of thing. Another question would be: why stop at `static` local functions? We could allow\nregular local functions in the base clause, and leverage definite assignment to continue doing the same things it does today to\nmake sure that things aren't used before assignment. This might work well with a general \"method header\" scope, instead of the\nscheme proposed above. Finally, we considered simply allowing the `base` call to be done in the body of the constructor instead,\na la Visual Basic. This has some support, and would allow us to avoid the question of a method header scope by simply allowing\nusers to move the base call to where the local function is visible.\n\n##### Conclusion\n\nTriaged into the Working Set. We like the idea, and have a few avenues to explore around method header scopes or allowing the\nbase call to be moved.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-11-04.md",
    "content": "# C# Language Design Meeting for November 4th, 2020\n\n## Agenda\n\n1. [Nullable parameter defaults](#nullable-parameter-defaults)\n2. [Argument state after call for AllowNull parameters](#argument-state-after-call-for-allownull-parameters)\n\n## Quote of the Day\n\nNo particularly amusing quotes were said during this meeting, sorry.\n\n## Discussion\n\n### Nullable parameter defaults\n\nhttps://github.com/dotnet/csharplang/pull/4101\n\nWe started today by examining some declaration cases around nullable that we special cased in our our initial implementation, but\nfelt that we should re-examine in light of `T?`. In particular, today we do not warn when you create a method signature that assigns\n`default` to `T` as a default value. This means that it's possible for generic substitution to cause bad method signatures to be\ncreated, where a `null` is assigned to a non-nullable reference type. The proposal, then, is to start warning about these cases, in\nboth 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\nwas no pushback to this proposal.\n\nAs part of this, we also considered the other locations in this example. For example, we could issue a warning at the callsite of such\na method. The proposal would be to expand the warnings on nullable mismatches in parameters to implicit parameters as well. This could\nend 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\notherwise unannotated methods, or libraries compiled with an older version of the compiler that did not warn here. There is some\nconcern, though, that putting a warning at the callsite is the wrong location. It was the method author that created this invalid\nsignature, and we'd be punishing users with additional warnings. Presumably, if the author allows `null`, they're appropriately\nhandling it, even if the code is still oblivious or in an older version of C#.\n\n#### Conclusion\n\nThe original proposal is approved. We'll continue looking at the callsite proposal as an orthogonal feature and come back when we have\na complete proposal to review.\n\n### Argument state after call for AllowNull parameters\n\nhttps://github.com/dotnet/csharplang/discussions/4102\nhttps://github.com/dotnet/roslyn/issues/48605\n\nNext, we looked at fallout over a previous decision to update the state of variables passed as parameters to a method. This allowed us\nto 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\nthat any change to add `NotNull` to a parameter would be a good change to make, and they were not interested in updating thousands of\nmethods to do this). However, it caused an unfortunate side effect: `void M([AllowNull] string s)` would have no warnings, and would\nsilently update the parameter state to not null, even though there was absolutely no way `M` could have affected the input argument as\nit was not passed by ref. We considered 2 arguments for this:\n\n1. Perhaps the method isn't annotated correctly? The real-world example here is `JsonConvert.WriteJson`, and there is an argument to be\nmade that in C# 9, this parameter would just be declared as `T?`, solving the issue. However, it does feel somewhat obvious that this\nmethod shouldn't update the state of the parameter.\n2. We loosen the \"effective\" resulting type of the parameter based on the precondition, if the parameter is by-value. `[AllowNull]` would\nloosen the effective resulting type to `T?`, which would not make any changes to the current state of the argument. We might also do the\ninverse for `DisallowNull`.\n\n#### Conclusion\n\nWe 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\nagain.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-11-11.md",
    "content": "# C# Language Design Meeting for November 11th, 2020\n\n## Agenda\n\n1. [IsRecord in metadata](#isrecord-in-metadata)\n2. [Triage](#triage)\n    1. [AsyncMethodBuilder](#asyncmethodbuilder)\n    2. [Variable declarations under disjunctive patterns](#variable-declarations-under-disjunctive-patterns)\n    3. [Direct constructor parameters](#direct-constructor-parameters)\n    4. [Always available extension methods](#always-available-extension-methods)\n    5. [Allow `nameof` to access instance members from static contexts](#allow-nameof-to-access-instance-members-from-static-contexts)\n    6. [Add `await` as a dotted postfix operator](#add-await-as-a-dotted-postfix-operator)\n\n## Quote of the Day\n\n- \"Alright, I'm going to make an analogy to social security here.\"\n\n## Discussion\n\n### IsRecord in metadata\n\nhttps://github.com/dotnet/csharplang/issues/4121\n\nWe discussed a few different ways to tackle this issue, which relates to customers depending on the presence of the `<Clone>$` method\nas 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\nas an identifying characteristic, such as by marking `<Clone>$` methods on non-record types, instead of marking the record types in\nsome manner. However, this approach would have to square with `struct` records, which may or may not have that special method. We also need\nto understand some of the dependent scenarios better: we understand the IDE scenario pretty well, we want to be able to have QuickInfo\nand metadata-as-source reflect the way the type was declared. However, we don't have an understanding of the EF scenario, and what it\nwould want to do for, say, a non-record class that inherits from a record type. Finally, we considered time frames, and came to the\nconclusion that the proposed solution would work fine if we wait until C# next to introduce it, and does not require being rushed out the\ndoor to be retconned into C# 9: the proposed solution is backwards compatible, as long as it is introduced at the same time as\nclass/record cross inheritance.\n\n#### Conclusion\n\nInto the Working Set, we'll consider this issue in conjunction with class/record cross-inheritance.\n\n### Triage\n\n#### AsyncMethodBuilder\n\nhttps://github.com/dotnet/csharplang/issues/1407\n\nWe generally like this proposal, as it solves a real need in the framework while creating a generalized feature that can be plugged into\nmore libraries. We did have a couple of questions come up:\n1. Should we allow this on just the method, or also the type/module level? This seems to be similar to `SkipLocalsInit`, and could be\ntedious to rep-specify everywhere.\n2. Can this solve `ConfigureAwait`? We don't think so: this controls the method builder, not the meaning of `await`s inside the method,\nso while it could potentially change whether a method call returns a task that synchronizes to the thread context by default, it could\nonly do that for methods defined in your assembly, which would just lead to confusing behavior.\n\n##### Conclusion\n\nTriaged into the Working Set, we'll work through the proposal in a full LDM session soon.\n\n#### Variable declarations under disjunctive patterns\n\nhttps://github.com/dotnet/csharplang/issues/4018\n\nWe like this proposal. There are a couple of open issues/questions that need to be addressed:\n1. We need a rule that says when you are allowed to redeclare existing variables. It needs to cover multiple switch case labels, while\nalso not permitting things declared outside the switch label to be redeclared.\n2. How identical do the types need to be? Are nullability differences permitted? ie, are `(object?, object)` and `(object, object?)` the\nsame for the purposes of this feature? It seems like they may have to be.\n\n##### Conclusion\n\nTriaged into the Working Set. We'll take some time and consider these questions, and we should also consider alternatives at the same time,\nsuch as an `into` pattern that would allow a previously-declared variable to be assigned in a pattern, including ones declared outside a\npattern.\n\n#### Direct constructor parameters\n\nhttps://github.com/dotnet/csharplang/issues/4024\n\nWe discussed this feature during our last look at primary constructors, and our conclusion is that we need to explore the space more fully\nwith both features in mind. There are concerns about abstraction leaks, particularly with property casing.\n\n##### Conclusion\n\nTriaged into the Working Set, to be considered in conjunction with primary constructors.\n\n#### Always available extension methods\n\nhttps://github.com/dotnet/csharplang/issues/4029\n\nThere was some strong negative reaction to this proposal. However, presented another way it's more interesting: users who use `var` need\nto include `using`s they otherwise do not need in order to access these types of extension methods, whereas users who do not use `var`\nwill already have the relevant `using` in scope, and will thus see these extension methods. These types of methods are also often ways of\nworking around various C# limitations, such as lack of specialization, and would naturally be defined on the type itself if it was possible.\n\nWe are concerned with doing anything in this space with extension everything/roles/type classes on the horizon, as we don't want to change\nextension methods in a way that we'd regret with those features.\n\n##### Conclusion\n\nTriaged into the backlog. We'll consider this in conjunction with extension everything.\n\n#### Allow `nameof` to access instance members from static contexts\n\nhttps://github.com/dotnet/csharplang/issues/4037\n\nThere 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\nimplementation). We do think this is generally good: yes, the scenario could just use `string.Length`, but that is not really what the user\nintended. They wanted the `Length` property on `P`, and if `P` changes to a different type that no longer has `Length`, there should be an\nerror there. Without this, the cliff that `nameof` tries to solve is just moved further, not removed.\n\n##### Conclusion\n\nTriaged into Any Time. We'd accept a community contribution here: it needs to only permit exactly this scenario, not allow any new types of\nexpressions in `nameof`.\n\n#### Add `await` as a dotted postfix operator\n\nhttps://github.com/dotnet/csharplang/issues/4076\n\nThe LDT has very mixed reactions on this. While we are sympathetic to the desire to make awaits more chainable, and the `.` can be viewed\nas the pipeline operator of the OO world, we don't think this solves enough to make it worth it. Chainability of `await` expressions\nisn't the largest issue on our minds with `async` code today: that honor goes to `ConfigureAwait`, which this does not solve. We could go\na step further with this form by making it a general function that would allow `true`/`false` parameters to control the thread context\nbehavior, but given our mixed reaction to the syntax form as a whole we're not optimistic about the approach. A more general approach that\nsimplified chaining generally for prefix operators would be more interesting.\n\n##### Conclusion\n\nRejected. We do like the space of improving `await`, but we don't think this is the way.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-11-16.md",
    "content": "# C# Language Design Meeting for November 16th, 2020\n\n## Agenda\n\n1. [Ternary comparison operator](#ternary-comparison-operator)\n2. [Nominal and collection deconstruction](#nominal-and-collection-deconstruction)\n3. [IgnoreAccessChecksToAttribute](#ignoreaccesscheckstoattribute)\n\n## Quote of the Day\n\n- \"If it turns out to be really hard, give it to a smarter compiler dev\"\n- \"The name is not good: It should be the BreakTermsOfServiceAttribute\"\n\n## Discussion\n\n### Ternary comparison operator\n\nhttps://github.com/dotnet/csharplang/issues/4108\n\nThis proposal centers around add a bit of syntax sugar to simply binary comparisons, where a user might want to compare 3 objects\nfor ascending or descending order. Today, the user would have to write `a < b && b < c`, but with this proposal they would just\nwrite `a < b < c`. In order to deal with the potential ambiguities, we'd have to first attempt to bind these scenarios as we would\ntoday, and if that fails then attempt to bind them as this new \"relational chaining\" form. This feature would need to have a very\nspecific pattern: if we were to allow `a < b > c`, for example, that could be syntactically ambiguous with a generic, and would need\nto keep binding to that as it would today. We therefore are only interested in strictly-ordered comparisons: all comparisons in a\nchain should be less-than/less-than-or-equal, or greater-than/greater-than-or-equal, without mixing between the 2 orders. We are\nalso worried about the compile-time cost of double-binding here, particularly since the most-likely binding will have to be done second,\nin order to preserve backwards compatability. We also considered allowing more than 3 objects in such a chain: we like the idea, but\nit will require some spec work as it does not just fall out of the current specification.\n\n#### Conclusion\n\nTriaged into Any Time. This needs some specification work to allow the 4 or more operators, which would likely be similar in form to\nthe null-conditional operator. Additionally, any implementation will have to take steps to address potential perf issues and demonstrate\nthat it does not adversely affect compilation perf on real codebases.\n\n### Nominal and collection deconstruction\n\nhttps://github.com/dotnet/csharplang/issues/4082\n\nThis feature provides unity between patterns and deconstruction assignment. Today, we have tuple deconstruction assignment, and tuple\npatterns. They evolved in the opposite direction: we started with tuple deconstruction assignment, then added general patterns to the\nlanguage. We now consider adding nominal deconstruction assignment, to complete the symmetry between the feature sets.\n\nOne 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`\nor `switch` forces the user to deal with the case that the pattern did not match, which is not present here. For nominal deconstruction,\nwe can leverage nullable reference types: the user will get a warning if they attempt to deconstruct an element that could be null. For\nlist 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\nexceptions at runtime. We are also concerned about some of the aspects of allowing names to be given to outer structures, such as allowing\n`var { Range: { Column: column } range } = GetRange();`. This could mix badly with allowing existing variable reuse: in patterns today,\nthe `{ ... } identifier` syntax always introduces a new variable, which we think would end up being confusing. We very wary of allowing\npatterns to match into existing variables because it would introduce side-effects to patterns, which is very concerning. Finally, given\nthat we haven't yet designed regular list patterns, we think we should hold off on list deconstruction assignment until those are complete,\nat which point we should have a discussion around whether we should have them at all.\n\n#### Conclusion\n\nNominal deconstruction assignment is accepted into the working set. Let's split list deconstruction assignment into a separate issue, which\nwill be followed up on after list patterns are designed. Open questions exist on whether we should allow names on patterns themselves.\n\n### IgnoreAccessChecksToAttribute\n\nWe had a very spirited discussion around this attribute, which is essentially the inverse of `InternalsVisibleToAttribute`. Where IVT\nallows an author to grant access to a specific other dll, this allows a specific other dll to grant themselves access to an author. There\nare many challenges around this scheme that fundamentally affect the entire ecosystem, and those discussions need to happen at a .NET\necosystem level, rather than at a language level, even though most of the implementation work will fall on the compiler. Ref assemblies,\nfor example, do not have internal members today. There also needs to be discussions on how we would enforce the \"use at your own risk\"\naspect 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\nAPI that we need to change, it could block shipping until either Roslyn readded the API or the dependency was removed. Given our\nexperiences with `InternalsVisibleToAttribute` already, we're not certain that this burden of risk will be correctly shouldered by the\nones actually taking on the risk.\n\n#### Conclusion\n\nTabled for now. Discussion needs to happen at a higher level.\n\n## Working Set Themes\n\nWith our discussions today, we have finished working through our current triage backlog! We've collected the various issues and themes\nin our working set and created a meta-issue to track them all: https://github.com/dotnet/csharplang/issues/4144. We've locked the issue\nto ensure that it stays a clean space. For discussion on a particular topic, please see the topic issue, or create a new discussion.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-12-02.md",
    "content": "# C# Language Design Meeting for December 2nd, 2020\n\n## Agenda\n\n1. [Partner scenarios in roles and extensions](#partner-scenarios-in-roles-and-extensions)\n\n## Quote(s) of the Day\n\n- \"Have you noticed how similar what you just said is to function pointers?\"\n- \"This is a modern version of COM aggregation.\" \"But in a good way.\"\n\n## Discussion\n\n### Partner scenarios in roles and extensions\n\nToday, we heard from partner teams on the Azure SDK and on ASP.NET, talking about friction they currently encounter\nwith some scenarios that might be addressable through roles, extension everything, or potentially some other solution.\n\n#### ASP.NET Feature Collections\n\nASP.NET models contexts through an aggregation system that allows different services to be composed onto a single `HttpContext`.\nFor example, adding TLS to a session involves creating a TLS connection, wrapping the existing connection, and adding it\nas an available feature to the context. This underlying connection could be one of several types connections: it could be\nrouted through a socket, or it could be in-process, or any of a number of other connection mechanisms, each with its own set\nof properties. It is possible to retrieve each of these sets of features from a `Get` method on the context, but this is\ncumbersome and not generally extensible: for their users, it would be nice to be able to expose a view over a context or\nconnection that exposed the underlying properties.\n\nThis scenario seems like a clear-cut use case for roles and extension-everything as we last discussed them. A role could be\nused to expose a grouping of properties on an upper layer from a lower layer. In fact, the ASP.NET architecture was designed\nwith the eventual intention of using extension properties to remove a number of extension methods that they have in place\ntoday to expose these underlying properties from a decorated type. Of the 3 scenarios we discussed today, this seems the\nmost obviously-addressed by the existing proposal.\n\n#### Azure SDKs\n\nThe Azure SDK scenario presents a more interesting challenge. Feature collections were designed with C# in mind, meaning\nthat both types and type names were thoughtfully designed when creating the API. The Azure SDK (and by extension many\nweb APIs), by comparison, are designed in a web-first manner. In this context, property _names_ are important, and general\nstructures of an API are important, but names of these structures are _not_ important. These APIs are often described and\ngenerated using Swagger, which uses JSON to describe the structure of a response. JSON structures can be strongly typed,\nof course: the structure itself is the type. But the nested properties of a JSON object, which can be nested objects\nthemselves, are described entirely in a structural manner, not in a nominal manner as we do in C#. Here, C#'s paradigms\nbreak down, and the SDK teams run into trouble when creating a C# API to wrap this structure. All of these nested structures\nneed to be named, so that C# can talk about them. This leads to an explosion of types, which can be made even more difficult\nwhen you consider identical structures developed by different teams (perhaps even different companies). By necessity, each\nteam will need to create their own \"named\" data structure to give C# an ability to talk about the object, but these names\nare really meaningless. The JSON didn't have this name, and the structures cannot unify. There are also scenarios with\nvery similar objects (perhaps one object has an extra field that the former does not have). This necessitates an entirely\nnew object to be created, and users often end up needing to write boilerplate methods that just translate objects from\nrepresentation A to B, changing nothing about the data other than making sure the type's name lines up.\n\nThis set of scenarios is not addressed by roles and extension methods, as they currently stand. We theorized that teams\nmight be able to a combination of `dynamic` and a custom completion provider/analyzer, to give users help in writing and\nvalidating code that is, in essence, a set of dynamic calls to nested properties of unnamed types that does have a structure,\nbut this is a complicated solution to the scenario that is likely not generally-leverageable. There are more IDEs than just\nVS, and more IDE scenarios than just completion: what would go-to-def do on these, or quick info on hover?\n\n#### Data Processing\n\nFinally, we took a look at a small proof-of-concept library exploring what replicating parts of the popular Python library\nPandas could be like in C#, with stronger typing around the data generated from a given input. This scenario is very\nreminiscent of F# type providers, allowing users to simply dot into a data structure. However, it suffers from the same\nset of issues that affect the Azure SDK scenarios above. In order to talk about nested data structures, they have to be\nnamed. And while the Azure examples entirely focus on the types of structures representable in JSON, Pandas is far more\nflexible. Additionally, Pandas allows you create new objects as they flow through a pipeline, adding or removing properties\nas they are manipulated.\n\nLooking at these last two examples, it seems that there are some scenarios not served well by C# today, involving JSON or\nother structured but unnamed data. These scenarios care deeply about the names of properties, and the structure attached to\neach property name, but the domains these scenarios interact with do not care about naming these structures. Further, adding\nnames to these structures in C# can be harmful, because it locks out scenarios that can be accomplished in the original\ndomain and forces a naming structure where none was intended, which can result in confusing or badly-named types that can\nthen never be changed because of backwards compatibility concerns. As we continue to evolve the roles and extension\neverything proposals, we should look at these scenarios and see if there are ways to improve the experience for them.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-12-07.md",
    "content": "# C# Language Design Meeting for December 7th, 2020\n\n## Agenda\n\n1. [Required Properties](#required-properties)\n\n## Quote(s) of the Day\n\n- \"I also can't see anyone's video, so raise your hand [in Teams] if you're not here.\"\n- \"If you can't solve required properties, you're not making a time machine.\"\n\n## Discussion\n\n### Required Properties\n\nhttps://github.com/dotnet/csharplang/discussions/4209\n\nToday, we took a look at the next revision of the required properties proposal, after a few months of design work from a smaller\nteam to flesh out the design. We had a small questions coming out of the meeting:\n\n* Could assignments in the nominal parameter list always imply `base.`? It would make it easier for automatically considering\nhidden properties being initialized.\n* We could make it more user friendly by possibly adding warning when a property that is required by the constructor is definitely\nassigned in the constructor?\n* There's still some debate as to this should only be a source-breaking change.\n* Is `init` the right word? Maybe `requires` would be better?\n\nMore 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\nvery complicated and introduces a bunch of new concepts. We may need to start looking at simplifying scenarios and seeing whether that\nallows us to cut this proposal down a bit.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-12-14.md",
    "content": "# C# Language Design Meeting for December 14th, 2020\n\n## Agenda\n\n- [List Patterns](#list-patterns)\n\n## Quote of the Day\n\n- \"My Monday is your Friday... you're going to get unadulterated truth here\"\n\n## Discussion\n\n### List Patterns\n\nhttps://github.com/dotnet/csharplang/pull/3245\n\nToday, we took our first in-depth look at list patterns, which will be the next big turn of the crank in generalized pattern\nsupport in C#. The intent of this type of pattern is to allow matching on arbitrary collection types, matching against both\nthe length and the content of the collection in a single, simple-to-understand fashion, much like our other pattern forms enable\nfor positional and nominal content. To bring context to the discussion around our general goals and principles for pattern\nmatching in C#, we again brought up the table from discussion [3107](https://github.com/dotnet/csharplang/discussions/3107):\n\n| Type | Declaration | Creation | Decomposition | Dispatch (pattern) |\n|-|:-:|:-:|:-:|:-:|\n|`int`|`int x`|`3`|`int x`|`int x` or `3`\n|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 }`\n|anonymous type|-|`new { X = 3, Y = 4 }`|`p.X`|`{ X: int x, Y: int y }` or `{ X: 3, Y: 4 }`\n|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)`\n|tuple|`(int x, int y)`|`(3, 4)`|`(int x, int y) = p`|`(int x, int y)` or `(3, 4)`\n|List|`List<int>`|`new List<int> { 3, 4 }`| ? | **List patterns fit in here**\n|Dictionary|`Dictionary<K,V>`|`new Dictionary<K,V> { { K, V } }`| ? | ?\n\nWhile we are not looking at list decomposition with this proposal, we should keep it in mind, as we will want whatever form\nwe use for pattern dispatch to be used for decomposition as well. In this table, we can see a correspondence between the different\nsyntactic forms of creation and destructuring: object initializers correspond with recursive object patterns, tuple literals\ncorrespond with tuple patterns, etc. By this principle, our initial instinct is to make the collection pattern correspond with\nthe collection initializer syntax, which uses curly braces. However, this runs into an immediate issue: `{ }` is already a\nvalid pattern today, the empty object pattern. This means it cannot serve as the empty collection pattern, as that pattern\nmust specifically check that the collection is actually empty. The current proposal instead takes the approach of using square\nbrackets `[]` to represent a collection pattern, instead of using the curlies. We're pretty divided on this approach: C# has\nnot used square brackets to represent a list or array in the past. Even C# 1.0 used the curly brackets for array initializers,\nreserving the brackets for array size or index access. This would make the proposed syntax a really big break with C# tradition.\nWe could \"retcon\" this by enabling new types of collection literals using square brackets, but that's an issue that LDM has\nnot intensely looked at beyond previously rejecting https://github.com/dotnet/csharplang/issues/414 and related issues. After\nsome discussion, we've come to the realization that the empty collection (ie, the base case for recursive algorithms) is the\nmost important pattern to design for, and the rest of the syntax falls out from that design. We've come up with a few different\nsyntactic proposals:\n\n1. The existing proposal as is. Notably, this pattern form is _not_ part of a recursive pattern, and that means that you can't\nspecify a pattern like this: `int[] [1, 2, 3]`. Indeed, such a pattern is potentially ambiguous, as `int[] []` already means\na type test against a jagged `int` array today. Instead, such a pattern would have to be expressed as `int[] and []`. The\nfirst part narrows the type to `int[]`, and the second part specifies that the array must be empty. We're not huge fans of needing\nthe `and` combinator for a base case (when the input type to the pattern is not narrowed enough to use a collection pattern)\ngiven that one is not needed for tuple deconstruction patterns or property patterns, but it is elegant in its simplicity.\n2. A similar version to 1, except that it allows nesting the square brackets inside the curly braces of the property pattern.\nThis would allow `int[] { [1, 2, 3] }` for the case where you need to both narrow the input type and test the array content.\nThere are some concerns with this syntax: we've also envisioned a dictionary pattern, that would match content using a form\nlike this: `{ [1]: { /* some nested pattern */ } }`. This would mean that the colon at the end of the brackets would determine\nwhether the contents of the brackets are used as arguments to an indexer or the patterns the collection is being tested against.\n3. Using curlies to match the list contents. There are a couple of sub proposals in this section, separated by the way they\nenable testing for the empty collection case. They share the content tests, which look like `{ 1, 2, 3 }`.\n    1. No empty case. Instead, use a property pattern on `Length` or `Count` to check for the empty case. This has issues\n    with our previously-desired support for `IEnumerable` and general `foreach`-able type support, as they do not have any\n    such property to check.\n    2. Empty case represented by a single comma: `{,}` would represent an array with `Length == 0`. This was suggested, but\n    no one argued in favor.\n    3. Square brackets for `Length` tests. This proposal would look something like this: `int[] [0]`. The interesting angle\n    with this version is that it allows for succinct length tests that could be composed of patterns itself. For example, the\n    BCL has some cases where they need to check to see whether an array has some content and Length between two cases, and that\n    could be expressed as `[>= 0 and < 256] { 1, 2, .. }`. This would also allow a general length check to be expressed for\n    `foreach`-able types, though there are some concerns that it would become a perf pitfall if enumerating the entire sequence\n    was necessary to check a non-zero length. The length or count of the collection could also be extracted with a declaration\n    pattern, which could turn into a nice shorthand for not having to know whether this collection uses `Length` or `Count`,\n    something we didn't standardize and now can't. How this version combines with other property tests on the same object would\n    still need to be discussed: could you do `MyType { Property: a } [10] { 1, 2, 3, .. }`, for example, or would the property and\n    collection patterns need to be combined with an `and`?\n    4. Add a new combinator keyword to make the transition to a collection pattern explicit. This is similar to how VB uses\n    `From` to indicate collection initializers. Such a pattern might look something like `int[] with { }` for the empty case.\n    (`with` was the word we spitballed here, but likely wouldn't end up being the final word for confusion with `with` expressions).\n\nWe came to no solid conclusions on the syntax topic today, as we were mostly generating ideas and need some time to mull over the\nvarious forms. We'll come back to this at a later date.\n\nWe also took a brief look at the slice pattern and whether it could be extended to `foreach`-able types. A trailing `..` in a\n`foreach` match would be easy to implement and not have any hidden costs, as it would just skip a check to `MoveNext()` after\nthe leading bits of the pattern match. However, a leading `..` would be much more concerning. Depending on implementation\nstrategy, we'd have emit a much larger state machine or keep track of a potentially large number of previous values as we\niterate the enumerable, so that when we get to the end we can ensure that the previous slots matched correctly. We're not\nsure if this difference will be obvious enough to users, and will need to think more about whether we should enable the trailing\nslice, or enable both slice patterns and let the codegen be what it will. In all likelihood, if the user needs this pattern\nthey'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\nif we generate the states programmatically instead of the user doing it by hand.\n\nAgain, we came to no solid conclusions here, as we spent most of our time on the syntax aspects.\n"
  },
  {
    "path": "meetings/2020/LDM-2020-12-16.md",
    "content": "# C# Language Design Meeting for December 14th, 2020\n\n## Agenda\n\n1. [List patterns](#list-patterns)\n2. [Definite assignment changes](#definite-assignment-changes)\n\n## Quote of the Day\n\n- \"They are syntax forms you little devil. No amount pedanticism is too much in C#.\"\n\n## Discussion\n\n### List patterns\n\nhttps://github.com/dotnet/csharplang/pull/3245\n\nComing out of [Monday's meeting](LDM-2020-12-14.md), we had a few different competing proposals for syntax. As a quick recap:\n\n1. The original proposal as is.\n2. Put the brackets from 1 inside the braces on the top level.\n3. Use braces for the list pattern, with the empty case being:\n    1. No empty case.\n    2. `{,}`\n    3. Add a `[pattern]` form that allows testing and potentially extracting the length of a collection.\n    4. Add a new combinator to make the braces explicitly a list pattern, which would allow `{ }` to be the base case.\n\nAfter the notes were published, we took the list and had an email discussion to narrow in on the specifics of each of these cases.\nCases 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\nproposals, the final 3 being variations of 3.iii from the original list (in psuedo-antlr):\n\n1. The original proposal. This introduces a new `pattern`, which uses `'[' (pattern (',' pattern)* ']')` as the syntax of that\nnew pattern. This cannot be expressed as a top-level concept in a `positional_pattern` or a `property_pattern` because the braces\ncan be ambiguous with the `type` component of these patterns.\n2. `type? ('(' subpatterns? ')')? ('[' pattern ']')? ('{' property_subpatterns_or_list_element_patterns '}')?`.  \nThis form modifies the `positional_pattern` syntax introduced in C# 8 to add a length pattern section, defined by the middle\n`[pattern]` section, and modifies the final braces to contain either a set of positional subpatterns, or a set of list element\npatterns, but not both. To test both property elements and list elements, a conjunctive pattern needs to be used.\n3. `type? ('(' subpatterns? ')')? ('[' pattern ']')? ('{' property_subpatterns '}')? ('{' list_subpatterns '}')?`.  \nThis is very similar to 2, except that it allows both property and list subpatterns at the same time.\n4. `type? ('(' subpatterns? ')')? ('[' pattern ']')? ('{' property_subpatterns_and_list_element_patterns '}')?`.  \nThis is very similar to 2, except that it allows both property subpatterns and list subpatterns in the same set of braces. Consider\nsubproposals of this version to require properties first, list elements first, or no ordering requirements.\n\nThe very important goal for the language team here is to follow the correspondence principle. That means that if you construct using one\nsyntax construct, you should use the same construct to deconstruct. For collection types, this means that we strongly want to prefer\nusing curly braces as the deconstruction syntax, rather than square brackets, because collection initializers use the braces. It is\npossible that at some point in the future, we could add a collection literal syntax that uses square brackets, but there is strong\nhistory in C# to avoid using the brackets in this fashion. Up to this point, the brackets have always contained indexes or lengths\nin the language, and lists of things to initialize have always been inside braces. Changing that at this point, even if we later seek\nto add conformance by introducing a new collection literal, would be asking C# users to unlearn a concept that has been unchanged\nsince C# 1.0, which is very concerning to us. Given this desire, option 1 deviates too much from existing C#, and we will instead\nfocus on one of the latter options.\n\nOf these latter options, option 2 can be viewed as a strict subset of both 3 and 4, as either will allow using conjunctive patterns\nto separate out the list and property patterns if users feel that the combination is unreadable. Additionally, we again turn to the\ncorrespondence principle: today, you cannot combine both collection initializers and object initializers. By the correspondence\nprinciple, then, you should not be able to combine them in the same pattern during deconstruction. We're not necessarily opposed to\nallowing collection and object initializers to be combined in the future, but that is out of scope for the collection pattern changes.\n\nFinally, in discussions Monday and over email, we also took a brief look at indexer patterns as possible `property_subpatterns`. These\nwould look something like this: `{ [1]: pattern, [2..^4]: var slice }`. This form seems like a good next step after list patterns to\nallow deconstructioning objects with indexers. These indexer arguments could allow non-integer constants as well as multiple arguments,\ngiving a deconstruction mechanism for dictionaries that corresponds to object initializers in this area.\n\n#### Conclusion\n\nWe'll move forward with the general syntax proposed in option 2, with a length subpattern and allowing either property subpatterns or\nlist subpatterns in the same \"recursive pattern\" section. We still need to translate the psuedo-spec above into a formal specification.\nWe also did not address the open questions around whether the length pattern should be applicable to types of `IEnumerable`, and if so\nwhether `[0]` is the only allowed pattern or if any pattern is allowable.\n\n### Definite assignment changes\n\nhttps://github.com/dotnet/csharplang/discussions/4240\n\nThis is an area of longstanding pain for C# users: any time conditional evaluation and comparison to constants mix, definite assignment\ncannot figure out what is going on and variables that the user can see are obviously assigned are not considered assigned. We're highly\nin support of this idea in general, as everyone has run into this at some point or another in their C# careers. The definite assignment\nrules are written in a very syntax-driven form, and thus this proposal is written in a very syntax-driven form to update the relevant\nconstructs. Despite that, we do wonder whether we can make these rules more holistic and systematic, such that we don't need to make\nthem syntax-specific like they need to be today. We're also less enthused about the conditional expression version. If it fell out of\nmore general rules it would be nice, but it's not highly important like the null conditional and coalescing changes seem to be.\n\n#### Conclusion\n\nThe 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.\n"
  },
  {
    "path": "meetings/2020/README.md",
    "content": "﻿# C# Language Design Notes for 2020\n\nOverview of meetings and agendas for 2020\n\n## Dec 16, 2020\n\n[C# Language Design Notes for December 16th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-12-16.md)\n\n- List patterns\n- Definite assignment changes\n\n## Dec 14, 2020\n\n[C# Language Design Notes for December 14th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-12-14.md)\n\n- List patterns\n\n## Dec 7, 2020\n\n[C# Language Design Notes for December 7th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-12-07.md)\n\n- Required Properties\n\n## Dec 2, 2020\n\n[C# Language Design Notes for December 2nd, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-12-02.md)\n\n- Partner scenarios in roles and extensions\n\n## Nov 16, 2020\n\n[C# Language Design Notes for November 16th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-11-16.md)\n\n- Triage\n\n## Nov 11, 2020\n\n[C# Language Design Notes for November 11th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-11-11.md)\n\n- IsRecord in metadata\n- Triage\n\n## Nov 4, 2020\n\n[C# Language Design Notes for November 4th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-11-04.md)\n\n- Nullable parameter defaults\n- Argument state after call for AllowNull parameters\n\n## Oct 26, 2020\n\n[C# Language Design Notes for October 26st, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-10-26.md)\n\n- Pointer types in records\n- Triage\n\n## Oct 21, 2020\n\n[C# Language Design Notes for October 21st, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-10-21.md)\n\n- Primary Constructors\n- Direct Parameter Constructors\n\n## Oct 14, 2020\n\n[C# Language Design Notes for October 14th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-10-14.md)\n\n- Triage\n- Milestone Simplification\n\n## Oct 12, 2020\n\n[C# Language Design Notes for October 12th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-10-12.md)\n\n- General improvements to the `struct` experience (continued)\n\n## Oct 7, 2020\n\n[C# Language Design Notes for October 7th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-10-07.md)\n\n- `record struct` syntax\n- `data` members redux\n- `ReadOnlySpan<char>` patterns\n\n## Oct 5, 2020\n\n[C# Language Design Notes for October 5th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-10-05.md)\n\n- `record struct` primary constructor defaults\n- Changing the member type of a primary constructor parameter\n- `data` members\n\n## Sep 30, 2020\n\n[C# Language Design Notes for September 30th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-09-30.md)\n\n- `record structs`\n    - `struct` equality\n    - `with` expressions\n    - Primary constructors and `data` properties\n\n## Sep 28, 2020\n\n[C# Language Design Notes for September 28th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-09-28.md)\n\n- Warning on `double.NaN`\n- Triage\n\n## Sep 23, 2020\n\n[C# Language Design Notes for September 23rd, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-09-23.md)\n\n- General improvements to the `struct` experience\n\n## Sep 16, 2020\n\n[C# Language Design Notes for September 16th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-09-16.md)\n\n- Required Properties\n- Triage\n\n## Sep 14, 2020\n\n[C# Language Design Notes for September 14th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-09-14.md)\n\n- Partial method signature matching\n- Null-conditional handling of the nullable suppression operator\n- Annotating IEnumerable.Cast\n- Nullability warnings in user-written record code\n- Tuple deconstruction mixed assignment and declaration\n\n## Sep 9, 2020\n\n[C# Language Design Notes for September 9th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-09-09.md)\n\n- Triage issues still in C# 9.0 candidate\n- Triage issues in C# 10.0 candidate\n\n## Aug 24, 2020\n\n[C# Language Design Notes for August 24th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-08-24.md)\n\n- Warnings on types named `record`\n- `base` calls on parameterless `record`s\n- Omitting unnecessary synthesized `record` members\n- [`record` `ToString` behavior review](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/records.md#printing-members-printmembers-and-tostring-methods)\n    - Behavior of trailing commas\n    - Handling stack overflows\n    - Should we omit the implementation of `ToString` on `abstract` records\n    - Should we call `ToString` prior to `StringBuilder.Append` on value types\n    - Should we try and avoid the double-space in an empty record\n    - Should we try and make the typename header print more economic\n- Reference equality short circuiting\n\n## Jul 27, 2020\n\n[C# Language Design Notes for July 27th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-07-27.md)\n\n- [Improved nullable analysis in constructors](https://github.com/RikkiGibson/csharplang/blob/nullable-ctor/proposals/nullable-constructor-analysis.md) (Rikki)\n- [Equality operators (`==` and `!=`) in records](https://github.com/dotnet/csharplang/issues/3707#issuecomment-661800278) (Fred)\n- `.ToString()` or `GetDebuggerDisplay()` on records? (Julien)\n- Restore W-warning to `T t = default;` for generic `T`, now you can write `T?`? (Julien) \n\n## Jul 20, 2020\n\n[C# Language Design Notes for July 20th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-07-20.md)\n\n- [struct private fields in definite assignment](https://github.com/dotnet/csharplang/issues/3431) (Neal/Julien)\n    - [Proposal 1](https://github.com/dotnet/roslyn/issues/30194#issuecomment-657858716)\n    - [Proposal 2](https://github.com/dotnet/roslyn/issues/30194#issuecomment-657900257)\n- Finish [Triage](https://github.com/dotnet/csharplang/issues?q=is%3Aopen+is%3Aissue+label%3A%22Proposal+champion%22+no%3Amilestone)\n- Records-related features to pick up in the next version of C# (Mads)\n\n\n## Jul 13, 2020\n\n[C# Language Design Notes for July 13th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-07-13.md)\n\n- Triage open issues\n\n## Jul 6, 2020\n\n[C# Language Design Notes for July 6, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-07-06.md)\n\n- [Repeat Attributes in Partial Members](https://github.com/RikkiGibson/csharplang/blob/repeated-attributes/proposals/repeat-attributes.md) (Rikki)\n- `sealed` on `data` members\n- [Required properties](https://github.com/dotnet/csharplang/issues/3630) (Fred)\n\n\n## Jul 1, 2020\n\n[C# Language Design Notes for July 1, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-07-01.md)\n\n- [Non-defaultable struct types](https://github.com/dotnet/csharplang/issues/99#issuecomment-601792573) (Sam, Chuck)\n- Confirm unspeakable `Clone` method and long-term implications (Jared/Julien)\n\n## Jun 29, 2020\n\n[C# Language Design Notes for June 29, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-06-29.md)\n\n- [Static interface members](https://github.com/Partydonk/partydonk/issues/1)  (Miguel, Aaron, Mads, Carol)\n\n## Jun 24, 2020\n\n[C# Language Design Notes for June 24, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-06-24.md)\n\n- Parameter null checking: finalize syntax\n- https://github.com/dotnet/csharplang/issues/3275 Variance on static interface members (Aleksey)\n- [Function pointer question](https://github.com/dotnet/roslyn/issues/39865#issuecomment-647692516) (Fred)\n\n\n## Jun 22, 2020\n\n[C# Language Design Notes for June 22, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-06-22.md)\n\n1. Data properties\n\n1. Clarifying what's supported in records for C# 9\n\n    - Structs\n\n    - Inheritance with records and classes\n\n## Jun 17, 2020\n\n[C# Language Design Notes for June 17, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-06-17.md)\n\n1. Null-suppression & null-conditional operator\n1. `parameter!` syntax\n1. `T??`\n\n## Jun 15, 2020\n\n[C# Language Design Notes for June 15, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-06-15.md)\n\nRecord:\n\n1. `modreq` for init accessors\n\n1. Initializing `readonly` fields in same type\n\n1. `init` methods\n\n1. Equality dispatch\n\n1. Confirming some previous design decisions\n\n1. `IEnumerable.Current`\n\n## Jun 10, 2020\n\n[C# Language Design Notes for June 10, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-06-10.md)\n\n- https://github.com/dotnet/csharplang/issues/1711 Roles and extensions\n\n## Jun 1, 2020\n\n[C# Language Design Notes for June 1, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-06-01.md)\n\nRecords:\n    1. Base call syntax\n    2. Synthesizing positional record members and assignments\n    3. Record equality through inheritance\n\n## May 27, 2020\n\n[C# Language Design Notes for May 27, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-05-27.md)\n\nRecord syntax\n    1. Record structs?\n    2. Record syntax/keyword\n    3. Details on property shorthand syntax\n\n## May 11, 2020\n\n[C# Language Design Notes for May 11, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-05-11.md)\n\nRecords\n\n## May 6, 2020\n\n[C# Language Design Notes for May 6, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-05-06.md)\n\n1. Target-typing ?: when the natural type isn't convertible to the target type.\n1. Allow `if (x is not string y)` pattern.\n1. Open issues in extension `GetEnumerator`\n1. Args in top-level programs\n\n## May 4, 2020\n\n[C# Language Design Notes for May 4, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-05-04.md)\n\n1. Reviewing design review feedback\n\n## April 27, 2020\n\n[C# Language Design Notes for April 27, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-04-27.md)\n\nRecords: positional & primary constructors\n\n## April 20, 2020\n\n[C# Language Design Notes for April 20, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-04-20.md)\n\nRecords: Factories\n\n## April 15, 2020\n\n[C# Language Design Notes for April 15, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-04-15.md)\n\n1. Non-void and non-private partial methods\n2. Top-level programs\n\n## April 13. 2020\n\n[C# Language Design Notes for April 13, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-04-13.md)\n\n1. Roadmap for records\n2. Init-only properties\n\n## April 8, 2020\n\n[C# Language Design Notes for April 8, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-04-08.md)\n\n1. `e is dynamic` pure null check\n2. Target typing `?:`\n3. Inferred type of an `or` pattern\n4. Module initializers\n\n## April 6, 2020\n\n[C# Language Design Notes for April 6, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-04-06.md)\n\n1. Record Monday: Init-only members\n\n## April 1, 2020\n\n[C# Language Design Notes for April 1, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-04-01.md)\n\n1. Function pointer design adjustments\n\n2. `field` keyword in properties\n\n## March 30, 2020\n\n1. Record Monday\n\n[C# Language Design Notes for March 30, 2020](LDM-2020-03-30.md)\n\n## March 25, 2020\n\n[C# Language Design Notes for March 25, 2020](LDM-2020-03-25.md)\n\n1. Open issues with native int\n\n2. Open issues with target-typed new\n\n## March 23, 2020\n\n[C# Language Design Notes for March 23, 2020](LDM-2020-03-23.md)\n\n1. Triage\n2. Builder-based records\n\n## March 9, 2020\n\n[C# Language Design Notes for March 9, 2020](LDM-2020-03-09.md)\n\n1. Simple programs\n\n2. Records\n\n## Feb 26, 2020\n\n[C# Language Design Notes for Feb. 26, 2020](LDM-2020-02-26.md)\n\nDesign Review\n\n## Feb 24\n\n[C# Language Design Notes for Feb. 24, 2020](LDM-2020-02-24.md)\n\nTaking another look at \"nominal\" records\n\n## Feb 19\n\n[C# Language Design Notes for Feb. 19, 2020](LDM-2020-02-19.md)\n\nState-based value equality\n\n## Feb 12\n\n[C# Language Design Notes for Feb. 12, 2020](LDM-2020-02-12.md)\n\nRecords\n\n## Feb 10\n\n[C# Language Design Notes for Feb. 10, 2020](LDM-2020-02-10.md)\n\nRecords\n\n## Feb 5\n\n[C# Language Design Notes for Feb. 5, 2020](LDM-2020-02-05.md)\n\n- Nullability of dependent calls (Chuck, Julien)\n- https://github.com/dotnet/csharplang/issues/3137 Records as individual features (Mads)\n\n## Feb 3\n\n[C# Language Design Notes for Feb. 3, 2020](LDM-2020-02-03.md)\n\nValue Equality\n\n## Jan 29, 2020\n\n[C# Language Design Notes for Jan. 29, 2020](LDM-2020-01-29.md)\n\nRecords: \"With-ers\"\n\n## Jan 22, 2020\n\n[C# Language Design Notes for Jan 22, 2020](LDM-2020-01-22.md)\n\n1. Top-level statements and functions\n2. Expression Blocks\n\n## Jan 15, 2020\n\n[C# Language Design Notes for Jan 15, 2020](LDM-2020-01-15.md)\n\nRecords\n\n1. \"programming with data\"\n1. Decomposing subfeatures of records\n\n## Jan 8, 2020\n\n[C# Language Design Notes for Jan 8, 2020](LDM-2020-01-08.md)\n\n1. Unconstrained type parameter annotation\n2. Covariant returns\n\n## Jan 6, 2020\n\n[C# Language Design Notes for Jan 6, 2020](LDM-2020-01-06.md)\n\n1. Use attribute info inside method bodies\n1. Making Task-like types covariant for nullability\n1. Casting to non-nullable reference type\n1. Triage\n"
  },
  {
    "path": "meetings/2021/LDM-2021-01-05.md",
    "content": "# C# Language Design Meeting for Jan. 5th, 2021\n\n## Agenda\n\n1. [File-scoped namespaces](#file-scoped-namespaces)\n\n## Quote of the Day:\n\n- \"I see a big tropical void where [redacted's] face was... It's so annoying\"\n- \"It's so cold here, it's 70 [F]\"\n\n## Discussion\n\n### File-scoped namespaces\n\nhttps://github.com/dotnet/csharplang/issues/137\n\nToday, we looked at some of the details around this feature, specifically what should be supported before or after a top-level\nnamespace declaration. The proposal as written allows only extern aliases, using directives, and global attributes. The proposal\nalso does not allow multiple top-level namespaces: you can only have one in the file, and all following type declarations are\nconsidered to be part of that namespace. The debate, therefore, centers on whether we allow multiple of these declarations in a\nfile, what they would mean in that case, and whether we allow a top-level namespace at the same file as top-level statements.\n\nIn many ways, this seems like a style question. Syntactically, regardless of whether allow these concepts to be mixed/duplicated\nin a single file in the formal grammar, the compiler will have to implement rules for what this means in order to provide a good\nIDE experience. There is potential value is allowing this to be flexible, as we generally do not take strong stances on syntax\nformatting guidelines beyond the default rules shipped with Roslyn, and those are very customizable to allow users to decide\nwhether to allow them or not (`var` vs explicit type has 3 major doctrines, for example). By allowing all forms here, we would\nlet users decide what is preferred to them and what is not.\n\nThat being said, however, we have concerns that we even understand what code like this would do:\n```cs\nnamespace X;\nclass A {}\nnamespace Y;\nclass B {}\n```\nFor 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\n`X.Y.B`. We have additional concerns around how this type of code would read in the presence of top-level statements, and\nwhether there would be enough visual contrast between the end of the top-level statements, the namespace, and then types under\nthe namespace, or whether that would be confusing to read. If we restrict the usage now, nothing would stop us from loosening\nrestrictions in a later language version if we discover that we were too restrictive initially, but if we let the genie out of\nthe bottle now, we can never put it back in.\n\n#### Conclusion\n\nNo conclusion today. We're largely split between these two extremes, allowing everything or allowing nothing. We'll take this\nback up again soon to finish debate and settle on a conclusion.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-01-11.md",
    "content": "# C# Language Design Meeting for Jan. 11th, 2021\n\n## Agenda\n\n1. [Required properties simple form](#required-properties-simple-form)\n\n## Quote of the Day\n\n- \"You didn't want to hear me say um anyway... So, um\"\n\n## Discussion\n\n### Required properties simple form\n\nhttps://github.com/dotnet/csharplang/discussions/4209#discussioncomment-275575\n\nToday, we took a look at an extension to the existing required properties proposal, that proposed a syntax form\nthat simplifies the base case of the proposal to remove complexity for what we believe is the 80% use case. This\nform adds a `require` modifier on a property definition. These requirements and then automatically added to the\nimplicit parameterless constructor of a type, if present, and can be added to explicit constructors with\n`require default`, in the same place as the `init` lists of the last proposal.\n\nFirst, we discussed the syntax in the proposal, and potential alternatives. We like the move to put a modifier\non properties and fields as it makes implicit constructor scenarios much simpler, but something still feels off\nabout the full-blown form of this syntax, with `require { Property, List }`. We could draw on type parameter\nconstraint clauses, and a rough first attempt looks promising:\n\n```cs\npublic Person() require FirstName, LastName\n{\n}\n\npublic Student() require ID\n    : base()\n{\n}\n```\n\nThe proposed ability to assign to properties in the require list might be either odd or outright impossible here,\ndepending on potential syntactic ambiguities we haven't thought of yet, but the syntax immediately feels more\nlike C# than the previous curly-brace version.\n\nWhere we spent the bulk of meeting, however, was on how implicit we can make the default parameter list. We\nhad immediate pushback on `require default` even being necessary on constructors: why can't we just infer that\nfor all constructors in a type, and then have a syntax for removing all requirements? There's a feeling that\n`require default` is just busywork, and the compiler should just infer the defaults from the properties and\nfields in the type that are marked `require`. Some proposals for the ability to remove all requirements are\n`require none` and `require default = _`. We also considered a version of the proposal that goes even further,\nthat doesn't allow constructors to `require` additional items: you mark a property or field as required, then\nremove requirements in the constructor itself. In this model, constructors would be unable to add new requirements,\nwhich does remove some potential scenarios, but could simplify the feature significantly. Roughly speaking, the\nthree versions of the proposal can be summarized as follows:\n\n1. Only implicit constructors get implicit require lists.\n2. All constructors get implicit require lists, and can add requirements of their own:\n    1. If the constructor calls base in some manner (including implicit calls to the `object` constructor), that\n    list is all the fields and properties in the type that are marked require.\n    2. If the constructor calls another constructor on `this`, then it simply advertises chaining to that\n    constructor, potentially removing some requirements if it takes care of them in its body.\n3. All constructors get implicit require lists, and cannot add to them. They can only remove them, and there\nis no `require` syntax. This version will need a new syntax for removing requirements, but that will likely\nbe much simpler than the full `require` clause and need less user education.\n\nAfter a read of the room, we're interested in seeing where proposal 3 goes. We'll work on fleshing that out\nwith examples and bring it back to LDM soon.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-01-13.md",
    "content": "# C# Language Design Meeting for Jan. 13th, 2021\n\n## Agenda\n\n1. [Global usings](#global-usings)\n2. [File-scoped namespaces](#file-scoped-namespaces)\n\n## Quote(s) of the Day\n\n- \"You're not yelling at me. You're just wrong.\"\n- \"All language rules are arbitrary. Some are just more arbitrary than others.\"\n\n## Discussion\n\n### Global usings\n\nhttps://github.com/dotnet/csharplang/issues/3428\n\nToday, we started by looking at a long-standing request in various forms: the ability to create using directives that apply\nto an entire project. This is of particular importance now as we solidify our work in relation to the .NET 6 themes, especially\naround both beginner scenarios and general ease-of-use. A well-studied problem in teaching a programming language is avoiding\ncognitive load, and usings are an ever-present cognitive load in C#, even in simple \"Hello, World!\" style applications. Either\nthe teacher says \"Ignore the `using` thing for now\" or they say \"Ignore what the `.`s mean for now\", with no ability to hold\noff on introducing them. That's not to say teaching `using` isn't necessary, and necessary early in the teaching process; merely\nthat delaying that introduction from the first second of seeing C# to a day or week into the curriculum can be very helpful in\navoiding overloading newcomers and scaring them off.\n\nWhile it's an important scenario, beginners aren't the only driving motivation here. .NET 6 is looking at making both beginner\nand general scenarios better, and there's an argument that this will help general scenarios as well. Large-sized projects such\nas dotnet/roslyn are the exception, not the rule; most .NET projects are smaller and don't have nearly so many moving and\ninteracting pieces. `using` boilerplate has a bigger impact on these projects, particularly as they tend to use many frameworks\nand a custom project SDK (such as ASP.NET). That custom SDK, combined with a feature to allow the SDK to specify global usings\nin some manner, can help ease these scenarios and remove unnecessary lines from most files in such solutions. Larger projects\nlike Roslyn may never use this feature, but Roslyn and projects like it are not the projects that much of our users are actually\nwriting.\n\nBroadly, there are two possible approaches to this type of feature: CLI flags, specifiable for actual users via the project file,\nand a syntax form that allows a user to specify a using should apply to all files. We have an existing proposal for the former\napproach, 3428 (linked above), and some spitball ideas for what the latter could look like (perhaps something like\n`global using System;`). Both have advantages:\n\n* If these are specified via command line flags, then there is one place to go looking for them: the project file. A syntax form\nwould be potentially able to be spread out among multiple files. It is would be possible to spread these out across multiple\nprops files if users wanted to, but the types of projects that use these features are likely rarer than the types of projects\nthat use multiple C# files. Tooling could certainly help here, such as creating a new node in the project explorer to list all\nthe 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.\n* We have a number of long-standing requests for having global using aliases. While these can be accomplished via the CLI flag\nproposal, it would be significantly easier and more accessible to users if they had a syntax form of doing so.\n* A syntax form would allow participation from source generators. We're somewhat split on whether that's a good thing or not.\n* A syntax form might be a barrier to potential abilities to do things like `dotnet run csfile` in the future: where would the\nsyntax form live? An ethereal temp file, or a hardcoded part of the SDK?\n\n#### Conclusion\n\nWe seem to have unanimous agreement here that the design space is interesting, and we would like a feature to address the issues\ndiscussed above. We're much more split on the potential approaches, however, and need to explore the space more in depth.\n\n### File-scoped namespaces\n\nhttps://github.com/dotnet/csharplang/issues/137\n\nWe're picking back up on the discussion from [last week](LDM-2021-01-05.md#file-scoped-namespaces), which is around how\nrestrictive we should be in permitted mixing and matching of multiple namespace statements and combination with traditional\nnamespace directives. An important point to acknowledge is that, regardless of what decision we make here, Roslyn is going to\nhave to do something to understand what multiple namespace directives in a file means because it will encounter that code at\nsome 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\nmeant. There is a big difference between a compiler trying to make as much sense as it can of invalid code and the language\nhaving actual rules for the scenario, though. The scenario we're targeting specifically is files with one namespace in them\n(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\ncomputer. This includes the Roslyn codebase, which has several of these types of files specifically for the purposes of\ntesting that we handle the scenario correctly. Measuring an even broader set of millions of C# files on GitHub shows literally\n99.99% of files have just one namespace in them.\n\nWe also briefly discussed the interaction with top-level statements. On the one hand, we're concerned about the readability of\ncombining these things, and that the namespace statement would be too easily missed. On the other hand, having just finished\ntalking about beginner scenarios, it seems like it might be annoying that beginners couldn't be introduced to the simple form\nuntil they start splitting things apart into multiple classes. Users will likely police themselves here if it doesn't read well,\nand maybe restricting it is just adding an arbitrary restriction.\n\n#### Conclusion\n\nWe allow one and only one file-scoped namespace per file. You cannot combine a file-scoped namespace with a traditional\nnamespace directive in the same file. We did not reach a conclusion on the combination with top-level statements and will\npick that up again soon.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-01-27.md",
    "content": "# C# Language Design Meeting for Jan. 27th, 2021\n\n## Agenda\n\n1. [Init-only access on conversion on `this`](#init-only-access-on-conversion-on-this)\n2. [Record structs](#record-structs)\n    1. [Copy constructors and Clone methods](#copy-constructors-and-clone)\n    2. [`PrintMembers`](#printmembers)\n    3. [Implemented equality algorithms](#implemented-equality-algorithms)\n    4. [Field initializers](#field-initializers)\n    5. [GetHashcode determinism](#gethashcode-determinism)\n\n## Quote of the Day\n\n- \"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.\"\n\n## Discussion\n\n### Init-only access on conversion on `this`\n\nhttps://github.com/dotnet/roslyn/issues/50053\n\nWe 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.\n\n1. Change nothing. The scenario remains an error.\n2. Allow unconditional casts.\n3. Allow `as` casts as well.\n\nWe feel that this case is pretty pathological, and we have trouble coming up with real-world examples of APIs that would need to\nboth 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\nin the constructor while not having a form of initializing the property from an object initializer, which is the new thing that\n`init` enables over `set` methods. If we continue seeing a need to name hidden members, perhaps we can come up with a feature that\ngenerally allows that, as opposed to solving one particular case in constructors.\n\n#### Conclusion\n\nWe'll go with 1. The proposal is rejected.\n\n### Record structs\n\nhttps://github.com/dotnet/csharplang/issues/4334\n\n#### Copy constructors and Clone methods\n\nWe're revisiting the decision made the last time we talked about record structs. In that meeting, we decided to disallow record\nstructs from defining customized `with` semantics, due to concerns over how such structs would behave in generic contexts when\nconstrained to `where T : struct`. If we do disallow this customization, do we need to disallow methods named Clone as well?\nAnd should we also disallow copy constructors? In looking at the questions here, we spitballed some potential ways that we could\nallow customized copies and still allow record structs to be used in generics constrained to `where T : struct`, potentially by\nintroducing a new interface in the BCL. A `with` on a struct type param would check for an implementation of that interface and\ncall that, rather than blindly emitting a `dup` instruction as our original intention was. We think it's an interesting idea and\nwant to pull it into a complete proposal, so we're holding off on making any decisions about allowed and disallowed members in\nrecord structs related to copying for now.\n\n##### Conclusion\n\nOn hold.\n\n#### `PrintMembers`\n\nA question was raised during initial review of the specification for record structs on whether we need to keep `PrintMembers`.\nStruct types don't have inheritance, so we could theoretically simplify that to just `ToString()` for this case. However, we\nthink that there is value in minimizing the differences between record structs and record classes, so conversion between them\nis as painless as possible. Since users can provide their own `PrintMembers` method with their own semantics, removing it\npotentially introduces friction in making such a change.\n\n##### Conclusion\n\nKeep `PrintMembers`. The behavior will be the same as in record classes.\n\n#### Implemented equality algorithms\n\nDuring review, a question was raised about our original decision here with respect to generating the actual equality implementation\nfor record structs. Originally, we had decided to not generate a new `Equals(object)` method, and have making a struct a record\nbe solely about adding new surface area for the same functionality. Instead, we'd work with the runtime to make the equality\ngeneration better for all struct types. While we still want to pursue this angle as well, after discussion we decided that this\nwould be another friction point between record classes and record structs, and could potentially have negative consequences if\nwe don't have time to ship better runtime equality for structs in .NET 6, as many scenarios would then just need to turn around\nand implement equality themselves. In the future, if we do get the better runtime-generated equality, that could be added as a\nfeature flag to `System.Runtime.CompilerServices.RuntimeFeature`, and we can inform the generation of equality based on the\npresence of the flag.\n\n##### Conclusion\n\nWe will generate equality methods in the same manner as proposed in the record struct specification proposal.\n\n#### Field initializers\n\nThe question here is whether we can allow field initializers in structs that have a primary constructor with more than zero\nparameters. The immediate followup to that question, of course, is can we just finally allow parameterless constructors for\nstructs in general, and then field initializers just work for all of them? We're still interested in doing this: the\n`Activator.CreateInstance` bug was in a version of the framework that is long out of support at this point, and we have universal\nagreement behind the idea. The last time we talked about the feature we took a look at non-defaultable value types in general,\nand while there are interesting ideas in there, we don't think we need to block parameterless constructors on it.\n\n##### Conclusion\n\nLet's dig up the proposal from when we did parameterless struct constructors last and get it done, then this question becomes\nmoot.\n\n#### GetHashcode Determinism in `Combine`\n\nThe record class specification, and the record struct specification, states:\n\n> The synthesized override of `GetHashCode()` returns an `int` result of a deterministic function combining the values of\n> `System.Collections.Generic.EqualityComparer<TN>.Default.GetHashCode(fieldN)` for each instance field `fieldN` with `TN` being\n> the type of `fieldN`.\n\nWe're not precise on the semantics of \"a deterministic function combining the values\" here, and the question is whether we should\nbe more precise about the semantics of that. After discussion, we believe we're fine with the wording. It does not promise\ndeterminism across boundaries such as different executions of the same program or running the same program on different versions\nof  the runtime, which are not guarantees we want to make.\n\n##### Conclusion\n\nFine as is.\n\n"
  },
  {
    "path": "meetings/2021/LDM-2021-02-03.md",
    "content": "# C# Language Design Meeting for Feb 3rd, 2021\n\n## Agenda\n\n1. [List patterns on `IEnumerable`](#list-patterns-on-ienumerable)\n2. [Global usings](#global-usings)\n\n## Quote of the Day\n\n- \"If the teacher doesn't show up, class is dismissed, right?\" \"Who is the teacher in this scenario?\"\n\n## Discussion\n\n### List patterns on `IEnumerable`\n\nhttps://github.com/alrz/csharplang/blob/list-patterns/proposals/list-patterns.md\n\nToday, we discussed what the behavior of list patterns should be for `IEnumerable`, and specifically how much of list patterns\nshould be able to operate on enumerables. There are multiple competing factors here that we need to take into consideration.\n\n1. `IEnumerable`s can be infinite. If a user were to attempt to match the count of such an enumerable, their code hangs.\n2. `IEnumerable`s can be expensive. Likely more common than the infinite case, enumerable can be a DB query that needs to run\noff to some data server in the cloud when queried. We absolutely do not want to enumerate these multiple times.\n3. 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\nthan checking the pattern by hand\".\n\nAll of that said, we do think that list patterns on enumerables are useful. While this can be domain specific, efficient enumeration\nof enumerables is relatively boilerplate code and with some smart dependence on framework APIs, we think there is a path forward.\nFor example, the runtime just approved a new API for [`TryGetNonEnumeratedCount`](https://github.com/dotnet/runtime/issues/27183),\nand 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\nmust 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\nneed 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\ncan do a more efficient enumeration while checking subpatterns than we could expose as an API from the BCL.\n\nFor the state machine fallback, we want to be as efficient as possible. This means not enumerating twice, and bailing out as soon\nas possible. So, the pattern `enumerable [< 6] { 1, 2, 3, .., 10 }` can immediately return false if it gets to more than 6 elements,\nor if any of the first 3 elements don't match the supplied patterns.\n\nFinally, on the topic of potentially infinite or expensive enumerations, they are an existing problem today. The BCL exposes a `Count`\nAPI, and if you call it on a Fibonacci sequence generator, your program will hang. Enumerating db calls is expensive, regardless\nof 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\nsurprise that they have an infinite enumerable, they've very likely already done a `Take` or some other subsequence mechanism if they're\nlooking for \"the last element from the end\". By having these patterns, we simply allow these users to take advantage of a generation\nstrategy that's as efficient as they could write by hand, with much clearer intent. As long as the enumeration has a specific pattern\nthat users can reason about, it's an overall win.\n\n#### Conclusion\n\nWe'll proceed with making a detailed specification on how `IEnumerable` will be pattern matched against. We're ok with taking advantage\nof BCL APIs here, including `TryGetNonEnumeratedCount`, and are comfortable working with the BCL team to add new APIs if existing ones\ndon't prove complete enough for our purposes.\n\n### Global usings\n\nWe started this by looking at a prototype of how ASP.NET is looking to reduce ceremony in their templates with a framework called\nFeather, which can be seen [here](https://github.com/featherhttp/framework). The hello world for this code is 12 lines long: 6 lines\nof actual code, 3 newlines, and 3 lines of usings. As apps get more complicated, these usings tend to grow quite quickly, and they're\nall 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\nfrom C# 2, and I want to build an ASP.NET application\". This hints at a related, but orthogonal, using feature: recursive usings. For\nexample, `using System.*` would bring in all namespaces under `System`, or `using Microsoft.AspNetCore.*` would bring in all namespaces\nunder `Microsoft.AspNetCore`. However, such a feature wouldn't really solve the issue in question here, which is \"how can specifying\nthe SDK in use ensure that I get the ability to use the features of that SDK by default?\"\n\nWe have 2 general approaches here: use the project file as the place where implicit usings go, or allow a source file to include them.\nBoth approaches have several pros and cons. In a project file works more natively for an SDK, as they can just define a property. The\nSDK does define an AssemblyVersion.cs today, but this feature is potentially more complicated than that. The project file is also\nwhere we tend to put these types of global controls, like nullable or checked. On the other hand, project files are very hard to tool,\nas MSBuild is a complicated beast that can do arbitrary things. Artificial restrictions on the feature, like requiring that it appear\ndirectly in the project file and not in some other targets file, severely limits the usefulness of the feature across solutions. Source\nfiles as the solution provide an easily-toolable experience that feels more C#-native, but potentially encourages these usings to be\nspread out in many locations. Razor has a `_ViewImports.cshtml` file that handles this problem for Razor files, but we don't think this\nmaps 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\nof the cshtml files in the solution as it provides things like the namespace of the rest of the pages.\n\n#### Conclusion\n\nWe're split right down the middle here between project file and C# files. We'll revisit this again very shortly to try and make\nprogress on the feature.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-02-08.md",
    "content": "# C# Language Design Meeting for Feb 8th, 2021\n\n## Agenda\n\n1. Virtual statics in interfaces\n    1. [Syntax Clashes](#syntax-clashes)\n    2. [Self-applicability as a constraint](#self-applicability-as-a-constraint)\n    3. [Relaxed operator operand types](#relaxed-operator-operand-types)\n    4. [Constructors](#constructor)\n\n## Quote(s) of the Day\n\n- \"If you need to kick yourself I see that [redacted] has a foot in the chat you can kick yourself with\"\n- \"Are we at the point where we derail your meeting with other proposals?\"\n- \"It's the classic, noble art of retconning\"\n\n## Discussion\n\nToday, 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\ndecisions for this feature.\n\n### Syntax Clashes\n\nC# 8 brought 2 new features to interfaces: default members, and non-virtual static members. This sets up a clash between static virtual members and\nstatic non-virtual members. In pre-C# 8, `interface` members were always virtual and abstract. C# 8 blurred the line here: private and static members\nin 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\nsee 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\nthe interface. We have a few options for addressing this inconsistency:\n\n1. 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\nmeant something for 21 years in C#, and that is not `virtual`. Requiring a modifier means this does not change.\n2. Break the world. Make static members in interfaces mean static virtual by default. This gets us consistency, but breaks consumers in some fashion\nand/or introduces multiple dialects of C# to support.\n3. We could introduce a bifurcation in interfaces with a `virtual` modifier on the `interface` declaration itself. When marked with `virtual`, `static`\nmembers 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\nwould `virtual interface`s be any different here? And how would you define the existing non-`virtual` members in such an interface?\n\nOptions 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\nstatic 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\ndesign 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\nproposals would likely need to have the first proposal for the class version of the feature anyway. While it would be consistent with instance members,\nneither of them would totally eliminate the needs to apply the modifiers to interface members.\n\n#### Conclusion\n\nWe will require `abstract` or `virtual` be applied to a virtual static member. We will also look at allowing these modifiers for instance interface\nmethods, even though they are redundant, much like we allow `public` on members today.\n\n### Self-applicability as a constraint\n\n`abstract` static members introduce an interesting scenario in which an interface is no longer valid as a substitute for a type parameter constrained\nto that interface type. Consider this scenario:\n\n```cs\ninterface IHasStatics\n{\n    abstract static int GetValue(); // No implementation of GetValue here\n}\n\nclass C : IHasStatics\n{\n    static int GetValue() => 0;\n}\n\nvoid UseStatics<T>() where T : IHasStatics\n{\n    int v = T.GetValue();\n}\n\nUseStatics<C>();           // C satisfies constraint\nUseStatics<IHasStatics>(); // Error: IHasStatics doesn't satisfy constraint\n```\n\nThe main question here is what do we do about this? We have 2 paths:\n\n1. Forbid interfaces with an abstract static from satisfying a constraint on itself.\n2. Forbid access to static virtuals with a type parameter unless you have an additional constraint like `concrete`.\n\nOption 2 seems weird here. Why would a user have constrained to a type that implements an interface, rather than just taking the interface, unless\nthey 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\nfor 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\na default method body for the virtual method, instead of making it abstract.\n\n#### Conclusion\n\nWe choose option 1.\n\n### Relaxed operator operand types\n\nToday, 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\noperators 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,\nwe 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\nthat 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\nwe relax operators enough, and define BCL-native interfaces in a way, such that asymmetric types are representable. For example, a matrix type would\nwant 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,\nwe 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\nin the general interfaces anyway to keep them flexible enough for all our use cases.\n\n#### Conclusion\n\nWe're ok with relaxing the constraints as much as we need to here. We won't block on self types being in the language.\n\n### Constructors\n\nFinally, we looked at allowing or disallowing constructors as virtual in interfaces. This is an interesting area: either derived types would be required\nto provide a constructor that matches the interface, or derived types would be allowed to not implement interfaces that their base types do. The feature\nitself 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\nwhat 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\nbe 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\ndeprecate `new()`, that would mean that every type that has a parameterless constructor would need to implement an `IHasConstructor` interface instead.\nAnd 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\nsheer surface area required and in terms of effect on type loads and runtime performance penalties for thousands and thousands of new types.\n\n#### Conclusion\n\nWe 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),\nthat 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\ncan work around the lack of additional constraints for now by using a static virtual.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-02-10.md",
    "content": "# C# Language Design Meeting for Feb 10th, 2021\n\n## Agenda\n\n1. [Follow up on record equality](#follow-up-on-record-equality)\n2. [Namespace directives in top-level programs](#namespace-directives-in-top-level-programs)\n3. [Global usings](#global-usings)\n4. [Triage](#triage)\n    1. [Nominal And Collection Deconstruction](#nominal-and-collection-deconstruction)\n    2. [Sealed record ToString](#sealed-record-ToString)\n    3. [`using` aliases for tuple syntax](#using-aliases-for-tuple-syntax)\n    4. [Raw string literals](#raw-string-literals)\n    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)\n    6. [First-class native integer support](#first-class-native-integer-support)\n    7. [Extended property patterns](#extended-property-patterns)\n\n## Quote of the Day\n\n- \"That's 3 issues in 8 minutes.\" \"That's an LDM record!\"\n- \"Back to serious stuff. Raw string literals. Because raw is better for digestion\"\n\n## Discussion\n\n### Follow up on record equality\n\nhttps://github.com/dotnet/csharplang/issues/39#issuecomment-678097433\nhttps://github.com/dotnet/csharplang/discussions/4411\n\nBack when the linked comment on #39 was raised, we had an internal email chain discussing changing the implementation of `==` to move the\nreference equality short-circuit down to the strongly-typed `Equals` implementation. We came to the conclusion that instead of moving the\ncheck we should duplicate it, to ensure that `==` still behaves correctly for `null`, but we never followed up on that conclusion. Today,\nwe confirmed that we do indeed want to do that, and update the C# compiler to generate this better version of equality.\n\n#### Conclusion\n\nWe'll do this. https://github.com/dotnet/roslyn/issues/51136 tracks following up on that work.\n\n### Namespace directives in top-level programs\n\nOur last discussion on the namespace directive had one open question left: should we allow them in combination with top-level statements?\nWe had an internal email chain on this topic since then, and came to the conclusion that we should disallow this combination. There's a\ncouple reasons for this:\n\n1. 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\nintroduce a new scope.\n2. 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.\n3. Users might expect to be able to put a namespace _before_ those top-level statements and change the namespace the implicit `Main` is\ngenerated into.\n\n#### Conclusion\n\nDecision upheld. Top-level statements are not allowed in combination with file-scoped namespace directives.\n\n### Global usings\n\nOur last discussion on global usings had us split right down the middle on whether to make global usings a C# syntax feature, or a\ncommand-line switch to the compiler, with a razor-thin majority leaning to C# syntax. In order to make progress here to begin\nimplementation, we again took an internal email chain to discuss this further. This conversation drew a few conclusions:\n\n* Neither a a command-line switch nor C# syntax would prevent a source-generator from providing their own set of usings, but the switch\nwould prevent the source-generator from _dynamically_ providing this, it would have to be predefined in props/targets file in the\ngenerator nuget package.\n* We really need to be considering the experience when using `dotnet`, not `csc`. The SDK passes 182 parameters to a build of a simple\nhello world application today. It's very unrealistic to base scenarios on calling `csc` directly.\n* 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\ntemplates drop down. In either case, the usings will be hidden. For more complicated templates, this choice changes whether the template\ndrops a `GlobalUsings.cs` file, or fills in a property in the template csproj. In either case, the template has really moved beyond a\nsingle-file program, so the difference isn't huge.\n* 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.\n\n#### Conclusion\n\nGiven the need to start implementing here and the thin majority that prefer C# syntax, we will start investigation and implementation\non the C# syntax version, with a speclet forthcoming later this week.\n\n### Triage\n\n#### Nominal and Collection Deconstruction\n\nhttps://github.com/dotnet/csharplang/issues/4082\n\nThis feature will add symmetry with tuple patterns/deconstruction, which is desirable. There is some potential parsing challenges, as\nseveral of the examples look like a block with a labelled statement inside it and will need some tricky work to ensure disambiguation\nworks.\n\n##### Conclusion\n\nTo 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.\n\n#### Sealed record ToString\n\nhttps://github.com/dotnet/csharplang/issues/4174\n\nThis is a simple enough change and we've had a few complaints about the behavior and inability to seal. As an alternative, we could\ndesign a parallel ToString implementation for records that the base type in a hierarchy will call into, which would be a minor behavior\nchange from C# 9 as released. However, this would be complicated, and `sealed` is the keyword to tell consumers \"No really, this is the\nfinal version of this behavior, you can't change it.\"\n\n##### Conclusion\n\nWe'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\nbit of effort to get it into C# 10.\n\n#### `using` aliases for tuple syntax\n\nhttps://github.com/dotnet/csharplang/issues/4284\n\nThe 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\nbroader proposal recently in conjunction with the global using statement feature, which would allow things like\n`global using MyDictionary<TValue> = System.Collections.Generic.Dictionary<int, TValue>` and other similar work. It seems like we want\nto make some improvements in the alias and using area, and we should consider doing a subset of that larger proposal now in the same\nfashion that we've continuously shipped incremental updates for patterns.\n\n##### Conclusion\n\nTriaged 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\nalias improvements in this release.\n\n#### Raw string literals\n\nhttps://github.com/dotnet/csharplang/issues/4304\n\nThere are a number of potentially contentious design decisions in this area, but we intentionally tried to steer away from them today\nand limit to just the general concept. There are many scenarios for embedding other languages into C#: XML, JSON/Javascript, C#, and\nmore. In many of these languages, \" and ' are not interchangeable, so anything with a \" in it is painful in C# today. We also thing that\ninterpolation in these strings is important, as these embedded code scenarios are often used for templating. There is potential work around\na way to specify what character sequence defines the interpolation holes, but we did not go into details or specifics here.\n\n##### Conclusion\n\nInto the Working Set. There's a bunch of design questions that we'll need to spend some time working on.\n\n#### Allow `var` variables to be used in a `nameof` in their initializers\n\nhttps://github.com/dotnet/csharplang/issues/4384\n\nThis is a minor convenience issue that has come up a few times for users, but has potential implementation nastiness with disambiguating\nwhether `nameof` is a method or a `nameof_expression`. Given the minor benefit and the potential implementation concerns, we're concerned\nabout doing this unless we decide to make `nameof` a non-conditional keyword.\n\n##### Conclusion\n\nRejected. If we ever make the change to make `nameof` not a conditional keyword and can simplify the binding here, then we can bring this\nback, but until that point we will leave this as is.\n\n\n#### First-class native integer support\n\nhttps://github.com/dotnet/csharplang/issues/4385\n\nAs the language is specified today, compliant C# compilers have to emit certain overflow conversions and then roundtrip those conversions\nback to the original representation. This is inefficient and a small spec change will produce no observable semantic difference, while\nallowing the compiler to emit better code.\n\n##### Conclusion\n\nAccepted into the working set.\n\n#### Extended property patterns\n\nhttps://github.com/dotnet/csharplang/issues/4394\n\nThis is something that patterns are very verbose about today, and it's a syntax we've previously discussed as a potential shorthand to\nreduce the boilerplate. We could also potentially extend this idea to object initializers, but don't want to tie that to this proposal.\n\n##### Conclusion\n\nAccepted into the working set.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-02-22.md",
    "content": "# C# Language Design Meeting for Feb 22nd, 2021\n\n## Agenda\n\n1. [Global `using`s](#global-usings)\n2. [`using` alias improvements](#using-alias-improvements)\n\n## Quote of the Day\n\n* \"You're muted\" \"I wanted to be muted\"\n\n## Discussion \n\n### Global `using`s\n\nhttps://github.com/dotnet/csharplang/blob/master/proposals/csharp-10.0/GlobalUsingDirective.md\n\nToday we discussed the proposed syntax and restrictions on the current feature specification. As checked in today, the proposal\nputs `global` after the `using` directive, which could be potentially ambiguous and require complicated parsing logic, as `global`\nis a valid namespace identifier today. For example, this is valid code:\n\n```cs\n// Is this a global using alias, or a top-level using variable declaration?\nusing global myVar = Test.AGlobal;\n\nclass Test\n{\n    public static global AGlobal = new global();\n}\n\nclass global : IDisposable { public void Dispose() {} }\n```\n\nWe could potentially resolve this in the same way we did for the `record` keyword, which is to forbid types be named `global` in\nC# 10. We haven't gotten pushback on this approach for `record` as a type name so far, which is positive. However, aside from the\nambiguity, there are other reasons to view `global`-first as a good thing. `global` here is a modifier on the `using`, which C#\ngenerally puts before the declaration, not after. We also considered 2 separate but related questions:\n\n1. Is `static` a similar modifier? Should it be allowed to come before the `using` as well?\n    * After discussion, we don't believe so. `static` isn't a modifier on the `using`, it fundamentally changes what the meaning\n    of the using is about.\n2. We already have existing modifiers for C# scopes: should we use `internal` as the keyword here?\n    * Using `internal` begs the followup question: what does `public` on one of these `using`s mean? What about `private`? We're\n    uncomfortable with the idea of treating these more like types than like macros. This starts to get into a very slippery slope\n    of how we export aliases publicly, can additional constraints be added to aliases, and how does that interact with roles?\n\nFinally, we discussed the proposed restrictions on the feature. We like them overall: if `global` and non-`global` `using`s can\nbe interspersed, it could lead to user confusion as to whether regular `using` directives can affect `global` ones. It also helps\nset up a clearly-defined set of scopes. We add a new `global` scope that comes before all top-level `using` statements today, and\ntheir interactions mirror the interactions of regular `using`s statements with those nested in a namespace.\n\n#### Conclusion\n\nWe put `global` before `using`, but the proposal is otherwise accepted as is.\n\n### `using` alias improvements\n\nhttps://github.com/dotnet/csharplang/pull/4452\n\nContinuing with the theme of `using` improvements, we also discussed generalized improvements to `using` aliases to address a\nnumber of reoccuring complaints over the years with limitations in today's approach. Specifically, `using` directives today\ncannot reference predefined names like `string`, they can't have generic type arguments, they can't use tuple syntax, or use\npointer types (including the C# 9 function pointer syntax). The current proposal allows all of these things, including aliases\nfor partially-bound type parameters such as `using MyDictionary<T> = System.Collections.Generic.Dictionary<int, T>;`. When\ncombined with the previous `global using` feature, enabling this would allow compilation-unit type aliases. Our remaining open\nquestions here focus again on how we want to push `using`s forward in the future:\n\n1. If we want to push `using` aliases as real types, then they need to have the ability to expression the same things all other\ntypes can, including constraints and variance. If we go this route, we could potentially have a future where you can introduce\nan alias that adds a _new_ constraint onto an existing type, such as an invariant `IEnumerable<T>` alias, or a dictionary that\nis constrained to only `struct`-type values.\n2. If we want to push `using` aliases as more macro-expansion, then the ability to expression constraints and variance is a\nconfusing detriment. The type parameter will be substituted at expansion site and we'll error at that point if an illegal\nsubstitution is made.\n\nApproach 1 has many followup questions that quickly start to slide into roles territory. Aliases can be used in public API, for\nexample, so how would we advertise them publicly if the alias has added new constraints? Is it possible for users to introduce\nan opaque alias, such as aliasing `int` to `CustomerId` in such a way as there's no implicit conversion between them? Ultimately,\nwe think that these problems are better solved by a discrete language feature such as roles, rather than as an expansion on\n`using` aliases.\n\n#### Conclusion\n\n`using` aliases will be treated more as macro expansions than as real types. We'll check substitutions for concrete types where\nwe can (such as erroring in the alias itself for `using MyList = System.Collections.Generic.List<int*>;`), but for things we\ncannot check at the declaration site, we will error at the use site. There is no way to add constraints to a `using` alias.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-02-24.md",
    "content": "# C# Language Design Meeting for Feb 24th, 2021\n\n## Agenda\n\n1. [Static abstract members in interfaces](#static-abstract-members-in-interfaces)\n\n## Quote of the Day\n\n- \"I'm not using the monoid word, I'm trying to make it relatable\"\n\n## Discussion\n\n### Static abstract members in interfaces\n\nhttps://github.com/dotnet/csharplang/issues/4436\n\nToday we went over the proposed specification for `static` abstract members. In order to scope the initial implementation, this proposal\nintentionally limits such members to _only_ `abstract` members, not `virtual` members. This is due to complexity in passing along the\n\"instance\" that the static is operating on. Consider this example:\n\n```cs\ninterface I\n{\n    virtual static void I1() { I2(); }\n    abstract static I2();\n}\n\nclass C : I\n{\n    public static void I2() {}\n}\n\nC.I1();\n// How does the runtime pass along the information that the type here is C,\n// and I.M1() should invoke C.I2()?\n```\n\nGiven the complexity of implementation of this scenario and the lack of current motivating examples, we will push this out for a later\nversion unless our investigations of representing generic math end up needing it.\n\n#### `==` and `!=` operators\n\nThese are restricted in interfaces today because interface types cannot implement `object.Equals(object other)` and `object.GetHashcode()`,\nwhich are integral to implementing the operators correctly. We can lift that restriction for `abstract static` members, as the implementing\nconcrete type will then be required to provide implementations of `Equals(object other)` and `GetHashcode()`.\n\n#### `sealed` on non-abstract members\n\nWe don't have any strong feelings on allowing `sealed` on non-virtual `static` interface members. It's fine to include in the proposal.\n\n#### Conversion restrictions\n\nAs we implement a set of math interfaces, we'll come across parts of the current restrictions that make it impossible. We should be cautious\nhere and only lift restrictions as much as is necessary to implement the target scenarios. We can review the rules in depth when they have\nbeen proven out by final usage.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-03-01.md",
    "content": "# C# Language Design Meeting for March 1st, 2021\n\n## Agenda\n\n1. [Async method builder override](#async-method-builder-override)\n2. [Async exception filters](#async-exception-filters)\n3. [Interpolated string improvements](#interpolated-string-improvements)\n\n## Quote of the Day\n\n- \"I checked my math twice before I spoke.\" \"Well I did not.\"\n\n## Discussion\n\n### Async method builder override\n\nhttps://github.com/dotnet/csharplang/issues/1407\n\nWe first looked at a proposal to enable customization of the async state machine generated by the compiler to allow for additional\ncustomizability. Today, there is no way to customize the builder that the compiler emits for an async method except by introducing\na new task-like type. This is a leaky abstraction that limits the ability of the BCL and other libraries to adopt pooling and other\ncustomizations where appropriate because they don't want to leak the implementation detail of the pooling to users of a method, but\ndon't have another way to customize the builder.\n\nThis proposal has simple core, with multiple possible addendums that add more complexity but also more customizability to usages.\nAfter review, we believe the initial proposal is enough to cover our needs here, as additional arguments to a builder can be achieved\nby using additional builder types that have their own `Create` methods. This could be somewhat ugly for deeply-variable scenarios,\nbut 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\ncomes up for it in a future version, we can look at adding more customization then.\n\nWe also looked at ways to simplify the type/module level constructor. The proposal today suggests having a constructor that takes\nboth the builder type and the task-like type, that would inform the compiler of when to apply the customized builder. This seems\nlike mandated busy-work for the developer: the builder type returns an instance of this task-like type from a well-defined method,\nand 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\nbe easier for the user to just infer the applicable task-like type from the builder. There are some interesting scenarios around\nopen generics here: how does the compiler perform substitution to arrive at the final builder type, and verify that the task-like\nreturn is correct? Some spec work will be needed to achieve this, but it should be possible, and should be overall worth it.\n\nAnother question is whether it's possible to go back to the default builder on a method if an attribute has been applied at a\ntype/module level. This should be doable: all the standard builder types are public API, so all the user needs to know is what the\ndefault builder for a type actually is. This is also a fairly niche corner in an already niche scenario, so we don't think any\nadditional sugar or \"default\" constructors are necessary.\n\nDiagnostics will need to be reported on the use-site for issues involving generic substitutions. Builder generics will be able add\nnew constraints on type parameters that the underlying task-like type doesn't have, so invalid uses need to be carefully handled\nand diagnostics reported to ensure a good user experience.\n\n#### Conclusion\n\nWe unanimously like looking at a type inference-based approach and seeing if we can make it work.\n\n### Async exception filters\n\nhttps://github.com/dotnet/csharplang/issues/4485\n\nThis is a proposal to address a pain-point in async contexts, where the state machine can catch exceptions and unwind the exception\nstack before user-code can catch the exception, which leads to bug reports and heap dumps that are missing the actual stack trace\nwhere an exception is thrown. Roslyn is a prime example of this, with lots of try/catch handlers sprinkled over the codebase in\nasync contexts to be able to report heap dumps before the async machine catches and unwinds the stack. However, this is often a\nerror-prone process: Roslyn receives a bug report with a missing stack, adds a new try/catch to ensure it gets a good bug report,\nthen waits for a user to encounter the problem again. This proposal would allow the user to define a handler that gets called when\nthe async state machine gets called back for an exception, allowing Roslyn and similar async applications to report take telemetry\nand other similar actions before stack unwinding. Similar to the first proposal today, it in many ways represents an aspect-oriented\nfeature of customizing the async state machine emit in some way.\n\n#### Conclusion\n\nWe 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.\n\n### Interpolated string improvements\n\nhttps://github.com/dotnet/csharplang/issues/4487\n\nFinally today, we looked at a proposal on improving code gen and usage for interpolated string expressions. Most of this section of\nthe meeting was spent going through the proposal itself, with not a lot of discussion on the individual points or open questions.\nObservations we made:\n\n* We should consider making the `GetInterpolatedString` and `TryFormat` methods public only. This ensures that, like instance\nGetEnumerator() methods, there isn't potential confusion when one method is preferred in project A but another method is preferred\nin project B, even when all the types involved are otherwise identical.\n* We'll need to carefully consider how the `out` parameter affects local lifetime rules for `ref struct` builder types, which we expect\nto be the majority. Most of this should end up falling out, but careful verification will be needed.\n* The more likely compat issue is that a library introduces a public API that exposes one of these builder types, and an older compiler\nis 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.\n* Even intentional, measured changes to better conversion from expression are scary, and this needs very careful review to ensure\nwe're doing exactly what we want, and no more.\n* `TryFormat` short-circuiting can be quite powerful. There are plenty of logging scenarios where the user would not want to evaluate\nsome expensive computation that we get around today by creating `Func`s and lazily-evaluating. This would solve that, but we need\nto make sure we're not creating an easy pitfall for users.\n\n#### Conclusion\n\nWe like the direction of this proposal. We did not address the open questions in depth today, will need to come back to them soon.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-03-03.md",
    "content": "# C# Language Design Meeting for March 3rd, 2021\n\n## Agenda\n\n1. [Natural type for lambdas](#natural-type-for-lambdas)\n    1. [Attributes](#attributes)\n    2. [Return types](#return-types)\n    3. [Natural delegate types](#natural-delegate-types)\n2. [Required members](#required-members)\n3. [Appendix: ASP.NET examples](#appendix-aspnet-examples)\n\n## Quote of the Day\n\n- \"I specifically avoided using the word to avoid settling on a pronunciation for everyone to get annoyed at.\"\n\n## Discussion\n\n### Natural type for lambdas\n\nhttps://github.com/dotnet/csharplang/blob/master/proposals/csharp-10.0/lambda-improvements.md\n\nToday we looked at a proposal around enhancing lambda expressions and method groups with a \"natural type\", which is helpful for several\nASP.NET scenarios. Overall, the LDM has general support for making enhancements here: explaining how lambdas and method groups don't have\nnatural types and why that means you can't use `var` or other similar scenarios has always been a pain point. Examples that show the\nASP.NET scenarios are at the bottom of these notes in [Appendix: ASP.NET examples](#appendix-aspnet-examples).\n\n#### Attributes\n\nThere are some important details around how exactly these attributes are emitted to the final assembly that need to be ironed out, and this\nlikely 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\nsure that we are cautious enough about this specification that we don't box ourselves out of future lambda optimizations we can make today.\n\nSyntax-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\nprevious expression. If we require that the lambda is entirely parenthesized when an attribute is used it shouldn't be ambiguous, but\nparenthesizing lambdas can be a pain and isn't the prettiest thing in the world. There's an additional question of whether we should always\nrequire the arguments to a lambda to be parenthesized if there is a leading attribute. This code is visually ambiguous if unparenthesized,\nfor example:\n\n```cs\n[MyAttribute] x => x; // Does MyAttribute apply to the parameter or the entire lambda?\n```\n\nAnother syntax question is around the requirement to specify the parameter type when attributing a parameter. We have an open proposal to\nremove the requirement to specify the type when using `ref` or other parameter modifiers, so why add the requirement here? The main issue\nis around making sure that we can parse the lambda. We added the requirement for modifiers previously because we weren't sure if we could\nalways 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\nare no parsing issues.\n\n#### Return types\n\nParsing issues abound here as well. `:` is _very_ dangerous from a parsing perspective, potentially requiring a large amount of lookahead and\nrecovery 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\nthe amount of effort that disambiguation will require. Some potential alternatives we discussed:\n\n```\n() -> int { ... } // Potentially ambiguous with pointer derefs, but should be easier to disambiguate than the :\n(-> int) { ... } // Also possibly ambiguous, but again easier to disambiguate than :\n(return: int) { ... }\n```\n\nWe could also look into forms that put the return type on the left side of the lambda, which fits more into existing method declaration\nsyntax today. However, lambdas are closer to `Func<T>` and function pointer types, and today both of those use the right-hand side for the\nreturn type, so using a right-hand return type here would fit.\n\n#### Natural delegate types\n\nOur main potential concerns with introducing a natural type for lambdas and method groups comes from conversion scenarios. By introducing\na natural type and allowing it to convert to `Delegate` and making no other changes, it could potentially change resolution for `Expression<T>`\nor other complicated inference scenarios. For most cases the more specific type in the better conversion would win, but we need to verify\nthat. A potential workaround is to define a specific type of conversion for delegate natural type to System.Delegate, and adjust better\nconversion to always consider this conversion to be worse. We also should consider whether delegate natural types should be natively\nconvertible to `Expression<T>` as well.\n\nAnother important note is that by allowing single-method method groups to have a natural type, we'll be taking a step we explicitly avoided\nin 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\nchange to C#, as adding a new overload to a previously-not-overloaded will _always_ be a potential breaking change, even if no parameter\ntypes are ambiguous.\n\nFinally, we looked at whether we should avoid synthesizing delegate types, and just restrict natural types to those that can be expressed\nas an `Action/Func`. While this would simplify implementation, it makes understanding the feature dramatically more complex, and prevents\nusing either ref parameters/returns or ref struct parameters/returns.\n\n### Required members\n\nhttps://github.com/dotnet/csharplang/issues/3630\n\nFinally today, we took a broad look at another revision of the required members proposal, following up on feedback from the \n[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\nproposal. There are still some open questions to resolve, but unlike previous iterations these are refinements to the proposal in its\ncurrent form, not total rewrites. Some questions raised today and recorded in the proposal are:\n\n* 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\nthe constructor? This affects whether it can use local functions defined in the constructor and whether the constructor body can shadow\nlocals.\n* How many diagnostics do we want to have for silly scenarios, such as a required property that is never required from a constructor?\n* What is the severity of diagnostics we are looking to have? Namely, warnings or errors?\n* Are we using the right keywords?\n\n### Appendix: ASP.NET examples\n\nThese are example ASP.NET programs we looked at when considering natural types, originally taken from https://github.com/halter73/HoudiniPlayground.\n\n#### As written in C# 9\n\n```cs\nusing System;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Mvc;\n\nvar app = WebApplication.Create(args);\n\n[HttpGet(\"/\")]\nTodo GetTodo() => new(Id: 0, Name: \"Play more!\", IsComplete: false);\napp.MapAction((Func<Todo>)GetTodo);\n\n[HttpPost(\"/\")]\nTodo EchoTodo([FromBody] Todo todo) => todo;\napp.MapAction((Func<Todo, Todo>)EchoTodo);\n\n[HttpGet(\"/id/{id?}\")]\nIResult GetTodoFromId([FromRoute] int? id) =>\n    id is null ?\n    new StatusCodeResult(404) :\n    new JsonResult(new Todo(Id: id.Value, Name: \"From id!\", IsComplete: false));\napp.MapAction((Func<int?, IResult>)GetTodoFromId);\n\nawait app.RunAsync();\n\nrecord Todo(int Id, string Name, bool IsComplete);\n```\n\n#### Simple proposal with natural types\n\n```cs\nusing System;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Mvc;\n\nvar app = WebApplication.Create(args);\n\napp.MapAction([HttpGet(\"/\")] () => new(Id: 0, Name: \"Play more!\", IsComplete: false));\napp.MapAction([HttpPost(\"/\")] ([FromBody] Todo todo) => todo);\n\nawait app.RunAsync();\n\nrecord Todo(int Id, string Name, bool IsComplete);\n```\n\n#### A version that uses a lambda return type\n\n```cs\nusing System;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Mvc;\n\nvar app = WebApplication.Create(args);\n\napp.MapAction([HttpPost(\"/\")] ([FromBody] Todo todo) : Todo => todo);\napp.MapAction([HttpGet(\"/\")] () : Todo => new(Id: 0, Name: \"Play more!\", IsComplete: false));\n\napp.MapAction([HttpGet(\"/id/{id?}\")] ([FromRoute] int? id) : IResult => \n    id is null ?\n    new StatusCodeResult(404) :\n    new JsonResult(new Todo(Id: id.Value, Name: \"From id!\", IsComplete: false)));\n\nawait app.RunAsync();\n\nrecord Todo(int Id, string Name, bool IsComplete);\n```\n"
  },
  {
    "path": "meetings/2021/LDM-2021-03-10.md",
    "content": "# C# Language Design Meeting for March 10th, 2021\n\n## Agenda\n\n1. [Property improvements](#property-improvements)\n    1. [`field` keyword](#field-keyword)\n    2. [Property scoped fields](#property-scoped-fields)\n2. [Parameterless struct constructors](#parameterless-struct-constructors)\n\n## Quote of the Day\n\n- \"I have a request for the second part of this meeting... more funny quotes!\" \"I'm here, don't worry.\" \"If nothing\nelse happens I'll take it I guess.\"\n\n## Discussion\n\n### Property improvements\n\nhttps://github.com/dotnet/csharplang/issues/140  \nhttps://github.com/dotnet/csharplang/issues/133\n\nWe started today by looking at these proposals again, examining the whole space to determine a priority for which to start implementing\nfirst. [Last time](../2020/LDM-2020-06-24.md#property-enhancements) we looked at this was 6 months ago, with mild preference for doing 133\nfirst, and these issues remain the issues with the largest general support on the csharplang repo.\n\nBroadly speaking, C# today has 2 types of properties, each lying on the extreme end of a spectrum of flexibility:\n\n* 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\nto only via the property getter and setter.\n* Manual props. These are maximally flexible, but have a lot of boilerplate involved and any needed backing fields are exposed to the entire\nclass.\n\nWe also see 2 broad classes of problems that users would like to be addressed:\n\n* 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\n`get` or `set`. This includes things like INotifyPropertyChanged and logging. 140 has a solution for this, the `field` keyword.\n* 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.\nToday, these pieces of state must be exposed to the entire type, which results in naming conventions like `_value_doNotUseOutsideOfProperty`.\n133 solves this by allowing fields to be scoped to properties.\n\nOne important distinction we see between these problems is that the first one, solved by the `field` keyword, tends to be _much_ more pervasive\nthan 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\nnumber of requests for the feature in general.\n\n#### `field` keyword\n\nThe field keyword, while seemingly simple, has some interesting design decisions that we will need to settle on:\n\n* What should the nullability of these backing fields be? An obvious answer is \"should match the property\", but this likely precludes the\nability to do any kind of lazy init in such properties. Rather, this scenario seems similar to `var`, where we allow `null` to be assigned\nto the local, but warn when it is used unsafely. It seems possible that we could devise rules that work similarly for the `field` keyword\nhere.\n* There are some concerns about how the compiler will know whether the property is a partial auto-prop or not. Just using the `field`\nkeyword can lead to some complicated scenarios, particularly if the user wants to have both custom getters and setters. We could look at a\nmodifier like `auto` to enable usage of the `field` keyword in the property body, or put a requirement that such properties must have either\nan auto-implemented `get` or `set`, but both of those feel like limitations we're not fans of. Investigation will be needed into how much\ncomplexity this will introduce for the compiler.\n    * 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\n    same determination.\n\n#### Property scoped fields\n\nProperty scoped fields are similarly simple on first glance, but have some questions to resolve:\n\n* 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\nit seems like that restriction would mean `Lazy<T>` would be unusable, since it likely needs access to `this`. Related questions:\n    * If they are visible, how can they be accessed? Just by name? Dotted off the property somehow?\n    * Can names conflict with each other?\n    * Can these property-scoped fields be seen by overrides? What are the valid accessibilities for them?\n* How do these fields influence nullable analysis?\n\nWe also considered whether to think of this proposal \"property scoped locals\", instead of as fields. However, thinking of these as locals\nraises confusing questions about lifetimes of these members, whether attributes can be applied to them, and still leaves the above questions\nunresolved.\n\nFinally on this topic, we looked at whether we should expand the set of property-scoped things to methods, classes, and other definitions.\nCurrently, we don't see a huge need for this, but we can revisit later if the need presents itself.\n\n#### Conclusions\n\nIn 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,\nbut resolves more cases and provides more benefit to the users who want it, as it actually reduces boilerplate rather than just moving\nboilerplate.\n\nWe 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.\n\n### Parameterless struct constructors\n\nhttps://github.com/dotnet/csharplang/blob/master/proposals/csharp-10.0/parameterless-struct-constructors.md\n\nFinally today, we looked at the proposal for parameterless constructors. This proposal needs to make sure that it can handle what the general\n.NET ecosystem can do with struct constructors today, including private struct constructors.\n\nInitialization behavior is one major open question. Today, constructors must initialize all fields in a struct, but they can delegate to the\nparameterless constructor to zero-initialize all fields if they choose to. If the user is defining the parameterless constructor themselves,\nthey can no longer do this. We could consider making the zero-initialization an implicit part of the parameterless constructor if not all fields\nwere definitely assigned, but this would create an inconsistency with how structs work in general. A related question arises with field\ninitializers when no parameterless constructor is present: if one field initializer is present, do all fields have to be initialized, or can\nwe infer zeroing them? We should also consider a warning for `this = default` in a parameterless constructor that has field initializers, as\nthat will overwrite the field initializers.\n\nWe also looked at warnings around when parameterless constructors are not called, namely everywhere that `default` is used instead of `new`.\nThis includes arrays, uninitialized fields, and others. One immediate comparison is to the compromises we made around nullable: we don't\nwarn when an array of a non-nullable reference type is created and then immediately dereferenced, so it seems contradictory that we'd add\nwarnings here. While non-defaultable structs are an interesting idea that LDM has looked at in the past, it is orthogonal to this feature\nand will need a bunch more rules than we can put in here.\n\nNext, we considered scenarios where `new StructType()` does not actually mean calling the constructor, such as default parameter values. This\nis allowed today, but if we add parameterless constructors it will not actually call that constructor. Warning or erroring on such things is\na breaking change, but the potential harm from developers thinking a constructor is being called when it's not is likely greater than any\nharm to users that would need to specify `default` instead of `new`. We should consider erroring when a parameterless constructor exists for\nthese cases, and having a warning wave to cover the cases when there isn't a parameterless constructor to help guide users to idiomatic patterns.\n\nFinally, we looked at interactions with generic type arguments. The `new()` constraint required a _public_ constructor, internal and private\ndo not work for this. We can block direct substitution for such type parameters, but indirect substitution would be possible as `where T : struct`\nalready implies `new()` today. We don't think that we can realistically block all `where T : struct` substitutions for structs with non-public\nconstructors, 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\nwhere we have to simply hold our noses and compromise on letting the runtime exception happen.\n\n#### Conclusions\n\nOverall, 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\nopen questions.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-03-15.md",
    "content": "# C# Language Design Meeting for March 15th, 2021\n\n## Agenda\n\n1. [Interpolated string improvements](#interpolated-string-improvements)\n2. [Global usings](#global-usings)\n\n## Quote of the Day\n\n- \"Need is a strong word... I'm just teasing, I'm just lobbing in a joke\"\n\n## Discussion\n\n### Interpolated string improvements\n\nhttps://github.com/dotnet/csharplang/issues/4487\n\nWe looked at the open question around argument passing today. In the current form, the proposal treats the receiver specially, even\nfor reduced extension methods where the receiver is just sugar for the first argument. This special treatment of the receiver is\nvery limiting, as many API patterns exist today where destinations are conveyed as arguments to a method, not as the receiver of the\nmethod, and we would like APIs to be able to continue having their same shapes. It's also inconsistent with how we treat extension\nmethods in the rest of the language: they're a sugar, and there is no semantic difference between calling them in reduced form or not.\n\nTo address this, we looked at a couple of possible solutions:\n\n1. 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\nthe builder type would need to support storage of an arbitrary number of arguments of arbitrary types, and would preclude working with\nref structs and other types that can't be in generics today.\n2. Require methods to have a `PrepFormat` or similar signature that is isomorphic to the original signature, with the builder parameters\nas `out` variables instead. This would allow us to simply call that signature, and there would be no fancy mapping to consider. However,\nthis is pretty messy from a public API standpoint. We can apply `EditorDisplay` to such methods, but they'll still exist, need to be\ndocumented, and generally get in the way. It also means that every method will need to have a second method, which possibly limits code\nsharing abilities.\n3. Put an attribute on either individual parameters or on the builder type, specifying that these parameters should be passed to the\nbuilder creation method. The former version was proposed in the open questions section, but the latter came up in discussion and seems\nlike a better approach. It gives a central location, handles multiple potential builders in a method signature, and allows including the\nreceiver type as either a magic name like `this` or as a boolean flag.\n\n#### Conclusion\n\nWe'll look at the attribute on the builder type solution. The next question we need to answer is around out-of-order execution for\narguments passed to builders.\n\n### Global usings\n\nhttps://github.com/dotnet/csharplang/issues/3428\n\nNext, we looked at 2 open issues in global usings: the scope of the global using statements, and how name lookup treats these usings\nwith respect to regular using directives. Both of these questions really hinge on the overall view we want to take on how global usings\nare represented. There are 2 views here:\n\n1. Global usings are effectively copy/pasted into the top of every file. They're just like regular `using` directives, and all the same\nrules that apply to regular `using` directives at the top level apply to global usings as well.\n    * This has the advantage that, at the top level, a regular `using` directive will _never_ be changed by a global using directive.\n    Users can't introduce namespace ambiguities at the top level by introducing a global using directive that has a nested namespace with\n    the same name as a top-level namespace.\n    * It aligns with our prior art: both CSX and VB.NET work this way.\n    * This version has the disadvantage that, at the top level, global aliases could not be reused in a file-scoped using alias. They could\n    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\n    someone will hit it at some point.\n    * If a name is imported in both a global `using` directive and a file-scoped `using` directive, that name is ambiguous.\n2. Global usings are a new scope, that exists _above_ regular `using` directives at the top of a file. They are to file-scoped `using`\ndirectives what file-scoped `using` directives are to `using` directives nested in a namespace.\n    * This would allow globally-defined aliases to be used in file-scoped directives.\n    * We would need to rationalize how these rules work for CSX. Do global using directives imported from a `#load` directive change the\n    meaning of `using` directives in the current file, or files that are subsequently `#load`ed?\n    * Name lookup would prefer the file-scoped `using` directives, only going to global directives if a name wasn't found.\n    * Has a bigger implementation cost: some PDB changes might be required in order to ensure that names mean the correct things and diverges\n    heavily from existing implementations.\n\nWe think both worldviews here are consistent and reasonable, and would be fine with either mental model as an explanation to consumers of how\nthe feature works. However, worldview 1 is more consistent with past decisions and has less implementation concerns.\n\n#### Conclusion\n\nWe'll go with worldview 1. The decisions for scoping and name lookup fall out from this.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-03-24.md",
    "content": "# C# Language Design Meeting for March 24th, 2021\n\n## Agenda\n\n1. [Improved interpolated strings](#improved-interpolated-strings)\n2. [`field` keyword](#field-keyword)\n\n## Quote of the Day\n\n- \"We all want to be happy\"\n\n## Discussion\n\n### Improved interpolated strings\n\nhttps://github.com/dotnet/csharplang/issues/4487\n\nToday, we looked at one of the open questions in improved interpolated strings, conditional evaluation of the interpolated\nstring holes. The proposal today allows the interpolated string builder to return `false` from creation or from any `TryFormat`\nmethods, which short-circuits evaluation of any of the following interpolation holes. This has some pros and cons:\n\n* Pro: Interpolation holes can be expensive, and if they don't need to be executed it gives an easy way to achieve semantics\nthat people often do with lambdas currently.\n* Con: This is \"invisible\" to the user. There isn't a way, looking at an interpolated string expression as an argument to a\nmethod, to tell whether the holes in this string will be conditionally-evaluated or not.\n\nThis conditional evaluation can have visible impacts when the interpolated string expression has side-effects. For example,\na conditionally-evaluated string won't have its holes impact definite assignment, because we can't be sure that the expressions\nwere evaluated. Further, due to the way the proposal is written, upgrading to a new version of a library could change the\nsemantics of existing code, as the library author could introduce a new overload that the interpolated string prefers, introducing\nconditional evaluation of what used to be unconditionally-evaluated code. While library upgrades can always introduce behavior\nchanges in a user's code (introducing a new instance method that is preferred over an extension method, for example), this would\nbe expanding such concerns.\n\nWe considered whether to have some syntax marker to indicate that \"the interpolated string expression holes will be conditionally\nevaluated\", such as putting a `?` in the hole (like `$\"{?name}\"`). While this syntax calls out that conditional evaluation is\noccurring, we're concerned that it leans too far into making new language features obvious. We'd need to start shipping analyzers\nthat ensure that users are using this syntax where possible, and it could become another pitfall of \"make sure you add this syntax\nfor maximum performance.\"\n\nFinally, we looked at whether we could investigate a broader feature around lazily-evaluated arguments. Today, users often use\nlambdas to defer this type computation. We're concerned by building a feature like this on lambdas, however, because of the\nimplicit allocation cost here. If we make advances in this space later, we can look at incorporating those advances at that point,\nbut we feel that we can move forward with conditional evaluation at this point.\n\n#### Conclusion\n\nWe will have conditional evaluation of interpolated string holes without a special syntax for calling this out.\n\n###  `field` keyword\n\nhttps://github.com/dotnet/csharplang/issues/140\n\nWe looked at how the `field` identifier will be resolved inside a property, and what exactly will indicate to the compiler that the\nproperty should have a backing field generated for it. The proposal calls for resolving `field` to the backing field when there is\nno other identifier named that in scope. We thought about a few alternatives:\n\n* Could we make `field` _always_ a contextual keyword in property bodies, gated by target language version? We made a bigger break\nwith `record` type names, but it was a very different break. `record` was used as a type name, which are by-convention PascalCase\nin C# programs. Here, we'd be breaking `field` as an identifier, which is much more common and fits in with standard C# naming\npractices.\n* Could we use a `__` name? Identifiers with a `__` are reserved by C#, so we can use one without breaking anyone. However, `__`\nnames are not common, only used for things that aren't common practice in C# (such as `__makeref` or `__arglist`).\n* Could we take a page from VB's book, and introduce a `_PropName` identifier? While it still has a potential conflict with class\nfields, the conflict should be much smaller, and theoretically resolving the ambiguity could be as easy as deleting the class field\n(provided we get the naming right), whereas a class `field` identifier could be entirely unrelated to the current property.\n\n#### Conclusion\n\nWe'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.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-03-29.md",
    "content": "# C# Language Design Meeting for March 29th, 2021\n\n## Agenda\n\n1. [Parameterless struct constructors](#parameterless-struct-constructors)\n2. [AsyncMethodBuilder](#asyncmethodbuilder)\n\n## Quote of the Day\n\n- \"I told people to question my vague memory and now I'm upset that you did\"\n\n## Discussion\n\n### Parameterless struct constructors\n\nhttps://github.com/dotnet/csharplang/blob/struct-ctor-more/proposals/csharp-10.0/parameterless-struct-constructors.md\n\nToday, we took a look at open questions in this proposal.\n\n#### Field initializers and implicit constructors\n\nThe main question on our mind here is, what does this code print?\n\n```cs\n// Is this `default(S)`, or does `Field` have a value of 42?\nvar s = new S();\nSystem.Console.WriteLine(s.Field);\n\npublic struct S {\n    public int Field = 42;\n    \n    public S(int i)\n    {\n        // C# executes:\n        //     Field = 42\n    }\n}\n```\n\nThere are a few possibilities for what this can imply:\n\n1. There is an implicit parameterless constructor that runs the field initializer. The code sample would print 42.\n2. No implicit parameterless constructors are synthesized. We warn on the field initializer if an explicit parameterless constructor\nis not provided. The code sample would print 0.\n3. An implicit parameterless constructor is synthesized _when no other explicit constructors are provided_. The code sample would\nprint 0.\n\nThe complication here comes from the fact that `new S()` was and will continue to be legal, even when there is no parameterless\nconstructor. This differs from class types, which do not have an implicit parameterless constructor that would run such a field\ninitializer. Therefore, one way that we could look at the problem is under the lens of \"We've always had this constructor, it's\njust been omitted as an optimization\". By that rule, option 1 should be the tack we take. However, we are also concerned that some\nusers will have taken a dependency on that parameterless constructor meaning a 0-initialized struct.\n\nAnother complication was raised in conjunction with record struct primary constructors. In record classes today, we require that if\nthe record has a primary constructor, all other constructors must chain to it. This would mean that the parameterless constructor\nneeds to chain to the primary constructor, which wouldn't work for an implicit parameterless constructor. We could require that record\nstructs with field initializers and a primary constructor provide a parameterless constructor that chains, but that also brings up\nconcerns about nullable annotations of parameters. In C# today, we generally advise struct authors to annotate for typical use, not\nfor all the technical possibilities. That means that if users shouldn't be using a default struct, we advise that a reference field\ncould be annotated not null. That would interact poorly with a requirement to define the primary constructor here, as there could\nvery well be _no_ valid default to specify.\n\n##### Conclusion\n\nThe points raised today around interactions with primary constructors need more thought. We'll take this back for more workshopping,\nand bring it to LDM again later.\n\n#### Other conclusions\n\nWe also came to a couple other conclusions this session, affirming the proposed behavior of:\n\n* Definite assignment simplification: the proposed rules are accepted. Further general relaxation of definite assignment might be\ninteresting, but require a separate proposal.\n* Some of the language around how the C# compiler handles private and internal constructors today needs to be modified a bit to\nreflect more nuances, but we approve of the general goal: keep behavior unchanged.\n\n### AsyncMethodBuilder\n\nhttps://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/async-method-builders.md\n\nWe started today by questioning whether we can simplify this proposal a bit. Today, the proposal covers both a scoped version and\na single-method version. The scoped version is complicated, and has a number of downsides:\n\n* Diagnostic story is unclear. If the user thought they were applying the builder to all methods with a specific return type but\ndid it incorrectly for a subset of the locations, we have no good way to let them know they made an error.\n* Relatedly, a scoped version would need a good amount of IDE work to help users understand what builder type this method was actually\nusing.\n\nWhen 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\nthe runtime is interested in, is pooling. This usecase is unlikely to want module-wide application because pooling is potentially\nharmful for infrequently-used APIs, and so users would want to be more precise about which specific methods in a type are high\nusage and which are not. The other big use case we can see is builders that responsible for tracing. These builders could potentially\nbe wanted module-wide so that tracing could be added everywhere, but we are again worried about the diagnostic and user-info story\nfor this.\n\n#### Conclusion\n\nWe will remove the scoped version of this proposal for now, and use the existing `AsyncMethodBuilder` attribute on an individual method,\nlocal function, or lambda, to control the builder type for that function. If we hear demand for a module-scoped version in the future,\nwe can use a new attribute designed for that case and think about the diagnostic situation at that point.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-04-05.md",
    "content": "# C# Language Design Meeting for April 5th, 2021\n\n## Agenda\n\n1. [Interpolated string improvements](#interpolated-string-improvements)\n2. [Abstract statics in interfaces](#abstract-statics-in-interfaces)\n\n## Quote of the Day\n\n- \"Every time someone tells me they have a printer that works, I believe they're part of the conspiracy\"...\n\"So what I'm getting from this is that you've given up on your printer and are now printing at the office?\"\n\nNB: 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,\nin this instance).\n\n## Discussion\n\n### Interpolated string improvements\n\nhttps://github.com/dotnet/csharplang/issues/4487\n\nOur 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)\nto move forward.\n\n#### Create method shape\n\nWe adjusted the shape of the `Create` method from the initial proposal to facilitate some improvements:\n\n* In some cases, `out`ing a parameter with a reference type field can cause the GC to introduce a write barrier.\n* For the non-`bool` case, `Create` feels more natural.\n\nThis may be a micro-optimization, but given that this pattern is not intended to be user-written, but instead lowered to by the compiler,\nwe feel that it's worth it.\n\n##### Conclusion\n\nApproved.\n\n#### TryFormatX method shape\n\nThe proposal suggests that we should allow `TryFormatX` calls to either return `bool` or `void`, as some builders will want to stop formatting\nafter 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`\nisn't necessarily in-keeping with C# style, we will keep the single name for a few reasons:\n\n* Again, this pattern isn't intended to be directly consumed by the end user, they'll be writing interpolated strings that lower to this.\n* It's harder for API authors to mess up and mix `void`-returning and `bool`-returning `TryFormatX` methods, because you can't overload on\nreturn type.\n* It's easier to implement.\n\nWe 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\nmethod. A logger, for example, would return `false` from `Create` if the log level wasn't enabled, but the actual format calls will always succeed.\n\nWe also looked at ensuring that a single `TryFormatInterpolationHole` method with optional parameters for both alignment and format components can\nbe used with this pattern. As specified today, these parameters are not named so overload resolution can only look for signatures by parameter type.\nThis 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\nfor the alignment and format components (their names will be `alignment` and `format`, respectively). The first parameter will still be unnamed.\n\nAnother discussion point was on whether we should require builders to _always_ support all possible combinations of a format or alignment component\nbeing present. For some types (such as `ReadOnlySpan<T>`), we're imagining that such components would be just ignored by the builder, and it would\nbe interesting to just have that be a compile error instead of just being silently ignored at runtime. However, the ship on invalid format specifiers\nsailed a long time ago, and there is potential difficulty in making a good compile-time error experience for these scenarios. Thus, our recommendation\nis to always include overloads that support these specifiers, even when ignored at runtime.\n\n##### Conclusion\n\nAPI shape is approved. We will use named parameters for `alignment` and `format` parameters, as appropriate.\n\n#### Disposal\n\nFinally in interpolated string improvements, we looked at supporting disposal of builder types. Our decision that we will have conditional execution\nof 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\nbuilder acquired resources (such as renting from the `ArrayPool`), it has the potential to be lost if we do not wrap the builder (and potentially\nlarger 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\ncomplication 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\nor a type parameter constrained to an interface type that has an `abstract static Create` method, the actual runtime type could implement `IDisposable`\nthat 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\n(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\ntype 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\njust for `ref struct`s (as we do for regular `foreach`).\n\nEven the concept of disposal for these builder types might not be needed. The runtime is a bit leary of having `InterpolatedStringBuilder` be disposable,\nbecause 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\nthat tell users to avoid interpolated strings in methods because it will affect inlining decisions. We have some ideas on avoiding this for interpolated\nstrings 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\ntrying to engineer a solution to a problem that doesn't actually exist?\n\n##### Conclusion\n\nNo conclusion on this point today. A small group will examine this in more detail and make recommendations to the LDM based on evaluation.\n\n### Abstract statics in interfaces\n\nhttps://github.com/dotnet/csharplang/issues/4436\n\nWe looked at 2 major changes to the proposal today: allowing default implementations and changes to operator restrictions.\n\n#### Default implementations\n\nThe existing proposal specifically scopes default implementations of virtual statics in interfaces out because of concerns about runtime implementation\ncosts. 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\nparameter 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\nchange 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\nthat 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\nnot 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\ntype parameter, not on the interface.\n\nHowever, there are some serious usability concerns for this approach. A default implementation of a virtual static member cannot be inherited by any\nconcrete 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\nthe 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\ncan 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.\nFor example:\n\n```cs\ninterface I<T> where T : I<T>\n{\n    public static abstract bool operator ==(T t1, T t2);\n    public static virtual bool operator !=(T t1, T t2) => !(t1 == t2);\n    public void M() {}\n}\nclass C : I<C>\n{\n    public static bool operator ==(C c1, C c2) => ...;\n}\n\nC c = new C();\nc.M(); // M is not accessible\n((I)c).M(); // This works, however\n\n_ = c == c; // Fine: C implements ==\n_ = c != c; // Not fine: I.!= is a default implementation that C does not inherit. This method cannot be called.\n```\n\nThere 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,\nor reimplementing the operator on C, thereby removing the benefit of the default implementation in the first place. Neither of these are particularly appealing.\n\n##### Conclusion\n\nA smaller group will revisit this and decide whether it is useful. We are skeptical of it based on the above problems currently.\n\n#### Operator restrictions\n\nToday, interfaces are prohibited from implementing `==` or `!=`, and from appearing in user-defined conversion operators. We have a long history of this, mainly\nbecause with interfaces there is always the change that the underlying type actually implements the interface at runtime, and the language should always prefer\nbuilt-in conversions to user-defined conversions. However, these operators cannot actually be accessed when the user only has an instance of the interface, they\ncan only be accessed when using a concrete derived type or a type parameter constrained to the interface type. This addresses our concerns about interface\nimplementation at runtime, and conversions from types defined in interfaces is particularly useful for numeric contexts such as being able to allow `T t = 1;`\nbecause `T` is constrained to an interface that has a user-defined conversion from integers.\n\n##### Conclusion\n\nLifting these restrictions is approved.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-04-07.md",
    "content": "# C# Language Design Meeting for April 7th, 2021\n\n## Agenda\n\nMVP-nominated session agenda\n\n1. [Abstract statics methods](#abstract-statics-methods)\n2. [Making other language literals easier](#making-other-language-literals-easier)\n3. [Expression trees](#expression-trees)\n4. [Metaprogramming](#metaprogramming)\n5. [Cost-free delegates and LINQ](#cost-free-delegates-and-linq)\n6. [Readonly locals and parameters](#readonly-locals-and-parameters)\n7. [Global usings](#global-usings)\n8. [Mixed-language projects](#mixed-language-projects)\n9. [Discriminated unions](#discriminated-unions)\n\n## Quote of the Day\n\n- \"Cats are the superior pet\" - followed by a lot of discussion that isn't relevant, as your note taker is a cat person\n\n## Discussion\n\nToday we held a more informal LDM session with Microsoft MVPs, where we selected an agenda from their suggestions and a brief discussion\non our thoughts around the topic, as well as getting their impressions and potential concerns on the topic.\n\n### Abstract statics method\n\nOne 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\nparticularly help with abstracting construction scenarios. There are also likely cases in Objective-C and Swift interop code that will be\nmade simpler with this feature, which we hadn't yet looked at as a possible application for this. We also briefly discussed the issue of\nmultiple inheritance with default implementations of abstract methods, but no new problems arise from abstract statics that did not already\nexist with default implementations of instance interface members.\n\n### Making other language literals easier\n\nA common complaint in C# is when users need to include literals from other languages such as XML or JSON, or even C# itself (particularly\nevident in source generators). While we aren't looking for language-specific literal types, we are looking at a more general \"raw string\"\nproposal that will allow more customization of escapes inside the string, which will address the problems around copying and pasting text\nthat includes quote marks in it.\n\n### Expression trees\n\nSome questions were raised on why we haven't updated expression trees since initial release. Our concerns here are around expression tree\nconsumers: any update we make to start including new things in the tree will likely break consumers of expression trees. This starts to get\nparticularly gnarly when we consider libraries that users want to ship and support on older target frameworks, or when newer code wants to\ndepend 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\nguardrails in these tricky scenarios to move this forward, and we don't have one yet.\n\n### Metaprogramming\n\nQuestions here centered around 2 points. First was ease of use, such as being able to define a source generator in the same project that\nconsumes 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\ngeneral ergonomics, and this will be one of the areas we'll investigate. There are some particularly hard questions around running a source\ngenerator when the project doesn't compile.\n\nThe second point is in source replacement. We are very unsure about this feature: in particular, the IDE experience isn't great. We've\nalready received occasional bugs from users about IDE experiences with existing code-rewriting solutions such as Fody (such as debuggers\nappearing to misbehave), and we have additional concerns about the perf implications of such generators.\n\n### Cost-free delegates and LINQ\n\nA number of scenarios would like lambdas to be more efficient. In particular, some applications of LINQ should be able to be cost-free, as\nthe results are immediately used and don't need to allocate closures. However, we don't have the language facilities to do this today. If\nwe add the ability for ref structs to implement interfaces and be used in generics, we could get this feature, but usage would be extremely\nunergonomic due to the inability to infer generics parameters for some of the cases involved. To really make a feature like this usable, we\nwould also want associated/existential types to remove those uninferrable generic parameters.\n\n### Readonly locals and parameters\n\nThis has been one of the ultimate examples of bikeshedding. We have an obvious syntax in `readonly`, but we are concerned that the effort\nthe user would put into putting `readonly` everywhere doesn't match the actual benefit they would derive from doing so. C#'s past a\nmutable-first language is definitely a liability with this issue.\n\n### Global usings\n\nWe 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\ncan do a better tooling experience in source, and we think that it will compose well with using aliases to enable other much-requested\nfeatures. It does make multiple-project aliases a bit more difficult, as the user will have to include the file from multiple projects,\nbut we think it's a worthwhile tradeoff. We also looked at global usings nested inside a namespace. We're concerned about the user experience\nfor 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.\n\n### Mixed-language projects\n\nWhile this is an interesting idea, the compiler support here is somewhat scary. Additionally, VB.NET and C# have a number of very subtle\ndifferences that could very easily lead to developer confusion. Overall, we're not pursuing this area.\n\n### Discriminated unions\n\nWhile 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\nleft 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\nwhat the MVPs are looking to get out of the feature:\n\n* Exhaustiveness in pattern matching\n* Brevity in declaration\n* Either-or parameters to methods\n"
  },
  {
    "path": "meetings/2021/LDM-2021-04-12.md",
    "content": "# C# Language Design Meeting for April 12th, 2021\n\n## Agenda\n\n1. [List patterns](#list-patterns)\n2. [Lambda improvements](#lambda-improvements)\n\n## Quote(s) of the Day\n\n- \"If the runtime team jumped off a bridge, would you [redacted]?\" \"If it would make my code faster\"\n- \"Quote of the day may need to involve corn fields\"\n\n## Discussion\n\n### List patterns\n\nhttps://github.com/dotnet/csharplang/issues/3435\n\nToday we looked over the changes around supporting `IEnumerable` types in list patterns, and how slice patterns will affect them. While\nwe overall like the lowering that has been proposed, we would like to continue to look at possible optimizations around using framework\napis such as `TryGetNonEnumeratedCount`. This will allow the framework to do all the grungy bookkeeping to make this quick for cases when\nthe `IEnumerable` is actually a countable type, or one of a certain type of LINQ expression that is countable under the hood (such as a\n`Select` over an array). The runtime is also planning on adding a `Take` method that does similar bookkeeping with index and range, falling\nback to buffering if it has to.\n\nWe also considered to what extent we should allow sub-patterns under a slice pattern. The obvious use case is a declaration pattern for the\nslice, but as worded today the syntax will allow any arbitrary sub-pattern on the slice. After discussion, while we think that the main use\ncase is just declaration patterns, we see no reason to disallow other nested sub-patterns. It should compose well, and while 99% of users\nwill never need it, it could be helpful for that 1%.\n\nThe other question with slice patterns is whether to allow nested sub-patterns for `IEnumerable` as well as for sliceable types. If we do\nallow this, it would mean treating `IEnumerable` specially here, while indexers and slicers cannot be used in the general case. Given\nthis, 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\ncan look at considering extension methods as a part of general sliceability, which, if combined with renaming that `Take` method from the\nframework to `Slice` before it ships, would enable the feature in a much more general fashion.\n\n#### Conclusions\n\n* Lowering is generally approved.\n* Slice sub-patterns will allow any pattern, so long as the input type to the list pattern is sliceable.\n* Making `IEnumerable` sliceable is orthogonal.\n\n### Lambda improvements\n\nhttps://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/lambda-improvements.md\n\nAfter 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\nside of the parameter list. This makes the syntax analogous to our other signature declarations in C#, looking like an unnamed version of a\nlocal 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\nclasses/record classes, and declaration forms/pattern forms. While we do have `Func` and `delegate*` as types that put the return last, we are\nat least consistent within type forms and within signature declaration forms. At this point, the only parity we are missing between lambdas\nand local functions is the ability to declare generic type parameters, but those won't be useful on lambda expressions unless we add\nhigher-kinded types to the language.\n\nWe also looked at requirements around return type specification: do we want to require that, if a return type is specified, parameter types must\nbe 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,\nwe 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\nrequiring this would lack symmetry. It's also very possible that the return type of a lambda could be uninferrable, while the parameter types\nare, 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\ntype to be specified without parameter types.\n\nWe 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\nwants 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\nto disambiguate between making the lambda `async`. Given this, we support making it required to escape the type name in the return type.\n\nThe changes around attributes in the proposal raised no concerns. These changes were requiring that, if an attribute is used, parentheses must\nbe used for the parameter list, and the rules around how the compiler will disambiguate conditional array accesses and dictionary initializers.\n\nFinally, we noted the possibility for a breaking change if single-method method groups are given a natural type with the following code:\n\n```cs\nusing System;\n\nvar c = new C();\nD.M(c.MyMethod);\n\n// Outputs \"Extension\" today, would print Instance if c.MyMethod had a natural type.\n\nclass C\n{\n    public void MyMethod() { Console.WriteLine(\"Instance\"); }\n}\n\nstatic class CExt\n{\n    public static void MyMethod(this C c, string s) { Console.WriteLine(\"Extension\"); }\n}\n\nclass D\n{ \n    public static void M(Delegate d) { d.DynamicInvoke(); }\n    public static void M(Action<string> a) { a(\"\"); }\n}\n```\n\nWe'll need to investigate to see if we can avoid this change, or if we're ok with the potential break.\n\n#### Conclusions\n\n* Return type before the parameter list is approved, does not require parameter types to be specified.\n* `async` as a return type name should require escapes.\n* Attribute changes are approved.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-04-14.md",
    "content": "# C# Language Design Meeting for April 14th, 2021\n\n## Agenda\n\n1. [Shadowing in record types](#shadowing-in-record-types)\n2. [`field` keyword](#field-keyword)\n3. [Improved interpolated strings](#improved-interpolated-strings)\n\n## Quote of the Day\n\n- \"We're taking my sarcastic suggestion\"\n\n## Discussion\n\n### Shadowing in record types\n\nIn 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\nissue with currently-legal C# 9 code like this:\n\n```cs\nusing System;\n\nvar c = new C(2);\nc.Deconstruct(out var x);\nConsole.WriteLine(x); // Prints 1\n\npublic record Base \n{\n    public int X { get; set; } = 1;\n}\npublic record C(int X) : Base\n{\n    public new int X = X;\n}\n```\n\nIn 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\nC# 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\nin 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.\n\n#### Conclusion\n\nMake this code an error in C# 9. In C# 10, `Deconstruct` will refer to `C.X`.\n\n### `field` keyword\n\nhttps://github.com/dotnet/csharplang/issues/140\n\nAfter our [last](LDM-2021-03-24.md#field-keyword) meeting on partially-implemented auto-properties, we had decided to look more deeply at a\nfew alternate syntaxes to see if we could avoid the need to make `field` a contextual keyword. While some of the suggestions would take less\ncompiler 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\nfeel is an inferior syntax. As part of this work, we can consider making the public Roslyn APIs around backing fields more consistent. Today,\nthere are differences between what `GetMembers()` will return for auto-properties vs field-like events, and in order to implement the `field`\nkeyword we will likely need to take the same strategy as we did with field-like events to avoid circularities. We will also consider standardizing\nthe 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\n`field` identifiers in properties that do not correspond to a backing field with either `@` or `this.`, as appropriate.\n\n#### Conclusions\n\nWe 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\nambiguous.\n\n### Improved interpolated strings\n\nhttps://github.com/dotnet/csharplang/issues/4487\n\nToday, 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\nsyntax needed on the builder? We think this will be important for both safety and optimal performance in some framework builders: if the builder\nis 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,\nwhich will help ensure things aren't unnecessarily rooted. We already have a good precedent for this in extension methods: struct types are allowed\nto 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.\n\nWe also took a look at out-of-order parameter evaluation. Our current proposal is that a builder can be annotated with an\n`InterpolatedStringBuilderArgument` attribute, and that the compiler will look at the names in the attribute to determine which parameters to pass\nto 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\nliteral and the interpolated string is being lowered using the `bool`-returning `Append` methods, as we will have to evaluate the trailing parameter\nbefore the contents of the interpolated string. This would break lexical ordering, which is likely to be extremely confusing and have detrimental\neffects on definite assignment, as well as user understanding. However, in order for maximum compatibility with existing API signatures, this would\nhave to be supported, as there existing API shapes (such as `Utf8Formatter`) that put the location the interpolated string would go before some of\nthe arguments that the builder will need (in the case of `Utf8Formatter`, their signatures are the value to be formatted, then the destination span).\nWe could potentially make this dependent on the `Append` calls used the by the builder: `void`-returning `Append`s would allow arguments after the\nbuilder, and `bool`-returning `Append`s would not. This would allow the compiler to evaluate the interpolation holes ahead of time and preserve\nlexical ordering. However, it has its own downsides of adding confusion to the builder pattern, and might be more difficult to tool. Further discussion\non this topic revealed that we need to revisit the whole question of conditional execution in order to make a decision here.\n\n#### Conclusion\n\n* Ref parameters are approved, using the same rules as extension method `this` parameters.\n* We will take the Monday LDM to resolve the questions around conditional execution and out-of-order parameter execution (and hopefully all other\nopen questions on this proposal).\n"
  },
  {
    "path": "meetings/2021/LDM-2021-04-19.md",
    "content": "# C# Language Design Meeting for April 19th, 2021\n\n## Agenda\n\n1. [Improved interpolated strings](#improved-interpolated-strings)\n\n## Quote of the Day\n\n- \"I'm glad you had a stomachache here so I don't have to\"\n\n## Discussion\n\n### Improved interpolated strings\n\nhttps://github.com/dotnet/csharplang/issues/4487\n\nToday, we spent the full meeting digging into the pros and cons of conditional evaluation of interpolation holes, to ensure that we feel\ncomfortable with the changes doing so will bring. The real challenge here is that conditional evaluation of interpolation holes will break\nwith current mental models of interpolated strings: today, interpolated string holes are unconditionally evaluated in lexical order, and\nthe way the proposal is designed makes it possible for a library update to change whether the expressions in an interpolation hole is\nevaluated or not. While library updates can always bring changes in behavior, this is the type of change that is currently only possible\nby a library adding the `Conditional` attribute onto a method or changing the type of an exception being thrown, causing a catch handler\nto no longer be hit. Adding a new instance method that is preferred over an extension method is similar, but except in rare cases involving\nuser-defined conversions this can't actually affect the expressions in the method body itself.\n\nIf we proceed with conditional evaluation, user education will be a key component. The proposal does not involve conditional evaluation when\nthe interpolated string literal is used directly as a `string`, but other types can introduce this. If a user is confused by this behavior,\nwe 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\na specific syntax to enable conditional interpolation hole evaluation, something like `$?\"{ConditionallyEvaluated()}\"`. With such a syntax,\nwe would never conditionally evaluate the holes unless the string were marked with `$?` or `@$?`. However, this immediately becomes a concern\nfor libraries that want to introduce conditional evaluation: presumably they were making that decision for a good reason. A logging library\nwould 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\nfeature to ensure their customers are actually using it.\n\nWe also considered the benefits that partial evaluation gives the user. An important goal for C# features is that users don't adopt the\nfeature then immediately switch to something else because it introduces performance issues. Patterns are a good example of doing this right:\nthe 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\ninterpolated strings, on the other hand, do _not_ do this today. They box value types, don't work with spans, and generate array garbage that\ncan't be elided. We want interpolated strings to be better: using the language feature should generate code that is just as performant as\nyou can get manually today. Conditional evaluation is a big part of this: both with the up front check, and with the intervening checks on\neach `Append` call, we can ensure that a simple line of C# generates code that is as good as manual checks.\n\nA good analogy to think about for concerns about conditional evaluation is in `struct`s: if C# were to introduce value types today, would\nwe 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\nand 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\nlibrary upgrade today. New instance methods can be introduced that cause extension methods to longer be chosen, libraries can introduce new\nconversions, new exceptions can be thrown/existing exceptions can be no longer thrown. While is another change that can happen, we don't think\nit's substantially different enough to warrant concern.\n\n#### Conclusion\n\nWe accept conditional evaluation of interpolation holes as written in the spec.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-04-21.md",
    "content": "# C# Language Design Meeting for April 21st, 2021\n\n## Agenda\n\n1. [Inferred types for lambdas and method groups](#inferred-types-for-lambdas-and-method-groups)\n2. [Improved interpolated strings](#improved-interpolated-strings)\n\n## Quote of the Day\n\n- \"And then we will open Pandora's box\"\n\n## Discussion\n\n### Inferred types for lambdas and method groups\n\nhttps://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/lambda-improvements.md  \nhttps://github.com/dotnet/csharplang/issues/4674\n\nFurther implementation work has revealed a few potential breaking changes in giving lambdas and method groups a natural type (linked in the issue\nabove). 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\nbe observed in extension method resolution (adding new ones in a closer scope or adding an instance method that is preferred), these would be a\ncase of the language actually changing the results of overload resolution for the same inputs. We have a few ideas for how to approach this:\n\n1. 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.\n2. Always prefer a target-type for method groups and lambda expressions. This idea, while sounding simple, is quite complex implementation-wise.\nThe C# type inference and overload resolution algorithms are very much tied to having a natural type for an expression, and flowing that information\nthrough 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\nprocess again. This would add a significant cost complexity to an already-expensive part of the compilation process, and while it might work it\nwill be an exponentially harder problem every time we want to do something else like this.\n3. Make natural types for lambdas and method groups opt-in. This would be through some sort of syntax gesture, such as:\n    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\n    that would forever need to be explained to users to \"use C# 10 please\".\n    2. Only lambdas with return types (indicating new feature uptake) would have a natural type. This would severely hamper the scenarios our\n    partner teams are interested in: most of the time, their return types should be inferred, and it will not support method groups.\n4. Only infer a natural type when converting to `System.Delegate` or `System.MulticastDelegate`. This technically still does have the chance of\nbreaking scenarios, but the breaks are significantly smaller. However, this would result in the unfortunate consequence that only non-generic\ndelegate types can cause natural types to be inferred, which feels like a pre-generics solution to the problem.\n\nWhile accepting a break here could potentially be big, it's important to note that this particular scenario is actually quite fragile today. In\neither of the code samples, simply extracting the lambda or method group to a local variable will cause overload resolution to pick the same\noverload that giving the lambda a natural type would. This is because the local variable will have a natural type itself. It seems relatively\nlikely that the only users intentionally taking advantage of this \"feature\" are creating extension methods that just call the original method\nwith the delegate, using the extension method as a source of a target-type for the lambda expression.\n\nWe 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\nVS 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\nit 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\nenough of a signal during this preview to know just how aggressive we can be here.\n\n#### Conclusion\n\nWe will tentatively accept the breaking change to overload resolution. Previews will be used to determine if we need to revisit this decision.\n\n### Improved interpolated strings\n\nhttps://github.com/dotnet/csharplang/issues/4487\n\nWe 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\ncurrent context. There is potential here to break lexical ordering of expressions if we allow arguments to the builder's `Create` method to come\nafter the builder itself in the argument list. While a possible model for thinking of interpolation holes is lambda expressions, where the holes\nare either not evaluated or evaluated at a later point from where they were written, these holes can potentially have definite assignment impacts\non the current method body. This is entirely different from other forms of deferred execution in C#, and we're concerned with the implication.\nAfter discussion, we agreed on requiring lexical ordering to be respected: if a parameter is an argument to the `Create` method of the builder type,\nit must come before the interpolated string. That error will be reported at the invocation site, and it should be affected by the true lexical\norder of the invocation. Named parameters can be used to reorder evaluation, so we should error if named parameter use results in an argument being\nevaluated after the interpolated string that needs it. We will implement a warning at the method declaration if the signature of the method requires\nnamed parameters to need to be used at the call site.\n\nWe also looked at the proposal around allowing interpolated strings to be \"seen\" through conversion expressions and through binary addition expressions.\nBinary addition being proposed resulted from prototyping work in the runtime to use the builder, while the conversion proposal was a logical next step.\nAfter discussion, we don't think that the use case of needing to disambiguate between two overloads with different builder types and otherwise identical\nsignatures 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\nhave an ask for `IFormattable` or `FormattableString` here.\n\n#### Conclusions\n\nLexical ordering should be respected, and seeing interpolated strings through binary addition expressions will be supported.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-04-28.md",
    "content": "# C# Language Design Meeting for April 28th, 2021\n\n## Agenda\n\n1. [Open questions in record and parameterless structs](#open-questions-in-record-and-parameterless-structs)\n2. [Improved interpolated strings](#improved-interpolated-strings)\n\n## Quote of the Day\n\n- \"I was kinda hoping you'd fight me on this\"\n\n## Discussion\n\n### Open questions in record and parameterless structs\n\nhttps://github.com/dotnet/csharplang/blob/struct-ctor-more/proposals/csharp-10.0/parameterless-struct-constructors.md  \nhttps://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/record-structs.md\n\n#### Initializers with explicit constructors\n\nThe first thing we need to resolve today is a question around our handling of field initializers, both in the presence of an\nexplicitly-declared constructor(s), and when no constructors are present. There's two parts to this question:\n\n1. Should we synthesize a constructor to run the field initializer? and\n2. If we don't, should we warn the user that their field initializer won't be run?\n\nWe feel that a simple rule here would be to mirror the observed behavior with reference types: if there is no explicit constructor\nfor a struct type, we will synthesize that constructor. If that constructor happens to be empty (as it would be today in a\nconstructorless struct type because field initializers aren't yet supported) we optimize that constructor away. If a constructor\nis explicitly declared, we will not synthesize any constructor for the type, and field initializers will not be run by `new S()`\nunless the parameterless constructor is also explicitly declared. This does have a potential pit of failure where users would\nexpect the parameterless constructor to run the field initializers, but synthesizing a parameterless constructor would have bad\nknock-on effects for record structs with a primary constructor: what would the parameterless constructor do there? It doesn't\nhave anything it can call the primary constructor with, and would result in confusing semantics. To address this potential issue,\nwe think there is room for a warning wave dedicated to using `new S()`, when `S` does not have a parameterless constructor. There\nwill be some holes in this, particularly around generics: `struct` today implies `new()`, and we're concerned about how breaking\nthe change would be if we tried to make the warning apply to everywhere that a parameterless struct was substituted for a type\nparameter constrained to `struct`. We would also have to take another language feature to enable `where T : struct, new()`, which\nisn't allowed today. If there is future appetite for introducing another warning wave to cover the generic hole, we can look at\nit at that point.\n\n##### Conclusion\n\nWe will only synthesize a constructor when the user does not explicitly declare one. We will consider a warning wave when using\n`new` on a struct that does not have a parameterless constructor and also has an explicit constructor with parameters.\n\n#### Record struct primary constructors\n\nNext, we looked at how the parameterless struct constructor feature will interact with record primary constructors. The rule we\ndecided for the first question ends up making the decisions very simple here:\n\n1. Parameterless primary constructors are allowed on struct types.\n2. The rules for whether an explicit constructor needs to call the primary constructor are the same as in record class types. This\napplies to an explicit primary constructor too, just like in record class types.\n\n##### Conclusion\n\nUse the above rules.\n\n#### Generating the Equals method with `in`\n\nWe looked at a potential optimization around the `Equals` method, where we could generate it with an `in` parameter, instead of\nwith a by-value parameter. This could help scenarios with large struct types get better codegen. However, when we would want to do\nthis is a very complicated heuristic. For structs smaller than machine pointer size, it is usually faster to pass by value. This\ngets even more complex when considering types that are passed in non-standard registers, such as vectorized code. We don't think\nthere's a generalized way to do this heuristic. Instead, we just need to make sure that the user can perform this optimization, if\nthey want to.\n\n##### Conclusion\n\nWe won't attempt to be smart here. Users can provider their more customized equality implementation if they so choose.\n\n#### `readonly` Equality and GetHashCode\n\nFinally in record structs, we looked at automatically marking the `Equals` and `GetHashCode` methods as `readonly`, if the all the\nfields they use for the calculation are also all `readonly`. While this would be technically feasible, we're not sure what the\nscenario for this is, beyond just marking the entire struct `readonly`. At that point, every method would be readonly, including\nthe ones we synthesize.\n\n##### Conclusion\n\nWe don't do anything smart here. Users can just mark the struct as `readonly`.\n\n### Improved interpolated strings\n\nhttps://github.com/dotnet/csharplang/issues/4487\n\nWe're getting close the end of open questions in this proposal. We looked at 2 today:\n\n#### Confirming `InterpolatedStringBuilderAttribute`\n\nAn internal discussion on simplifying the conversion rules resulted in a proposal that we only look for the presence of a specific\nattribute on a type to determine if there exists a conversion from an interpolated string literal to the type. This simplification\nresults in much cleaner semantics: the presence of various methods on the builder type no longer plays into whether the conversion\nexists, only whether conversion is valid. This will help users get understandable errors that don't silently fall back to\nstring-based overloads when a builder doesn't have the right set of `Append` methods to lower the interpolated string.\n\nWe also looked at whether we should control the final codegen based on a property on the attribute: we initially proposed conditional\nevaluation could be controlled by the attribute. This would potentially let the compiler change the behavior of when expressions in\ninterpolation holes are evaluated: up front, or in line the `Append` calls. However, the logic for determining the codegen is not\nas simple as one property: the `Append` calls can potentially return `bool`s to stop evaluation, and the `Create` method can\npotentially `out` a parameter to control this as well. There are valid scenarios for all 4 possibilities here, so a switch that only\nallows either all conditional or no conditional isn't a good option. It's also complex because this would be a library author making\na 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\nthen.\n\n##### Conclusion\n\nUsing the attribute is accepted. The `Append` and `Create` method signatures will drive the lowering process.\n\n#### Specific extensions for structured logging\n\nFinally today, we looked at a question around including specific syntax to support structured logging. [Message templates](https://messagetemplates.org/)\nare a well-known structured logging format that most of the biggest .NET logging frameworks support, and as we want these libraries\nto consider using the improved interpolated strings feature, we looked to see if we can include specific syntax to help encourage\nthis. After some initial discussion, our general sentiment is that this feels too narrow. An example syntax we considered is\n`$\"{myExpression#structureName,alignment:format}\"`, and while this would work for the scenario, it wouldn't be a meaningful improvement\nover simply using a tuple expression: `$\"{(\"structureName\", myExpression),alignment:format}\"`. It is possible to construct interpolated\nstring builders that only accept tuples of `string` and `T` in their interpolation holes, and with the other adjustments we made today\nthere should be good diagnostics for such cases. Further restrictions can be imposed via analyzers, as is possible today. While a more\ngeneral string templating system could be interesting, we think that this is a bit too narrow of a focus for a language feature today.\n\n##### Conclusion\n\nWe won't pursue specific structured syntax at this time.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-05-03.md",
    "content": "# C# Language Design Meeting for May 3rd, 2021\n\n## Agenda\n\n1. [Improved interpolated strings](#improved-interpolated-strings)\n2. [Open questions in record structs](#open-questions-in-record-structs)\n\n## Quote of the Day\n\n- \"You all have a special way of working\"\n\n## Discussion\n\n### Improved interpolated strings\n\nhttps://github.com/dotnet/csharplang/issues/4487\n\nToday, we got through the last of the open questions around the improved interpolated strings feature proposal.\n\n#### `Create` vs `.ctor`\n\nThe first open question is around using the `Create` method instead of a constructor call. The spec today uses a static `Create` method as\nan abstraction, to allow a hypothetical builder type to pool reference types in a static context, rather than being forced to return a `new`\ninstance on every builder creation. However, while this is a nice abstraction, we don't know of any proposed builder types that would take\nadvantage of this feature, and there are real codegen benefits to using a constructor instead. If we later come across a use case that would\nlike a static `Create` method instead, we can also add it later by using a switch on the attribute.\n\n##### Conclusion\n\nFor better codegen, we will go with a single method of creation, a constructor, not a `Create` method.\n\n#### Converting regular strings to builder types\n\nWe could consider any `string` value as being convertible to a builder type automatically via the builder pattern, which is the trivial case\nof `value.Length` number of characters with zero interpolation holes. If we were to do this, it would be in the interest of consistency: a\nuser could more readily reason about how all string types will interact with an API. However, we do already have a mechanism in the language\nto enable this: implicit user-defined conversions. Pushing a string through the standard builder pattern will likely be worse for performance\nthan what an API-author would write in an implicit conversion, and user-defined conversions already have well-defined semantics and impacts\non overload resolution.\n\n##### Conclusion\n\nRejected. If an API author wants string to be convertible to their builders, they can use a user-defined conversion.\n\n#### `ref struct` builder types in `async` contexts\n\nToday, `ref struct` types are generally forbbiden in `async` contexts. This is because `await` expressions can occur in any subexpression, and\nwe have not formalized rules around ensuring that a `ref struct` variable does not cross an `await` boundary. In order to enable `ref struct`\nbuilder 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\nby avoiding this: already today, developers need to choose between using a `ref struct`, and allowing usage in `async` contexts. While we would\nbe interested in general rules here, we don't think we should do anything special with regard to interpolated strings builder types. If we enable\nit in general, interpolated string builders will naturally come along for the ride.\n\n##### Conclusion\n\nWe will treat interpolated string builder usage as any other usage of a `ref struct` in `async` methods (today, that means disallowed).\n\n### Open questions in record structs\n\n#### Implementing `ISpanFormattable`\n\nThe BCL is adding a new interface for .NET 6, `ISpanFormattable`, which allows types to be formatted directly into a span, rather than having to\ncreate a separate string instance. One immediate thought we have is why are records (struct or class) special here? We often think of records as\nbeing 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.\nThis is important because it does impact public API: new overloads of `PrintMembers` will need to be implemented, and how this will interact with\nthe existing `PrintMembers` method that takes a `StringBuilder` is unclear. We also don't have a clear scenario here: `ToString()` in records is\nmainly focused around debugging and logging scenarios. While performance is a nice to have here, it's not an overridding concern, and users who\nwant to actually use `ToString()` to do more important work can provide their own implementation, and `ISpanFormattable` with it. They can handle\nthe problems around interop with existing APIs by simply not using those APIs, which will keep the considerations simpler for them.\n\n##### Conclusion\n\nRejected.\n\n#### Using `InterpolatedStringBuilder` in record formatting\n\nWe could potentially optimize the implementation of `ToString()` by using `InterpolatedStringBuilder` as the string-building mechanism, rather\nthan `StringBuilder`. Unfortunately, this again runs into the problem of needing to interop with existing code, which unfortunately limits our\noptions here. Without a clear scenario to try and solve, we don't think this is worth it.\n\n##### Conclusion\n\nRejected.\n\n#### Passing an `IFormatProvider`\n\nWe could potentially generate an overload of `ToString` that takes an `IFormatProvider` and passes it to nested contexts. This again runs the\nquestion 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\nprovider to a nested type, as there is no standardized `ToString(IFormatProvider)` method on all types. If a user wants to have formatted\nstrings in their records, they presumably are providing their own implementation anyway, so we don't feel this is appropriate.\n\n##### Conclusion\n\nRejected.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-05-10.md",
    "content": "# C# Language Design Meeting for May 10th, 2021\n\n## Agenda\n\n1. [Lambda improvements](#lambda-improvements)\n\n## Quote of the Day\n\n- \"I'll allow it\"\n\n## Discussion\n\n### Lambda improvements\n\n#### Lambda natural types in unconstrained scenarios\n\nThere are a few related open questions around how we handle lambda expressions and method groups in unconstrained scenarios. These\nare scenarios such as:\n\n```cs\nvar a = (int x) => x; // What is the type of A?\n\nvoid M1<T>(T t);\nM1((int x) => x); // What is the type of T?\n\nvoid M2(object o);\nM2((int x) => x); // What is the type of the expression? ie, o.GetType() returns what?\n```\n\nThese 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\nstifle later development around value delegates (if we even do such a feature). In C# today, we have 3 function types:\n\n* Delegate types that inherit from `System.Delegate`.\n* Expression tree types that inherit from `System.Linq.Expressions.**Expression`.\n* Function pointer types.\n\nAll of these types support conversions from some subset of method groups or lambdas, and none is currently privileged above another.\nOverloads between these types are considered ambiguous, and users must explicitly include information that tells the compiler what\ntype of function type to use, such as by giving a target type. If we allow `var`, conversions to `object`, and/or unconstrained generic\ntype inference to work, we would be setting in stone what the \"default\" function type in C# is. This would be particularly noticeable\nif our future selves introduced a form of lightweight delegate types and wanted to make them the default in various forms of overload\nresolution. We are doing analogous work with interpolated strings currently, but interpolated strings are a much smaller section of\nthe language than lambda expressions, and lambda irregularities are potentially much more noticeable.\n\nWe could protect our future selves here by making the spec more restrictive: Do not allow lambdas/method groups to be converted to\nunconstrained contexts. This would mean no `var`, no unconstrained type parameters, and no conversion to `object`. We would only infer\nwhen there was information that we could use to inform the compiler as to which type of function type to use: conversion to just\n`System.Delegate` would be fine, for example, because we know that the delegate type version was being chosen. While this would protect\nthe ability to introduce a value delegate type later and make it the default, we see some potential usability concerns with making\nsuch a delegate type the default. At this point, we believe such a delegate type would be based on ref structs, and making `var`\ndeclare these types would be minefield for async and other existing scenarios. Using such types by default in generic inference would\nhave similar issues around ref struct safety rules. And finally, if such a type were converted to `object`, it would by necessity need\nto be boxed somewhere, obviating the point of using a lightweight value delegate type in the first place. Given these concerns, we\nbelieve that we would just be protecting our ability to make the same decision later, and that another function type would not be a\ngood \"default\".\n\n##### Conclusion\n\nWe allow inferring a natural type for a lambda or method group in unconstrained scenarios, inferring Action/Func/synthesized delegate\ntype, as appropriate.\n\n#### Type inference\n\nWe 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\nconstraints to determine whether it should be inferred to be a Delegate or an Expression.\n\n##### Conclusion\n\nAccepted, with the additional step around constraints.\n\n#### Direct invocation\n\nFinally today, we looked at supporting direct invocation of lambda expressions. This is somewhat related to the\n[first topic](#lambda-natural-types-in-unconstrained-scenarios), but could be implemented even if we chose to do the restrictive version\nof that issue because this feature would not require us to actually choose a final function type for the lambda expression. We could\njust 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\nimportant driving scenario behind this feature: technically it could be used as a form of statement expression, but it doesn't feel like\na good solution to that problem. The main thing we want to make sure works is regularity with other inferred contexts:\n\n```cs\n// If this works\nvar zeroF = (int x) => x;\nvar zero = zeroF(0);\n\n// This should also work\nvar zero = ((int x) => x)(0);\n\n// But this wouldn't work with var, so is it fine to have not work here?\nvar zero = (x => x)(0);\n```\n\n##### Conclusion\n\nWe 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\nmore formal specification for approval.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-05-12.md",
    "content": "# C# Language Design Meeting for May 12th, 2021\n\n## Agenda\n\n1. [Experimental attribute](#experimental-attribute)\n2. [Simple C# programs](#simple-c-programs)\n\n## Quote of the Day\n\n- \"I've always felt the shotput with the Rubik's Cube should be part of the Olympics\"\n\n## Discussion\n\nToday 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.\n\n### Experimental attribute\n\nhttps://github.com/dotnet/designs/blob/main/accepted/2021/preview-features/preview-features.md\n\nThe first proposal we looked at is the design the runtime team has been working on around preview features. The C# compiler has shipped\npreview features in the compiler ahead of language releases before, but this hasn't been very granular, and we've never shipped a version\nof the runtime (particularly not an LTS!) where some parts of the runtime and language features built on top are actually still experimental.\nSupport stories get complicated, particularly when you start mixing installations of LTS versions of .NET 6 and .NET 7 on the same machine.\nFor example, we'll be shipping a preview of abstract static members in interfaces in .NET 6, but this implementation will _always_ be a\npreview. 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\npoint would no longer consider abstract statics to be a preview language feature, even if the project itself is targetting .NET 6. To solve\nthis, the runtime will introduce a new attribute, detailed in the preview feature proposal, which marks APIs and elements of RuntimeFeature\nthat should be considered preview in this version of the runtime, and then require that the consuming library be marked preview itself.\nWhere this requirement comes from is one of the open questions in this meeting: should it come from an analyzer or from the compiler itself?\n\nThe analyzer approach is initially attractive because it is easier to implement. Roslyn's analyzer infrastructure, particularly with the\ninvestments around both the symbol analyzer model and IOperation, means that it is possible to implement this analyzer almost entirely\nlanguage-independently, while a compiler feature would have be implemented in each compiler separately. It is also significantly easier to\nmaintain an analyzer: turning off analyzer errors is possible for false-positives while bugs are patched, while compiler errors are impossible\nto disable. However, this flexibility does come with downsides: it's possible to disable the analyzer for _real_ positives and ship in an\nunsupported state, and potentially cause downstream dependencies to take advantage of preview features unintentionally. There's also no\nguarantees that users actually enable the analyzer, as they might just disable analyzers for any particular reason. Despite these concerns,\nwe 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\nfeature works, and look at putting the logic into the compiler itself in a future version.\n\nIn particular, there are some interesting semantics that still need to be worked out. Should APIs be allowed to introduce or remove previewness\nwhen overriding or implementing a member? For example, `System.Decimal` already has a `+` operator today, and it will be implementing the\npreview numeric interfaces that define the `+` abstract static operator. The `+` on System.Decimal is not preview today, nor should it be in\n.NET 6, but it _will_ be implementing the preview `+` operator. Explicit implementation is also not always possible for these operators, as\nwe will have asymmetric operator support in the math interfaces that get unified with a symmetric operator later in the hierarchy, so we\ncan't rely on enforcing explicit implementation to solve this problem. On the opposite side of this problem, allowing adding of previewness\nat more derived API level is problematic, because the user could be calling a less-derived method and therefore accidentally taking advantage\nof a preview feature.\n\nFinally, there is some IDE-experience work to think through. While we do want these APIs to show up in places like completion and refactorings,\nwe would also like to make sure we're not accidentally opting users into preview features that then break their build totally unexpectedly. We\nthink there is design space similar to our handling of `Obsolete`, such as marking things preview in completion lists.\n\n#### Conclusion\n\nWe 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\ndesign is needed on some parts of the feature, but it doesn't require direct involvement of the LDM.\n\n### Simple C# programs\n\nhttps://github.com/dotnet/designs/pull/213\n\nFinally 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\npossibly on the smaller side code-wise. Simple does _not_ necessarily mean \"Hello, World!\" and nothing else. While we are interested in the\nintro experience, we additionally think there is opportunity to expand to address a market that has traditionally had a bunch of friction to\nuse C# in today.\n\nC# has historically had a focus on very enterprise scenarios: professional developers working on larger projects using a dedicated IDE. Our\nuser studies have shown that this workflow isn't what many newer users are expecting, particularly if they're coming from scripting languages\nlike Go, Javascript, or Python. These users instead expect to be able to simple make a `.cs` file and run it, with potentially more ceremony\nas they start adding more complex dependencies or other scenarios. Other expectations exist (such as repls), but our studies have shown that\nthis is the most popular. An important part of our task here will be figuring out where that \"more ceremony\" step lies, what that additional\nceremony will look like, and how it will interact with any additions we make to the language (how project-file based projects interact with\n`#r` directives, for example).\n\nInvesting in tooling that puts NuGet directives in C#, as well as potentially `#load` or other similar file-based directives, is going to\nnecessitate that we reconcile file structure and project structure in C#. Today, the contents of C# files are very intentionally independent\nof their locations on disk: file structure is handled by the project file, and project structure is handled by `using` directives and\nnamespace declarations. `#r` to local NuGet packages or `#load` to add other `.cs` files would blur the line here.\n\nAnother important consideration of these directives is how complex we want to let them get. At the extreme end, these directives could be\nnested inside `#if` directives, which starts to necessitate a true preprocessing step that the SDK tooling will need to understand and perform.\nToday, preprocessor directives in C# don't have massive effects, and they can be processed in line with lexing. There are restrictions we can\nlook at for where to allow `#r` and similar directives, and deciding on those restrictions will help inform where exactly that additional\nceremony will land. For example, we could require that all of these directives must be the first things in a file, with nothing preceding\nthem. This would ensure that conditional NuGet references are that cliff of complexity that requires a project file.\n\nFinally, 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\nin 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\nsome of these answers will be driven by discussions with the SDK teams, but they're all part of determining where the cliff of complexity\nwill land.\n\n#### Conclusion\n\nOverall, we're extremely excited to take this challenge on, and look forward to working through this design to find the edges.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-05-17.md",
    "content": "# C# Language Design Meeting for May 17th, 2021\n\n## Agenda\n\n1. [Raw string literals](#raw-string-literals)\n\n## Quote(s) of the Day\n\n- \"You have a mongolian vowel separator\"\n\"Dear god\"\n- \"I was expecting [redacted] to flip the table and say I'm out of here\"\n\"When you flip the table at home, how do you clean that up?\"\n\"Exactly, I don't want to have to clean that up\"\n\"Wait wait, that sounds like a new teams feature\"\n- \"Pretty easy to interpolate those results\"\n\"Is that a correct use of the word interpolate?\"\n\"No\"\n\n## Discussion\n\nhttps://github.com/dotnet/csharplang/issues/4304\n\nToday we took a look through the proposal for raw string literals. This would add a new type of string literal to C#, specifically\nfor working with embedded language scenarios that are difficult to work with in C# today. A number of other languages have added\nsimilar features, though our colleagues on Java are perhaps the most direct inspiration for this proposal (particularly with the\nwhitespace trimming feature).\n\nOverall, the LDM is universally in favor of the feature. Some details still remain to be worked out, but we believe this is a feature\nthat will benefit C#, despite the complexity in adding yet another string literal format.\n\n### Single-line vs multi-line\n\nThe proposal suggests both single-line and multi-line forms for this new literal format. While multi-line literals are the obvious\nheadline feature here, we do think there's a use-case for a single-line form: embedded languages like regex are often single-line,\nused inline in a method call or similar. They suffer from all the same problems as other embedded languages today (frequent need\nfor quotes, but using quotes is both hard and results in hard-to-read code).\n\n#### Conclusion\n\nWe would like a single-line version.\n\n### Whitespace trimming\n\nVerbatim string literals today have behavior that make them somewhat unpleasant for multiline strings because, if whitespace is not\ndesired 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\nin the file which breaks up the flow of the file and can make subsequent indentation hard to judge. Trimming solves this by removing\nwhitespace from the start of every line, determined by the whitespace preceding the final quotes. This feature has a couple of levers\nwe can tune to increase or decrease the requirements on the user, namely around handling blank lines. The proposal currently says\nthat blank lines must have a _prefix_ of the removed whitespace on the line. That means that, if the whitespace to be removed is\n`<tab> <tab> <space>`, a completely empty line is fine, as is a blank line with `<tab> <tab>`. Both are prefixes of the whitespace to\nbe removed. However, a line with `<tab> <space>` is _not_ fine, because that is not a prefix of the whitespace to be removed. We\ncould make this more strict by saying that a blank line must either have the full whitespace to be removed, or no content at all.\nWhile this is more strict, it could end up being a better user experience: whitespace is, by nature, hard to visualize, and providing\na good diagnostic experience around \"this whitespace isn't a prefix of that whitespace\" is not something we're eager to tackle. On the\nother hand, trailing whitespace is pretty easy to accidentally insert today, and we don't make that a compile error by default anywhere\nelse.\n\n#### Conclusion\n\nWe'll go with the stricter behavior for now: blank lines must either contain the entire whitespace being removed, or no text at all.\nWe can relax this later if it makes the experience better.\n\n### Language fences\n\nWe also looked at allowing a language fence in literals, similar to how markdown works. In multiline markdown strings, ```` ```identifier ````\nmarks the code block as having a specific language, which the markdown renderer can use to render the text inline. In C# string literals\ntoday, there's fragmented support for this implemented in a number of tools: VS, for example, detects when a string is being passed\ndirectly to a regex API, and also has support for a comment syntax to turn on highlighting for different locations. We could standardize\nthis for C# raw string literals: the proposal is specifically worded such that text is _required_ to start on the line after the open\nquotes to allow us to include this feature in the future. One immediate question, however, is how would we support this for single-line\nliterals. Our existing syntax highlighting support is specifically for regex, which is the exact use case for the single-line version,\nbut the language specifier doesn't work there. We could potentially support a trailing language specifier for this case, such as\n`\"\"\".*\"?\"\"\"regex`, but it would limit the number of things that can be put in the space.\n\n#### Conclusion\n\nWe're mixed on language fences, leaning against supporting them for now. More debate is needed.\n\n### Interpolation\n\nThis proposal didn't originally have interpolation, but after a large pushback from the community, interpolation was added. Because the\ngoal of the proposal is to represent all strings without escaping, the immediate next question is how we represent interpolation holes\nwithout requiring escaping of braces. The proposal suggests we use the number of `$`s in front of the raw string to represent the number\nof braces required to trigger an interpolation hole: `$$\"\"\"{}\"\"\"` would be the string `{}`, because `{{}}` is needed to be counted as an\ninterpolation hole. IDE experience is going to be very important here: context-sensitive interpolation holes are going to be somewhat\nharder to keep track of, and refactorings to add additional braces to an existing string if needed will be very helpful for users to avoid\ntedious and potentially error-prone manual changes when suddenly the user needs to use the existing number of braces as an actual string\ncomponent.\n\nWe also considered a slightly different form, `$\"\"\"{{`, where the number of braces after the triple quotes controls how interpolations work.\nThis form, while providing a more direct representation of the number of curlies required, doesn't work for single-line strings and cannot\nbe applied to all interpolated strings. We further thought about using the number of quotes to control both the number of braces required\nfor interpolation holes and the number of quotes required to close the string; while this would work for the single-line form, it would\nrequire 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\nto represent a single open/close brace. It also cannot be extended to all interpolated strings.\n\n#### Conclusion\n\nWe want interpolation, and we're ok with using the number of `$`s to control the number of braces.\n\n### Alternative Quotes\n\nWe considered whether to use ```` ``` ```` or `'''` instead of or in addition to `\"\"\"`. The `` ` `` symbol is concerning because it can\nbe hard for non-English keyboard layouts to hit; while there are symbols in C# today that are already difficult for these layouts to hit,\nwe don't want to deliberately introduce more pain for these users. We also don't like the complexity of either having multiple symbols\nthat 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\nthe additional axes of complexity is worth the tradeoff here. It does mean that the single-line version cannot represent a string that\nstarts with a `\"`, but we think this is an OK tradeoff.\n\n#### Conclusion\n\nQuotes are the only way to start strings. Users that need to start a string with a quote must use the multi-line version.\n\n### Miscellaneous conclusions\n\nEven 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\nuser wants to use 4 quotes in a string, the raw string delimiters must be at least 5 quotes long.\n\nStrings like this are supported:\n```cs\nvar z = $$\"\"\"\n{{{1 + 1}}}\n\"\"\";\n```\nThe innermost braces are the interpolation holes, the resulting value here would be `{2}`.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-05-19.md",
    "content": "# C# Language Design Meeting for May 19th, 2021\n\n## Agenda\n\n1. [Triage](#triage)\n    1. [Checked operators](#checked-operators)\n    2. [Relaxing shift operator requirements](#relaxing-shift-operator-requirements)\n    3. [Unsigned right shift operator](#unsigned-right-shift-operator)\n    4. [Opaque parameters](#opaque-parameters)\n    5. [Column mapping directive](#column-mapping-directive)\n    6. [Only allow lexical keywords](#only-allow-lexical-keywords)\n    7. [Allow nullable types in declaration patterns](#allow-nullable-types-in-declaration-patterns)\n2. [Protected interface methods](#protected-interface-methods)\n\n## Quote of the Day\n\n- \"I feel like I've known this before and then I packed it away in some chamber of horrors in my brain\"\n\n## Discussion\n\n### Triage\n\n#### Checked operators\n\nhttps://github.com/dotnet/csharplang/issues/4665\n\nThere are some complexities to this proposal (such as betterness rules between checked and unchecked operators), how it will affect VB, and some\npotential clunkiness in the interface definitions (`int` shift doesn't overflow today even in checked contexts, but would need to expose both?),\nbut we think that this is pretty essential to a well-formed generic math interface structure.\n\n##### Conclusion\n\nTriaged into the working set.\n\n#### Relaxing shift operator requirements\n\nhttps://github.com/dotnet/csharplang/issues/4666\n\nWe 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\noperators. It might be time to lift the restriction here.\n\n##### Conclusion\n\nTriaged into the working set.\n\n#### Unsigned right shift operator\n\nhttps://github.com/dotnet/csharplang/issues/4682\n\nThis is an odd missing operator in general, and a hole in our design for generic math that similar libraries in other languages have filled.\n\n##### Conclusion\n\nTriaged into the working set.\n\n#### Opaque parameters\n\nhttps://github.com/dotnet/csharplang/issues/4629\n\nWe'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\n2 of these parameters with the same type, or wants to add multiple constraints to a type parameter?\n\n##### Conclusion\n\nRejected. It's possible we could revisit flavors of this with associated types at a later point, but as is this is rejected.\n\n#### Column mapping directive\n\nhttps://github.com/dotnet/csharplang/issues/4747\n\nWe have a few open questions, such as whether we need an end offset as well. However, overall this looks good. These directives are basically\nnever human-written or read, and it helps solve problems for partner teams using C# as a DSL.\n\n##### Conclusion\n\nTriaged into the working set.\n\n#### Only allow lexical keywords\n\nhttps://github.com/dotnet/csharplang/issues/4460\n\nThis is a discussion that has been building in the LDM for years, particularly around older contextual keywords such as `var` and `dynamic`\nused in a type position. We think there are two broad categories of contextual keywords here: keywords that we think are \"safe\" to reserve,\nsuch as the aforementioned `var`, that are used in positions where standard C# conventions wouldn't allow things to be named in a conflicting\nmanner: types, for example, are PascalCase by convention in C#, and `var` starts with a lowercase character. Making a break here helps _both_\nthe compiler team and the average language user, as it simplifies the language and isn't likely to break code that isn't intentionally trying\nto avoid the feature. There are other keywords though, such as `yield`, that we think are good to keep as contextual keywords. It makes the\ncompiler 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.\nWe 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#\nX and then totally deprecate in Y.\n\n##### Conclusion\n\nTriaged into the working set. We'll revisit soon to think about the phased strategy and see what we want to do for C# 10.\n\n#### Allow nullable types in declaration patterns\n\nhttps://github.com/dotnet/csharplang/issues/4724\n\nThere are some really gnarly parsing ambiguities here, but even if we could solve the compiler parsing problem, the human parsing problem will\nremain. We don't think those problems are really solveable, and that the gain isn't worth the complexity.\n\n##### Conclusion\n\nRejected.\n\n### Protected interface methods\n\nhttps://github.com/dotnet/csharplang/discussions/4718\n\nWhen DIMs were initially implemented, we were concerned about a `public` member in a type named the same as a `protected` member in an interface\nthat type is implementing being confused for an implicit implementation of that `protected` member. However, this ends up somewhat hindering the\ngoal 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\nfuture option for _having_ implicit `protected` interface member implementation was already removed in V1 of DIMs, we'd like to remove this\nrestriction. 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\nand 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\nmembers\".\n\n#### Conclusion\n\nWe'll relax this restriction as a new language feature.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-05-26.md",
    "content": "# C# Language Design Meeting for May 26th, 2021\n\n## Agenda\n\n1. [Open questions in list patterns](#open-questions-in-list-patterns)\n\n## Quote of the Day\n\n- \"If somebody lays down on the track I'm perfectly willing to be taken hostage\"\n\n## Discussion\n\n### Open questions in list patterns\n\nhttps://github.com/dotnet/csharplang/blob/main/proposals/list-patterns.md\n\nToday we looked at a number of open questions in list patterns, currently being implemented.\n\n#### Patterns allowed after a slice operator\n\nWe first revisited the question of what to allow after a `..` pattern. Previously we stated that any possible pattern\nshould be allowable in this position; however, there is some concern that this could be confusing to code readers. We\nforsee the vast majority of patterns in this location being simply capturing the slice into a pattern, and there is a\ndissimilarity here with other containing pattern contexts. For positional, property, list, and length patterns, nested\npatterns are all visually inside delimiters (`()`, `{}`, and `[]`, respectively). Here, the pattern would be on the\nslice element, but _not_ visually inside. There is also some concern that perhaps we should take the position that using\na nested pattern here is just generally not good form: we think that such syntax will become quickly unreadable, going\nagainst the general goal of the feature. There's also potential for being visually hard to parse: something like\n`..var x and not null` parses very differently in a pattern (as `..(var x and not null)`) than it does in regular syntax,\nfor something like `..1+2` (which parses as `(..1)+2`).\n\nLooking at these concerns gives us 3 general options for how to move forward:\n\n1. Simplify the syntax, and only allow `..identifier`. Users can omit the type entirely. General patterns are not allowed.\n2. Only allow `..var pattern`. This has symmetry with other declaration patterns.\n3. Allow all patterns.\n\nOption 1 is initially somewhat attractive because it will simplify the 99% case here. However, we have some concerns: it's\nnot regular with other declarations, and some users do not like implicitly-typed variables. It also makes it harder to\nchange our minds here in the future, if we ever wanted to add an `all` or `any` pattern. Meanwhile, version 2 suggests\na pattern generality that would not exist, and (to the user that runs into this) for seemingly arbitrary reasons.\n\nGiven our concerns with the first two approaches, we think that, despite earlier concerns, approach 3 is the way to go.\nWe can take a stronger stance in the IDE and our documentation with fixers and best practices to help ensure that nested\npatterns don't get too crazy here.\n\n##### Conclusion\n\nOriginal design upheld, any pattern is allowed after a slice.\n\n#### Multi-dimensional array support\n\nCurrently, the list pattern specification has an open question as to whether MD-arrays should be supported. One of our\ngoals for this feature was to bring symmetry between object creation and deconstruction/pattern forms, and array/collection\ninitializers work with MD-arrays today, suggesting they should be supported in patterns. However, our current rules depend\non types being indexable/countable/sliceable, which MD-arrays are not today. They're also generally not a huge area of\ninvestment for either the language or the runtime, so it feels odd to make sure they work here but not also with the rest of\nthe indexing/counting/slicing features.\n\n##### Conclusion\n\nNot supported. If we want to make a general MD-array focused release, we would want to revisit all the areas they're currently\nlacking, not just list patterns.\n\n#### Binding rules for Slice\n\nThis is a double-sided question on how we bind `Slice` methods: should we allow default parameters, and should we allow\nextension methods for Slice? In general, we think we should follow the same rules as the existing support around slicing,\nwhich is no on both questions. We can look at a general feature to loosen the restrictions as a separate proposal.\n\n##### Conclusion\n\nNo default parameters or extension methods.\n\n#### Tests emitted for `{ .. }`\n\nThe main question here is whether `{ .. }` should emit a check that `Length` or `Count` is greater than or equal to 0, or if it should\nsimply be a no-op. This must be specified in the language, as not doing so would result in \n`default(ImmutableArray<int>) is { .. }` having undefined behavior (it will throw or not, depending on whether `Length` is\nevaluated). We think that `..` without a trailing pattern and without any other element patterns is similar in concept to a\n`_` pattern: `default(ImmutableArray<int>) is { Length: _ }` does not actually evaluate `Length`, and thus won't throw.\nThe `..` is the same: _other_ things cause `Length` to be evaluated, such as the precense of other element patterns or a\nlength pattern. A slice pattern can change the nature of that check (moving it from an `==` to a `>=`), but it doesn't add\nthe check on its own. Similarly, `.._` will not call slice, just like other discard operations. This does mean that, for\nlist implementations that do not follow framework design guidelines and return negative lengths or counts, `{ .. }` will not\nfail when they do so, but we think that is fine.\n\n##### Conclusion\n\n`{ .. }` will not emit a `Length` check, and `{ .._ }` will not call `Slice`.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-06-02.md",
    "content": "# C# Language Design Meeting for June 2nd, 2021\n\n## Agenda\n\n1. [Enhanced #line directives](#enhanced-line-directives)\n2. [Lambda return type parsing](#lambda-return-type-parsing)\n3. [Records with circular references](#records-with-circular-references)\n\n## Quote of the Day\n\n* If you make it `..`, does that mean the end is included or not?\n\n## Discussion\n\n### Enhanced #line directives\n\nhttps://github.com/dotnet/csharplang/issues/4747\n\nThis proposal covers a set of enhancements for the `#line` directive that solve several problems that the razor team has had over the years with\nthe existing directive causing mismapping of code in the debugger. While the razor team is the main user and driver of this scenario, these enhancements\nwill help any DSL authors that embed C# in their code and want to have a debugging experience. The issue today is that nested expressions don't have\nsequence points emitted correctly, and putting the expression on a newline is often not a sufficient solution to ensure that they end up correctly\nrepresented.\n\nWe brainstormed a few different ways to determine the span of an expression for this mapping. Inherently, the enhanced directive needs to be able to\nspecify the length of the mapped line, because users might end up putting multiple separate fragments of C# code on the same line in the original text\nfile. To be able to represent that accurately, we therefore need to ensure that the exact length is represented. We considered whether we could do this\nvia the total length of the mapped expression, rather than specifying the end line/column of the directive. However, there are a few concerns with that\napproach:\n\n1. Files are often written and checked into source control with different encodings/line endings, most commonly differing between `\\r\\n` and `\\n` for\nline endings. For maps that span multiple lines, therefore, the total character count could end up being wrong after compilation depending on what system\ncreated the mapping and what built it.\n2. For humans attempting to author and debug generators that use these directives, line and column are easier to map to the real code that they're writing.\nEvery editor includes this information when editing a file based on the current cursor location. This makes understanding what is happening easier.\n\nWe also considered how the line and column information is defined. Today, C# in general defines specific characters that are newlines (in part to ensure\nthat the existing `#line` directives are well-defined). This doesn't change with the new proposal, and some editors don't always agree on what constitutes\na new line (such as vertical tab), this proposal doesn't change these inconsistencies. For character offsets, we define it as UTF-16 characters, following\nwith the rest of the .NET ecosystem here. If the ecosystem ever wants to attempt to change to a different encoding, it will be a much larger effort and\nadjusting the semantics of `#line` should be trivial by comparison.\n\nFinally, we looked at a few different syntax options for the directive, as we felt that just 5 numbers next to each other was unnecessarily difficult to\nread:\n\n1. `#line (10,20)-(11,22) 3 \"a.razor\"`\n2. `#line (10:20)-(11:22) 3 \"a.razor\"`\n3. `#line 10:20-11:22 3 \"a.razor\"`\n4. `#line 10,20-11,22 3 \"a.razor\"`\n5. `#line (10,20)-(11,22):3 \"a.razor\"`\n6. `#line (10,20) (11,22) 3 \"a.razor\"`\n7. `#line (10,20):(11,22) 3 \"a.razor\"`\n8. `#line (10,20)..(11,22) 3 \"a.razor\"`\n\nWe think options without the parens are a bit confusing, because `-` binds more tightly than `,` or `:` in c#, making it look like `10 , (20-11) , 22`.\nWe also think that `,` is the more common line/column separator. Given this, we'll go with option 1.\n\n#### Conclusions\n\nExisting proposal is accepted with the following clarifications:\n\n1. Column info is described as UTF-16 characters.\n2. The syntax is `#line (number , number) - (number , number) number string`.\n\n#### Lambda return type parsing\n\nhttps://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/lambda-improvements.md\n\nIn a previous LDM, we decided that lambda return types should go before the parameter list, as in `ReturnType (ParamType param) => { ... }`. This has\npresented some challenging parsing scenarios.\n\n```cs\nF(b ? () => a : c); // Conditional expression or lambda that returns 'b?'?\n```\n\nThis issue is very similar to generics and greater-than/less-than parsing, and can benefit from the same solution: we specifically define a set of\ncharacters after the lambda body in the language and use them to determine, at that point, whether the expression is a ternary or a lambda with a return\ntype. For example, if token after the lambda is a `)`, it couldn't have been a ternary. This will take effort, but should be doable.\n\nAnother parsing problem comes from multiplication:\n\n```cs\nF(x * () => y) // Is it multiplication, or a lambda with a return type of x*?\n```\n\nHere, our saving grace is that `*` binds more tightly than the lambda expression today, so this code does not parse. This should allow us to disambiguate\nthe cases here. Again, this will take effort, but should be doable.\n\nWhile considering these cases, we also thought about lambda naming as a potential easier disambiguation point. We could allow lambdas to be named (perhaps\njust with a `_` to start), and require them to have a `_` to use the return type. Further, we need to consider this now because the `identifier () => {}`\nsyntax can only mean one thing: `identifier` will either need to be the return type, or the name of the lambda. As we continue to narrow the gap between\nlambda expressions and local functions, it stands to reason that we may at some point want to give them names (despite the phrase \"named lambda\" being a\nbit of an oxymoron). Further, choosing to make the single-identifier case mean the type instead of the name breaks with the precedent we have around lambda\nparameters, where the name can be specified without the parameter type.  \nOn the other hand, we do feel that the return type is the more common thing to want to specify for a lambda. While named lambdas could be useful for recursive\nscenarios, we don't see this as a driving need, while the return type is explicitly being driven to enable .NET 6 scenarios. Additionally, if we allowed\nlambda names for recursion we'd sign ourselves up for recursive type inference, as we'd have to start inferring the return type of lambdas that can call\nthemselves. By saying that the single-identifier case is for specifying the return type, we separate that out into a different feature, and we have a natural\ntype to allow as the return type of the lambda for this case: `var`. In order to protect this design space, we'll disallow `var` as the explicit return type\nof a lambda expression.\n\n#### Conclusion\n\nWe think the existing difficulties should be possible to parse, with a bit of effort. We'll reserve `var` as an explicit return type to protect our design\nspace around recursive type inference in lambdas, if we ever decide to try and tackle that challenge.\n\n### Records with circular references\n\nhttps://github.com/dotnet/roslyn/issues/48646\n\nIn the brief time left at the end of the meeting, we wanted to re-examine our previous position around circularity in record types. There are several ways\nthat users can end up with circular data structures in records, in both obvious (and detectable) ways of direct mutable recursion, such as in a doubly-linked\nlist, and indirectly, via nested mutation. Our initial position in records was that this isn't something we want to try and solve in the language, but could\nbe solved via source generators. There are a number of points where users might want to customize aspects of record code generation, such as using a different\nequality comparison option for strings, or doing sequence/set equality for collections. The question we want to answer, therefore, is whether we should move\nthe cliff to generators up a bit further and add a method of excluding specific fields from record semantics to the language, and whether we should add a new\nwarning wave warning to inform users when they're setting themselves up for direct recursion issues. This warning can't be perfect, however: it cannot catch\nmutually-recursive types where one type has a mutable field of the other type, particularly when fields of a non-sealed type are involved. For example, record\n`A` has a mutable field of type `IDisposable`. Record `B` has an immutable field of type `A` and implements `IDisposable`. `A` is constructed, then `B` is\nconstructed with that instance of `A`, then `A`'s mutable field is set to `B`. Unless we warn on every mutable field of a non-sealed type, that case is\nimpossible to detect, and we're cautious of overwarning and then causing users to miss real issues.\n\n#### Conclusion\n\nA smaller working group will meet to explore this in more depth, and make a recommendation to the LDM about the approach we should take.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-06-07.md",
    "content": "# C# Language Design Meeting for June 7th, 2021\n\n## Agenda\n\n1. [Runtime checks for parameterless struct constructors](#runtime-checks-for-parameterless-struct-constructors)\n2. [List patterns](#list-patterns)\n    1. [Exhaustiveness](#exhaustiveness)\n    2. [Length pattern feedback](#length-pattern-feedback)\n\n## Quote of the Day\n\n- \"They should probably be told off, I was going to say something else, but they should be told off in code review\"\n\n## Discussion\n\n### Runtime checks for parameterless struct constructors\n\nhttps://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/parameterless-struct-constructors.md\n\nIn testing parameterless struct constructors, we've found a new bug with `Activator.CreateInstance()` on older frameworks. This code\nwill print `True, False` on .NET Framework 4.8:\n\n```cs\nSystem.Console.WriteLine(CreateStruct<S>().Initialized); // True\nSystem.Console.WriteLine(CreateStruct<S>().Initialized); // False (On .NET Framework)\n\nT CreateStruct<T>() where T : struct\n{\n    return new T();\n}\n\nstruct S\n{\n    public readonly bool Initialized;\n    public S() { Initialized = true; }\n}\n```\n\nThis is due to a caching bug in the framework, at it essentially means that `Activator.CreateInstance()` will only correctly invoke a\nstruct constructor the first time it is used, and any subsequent calls in the same process will run the constructor and then zero-init\non top of that value, so side-effects (such as `Console.WriteLine`) would be observed, but field initialization would not. This is similar\nto the bug that sunk parameterless struct constructors the last time we attempted to add them, but .NET Core and 5 do have the correct\nbehavior here. As .NET Framework is not a supported target platform for C# 10, however, we don't think this is a showstopper like it would\nhave been back in C# 6. We think that this is a good place for an analyzer to warn consumers, as the compiler itself doesn't want to try\nand infer what framework a user is targeting based on the presence of APIs, and runtime feature checks in the compiler are always hard\nerrors and cannot be worked around.\n\n#### Conclusion\n\nAn analyzer will be incorporated into the default analyzer pack to warn users about use of parameterless struct constructors on older,\nunsupported framework targets.\n\n### List patterns\n\nhttps://github.com/dotnet/csharplang/issues/3435\n\n#### Exhaustiveness\n\nWe have a couple of test examples that add some exhaustiveness complications:\n\n```cs\n_ = list switch\n{\n    { .., >= 0 } => 1,\n    { < 0 } => 2,\n    { Count: <= 0 or > 1 } => 3,\n};\n```\n\nThis switch expression should be considered exhaustive, but it will require understanding that the `>= 0` in the first pattern _can_ apply\nto element 0, and that the last expression should then handle all the rest of the cases. Another similar case is this one:\n\n```cs\n_ = list switch\n{\n    { .., >= 0 } => 1,\n    { ..{ .., < 0 } } => 3,\n};\n```\n\nWhile this example is a bit silly, it illustrates the general thing we want to: list patterns on a slice should count towards the containing\nlist pattern for exhaustiveness. While there is the possibility that this means a slice could give bad results (ask for a slice from x to y,\nget the wrong thing back), we generally consider such types to be intentionally subverting user expectations. A list pattern would not be the\nonly place where such a type mislead a user, and we don't think there's a reasonable way to protect against such types.\n\n##### Conclusion\n\nWe should make exhaustiveness work for these scenarios.\n\n#### Length patterns\n\nWe've heard from a number of our more heavily-invested users through channels such as Twitter, Discord, Gitter, and GitHub Discussions that\nour existing plan for length patterns have been generally confusing and/or actively misleading. The major issues that have been raised:\n\n1. While there is symmetry with array size specifiers in construction, that symmetry doesn't carry to any other collection creation.\n2. The `[]` syntax is most often used for accessing at an index, which length patterns don't do.\n3. It is extremely tempting to do `{}` as the empty list pattern as a reduction of the rest of the patterns.\n\nWe've brainstormed a few ways to try and address various parts of this feedback:\n\n1. Have a special `length` pattern that can be used in a list pattern: `{ 1, 2, 3, length: subpattern }`. This pattern can only be used in\nlist patterns, so the empty list would be `{ length: 0 }`. This can help with issues 1 and 2, but not with 3.\n2. Go back to square brackets, as in the original proposal. This helps with all 3 issues, but reintroduces the new issue that `[]` isn't\nsymmetric with array and collection initializers.\n3. Use parens/positional patterns. This seems interesting, but has a problem because positional patterns will check for `ITuple` on inputs\ntoday.\n4. Require using indexers in nested patterns: `{ [0]: pattern, [2]: pattern }`. This is understandable, but extremely verbose.\n5. A more general version of 1: just allow combining list and property patterns into one `{}`. We could potentially have a separator token\nsuch as `,` or `;`, which would allow us to have a pretty simple empty list pattern of `{ , }` or `{ ; }`.\n\nWe didn't get too deep on any particular syntax with the time remaining, but we are convinced that we need to take another look at these.\n\n##### Conclusion\n\nA smaller group will hammer out a proposal and bring it back to LDM. We need to take the time to get this right, which may mean that the feature\nslips and does not make C# 10.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-06-14.md",
    "content": "# C# Language Design Meeting for June 14th, 2021\n\n## Agenda\n\n1. [Open questions in CallerArgumentExpressionAttribute](#open-questions-in-CallerArgumentExpressionAttribute)\n2. [List pattern syntax](#list-pattern-syntax)\n\n## Quote of the Day\n\n- \"My first reaction is that I thought we got rid of the C# test team for testing esoteric scenarios\"\n\n## Discussion\n\n### Open questions in CallerArgumentExpressionAttribute\n\nhttps://github.com/dotnet/roslyn/issues/52745#issuecomment-849961999  \nhttps://github.com/dotnet/csharplang/issues/287\n\n#### VB Support\n\nConclusion: yes, we should support VB here.\n\n#### Generated code\n\nThis question centers around this example:\n\n```cs\nvoid M([CallerMemberName]string arg1 = \"1\", [CallerArgumentExpression(\"arg1\")]string arg2 = \"2\")\n{\n    Console.WriteLine(arg2); // What gets printed?\n}\n\nvoid M2()\n{\n    M();\n}\n```\n\nAs we see it, there are 5 possible values that a reasonable programmer could expect.\n\n1. `null`\n2. The empty string: `\"\"`.\n3. The default value of `arg1`, as an expression: `\"\\\"1\\\"\"`.\n4. The default value of `arg2`: `\"2\"`.\n5. The value filled in for `arg1`, as an expression: `\"\\\"M2\\\"\"`.\n\nWe don't think option 1 is useful here, as the parameter is attributed to not accept `null`, and this\nwould just mean that every use of `CallerArgumentExpression` would be required to handle the `null` case.\nWe also don't think that options 3 or 5 are really correct either: the attribute here is about providing\nthe specific syntax the user used, not the _value_ the user used. There are many ways to express the values\ngiven as a constant value: we could just turn `\"M2\"` into a string, or we could say `\"\\\"\" + \"M\" + \"2\" + \"\\\"\"`.\nBoth are technically correct, but neither reflects what the user actually wrote. Finally, for option 3, we\nthink that this is trying to second-guess the user. They provided a default value for the parameter, and if\nwe never respect that value then the default value was useless. Given these, we think the correct approach\nis option 4.\n\n##### Conclusion\n\nOption 4: the default value of the parameter will be used. We will not turn compiler-generated code into\nequivalent C# expressions.\n\n#### Self-referential arguments\n\nConsider these examples:\n\n```cs\nvoid M3([CallerArgumentExpression(\"arg1\")]string arg1 = \"\"); // Warning?\n\nM3(); // What gets passed? null? \"\"?\n```\n\n##### Conclusion\n\nWe think this is absolutely worth a warning in source code, and if in metadata then we should just provide the\ndefault value of the parameter.\n\n#### Span of the expression\n\nConsider this example:\n\n```cs\nM(arg1: /* Before */ \"A\" + /* Mid */ \"B\"\n /* After */); // What is passed for arg2?\n```\n\nThere are 3 possible answers for this:\n\n1. The argument expression should refer to the start `arg1:` to the end of the position, either `)` or `,`,\ndepending on whether the argument is followed by another or not.\n2. The argument expression should refer from just after `arg1:` to the end of the position, not including the\nargument specifier.\n3. We should ignore any trivia, and just have the expression span from the start of the real C# executable code\n(the string `\"A\"`) to the end of the real executable C# code (the end of `\"B\"`).\n\nWhile there are legitimate argument for 1 or 2, we don't think they provide enough benefit to make up for the fact\nthat they will be including leading and trailing whitespace that we don't believe is useful for the users of this\nattribute. Given this, we think option 3 is the correct way forward.\n\n##### Conclusion\n\nOption 3: we go from the start of real C# executable code to the end of the expression, not including any leading\nor trailing trivia.\n\n### List pattern syntax\n\nhttps://github.com/dotnet/csharplang/issues/3435\n\n#### Revisiting syntax\n\nWe've heard a lot of community feedback around our existing proposal for length patterns, which looks like this:\n\n```cs\n_ = list is [0]; // List has length 0;\n```\n\nTop among user feedback is that this syntax is:\n\n1. Confusing. Even among users who tend to give the LDM the benefit of the doubt with syntax choices, we've heard\nvociferous feedback that this is not clear and that there is not a clear enough parallel to array creation length\nspecifiers to make this obvious.\n2. Unnatural for the base case. The traditional recursive pattern that languages with strong pattern matching\nconstructs use is some number of cases that pull out interesting bits, and then a base case to handle the empty list.\nUnfortunately, `{ }` is _not_ the empty list case, despite being what otherwise appears to be an empty list pattern.\nWhile in some cases this happens to work because all that's left to handle is when the input is non-null, we don't\nthink it will lead to clear code.\n\nA smaller group met to try and brainstorm some approaches to solving the issue. These are:\n\n1. Return to the original proposal syntax, using square brackets (`[]`) to denote a list pattern. This breaks with\nthe correspondence principle, but it does have stronger parallel with other languages, has a natural base case, and\nwe could potentially add a new creation form that achieves correspondence (and take the time to address things like\n`ImmutableArray<T>`, which cannot be initialized by collection initializers today).\n2. Use a separator at the end of a list pattern, such as `;`: `{ 1, 2, 3; } or { ; }`. This separator would be\nrequired, giving a few advantages:\n    1. Because the separator is always required, the base case looks like the shortest version of the pattern.\n    2. Allows list and property patterns to be combined into a single block.\n    3. Gives us an avenue to allow collection and property initializers in the same block, by reusing the same syntax\n    later.\n3. Keep the status quo. Users will get used to the syntax.\n\nThese suggestions led to spirited debate. An unfortunate truth here is that, no matter what approach we take, we have\ndiscrepency with some aspect of the language. The semicolon separator approach allows us to mostly keep in line with\ncollection initializers, but the trailing `;` being required is very different and a wart. Square brackets, on the other\nhand, are _very_ different from the rest of C#. Today, square brackets are used for indexing operations and for\nspecifying the length of an array. Nothing in C# uses them to denote a group of things that is a collection. There are\nproposals to use these brackets for an improved version of collection initializers though, giving us an opportunity for\nfuture fulfillment of the correspondence principle, even if it won't be fulfilled on initial release. Patterns also\nalready have some discrepency with the rest of C#, particularly around `and/or/not` patterns, which aren't words used\nin the rest of the language.\n\n##### Conclusion\n\nWe will go with option 1: using square brackets for the list pattern. We still need to decide if and how these can be\ncombined with recursive patterns, but it gives us the most flexibility with regard to future regularity in the language.\n\n#### Length patterns\n\nOrthogonally, we have also come up with a few suggestions for the length pattern:\n\n1. Recognize a special `length` keyword as a property pattern: `{ length: 10 }`. When a type is Countable, this\nproperty is available, and it will bind to `Length` or `Count` as appropriate.\n2. Recognize the `Length` and `Count` properties on:\n    1. Types that are countable\n    1. Types that are both countable and indexable\n3. Keep the status quo.\n\nGiven that we've chosen square brackets for our new list pattern syntax, option 3 is out. This leaves us with option\n1 or 2. We originally wanted special length patterns in the language because we wanted list patterns to work on a type\nthat didn't have a `Length` or `Count` property: `IEnumerable`. While we still want to do this, the implementation work\nis quite complex and we think that it might not get into the initial version. So, while we're not ruling out 1, we don't\nthink it's necessary quite yet.\n\nOption 2 is nice, but it has a couple of wrinkles. First, it's a breaking change, because we specially recognize that\nthe property in question cannot be negative. This can affect flow analysis and introduce warnings or errors about\nunreachable patterns, and remove warnings about non-exhaustive switch expressions. It's not pretty, but we think we can\ntie this recognition to a warning wave. It will be the first time a warning wave _removes_ warnings, instead of adding\nthem, but we think it's the right move. Second, what types should we specially recognize here. Countable is a very broad\ndefinition in C#: it pretty much just means has an accessible property named either `Count` or `Length`. We think that's\ntoo broad for general recognition; while collections should never have negative lengths, the word `Count` or `Length` on\nits own is not strong enough evidence that the type is a collection. Instead, we think we should require both countable\nand indexable, the same requirements for using a list pattern in the first place. This will ensure that the type at least\nbehaves like a collection, and while there still might be such types that return negative `Count`s or `Length`s, patterns\nare only one place where such types will confuse their users and we don't think it's an edge case that should derail the\nwhole feature.\n\n##### Conclusion\n\nWe will specially recognize the `Count` and `Length` properties on types that are both countable and indexable, assuming\nthat it can never be negative.\n\n#### Timing\n\nGiven that the changes we've made today are specifically driven by community feedback, we feel that this feature needs\nmore bake time than is left in the C# 10 cycle. The feature will ship in preview, either with C# 10 (like static abstracts in\ninterfaces) or shortly after 10 is released. We want to make sure that the course-corrections we're making here help\ncommunity understanding of the feature, and we don't have enough time before C# 10 is released to implement the changes\nand get them in customer hands before 10 is declared final.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-06-21.md",
    "content": "# C# Language Design Meeting for June 21st, 2021\n\n## Agenda\n\n1. [Open questions for lambda return types](#open-questions-for-lambda-return-types)\n2. [List patterns in recursive patterns](#list-patterns-in-recursive-patterns)\n3. [Open questions in async method builder](#async-method-builder-overrides)\n4. [Email Decision: Duplicate global using warnings](#email-decision-duplicate-global-using-warnings)\n\n## Quote of the Day\n\n- \"[redacted] is suddenly very blue.\" \"They're only transmitting the blue channel.\" \"They don't like where this is going.\"\n\n## Discussion\n\n### Open questions for lambda return types\n\nhttps://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/lambda-improvements.md\n\n#### Method type inference from return types\n\nThe question here centers on the following scenario:\n\n```cs\nstatic void F<T>(Func<T, T> f) { ... }\n\nF((int i) => i); // ok (in C# 9 and 10)\nF(i => i);       // error (in C# 9 and 10)\nF(int (i) => i); // what should the behavior in C# 10 be?\n```\n\nThe reason for this is that the way anonymous method inference is worded, we specifically pay attention to types specified in source.\nThe question here, then, is whether we should get information from an explicit return type of a lambda, and if so what type of inference\nwe should make?\n\nFor the first question, we think the answer is pretty simple: the user explicitly put a type in, so we should see it. Anything else will\nmake the feature feel incomplete, and will likely end up being a breaking change _somehow_ if we were to do it later.\n\nFor question 2, we looked at the current behavior for parameters. Today, we make an _exact_ inference from explicit lambda parameter types\nto type parameters, rather than an upper bound inference. This means that the type parameter must exactly match the lambda parameter type,\nrather than allowing any kind of variant conversion in that position. We could potentially loosen this restriction in a future version (and\nVB.NET actually does this already), but we do question the merits of the feature a bit: why would a user be using a different type here?\nThe lambda is only being used in this one location, so it should just be using the type it needs. We can squint and see a few potential use\ncases, but they don't rise to the 100 points for us at the moment. Therefore, to be consistent with parameters, we'll make an exact inference\nfor lambda return types.\n\nThis also needs to apply for other variance scenarios, such as lambda->delegate type conversions:\n\n```cs\nFunc<object> f = string () => \"\";\n```\nThis will also require an exact match, and thus the above code will error.\n\n##### Conclusion\n\nVariance is disallowed for explicit return types in lambdas. This means that type inference will make an exact inference from explicit return\ntypes to type parameters in that position, and variant conversions will be disallowed for lambda->delegate conversions.\n\n#### Parsing ref return types\n\nWe have a question on whether ref return types will need to be surrounded by parens to make parsing work. For example:\n\n```cs\nDelegate d1 = (ref int () => x); // ok\nDelegate d2 = ref int () => x;   // Currently parses as ref (int () => x)\nDelegate d3 = ref b ? ref int () => x : ref int () => x; // What should this mean?\n```\n\nThis seems like a problem we should be able to fix with some clever grammar rules. Semantically, the idea of `ref`ing a lambda doesn't make\nmuch sense, as `ref`s should point to locations, and lambdas are not a location.\n\n##### Conclusion\n\nLets do the fancy grammar work to make this parse like the user would want.\n\n### List patterns in recursive patterns\n\nhttps://github.com/dotnet/csharplang/issues/3435\n\nLast week's discussion left us with a strong conclusion about the general form of list patterns: they will use `[]` as the list pattern\nsyntax, so matching an integer list with the numbers 1-3 would be `list is [1, 2, 3]`. However, we still need to address where a list\npattern will be allowed. We have a few proposals:\n\n1. Do not put the list pattern in a recursive pattern at all. To combine a list pattern and a property pattern or type pattern, `and`\nwill need to be used.\n2. Put the list pattern after the property pattern in regular recursive patterns, and require that a property pattern is used (even if\nempty) when combining a list pattern with either a type pattern or a positional pattern.\n3. The same as 2, but only require the property pattern for the actually ambiguous case of the empty list pattern.\n4. Have a separate list pattern, and also allow the list pattern as an optional trailing component to a property pattern. The effect\nof this version is a combination of 1 and 2.\n\nOne concern with the versions that allow property patterns to be directly combined with list patterns is that it recomplicates recursive\npatterns, after C# 9 decomplicated them by allowing the type pattern to be used on its own. We don't think that the combination of type\nand list patterns is going to be a common case, and we therefore have concerns about the special disambiguation rules that they would\nneed as a part of recursive patterns as it would just never become a common enough case for users to internalize the rules here. This\nwould make both reading and writing such patterns less straightforward. However, if we're wrong about the commonality of this combination,\nthen requiring an `and` pattern everywhere would also get tedious and repetitive. Ultimately, we think we need to get a version of this\ninto preview first and see if users actually end up needing the combination patterns. To get the best feedback, therefore, we'll go with\noption 1 for now, and if we hear complaints about needing to use `and` to combine various patterns with list patterns frequently we can\nrevise our approach.\n\nGiven that we are choosing to go with 1, we also looked at whether to allow a trailing designator after the list pattern. This starts\nto get to a slippery slope: why allow trailing designators but not property or type patterns? However, it is our job as the LDT to\ndetermine how far down a slippery slope we want to go, and stop there. We think that, unlike property or type patterns, designators are\ngoing to be an extremely common case for list patterns, particularly in nested contexts, and we already have other feedback from patterns\nto add more designators in places (such as after a `not null` pattern). Given this, we'll add an optional designator after list patterns.\n\n#### Conclusion\n\nList patterns will be their own pattern type, not part of recursive patterns, and will have an optional trailing designator.\n\n### Open questions in async method builder\n\nhttps://github.com/dotnet/csharplang/issues/1407\n\n#### Async method builder override validation\n\nThe first question today is whether we should validate that the return type of a method or lambda marked with `AsyncMethodBuilder` is\nactually task-like. For example, should this be legal:\n\n```cs\n[AsyncMethodBuilder(typeof(MyCustomBuilder))]\npublic async int M() => ...;\n```\n\nOur options here are:\n\n1. Require that the return type be task-like, even though we won't use the information from that type.\n2. Do not validate that the return type is task like. This will even include lambdas with an inferred return type.\n3. Do not validate, but require that lambdas marked with this attribute have an explicit return type.\n\nWe don't like number 2 because the user is saying what builder type the compiler should use, but not actually saying what type the\nbuilder is building. This feels backwards. We also think 1 is too restrictive: the user has to make the type a task-like type, but\nthen the compiler discards all the information from that type when actually emitting the method. Given these, our preference is 3.\n\n##### Conclusion\n\nWe will not validate that the return type is task-like, but when applied to a lambda the lambda must have an explicit return type.\n\n#### Async method builder on public members\n\nFor task-like types, we have a requirement that the builder type must have the exact same accessibility as the task-like type itself,\nto ensure that users don't run into scenarios where the task-like type is not usable in an async context despite having the attribute.\nThis isn't a concern for the attribute on a method, however, because the attribute doesn't affect consumers of the method. It only\naffects the codegen for the method itself. These attributes are also not inherited, so if an override would like to use the same\nbuilder type it will have to manually apply the attribute itself. Given that, we think that it should be fine if the visibility of\nthe builder type is not the same as the visibility of the return type, so long as both are visible at to the method using those types.\n\n##### Conclusion\n\nAccessibility of the builder type does not need to match the accessibility of the return type in method contexts.\n\n#### Factory indirection\n\nThe existing proposal has an indirection for allowing a factory to create the builder, which the compiler then uses in the method\nbody. We don't have a use case for this at the present, so we will remove it from the spec to simplify the proposal.\n\n##### Conclusion\n\nFactory indirection is removed.\n\n### Email Decision: Duplicate global using warnings\n\nSome early feedback on global usings has suggested that duplicated using warnings can be painful, particularly if a global using and\na non-global using are duplicated. Code generation can very easily run into this scenario, and it doesn't have an easy resolution.\nAfter discussion, we decided to remove the duplicated using warning for when a global using directive or a regular using directive are\nduplicated. The compiler will still issue a hidden diagnostic to inform the IDE and analyzers, but there will be no user-facing warning\nby default. We will still error when the same alias is defined more than once, even if the alias refers to the same type, as we feel\nthat aliases are more like declarations and we believe declarations should be intentional.\n\n#### Conclusion\n\nDuplicate using warning is removed when a global using is duplicated by another using (global or otherwise).\n"
  },
  {
    "path": "meetings/2021/LDM-2021-07-12.md",
    "content": "# C# Language Design Meeting for July 12th, 2021\n\n## Agenda\n\n1. [C# 10 Feature Status](#c-10-feature-status)\n2. [Speakable names for top-level statements](#speakable-names-for-top-level-statements)\n\n## Quote of the Day\n\n- \"You do realize there was a quote of the day there when you said there are still holes in the interpolated strings feature?\" _collective groan_ \"I keep track of the important stuff\"\n\n## Discussion\n\n### C# 10 Feature Status\n\nhttps://github.com/dotnet/roslyn/blob/main/docs/Language%20Feature%20Status.md#c-next\n\nWe spent the first half of today going through the remaining features that are currently being worked on by the compiler team and prioritizing them for what is going to make\nC# 10, and what will need to be pushed out to early preview for C# 11. Of the things still under C# Next, the current statuses are:\n\n- Parameterless struct constructors - will be merged for 17.0p3. This includes integration with record structs.\n- nameof(parameter) - This is becoming increasingly important as we add new features that reference other parameters in attributes. Nullable already existed, but we're additionally\nadding `CallerArgumentExpression` and `InterpolatedStringHandlerArgument` in C# 10. However, it is unlikely to be prioritized enough for C# 10.\n- Parameter!! - This has IDE impact, so while the compiler-side is basically done, it does need some more work. We additionally want more community bake time to let customers actually\nuse the feature before we ship it. We'll be aiming for early C# 11 previews.\n- Relax ordering of partial and ref - This is not being worked on, and should be removed from the status page.\n- CallerArgumentExpression - The feature work for this is very nearly done. Should be in for C# 10.\n- Generic attributes - The feature work for this is complete. Needs a few more tests, then should be merged for C# 10.\n- List patterns - We're aiming for an early preview in C# 11.\n- Remaining lambda work - Wave 1 (conversion to Delegate/Expression and attributes) and wave 2 (explicit return types) have been merged. We are currently working on Wave 3 (natural type and synthesized delegate types). Should be in for C# 10.\n\n### Speakable names for top-level statements\n\nWhen we initially shipped top-level statements in C# 9, we made the decision that the type and method that the statements generated should be unspeakable. Our reasoning here was that\nthe only reason the type or method would be needed would be for reflection to obtain the assembly, and users could use another type in the assembly for this. However, as work continues\non the lighter ASP.NET feather templates, we are encountering scenarios where there actually _aren't_ any other types in the user's assembly, which makes obtaining the assembly for\nunit testing very complex. To address this, we considered a mechanism to make the type and method speakable by user code. We have a few main axes of choice for a proposal, several of\nwhich are tied together:\n\n* Introducing a named type into a compilation could break that compilation. Do we want to make it conditional on whether the user already has a type with the name we choose?\n* Do we want to tie generating the type to language version or not?\n* Will we allow the type to be speakable from the current compilation, or only from assemblies that _reference_ the current compilation?\n* Will the type be partial or not?\n* Do we want just the type to be speakable, or the type and the method both?\n* Do we want the type to be public or internal?\n\nFirst, we looked at the breaking change. We believe we would name the type `Program` and the method `Main`, following long C# template tradition, so our real question is \"who is going\nto create a program that is using top-level statements and has a type named `Program`?\". We believe this to be a sufficiently small number of users that we are ok with the breaking\nchange. At the same time, we also looked at whether we should only generate the type when the user's language version is set to the appropriate version, meaning that C# 9 would still\ngenerate an unspeakable name. After some consideration, we don't think that it's worth it to have separate generation strategies, as it will complicate the code for very little chance\nof breaking. It does mean that there is the potential for someone to upgrade the compiler and not the language version and observe a breaking change from a different assembly, but we're\nok with this.\n\nNext, we looked at the various levels of speakability. Only allowing the type to speakable by external assemblies is the minimal change to make, but it feels oddly inconsistent. Similar\nreactions were had for the method name: while we don't have a specific scenario currently for the method naming being speakable, we feel it would simplify the mental model for either\neverything to be speakable, or nothing to be speakable. We've always had the view that top-level statements are simply a sugar over a Main method in some type, and now we solidify\nthat view by adjusting the sugar to this:\n\n```cs\nusing System;\n\nConsole.WriteLine(GetInt());\n\nstatic int GetInt() => 1;\n```\n\ndesugars into:\n\n```cs\nusing System;\n\npartial class Program\n{\n    public static void Main()\n    {\n        Console.WriteLine(GetInt());\n\n        static int GetInt() => 1;\n    }\n}\n```\n\nBy only specifying `partial class`, the type defaults to `internal` visibility, and we allow any other `partial` parts to be explicit about the visibility of the type and change it\nhowever they choose. We will also change the signature of main based on the content, as we already do today with `args` and `await`.\n\n\n#### Conclusion\n\nWe will adopt the above desugaring for top-level statements. This will introduce a break for any programs that have a non-partial `Program` type in the global namespace, or have a\npartial `Program` type in the global namespace that is either not a `class` or defines a method named `Main` if that program is using top-level statements.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-07-19.md",
    "content": "# C# Language Design Meeting for July 19th, 2021\n\n## Agenda\n\n1. [Global using scoping revisited](#global-using-scoping-revisited)\n\n## Quote of the Day\n\n- \"Any guesses on how many tries it took for me to spell that correctly?\" \"Well, you misspelled it.\"\n\n## Discussion\n\n### Global using scoping revisited\n\nhttps://github.com/dotnet/csharplang/issues/3428\n\nThe SDK team is currently considering how and where they will generate default global usings for .NET 6, and we want to take another look at our decisions around the\n[scope of global usings](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-03-15.md#global-usings). Previously, we decided that global usings should\nbe thought of as being copied and pasted into every file, and that there is no separate outer scope for global usings. However, there are some type names that are relatively\ncommon in .NET, such as `Task`, that would likely be part of a default set of SDK global usings (as `using System.Threading.Tasks.Task;` is another way of saying \"Use C# 5\nfeatures please\"). If there is no separate global using scope for these types, however, we'd introduce ambiguities for these types.\n\nThere are a number of complexities to the separate scope idea that would be equally as painful for users, in potentially subtler ways. In particular, extension method lookup\nacross multiple sets of usings can be tricky, and explaining the intricacies of the lookup rules is complicated, even for language designers talking to other language designers.\nThis would hit Linq hard in particular, as `System.Linq` is on the shortlist of default global usings, but users often add their own versions of the extension methods to\ncustomize particular behaviors or performance characteristics for particular scenarios. In these scenarios, users would have to add a manual `using System.Linq;` at the top\nof their files, which is the same problem as we'd be trying to address by having separate scopes in the first place.\n\nWe considered a few compromise positions as well, such as considering global usings to be in the same scope for extension method lookup, but different scopes for type lookup.\nThese are complex, both in terms of implementation and in terms of explaining to users, so we don't think this is a good approach. Instead, we think that we have a good tooling\nstory around name clashes already, and we can strengthen the tooling to be aware of global using clashes and introduce global aliases to solve the issue, which is a fairly simple\nfix for the problem.\n\nFinally, we noted that even if we introduced a separate scope for global usings, this wouldn't even fix the issue permanently. The next request would be a way to separate the\nimplicit usings from the SDK, and the user-created global usings.\n\n#### Conclusion\n\nExisting behavior is upheld.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-07-26.md",
    "content": "# C# Language Design Meeting for July 26th, 2021\n\n## Agenda\n\n1. [Lambda conversion to System.Delegate](#lambda-conversion-to-system-delegate)\n2. [Direct invocation of lambdas](#direct-invocation-of-lambdas)\n3. [Speakable names for top-level statements](#speakable-names-for-top-level-statements)\n\n## Quote of the Day\n\n- \"You just don't want me to have poor man expression blocks\"\n\n## Discussion\n\n### Lambda conversion to System.Delegate\n\nhttps://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/lambda-improvements.md\n\nWe've received a few bug reports from customers on upgrading to a new version of the preview SDK that existing code, targeting .NET 5, was now failing to compile\nbecause code that previously chose an extension method with a strongly-typed delegate type was now binding to an instance method that took a `Delegate` instead.\nWhile this is a break we intended to make, we wanted to revisit it and make sure that we still believed it was appropriate for these cases. While we are still\nwaiting to hear back from these customers as to what their extension method was actually doing, a survey of code on GitHub shows that the vast majority of these\nare what we expected: the extension forwards from a strongly-typed delegate to the `Delegate` instance method. Given this, we believe that our original decisions\naround this feature are still what we were expecting, and that we will keep the behavior for C# 10.\n\nHowever, we are also concerned with not making tooling updates that break our users (beyond bugfixes, such as the ternary type inference issues in C# 9's initial\nrelease). This is code that has been compiling successfully for a decade or more, and we don't want to break it when the user has only updated their version of VS,\nand not actually updated to a new version of .NET (ie, using VS 2022, but still targeting .NET 5 or lower). In order to preserve this, we will bring back our\nworkaround for the 16.10 release, where we changed the binding of this case depending on the current language version. It does mean that there will be a subpar\ntooling experience for upgrades involving this type of code, but we think missing codefixes are better than code that completely stops compiling.\n\n#### Conclusion\n\nWe will keep the current behavior for C# 10. C# 9 and lower will have a different binding behavior, compiling as they used to.\n\n### Direct invocation of lambdas\n\nhttps://github.com/dotnet/csharplang/issues/4748\n\nCurrently, the lambda improvements proposal states that lambdas should be directly invocable. While we think this could fall out for some scenarios, it will not do\nso for all scenarios. For example:\n\n```cs\n(() => {})(); // Infer Action, can be invoked\n(x => x)(1); // Cannot infer a delegate type on its own: would need to take the argument expression into account\n```\n\nWe don't have a strong scenario for this feature at the moment: our best justification for the feature would be as a poor replacement for expression blocks, and we've\nreceived vocal and vociferous feedback from the community on the \"poor\" part of that phrase. We do think it will be odd that lambdas will be able to be assigned to\n`var` and then be invoked/used as instance receivers, but cannot be invoked/used as instance receivers directly, but we believe that if we explicitly block this scenario\nnow, we will adequately preserve our design space to remove this restriction later, if we have a better scenario we want to enable.\n\n#### Conclusion\n\nLambda and method group natural types will only be allowed to surface in specific contexts: `var`, method type inference, determining the best type of a group of types,\nand conversion to `System.Delegate`/`System.Linq.Expressions.Expression`. No direct invocation of lambdas or instance member access on lambda expressions or method groups\nwill be allowed.\n\n### Speakable names for top-level statements\n\n[Two weeks ago](LDM-2021-07-12.md#speakable-names-for-top-level-statements), we made a decision that top-level statements would be sugar for a partial `Program` type in\na `Main` method. However, a [comment on the subsequent discussion](https://github.com/dotnet/csharplang/discussions/4928#discussioncomment-1013469) gave us a separate\nidea that we had not considered in the meeting, and we wanted to bring up the idea: naming the type that contains the top-level statements after the name of the file\nthe statements are in. There are a few wrinkles to this: what if the file name contains characters that are not legal as C# identifiers? Or what if there is no file name,\nand the text was passed directly to the compiler not in a file (as is possible using the Roslyn APIs)? We're also concerned by the fragility of this solution: renaming a\nfile could potentially leave dangling partial types and no longer have methods in scope for the top-level statements. Additionally, C# today does not depend on file\nlayout or structure for programs: file names do not have to line up with type names, and namespaces are entirely unconnected from the physical layout of files. This\nproposal would change that, and we're not sure for the better.\n\nHowever, the idea that we might have a future where we want to combine multiple files, each with top-level statements, into a single program is a distinct possibility.\nAs we move towards the idea of `dotnet run Program.cs`, it's conceivable that a single program might have a few files for different UI stacks (for example, `WebUI.cs`,\n`ConsoleUI.cs`, and `Desktop.cs`), each of which shares a bunch of common files in the same directory. Users would then choose which to run by just saying\n`dotnet run Console.cs`, and all 3 of these UI entrypoint files would be combined into a single program, with the entrypoint selected by the file that was run. Given\nthat our specific ask for the speakability feature is being able to get access to the current Assembly (via `typeof(Program).Assembly`), we think that we can protect\nfuture design space here by only making `Program` speakable, rather than both `Program` and `Main`. This will allow our future selves a space to design this multi-file\nexperience without worrying about having multiple methods named `Main` in the same type, as we will be able to combine these different partial `Program` types into a\nsingle one and name the entrypoints whatever we need to.\n\n#### Conclusion\n\nWe will keep the type name `Program` and make it speakable, but we will not make the `Main` method speakable.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-08-23.md",
    "content": "# C# Language Design Meeting for August 23rd, 2021\n\n## Agenda\n\n1. [Nullability differences in partial type base clauses](#nullability-differences-in-partial-type-base-clauses)\n2. [Top-level statements default type accessibility](#top-level-statements-default-type-accessibility)\n3. [Lambda expression and method group type inference issues](#lambda-expression-and-method-group-type-inference-issues)\n    1. [Better function member now ambiguous in some cases](#better-function-member-now-ambiguous-in-some-cases)\n    2. [Conversions from method group to `object`](#conversions-from-method-group-to-object)\n4. [Interpolated string betterness in older language versions](#interpolated-string-betterness-in-older-language-versions)\n\n## Quote of the Day\n\n- This is the thing that's not weird, so let's handle that\n\n## Discussion\n\n### Nullability differences in partial type base clauses\n\nhttps://github.com/dotnet/csharplang/issues/5107\n\nWe looked at inconsistencies and errors when base and interface clauses differ by nullability today. This is particularly problematic\nfor source generators, as generated files are always `#nullable disable`d by default, and if the author just copied the class header\nover it can cause a compilation error if the original declaration had type parameters and was `#nullable enable`d. The scenarios with\nbase types and interfaces are similar but not identical, as interfaces are allowed to be duplicated in metadata, but base types are not.\nWhile the compiler is resilient to importing types with this duplicate metadata, we're not certain that relaxing anything with regards\nto interface deduplication would be good for the whole ecosystem, as not every tool is written with the same level of error-recovery\nas Roslyn is. We'll need to look more into the interface scenario before making any more changes.\n\nFor base types, the proposal suggests that we report warnings when there are differences between nullable and non-nullable type\nparameters, but not for any other scenario. However, we think that this is a bit too big of an exception. As an example:\n\n```cs\n#nullable enable\npublic partial class Derived : Base<\n    object,\n#nullable disable\n    object\n#nullable enable\n> {}\n\n#nullable enable\npublic partial class Derived : Base<\n#nullable disable\n    object,\n#nullable enable\n    object\n> {}\n```\n\nThe type parameters only differ by obliviousness in this code, but we'd have to do a merge of all the declarations to get the \"true\"\nnullability of all type parameters. We think this is an extremely complex case that gets away from the root of the problem: one\ndeclaration is entirely oblivious. Therefore, a narrower, less complex compromise is to simply say that any entirely-oblivious base\ntype declarations are ignored when checking to see if the nullability of base types on all partial parts matches. This carves out the\nsimple case for source generators, and leaves the complex case for manual authors to get correct.\n\n#### Conclusion\n\nEntirely oblivious base type declarations are ignored when ensuring the nullability of all base type clauses in a partial type match.\n\n### Top-level statements default type accessibility\n\nASP.NET has been testing the changes with [speakable types in top-level statements](https://github.com/dotnet/csharplang/blob/dcbaa815253df779d1ecc206c446c9eb6b059b82/meetings/2021/LDM-2021-07-26.md#speakable-names-for-top-level-statements),\nand some initial feedback has been that, because the default for types in C# is internal, it requires `InternalsVisibleTo` for all test\nprojects. However, we don't think that this case is important enough to complicate the feature: making it `public` by default is different\nthan anything else in C#, and makes it a much more complex feature to specify, explain, and implement. We also think that the likelihood\nis that most test projects are going to need IVT to their original at some point, so we wouldn't be saving much in the long run by making\n`Program` public by default anyway.\n\n#### Conclusion\n\nDecision from the last meeting stands.\n\n### Lambda expression and method group type inference issues\n\nWe looked at issues from https://github.com/dotnet/csharplang/issues/5095. The first item we determined to be an implementation bug before\nthe meeting and skipped it.\n\n#### Better function member now ambiguous in some cases\n\nAnother entry in the continuing saga of breaking changes we're discovering from giving lambdas a natural type is a new way in which functions\nthat were previously unambiguous for lambda expressions are now ambiguous:\n\n```cs\nstatic void F(object obj, Action callback) { }\nstatic void F(int i, Delegate callback) { }\n\n// C#9: F(object, Action)\n// C#10: ambiguous\nF(0, () => { });\n```\n\nThe reason for this is because, in C# 9, the `M(int, Delegate)` overload was not applicable at the call site, and only the `M(object, Action)`\nwas. However, with lambda expressions now having a natural type and being convertible to `Delegate`, we have 2 applicable overloads, with the\nfollowing conversions:\n\n* `M(object, Action)`: implicit boxing numeric conversion from `int` to `object`, identity conversion from `Action` to `Action`.\n* `M(int, Delegate)`: identity conversion from `int` to `int`, implicit reference conversion from `Action` to `Delegate`.\n\nNeither of these sets of conversions is better than the other, so the method is now ambiguous. This was reported from ASP.NET, as they have\nan unfortunate set of shipped methods that can hit this problem:\n\n```cs\nstatic class AppBuilderExtensions\n{\n    public static IAppBuilder Map(this IAppBuilder app, PathSring path, Action<IAppBuilder> callback) => app;\n}\nstatic class RouteBuilderExtensions\n{\n    public static IRouteBuilder Map(this IRouteBuilder routes, string path, Delegate callback) => routes;\n}\n```\n\nwhere both `IAppBuilder` and `IRouteBuilder` are defined on `WebApp` instances. When a user calls `app.Map(\"sub\", (IAppBuilder b) => {})`, this\nis now ambiguous because each overload has 2 implicit non-identity conversions and 1 identity conversion, and the overloads are ambiguous.\n\nWe note, however, that these overloads are _already_ ambiguous if, instead of passing a method group or a lambda expression, the user instead\npasses a variable of type `Action<IAppBuilder>`, with the same ambiguity. There is also a fairly easy workaround for ASP.NET, as they can add a\nmost-specific extension method of `Map(this IAppBuilder, string, Action<IAppBuilder>)`, which will have 2 identity conversions and 1 reference\nconversion, making it more specific than the other two. We think this is a fine workaround, especially since this API is already ambiguous in\nmany cases, and will not be making any changes here.\n\n##### Conclusion\n\nNo changes.\n\n#### Conversions from method group to `object`\n\nAllowing method groups to be convertible to `object` has a potentially deleterious effect on this simple scenario:\n\n```cs\nstatic object GetValue() => 0;\nobject o = GetValue;\n```\n\nIn C# 9, the user would get an error stating that method groups cannot be converted to `object`. In C# 10, this is legal code and will compile.\nHowever, we think the likelihood of this being intentional is much lower than the likelihood of it being a mistype. We have a few options for\naddressing this:\n\n- Require an explicit cast to object for such cases.\n- Let an analyzer detect this case.\n- Accept it as is.\n- Have the compiler warn for this case.\n\nWe think that hard-requiring a cast to `object` is too prescriptive here, as this code is legal and well-formed. However, we also think that\neither leaving it as is or leaving it to some other analyzer to detect this case is not ideal either. Given that, we think we should warn when\na method group is _implicitly_ converted to `object`. Suppressing the warning via an explicit cast or via a standard warning suppression\nmechanism should be enough to ensure that there is clarity for these cases.\n\n##### Conclusion\n\nThe compiler will warn on implicit method group conversions to `object`.\n\n### Interpolated string betterness in older language versions\n\nhttps://github.com/dotnet/roslyn/issues/55345\n\nFinally today, we looked at a bug reported by a user when upgrading the compiler and target framework, but setting `LangVersion` back to 9 or\nearlier. This causes an error for common calls such as `stringBuilder.Append($\"\")`, as they now pick the interpolated string handler overload\ninstead of the string overload, which then causes a language version error. We solved this similarly to how we dealt with lambda expressions,\nwhere we made the better conversion code conditional on whether the language version supported interpolated string handlers. LDM had no issues\nwith this decision.\n\n#### Conclusion\n\nDecision upheld.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-08-25.md",
    "content": "# C# Language Design Meeting for August 25th, 2021\n\n## Agenda\n\n1. [Interpolated string handler user-defined conversion recommendations](#interpolated-string-handler-user-defined-conversion-recommendations)\n2. [Interpolated string handler additive expressions](#interpolated-string-handler-additive-expressions)\n\n## Quote of the Day\n\n- \"Let's have a bio break until next Monday\" [LDM proceeds to end an hour early]\n\n## Discussion\n\n### Interpolated string handler user-defined conversion recommendations\n\nhttps://github.com/dotnet/csharplang/issues/5077\n\nWe think the scenarios such a recommendation would serve are extremely small, as we don't expect the vast majority of users to use handler types directly. Instead,\nthey will create interpolated string literals and the compiler will generate the handlers for the user. Additionally, while there's often not much protection, we're\nconcerned that some cases without `string` overloads for methods would cause forgetting a `$` to have unintended behavior, particularly when combined with other\noperators such as `+`.\n\n#### Conclusion\n\nRecommendation rejected. We will not make strong statements on whether users should define implicit conversions from `string`.\n\n### Interpolated string handler additive expressions\n\nhttps://github.com/dotnet/csharplang/issues/5106\n\nThe root of this question is how we apply order of operations and the associative and commutative properties to parenthesized interpolated string addition expressions.\nFor example, given the following code: `$\"....\" + ($\"....\" + $\"....\")`, order of operations would suggest that we evaluate the components of part 1, then part 2, then\npart 3. Then we combine parts 2 and 3, and finally combine the results of 1 with the results of 2+3. Interpolated string handlers can't operate in this \"combine the\nlatter bits then prepend the former\" mode. However, by the same token the side effects of this combination are mostly unobservable, and we're very leary of having\nparentheses be ok in some scenarios but not in others. This means that we have 2 options:\n\n1. Make parentheses always break the magic. A parenthesized interpolated string is just a string.\n2. Make parentheses not matter. An expression composed only of additive expressions, interpolated string expressions, and parenthesized expressions counts as single\ninterpolated string for the purposes of handler conversions.\n\nOption 1 forces us to try and answer awkward questions such as \"What does `CustomHandler c = ($\"\" + $\"\");` mean?\", and we don't like how it makes parentheses less\ntransparent than they are currently. Therefore, we'll go with option 2. As part of this, we'll also allow nullable suppression operators to be interspersed, as they\nare similarly \"transparent\" and shouldn't have any impact on the final code.\n\n#### Conclusion\n\nAllow parentheses and nullable suppression operators anywhere in the interpolated string additive expression chain.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-08-30.md",
    "content": "# C# Language Design Meeting for August 30th, 2021\n\n## Agenda\n\n1. C# 11 Initial Triage\n    1. [Generic attributes](#generic-attributes)\n    2. [`field` keyword](#field-keyword)\n    3. [List patterns](#list-patterns)\n    4. [Static abstracts in interfaces](#static-abstracts-in-interfaces)\n    5. [Declarations under `or` patterns](#declarations-under-or-patterns)\n    6. [Records and initialization](#records-and-initialization)\n    7. [Discriminated unions](#discriminated-unions)\n    8. [Params `Span<T>`](#params-spant)\n    9. [Statements as expressions](#statements-as-expressions)\n    10. [Expression trees](#expression-trees)\n    11. [Type system extensions](#type-system-extensions)\n\n## Quote(s) of the Day\n\n- \"Any proposals for a prioritization strategy?\"\n- \"I'm not going to run a ranked choice algorithm in real time\"\n- \"By small, I mean large\"\n- \"Even Midori wasn't crazy enough to put ref and out into the type system\" \"Maybe that's what went wrong\"\n- \"If you're using ref fields for something other than performance, come talk to me and we can find you help\"\n\n## Discussion\n\nToday, we start our _initial_ triaging passes for C# 11. It's important to note that, while we talked about a number of potential features for\nthis cycle, it's extremely unlikely we'll be able to get to all of them. These triage sessions are a good way to see what the LDM is currently\nthinking about, but please don't try to speculate about what's in or out of C# 11 from them. We don't even know that yet.\n\n### Generic Attributes\n\nhttps://github.com/dotnet/csharplang/issues/124\n\nWe're shipping this in preview in C# 10 because we found a number of late-breaking incompatibilities with other tools. C++/CLI will straight-up\ncrash if it encounters an assembly with a generic attribute, even if the type with the attribute is entirely unused, and they're not the only\ntool with issues. We'll need to work with them and others to make sure the ecosystem won't crash around generic attributes before we can remove\nthe preview flag.\n\n### `field` keyword\n\nhttps://github.com/dotnet/csharplang/issues/140\n\nDidn't quite have time for this in 10. Let's get it done!\n\n### List patterns\n\nhttps://github.com/dotnet/csharplang/issues/3435\n\nWe have a syntactic design and semantic design for arrays and indexable types, but we will need to some more work for `IEnumerable` support.\nWe hope to have an initial preview soon into the C# 11 development cycle to help get user feedback on the design choices we've made so far.\n\n### Static abstracts in interfaces\n\nhttps://github.com/dotnet/csharplang/issues/4436\n\nWe'll need to look through the feedback consumers give us on the initial preview. We already know that CRTP (ie, `INumeric<T> where T : INumeric<T>`)\nmight be better served with `this` type constraint, and if we do want to have such a constraint we'll want it now so that the generic math\ninterfaces can use it where appropriate.\n\n### Declarations under `or` patterns\n\nhttps://github.com/dotnet/csharplang/issues/4018\n\nThis is one of our more common pattern complaints. Let's try and get this done.\n\n### Records and initialization\n\nWe have a number of topics around both records and initialization:\n\n1. Required properties\n2. Final initializers\n3. Factories\n4. Primary constructors\n5. Public init fields\n6. Immutable collection initializers\n7. Combined object and collection initializers\n8. Nested properties in with-exprs\n9. Event hookup in object initializers\n\nWe'll look at triaging this list in the next meeting.\n\n### Discriminated unions\n\nhttps://github.com/dotnet/csharplang/issues/113\n\nThere is a ton of interest in this, both within the LDM and in the wider community. At the same time, this is a potentially broad topic, broader\nthan records, and we have not yet done the work to fully explore the space and break things into individual parts that can combine into a bigger\nwhole like we did with records. We'll need to start that now if we ever want to ship something in this space (and we do).\n\n### Params `Span<T>`\n\nhttps://github.com/dotnet/csharplang/issues/1757\n\nThis was initially going to be part of the improved interpolated strings proposal, but that feature grew and pushed this part out of scope. We'll\nneed to work together with the runtime on this to make sure that we're stackalloc'ing where possible but not unnecessarily blowing out stacks. It\nmight also call for being able to stackalloc an array of reference types.\n\n### Statements as expressions\n\nhttps://github.com/dotnet/csharplang/issues/3086\n\nWe see potential for smaller features here that we can ship one at a time, leaving design priority for other features.\n\n### Expression trees\n\nhttps://github.com/dotnet/csharplang/discussions/4727\n\nHistorically, our inability to improve this space has been because of concern about breaking our customers. However, recent discussions between\nEF and members of the LDT have us encouraged, and we plan to look at this.\n\n### Type system extensions\n\nThere are a number of type system improvements we could look at, from large changes like roles and extension everything to smaller things such as\nunifying our story around `Task` and `Task<T>`/`Action` and `Func`/etc. This last thing would require some kind of unit-type, and `void` is the\nobvious choice as it's already the return type of nothing-returning methods. Maybe we could work with the BCL to unify these types and make them\ntransparent? We could also look at generic improvements around other restricted types, such as pointers and ref structs.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-09-01.md",
    "content": "# C# Language Design Meeting for September 1st, 2021\n\n## Agenda\n\n1. [Lambda expression conversions to `Delegate`](#lambda-expression-conversions-to-delegate)\n2. [C# 11 Initialization Triage](#c-11-initialization-triage)\n    1. [Required properties](#required-properties)\n    2. [Primary constructors](#primary-constructors)\n    3. [Immutable collection initializers](#immutable-collection-initializers)\n\n## Quote(s) of the Day\n\n- Starting the meeting with 11 minutes of technical issues\n- \"In my next language, no users\"\n- \"Has anyone made that companion book? Javascript, The Terrible Bits\"\n- \"Do we actually want to do this feature because customers are asking for it, or do we just think it's interesting as an LDM?\"\n\n## Discussion\n\n### Lambda expression conversions to `Delegate`\n\nhttps://github.com/dotnet/csharplang/issues/5124\n\nToday, we do not allow lambdas without a natural type to be convertible to `Delegate` or `Expression`. This can lead to niche but possible\ncases where _adding_ type information to a lambda actually makes a method call ambiguous, where the typeless lambda was unambiguous. These\ncases, however, are both niche and usually fixable by adding a new, most-specific overload, as we discussed in the notes\n[last week](LDM-2021-08-23.md#better-function-member-now-ambiguous-in-some-cases). Making a change here would also break APIs where the\nuser has an instance method that takes a `Delegate` (often not defined in their code) and adds extension methods with strongly-typed delegates\nto add the necessary information for the compiler to bind their lambdas. This is a fairly common pattern when working with a `Delegate` API,\nand despite making the language more complex and having weird consequences for niche cases, we think that keeping the existing rule as it is\nthe appropriate compromise to keep existing code working. While we don't think that we would have this complex of a rule if we were redesigning\nthe language, we also think that we've hit the limit of breaking changes we'd want to take in this feature.\n\n#### Conclusion\n\nWe'll keep the conversion rules as they are.\n\n### C# 11 Initialization Triage\n\nContinuing from [last meeting](LDM-2021-08-30.md), we're triaging potential C# 11 features, this time specifically around initialization\nand records. The same disclaimer from last time applies: this is _early_ triage. Please do not try to infer what will be in C# 11 or not from\nthese notes. If we don't know the answer to that, these notes won't help you find it either 🙂.\n\nThe general list of initialization and record related topics is as follows:\n\n1. Required properties\n2. Final initializers\n3. Factories\n4. Primary constructors\n5. Public init fields\n6. Immutable collection initializers\n7. Combined object and collection initializers\n8. Nested properties in with-exprs\n9. Event hookup in object initializers\n\nOf these, we can subdivide them into a few sets of categories:\n\n* Truly new features that enable a new type of expressiveness that doesn't exist today. This is 1, 2, 3, and 6.\n* Features that build off of others, either in this list or already in the language. This is 4 and 5.\n* Features that solve pain points in existing features. This is 7, 8, and 9.\n\nOf these, there are a few that stand out as being features we're more interested in: required properties, primary constructors, and immutable\ncollection initializers.\n\n#### Required properties\n\nhttps://github.com/dotnet/csharplang/issues/3630\n\nWe did a big design push on this a little under a year ago. We should revive the proposal, make the changes we talked about at the end of\nthe last design review, and see what we think about it now.\n\n#### Primary constructors\n\nhttps://github.com/dotnet/csharplang/issues/2691\n\nWe've had a few designs for primary constructors over the years. C# 6 nearly shipped with one design, then we shipped records with a design,\nand now we need to think about how primary constructors will interact with record/class cross inheritance when we get to that. We really need\nto come back with a new proposal that looks at the past versions, and that may well be next year.\n\n#### Immutable collection initializers\n\nThis is an idea we've been ruminating on as we designed the syntax for list patterns: we've given up on trying to make the correspondence\nprinciple work with the existing collection initializer syntax, but we could potentially make the principle work by design a new collection\nliteral syntax, one that will work with immutable types as the current one does not. A smaller group will look at this and make a proposal\nfor the space.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-09-13.md",
    "content": "# C# Language Design Meeting for September 13th, 2021\n\n## Agenda\n\n1. [Feedback on static abstracts in interfaces](#feedback-on-static-abstracts-in-interfaces)\n\n## Quote(s) of the Day\n\n- \"Computer math never equals real math, it never does\"\n- \"If we add default interface methods to LINQ, we get dim sum.\"\n\n## Discussion\n\nhttps://github.com/dotnet/csharplang/issues/4436\n\nToday, we looked at some of the initial feedback we've gotten on both static abstracts in interfaces and generic math from our blog posts and on our design issues.\nSome of the channels we looked at:\n\n* https://github.com/dotnet/csharplang/issues/4436\n* https://github.com/dotnet/designs/pull/205\n* https://devblogs.microsoft.com/dotnet/preview-features-in-net-6-generic-math/\n* https://www.reddit.com/r/csharp/comments/p20xap/preview_features_in_net_6_generic_math/\n* https://www.reddit.com/r/dotnet/comments/p20jlc/preview_features_in_net_6_generic_math/\n* https://www.reddit.com/r/programming/comments/p20j22/preview_features_in_net_6_generic_math/\n* https://twitter.com/tannergooding/status/1425223277941719040?s=20\n* https://twitter.com/dotnet/status/1428127070530514944?s=20\n\nWe've also had discussion on our various other platforms not so easily directly linked, such as the C# community discord (https://discord.gg/csharp), email, and \nother similar informal chats. Overall, we're pleased to see both the number of people looking at the feature, and that their reactions to the feature are overwhelmingly\npositive. We also received a good deal of concrete feedback we can examine to see what, if anything, we should change or improve about the feature before shipping for\nreal with .NET 7.\n\n### Keyword confusion\n\nSome users didn't immediately connect the idea of `static` and `abstract`, and suggested that we might want to consider a new keyword specifically for this concept.\nHowever, we think this is another case of initial reactions wanting new features to stand out. This is particularly exacerbated because `abstract` is not used in\ninterfaces today, but is required here. Despite that, we intend to keep the keywords the way we have them: even if we introduced something special for interfaces,\nwe'd want to use `static abstract` in classes when we support defining such methods there.\n\n### Traits/Shapes/Roles\n\nSome of the feedback has been about asking us to go further, into traits/shapes/roles/type expansion du jour. This is only natural: static abstracts represents a major\nnew expressive ability in C#, and these types of expansions are the logical next step. While the feature we're currently working is not going to address those requests,\nwe by no means are done in this space, and will continue to explore more enhancements we can make in this space.\n\n### Missing types\n\nWe didn't get to implementing the generic math interfaces on all types that would benefit from them in .NET 6, such as `BigInteger` or `Vector2/3/4`. We plan to expand\nour implementations on these interfaces with .NET 7 to cover more types.\n\n### Direct parsing support in INumber\n\nSome users have expressed a sentiment that proper mathematical numbers don't necessarily have serialization/deserialization as a concept, and thus asked for INumber to\nnot include those concepts in the extended interface set. This will be a question for the runtime API reviewers to think on.\n\n### Self types\n\nOf the biggest pieces of feedback we've gotten is around confusing on type constraints. In particular, users expect calls like `IParsable<double>.Parse(\"123\", null)` to\nwork, but because of the way we've implemented the type constraints currently, the language cannot understand that `double` is the type that `Parse` needs to be constrained\nto. We can solve issues like this by implementing a self type, which will also just be a generally-useful feature for the language. We're positive about the feature, but\nit is going to need a decent amount of design work. In particular, there are interfaces such as `IEquatable<T>` that have been in C# since C# 2.0, and we need to think about\nif we want to be able to apply such a constraint to those interfaces, how that would work, and what level of breaking change it would be. There is also syntax to be worked\nout, which makes for everyone's favorite LDMs.\n\n### DIMs for static abstracts\n\nWe consider the ability to have a DIM for static virtual members a must-have for v1, as we'll need it for versioning, and potentially some of the initial implementation will\nwant to be a DIM instead of being required to be implemented by users.\n\n### `static abstract`s in classes\n\nThe ability to declare `static abstract` members in classes will almost certainly be in the runtime for .NET 7. However, we don't consider it as important of a ship-blocker\nas the DIM feature, so it might have less priority than other C# 11 features.\n\n### Checked operators\n\nhttps://github.com/dotnet/csharplang/issues/4665\n\nWe think this operator is likely important for semantic correctness in generic math. It's a niche case, and we may want to use the afformentioned DIMs to forward the checked\nimplementation to unchecked, but that will be a decision for the runtime API design team.\n\n### Relaxing shift operator requirements.\n\nhttps://github.com/dotnet/csharplang/issues/4666\n\nOur thoughts on this proposal have not changed since the [last time](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-05-19.md#relaxing-shift-operator-requirements)\nwe looked at it.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-09-15.md",
    "content": "# C# Language Design Meeting for September 15th, 2021\n\n## Agenda\n\n* [Feedback from the C# standardization committee](#feedback-from-the-c-standardization-committee)\n* [Permit pattern variables under disjunctive patterns](#permit-pattern-variables-under-disjunctive-patterns)\n\n## Quote of the Day\n\n- \"We've so far decided not to decide\"\n\n## Discussion\n\n### Feedback from the C# standardization committee\n\nhttps://github.com/dotnet/csharpstandard/issues/366\n\nFor the first half of today's LDM, we had a guest from the C# standardization committee on to talk about the ongoing process by TC-49\nto produce an update to the ECMA C# specification, the latest version of which covers C# 5. In the csharplang repository, we currently\nhave an initial conversion of an internal Microsoft C# specification of C# 3, which was updated to cover some aspects of C# 6. The ECMA\nteam has converted the C# 5 specification to markdown, and is currently working to integrate the changes from our C# 6 spec into that\nversion.\n\nThese dual versions of the specification can confuse users. The language reference on Microsoft Docs comes from the csharplang\nversion of the spec, but the TC-49 version of this specification has had a number of bug fixes and is a better markdown conversion overall.\nBecause of this the csharplang version of the spec gets occasional pull requests to update various things, from English spelling and\ngrammar issues to actual spec bugs, but many times those issues have already been fixed in the TC-49 version of the specification. To\naddress this, we plan to remove the csharplang version of the specification when the last PRs for C# 6 are merged into the csharpstandard\nrepo, which should hopefully be soon.\n\nAdditionally, the standardization committee has draft PRs out for most C# 7 features, and is working on C# 8 specifications as well.\nCurrently, when they run into questions they've been emailing a few specific compiler team members, who hopefully can either answer their\nquestions or forward to the right team member. To facilitate better interactions, we've created an internal alias with the compiler team,\nthe language design team, and the TC-49 members currently working on the draft specifications. The specification changes for C# 8 are big,\nparticularly with nullable reference types, and will require close collaboration between these groups to make sure the spec actually reflects\nthe feature that was implemented by the compiler team.\n\nFinally, we did some thinking about how to collaborate moving forward on new language features. We'd like to think about maintaining proposals\nas branches on the TC-49 specification, to make sure that we are considering the real specification when we think about new language features\nand ensuring that we can see other proposed changes to the specification as a whole when making new features, as opposed to having to remember\nwhat not-yet-specified proposal from a previous language version modified a particular section of the specification while designing a new\nchange to that section.\n\n### Permit pattern variables under disjunctive patterns\n\nhttps://github.com/dotnet/csharplang/issues/4018\n\nWe took a first pass over this proposal in the second half of the LDM. At first brush, there are a couple of major points of contention:\n\n1. Should we allow redeclaration, or should we have some form of `into` pattern that would allow the reuse of an existing variable in\na pattern?\n2. Is variable declaration across multiple expressions ok, or should it only be permissible within a single pattern?\n\nPoint 1 arises from potential confusion around the double declaration: will users find the multiple declarations intuitive, or will they\nwonder about \"which\" of the pattern variables future usages refer to? We've also had requests for an `into` pattern in the past, that would\nallow a pattern to assign into an existing variable. We're concerned about a generalized version of this pattern because it could have\nunpredictable effects, particularly when combined with `when` clauses, but a more specialized version that can only use variables declared\nin the same pattern could be a usable version of this proposal. We also want to think about how this would interact with any potential\npattern matching over types themselves in the future, such as extracting the `T` from an `IEnumerable<T>`: if such a thing could be done,\nit should be doable under an `or` as well, and we will want to have similar syntax forms for redeclaration as here. We also need consider\nhow an `into` pattern or other form of assignment syntax would interact if we ever want to permit non-constants to be used as a pattern\nthemselves.\n\nFor point 2, we're concerned about the potential large impact throughout the language. This would be very similar to permitting a\ngeneralized `into` pattern, where `when` clauses can cause otherwise-matching patterns to not be executed and reassign existing variables.\nSeveral members of the LDM feel that we should tackle just within a single expression first, and consider multiple expressions at a later\ntime with more examples of the types of code it would enable.\n\n#### Conclusions\n\nNo conclusions today. We want to see the specification PR updated with more motivating samples, including samples from real code, before\nwe make any conclusions on these issues.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-09-20.md",
    "content": "# C# Language Design Meeting for September 20th, 2021\n\n## Agenda\n\n1. [Lambda breaking changes](#lambda-breaking-changes)\n2. [Newlines in non-verbatim interpolated strings](#newlines-in-non-verbatim-interpolated-strings)\n3. [Object initializer event hookup](#object-initializer-event-hookup)\n4. [Type alias improvements](#type-alias-improvements)\n\n## Quote of the Day\n\n- \"You're kicking in an open door\"\n\n## Discussion\n\n### Lambda breaking changes\n\nhttps://github.com/dotnet/roslyn/pull/56341\n\nIn the ever continuing saga of new breaking changes introduced by giving method groups and lambda expressions natural types, we looked\nat a few new breaking changes today to decide what, if any, workarounds we should adopt to try and fix them.\n\n#### Breaking changes around overload resolution\n\nhttps://github.com/dotnet/roslyn/issues/55691  \nhttps://github.com/dotnet/roslyn/issues/56167  \nhttps://github.com/dotnet/roslyn/issues/56319  \nhttps://github.com/dotnet/csharplang/discussions/5157  \n\nWe have a number of reports from users who have been broken by changes in overload resolution, mostly because a set of overloads that\nused to succeed in overload resolution are now ambiguous. A smaller group met to discuss a number of different potential solutions to\nthe issue. These options were:\n\n1. Leave the breaking changes as-is.\n2. Change “method type inference” and “best common type” to not infer from the natural type of a lambda expression or method group.\n3. Change “better function member” to treat delegate types with identical signatures as equivalent, allowing tie-breaking rules to apply.\n4. Change “better function member” to prefer overloads where method type inference did not infer type arguments from the natural types\nof lambdas or method groups.\n5. Change “better function member” to prefer parameter types that are delegate types other than those used for natural type. (Prefer `D`\nover `Action`.)\n6. Change “better function member” to prefer argument conversions other than “function type” conversions.\n7. Change “better function member” to prefer parameter types `D` or `Expression<D>` over `Delegate` or `Expression`, where `D` is a delegate type.\n\nDiscussion further narrowed our focus to two combinations of the above options: 3+7 or 4+6. 3+7 results in a more aggressive break, while\n4+6 is more compatible with previous versions of C#. Given the extent of some of the breaks we're seeing, we think the more compatible\napproach is the better way to go, so we'll proceed with the PR linked at the start of this section.\n\n##### Conclusion\n\nOptions 4+6 accepted.\n\n#### Method groups converting to `Expression`\n\nAnother break testing has revealed looks like this:\n\n```cs\nvar c = new C();\nc.M(F); // C#9: E.M(); C#10: error CS0428: Cannot convert method group 'F' to 'Expression'.\n\nstatic int F() => 0;\n\nclass C\n{\n    public void M(Expression e) { Console.WriteLine(\"C.M\"); }\n}\nstatic class E\n{\n    public static void M(this object o, Func<int> a) { Console.WriteLine(\"E.M\"); }\n}\n```\n\nWe think we would have a solution for this: split our \"function type conversion\" into two separate conversion types: a function type\nconversion from lambda, and a function type conversion from method group. Only the former would have a conversion to Expression. This\nwould make it so that `M(Expression)` is not applicable if the user passed a method group, leaving only `M(object, Func<int>)`. This\ncould be a bit complex, but it should resolve the issue.\n\nUnlike the previous examples, however, we don't have any reports of this issue. Given the number of reports of the previous breakages\nwe've received, and the lack of reports for this issue, we tentatively think that it's not worth fixing currently. If, after we ship\nC# 10 for real, we received reports of this break, we know how to fix it and can change course at that time without making a breaking\nchange.\n\n##### Conclusion\n\nNo changes will be made.\n\n#### Lambdas in OHI\n\nA final break we looked at today is:\n\n```cs\nusing System;\n\nB.F1(() => 1); // C#9: A.F1(); C#10: B.F1()\nvar b = new B();\nb.F2(() => 2); // C#9: A.F2(); C#10: B.F2()\n\nclass A\n{\n    public static void F1(Func<int> f) { }\n    public void F2(Func<int> f) { }\n}\nclass B : A\n{\n    public static void F1(Delegate d) { }\n    public void F2(Delegate d) { }\n}\n```\n\nThis is standard OHI behavior in C#, but because the derived overloads were previously not applicable, they were not included in the\n`B.F1` or `b.F2` method groups, and only the methods from `A` would be applicable. Now that methods from the more derived type are\napplicable, methods from the base type are filtered out by method group resolution.\n\nWe think this is both fine and actually desirable behavior. We don't have contravariant parameters in C#, but this is effectively\nacting like such, which is a good thing. This change is also not customer-reported, but was instead discovered in testing. Given the\ndesirable behavior and lack of reports, we think no change is necessary.\n\n##### Conclusion\n\nNo changes.\n\n### Newlines in non-verbatim interpolated strings\n\nhttps://github.com/dotnet/csharplang/issues/4935\n\nWe have a lot of compiler complexity around ensuring interpolated strings do not have a newline in them, and we don't see a real\nreason to forbid newlines. We think the origin might have come from the number of different design flip-flops we made on interpolated\nstrings during their initial design.\n\n#### Conclusion\n\nLanguage change approved.\n\n### Object initializer event hookup\n\nhttps://github.com/dotnet/csharplang/issues/5176\n\nLDM is not only interested in this change, we're also interested in generalized improvements that can be made in object initializers\nand with expressions. Compound assignment is interesting, particularly in `with` expressions, and we would like to see what improvements\nwe could make not just for events, but for all types of properties and fields.\n\n#### Conclusion\n\nApproved. We want to explore even more enhancements in this space.\n\n### Type alias improvements\n\nhttps://github.com/dotnet/csharplang/issues/4284\n\nFinally today, we looked at one of the open questions in this proposal: how should we handle nullable types in using aliases when the\nalias is used in a `#nullable disable` location.\n\nThere are largely 2 ways to view using aliases:\n\n1. Syntactic substitutions: the compiler is literally copy/pasting the thing in the alias into the target location. In this view, the\ncompiler should treat the syntax as occuring at the use point, and warn based on that.\n2. Semantic substitutions: the using alias is effectively defining a new type. It's not a truly different type, but only the meaning\nis substituted, not the actual syntax. If we ever want to consider a way to export using aliases, this will be a useful meaning to assume.\n\nWe also have some (possibly unintended) prior art here: `using MyList = System.Collections.Generic.List<string?>;` takes the second\napproach today, acting like a semantic substitution.\n\nThe one thing we still want to consider in this space is top-level nullability. We're not sure about allowing a type alias to have\ntop-level nullability when it's an alias to a reference type. There is (very intentionally) no extra C# syntax for \"not null reference\ntype\" beyond the lack of a `?`, and the next ask if we were to allow aliases to be top-level nullable would be for such a syntax.\n\n#### Conclusion\n\nOverall, we like the semantic meaning. We still need to consider whether aliases should be allowed to have top-level nullability.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-09-22.md",
    "content": "# C# Language Design Meeting for September 22nd, 2021\n\n## Agenda\n\n1. [Open questions in list patterns](#open-questions-in-list-patterns)\n    1. [Breaking change confirmation](#breaking-change-confirmation)\n    2. [Positional patterns on ITuple](#positional-patterns-on-ITuple)\n    3. [Slicing rules](#slicing-rules)\n    4. [Slice syntax recommendations](#slice-syntax-recommendations)\n    5. [Other list pattern features](#other-list-pattern-features)\n2. [Nested members in `with` and object creation](#nested-members-in-with-and-object-creation)\n3. [CallerIdentityAttribute](#calleridentityattribute)\n4. [Attributes on `Main` for top level programs](#attributes-on-main-for-top-level-programs)\n\n## Quote of the Day\n\n- \"That's not just our normal passive aggressive shtick, it's just actively aggressive.\"\n\n## Discussion\n\n### Open questions in list patterns\n\nhttps://github.com/dotnet/csharplang/issues/3435  \nhttps://github.com/dotnet/csharplang/issues/5201\n\n#### Breaking change confirmation\n\nFirst, we looked at the breaking change for `Length`/`Count` on indexable and countable types. We're a bit concerned about making this\ncase a generalized error, even when a list pattern isn't being used: there are potential use cases for a `Length` that returns negative,\nsuch as some object modeling a physics concept. We think we'd like to try and downgrade this to a warning instead of an error, for the\nspecific case where a negative length is tested and the location wasn't already subsumed. Some examples:\n\n```cs\nx is { Length: -1 } // Warning, not subsumbed by any previous case\nx is { Length: >=0 } // Considered Exhaustive\nx is { Length: <5 or -1 } // Error on the -1, subsumed by <5. No warning on the <5.\n```\n\n##### Conclusion\n\nTry to make it a warning for non-subsumed cases.\n\n#### Positional patterns on ITuple\n\nCurrently, we've implemented subsumption rules that allows list patterns and `ITuple` positional patterns to understand they refer to\nthe same alias. However, we think that this results in weird interactions with regular `ValueTuple` instances. `ValueTuple`s explicit\nimplement `ITuple`'s properties, so when pattern matching on one they would not be considered indexable or countable unless boxed into\n`ITuple`. This would mean that, unless we were to make `ValueTuple` special in list patterns, there wouldn't be the same correspondence\nas `ITuple` has. We also don't think that, in general, `Deconstruct` implies an order for an indexer: other than for `ITuple`, these\nseem to be unrelated concepts.\n\n##### Conclusion\n\nThere will be no correspondence between positional patterns and list patterns, even for ITuple. If someone comes along with a killer\nscenario for ITuple later, we can readd this.\n\n#### Slicing rules\n\nThese rules, as stated, matches our previous discussions on the topic.\n\n##### Conclusion\n\nNo changes.\n\n#### Slice syntax recommendations\n\nWe have two general choices for the slice pattern:\n\n```cs\ne is [ first, .. var rest ] // Space\ne is [ first, ..var rest ] // No space\n```\n\nWe feel that the code reads oddly without the leading space because the pattern being applied itself has a space. It introduces an odd\nfeeling of `(..var) rest`, even though the code is really `.. (var rest)`.\n\n##### Conclusion\n\nWe're in favor of having a space.\n\n#### Other list pattern features\n\nFor `IEnumerable` patterns, we'd like to introduce them at the same time as the rest of the list pattern feature, even if in a more\nlimited form, to ensure we avoid any potential breaking changes. They may go to preview at different times, and we may need to section\noff some of the pattern features to ensure we can ship, but we'd like to at least have an initial version. We also do want to make\nsure that we're generating as good code for this as possible, which may overlap some with params Span work to see whether we can\nstackalloc.\n\nFor indexer patterns, we are interested, but they don't need to be this version of C#. We do think that we'll want them in the near\nfuture though: we have lists, we should also be able to have dictionaries.\n\nFor length patterns, we're not seeing the need. We explored them previously and the exploration seems to have concluded that they might\nbe needed for IEnumerable, but if so we can revisit as we look at IEnumerable again.\n\n### Nested members in `with` and object creation\n\nhttps://github.com/dotnet/csharplang/issues/4587\n\nWe like the concept of reducing the boilerplate for nested with patterns. However, we're not a fan of the strawman syntax. Multiple members\nof the LDM misinterpreted it as modifying the nested instance, rather than doing a `with` on the nested property. It would also fall over\nif multiple properties on a nested instance need to be set. We have a couple of initial ideas:\n\n```cs\nmethodCallExpression with { Method with { Name = \"MethodName\", BaseType = \"C\" } }\nmethodCallExpression with { Method = { Name = \"MethodName\", BaseType = \"C\" } } // more similar to nested object initializer?\n```\n\n\n#### Conclusion\n\nInto the working set, with some syntax modifications.\n\n### CallerIdentityAttribute\n\nhttps://github.com/dotnet/csharplang/issues/4984\n\nMostly a convenience feature for ASP.NET which will help them structure code in a way more conducive to AOT. It seems in line with our\nexisting caller info attributes, so we'll work with the BCL and ASP.NET teams to prioritize the issue.\n\n#### Conclusion\n\nInto the working set.\n\n### Attributes on `Main` for top level programs\n\nhttps://github.com/dotnet/csharplang/issues/5045\n\nWe do think there needs to be some design work: the feature proposes allowing the `main` modifier in any file. We need to decide whether\nthat's a use case we want to support, and if we do, whether we should allow the target with regular entry points or only with top level\nstatements. If we allowed it with any entry point, we think there are some decent engineering challenges with the way the language is\ncurrently structured that would make it more complex than first blush might indicate. Some form of this feature seems reasonable though,\nso we'll work with the BCL to determine the right scope of the feature.\n\n#### Conclusion\n\nInto the working set.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-10-13.md",
    "content": "# C# Language Design Meeting for October 13th, 2021\n\n## Agenda\n\n1. [Revisiting DoesNotReturn](#revisiting-doesnotreturn)\n2. [Warning on lowercase type names](#warning-on-lowercase-type-names)\n3. [Length pattern backcompat](#length-pattern-backcompat)\n\n## Quote of the Day\n\n- \"You're opinionated against opinionated features\" \"I see the irony, but...\"\n\n## Discussion\n\n### Revisiting DoesNotReturn\n\nhttps://github.com/dotnet/csharplang/issues/5231\n\nWe wanted to revisit this design decision after a few years and some reports of customer confusion around this attribute.\nWhile it's not an overwhelming amount of confusion, it's non-zero. When last this attribute was\n[discussed](../2019/LDM-2019-07-10.md#doesnotreturn), we decided that we couldn't use it to broadly enforce the concept of\na method that does not return: instead, it could only influence nullable analysis. Much like the rest of the features\nnullable analysis added, it cannot make strong guarantees. Changing this behavior now wouldn't really solve any of the\nissues with it, as code exists today that is attributed with `DoesNotReturn` that cannot be statically-proven to never\nreturn.\n\nInstead, we think that https://github.com/dotnet/csharplang/issues/538 would be needed to make progress here: once we have\na `never` type, these guarantees can be statically proven, the runtime can abort if an instance of `never` is ever created,\nand we can introduce a warning wave at that point to suggest that methods attributed with `DoesNotReturn` should have a\nreturn type of `never`. This would prevent us from introducing another loose generalized analysis that can't be statically\nrelied upon before later adding a more strict version that can be relied upon.\n\n#### Conclusion\n\nNo changes.\n\n### Warning on lowercase type names\n\nhttps://github.com/dotnet/roslyn/issues/56653\n\nThis is an issue that we've been kicking around for a long time to try and protect language design space, and we've recently\nstarted to make more breaks in this space. For example, C# 9 introduced `record` as a type specifier, and made it illegal\nto declare a type named `record` without escaping it. We've heard no complaints about this change, and this has given us\nmore confidence to go ahead with a warning in this area.\n\nAnd important point is that this change is _not_ motivated by style. C# as a language tries hard not to be opinionated on\ncoding styles; we have defaults for formatting that are part of VS and `dotnet new editorconfig`, but these are highly\ncustomizable and we try not to punish users for taking advantage of that customizability. Instead, this warning is about\ntrying to ensure that C# has design space to work with that doesn't break users who upgrade to new C# versions. This goal\nmeans we're trying to help 2 sets of customers:\n\n1. People who author types with lowercase names. These authors should be informed that they could be causing issues for their\nusers by using a lowercase name.\n2. People who use types with lowercase names. These users should be informed that, if a future version of C# adds the type\nthey're using as a keyword, their code could change meaning or no longer compile.\n\nSome other points of consideration we brought up:\n\n* Should we do this for just public types?\n    * Answer: we are trying to protect users from both themselves and others. This means we want to warn everywhere.\n* Should we have codefixers to prepend `@` in front of identifiers?\n    * Ultimately this will be up to the IDE team, but we think that each set of customers above should have a different answer\n    here. For set 1, we don't want to encourage this type of naming, even when escaped, so we would not want to see a fixer on\n    type definitions. However, for set 2, they're just using a type someone else defined. We don't want to unreasonably punish\n    them, so a fixer to prepend `@` for these users seems appropriate.\n\n#### Conclusion\n\nThe compiler will issue a diagnostic for types named all lowercase letters. We may simplify that to be just types named all\nASCII lowercase characters, to avoid worrying about lowercase characters in other encodings and because we don't believe C#\nwill be interested in adding non-ASCII keywords.\n\n### Length pattern backcompat\n\nhttps://github.com/dotnet/csharplang/issues/5226\n\nThere are user tradeoffs here. In our previous discussion, we expressed a desire to have a similar ability to nullable, whereby\na missing negative Length test would not count against exhaustive matching, but if one was present it would then cause negative\nvalues to need to be fully matched against. However, describing these rules and implementing them is quite complex, to the point\nthat we are concerned both about the code complexity and the explanation of the rules to users. We therefore think that the\nsimpler implementation, where we just consider the domain of `Count`/`Length` for indexable and countable types to be non-negative\nintegers, to be the better approach.\n\nWhile we were discussing this, we also brought up the inherent flaw of structural typing, where types that do not satisfy the contract\nof indexable and countable but still have the correct shape end up having incorrect behavior. For example, the BCL recently approved\na `Vector2<T>` type. That type has an indexer, and it has a property called `Length` that returns an integer. This `Length` property\nis not the length of the Vector: that's always 2. Instead, this is the euclidean length of the vector, ie the distance from (0, 0).\nOur knowledge of `Length` and combining subsumption with list patterns will behave incorrectly here. However, we note that this type\nis _already_ broken with structural typing in C# today. For example, `vector[^1]` would work on the type, but it wouldn't have the\nexpected behavior. Instead of trying to solve something here, we instead think we should see what other uses customers have for opting\nout of structural typing, and started a discussion about that [here](https://github.com/dotnet/csharplang/discussions/5278).\n\n#### Conclusion\n\nWe will accept the existing breaking change on subsumption for indexable and countable types, and treat Length/Count on types that are\nboth indexable and countable as if they can _only_ have non-negative values. We would like to get this change in preview sooner\nrather than later so that we can receive feedback on the change.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-10-20.md",
    "content": "# C# Language Design Meeting for October 20th, 2021\n\n## Agenda\n\n1. [Open questions in list patterns](#open-questions-in-list-patterns)\n    1. [Types that define both Length and Count](#types-that-define-both-length-and-count)\n    2. [Slices that return null](#slices-that-return-null)\n2. [Primary constructors](#primary-constructors)\n\n## Quote of the Day\n\n- \"No fingerprints today, I always struggle with it after a bank robbery, when I file them down\"\n\n## Discussion\n\n### Open questions in list patterns\n\nhttps://github.com/dotnet/csharplang/issues/5137\n\nWe had 3 open questions from tests on list patterns. Questions 1 and 2 both relate to types with both `Length` and `Count` properties, so our decision\napplies to both.\n\n#### Types that define both Length and Count\n\nOur previous definition of a type that can be matched by a list pattern is that the type must be both indexable and countable. Because countable could be\none of two properties, `Length` or `Count`, we need to decide what do when a type has both. Our options are:\n\n1. Treat them as equivalent and assume they return the same value. This will affect subsumption.\n2. Treat the non-recognized one (`Count` in the case where both `Length` and `Count` are defined) as not being special at all.\n\nConceptually, we think it would be odd to assume that `Count` is equal to `Length`, even though we'll never use it for any form of slicing or length checking.\nWhile it might be reasonable to assume they return the same value, we don't think it's an important scenario. We'll have nearly a year of preview on this\nfeature, so we have plenty of time to react to feedback if dogfooding shows that it's an important scenario.\n\n##### Conclusion\n\nWe will not treat `Length` and `Count` as being connected when both are defined.\n\n#### Slices that return null\n\nWe believe that well-defined slice methods should never return `null` for an in-bounds range, and we'll never generate a call to such a slice method with\nan out-of-bounds range. However, we also don't think there's a customer for this scenario: a search of GitHub showed no `Slice` methods that return an\nannotated value, and treating a slice method differently than its annotation would require both implementation effort and customer education. Given that\nthere are no known cases this affects, we don't think it's worth it. Similarly to the first question, if such scenarios are identified during preview, we\ncan correct appropriately.\n\n##### Conclusion\n\nIf a `Slice` method is annotated, we will treat it as potentially returning `null` for the purposes of subsumption and exhaustiveness.\n\n### Primary constructors\n\nhttps://github.com/dotnet/csharplang/issues/2691\n\nNow that records have been out for a year and we've expanded them to struct and reference types, we think it's time to start looking at primary constructors\nagain. We updated the proposal with the new syntax forms from our records work, removing or modifying components where they make sense. Unlike for records,\nprimary constructors aren't about defining the members that make up a grouping of data: instead, they're purely for defining the inputs to a class. So things\nlike deconstruction, equality, and public properties aren't automatically generated from the parameters. Instead, they become fields, that are then eliminted if\nthe field is never used outside of a field initializer.\n\nWe think there are a couple of open discussion topics:\n\n1. Should the fields be readonly or not?\n2. How important are primary constructor bodies for a generalized feature?\n\nFor question 1, we think that, for better or for worse, C# is a mutable-by-default language. We were able to change the defaults for `record` types because\nmutability in a value-based reference type is actively harmful, but we have to consider a number of naming and mutability issues we were able to skirt around\nin record types. Field naming conventions, for example, are heavily split in C#, with some users using a leading `_`, and some preferring to just use pascalCase\nwith no leading modifiers. We think `readonly` is similar: if users would like to modify the defaults of C#, they can define their own field and do so. If this\nproves to be the wrong default we can make a change before it ships for real, or potentially invest in https://github.com/dotnet/csharplang/issues/188 to allow\nputting modifiers on parameters.\n\nFor question 2, we think that it will be important, but that once https://github.com/dotnet/csharplang/issues/2145 is in the language, a good portion of\ninitialization code will be expressable in just a single initialization expression. It will miss some more complex scenarios, but we think just primary constructors\nare a good first step.\n\nIn general, we also want to make sure we're defining the difference between primary constructors and required properties well. With the potential for multiple new\ninitialization features to ship in a single language version, we want to make sure they complement each other well. We think required properties work well for\npublic contracts: DTOs, POCOs, and other similar, nominal data structures that will expose these properties externally. Primary constructors, on the other hand,\nare for other types, that do not define public surface area based on their parameters. Instead, they simply define input parameters, and can assign them to private\nfields or otherwise manipulate them as they choose.\n\nSome concrete feedback on the proposal:\n\n* The exception for calling `this` for copy constructors feels premature, as they don't mean anything to any type except record types. If we generalize `with` in\nthe future, then the exception will make sense, and we can add it then.\n* We should disallow methods with the same name as primary constructor parameters. This is confusing and while it could potentially be understandable code if the\nparameter was never captured, could then have spooky action at a distance if the parameter was accidentally captured when a user forgot to write the `()` of the\nmethod name.\n\n#### Conclusion\n\nThese words are accepted.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-10-25.md",
    "content": "# C# Language Design Meeting for October 25th, 2021\n\n## Agenda\n\n1. [Required members](#required-members)\n2. [Delegate type argument improvements](#delegate-type-argument-improvements)\n\n## Quote of the Day\n\n- \"It's officially late, not casually late\"\n\n## Discussion\n\n### Required members\n\nhttps://github.com/dotnet/csharplang/issues/3630\n\nIt's been nearly a year since we last looked at required members, so we started today by recaping the proposal as it currently\n[exists](https://github.com/dotnet/csharplang/blob/ec01d26c47d8d3e3e10b1dd0ade96dae6f99934a/proposals/required-members.md). We also\ntook a look at the feedback we received when this was last shown to our design review team (mainly internal partners and former\nlanguage design members who aren't involved the day-to-day design of the language anymore). The feedback we received at that point\nwas that the proposal, as it currently stands, is too complex. We have a lot of syntax for enabling a set of contract modifications:\n\n1. Users can say `init(Prop)` to signal that the constructor requires all things the type does, except the members in the `init` clause.\n2. Users can say `init required` to signal that the constructor does not require any of the members the type does, and the compiler\nwill ensure that the user correctly initializes all members in that constructor.\n3. Users can say `init required!` to signal the same 2, except that the compiler will not enforce that the user correctly initializes\nall members in that constructor.\n\nThis syntax was quite specialized, as we intended it to be extensible enough that future work around factories would be able to take\nadvantage of the same syntax. However, upon coming back to the syntax, we have several people that changed their opinions on the form;\nsome of the people that didn't originally feel like the syntax \"clicked\" now like it, and others that originally liked it now think that\nit doesn't work well. We took a look at the concrete cases that will want to use the above modifications:\n\n* Copy constructors will want to opt out of the entire contract, as their job is to initialize all the fields to the original instance's\nvalues.\n* Types might have a grow-up story, where they may originally ship with just some number of required properties, but later may want to add\na convenience constructor that sets a few common properties. We think that this case, while not unreasonable, is not the common case for\nthis feature.\n\nThe first use case wants at least contract modification 3, and possibly 2 as well. It does not need 1. The second case needs contract\nmodification 1 to be expressible in C#. Given this, we think that there's a gradual approach we can take to introducing contract\nmodifications to the language. A potential first approach is just introducing modification 3, without any constructor body validation.\nA later version of the language can, as part of a warning wave, turn on body validation, and then later allow individual member exceptions\nas in modification 1. We are a bit split on this decision, however. We think a prototype to play around with that implements this initial\ndecision should help inform the initial feature set we want to ship for this feature. One thing we definitely don't want to do is ship\nwithout constructor body validation and without feeling like we can make that the default state later via a warning wave, as that would\nleave us in a bad position where validation is available, but off by default.\n\nWe also looked at different syntax forms, namely attributes. We'd considered attributes previously in the design, but steered away from\nthem to see what we could do with language-integrated syntax. We think we've gone as far down that road as we can, but our final design\nstill doesn't feel quite right. Given that, we think that having an attribute to express the contract modifications will serve us well.\nIt can be named more verbosely, should still be able to apply to factory methods, and required no new syntax for users to learn.\n\nFinally, we also considered a couple of other questions:\n\n* Should we have a new accessor, `req`, that is used for a required property instead of `init`?\n    * We think that this use case is too small, cuts out required setters, and cuts out the ability to mark fields as required.\n* Should we use a warning or error on construction? Traditionally, \"suppressions\" correspond to warnings, and the contract modifications\ncan be viewed as suppressing the need to initialize things.\n    * They're not really suppressions though. It's changing the semantics of the code, so we think it's fine (and safer) for us to use\n    errors on construction, not warnings.\n* We haven't considered how required members will interact with `default(StructType)`. Some thought needs to be put into that.\n\n#### Conclusion\n\nWe will start working on an implementation of the simplified version of this proposal that uses attributes for contract modifications,\nnot specific syntax, and only has contract modification 3. Feedback will then inform whether we need 2 or 1 before we ship.\n\n### Delegate type argument improvements \n\nhttps://github.com/dotnet/csharplang/issues/5321\n\nA couple of weeks ago, Microsoft held our annual internal hackathon, and one of the ideas that we worked on for the it this year was\nrelaxing type argument restrictions, specifically for delegate types. This would allow delegate types such as `Action<void>` or\n`Action<in int, ref readonly Span<char>>`, where these types are restricted from use in delegate types today. In general, the LDM has\na lot of interest in this space, but there is some concern that this proposal doesn't go far enough in relaxing restrictions, and might\nrun into issues if we try to generalize it more fully. A very common pattern in generic code in C# is to further abstract over parameter\ntypes: for example, a method might take a `Func<T, bool>` and a `T`, and pass the `T` parameter to the `Func<T, bool>` invocation. This\nproposal falls apart for such methods, which is a very early cliff to fall over. If we can instead generalize this work, such that these\nrestricted types are allowed in more places, then we'd be in a much better position. Even if we don't ship the whole thing at once, we'd\nreally like to make sure we're not painting ourselves into a hole with a proposal like this.\n\nAs a part of this, we also want to explore a revamp to the .NET delegate story. Today, `Action` and `Func` are the de-facto delegate types\nin C#: they're used throughout the BCL and lambdas/method groups use them where possible for their natural type. However, there are limits\nto this, as custom delegate types still have some advantages:\n\n* Ref kinds/restricted type arguments. This is solved by the current proposal as it stands.\n* Parameter names. We don't think this would be very difficult to solve, as we have prior art with tuple names.\n* Attributes. This is much more difficult to accomplish, to avoid needing to synthesize custom delegate types we'd need to have some way of\nputting attributes on a type argument. The runtime does not support this today, and it won't be as simple to add as the type restriction\nremovals were.\n\nWe've been moving towards structural typing of delegates ever since `Action` and `Func` were introduced, and we think it might be a better\napproach to the problem to start from fully structural delegate types, and work backwards to see how we could make that work. It's very\nlikely that we'd end up doing some of the same work generalizing on `Action` and `Func`, but there's some additional interesting wrinkles\naround `Action` and `Func<void>`. We might be able to unify these two, but we then want to be able to do the same for other types. How\nwould we make it work for `Task` and `Task<void>`, for example? Is there some attribute we could add to the runtime that would allow it\nto treat these types as identical, forwarding from one to the other? And how would that flow through the C# type system?\n\n#### Conclusions\n\nWe don't have any conclusions today. We think that much more exploration of this space is needed before moving forward with any specific\nproposal. We want to look into generalizing the generic restriction removals, and into generalized structural typing for delegates.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-10-27.md",
    "content": "# C# Language Design Meeting for October 27th, 2021\n\n## Agenda\n\n1. [UTF-8 String Literals](#utf-8-string-literals)\n2. [Readonly modifiers for primary constructors](#readonly-modifiers-for-primary-constructors)\n\n## Quote of the Day\n\n- \"I fought for that when I was young and idealistic\"\n\n## Discussion\n\n### UTF-8 String Literals\n\nhttps://github.com/dotnet/csharplang/issues/184\n\nUTF-8 strings are an extremely important part of modern day programming, particularly for the web. We've previously talked about including special support for literals\nbased on UTF-8 in C#, as currently all our literals are UTF-16. It is possible to manually obtain byte arrays of UTF-8 bytes, but the process for doing so is either:\n\n1. Error-prone, if you're hand-encoding a byte array.\n2. Cumbersome and slightly inefficient, if you're creating static data to be later used.\n3. Very inefficient, if you're converting the bytes every invocation.\n\nWe'd like to address these issues, doing the minimum possible work to make current scenarios more palatable without blocking our future ability to innovate in this space.\nCurrently, the runtime does not have a real `Utf8String` type, and instead uses `byte[]`, `Span<byte>`, or `ReadOnlySpan<byte>` as the de-facto interchange type for UTF-8\ndata. Many members of the LDM are concerned that, if we bless these types with conversions in the language, we will limit our future ability to react to the addition of\nsuch a type into the runtime itself. In particular, if `var myStr = \"Hello world\"u8;` meant any of those three types, we lose out on the ability to make it mean `Utf8String`\nin a future where that is added. This issue is further compounded because we don't know that such a type _will_ be added in the future: ongoing discussions are still being\nhad over whether a dedicated type will be added, or if the runtime could just have a flag to opt into having all `System.String` instances just become UTF-8 under the hood.\n\nThe u8 suffix had mixed reception with LDM. On the one hand, turning strings into one of the interchange types (either implicitly via target-typing, or only via explicit\ncast) is convenient from a programming perspective. It also doesn't create a blessed syntax form that runs into the problems of the previous paragraph. On the other hand,\nthere is no direct indication _how_ the strings are being converted to bytes, which the suffix is useful for. Are the bytes just a direct representation of the UTF-16 data,\nor an encoding the string in UTF-8 bytes?\n\nAnother question is whether a language-specific conversion is the correct approach here, or if we could create a user-defined conversion from `string` to `byte[]`. This\nwould allow non-constants to be converted as well, and the language/compiler could make the conversion special such that it could be optimized to occur at compile-time\nwhen constant data is involved. It does suffer from the same problems of what byte encoding is being used, however, and we have existing solutions for converting non-constant\nstrings to UTF-8.\n\nWe also discussed a few other questions:\n\n* Should we have a u8 character literal?\n    * People cast `char`s to `byte`s in a number of places today, this would need a suffix.\n    * It would also still need to return a sequence of bytes, rather than a single byte, so what advantage would it bring over a single-character string literal?\n* Should the byte sequence have a null terminator?\n    * Interop scenarios will want a null terminator. However, they can add one by including a `\\0` at the end of the string, and an analyzer can catch these cases.\n    * On the other hand, most managed code scenarios would break if a terminator was included.\n* How specific should we make the language around the compile-time encoding of a given string literal?\n    * We'd like to make it relatively loose, such that we can say \"the compiler is free to implement the most efficient and allocation-free form possible.\"\n\n#### Conclusion\n\nWe don't feel confident enough to make any final calls today, but we'd like to make a prototype with target-typed literals and get some usage feedback. We'll implement\nthat behind a feature flag, and give the compiler to our BCL and ASP.NET partners so they can give us their thoughts from real API usage.\n\n### Readonly modifiers for primary constructors\n\nhttps://github.com/dotnet/csharplang/discussions/5314  \nhttps://github.com/dotnet/csharplang/issues/188\n\nWe wanted to revisit this question after we received a large amount of feedback from the community after our [last meeting](./LDM-2021-10-20.md#primary-constructors) on\nprimary constructors. The feedback was notable in particular because of the volume, as our discussion issues don't normally generate as much discussion from as many separate\ncommunity members as this one did. The feedback generally tended in one direction: mutability is an ok default, especially given the history of C#. However, they would like\na succinct way to make the generated fields `readonly`, without having to fall back to manual field declaration and assignment. To address this, we took a look at another\nlongstanding C# proposal, allowing `readonly` on parameters and locals. Several LDM members are concerned about this as a general feature, mainly because of the \"attractive\nnuisance\" issue. `readonly` is often a sensible default for locals and (in particular) parameters, but in practice LDM members do not find accidental local/parameter mutation\nto be a real source of bugs. Meanwhile, if we introduce this feature in general, people will start to use it, and require usage where possible in their codebases. It can add\nclarity of intent for reading later, but many members are not convinced it meets the bar with C# 20 years old.\n\nHowever, scoping the feature down to just primary constructor parameters was slightly less controversial. Most members of the LDM are not opposed to the concept in general,\nbut we remain conflicted as to whether we need to have such a feature immediately. While we did get a good deal of immediate feedback, some LDM members are unsure whether\nthis feedback will persist after users actually get their hands on the feature and give it a try. We could also take primary constructors in a more radically different direction,\nwhere we'd adopt a more F#-like approach and consider these parameters captures, not fields.\n\n#### Conclusion\n\nWe did not come to any conclusions today. We will revisit soon to talk more about this area.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-11-01.md",
    "content": "# C# Language Design Meeting for November 1st, 2021\n\n## Agenda\n\n1. [Order of evaluation for Index and Range](#order-of-evaluation-for-index-and-range)\n2. [Collection literals](#collection-literals)\n\n## Quote of the Day\n\n- \"So 'The customer wants it therefore it's wrong' is your new motto?\"\n\n## Discussion\n\n### Order of evaluation for Index and Range\n\nhttps://github.com/dotnet/roslyn/issues/57349\n\nWe looked at an inconsistency in the order of evaluation between `Index` and `Range` operations, when those are applied to a type that does not have\nnative methods that accept `Index` or `Range` types. The `Index` portion of the spec is fairly straightforward and we were easily able to determine\nthe compiler had a bug with the lowering it performed. However, the specification is unclear about the `Range` translation: it does not clearly\ncommunicate the order of evaluation for the `receiver`, `Length`, and `expr` expressions that are cached. Our current behavior is inconsistent with\nthe `Index` behavior, and likely confusing to users. After a bit of discussion, we unanimously agreed to standardize the order of evaluation to be\nconsistent with the written original order in the source, followed by compiler-needed components if necessary. For indexers, this is `receiver`, then\n`expr`, then `Length` if needed.\n\n#### Conclusion\n\nCodify the expected behavior as `receiver` then `expr` then `Length`.\n\n### Collection literals\n\nhttps://github.com/dotnet/csharplang/issues/5354\n\nWe took a first look at a proposal for a \"collection literal\" syntax in C#, doing a general overview of the proposed syntax form and gathering general\nfeedback on the proposal. We hope to approach this proposal as a \"one syntax to rule them all\" form, that can achieve correspondence with the list\npattern syntax form, support new types that collection initializers can't today (such as `ImmutableArray<T>`), and serve as a zero or even negative\ncost abstraction around list creation that is as good or better than hand-written user code.\n\nThere's some unfortunate bad interaction with existing collection initializers, however. They'll still exist, and they will be advantageous in some\ncases. Since the user is explicitly calling `new Type` on them, they have an obvious natural type, while collection literals will need some form of\ntarget-type for cases where there is no obvious natural type or if the user is trying to select between ambiguous overloads. They also probably wouldn't\nsupport this new splat operator, which also makes them worse in that case; even if we extended support for it, it's very likely that the new form would\nlower to a more efficient form with the pre-length calculation that it able to support.\n\nWe're unsure about some of the various axes of flexibility in this space. Some of them that we talked about are:\n* Existing collection initializers require the type to implement `IEnumerable` to be considered collection-like. Do we want to keep this restriction for\nthe new form? It would lead to an odd non-correspondence with list patterns, since they are pattern-based and not interface-based. The proposal actually\nstarted more restrictive, but loosened to the current form after considering things like `HashSet<int> h = [1, 2, 3];` and deciding that was perfectly\nfine.\n* How specific do we want to make the lowering for various forms? Since it's a goal of the feature to be as optimal as possible here, if we prescribe\ntoo specific of lowering forms then we potentially make it difficult to optimize the implementation. We know from experience, though, that while we'll\nhave a small window of opportunity just after ship to make changes to the way code is emitted, making changes years on will be dangerous and will likely\nhave impacts on some user's code.\n* We think that a natural type for this syntax will have a lot of benefits, such as allowing it to be used for interfaces (`IEnumerable<int> ie = [1, 2];`)\nand it will be in line with the recent work we did around lambda expressions. However, unlike lambdas, we don't have a single list type in .NET that is\nunambiguously the natural type it should be. We'll need to dig into the pros and cons of the space and decide on how we want to approach this.\n\nWe also talked briefly about possible extensions of this space. One obvious one is dictionary literals. We think we can move ahead with collection\nliterals for now, as long as we keep both dictionary literals and dictionary patterns, to be sure we're holding ourselves to the correspondence principle.\nAnother area we should investigate is list comprehensions. We're not sure whether we want comprehensions, but we should at least look at the space and\nmake sure we're comfortable that we'd never consider them or leave ourselves the space to be able to consider them in the future.\n\nFinally, we want to look at other contemporary languages and see what they do for this space. For example, F# has dedicated syntax forms for each of it's\nmain list/sequence types. Unlike C#, they have largely unified on a very few specific collection types. This allows them to have dedicated syntax for each\none, but this approach isn't likely to work well in C# because we have a much wider variety of commonly-used collections, tuned for performance across a\nvariety of situtations. Kotlin takes a different approach of having well-known methods to construct different collections, such as `listOf` or `arrayOf`.\nIt's possible that, with `params Span`, we'd be able to achieve 90% of what we're trying to do without needing to build anything into the language itself.\nAnd then there are languages like Swift, Python, Scala, and others that actually have a dedicated literal for lists, with varying degrees of flexibility.\n\n#### Conclusions\n\nNo conclusions today. A smaller group will begin a deep dive into the space to flesh out the various questions and components of this proposal, and come\nback to LDM with more research in the area.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-11-03.md",
    "content": "# C# Language Design Meeting for November 3rd, 2021\n\n## Agenda\n\n1. [Name shadowing in local functions](#name-shadowing-in-local-functions)\n2. [`params Span<T>`](#params-spant)\n\n## Quote(s) of the Day\n\n- \"params Span<T>. This is an easy one, we should be out in 10 minutes.\"\n- \"For some value of 8\"\n- \"Stack goes up. Stack goes down. You can't explain that.\"\n- \"That killed my monologue.\" \"Did you mean 'evil villain monologue'?\" \"No one killed me during the monologue\ntherefore I can't be an evil villain.\" \"No one kills the evil villain during the monologue, they just learn the evil plan and then escape to thwart it when the villain\nleaves the implementation to his minions.\"\n- \"Solved the mystery: cat sitting on the spacebar\"\n\n## Discussion\n\n### Name shadowing in local functions\n\nhttps://github.com/dotnet/csharplang/discussions/5327\n\nIn C# 8, we relaxed the name shadowing requirements for lambdas and local functions, but we wanted to revisit the specific implementation strategy and whether we went too\nfar. In particular, we allowed a local function to _both_ capture a variable from an outer scope and shadow that variable in a nested scope inside the local function. This\n_and_ in the previous sentence is the part we're concerned with: several members of the LDT didn't realize that we were agreeing to this in the original discussions on\nshadowing.\n\nThere are two general models of shadowing in C#:\n\n* Locals shadowing another local within the same function. This is expressly disallowed, and has been since C# 1.\n* Locals shadowing a field. This is allowed, but the user can always get to the field version by using `this`. In the same method, it is possible to use the field without\nthe `this` qualifier and shadow it in a nested scope.\n\nShadowing between local functions while also capturing that local from the outer scope has similarities to both of these models: on the one hand, it's a local variable,\neven if that variable has been potentially lifted to a field in an implicit closure. On the other hand, it's a variable from a scope outside the current function, just like\na field. This duality leads to conflicting resolution strategies, but we ultimately think this has more in common with locals shadowing other locals in the same method than\nit does with locals shadowing fields.\n\nThe rules we wish we had implemented are: if a lambda or local function (or a nested lambda or local function) captures a variable from an outer method, it is an error to\nshadow that variable. However, these rules have been out in the wild for nearly 3 years at this point, and we don't feel that the level of concern warrants a language change\nor a warning wave to cover it. If an analyzer wants to implement such a suggestion (in dotnet/roslyn-analyzers, for example), they are free to, but the compiler itself will\nnot do so.\n\n#### Conclusion\n\nWe regret that simultaneous capture/shadowing was allowed, and now it's too late to really fix it. Future features should keep this regret in mind and not use the way shadowing\nin local functions/lambdas works as precedent.\n\n### `params Span<T>`\n\nhttps://github.com/dotnet/csharplang/issues/1757\n\n`params Span<T>` is a feature that has been requested since we first implemented `Span<T>` in C# 7, and has a number of benefits. Today, users interested in performance with\n`params` methods need to maintain overloads for common scenarios, such as passing 1-4 arguments (as we do for `Console.WriteLine`). These APIs are often not straightforward\nto implement: if there was a simple common method they could all delegate to, that API would have been exposed in the first place.\n\nBecause of this focus, `params Span<T>` is an interesting first for the language: a `Span<T>`-based API that is explicitly targetted at the average C# developer, rather than\nat someone who already knows what a `Span<T>` and why they would want to use it. There are also strong conflicting desires in the space that makes it very difficult to design\na single lowering strategy. We want to avoid allocations where possible, but we also want to avoid blowing out the stack when large numbers of parameters are passed to a\n`params` method. This is particularly important in recursive code: Roslyn regularly runs into issues when inlining decisions can affect whether we are able to compile some\ncustomer's code, as the compiler is an extremely recursive codebase.\n\nAt the same time, we also want to avoid being overly specific in the language specification on how this feature works. We would like to view the details as more an implementation\nconcern, much like we do with how lambdas are emitted, and avoid making strong guarantees about what will or won't stackalloc for what scenarios. As this is more targetted to\nperf than lambdas are, it's possible that we can't be as glib in this space as we can for lambdas, but it's an aspiration for the feature.\n\nDespite our desire to be less specific, we do think it's important to the initial design, and therefore the conception of who the feature is for, to have an implementation\nstrategy in mind. There are a number of different strategies that have been brought, with various pros and cons:\n\n* Using a custom struct with a specific layout, and then making a span from the start of that struct.\n* A shadow-stack that exists solely for the purpose of being able to give out and return stackalloc'd chunks of memory (think RAII stack space).\n* Pushing variables onto the stack, then making a span from the start of those pushes (similar to the first approach, but without a dedicated type to be wrapped).\n* `stackalloc` space that can be popped after a function is called.\n* Not doing any kind of optimized IL in C#, and relying on the JIT to perform the escape analysis and translation from array to stackalloc when viable.\n\n#### Conclusion\n\nWe'd like to see a group from the compiler and the runtime work through these proposed strategies and come up with \"the way\" or combination of ways that this will work, so we\ncan start to see how the user experience for the feature would actually work.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-11-10.md",
    "content": "# C# Language Design Meeting for November 10th, 2021\n\n## Agenda\n\n1. [Self types](#self-types)\n\n## Quote of the Day\n\n- \"Is that a threat [redacted]?\" \"I think it's a promise\" \"Well, then someone gets to tell management why it slipped.\" \"Now that was a threat.\"\n\n## Discussion\n\n### Self types\n\nhttps://github.com/dotnet/csharplang/issues/5413\n\nToday, we took a first look at adding a self type constraint to C#, as part of the work on generic math in C#. We see 3 main problems that the self type\nconstraint could address:\n\n1. Today, generic math using the Curiously Recurring Type Pattern (CRTP) to specify self types, which looks like `interface INumber<T> where T : INumber<T>`.\nThis is quite verbose, requiring stating the name of the interface twice, and even a small reduction to `interface INumber<T> where T : this` helps both\nwith the number of characters typed and the clarity of the intent of the code.\n2. CRTP does not actually enforce that the `T` implemented must be the current type. For example, someone could do `struct MyStruct : IAdditiveIdentity<int>`,\nbecause `int` implements `IAdditiveIdentity<int>`. CRTP involving operators will naturally enforce that `T` is actually the current type, because of the rules\naround operator implementation, but this is complex from both a spec perspective and an implementation perspective.\n3. Being able to call explicit implementations of an interface. In .NET 6, many of the preview interface definitions are implemented on types _explicitly_, to\navoid users accidentally taking a dependency on them without meaning to. However, this leads to confusion with how to call that implementation: you have to\ncreate a generic wrapper method, which we've received feedback is quite confusing. While some of these explicit implementations will be transitioned to regular\nimplementations in .NET 7 when the feature ships for real, a few must remain explicit to avoid covering existing functionality that behaves in a slightly\ndifferent manner.\n\nOf these concerns, we think the best motivation for self types is actually the first one. For concern 2, we're unsure what the real harm is. Yes, users can\nprovide an odd implementation of one of these interfaces, but that's going to be true forever in C# regardless of our decision here, unless we take a breaking\nchange to `IEquatable<T>` and similar interfaces that shipped with C# 2. It does simplify some rules for the compiler, but ultimately we're not sure that\naddressing concern 2 is a motivating factor.\n\nConcern 3 is valid, but we're not sure the self type is the appropriate way to fix it. We've had `base` calls for DIMs on the backlog for a few years now, and\nwe see the possibility for a more generalized way to call a specific implementation of a method on a type. The current design for the self type happens to\naddress this concern, but not in a generalized fashion. In addition, several members of the LDM are not convinced by the prevalence of the need to call these\nimplementations once .NET 7 is out: they do exist, but how common will needing those implementations be?\n\nWe also talked about the possibility of using associated types to represent the self type, rather than a public type parameter. While this is somewhat attractive,\nwe're in general agreement that unless we have real runtime support for an associated self type, we don't want to take this direction. In C#, we generally avoid\nhaving metadata significantly differ from the source; if the metadata needs to have a generic type parameter, then we would like the source to indicate such.\nAt some point, associated types need to be translated into the universal type space, which will spread virally throughout the program: that either needs to be\ndone at compile time by Roslyn (the representation change we want to avoid), or it needs to be done by the runtime. The runtime has concerns about avoiding an\nMxN problem (where M methods will need to be specialized N times) without whole-program analysis, which is not always available. There's also some argument that,\nof all the things associated types can do, the self type is one of the least interesting ones. Consumers of the generic math feature will almost certainly still\nneed to use a generic type parameter, because unless they're creating a method with one input and no outputs, they will need to constrain each input and output to\nbe the _same_ associated type, not just _some_ associated self type. IE, using a hypothetical `INumber.this` syntax:\n\n```cs\n// How is the compiler to know that the `INumber.self` of the `left` parameter is the same as the `INumber.self` of the `right` parameter, and how does it make\n// any assumptions about the return type?\npublic INumber.self Add(INumber.self left, INumber.self right) => left + right;\n\n// Users would actually need to resort to generics to relate these parameters:\npublic T Add<T>(T left, T right) where T : INumber.self => left + right;\n```\n\nGiven that we see the _vast_ majority of the usages of the self type being consumption, not definition, we're unsure the potentially significant cost of the\nassociated->universal type translation actually buys the user anything.\n\n#### Conclusions\n\nWe're going to have a small group explore this space more and make revisions to the proposal before coming back to LDM.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-12-01.md",
    "content": "# C# Language Design Meeting for December 1st, 2021\n\n## Agenda\n\n1. [Roles and extensions](#roles-and-extensions)\n\n## Quote(s) of the Day\n\n- \"A certain section of the community that I suspect are [long pause] uncommonly aligned with Haskell\"\n- \"I feel like I might be, as [redacted] said earlier, uncommonly aligned with Haskell.\"\n- \"This conference room table is too heavy to flip\"\n\n## Discussion\n\n## Roles and extensions\n\nhttps://github.com/dotnet/csharplang/issues/5497\n\nThe idea of roles and extensions has a long history in C#, under various names, throughout the years. Previous discussions/issues\non the topic include (but aren't limited to: these issues have more links themselves):\n\n* https://github.com/MattWindsor91/roslyn/blob/master/concepts/docs/csconcepts.md - Concept C#\n* https://github.com/dotnet/csharplang/issues/110 - Type classes\n* https://github.com/dotnet/csharplang/discussions/164 - Shapes and extensions\n* https://github.com/dotnet/csharplang/issues/1711 - Previous roles and extensions exploration post\n\nAfter some more thinking on the topic, we're back with a proposal in the space. It's early days yet for this proposal: extensive\nprototyping and exploration of implementation details will be needed to make forward progress. But overall, the LDM is excited\nabout the direction this proposal is taking, and we spent all of today's session discussing the proposal, both from a high level\nand getting into some implementation ideas.\n\nBroadly, there are 2 different features here, and the feature we choose to pursue will heavily drive our implementation concerns.\nThere's a smaller, simpler feature where we say that we will never allow implementing interfaces on classes the user doesn't own.\n(Not to say that it's a small feature, just that it's small_er_). This feature could be implemented entirely through erasure if\ndesired, requiring little to no runtime changes, but that would mean it has the commensurate issues erasure brings. Overloading\ncould be accomplished via `modopt`s, but edges would still bleed through in reflection and generic usage.\n\nThe larger, much more complex feature is saying that we will, at some point, allow implementing interfaces on classes the user\ndoesn't own. Even if this feature doesn't ship initially, it will impose a much higher burden on the implementation. In such a\nworld, this code (or something similar) should be possible:\n\n```cs\n// Assume some pre-existing Fraction type from an older library with a constructor that takes an int numerator and an int denominator\nrole FractionAdditiveIdentity : Fraction, IAdditiveIdentity<Fraction>\n{\n    public static Fraction Zero => new(0, 1);\n    public static Fraction operator+(Fraction left, Fraction right) => left + right;\n}\n\n// With the above adapter, this code should be compilable:\n\npublic T Sum<T>(IEnumerable<T> elements) where T : IAdditiveIdentity<T>\n{\n    T result = T.Zero;\n    foreach (var el in elements)\n    {\n        result += el;\n    }\n    return result;\n}\n\nIEnumerable<FractionAdditiveIdentity> fractions = ...;\nConsole.WriteLine(Sum(fractions));\n```\n\nHowever, if that code can compile, then it means a few things:\n* FractionAdditiveIdentity needs to be real in metadata. It can't just be erased: there needs to be a real runtime type that\ncan be used to find the implementation of `T.Zero`.\n* There needs to be some sort of variance relationship between `IEnumerable<Fraction>` and `IEnumerable<FractionAdditiveIdentity>`.\nIs that an identity conversion somehow? Or a role variance conversion?\n\nNeither of these can be accomplished via erasure, and moreover would be a big breaking change if we were to add them later. It might\nbe possible, with the right set of restrictions, to ship an erasure-based solution now and add this later, but we'll need to fully\nexplore the space and have a good understanding of how the full solution would be implemented before we ship the initial feature.\n\nWhen it comes to erasure, there are also different stages that types can be erased in. For example, we could have real metadata for\nroles, but they could be erased in most scenarios by the JIT compiler, as opposed to being erased by Roslyn. This could potentially\nsimplify the language rules, at the expense of making the runtime side more complex.\n\nWe also think there are opportunities to leverage our existing variance rules here. `List<Fraction>` and\n`List<FractionAdditiveIdentity>` are hard to relate to each other in a non-erasure-based system, because those are really different\ntypes and need to have different observable results in type tests, reflection, generics, etc. But perhaps we can say that there is\na _variance_ relationship between `List<Fraction>` and `IList<FractionAdditiveIdentity>`: they are not the same object, but the class\n`List` type is convertible to an interface via a variant conversion, with automatic boxing conversions inserted by some stage of the\npipeline where necessary.\n\nOverall, the team is interested in trying to go all the way here. An erasure-based system would allow us to ship in the nearer term,\nbut we've been talking about type classes in the language for years. We'd really like to enable the whole deal, rather than cordoning\nit off forever more. Doing that is going to take both effort and time, but we think it's worth it.\n\nSome other miscellaneous thoughts:\n\n* Can roles reimplement underlying behavior? IE, can they provide their own `ToString` to override the existing one? While this is\npotentially an attractive feature, it would have some serious consequences on implementation strategies, and it throws some odd\nquestions in for the goal of having `Identity` conversions from a role to the underlying type and back.\n* Is there a way we could have automapping of role properties onto an underlying dictionary, enabling an \"easy\" mode similar to typescript\ninterfaces? This might be a place where source generators would work well, but if that's the approach we would want to take we'd need\n`partial` roles.\n* This feature would resolve a number of alias requests we've had over the years, particularly if we disallow sideways role conversion\n(or make it require an explicit cast). This would allow a user to have a `Mile` role and a `Kilometer` role, both of which extend\nsome numeric type. They could even potentially be a generic role on top of `INumber<T>`, allowing `Mile<decimal>` to automatically derive\nall conversion information from a generic implementation.\n \n#### Conclusion\n\nThe LDM is excited to continue exploring this feature, in particular the full interface implementation version. This is a long lead\nproposal: it's going to take time to explore and implement. But we think we have a promising start to really start prototyping with.\n"
  },
  {
    "path": "meetings/2021/LDM-2021-12-15.md",
    "content": "# C# Language Design Meeting for December 15th, 2021\n\n## Agenda\n\n1. [Required parsing](#required-parsing)\n2. [Warnings for parameterless struct constructor](#warnings-for-parameterless-struct-constructor)\n\n## Quote of the Day\n\n- \"Please don't make that the quote of the day. We want to project responsibility to the community.\"\n\n## Discussion\n\n### Required parsing\n\nhttps://github.com/dotnet/csharplang/issues/5439\n\nThe main question here is whether we should allow types named `required` in the language in C# 11, without escaping the name with an `@`. We did\na similar thing for `record` in C# 9, but in that scenario `record` had true syntactic ambiguities. For `required`, there aren't true syntactic\nambiguities: just like with `async`, it is possible to fully disambiguate types named `required` and `required` used as a modifier with enough\nlookahead. However, we have started taking a harder stance against types named with all lowercase 'a'-'z' characters: in .NET 7, we will be report\na warning on such type names in general. While we still want to make sure that we're choosing names for new keywords that are unlikely to conflict\nwith user-defined types, we think `required` is unlikely to be a type name, even beyond the general C# convention of not naming in lowercase, as\n`required` is not a noun. Even for `record`, which is a noun and reasonable one to use (for a record in a DB, as an example), we heard little to\nno complaints about erroring on it. Therefore, we are comfortable making `required` illegal as a type name without using an `@` to escape it.\n\n#### Conclusion\n\n`required` will be disallowed as a type name in C# 11. In general, we are ok with taking over all-lowercase identifiers that can be confused for\ntype names, so long as we do our due diligence in making sure that we're not breaking existing common usages.\n\n### Warnings for parameterless struct constructor\n\nhttps://github.com/dotnet/csharplang/issues/5546\n\nThis issue around `new S()` where `S` is a struct without a parameterless constructor is a particularly thorny area. There are three main paths\nwe could take to resolve it, each with significant downsides:\n\n1. Warn on field initializers when a parameterless constructor will not be created. This is painful for users trying to share initializer logic\nacross multiple other constructors, and is also painful for record structs. If a user wants to change anything about a record struct parameter\n(ie, turn the property into a field, make one property `init`-only, add a validation check) there is no alternative _but_ making a field initializer.\n2. Warn when calling `new S()` if `S` doesn't have a parameterless constructor. This is an extremely broad hammer, as this code has been legal\nsince C# 1. It also has bad interactions with generics, as `where T : struct` implies `where T : new()`. We think this option is like attempting to\nuse a sledgehammer to drive in a finishing nail.\n3. A more limited version of 2 where we only warn if the struct in question has field initializers. This heuristic breaks almost immediately, as\nwe have no way to determing whether a struct from metadata has field initializers.\n\nThis might be a place that an analyzer implementing option 1 would make more sense than a compiler warning: analyzers can be more configurable than\nanalyzer warnings, both in their severity levels, and in accepting additional options to tune the analyzer. An analyzer will also be able to do\nmore heuristics than we feel comfortable doing in the language, such as detecting when initializers are only using the primary constructor parameters\nin record structs.\n\nWe also looked at the second issue listed in the bug, but determined that it is already an error, and we did not need to make any further changes.\n\n#### Conclusion\n\nWe'll look at doing an analyzer implementing a warning on structs with field initializers that do not generate a parameterless constructor, with\nsome amount of heuristic suppression for scenarios where it is unavoidable.\n"
  },
  {
    "path": "meetings/2021/README.md",
    "content": "# C# Language Design Notes for 2021\n\nOverview of meetings and agendas for 2021\n\n## Dec 15, 2021\n\n[C# Language Design Notes for December 15th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-12-15.md)\n\n1. Required parsing\n2. Warnings for parameterless struct constructor\n\n## Dec 1, 2021\n\n[C# Language Design Notes for December 1st, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-12-01.md)\n\n1. Roles and extensions\n\n## Nov 10, 2021\n\n[C# Language Design Notes for November 10th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-11-10.md)\n\n1. Self types\n\n## Nov 3, 2021\n\n[C# Language Design Notes for November 3rd, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-11-03.md)\n\n1. Name shadowing in local functions\n2. `params Span<T>`\n\n## Nov 1, 2021\n\n[C# Language Design Notes for November 1st, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-11-01.md)\n\n1. Order of evaluation for Index and Range\n2. Collection literals\n\n## Oct 27, 2021\n\n[C# Language Design Notes for October 27th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-10-27.md)\n\n1. UTF-8 String Literals\n2. Readonly modifiers for primary constructors\n\n## Oct 25, 2021\n\n[C# Language Design Notes for October 25th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-10-25.md)\n\n1. Required members\n2. Delegate type argument improvements\n\n## Oct 20, 2021\n\n[C# Language Design Notes for October 20th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-10-20.md)\n\n1. Open questions in list patterns\n    1. Types that define both Length and Count\n    2. Slices that return null\n2. Primary constructors\n\n## Oct 13, 2021\n\n[C# Language Design Notes for October 13th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-10-13.md)\n\n1. Revisiting DoesNotReturn\n2. Warning on lowercase type names\n3. Length pattern backcompat\n\n## Sep 22, 2021\n\n[C# Language Design Notes for September 22nd, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-09-22.md)\n\n1. Open questions in list patterns\n    1. Breaking change confirmation\n    2. Positional patterns on ITuple\n    3. Slicing rules\n    4. Slice syntax recommendations\n    5. Other list pattern features\n2. Nested members in `with` and object creation\n3. CallerIdentityAttribute\n4. Attributes on `Main` for top level programs\n\n## Sep 20, 2021\n\n[C# Language Design Notes for September 20th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-09-20.md)\n\n1. Lambda breaking changes\n2. Newlines in non-verbatim interpolated strings\n3. Object initializer event hookup\n4. Type alias improvements\n\n## Sep 15, 2021\n\n[C# Language Design Notes for September 15th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-09-15.md)\n\n* Feedback from the C# standardization committee\n* Permit pattern variables under disjunctive patterns\n\n## Sep 13, 2021\n\n[C# Language Design Notes for September 13th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-09-13.md)\n\n1. Feedback on static abstracts in interfaces\n\n## Sep 1, 2021\n\n[C# Language Design Notes for September 1st, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-09-01.md)\n\n1. Lambda expression conversions to `Delegate`\n2. C# 11 Initialization Triage\n    1. Required properties\n    2. Primary constructors\n    3. Immutable collection initializers\n\n## Aug 30, 2021\n\n[C# Language Design Notes for August 30th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-08-30.md)\n\n1. C# 11 Initial Triage\n    1. Generic attributes\n    2. List patterns\n    3. Static abstracts in interfaces\n    4. Declarations under `or` patterns\n    5. Records and initialization\n    6. Discriminated unions\n    7. Params `Span<T>`\n    8. Statements as expressions\n    9. Expression trees\n    10. Type system extensions\n\n## Aug 25, 2021\n\n[C# Language Design Notes for August 25th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-08-25.md)\n\n1. Interpolated string handler user-defined conversion recommendations\n2. Interpolated string handler additive expressions\n\n## Aug 23, 2021\n\n[C# Language Design Notes for August 23rd, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-08-23.md)\n\n1. Nullability differences in partial type base clauses\n2. Top-level statements default type accessibility\n3. Lambda expression and method group type inference issues\n    1. Better function member now ambiguous in some cases\n    2. Conversions from method group to `object`\n4. Interpolated string betterness in older language versions\n\n## Jul 26, 2021\n\n[C# Language Design Notes for July 26th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-07-26.md)\n\n1. Lambda conversion to System.Delegate\n2. Direct invocation of lambdas\n3. Speakable names for top-level statements\n\n## Jul 19, 2021\n\n[C# Language Design Notes for July 19th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-07-19.md)\n\n1. Global using scoping revisited\n\n## Jul 12, 2021\n\n[C# Language Design Notes for July 12th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-07-12.md)\n\n1. C# 10 Feature Status\n2. Speakable names for top-level statements\n\n## Jun 21, 2021\n\n[C# Language Design Notes for June 21st, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-06-21.md)\n\n1. Open questions for lambda return types\n2. List patterns in recursive patterns\n3. Open questions in async method builder\n4. Email Decision: Duplicate global using warnings\n\n## Jun 14, 2021\n\n[C# Language Design Notes for June 14th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-06-14.md)\n\n1. Open questions in CallerArgumentExpressionAttribute\n2. List pattern syntax\n\n## Jun 7, 2021\n\n[C# Language Design Notes for June 7th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-06-07.md)\n\n1. Runtime checks for parameterless struct constructors\n2. List patterns\n    a. Exhaustiveness\n    b. Length pattern feedback\n\n## Jun 2, 2021\n\n[C# Language Design Notes for June 2nd, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-06-02.md)\n\n1. Enhanced #line directives\n2. Lambda return type parsing\n3. Records with circular references\n\n## May 26, 2021\n\n[C# Language Design Notes for May 26th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-05-26.md)\n\n1. Open questions in list patterns\n\n## May 19, 2021\n\n[C# Language Design Notes for May 19th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-05-19.md)\n\n1. Triage\n    1. Checked operators\n    2. Relaxing shift operator requirements\n    3. Unsigned right shift operator\n    4. Opaque parameters\n    5. Column mapping directive\n    6. Only allow lexical keywords\n    7. Allow nullable types in declaration patterns\n2. Protected interface methods\n\n## May 17, 2021\n\n[C# Language Design Notes for May 17th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-05-17.md)\n\n1. Raw string literals\n\n## May 12, 2021\n\n[C# Language Design Notes for May 12th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-05-12.md)\n\n1. Experimental attribute\n2. Simple C# programs\n\n## May 10, 2021\n\n[C# Language Design Notes for May 10th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-05-10.md)\n\n- Lambda improvements\n\n## May 3, 2021\n\n[C# Language Design Notes for May 3rd, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-05-03.md)\n\n1. Improved interpolated strings\n2. Open questions in record structs\n\n## Apr 28, 2021\n\n[C# Language Design Notes for April 28th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-04-28.md)\n\n1. Open questions in record and parameterless structs\n2. Improved interpolated strings\n\n## Apr 21, 2021\n\n[C# Language Design Notes for April 21st, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-04-21.md)\n\n1. Inferred types for lambdas and method groups\n2. Improved interpolated strings\n\n## Apr 19, 2021\n\n[C# Language Design Notes for April 19th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-04-19.md)\n\n1. Improved interpolated strings\n\n## Apr 14, 2021\n\n[C# Language Design Notes for April 14th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-04-14.md)\n\n1. Shadowing in record types\n2. `field` keyword\n3. Improved interpolated strings\n\n## Apr 12, 2021\n\n[C# Language Design Notes for April 12th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-04-12.md)\n\n1. List patterns\n2. Lambda improvements\n\n## Apr 7, 2021\n\n[C# Language Design Notes for April 7th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-04-07.md)\n\n- MVP session\n\n## Apr 5, 2021\n\n[C# Language Design Notes for April 5th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-04-05.md)\n\n1. Interpolated string improvements\n2. Abstract statics in interfaces\n\n## Mar 29, 2021\n\n[C# Language Design Notes for March 29th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-03-29.md)\n\n1. Parameterless struct constructors\n2. AsyncMethodBuilder\n\n## Mar 24, 2021\n\n[C# Language Design Notes for March 24th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-03-24.md)\n\n1. Improved interpolated strings\n2. `field` keyword\n\n## Mar 22, 2021\n\n- *Design review* (No notes published)\n\n## Mar 15, 2021\n\n[C# Language Design Notes for March 15th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-03-15.md)\n\n1. Interpolated string improvements\n2. Global usings\n\n## Mar 10, 2021\n\n[C# Language Design Notes for March 10th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-03-10.md)\n\n1. Property improvements\n    1. `field` keyword\n    2. Property scoped fields\n2. Parameterless struct constructors\n\n## Mar 3, 2021\n\n[C# Language Design Notes for March 3rd, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-03-03.md)\n\n1. Natural type for lambdas\n    1. Attributes\n    2. Return types\n    3. Natural delegate types\n2. Required members\n\n## Mar 1, 2021\n\n[C# Language Design Notes for March 1st, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-03-01.md)\n\n1. Async method builder override\n2. Async exception filters\n3. Interpolated string improvements\n\n## Feb 24, 2021\n\n[C# Language Design Notes for February 24th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-02-24.md)\n\n1. Static abstract members in interfaces\n\n## Feb 22, 2021\n\n[C# Language Design Notes for February 22nd, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-02-22.md)\n\n1. Global `using`s\n2. `using` alias improvements\n\n## Feb 10, 2021\n\n[C# Language Design Notes for February 10th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-02-10.md)\n\n1. Follow up on record equality\n2. Namespace directives in top-level programs\n3. Global usings\n4. Triage\n    1. Nominal And Collection Deconstruction\n    2. Sealed record ToString\n    3. `using` aliases for tuple syntax\n    4. Raw string literals\n    5. Allow `var` variables to be used in a `nameof` in their initializers\n    6. First-class native integer support\n    7. Extended property patterns\n\n## Feb 8, 2021\n\n[C# Language Design Notes for February 8th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-02-08.md)\n\n1. Virtual statics in interfaces\n    1. Syntax Clashes\n    2. Self-applicability as a constraint\n    3. Relaxed operator operand types\n    4. Constructors\n\n## Feb 3, 2021\n\n[C# Language Design Notes for February 3rd, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-02-03.md)\n\n1. List patterns on `IEnumerable`\n2. Global usings\n\n## Jan 27, 2021\n\n[C# Language Design Notes for January 27th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-01-27.md)\n\n1. Init-only access on conversion on `this`\n2. Record structs\n    1. Copy constructors and Clone methods\n    2. `PrintMembers`\n    3. Implemented equality algorithms\n    4. Field initializers\n    5. GetHashcode determinism\n\n## Jan 13, 2021\n\n[C# Language Design Notes for January 13th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-01-13.md)\n\n- Global usings\n- File-scoped namespaces\n\n## Jan 11, 2021\n\n[C# Language Design Notes for January 11th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-01-11.md)\n\n- Required properties simple form\n\n## Jan 6, 2021\n\n[C# Language Design Notes for January 5th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-01-05.md)\n\n- File scoped namespaces\n"
  },
  {
    "path": "meetings/2022/LDM-2022-01-03.md",
    "content": "# C# Language Design Meeting for January 3rd, 2022\n\n## Agenda\n\n1. [Slicing assumptions in list patterns, revisited](#slicing-assumptions-in-list-patterns-revisited)\n2. [Parameterless struct constructors, revisited](#parameterless-struct-constructors-revisited)\n\n## Quote of the Day\n\n- \"I just want to point out that slicing with [redacted] sounds like a cooking show, and I'd watch that\" \"Yeah\" \"Me too\"\n\n## Discussion\n\n### Slicing assumptions in list patterns, revisited\n\nhttps://github.com/dotnet/csharplang/issues/5599\n\nWe took another look at this corner case of list patterns, with an eye for trying to settle on a consistent and logical representation\nthat will be both unsurprising to the user, and set the language up for success in the future if we ever want to build on list patterns\nin other ways. We generally agree that this is an extreme corner case: the overwhelming majority of slice patterns should be variable\nassignments, and those that aren't are almost certainly not going to be another a list of pattern with a finite number of elements in it.\nHowever, we think it's important to codify the language's _expectations_ of how a well-behaved slice method should work, and that future\npattern work could possibly suffer if we don't make those assumptions now.\n\nFormally, our expectation is: a `Slice` method should _never_ return `null`. It should return an empty slice, or throw if indexes are out\nof range, but never return `null`. In order to resolve the pattern handling of this, we have 4 options:\n\n1. Keep the status quo, with inconsistencies between value type slices and reference type slices in this corner case.\n2. Remove the null test from the DAG. If the `Slice` method violates the above expectation, the code might throw a null reference exception,\ndepending on how the slice is used.\n3. Perform just reachability analysis without the null test, and include the null test in codegen. Codegen will produce slightly less\nefficient code for reference types.\n4. Perform reachability analysis and codegen with a \"slice and throw if null\" node, which will throw a custom exception type if the above\nexpectation is violated. This has slightly worse codegen than 2, but better than 3. However, it cannot be worked around: an explicit\n`.. null` pattern would never match, as the custom exception would be thrown when a `null` return from `Slice` was encountered. The only\nworkaround would be to fall out of pattern matching entirely.\n\nAfter some discussion, we were split between 2 and 4. We feel that 1, while an ok solution for this niche case, could potentially have\nbad consequences long term for patterns if we want to evolve anything about slice patterns in the future. 3 is ok, but we're concerned\nabout the worse codegen for the 99% case here. Patterns can and do assume certain behaviors for the things they operate on: properties\nmight be called multiple times, or they might not be, and should return the same result across evaluations, for example. This is just\nanother similar expectation, this time on the `Slice` method. After further discussion, we think that the inability to workaround the\nchecks in 4 are enough of a concern to tilt the balance between the two.\n\n#### Conclusion\n\nWe will adjust our expectations around slice patterns to assume that `Slice` will never return a `null` value, and we will not insert a\n`null` test into the reachability or codegen DAGs.\n\n### Parameterless struct constructors, revisited\n\nhttps://github.com/dotnet/csharplang/issues/5552\n\nThere has been some feedback on parameterless constructors in C# 10 that we want to address now, while C# 10 is still new. Specifically,\nwhen a parameterless struct constructor is synthesized has raised concerns about silent breaks for `new StructType()` when a user or\nlibrary updates their code.\n\nIn general, it's a bit unfortunate that C# allows `new StructType()` syntax. `default(T)` wasn't in C# 1 (it was introduced with C# 2's\ngenerics), so that was the original way to get a default instance of a value type. We think there may be an opportunity to start correcting\nthis with a .NET 7 warning wave, but that will need more design, particularly around object initializers on struct types. In the meantime,\nwe have 3 options for addressing the concerns with the initial release of C# 10:\n\n1. No change from ship. This would mean that we stop synthesizing parameterless constructors when an explicit constructor is introduced.\nIn particular, this has some serious community concerns about binary compat, namely that adding or removing an explicit constructor changes\nwhether field initializers are run (changing the behavior of source and breaking binary compat). We think they're important enough to rule\nout this option.\n2. Synthesize parameterless constructors in more places. We have a good idea how to do this for regular structs: zero init, then run all\nthe field/property initializers. However, we don't know how to do this for record structs. Field and property initializers in record structs\ncan use primary constructor parameters so the synthesized constructor would need to invoke the primary constructor to run field initializers,\nbut using default values for primary constructor arguments may be invalid. Ultimately, we don't think the inconsistency here is any better\nthan option 1: there would be 3 sets of rules for when a parameterless constructor would be generated. One for reference types (always unless\nthere is an explicit constructor), one for regular structs (always if there are field initializers), and one for record structs (always\nunless there is an explicit constructor, but you can call `new RecordStructType()` anyway).\n3. Never synthesize a parameterless constructor. This means that the simple case of just wanting to add a field initializer isn't supported:\na full constructor will have to be added. For example:\n```cs\nConsole.WriteLine(new S().field1); // This prints 0\n\nstruct S\n{\n    int field1 = 1; // No constructor is synthesized\n    int field2;\n    public S(int field2) => this.field2 = field2;\n}\n```\n This will get easier in the future with primary constructors, making it simple to just append `()` on the end of the struct name to add\n this constructor definition, but it will be unfortunate for now. Of the downsides in all of these options, this is the one we best\n understand, and more importantly while it is the least ergonomic, it does fully solve the issue around accidentally removing the\n parameterless constructor (which changes the behavior of source and is a binary break).\n\n#### Conclusion\n\nWe will go with option 3, never synthesizing a parameterless constructor. If a struct has field initializers with no constructors, this is\nan error. It is a break over C# 10 as initially released, but the fix is both simple and backwards-compatible with the initial version of\nC# 10, so we think we're still within our ability to make this change.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-01-05.md",
    "content": "# C# Language Design Meeting for January 5th, 2022\n\n## Agenda\n\n1. [Required Members](#discussion)\n\n## Quote of the Day\n\n- ![OHI Mark!](LDM-2022-01-05-OHIMark.jpg \"Image of Johnny from The Room in the roof scene, saying 'OHI Mark'\")\n- \"`System.Runtime.CompilerServices.HemlockAttribute`\"\n\n## Discussion\n\nhttps://github.com/dotnet/csharplang/blob/main/proposals/required-members.md\n\nToday was entirely devoted to going over open questions in required members, validating the recent specification\nupdates and debating the restrictions introduced.\n\n### Required properties accessibilities\n\nIn our initial version of the proposal, we had a complex meta-language around contracts, allowing individual members\nto be added or removed on a per-constructor basis. However, our recent design work has sought to pare back the complexity\nof the feature, which has lead to needing to revisit the topic of members that cannot be set by consumers of a type.\nSince constructors can only opt out everything or nothing, they don't have the tools to effectively deal with less visible\nmembers. Ultimately, we see 4 options for dealing with this:\n\n1. Disallow the scenario. This is the most conservative approach, and the rules in the OHI are currently written with\nthis assumption in mind. The rule is that any member that is required must be at least as visible as its containing type.\n2. Require that all constructors are either:\n    1. No more visible than the least-visible required member.\n    2. Have the NoRequiredMembersAttribute applied to the constructor. These would ensure that anyone who can see a\n    constructor can either set all the things it exports, or there is nothing to set. This could be useful for types that\n    are only ever created via static Create methods or similar builders, but the utility seems overall limited.\n3. Readd a way to remove specific parts of the contract to the proposal, as discussed in LDM previously.\n4. Require that the derived constructor must set any properties that are not at least as visible as itself.\n\nOf these, we are most interested in 1 or 2. 3 is readding complexity we specifically wanted to remove from this proposal,\nand while we can add it back at a later date, we're concerned about feature creep for the initial version. 4 has some \nconcerning impacts on implicit changes to the public API of a constructor: by making a member more visible than it is\ncurrently, a user could unintentionally expose requirements to their consumers they didn't mean to.\n\nFor 1 and 2, we think either would be acceptable. 2 is more flexible, but we also don't think the scenario it would cover\nis important to the feature. We think starting with the most conservative set of rules is acceptable, and keeping 2 or a\nmore complex meta-langauge in our back pocket for future requests.\n\n#### Conclusion\n\nWe will go with option 1: all required members must be at least as visible as their containing type.\n\n### Hiding\n\nWe verified the section of the specification on hiding, now that we have a decision on the principle for accessibility.\nUsers cannot access hidden members in an object initializer, so we agree that required members cannot be hidden. In the\nfuture, if we come up with some syntax for accessing a specific (potentially hidden) member, we should keep this scenario\nin mind.\n\n#### Conclusion\n\nSpecification upheld. We will disallow hiding required members.\n\n### Overriding\n\n#### Adding/removing `required` on override\n\nIn order to preserve our future design space on contract modifications, we want to disallow removing `required`ness on\noverride. We don't think adding `required` is a problem, as contracts are already additive today, but removing on a\nper-member basis is not supported in the other aspects of the proposal, so we think we should disallow here too.\n\n##### Conclusion\n\nAdding `required` on override is allowed. If the overridden member is `required`, the overridding member must also be\n`required`.\n\n#### Overriding `required` virtuals\n\nWe have another interesting question on overriding:\n\n```cs\nabstract class Base\n{\n    public required abstract int Prop1 { get; set; }\n    public required virtual int Prop2 { get; set; }\n}\n\nclass Derived : Base\n{\n    public required override int Prop1 { get; set; } // This is probably fine?\n    public required override int Prop2 { get; set; } // Is this ok?\n    \n    public void ToString()\n    {\n        _ = base.Prop1; // Already illegal\n        _ = base.Prop2; // What happens, was base.Prop2 initialized?\n    }\n}\n```\n\nThere is a general anti-pattern in C# around overriding a virtual property that has storage, and not delegating to that\noriginal storage. In particular, the above code overrides Prop2, and then explicitly goes to the base storage. While this\nis certainly an anti-pattern, we don't think `required` is the place to solve it. There are other logic errors that can result\nfrom this case, all of which relate to stale or incorrect data from accessing the wrong storage location. A warning or\nanalyzer would be better suited to addressing that problem in general, and `required` should not be opinionated beyond that.\n\n##### Conclusion\n\nNo specific restrictions. An analyzer can generally warn about this type of anti-pattern.\n\n### Metadata Representation\n\n#### `RequiredMembersAttribute`\n\nFinally today, we looked through the proposed metadata representation, verifying the general design. We have two proposals\nfor indicating the required members in a type:\n\n1. Put a single `RequiredMembersAttribute` on the type, listing every member of that type that is required.\n2. Put a `RequiredMemberAttribute` on the type, and then put a `RequiredMemberAttribute` on every member in that type that\nis required.\n\nWe're happy that both of these preserve our desire for _additive_ contracts: they both require walking up a type chain to\nget the full list of required members for a type, and additions to a base type do not require downstream changes. We think\nthe version with a single attribute is slightly more attractive, so we'll go with that one, but with a small modification\nto the lookup rules. The current proposal says that the lookup rules should be standard member lookup: we think this is\nneedlessly complex, and we can simply look at members defined in the current type. Future contract modification attributes\nmight need more complicated lookup rules, but we can address that when we get there.\n\n##### Conclusion\n\nDesign 1 is upheld, and the member lookup rules are simplified to just looking at members of the current type.\n\n#### Constructor protection\n\nOne of our desires for this feature is that removing required members is _not_ a binary breaking change. This means that our\nusual protection trick, putting a `modreq` on any constructor that must set required members, isn't going to work for this\nscenario; if a user removed the last `required` member from a type, that constructor would no longer have a `modreq` on it,\nbreaking binary compat. We therefore need to look at a different method of protecting required members. Our last prior art\nhere is in ref structs, which put an `ObsoleteAttribute` on the type with a specific message, that newer compilers could\nrecognize and specifically ignore. This solution is imperfect, however: `ObsoleteAttribute` can only be applied once, and if\nthe user is in an obsolete context (such as in an obsolete type/member) that obsolete marker is ignored. While some users do\nthis intentionally to work around restrictions, it's also very easy to accidentally hit just by virtue of working in a\nlegitimately actually obsolete member. We think this is unfortunate, and that we'd like to add a new trick to our toolbox for\nthese scenarios. We will look at adding a new attribute to the runtime for the express use of the compiler to \"poison\"\nsomething without affecting binary compat, and have the compiler start recognizing this attribute and specifically disallowing\nit. This won't help us for required members immediately: we'll need to apply both this new poison attribute and\n`ObsoleteAttribute`, and may need to continue doing so for some time. But we regret not adding such an attribute for ref\nstructs then, so we should go ahead and do this now.\n\n##### Conclusion\n\nWe will apply `System.ObsoleteAttribute` to constructors of types with required members, and work with the runtime team and\nother .NET language teams to add a new attribute specifically for poisoning types/members without affecting binary compat.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-01-12.md",
    "content": "# C# Language Design Meeting for January 12th, 2022\n\n## Agenda\n\n1. [Open questions for `field`](#open-questions-for-field)\n    1. [Initializers for semi-auto properties](#initializers-for-semi-auto-properties)\n    2. [Definite assignment for struct types](#definite-assignment-for-struct-types)\n2. [Generic Math Operator Enhancements](#generic-math-operator-enhancements)\n\n## Quote(s) of the Day\n\n- \"I should really get a beer, but I'll wait\" \"Stop [redacted], it's only 10:01 here\" ... \"What time is it there, snark-o'clock?\" \"It would be if I grabbed that beer\"\n- \"It was stupid syntax, but it was legal\"\n\n## Discussion\n\n### Open questions for `field`\n\nhttps://github.com/dotnet/csharplang/blob/4773c1bdb692aba574204a9affa890b0af3d2c05/proposals/semi-auto-properties.md#open-ldm-questions\n\n#### Initializers for semi-auto properties\n\nFor semi-auto properties, there is a question of where initializers are allowed, and what effect they have when written. Our existing rules are pretty simple:\nmanually-implemented properties cannot have initializers. Auto-properties can have initializers, and the effect of the initializer is assigning to the backing field.\nThe `field` keyword walks a fine line here, sitting squarely between both worlds. We think there's some main issues to solve:\n\n* If there is a manually-implemented setter, then an initializer cannot call the setter, as initializers run _before_ the constructor and setters can reference\ntype state. Initializers cannot reference type state, so this breaks the rules that rely on that invariant.\n* On the other hand, for manually-implemented setters, if an initializer assigned directly to the backing field this would cause a very visible but non-obvious\nbehavior difference between putting an initializer on a property and an initializer in the constructor. It is possible to observe a difference here today, but it\nrequired a virtual property overridden in a dervied type and is a much more niche case. We think this difference is both confusing and a potential footgun in waiting.\n\nTo solve this, we have a few options for restrictions on initializers:\n\n1. Treat semi-auto properties as if they are manually-implemented properties. This means they would not support initializers.\n2. Treat semi-auto properties with non-existent for auto-implemented setters as if they were auto properties. This means such properties would be allowed to have\ninitializers, and no other types of properties would be allowed to do so.\n3. Allow all properties with backing fields to have initializers. These would assign to the backing field, and there would be a meaningful difference between the\ninitializer and assigning in the constructor.\n\nAfter some discussion, we feel that 3 is a step too far. It could potentially be enabled later, if we can find a set of rules that makes sense and unifies the area,\nbut for the moment we don't have those rules. We also think 1 might be a bit too conservative: part of this feature is easing the cliff between full properties and\nauto properties. Disallowing initializers when the setter is \"trivial\" seems like it goes against this desire.\n\nThere's also some potential future overlap with [property-scoped fields](https://github.com/dotnet/csharplang/issues/133). These fields will, presumably, need to be\naccessible in a limited fashion from constructors or other locations that can access type state, in order to initialize them. `Lazy<T>` backing fields, for example,\nwill almost certainly need to be initialized with a delegate that references the current type, something that cannot be done from an initializer today. If we need\nmore granular control for the automatic backing field, we think we can rely on that proposal to allow this control.\n\n##### Conclusion\n\nWe have the following formalized rule for when initializers are permitted:\n\n* Initializers are permitted when a property has a backing field that will be emitted and the property either does not have a setter, or its setter is auto-implemented.\n\nWe have the following rule for when properties can be assigned in the constructor of a type:\n\n* Properties can be assigned in the constructor of a type if that property has a setter, or is a get-only property whose backing field will be emitted.\n\n#### Definite assignment for struct types\n\nSemi-auto properties pose a very interesting challenge for definite assignment in struct types. Today, all fields in a struct type must be fully initialized by any\nconstructor of that type. Existing auto properties are fine here: the compiler controls the implementation of the `set` method, and we know that they are not accessing\nany instance state other than the backing field, and not exposing `this` before assignment of all fields are completed. Semi-auto properties, by contrast, can have a\nuser-implemented `set` or `init` method, which has all the power a regular `set` or `init` method has. It can access instance state, potentially before some other part\nof the instance state has been assigned. Further, there is no way to mention the backing field from outside the property (this being one of the main selling points of\nthe feature). We see a few potential solutions for this:\n\n1. Require a chain to another constructor or a `this = default` before access to semi-auto properties is permitted. This a bitter pill, as property initializers run\nbefore the constructor body. This would mean any property initializers are blown away by the `this = default;` assignment.\n2. Have the compiler initialize all automatically-generated backing fields to `default`. This would allow skipping initialization of all auto and semi-auto properties,\nthe former of which is not allowed today. While we think this would work, it introduces inconsistencies between regular fields and backing fields, which is odd, and\nthere could be some clients that suffer from default initializers for all backing fields (mainly around perf).\n\nAfter some discussion, we're pretty conflicted here. We'll have a small group go and explore these ideas and other potential solutions and come back to the LDM with\ntheir findings.\n\n##### Conclusion\n\nNo answers today.\n\n### Generic Math Operator Enhancements\n\nhttps://github.com/dotnet/csharplang/issues/4665  \nhttps://github.com/dotnet/csharplang/issues/4666  \nhttps://github.com/dotnet/csharplang/issues/4682\n\nFinally, we took a look at 3 different operator-related enhancements for the generic math scenarios we're targeting for .NET 7/C# 11. We're supportive of all of them,\nbut the `checked` operator enhancements are definitely going to be the largest amount of work of the 3. There's new syntax and rules around what things are called when\nto be hammered out.\n\nFor relaxing shift operator requirements, we think that this rule has served its purpose. It is technically possible, via external libraries, to emulate `cout` and other\nshift operator semantics in C# today, but we don't see people doing this. Relaxing the restrictions will make it easier for those libraries to be written, but the general\npatterns for the language have been established at this point.\n\n#### Conclusion\n\nThese proposals are generally approved of. We'll look forward to reviewing the concrete designs soon, particularly around `checked`.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-01-24.md",
    "content": "# C# Language Design Meeting for January 24th, 2022\n\n## Agenda\n\n1. [Required members metadata representation](#required-members-metadata-representation)\n2. [Default implementations of abstract statics](#default-implementations-of-abstract-statics)\n3. [Triage](#triage)\n    1. [Nested members in with and object creation](#nested-members-in-with-and-object-creation)\n    2. [Binary Compat Only](#binary-compat-only)\n    3. [Attribute for passing caller identity implicitly](#attribute-for-passing-caller-identity-implicitly)\n    4. [Attributes on Main for top level programs](#attributes-on-main-for-top-level-programs)\n\n## Quote(s) of the Day\n\n- \"More knowledgeable, but scared is how I like to live my life\"\n- \"My new goal is to be able to say C# 11 has a 'spaceship operator'. I don't care what it does.\"\n\n## Discussion\n\n### Required members metadata representation\n\nhttps://github.com/dotnet/csharplang/discussions/5615#discussioncomment-1940488  \nhttps://github.com/dotnet/csharplang/blob/main/proposals/required-members.md\n\n[Last time](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-05.md#requiredmembersattribute) we discussed the metadata for required\nmembers, we had indicated that we tentatively preferred a single `RequiredMembersAttribute` on a type, which listed strings for each member in the type that\nwas required. We had not considered a couple of potential issues with this, however:\n\n1. IL is allowed to duplicate names for members, so long as the members are of a different kind. IE, a field and a property with the same name is perfectly\nlegal in IL.\n2. Non-compiler usages might become more difficult. Doc generation, for example, will want to be able to list the required members for a type, and reflection\nwill likely want to represent whether a member is required in that member reflection info. While still doable with the class-based attribute, it requires more\nwork than just looking on the member for an attribute.\n\nWe did have some initial concern with the many attribute approach that it would potentially impact load times for assemblies, like nullable was going to before\nwe invested in a compression strategy. After discussion with the runtime folks, however, we came to the conclusion that this is likely minimally concerning,\nas there won't be nearly the proliferation of these attributes that `NullableAttribute` would have had as originally designed. Thus, to make implementation and\nconsumption simpler, we will go with the `RequiredMemberAttribute` on every member that is required, and on a type that defines required members.\n\n#### Conclusion\n\nWe will adjust the specification to put a `RequiredMemberAttribute` on every member that is marked required, and to put it on any type that contains such members.\n\n\n### Default implementations of abstract statics\n\nAs part of determining our C# 11 focuses, we wanted to discuss default implementations for abstract statics, and whether we want to try and get them in during C#\n11, or in some future version of C#. Part of this is, of course, runtime dependent; if support isn't there, there's nothing for the language or compiler to\nimplement. From looking at our motivating scenarios, we have some comments on DIMs:\n\n* They're an important library design tool. Generic math would like to use them in a few scenarios, but it's not a \"critical\" feature to have in V1. If they\nslipped to C# 12, the scenario would be ok.\n* The ability to call base implementations is not a concern from a library design tool, and likely will not be designed for C# 11. We need to make sure to account\nfor the ability to call base DIMs for instance methods as well, so this is a bigger feature. We'll let prioritization be driven by user request.\n\n#### Conclusion\n\nIf the runtime support lands, we'll try to land the language side as well.\n\n### Triage\n\n#### Nested members in with and object creation\n\nhttps://github.com/dotnet/csharplang/issues/4587\n\nThere is some confusion around this proposal in `with` expression: what are the semantics going to be? In object initializers, nested member initializers do not\ncreate new objects, they just assign to existing ones. This makes the presented `with` syntax confusing, and we think it needs more workshopping. A potential\nalternative could be something like `a with { Member with { ... } }` to imply the nested withing, but this needs to be explored and fleshed out a bit more before\nwe are ready to commit to accepting the proposal.\n\n##### Conclusion\n\nNeeds more work.\n\n#### Binary Compat Only\n\nhttps://github.com/dotnet/csharplang/issues/4984#issuecomment-891213312\n\nAs part of the next issue, we heard about a nascent proposal around the ability to mark a method as for binary compatability only, removing it from overload resolution\nentirely. We think the idea has merit, but need to see a complete proposal on this before we move forward.\n\n##### Conclusion\n\nNeeds more work. Whoever looks at this should also look at a version where this is a flag on ObsoleteAttribute.\n\n#### Attribute for passing caller identity implicitly\n\nhttps://github.com/dotnet/csharplang/issues/4984\n\nThis attribute is useful for the BCL team and expands our caller info attributes. While we do have some reservations on how useful it will be until we get the above\nbinary compat only ability, we think this is fine. Some small details left to work out before we can add it to the working set or backlog though.\n\n##### Conclusion\n\nNeeds more work.\n\n#### Attributes on Main for top level programs\n\nhttps://github.com/dotnet/csharplang/issues/5045\n\nThis is important to unblocking partner scenarios, and we will be starting implementation shortly.\n\n##### Conclusion\n\nWorking set.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-01-26.md",
    "content": "# C# Language Design Meeting for January 26th, 2022\n\n## Agenda\n\n1. [Open questions in UTF-8 string literals](#open-questions-in-utf-8-string-literals)\n\n## Quote of the Day\n\n- \"Doesn't everyone love the native compiler?\"\n\n## Discussion\n\n### Open questions in UTF-8 string literals\n\nhttps://github.com/dotnet/csharplang/blob/main/proposals/utf8-string-literals.md#unresolved-questions  \nhttps://github.com/dotnet/csharplang/issues/184\n\nToday, we looked to answer some initial questions on the UTF-8 prototype implementation. It's important to note that this prototype is intended to be\nhanded off to partners to play with so we can get some feedback on what works and what doesn't: the rules we're deciding today are not intended to be\nthe final LDM rulings on the questions. We can and should revisit some or all of these questions after initial impressions are gathered from users.\n\n#### Conversions from null literals\n\nWe do have precedent in the language for conversions that depend on the constant value being converted: for example, integer constants can be converted\nto bytes if the constant value would fit in a byte. However, we don't think that it's necessary to special case here. We already allow `(string)null` to\nbe converted to `Span<char>` via a user-defined conversion, so we don't think there's any new ground being tread here. It does marginally widen the\nbreaking change surface, but we think that's ok for the prototype.\n\n##### Conclusion\n\nThe conversion will apply to null string constants.\n\n#### Conversion kinds\n\nAfter examining the existing types of implicit conversions, we think conversion is best specified as a new kind of conversion. It doesn't fit well into\nany existing conversion: constant conversions, for example, have both constant input and output values. This conversion won't have a constant output\nvalue.\n\n##### Conclusion\n\nWe will introduce a new conversion kind for string constant to UTF-8 bytes.\n\n#### Implicit standard conversion\n\nThe next question after deciding on a separate kind is whether this conversion will be a standard conversion or not. This impacts whether it can be used\nas an input or output conversion for user-defined conversions, and is also where history complicates our decision a bit. The native C# compiler (used\nfor C# 5 and earlier) implemented the spec incorrectly and considered more conversions to be standard than actually are, leading to an experience that\nis potentially inconsistent, no matter what we do. For now, though, our initial gut reaction is that there's too much involved in one of these conversions\nto be considered in the list of standard conversions. We will revisit this question after prototype feedback.\n\n##### Conclusion\n\nNot a standard conversion, for now.\n\n#### Expression tree representation\n\nIn theory, this conversion could be represented in an expression tree just as the final bytes wrapping an array creation. However, the conversion itself\nhas semantic meaning, and we think that it's important for expression trees to show this meaning. Therefore, we will block this conversion in expression\ntrees, and future modernization efforts will consider this case well.\n\n##### Conclusion\n\nBlocked.\n\n#### Natural type of `u8` literals\n\nSince this is a prototype, we think that the proposed `byte[]` is fine for now. We will likely want to have a deeper debate about whether string literals\nshould have a natural type of a mutable array, but we don't think that debate is necessary for now.\n\n##### Conclusion\n\nThe natural type of `u8` literals will be `byte[]`, for the prototype.\n\n#### Conversion depth\n\nThere is some interplay here with the standard conversion rules: if the conversion is a standard conversion, then any place that takes a `byte[]` as a\nuser defined conversion would be able to take a string literal. That leaves things like `IEnumerable<byte>`, which standard conversions have no impact\non.\n\nThere's a slippery slope here. If we don't make the conversion a standard conversion, then there's a potentially-infinite number of places to make the\nconversion work. We'll err on the side of getting feedback for now: the current set of conversion targets (`byte[]`, `Span<byte>`, and `ReadOnlySpan<byte>`),\nand we'll see what users think after using the prototype.\n\n##### Conclusion\n\nNo new conversion targets added for now.\n\n#### Breaking changes\n\nThis one is definitely the trickiest of the issues we're discussing. We just made a big breaking change in C# with lambda natural types. This was\nsuccessful, but it took a lot of users using the feature and telling us what was broken for us to hammer down the rules. The better function member\nrule as proposed will address some of the breaking changes, but not all: new instance methods could be called instead of extension methods, for example.\nAdditionally, the justification we used for such changes with lambdas does not apply here. The justification for lambdas was that any extension methods\nalmost certainly delegated to the original method, just providing a target type. This reasoning almost certainly does not hold up for `byte[]` vs `string`.\n\nWe think the best way to gather feedback is again to be bold and have the prototype make no adjustments at all. This will almost certainly break some\npeople, but based on the lambda feature we have real evidence that people use our previews and report back to us when things break. This feedback will be\nused to help determine how agressive we need to be around breaking changes, or whether we need to abandon the conversion form entirely and only do a `u8`\nsyntax form.\n\n##### Conclusion\n\nThe prototype will not adjust any rules here, so we can hopefully see what breaks in practice.\n\n#### Suffix case sensitivity\n\nWe should be consistent with other constant suffixes.\n\n##### Conclusion\n\nConsistency means that `u8` or `U8` will be allowed.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-02-07.md",
    "content": "# C# Language Design Meeting for February 7th, 2022\n\n## Agenda\n\n1. Detailed review of https://github.com/dotnet/csharplang/blob/main/proposals/checked-user-defined-operators.md (AlekseyTs)\n\n## Checked user-defined operators\nhttps://github.com/dotnet/csharplang/blob/main/proposals/checked-user-defined-operators.md\n\n### Syntax\nWe discussed a few syntax options:\n1. `checked` after `operator`\n2. put `checked` before `operator`\n3. use `checked` modifier\n\nConclusion: Stick with proposed syntax (option 1, `checked` after `operator`).  \nPS: it will be nice for implementation to gracefully handle invalid combinations, like `checked +`.\n\n### Checked implicit conversions?\n\nWe clarified why conversions cannot be `implicit` and `checked`.\nGenerally, implicit conversions should not fail, throw or be lossy. That's already the case with (most) existing conversions and .NET guidelines.\nThere's an exception: integer to floating point conversion in C# does allow loss.\n\nConclusion: Stick with proposed restriction (conversions cannot be `implicit` and `checked`).\n\n### Explicitly `unchecked` operators\n\nThe proposal is that there are `regular operators` (without a keyword) and `checked operators` (with `checked` keyword), but there is no keyword like `unchecked` to express the \"no keyword\" default.\nIn some other discussions, we have have allowed a keyword to make the default explicit, but it doesn't feel that useful here. Legacy operators don't exactly have the `unchecked` meaning.\n\nConclusion: No explicitly `unchecked` operator (whether semantically equivalent to regular operators or some other meaning).\n\n### Restricting allowed combinations of declared operators?\n\nShould there be some requirements on having both operators when a `checked` operator is declared?\n\nWhat combinations do we allow?\n0. provide none\n1. provide both\n2. provide only regular/unchecked\n3. provide only checked\n\nThe only combination we could consider restricting is (3).\nBut that seems a valid case when you don't know what to do for overflow.\nThere's a question whether should declare a regular operator in such case.\n\nConclusion: No requirement. We may revise this after follow-up discussion on overload resolution rules.\n\n### Is the body of a checked operator in checked context?\n\nThere's a risk users would assume that `checked` keyword affects context in method body.\nBut we feel users are likely to want to implement their own checks and use unchecked logic in the body, and we don't want such cases to require use of `unchecked`:\n```\noperator checked ++(...)\n{\n    unchecked { ... }\n    _ = unchecked(...);\n}\n```\n\nFor example, some types like uint128 need some checked and some unchecked logic in their checked operators:\n```\nresult.lower = left.lower + right.lower; // overflow is expected/by-design\nresult.upper = left.upper + right.upper; // overflow is an exception for checked operator\n```\n\nWe considered some possible rules for producing a warning. For example: a `checked` operator must has an `checked` or `unchecked` block/context.\n\nConclusion:\nNo warning in the language. We encourage analyzer or IDE help. Can be revised based on feedback.\n\n### Names in metadata\n\nProposal API names seem straightforward but should be reviewed through API review.\nop_UnsignedRightShift already establishes precedent on naming schema.\n\n### Overload resolution\n\nWe reviewed the alternatives listed in the proposal doc, and explored some variants.\nIt's not obvious that we should favor a checked operator on base type over an unchecked/regular operator on closer type, in a checked context.\nIt's not obvious whether the rules should be symmetric (checked picked first in checked context, unchecked/regular picked first in unchecked context) or asymmetric (checked operator can only be picked in checked context).\nWe discussed how to represent a type with only a checked operator. Should that literally be a `checked` operator, or rather a regular operator?\n\nThe main alternative proposal we explored:\n1. lookup would find the nearest applicable candidate (`checked` operator only applicable in checked context, regular operator applicable in either context)\n2. in checked context, if there's any `checked` candidates, discard the unchecked ones\n\nConclusion: proposal will be spelled out and re-discussed in LDM.\n\n"
  },
  {
    "path": "meetings/2022/LDM-2022-02-09.md",
    "content": "# C# Language Design Meeting for February 9th, 2022\n\n## Agenda\n\n1. Continue discussion of checked user-defined operators\n2. Review proposal for unsigned right shift operator\n3. Review proposal for relaxing shift operator requirements\n4. Triage champion features\n\n## Quote(s) of the Day\n\n* \"Sorry, Jared, gonna have to veto that. Somebody else say something funny in the next 40 minutes\"\n\n## Discussion\n\n###  Checked user-defined operators (cont'd)\n\nhttps://github.com/dotnet/csharplang/blob/main/proposals/checked-user-defined-operators.md\n\n* We discussed the expected behavior for checked operators in Linq expression trees. Checked operators will be supported via UnaryExpression and BinaryExpression expressions in tree.\n  * The `BinaryExpression` already supports `Checked` expression types that determine whether or not the operation is occuring in a checked context.\n  * The `MethodInfo` stored in `expression.Method` will provided information about whether or not the operator used is a checked operator.\n* We discussed the possibility of supporting invoking `checked operators` in `dynamic` invocations.\n  * Behavior can be adjusted in Core but not in framework\n  * We discussed the possibility of disabling the feature on platforms that do not support dynamic invocation via a runtime flag through `RuntimeFeature`.\n    * This would be the first time that we introduce a runtime feature flag for a C# langauge feature as they are typically intended for runtime limitations.\n  * We discussed the set of possible options for resolving this:\n    * Option 1: Do not add support for this.\n    * Option 2: Only implement for CoreCLR and assume that dynamic evaluation behavior will be different in Framework.\n    * Option 3: Adjust the runtime binder across all platforms (most expensive option).\n  * There is prior art for scenarios where we have added language features but did not make modifications to the runtime binder, such as for default interface methods.\n    * We acknowledge that support has been added for smaller features in the past but that we don't consistently evolve the runtime binder with the language.\n  * **Conclusion:** We will investigate the cost of adding support for `checked operator`s in dynamic invocation in CoreCLR and pursue an implementation if the cost is not too high.\n\n### Unsigned right shift operator\n\nhttps://github.com/dotnet/csharplang/blob/main/proposals/unsigned-right-shift-operator.md\n\n- We examined the behavior of support unsigned shift operator as a built-in and user-defined operator.\n- The unsigned shift operator will generally match the behavior of other shift operators when it comes to aspects around grammar ambiguities, precedence, and more.\n- The operator will support target the same built-in types as the signed right shift operator.\n  - :warning: The spec currently outlines that the right shift operator supports fewer types than it actually does. For example, the right shift operator does support target `nint`s and `nuint`s but this is not documented. We should follow up on updating the spec to synchronize with the acactualmplementation.\n  - To this end, the unsigned shift operator will support the same set of types that the signed shift operator does in implementation.\n- We discussed some of the challenges around supporting `>>>` in Linq expression trees. \n  - Proposal 1: For user-defined operators, a `BinaryExpression` node targeting the operator method will be created. For built-in operators, a `BinaryExpression` node will only be created if the first operand is an unsigned type. For scenarios where the first operand is a signed type, a conversion from signed to unsigned will happen before the `BinaryExpression` node is created, then converted back to a signed type.\n  - Proposal 2: Do not add support for `>>>` in Linq expression trees as part of this change.\n  - Proposal 3: Do not add support for `>>>` in Linq expressions as part of this change but place to introduce a new node type for handling unsigned types in `BinaryExpression`s.\n  - **Conclusion:** We'll adopt Proposal 3 and not add support for `>>>` in Linq expressions in the initial phase of this work.\n\n### Relaxing shift operator requirements\n\nhttps://github.com/dotnet/csharplang/blob/main/proposals/relaxing_shift_operator_requirements.md\n\n* To support some generic math scenarios, we are relaxing the requirements for shift operators so that the right-hand operator is no longer restricted to an `int` type.\n* We recognize that the restrictions on the type of the second operand were placed intentionally to avoid unintended behavior (e.g.  `cout << \"foobar\"`) but recognize that the benefits of relaxing the constraint outweight the benefit of stricter requirements on the operator.\n* **Conclusion:** We support relaxing the constraints to support these new scenarios and recognize that this opens the door to strange behavior.\n\n## Triage\n\n### Collection literals\n\nhttps://github.com/dotnet/csharplang/issues/5354\n\n* This proposal already has general approval from LDM but needs to be fleshed out further in a working group.\n* Conclusion: Place this issue in the **Working Set** milestone.\n\n###  Label statements\n\nhttps://github.com/dotnet/csharplang/issues/5470\n\n* This proposal outlines adding support for label as a statement on its own to avoid scenarios where a `:;`  has to follow labels that are defined at the end of a scope, which impacts readability.\n\n```csharp\nif (!Condition()) goto AfterWork;\nWork();\nAfterWork:;\n```\n\n* This issue was discovered in the context of the Regex source generator, but since labeled statements are frequently used in high-performance code it can also appear in non-generated source as well.\n\n* Conclusion: The problem is valid and the proposed solution is elegant and non-invasive. Place this issue in the **Any Time** milestone due to lack of urgency.\n\n###  Roles and extensions\n\nhttps://github.com/dotnet/csharplang/issues/5497\n\n* This issue has been previously discussed in an LDM and is being followed up on.\n* Conclusion: Place in **Working Set** milestone.\n\n### \"file private\" Visibility\n\nhttps://github.com/dotnet/csharplang/issues/5529\n\n* This proposal outlines adding a mechanism to support limiting the visibility of a types to a particular file.\n* Other lanuages have the ability to hide types from other files in the build including signature implementation files in F# and package level visibility configuration in Go.\n* There was a variety of discussion about the pros/cons of different levels of visibility for this feature including file-based visibility and namespaced-based visibility to support for local types.\n  * Implementations in other languages have varied levels of scoping from file-based to type-based.\n* **Conclusion:** We generally agree that there is merit to solving this problem, but some more details need to be fleshed out before we can examine the proposal more fully. Marking this one as a candidate for surfacing back to the committee.\n\n### Adding Index support to existing library types\n\nhttps://github.com/dotnet/csharplang/issues/5596\n\n* This proposal outlines adding support for implicit Index types to existing library types (e.g. `List.Remove`) to allow existing overloads to work with indexors.\n* We discussed some general concerns around overload resolution with this change and the need to have sensible rules for when an `Index` type is supported in a feature.\n  * The current proposal limits this implicit support to APIs that accept an `int index` parameter but this does not capture:\n    * APIs that might use other types, such as `long`, particularly for those that are in libraries targeting \"big data\" scenarios (machine learning, GPU-based work, etc.)\n    * APIs that use alternative parameter names (e.g.`position` or `offset`) for arguments that can be treated as indexors.\n    * Scenarios where an API might have multiple arguments (e.g. `(int index, int length)` ) not all of which can be treated as an index.\n* We discussed the benefits of this work, particularly in reducing the number of new overloads that need to be added and ensuring that users don't have to be on a particular version to use the new Index-based APIs.\n* We discussed whether it would be sensible to provide an opt-in or an opt-out for some of the functionality to account for scenarios where the overload resolution in a way that doesn't adhere to the users expectations\n* **Conclusion:** Place in **Working Set** milestone and bring it as an agenda item in an upcoming LDM meeting.\n\n\n\n"
  },
  {
    "path": "meetings/2022/LDM-2022-02-14.md",
    "content": "# C# Language Design Meeting for February 14th, 2022\n\n## Agenda\n\n1. [Definite assignment in structs](#definite-assignment-in-structs)\n2. [Checked operators](#checked-operators)\n\n## Quote of the Day\n\n- \"Do we have any historical records on how the early design meetings handled bio breaks?\"\n\n## Discussion\n\n### Definite assignment in structs\n\nhttps://github.com/dotnet/csharplang/issues/5737\n\nAs part of designing the semantics of the `field` keyword in value types, we have to decide what the impact to definite assignment is.\nIn a [previous meeting](LDM-2022-01-12.md#definite-assignment-for-struct-types), we looked at some possible solutions, and a small group\nmet to discuss a couple of possible solutions:\n\n1. Require `this = default;` in the constructor of the struct. We quickly discarded this as unusable: we just added field initializers,\nand this would completely blow those initializers away.\n2. Automagically initialize all backing fields to default. We like this idea, but are concerned it's very broad, and would lead to double\ninitialization\n3. Provide a way to assign the backing field of an auto or semi-auto property and require users to assign it. We thought this was tedious,\nand could potentially lead to user confusion.\n\nOf the 3 options, we liked 2 the best. However, futher thought lead to the idea being debated today, which is to repurpose the existing\ndefinite assignment for struct parameters to be used for determining what fields need to be assigned by default.\n\nIn order to think about this, we wanted to look back at the original design for structs, and examine why C# didn't take this route in the\nbeginning. While there are currently no members of the LDT who were on the design team at that time, we have a decent understanding of the\nreasoning here:\n\n1. C# originally had \"making porting from C really easy\" as a top-of-mind issue. In C/C++, value types are often initialized by assigning\nto all the components of the value directly, rather than by calling any named constructor. In order to make this work with the concept of\ndefinite assignment in C#, that meant that the struct must be able to be considered definitely assigned after all components have been\ninitialized (this was the source of the bug in the native compiler that resulted in [CS8882](https://github.com/dotnet/roslyn/issues/30194)).\n2. For consistency with local definite assignment for value types, the constructor of a value type has similar restrictions. For `this` to\nbe accessible in the constructor, it must fulfill similar restrictions to `this` as a local.\n\nHowever, this \"similar restrictions\" reason has a hole in it: regular partial properties already throw a wrench in the mix by creating an\nanonymous field that can't be seen by anyone. Further, since private fields aren't visible outside the struct, there was already a hole in\nthis logic from the start. We think that, given these points, using definite assignment for this purpose with the option to activate warnings\nto go back to the original behavior in C# 10 and prior is a fine solution. We will follow up with emeritus members of the LDT who were\npresent when the original restrictions were made, but barring any large revelations we like this approach.\n\n#### Conclusion\n\nProposal is accepted, contingent on following up with emeritus LDT members on original reasoning around struct definite assignment.\n\n### Checked operators\n\nhttps://github.com/dotnet/csharplang/pull/5740  \nhttps://github.com/dotnet/csharplang/issues/4665\n\nFollowing the last [2](LDM-2022-02-07.md) [meetings](LDM-2022-02-09.md#checked-user-defined-operators-contd) on checked operators, we\nreviewed the detailed update on checked operators. In general, this is attempting to resolve the hierarchy of importance for operator\nresolution, where the elements are:\n\n1. Nearness of the operator - how far up the type hierarchy is the operator? IE, defined on the type being used, or on its base, or\nthat type's base, etc.\n2. Betterness - this is standard overload resolution, ie which types are better suited.\n3. Checkness - this is a new axis for operator resolution: whether we're in a checked context or not.\n\nFor existing resolution, the order is nearness, then betterness. Containing types are searched _until_ an applicable operator is found,\nand then all operators from that type are added to the candidate type list and no further types are searched. At that point, the candidates\nare narrowed via betterness rules. Importantly, this means that, even if an operator further up the tree is \"better\" (types are a more exact\nmatch), it will never be found because nearness is more important than betterness. In the previous meetings, we decided that, for the new\naxiom of checkness, checkness is less important than nearness, but more important than betterness, and for the most part the new rules\nreflect this.\n\nHowever, we are still a bit conflicted on this ranking of axioms. Part of this conflict is in how the operators are defined; we don't have\n\"checked\" and \"unchecked\" operator flavors, we have \"checked\" and \"default\" operator flavors. This means that, in derived type that provides\na single default operator, that default operator will always be preferred, even if the base type defines a checked operator. This implies that\ncheckness is less important than nearness; in the linked PR, this is example 4. _However_, the rules are also written that, in unchecked\ncontexts, no checked operators are even considered. If nearness was truly more important than checkedness, then if we encounter a type with\nonly `checked` operators, we should stop lookup, and then fail to resolve an operator because that type doesn't define an appropriate default\noperator. However, that's not the proposal states: instead it only looks for default operators, completely ignoring all checked operators (shown\nin example 5). This difference has a few members of the LDT uncomfortable, and we think we need more time to mull the rules over.\n\nWe also acknowledge that, no matter whether checkness or nearness is ultimately more important, the BCL team is going to need to have careful\nguidance on breaking changes with introducing new checked versions of operators, as a new checked operator will always be considered better\nfor a checked operation than all default operators on a given type. This is also another source of tension around our concern here: if nearness\nis more important than checkedness, then any subtype that introduces a new checked operator must introduce default operators as well, so that\nthey don't break any users of the operators from a base type. The same is true in reverse for checkness being better than nearness: if checkness\nis more important, than any subtype that introduces a new default operator must also introduce a checked version of that operator, to ensure that\nthe base type's checked operator is not erroneously preferred over the subtype's.\n\n#### Conclusion\n\nNo conclusion was reached today. We need to think more about this scenario.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-02-16.md",
    "content": "# C# Language Design Meeting for February 16th, 2022\n\n## Agenda\n\n1. [Open questions in `field`](#open-questions-in-field)\n2. [Triage](#triage)\n    1. [User-defined positional patterns](#user-defined-positional-patterns)\n    2. [Delegate type arguments improvements](#delegate-type-arguments-improvements)\n    3. [Practical existential types for interfaces](#practical-existential-types-for-interfaces)\n    4. [Static abstract interfaces and static classes](#static-abstract-interfaces-and-static-classes)\n\n## Quote of the Day\n\n- \"It's not as if we don't have guns lying around that you can point at your foot in the rest of the language\"\n\n## Discussion\n\n### Open questions in `field`\n\nhttps://github.com/dotnet/csharplang/issues/5703  \nhttps://github.com/dotnet/csharplang/issues/140\n\nOur open question today is whether `field` can be shadowed in a nested scope in a semi-auto property. For prior art, we looked at two scenarios:\n\n1. In C# today, fields can be shadowed by parameters or locals. This is done intentionally, as it is a common pattern to have a local or parameter with the same\nname, and then assign to the type's field by using `this.` as a prefix. We don't have that same intentionality of purpose here: `field` does represent an anonymous\nfield in the type, but that field isn't actually named `field`, and there's very little logical reason to name a local `field` to intentionally shadow the implicit\nbacking field keyword.\n2. `value` is an invalid local name in property setters, as there is an implicit parameter named `value` and parameters cannot be shadowed by locals. However, the\nreasoning doesn't appear to hold water for `field`, as `field` is not parameter.\n\nUltimately, we think that since `field` represents a field in the type, even if anonymously, the shadowing rules of regular fields should apply. This means that the\n`field` keyword can be shadowed by parameters or locals in a nested scope.\n\n#### Conclusion\n\n`field` can be shadowed by parameters or locals in a nested scope.\n\n### Triage\n\n#### User-defined positional patterns\n\nhttps://github.com/dotnet/csharplang/issues/4131\n\nUser-defined patterns, also known as active patterns in F#, are extremely powerful, but when designing them we need to be sure we're not painting ourselves into a\ndesign corner for other future pattern enhancements. There are also some interesting questions we will have to answer around exhaustiveness. Regardless of these\nquestions, we see active patterns as one of the last pattern-related things that need to be added to the pattern feature to make it generally \"complete\", and are\nexcited to look at them after we land the current pattern work.\n\n##### Conclusion\n\nInto the backlog, for after we finish the current pattern features.\n\n#### Delegate type arguments improvements\n\nhttps://github.com/dotnet/csharplang/issues/5321\n\nWe previously looked at this in LDM [here](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-10-25.md#delegate-type-argument-improvements), but\ndidn't triage it at this time. Our feelings haven't changed, and we want more exploration of the generalized version before more active work can continue.\n\n##### Conclusion\n\nInto the backlog.\n\n#### Practical existential types for interfaces\n\nhttps://github.com/dotnet/csharplang/issues/5556\n\nThere is still some discomfort on the LDM around munging of generic parameter lists, but we like having a real translation proposal for this. We wonder if there is\nsome way that, with the restrictions imposed on existential types in this proposal, we could have the runtime do the translation without previously-expressed concerns\nabout combinatoric generic explosion, since all usages of these interfaces must already be generic. We think this will be a good thing to explore post roles, as we're\nactively thinking about them now and don't want to have too many huge type-system changes in flight at the same time.\n\n##### Conclusion\n\nInto the backlog.\n\n#### Static abstract interfaces and static classes\n\nhttps://github.com/dotnet/csharplang/issues/5783\n\nThis would be a nice hole to fill, as long as it comes with either an anti-constraint for allowing static classes as type parameters, or simply removing the restriction\nentirely.\n\n##### Conclusion\n\nInto the working set.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-02-23.md",
    "content": "# C# Language Design Meeting for February 16th, 2022\n\n## Agenda\n\n1. [Pattern matching over `Span<char>`](#pattern-matching-over-spanchar)\n2. [Checked operators](#checked-operators)\n\n## Quote of the Day\n\n- \"If Memory serves?\"\n\n## Discussion\n\n\n### Pattern matching over `Span<char>`\n\nhttps://github.com/dotnet/csharplang/issues/1881  \nhttps://github.com/dotnet/csharplang/blob/main/proposals/pattern-match-span-of-char-on-string.md\n\nWe started today by going through the proposal for allowing matching `Span<char>` and `ReadonlySpan<char>` instances against `string` literals. This is an\nAny Time feature being implemented by a community contributor, and has a few open questions left before it will be ready to be merged. Most places in this section\nthat use `Span<char>` are actually referring to both `Span<char>` and `ReadonlySpan<char>`, unless called out otherwise.\n\n#### Non-constant matches\n\nMatching a `Span<char>` to a `string` is interesting as a pattern feature because it's the first time that we're matching an input to a value that is non-constant.\nMatched constants can be subjected to a conversion today: for example, `obj is uint and 1` will convert the `1` integer value in the pattern to a `1` unsigned\ninteger value. The result of this conversion, though, is itself a constant value. For `Span<char>`, this isn't the same. `spanValue is \"Hello world\"` needs to\nconvert `\"Hello world\"` to a `ReadonlySpan<char>`, the result of which is _not_ a constant value. It could be argued, therefore, that this should not be permitted,\nand instead the scenario should wait for [active patterns](https://github.com/dotnet/csharplang/issues/1047). However, we think that this scenario is still morally\nconstant, even if not strictly semantically constant. We can additionally emit better code for the scenario than we currently think active patterns could, as it will\nbenefit from our existing optimizations around string comparisons.\n\n##### Conclusion\n\nWe are ok with allowing a morally constant pattern, even if it's not semantically constant.\n\n#### Specification terms\n\nThis question is around how we should specify the comparison: should we specifically call out `MemoryExtensions` in the specification and require it to be provided\nby the framework, or should we have some kind of fallback ability?\n\nIn supported all distributions, `MemoryExtensions` and `Span`/`ReadonlySpan` have been either been directly in the framework together, or have been shipped as part\nof the same NuGet package. So we don't think there are any places where `Span` would be present, but the `SequenceEquals` method for comparison won't be.\nSpecifying in terms of `MemoryExtensions` is also much easier for the implementation: if we have some kind of fallback ability, then that code has to be implemented\nand tested, all in service of a scenario that we think is extremely unlikely.\n\n##### Conclusion\n\nWe will specify the feature in terms of `System.Memory.MemoryExtensions`.\n\n#### `null` constants\n\nWe considered whether `null` should match against an empty `Span<char>`, since `null` is convertible to `Span<char>`, and the result is an empty `Span`.\n\nThere are some pros and cons to going either direction. In favor of allowing `null` to match, `Span<char> s = null;` works today, so it will be odd if `s is null`\nwould then fail to compile. On the other hand, the subsumption rules start to differ from string, and in a way that's very hard to explain. `s is null or \"\"` would\nfail to compile and `\"\"` would say that it was already handled by a previous case: we think this is more confusing than a clear error message stating that `null`\ncannot be used to match against a `Span<char>`, please use `\"\"` instead.\n\n##### Conclusion\n\nWe will not allow `Span<char>`s to be matched against `null` constants.\n\n#### Type tests\n\nWe universally agreed that the input type must be known to be `Span<char>`. This is similar to how other constants work, such as this `uint` example:\n\n```cs\nusing System;\n\nuint u = 1;\nConsole.WriteLine(u is 1); // true\nConsole.WriteLine(((object)u) is 1); // false\nConsole.WriteLine(((object)u) is uint and 1); // true\nConsole.WriteLine(M1(u)); // false\nConsole.WriteLine(M2(u)); // true\n\nbool M1<T>(T t) => t is 1;\nbool M2<T>(T t) => t is uint and 1;\n```\n\n##### Conclusion\n\nInput type must be `Span<char>` to be matched as a `Span<char>`. No implicit type tests will be emitted.\n\n#### Subsumption rules\n\nBased on our discussion around `null` constants, we think the subsumption rules for `Span<char>` should match the subsumption rules for `string`s, since they are both\nbeing matched with `string` constants. We think that there are a couple of open questions for Utf8 strings and list patterns though:\n\n1. Should Utf8 strings allow pattern matching as well?\n2. Should `string` patterns contribute to subsumption in list patterns over that same value? For example, should `stringValue is [] or \"\"` report an unreachable case?\n\n##### Conclusion\n\nUse the same subsumption rules as `string`s.\n\n### Checked operators\n\nhttps://github.com/dotnet/csharplang/issues/4665\n\n[Last time](LDM-2022-02-14.md#checked-operators) we discussed checked operators, we made no solid conclusions on the lookup rules. At the core of our concerns\nwith the lookup rules was concern over what principle was the \"most important\" part of lookup: nearness (how far up the type hierarchy did the compiler have to\ngo to find the operator) or checkness (whether the current context is checked or unchecked). We've had a few different versions of the lookup rules here:\n\n* Version 1 was the original proposal for\n[unary operators](https://github.com/dotnet/csharplang/blob/7dcc4e6903e2d80b52d21bd8901df964cd16a708/proposals/checked-user-defined-operators.md#unary-operator-overload-resolution)\nand\n[binary operators](https://github.com/dotnet/csharplang/blob/7dcc4e6903e2d80b52d21bd8901df964cd16a708/proposals/checked-user-defined-operators.md#binary-operator-overload-resolution).\nThis was originally discussed on [February 7th](LDM-2022-02-07.md#overload-resolution).\n* Version 2 was updated based on that feedback in\n[this version](https://github.com/dotnet/csharplang/blob/136d05563a881a451b78034196e4a5becfcc28bc/proposals/checked-user-defined-operators.md#unary-operator-overload-resolution).\nThis was discussed on [February 14th](LDM-2022-02-14.md#checked-operators).\n* Finally, we have a new version of the rules to consider today:\n    > 1. In an unchecked context, `checked` operators are ignored.\n    > 2. In a checked context, when we find a `checked` operator in `T0` we take that candidate but we ignore its regular counterpart (ie. in `T0`, same signature, but no `checked`) if any.\n    > All the other rules (resolution, betterness) can remain as they are today.\n\nThis final version is an attempt to codify that, on its own, a single unmarked operator means \"all operations\", but when paired with a marked `checked` operator,\nit's actually an `unchecked` operator. This is an idea that had been originally put into the `checked` operator proposal, but we had tried to step away from it\nand maintain existing operators as applicable to both `checked` and `unchecked` scenarios. As we tried to work through the effects on lookup, however, this seemed\nincreasingly complicated and hard to reason about, so we are revisiting the idea.\n\nWe further considered whether we should require that, if a type defines a `checked` operator, it should also be required to define an unchecked version. There is\nthe potential that this requirement could be onerous for some types that don't have a well-defined `unchecked` version, but those types have tools to express that:\neither continue to use a single unmarked operator, meaning it will be used for all `checked` and `unchecked` operations, or explicitly mark the `unchecked` version\nwith `Obsolete` and throw from the body. We think that this nicely sets us up for success here: introducing a `checked` operator at level requires that we go from a\ndefault operator world, which just has a single unmarked operator, into a world that knows about `checked` and `unchecked` contexts. This allows us to design the\nlookup rules coherently to favor nearness, then checkedness, then betterness, as we wanted to. We still need to finalize the exact wording of the rules, but we liked\nthe general principle of option 3. The compiler and the rules will still need to handle cases when a user manually defines a single `checked` operator without an\n`unchecked` version, either in IL or by making a method with the right names and attributes to appear to be an operator, but this is analogous to other operator\nscenarios the compiler needs to deal with today.\n\nFinally, we discussed whether we should allow and/or require `unchecked` for unchecked counterpart operator. However, we did not have enough time to dig much into\nthis, beyond realizing the room is evenly split among the three camps (required vs allowed vs disallowed), so a future meeting will need to resolve this.\n\n#### Conclusion\n\nWe will require that declaring a `checked` operator means there must be a counterpart unchecked operator, and a future meeting will decide whether this counterpart\noperator can or must be marked with `unchecked` or not.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-02-28.md",
    "content": "# C# Language Design Meeting for February 28th, 2022\n\n## Agenda\n\n1. [Ref fields](#ref-fields)\n    1. [Encoding strategy](#encoding-strategy)\n    2. [Keywords vs Attributes](#keywords-vs-attributes)\n    3. [Breaking existing lifetime rules](#breaking-existing-lifetime-rules)\n\n## Quote of the Day\n\n- \"I want to see your all reactions to how crazy I sound\"\n\n## Discussion\n\n### Ref fields\n\nhttps://github.com/dotnet/csharplang/blob/3d557a45ab03597aca4ccc24ba6eaacbcc930431/proposals/low-level-struct-improvements.md#open-issues\n\nToday, we looked at open questions in the `ref field`s proposal, specifically around tradeoffs between enforcement and the approach to the feature.\n\n#### Encoding strategy\n\nhttps://github.com/dotnet/csharplang/blob/3d557a45ab03597aca4ccc24ba6eaacbcc930431/proposals/low-level-struct-improvements.md#to-use-modreqs-or-not\n\nOur general question here is whether to use `modreq`s as the encoding mechanism for the various semantic elements of the feature, or if we should instead\nuse attributes. Using attributes as the encoding mechanism would allow APIs to evolve their surface areas without a binary breaking change later: for\nexample, if a library forgot to add `DoesNotEscape` (or whatever the final syntax for such a thing ends up being), they could add that attribute later\nwithout it being a binary-break to do so. We therefore need to decide whether we consider such elements an integral part of the method signature, and\nwhether this compat scenario is something we feel is likely. After a bit of discussion, we concluded that, except for potentially as part of the initial\nattribution of existing BCL methods, the idea that something does or does not escape is integral to the design of a method, and we don't find it likely\nthat there will be a general need to change the ref struct capturing of a method after it shipped. Meanwhile, `modreq` gives us much stronger enforcement\nof the safety rules, and the safety rules are integral to avoiding all sorts of memory safety issues. It is better in this area for a binary break to\noccur than for an accidental RCE to be opened because memory escaped where it wasn't expected to on binary upgrade.\n\n##### Conclusion\n\nWe will use modreqs for encoding the safety rules.\n\n#### Keywords vs Attributes\n\nhttps://github.com/dotnet/csharplang/blob/main/proposals/low-level-struct-improvements.md#keywords-vs-attributes\n\nNow that we've decided on using `modreq`s as the encoding mechanism, we can look at how they should be applied by a user. This is going to be a complex\narea for this feature: there are entire languages (ie Rust, M#, and others) that ingrain lifetime management into the language itself, from the very\nbeginning. The initial proposal used attributes as the syntax, and they do have some advantages: they can be sufficiently wordy without seeming unnatural,\nand we don't have to invent a syntax for a niche of the language. However, given that we have now decided to use `modreq`s as the encoding mechanism\nfor the feature, using attributes seems the wrong approach. Attributes never affect the encoded signature of a method (ie, what is emitted as part of\na `call` or `callvirt` instruction), while `modreq`s do. This would set an unfortunate precedent and complicate both the compiler and user understanding\nof what is actually part of a signature. We think this is something that should be avoided.\n\n##### Conclusion\n\nWe will explore the dedicated syntax space. We're open to ideas here: anything from specific keywords to more complex lifetime tracking syntax are things\nwe will look at.\n\n#### Breaking existing lifetime rules\n\nhttps://github.com/dotnet/csharplang/blob/3d557a45ab03597aca4ccc24ba6eaacbcc930431/proposals/low-level-struct-improvements.md#take-the-breaking-change\n\nOur existing lifetime rules are both complex and somewhat inconsistent, which leads to confusion for all levels of users. We'd like to fix it, but it will\nrequire taking a breaking change. Our advantage here is that the users who are authoring these APIs are mostly the BCL, or avid followers of the language\nand improvements. Informal surveys of these populations have indicated receptiveness to taking this breaking change to simplify the surface area. It may\nalso be possible to structure the breaking changes such that the actual C# written gets simpler, but the metadata is more compatible with the existing\nformat today (ie, not changing the meaning of existing metadata, but changing what metadata existing source will compile down to). This would make the\ncompiler implementation more complex, but it might be a good compromise to allow existing code to continue to exist safely.\n\n##### Conclusion\n\nWe are willing to consider breaks to the area to simplify the existing rules.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-03-02.md",
    "content": "# C# Language Design Meeting for March 2nd, 2022\n\n## Agenda\n\n1. [Open questions in `field`](#open-questions-in-field)\n    1. [Initializers](#initializers)\n    2. [Property assignment in structs](#property-assignment-in-structs)\n\n## Quote of the Day\n\n- \"Wouldn't infinite productivity be subject to a Poisson distribution?\" \"I gave up on my math degree years ago\"\n\n## Discussion\n\n### Open questions in `field`\n\nhttps://github.com/dotnet/csharplang/issues/140  \nhttps://github.com/dotnet/csharplang/blob/6501263ca17173262ecb4449c4977b28a28cc375/proposals/semi-auto-properties.md#open-ldm-questions\n\nWe looked at a few open questions in `field` today with fresh eyes, now that we made adjustments to\n[how definite assignment works in structs](LDM-2022-02-14.md#definite-assignment-in-structs). In particular, we want to make sure that,\ngiven the adjustments made to when structs are definitely assigned, our previous decisions make sense.\n\n[Previously](LDM-2022-01-12.md#initializers-for-semi-auto-properties) we'd stated:\n\n> We have the following formalized rule for when initializers are permitted:\n> * Initializers are permitted when a property has a backing field that will be emitted and the property either does not have a setter, or its setter is auto-implemented.\n>\n> We have the following rule for when properties can be assigned in the constructor of a type:\n> * Properties can be assigned in the constructor of a type if that property has a setter, or is a get-only property whose backing field will be emitted.\n\nBoth of these rules are being re-examined today.\n\n#### Initializers\n\nIn addition to re-examining our initializer rule in light of struct definite assignment, we also wanted to consider community feedback, which\nwe received a small amount of. In particular, the feedback was concerned that we were ruling out defaults for INPC or other similar scenarios.\nAfter some thought, we agreed with this feedback, and think that with how we've structured the definite assignment rule, we can come up with a\nsimple rule that is just as easy to explain, if not necessarily as obvious to a reader:\n\n* Initializers are permitted for any property with a backing field. The initializer always assigns directly to the backing field.\n\nWe are concerned that this rule will be something learned, rather than something taught. We can potentially improve compiler tooling for error\ninitializer scenarios, but, in records in particular, there is some potential concern that this will be stumbled onto by accident, rather than\nintentionally. For example, there could be confusion about what this code does:\n\n```cs\nnew Rec(-1);\n\nrecord struct Rec(int Item)\n{\n    public int Item { get; set => value < 0 ? throw new Exception() : field = value; } = Item;\n}\n```\n\nThis will assign `Item` directly to the backing field and not run the initializer, and no exception will be thrown. Despite this, we're hesitantly\nok with moving forward with the design.\n\n##### Conclusion\n\nThe following rule is accepted:\n\n* Initializers are permitted for any property with a backing field. The initializer always assigns directly to the backing field.\n\n#### Property assignment in structs\n\nWith the updated rules for definite assignment, the change is relatively straight forward. A semi-auto-property will be treated as a regular auto\nproperty for the purposes of calculating `default` backing field initialization if its setter/initer is automatically implemented, or if it\ndoes not have a setter or initer.\n\n##### Conclusion\n\nAs above.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-03-09.md",
    "content": "# C# Language Design Meeting for March 9th, 2022\n\n## Agenda\n\n1. [Ambiguity of `..` in collection expressions](#ambiguity-of--in-collection-expressions)\n2. [`main` attributes](#main-attributes)\n3. [`nameof(param)`](#nameofparam)\n\n## Quote(s) of the Day\n\n- \"I think the entire language is biased to developers general nature to be introverted. Sure, we can have variables as int j and int p, but to be really inclusive we need ent j and ent p.\"\n- \"'Enthusiastic Markdown File' is the name of my new punk band\"\n- \"Just to clarify, you were talking about heinous rule number 3?\"\n- \"The language of 1000 keywords\"\n- \"I don't know why I'm passing methane around\" \"You're passing gas\"\n\n## Discussion\n\n### Ambiguity of `..` in collection expressions\n\nhttps://github.com/dotnet/csharplang/issues/5904  \nhttps://github.com/dotnet/csharplang/issues/3435  \nhttps://github.com/dotnet/csharplang/issues/5354\n\nWe got some feedback on our proposal for collection expressions that we wanted to consider in relation to list patterns, before they ship in C# 11 and we can't take back our decisions.\nSpecifically, there is concern that using `..` for slicing in list patterns is setting us up for ambiguities in the future with collection literals, where we want `..` to mean add all\nelements of a sublist to the list being created. This would make the syntax potentially ambiguous when constructing a list of ranges, as `var x = [1.., .. b, 3..4]` could mean add all\nthe elements of `b` to `x`, or it could mean add the range `.. b` to `x`.\n\nOur original motivation for using `..` as the slice pattern was for a different form of consistency: ranges are used to slice collections, so the `..` pattern implicitly slices, where\nthe access form would be `var x = array[1..3];`. So no matter what we do here, there will be some form of inconsistency: either slicing has the inconsistency, or we'll need to parenthesize\nranges in collection literals to make a collection of ranges. We have a few different proposals on what do here:\n\n1. Do nothing.\n2. Use a different syntax. We looked through a few suggestions and other language's spread/splat operators:\n    1. `...` - used by JS, TS, and Dart, among others.\n    2. `*` - used by Ruby and Python\n    3. `#` - Suggested on csharplang\n3. Create a \"spread/splat\" operator context, as a separable feature from list patterns.\n\nWe explored the other proposed syntaxes, but nothing immediately stood out as obvious and the right choice. We like the existing consistency of the `..` operator between slicing expressions\nand slicing patterns, and none of the other syntaxes would keep that. We also did a bit of exploration on proposal 3, and after some discussion we think that there's a potential feature\nthere. We might be able to say that `..` on `Index` and `int` expressions creates a `Range`, and for any other type it performs a spread/splat operation, when in a spread/splat context. We\ndidn't get too far into details around what constitutes such a context, but far enough that we think our future selves will be able to define such contexts.\n\n#### Conclusion\n\nWe will explore option 3 when we get more in-depth on collection literals, and will keep `..` as the syntax for slice patterns.\n\n### `main` attributes\n\nhttps://github.com/dotnet/csharplang/issues/5045  \nhttps://github.com/dotnet/csharplang/pull/5817\n\nWe looked at open questions in `main` attributes, starting with where to allow `main` and what that specifier should apply to. Every option for allowing `main` in a different file has a set\nof downsides associated with it:\n\n1. If we allow `main` in other files to target any entry point, that means that we introduce a new project file switch that affects the language, as the project file can set what the\nentry point is. This means that the attributes applied to a specific `Main` will change based on the project file, which we immediately dislike.\n2. If we allow `main` in other files to only target top-level statements, then top-level statements suddenly become not just a stylistic choice, but one that affects what other features\nof the language can be used. This will make an inconsistent experience for users of generators that want to use the feature.\n\nWe further examined the motivating use case for this feature, `STAThread` in WinForms. After some review, we're not convinced of this as a motivation. The `Main` method in a WinForms\napplication is basically never touched: in VB, it's even hidden from the user. It seems to us that a source generator could simply generate the entire `Main` method for the scenario, rather\nthan just adding `STAThread` as an attribute to it. While we think that a `main` specifier in the same file might find some use in the future, we don't think we currently have a scenario\nthat supports moving it forward.\n\n#### Conclusion\n\nAllowing `main` in other files is removed from the proposal, and we will move the proposal to the backlog for consideraton when we have a better motivating scenario for it.\n\n### `nameof(param)`\n\nhttps://github.com/dotnet/csharplang/issues/373\n\nThis proposal introduces a potential breaking change that we need to consider: by bringing parameters into scope, we potentially cause a dotted expression to bind to the parameter, instead\nof whatever it binds to now. This, in turn, could cause existing code to no longer compile. We think it's a good change overall though: we generally wish we had designed `nameof` this way\nin the beginning, and we think the likelihood of the break is low. The most likely thing for a parameter to collide with is a field of the same name, and this will most often be of the same\ntype, so existing code will continue to compile, even if it refers to a member through a different path now. We do want to get it out in preview soon, so that we can assess the extent of people\nbroken by this change, but we expect it to be very low.\n\n#### Conclusion\n\nWe'll accept the breaking change, and get it into preview soon to ensure that we can understand how many users it might affect.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-03-14.md",
    "content": "# C# Language Design Meeting for March 14th, 2022\n\n## Agenda\n\n1. [file private visibility](#file-private-visibility)\n\n## Quote of the Day\n\n- \"They've removed stuff in my Teams\"\n\n## Discussion\n\n### file private visibility\n\nhttps://github.com/dotnet/csharplang/issues/5529\n\nToday we looked an issue that has been requested by the community before, but now has new significance with source generators. In particular, the framework libraries are now starting to\nship more functionality in source generators. These generators, such as the regex generator, are thought of as part of the API of the framework, but are defined as part of the user's library.\nThis is concerning from a public API perspective, as internal implementation details of these generators are now much easier for users to access and take a dependency on. There's no\nexisting scoping that can reliably separate generator-written code from user-written code, which then becomes an issue if (when) the framework will want to change internal implementation\ndetails of their generators. There is an additional problem that generators need to come up with deterministic-but-unique names, to ensure that they don't collide with other generators\nor with themselves, running from two different assemblies where assembly A gives B IVT.\n\nIn general, we agree with the first concern, and would like a mechanism to solve it. The latter concern, duplicated names within the same assembly, is where we spent most our time debating\ntoday. Having the compiler do name mangling is slightly concerning as it impacts the user experience in several ways: the IDE experience, the debugger experience, and the expression evaluator\n(EE) experience. These are all potentially solveable problems, but will take some design work to ensure it works correctly and seemlessly. After some debate, we feel that unless we were to\nallow duplicated names, this feature would feel incomplete. If a thing is file private, then allowing it to be visible in some other contexts feels like we didn't actually solve the problem.\n\nWe also thought about generalizing this feature. The proposal today specifically only applies to top-level types, and while they are the primary motivation currently, we don't think they\nshould be the only one. More accessibilities has been a user request for a long time, applying to more things than just top-level types. Member fields or methods, for example, or nested types.\nIt seems unfortunate to design specifically for just one small use case and not consider how it could be extended to other components in the future.\n\nFinally, we talked a bit about the syntax. We're not sold on just using `private` here: `private` on nested types already means something, and just using `private` on the top level type would\nbe confusing. It would also interfere with extending a file private accessibility to other scopes. We could simply introduce `file private` as a new accessibility, or we could look at other\ncombinations like `private internal`.\n\n#### Conclusion\n\nWe've settled our first big pivot point for this feature, that file private names should be able to be duplicated in multiple files in the same assembly. We will need to take the feedback from\nLDM today back to design and come back to a future LDM for the next elements.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-03-21.md",
    "content": "# C# Language Design Meeting for March 21st, 2022\n\n## Agenda\n\n1. [file private visibility](#file-private-visibility)\n2. [Open question in semi-auto properties](#open-question-in-semi-auto-properties)\n3. [Open question in required members](#open-question-in-required-members)\n\n## Quote of the Day\n\n- \"If we pick one syntax, we can have a quick meeting\" *Collective laughter*\n\n## Discussion\n\n### file private visibility\n\nhttps://github.com/dotnet/csharplang/issues/5529\n\nOur discussions today were on both syntax, and the semantics of what differing syntaxes mean. We see problems with both presented options of `file private` and\n`private`:\n\n* For `file private`, what does that mean when applied to member of a type? Is that member private to the member and _also_ private to the file? What does the\n`private` part of `file private` mean when applied to a top-level type?\n* For `private`, this is inconsistent with how `private` can already be applied to types in nested contexts: what if we wanted to enable nested file private types\nin the future?\n\nTo address these issues, we thought about a variation on `file private`: `file <accessibility>`. This would add `file` as a modifier on all current accessibilities,\nrestricting their scope to be the current file. So `file public` would allow access to everything in the current file, while `file private` would only allow access\nto things in the containing member (and would not be allowed to apply to a top-level type, as just `private` isn't allowed to do this). However, there are a lot of\ninteresting side-effects from things like `public` vs `private` accessibility: it has impacts on reflection, dynamic, serialization, and more. We're somewhat\nconcerned about these potential effects, and want to be very careful about allowing these things for types and members that ostensibly only accessible inside a single\nfile. We therefore want to take a look at what the minimal solution to address the motivation without blocking off future development work would look like: perhaps\njust `file`, which would inherit the default accessibility of the location, with no other accessibility specifiers allowed, but this will be looked at in a smaller\ngroup and revisited soon.\n\n#### Conclusion\n\nNo decisions today. We'll rethink with a `file` keyword approach see what the downsides are.\n\n### Open question in semi-auto properties\n\nhttps://github.com/dotnet/csharplang/issues/5923\n\nOur model is that `field` reflects an actual field of the type, and rules should flow out from that. Since in this case a `field` is a static field, and static\nlambdas can access static fields, a static lambda can access `field`, even if it doing so is what causes the field to be brought into existence.\n\n#### Conclusion\n\nAllowed.\n\n### Open question in required members\n\nhttps://github.com/dotnet/csharplang/issues/3630\n\nOur final question today is on whether we should issue warnings for this scenario, where a required member is being initialized to a value:\n\n```cs\nclass C\n{\n    public required int Field = 1;\n    public required int Prop { get; set; } = 1;\n}\n```\n\nAfter some consideration, we think that there could be potential scenarios if a type exposed multiple constructors, and several of them were marked\n`SetsRequiredMembers`. These constructors could be sharing this initializer, but any remaining constructors will require that consumers set a value. An analyzer\nseems appropriate if a user wants to forbid redundant assignments here.\n\n#### Conclusion\n\nNo warning.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-03-23.md",
    "content": "# C# Language Design Meeting for March 23rd, 2022\n\n## Agenda\n\n1. [Open questions in required members](#open-questions-in-required-members)\n    1. [Emitting `SetsRequiredMembers` for record copy constructors](#emitting-setsrequiredmembers-for-record-copy-constructors)\n    2. [Should `SetsRequiredMembers` suppress errors?](#should-setsrequiredmembers-suppress-errors)\n    3. [Unsettable members](#unsettable-members)\n    4. [Ref returning properties](#ref-returning-properties)\n    5. [Obsolete members](#obsolete-members)\n\n## Quote of the Day\n\n- \"We can and do allow users to shoot their feet off. However, lets not give them something capable of doing nothing else\"\n\n## Discussion\n\n### Open questions in required members\n\nhttps://github.com/dotnet/csharplang/issues/3630  \nhttps://github.com/dotnet/csharplang/issues/5945\n\n#### Emitting `SetsRequiredMembers` for record copy constructors\n\nWe're not ok with option 1 here: these constructors can be accessed directly by consumers within the record type or any derived type of the record. We also think that option 2\nchanges too much metadata to be palatable: every existing record would change on recompile. While incorrect compilation order could result in a `SetsRequiredMembers` being missed\nfrom a derived record, we think that this case is sufficiently in the corner that it's not necessary to try and address.\n\n##### Conclusion\n\nOption 3, `SetsRequiredMembers` will be added to record copy constructors when the record or any base type has required members.\n\n#### Should `SetsRequiredMembers` suppress errors?\n\nThis is a corner case, as the scenario cannot arise from C# code, but it could potentially occur if another language were to extend a type with required members and either\noverride (without applying the correct attributes) or hide those members. This would cause the required member list to not be understood by the language, and there is danger in\nallowing something we don't understand to proceed. However, in those cases, the external language user did decide to explicitly add the `SetsRequiredMembers` attribute: this is\na signal we can understand without context, so it seems fine to ignore errors around required members if the attribute is found.\n\n##### Conclusion\n\n`SetsRequiredMembers` will suppress the error.\n\n#### Unsettable members\n\nWe've previously said constructors that require members must be at least as accessible as the members, to ensure that constructors don't become uncallable. This is just an extension\nof that scenario.\n\n##### Conclusion\n\nWe will require that required fields cannot be readonly, and that required properties are settable from every constructor (meaning that they have a setter/initer at least as\naccessible as every constructor that requires them to be set).\n\n#### Ref returning properties\n\nThere's an interesting debate here similar to the placement of `readonly` in comparison to the ref: does `required` here require setting of the ref itself (not possible with\nref properties, might be possible with ref field?), or does it require setting the _value_ pointed at by the ref? If the former, that would suggest `required ref` to be in line\nwith `readonly` members, and would necessitate a syntax for initializing a ref in an object initializer, which doesn't exist today. If the latter, it would suggest\n`ref required`, to be in line with `ref readonly`, but it's unclear if this is a scenario to be concerned with.\n\n##### Conclusion\n\nGiven lack of motivation, this is disallowed entirely (on both ref properties and, when added, ref fields). We can revisit in the future if we have motivating use cases.\n\n#### Obsolete members\n\nFinally, we considered `Obsolete` required members. We're not fans of libraries forcing their users into a warning, either by accident (adding `Obsolete` to a member while\nforgetting to remove `required`) or intentionally. However, we don't feel this is worth an error: it's technically understandable, we just don't know why someone would intentionally\ndo it. This category of issue is best served by warnings, so we think that's the appropriate strategy.\n\n##### Conclusion\n\nOption 3, with a warning. Warnings will be suppressed for `Obsolete` constructors and for types that are obsolete.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-03-28.md",
    "content": "# C# Language Design Meeting for March 28th, 2022\n\n## Agenda\n\n1. [Variable declarations under disjunctive patterns](#variable-declarations-under-disjunctive-patterns)\n2. [Type hole in static abstracts](#type-hole-in-static-abstracts)\n3. [Self types](#self-types)\n\n## Quote of the Day\n\n- \"That feels like a baby we might throw out with the bathwater\"\n\n## Discussion\n\n### Variable declarations under disjunctive patterns\n\nhttps://github.com/dotnet/csharplang/issues/4018  \nhttps://github.com/dotnet/csharplang/blob/b6f901132d4ee299157bc9b1745eb578f30d29ef/proposals/pattern-variables.md\n\nLast time we discussed this issue, we felt that there were potential dragons in two directions:\n\n1. Should we re<i>declare</i> existing variables, or have a syntax for assigning into them?\n2. Should we allow assignment/declaration into all variables in scope?\n\nThis update to the proposal attempts to address the latter concern: the former discussion has not yet been had. The updated\nversion of the proposal suggests using definite assignment to determine when a variable can be assigned into: if the variable\nhas a flow state of \"not definitely assigned\", it can be redeclared in a pattern, and defines definite assignment rules for\ninside patterns to allow the rules to generalize within patterns and without.\n\nThere are still some concerns that this is too wide of a scope. Our motivations in this proposal are around allowing sharing\nblocks of code: allowing `case` clauses to enter a specific body in a `switch` statement with the appropriate information\nextracted, for example, or allowing multiple conditions to be put on either side of an `||` as part of the condition of an\n`if` statement. The goal isn't to allow general redeclaration: it's to allow sharing of code. Redeclaring or reusing between\nunrelated conditions concerns us more: should consecutive `if` statements be able to reuse that name and stomp on that location?\nBecause it refers to a location, a previous `if` body could have passed a `ref` to another area, which could then observe the\nwrite to the local.\n\nWithin a single related construct, however, we think using definite assignment as the mechanism for enforcement is a good\nsolution. While it's not a perfect \"definitely not assigned\", it limits the redeclaration points and it's much harder to\nobserve state being assigned (not impossible, but much harder, particularly unintentionally). We still need to consider ways\nto address the first concern, but that exploration will need to be the next meeting.\n\n#### Conclusion\n\nWe would like to scope down the allowed location for redeclaration/assignment to:\n\n1. Within `case` labels for the same switch section.\n2. Within a single expression.\n3. Within related statements: an `if`/`else if`, for example, but not in two unconnected `if` statements.\n\n### Type hole in static abstracts\n\nhttps://github.com/dotnet/csharplang/issues/5955\n\nA variation of this issue is what stopped the original exploration of static abstracts from proceeding a decade ago: we\naddressed the wider hole with the existing\n[restriction](../../proposals/static-abstracts-in-interfaces.md#interface-constraints-with-static-abstract-members), but\nthe hole is still possible to exploit. We therefore are ok with this further restriction, but think that when we add support\nfor static _virtual_ members, we should work with the runtime team to make sure that, if all static virtual members of an\ninterface have a body, it should be usable as a type argument. This would avoid the breaking change from adding a static virtual\nDIM to an interface, which despite not requiring consumers to update implementing code, would potentially break usage as a type\nargument.\n\n#### Conclusion\n\nRestriction is accepted.\n\n### Self types\n\nhttps://github.com/dotnet/csharplang/issues/5413#issuecomment-1079584415\n\nAfter considering Mads' feedback on self types, we find ourselves agreeing with it. It would be very concerning that we would\nintroduce a version of self types now, marginally improving the usability of generic math but potentially breaking our ability\nto evolve the type system further.\n\n#### Conclusion\n\nSelf types in this form are rejected.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-03-30.md",
    "content": "# C# Language Design Meeting for March 30th, 2022\n\n## Agenda\n\n1. [Definite assignment in struct constructors calling `: this()`](#definite-assignment-in-struct-constructors-calling--this)\n2. [`file private` accessibility](#file-private-accessibility)\n\n## Quote of the Day\n\n- \"Maybe we should renumber that list so we're not confused? I know we're all programmers, but 0-based is confusing here.\" \"We're all programmers, but VB programmers at heart.\"\n\n## Discussion\n\n### Definite assignment in struct constructors calling `: this()`\n\nhttps://github.com/dotnet/roslyn/issues/58790  \nhttps://github.com/dotnet/csharplang/issues/5552\n\nFor solving this issue, we generated the following ideas:\n\n1. No change to the behavior, and document it. We don't really think this is tenable, but it is technically an option.\n2. Report an error calling `: this()` when field initializers are present and `this()` is a default parameterless constructor.\n3. No error; zero fields after running initializers (silent breaking change to existing code).\n4. No error, zero fields before running initializers.\n5. Option #4 for now (C# 10), then #2 later.\n6. Option #4 for now (C# 10), add a warning wave later on uses of `: this()` or `new S()` when there is no user-defined parameterless constructor.\n\nSeveral LDM members immediately felt that 4 was the correct option, and did what they were expecting the code to do. However, it does carry with it the potential for\nconfusion around what calling the parameterless constructor does: for a struct with no parameterless constructor with field initializers, the behavior of `: this()`\nand of `new S()` will appear to differ. We may specify that field initializers run in a different order, but the perception will likely be different. Option 2 would\nbe a consistent way of correcting this perception issue: either make the behavior between all references to a parameterless constructor identical, or forbid calling a\nparameterless constructor where behavior would be confusing. However, while this option is most in line with C# of the past, we are already planning on making big\nchanges to struct initialization in C# 11, and this behavior would have the unfortunate behavior of punishing any user that adds a field initializer to existing structs\nthat already use `: this()` in places.\n\nWe're also concerned about a warning wave here, as there are plenty of uses of `: this()` as a struct initializer that are perfectly fine today that would become\nwarnings if we took a hard line stance here. It might be better to approach such a ruling a code style thing: the IDE can gray out the `: this()` initializer in C# 11,\nand fixers can remove dead code as they do today.\n\n#### Conclusion\n\nWe will adopt option 4 for C# 10, and look into code style analyzers and IDE experiences to remove potentially confusing and redundant use of `: this()` in C# 11.\n\n### `file private` accessibility\n\nhttps://github.com/dotnet/csharplang/issues/5969  \nhttps://github.com/dotnet/csharplang/issues/5529\n\nWe looked at another turn of the crank in the proposal around `file private`. The proposal today goes for a very integrated approach, adding a new accessibility modifier\nand rationalizing its existence with other accessibilities, paring the accessibilities that can be combined with `file` down to a small set. Through discussion, we\narrived at 3 proposal options:\n\n1. #5969 as is.\n2. `file` or `fileonly` as a new accessibility. It cannot be combined with other accessibilities, and means only \"can be accessed in this file\".\n3. `file` is allowed to be combined with any existing accessibility. Everything works exactly as it does today, but when `file` is applied, the name is not in scope\noutside the current file.\n\nWe think that option 1 has the potential to be complicated. Both 2 and 3 are relatively simple to explain, with 2 being the simpler of them. Option 1 limits and changes\nexisting rules when `file` is applied, which starts to need a decoder ring to understand.\n\n#### Conclusion\n\nWe're equally split between option 2 and 3 at this point. We need to explore these a bit more with a smaller group, clarify the motivating scenarios for the feature, and\ncome back soon for another session.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-04-06.md",
    "content": "# C# Language Design Meeting for April 6th, 2022\n\n## Agenda\n\n1. [Unresolved questions for static virtual members](#unresolved-questions-for-static-virtual-members)\n2. [Parameter null checking](#parameter-null-checking)\n\n## Quote of the Day\n\n- \"You need a cat to sit on your space bar while you hit a reaction button!\"\n\n## Discussion\n\n### Unresolved questions for static virtual members\n\nhttps://github.com/dotnet/csharplang/blob/main/proposals/static-abstracts-in-interfaces.md#unresolved-questions\n\n#### Equality operators and conversions\n\nPrior to this feature we didn't allow equality operators and conversions (implicit or explicit) in interfaces.\n\nThe main reason for not allowing equality operators in an interface is that you can't pair them with an overload of `Object.Equals` and `Object.GetHashCode`.\n\nFor conversions the reason is that there are already language-level conversions to and from interfaces, and we try to prevent user-defined conversions where the language already has them.\n\nWhy should we allow these as *virtual* static members when we don't allow them as *non-virtual* static members? Arguably the virtual declarations are very different: They do not really say that the interface *itself* has these operators and conversions, but rather that an implementing type would. You cannot call these operators and conversions on the interface itself, but only on a type parameter `T` that is *constrained* by the interface. So they don't really run afoul of the situations that motivate the restrictions on the non-virtual operators and conversions.\n\nStatic virtual equality operators and conversions are not an esoteric scenario - we eagerly use both in the new generic math interfaces, and usability would be diminished if we didn't allow them.\n\n##### Conclusion\n\nStick to the plan. It's ok to have equality operators and conversions as static virtual members, even while interfaces don't allow them as non-virtual members.\n\n#### Confirm placement of qualifier for explicit implementation\n\nFor explicit implementations of operators we currently put the `IMyInterface.` prefix before the `operator` keyword. Are we certain that this is the right place?\n\nIt is in fact one of the only places that consistently *exists* across all operator kinds, including conversions. Not all operators have an operator symbol for instance.\n\n##### Conclusion\n\nWe like it where it is.\n\n#### When does a type parameter count as \"the type itself\" in an operator declaration?\n\nUp until now, operator declarations have required the containing type to occur as at least one of the operand types. In static virtual operators we relax that so that a type parameter gets to count as \"the type itself\", but we have been imprecise on what this means in the past. What should the exact requirement be?\n\nIn order for a type parameter `T` to count as \"the enclosing type\" the following are the strictest requirements we can express that still satisfy the scenarios:\n\n- `T` is a direct type parameter on the interface in which the operator declaration occurs, and\n- `T` is *directly* constrained by what the spec calls the \"instance type\" - i.e. the surrounding interface with its own type parameters used as type arguments.\n\nWithout self-types in the language we can't express a requirement that `T` is a self-type. On the other end we *could* probably choose to make the rules somewhat *loser* and still make lookup work.\n\n##### Conclusion\n\nWe keep the strict rules outlined above. The rules on operators today are also quite strict, even though they could probably be loosened without breaking lookup, so this feels in line with the existing language. Furthermore we don't know of scenarios that would benefit from a looser rule, but if we find them we can always relax it later.\n\n#### Query expressions over types\n\nSince query expressions are spec'ed as a syntactic rewrite, C# actually lets you use a *type* as the query source, as long as it has static members for the query operators you use! In other words, if the *syntax* fits, we allow it!\n\nPreviously that could never apply to a type parameter, because you couldn't dot off of those, but now that we allow that, should we be true to the syntactic rewrite and allow a type parameter there?\n\n##### Conclusion\n\nWe think this behavior was not intentional or important in the original LINQ, and we don't want to do the work to support it on type parameters. If there are scenarios out there we will hear about them, and can choose to embrace this later.\n\nWe don't believe there are other places in the language where this situation can occur, but will check.\n\n#### Resolution rules for conversion operators\n\nWe need to adjust the operator resolution rules to look for operator declarations on type parameters constrained by interfaces that have static virtual operator declarations.\n\nIn the current implementation there is a stopgap rule that looks for operators in interface constraints essentially *only* when there is not also a class constraint. As soon as there is a class constraint, it hides the interface operators regardless of whether the class itself implements the operators.\n\nMore consistent with the behavior of member lookup would be that when there are no applicable candidates from the effective base class (essentially the class constraint) we just try again with the effective interfaces (essentially the interface constraints).\n\n##### Conclusion\n\nProposal adopted.\n\n### Parameter null checking\n\nhttps://github.com/dotnet/csharplang/blob/main/proposals/param-nullchecking.md\n\nThis feature has caused some amount of debate in the community after being released in preview. After having talked to a number of constituencies our read is that there *is* a majority who are happy with the feature but others raise a number of objections at different levels. These are the opinions most commonly expressed:\n\n1. There shouldn't be a feature; NRT is good enough and saving one line of code isn't worth it\n2. We should go further and support other preconditions through more of a \"contracts\" feature\n3. We should do it by allowing NRTs to incur runtime checking semantics, under a flag or otherwise\n4. We should do it with the proposed semantics but with a different syntax\n\nWe do feel that this is a small syntactic-sugar feature that not everyone will be using - it is only for when you would have thrown `ArgumentNullException` in your code today. We think some of the fervor of the feedback may be driven by a perception that this is going to be more pervasive in code than it is.\n\nHere is a brief summary of the reasons we have had for not taking one of the four paths outlined above; not to say that those aren't up for debate:\n\n##### 1. Do nothing\n\nWe feel that the feature does have value. In most cases it only removes a line of code, but that could be the only line of code you had (e.g. in a constructor body that otherwise chains to another constructor), or the line that prevents you from using an expression body. In general, validation code can be voluminous enough to obscure the main logic, and the bulk of validation code by far is argument null checks.\n\nAdditionally the feature gives extra expressiveness in certain situations. In a constructor it will check a parameter *before* it is passed to a chained constructor. In an iterator it will be checked eagerly instead of during the first `MoveNext` call. In an async method it will throw synchronously instead of as part of the `await`.\n\nIn docs having a shorter syntax means we will include it in more examples (it will not obscure the main point of the sample) which means those examples will be \"safer\". That matters because many people copy from those samples.\n\nSo in summary the feature does add value.\n\n##### 2. Do contracts\n\nOver the years there have been dialects of C# that embraced generalized contracts to express and check preconditions (and sometimes postconditions) either statically, at runtime or both.\n\nOne important learning from these experiments is that around 9 out of 10 preconditions are null checking. Deal with that and the rest is in the noise. There would be very little extra value from the significant investment and likely syntax overhead of a generalized contracts feature of any kind.\n\nIn summary, null checks are the sweet spot for a feature.\n\n##### 3. Use nullability annotations to generate checks\n\nIt was a core design pillar of nullable reference types (NRT) that they did not alter runtime semantics in any way. If your code compiles, it runs the same way no matter the annotations you have and the warnings you get. This tremendously simplifies the reasoning one has to do about the impact of the annotations.\n\nIndiscriminately doing runtime checks based on nullability annotations would obviously be a massive breaking change, but we could of course put the behavior behind a flag - like we did NRT itself.\n\nGenerating runtime checks for every nonnullable parameter type may be overkill because you get checking in too many places, which is a performance hit, but also may not always be what you want. Of course that could be mitigated by an opt-out syntax on parameters, but now you're back to having just as much syntax, and sort of an arms race between opt-in and opt-out mechanisms.\n\n##### 4. Use a different syntax\n\nThe `!!` syntax was arrived at after much debate. The feature started out with a single `!`, but it was felt that it was to easily confused with the `x!` null-forgiveness operator in expressions. Moreover we might want to apply null checking elsewhere in the future (e.g. on property setters/initers) and even maybe as an expression or statement. The latter would not be possible if we reused `!` for it.\n\nOther proposed syntaxes were longer, diminishing the \"savings\" compared to just doing the check manually, though possibly improving readability. There is a tradeoff between what's the right \"weight\" of a feature when you're used to it, versus when you're first learning it. If we optimize for \"self-explanatory\" that may turn into annoyingly heavy-weight with frequent use.\n\n##### Conclusion\n\nWe debated between the above overall approaches and concluded that we still have a clear lean towards the currently proposed semantics with *some* syntax. A few people were leaning in the direction of option 2 above, but the partial conclusion is that *if* we are going to do a parameter null checking feature it will be through *some* form of annotation of the parameter declaration, as originally proposed.\n\nRunning out of time we will save for later the decisions of:\n- What *should* the syntax be for this feature, and\n- Once we settle that, do we still feel confident that we want the feature at all.\n\n\n\n\n"
  },
  {
    "path": "meetings/2022/LDM-2022-04-11.md",
    "content": "# C# Language Design Meeting for April 11th, 2022\n\n## Agenda\n\n1. [Relax restrictions on braces on raw interpolated strings](#relax-restrictions-on-braces-on-raw-interpolated-strings)\n2. [Self-type stopgap attribute](#self-type-stopgap-attribute)\n\n## Quote of the Day\n\n- \"Maybe we should introduce the £ symbol for interpolated strings\"\n\n## Discussion\n\n### Relax restrictions on braces on raw interpolated strings\n\nhttps://github.com/dotnet/csharplang/issues/5960\n\nAfter some initial usage of raw string literals, we wanted to revisit the reasoning behind limiting the number of `{`'s just before an interpolation\nhole, as it came up as confusing to explain to several users. The idea is that, before an interpolation hole, users would be able to specify as many\n`{` characters as they wanted, and the compiler would only treat the inner `{`'s that make up an interpolation hole as the delimiters. This would allow\n`$\"\"\" {{0}} \"\"\"` to be a string with the content ` {0} `. There are, however, some potential issues with this:\n\n1. In 99% of cases a `{` in an interpolated raw string literal with a single `$` is not permitted, as such a character denotes the start of an interpolation\nhole. Relaxing this restriction would be odd, as `{ {0}` would be disallowed, but `{{0}` would be allowed.\n2. The rules as is are consistent with the rules for the quotes, and changing the rules would require that users understand multiple sets of rules.\n3. `$\"{{expr}}\"` has meaning today, as a string with the content of `{expr}`. If we permitted `$\"\"\"{{expr}}\"\"\"` to compile, it might end up confusing\nusers who expect it to have a similar meaning to existing interpolated strings.\n\n#### Conclusion\n\nWe will keep the restriction as is.\n\n### Self-type stopgap attribute\n\nhttps://github.com/dotnet/csharplang/issues/6000\n\nAs an attempt to prevent simple user errors with our new numeric interfaces, and preserve the potential to use self types in those interfaces in a future\nwhere we add support for them, we considered an attribute that could be applied to type parameters to enforce that the type parameter can only be substituted\nwith the containing type, or a type parameter that is also attributed with the same attribute. We quickly started delving into the nitty gritty of the\nimplementation: should we allow it on abstract classes, for example, or be more opinionated with where the parameter so attributed must occur? However, we\ncame to the conclusion as we were doing this that we were creating `GenericMathSelfTypeAttribute`, not a generalized `SelfTypeAttribute`. We don't have the\nbroader understanding of the usage of self-type type parameters of the entire ecosystem to attempt to rush in a generalized protection feature here, and\nthink the space is more appropriate for an analyzer in the BCL to enforce the rules that matter for the interfaces in question.\n\n#### Conclusion\n\nRejected. We will look at a BCL analyzer to enforce the rules they want to enforce for these interfaces.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-04-13.md",
    "content": "# C# Language Design Meeting for April 13th, 2022\n\n## Agenda\n\n- [Parameter null checking](#parameter-null-checking)\n- [File-scoped types](#file-scoped-types)\n\n## Quote of the Day\n\n- \"I think we're just vague about where we become soup\"\n\n## Discussion\n\n### Parameter null checking\n\nhttps://github.com/dotnet/csharplang/issues/2145\n\nWe're following up to [last week's](LDM-2022-04-06.md#parameter-null-checking) discussion on parameter null checking, deciding on our answers to two questions:\n\n1. Should we change the syntax of the feature, and if so, what syntax should we choose?\n2. Do we still feel confident in this feature at all?\n\nTo think about the first question, we put up some syntax ideas. Some of these have been previously discussed, others arose from community discussion on this feature.\nWe also went through and listed some pros and cons for each syntax form.\n\n1. `void M(string s!!);` - The current form\n   1. This syntax is perceived as very shouty, which we can understand. It does generalize to an expression form later though, which is nice to think about the future.\n2. `void M(string! s);`\n   1. We dislike putting the modifier on the type, as it implies that `!` can be put on types in other locations, and we don't have any idea on how we'd actually enable\n   such a feature in the future. It also negatively affects usage in lambdas, as users would be required to add a type to their lambda declarations to use the feature.\n   2. We also considered whether `Type!` could be used on a local, which would force a null check whenever something is assigned to that local. There was not much support\n   this extension after consideration, however.\n3. `void M(string s!);`\n   1. This is much less shouty, as it's only one `!` character. However, we're concerned about confusing all the different meanings of `!`; for example, the `!`'s in this\n   example mean different things: `x! => x!;`.\n4. `void M(notnull string s);`\n   1. A keyword can be more clear, but we're not certain this is. It feels redundant, as the parameter is already declared as not null. It also has a different meaning than\n   the `NotNull` attribute.\n5. `void M(string s ?? throw);`\n   1. On the one hand, this feels pretty intuitive, as `?? throw` is already legal expression syntax (provided there's an exception type on the other side). However, we're\n   concerned with the interaction with default parameters, as `string s ?? throw = \"\"` looks very confusing, and `string s = \"\" ?? throw` looks like `?? throw` is part of\n   the default parameter value.\n6. `void M(string s is not null);`\n   1. Our concerns here are the same as 5.\n7. `void M(checked string s);`\n   1. We like that `checked` already deals with exceptions, and it feels like the right word to use: when used with arithmetic, it ensures that users aren't violating the\n   bounds of a type, which is very similar to parameter null checking. However, `checked` can already be applied to expressions, or even turned on project-wide, and we're\n   not sure how we'd apply the null-checking feature in these locations: should all parameters be null-checked if the project-wide setting is on, for example? Or should a\n   `!` in a checked block be checked for null?\n8. `void M(string s) where s is not null;`\n   1. This looks like a promising start for a full contracts feature, but not for a feature only doing null checking of parameters.\n\nAfter the discussion leading to the above points, we felt that only two of the options had enough support to continue discussion: option 1, the current form, and option 3,\nthe less shouty version of the current form.\n\nWe then turned our focus to question 2: do we still feel confident in this feature at all? As part of this, we also looked at the initial feedback we received on this\nfeature by a number of channels: GitHub, social media, MVPs, conference audiences, internal reviewers, and the LDT itself. We do see a majority of positive reactions to\nthe feature, but it isn't the large majority we normally like to see for C# features, particularly ones that are as broadly applicable as this feature will be, and even the\nLDT is split on the feature itself. While we think the preview provided us with valuable feedback and was worth pursuing, we ultimately decided that, between options 1, 3, or\npulling the feature from C# 11 entirely, pulling the feature is the right move. We may revisit at a later date, if we ever want to pursue more generalized contracts, but for\nC# 11 this feature will removed.\n\n#### Conclusion\n\nParameter null checking is removed from C# 11.\n\n### File-scoped types\n\nhttps://github.com/dotnet/csharplang/issues/5529  \nhttps://github.com/dotnet/csharplang/issues/6011\n\nThis next change in design of this feature pares it back significantly, basically back to the original design, but with a couple of key differences:\n\n1. There is no `private` keyword here, which was a significant stumbling block in understanding of the feature and unintended feature creep.\n2. There are more heavy restrictions on how the feature can be used.\n\nIn particular, this version solves the immediate source-generator issues that the BCL is running into, while allowing us design room if we ever want to expand the\nfeature in the future. We do need to validate that the restrictions around `partial` types and signatures will solve all the issues the BCL source-generators have, but\nwe think it's a forward direction we can make progress on.\n\n#### Conclusion\n\nThe updated proposal can move forward, and we should validate the restrictions on `partial` types will solve the scenarios in the BCL.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-04-18.md",
    "content": "# C# Language Design Meeting for Apr 18, 2022\n\n## Agenda\n\n- [Issues with Utf8 string literals](#issues-with-utf8-string-literals)\n- [Ref and ref struct scoping modifiers](#ref-and-ref-struct-scoping-modifiers)\n\n## Quote of the Day\n\n- \"Basically, they already know '*this step squeaks.*'\"\n\n## Discussion\n\n### Issues with Utf8 string literals\n\nWe [previously](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#open-questions-in-utf-8-string-literals) made a few decisions deliberately to test them out in a prototype. It's been used internally and externally and we've gathered some feedback and have some recommended changes.\n\n#### Target typing a regular string literal to Utf8 types\n\nhttps://github.com/dotnet/roslyn/issues/60612\n\nThe preview implementation allows regular string literals `\"...\"` to be target typed to the Utf8 representation types. This has several problems:\n\nFirst of all it doesn't *tell* you that the implicit conversion causes a Utf8 encoding; the different string encoding is silently adopted.\n\nMore problematically it is a significant breaking change: There are in fact quite a lot of methods with overloads for both `string` and e.g. `ReadOnlySpan<byte>`, and existing calls may now either fail or silently pick a different overload.\n\nIf we want to mitigate, the choice seems to be between always requiring the `u8` suffix for Utf8 literals or coming up with some tie-breaking shenanigans to reduce the risk of a break.\n\n##### Conclusion\n\nLet's require the `u8` suffix in order for string literals to be Utf8 encoded.\n\n#### Natural type of Utf8 literals\n\nhttps://github.com/dotnet/roslyn/issues/60644\n\nIn the preview implementation the natural type of a `\"...\"u8` literal is `byte[]`. This has the benefit that `byte[]` is already implicitly convertible to the other types we would like to use to represent Utf8 strings, most notably `ReadOnlySpan<byte>`.\n\nHowever, this leads to some very subtle costs, where a `byte[]` is allocated even just to be a receiver or argument of a call that doesn't need an array.\n\nAlso, we often offer fallback `byte[]` overloads for the use of languages that don't know about spans, and with that being the natural type we end up preferring those more expensive overloads in C# as well.\n\nThe proposal is to instead make `ReadOnlySpan<byte>` the natural type of Utf8 literals. We would then have a conversation about whether there should be target typing to some of the other byte sequence types.\n\nSince the literals would be allocated as global constants, the lifetime of the resulting `ReadOnlySpan<byte>` would not prevent it from being returned or passed around to elsewhere. However, certain contexts, most notably within async functions, do not allow locals of ref struct types, so there would be a usage penalty in those situations, with a `ToArray()` call or similar being required.\n\n##### Conclusion\n\nWe are ok changing the natural type to `ReadOnlySpan<byte>`. See discussion on target typing next.\n\n#### Target type Utf8 literals to `byte[]`?\n\nShould we alleviate the async scenario, described above, by allowing Utf8 literals to target type to `byte[]`? That way, in an async method you could still have a local variable:\n\n``` c3\nbyte[] myU8 = \"I am an async resilient Utf8 string\"u8;\n```\n\nOn the other hand, even though `ReadOnlySpan<byte>` would win in an overload resolution scenario, there is some risk of unwanted implicit allocation.\n\n##### Conclusion\n\nDon't target type. It is ok to have to explicitly use `ToArray()` in these scenarios, especially since it makes it clearer what you are doing.\n\n#### Should Utf8 literals be null-terminated\n\nToday, for string literals, we put a null terminator beyond the last character in memory (and outside the length of the string) in order to handle some interop scenarios where the string is being `fixed` and the call expects null terminated strings. We do not do the same for other string values, so the solution is at best partial, and at worst a source of a false sense of security. However, it is what it is.\n\nIn the preview implementation we don't null-terminate the data from a Utf8 literal in the same way. However, an inconsistency with string literals here might lead to further bugs or misunderstandings, especially if interop code is copied and converted over from Unicode to Utf8.\n\n##### Conclusion\n\nWhile the current string literal behavior is debatable, we think the least risky approach is to be consistent and adopt the same behavior for Utf8 literals.\n\n\n### Ref and ref struct scoping modifiers\n\nhttps://github.com/dotnet/csharplang/blob/main/proposals/low-level-struct-improvements.md#open-issues\n\nWe looked at two ways in which you might want to be able to modify the default rules around escaping of refs and ref structs.\n\n#### \"Scoped\" refs and ref structs\n\nUp until now the default assumptions around escaping of refs and ref structs have been inconsistent. For every combination of incoming and outgoing refs and ref structs on a given method, we have assumed that incoming might escape through the outgoing. *Except* in one case: When a ref struct was returned, incoming `ref`s were not assumed to be captured. This was because there was no safe way to create a ref struct from a `ref` at the time, but we're looking to change that, e.g. with literally a new constructor overload on `Span<T>` taking a `ref T` to be wrapped by the span!\n\nChanging the assumptions to remove the exception would of course be a breaking change, but it would also be a highly desirable simplification. We've therefore done an audit of all the places the break would affect the core libraries, and the result is that only two public methods (and a number of private methods) rely on being able to take refs and return ref structs. Those methods are already inherently unsafe and documented as such.\n\nHowever they are also used extensively! We need a way to modify them to for them to continue to be callable in the same contexts (even if it's unsafe!). Such a modifier would also help other APIs out there which might have relied on the current assumptions to avoid a break for their users.\n\nGiven the general sophistication of developers trading in combination of refs and ref structs, and the availability of such a modifier, we assess that a break would be quite well contained.\n\nIn general we want to allow methods to \"scope\" the use of incoming refs and ref structs to signal that they will not be returned. We could use a keyword or an attribute for this purpose, and our previous leaning has been to use a keyword.\n\nToday's proposal is to introduce a keyword `scoped` as a modifier on ref and ref struct parameters.\n\n##### Conclusion\n\nBless the breaking change in light of its small perceived impact, and adopt the `scoped` modifier proposal as the mechanism to block \"escaping\" of incoming refs and ref structs.\n\n#### Escaping `this` from structs\n\nEven with the above decision, one assumption that still deviates from the default expectation of escaping is around references to the receiver struct. The escape analysis does assume that ref or ref struct returning members do not share references to `this` or to fields within `this`.\n\nThe proposal therefore is to introduce a second modifier, `unscoped`, to override the default and allow such escaping when desired.\n\nThere are several concerns with that:\n\n1. Why is the default for `this` different than for parameters? Is this something we could also change with a similarly well-contained break?\n2. While we have a clear and present need for `scoped`, this seems to be pure additional expressiveness. Do we have enough motivation to add it at this point?\n3. The `unscoped` keyword seems like a distinct misnomer, since it does not seem like the exact opposite of the `scoped` modifier. The things it \"unscopes\" (`this` and also `out` parameters) are distinct from things the `scoped` modifier \"scopes\" (ref and ref struct parameters).\n4. If we adopt the feature it is unclear if it is \"worthy\" of a keyword. Its expected use might be rare enough that an attribute is a better choice. Attributes cannot go on local variables, but whereas that might be a useful future scenario for `scoped` it does not seem as useful for `unscoped`.\n\nOn the other end we would like to allow ref capture where it's not allowed today.\n\n##### Conclusion\n\nConsider \"unscoped\" as a separate feature, which needs more thinking and fleshing out based on the above feedback. If we do want to change the default assumptions we should try to get it done in this same release, but if not, \"unscoped\" can potentiall wait for a future release.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-04-25.md",
    "content": "# C# Language Design Meeting for Apr 25th, 2022\n\n## Agenda\n\n- [`ref readonly` method parameters](#ref-readonly-method-parameters)\n- [Inconsistencies around accessibility checks for interface implementations](#inconsistencies-around-accessibility-checks-for-interface-implementations)\n\n## Quote of the Day\n\n- \"The group you're talking about just raised their hand\"\n\n## Discussion\n\n### `ref readonly` method parameters\n\nhttps://github.com/dotnet/csharplang/issues/6010\n\nIn another lowlevel session, we looked at a feature designed to address pain points in the BCL with `in`. For the most part, `in` works quite\nwell. However, there are a few APIs that have been reluctant to adopt `in` because of two main reasons:\n\n* Passing an rvalue, which `in` allows, is an anti-pattern and should be disallowed for a subset of APIs. This part could be addressed in an\nanalyzer.\n* `in` requires that `in` be specified at the callsite for lvalues, not `ref`. For APIs that would want to move, such as `QueryInterface`, the\nsource-breaking change of moving to `in` is undesirable, and blocks adoption of the feature. This is not addressable by an analyzer.\n\nWe think that we've left ourselves room in the middle between `ref` and `in` for a `ref readonly` feature, where `in` can be thought of as\n`ref readonly` plus an additional feature of allowing rvalue parameters.\n\nAs part of this, we re-examined the motivation behind `in` allowing rvalues, and behind not allowing `ref` to be used for `in` parameters.\nRvalues were allowed because the similar feature in Midori originally didn't allow rvalues, and that proved painful for devs in that environment.\nThat environment also had an advantage of being entirely new code: migrating from `ref` to `in` or another keyword as a source-break wasn't nearly\nthe pain point it is for the BCL and C#, which has 20-year-old code still in use today.\n\nWe therefore believe there is space for two changes to ease the migration path:\n\n* Allow `in` and `ref` to both be used at the callsite for `in` parameters. `in` will still be preferred, and a warning will be issued when using\n`ref` for such cases, but this will allow a migration path that doesn't completely break consumer code, and the warning can be disabled for\ncodebases that don't want to update.\n* Have a language feature to prevent rvalues being passed where they don't belong. We looked at two possible syntaxes for this: `ref readonly`,\nor using an attribute like `LvalueOnly`, effectively making it an analyzer. After some discussion, we prefer it being `ref readonly`: it's a\nlanguage feature, not an analyzer, so it should look like one. We will error when an rvalue is passed to a `ref readonly` parameter. Both `ref`\nand `in` will be usable at the callsite, but use of `ref` will warn, like it will for `in` parameters.\n\n#### Conclusion\n\nFeature is accepted. The syntax will be `ref readonly`. `ref` will be usable for both `ref readonly` and `in` parameters at the callsite, but a\nwarning will be issues for such cases. Passing an rvalue to a `ref readonly` parameter is an error.\n\n### Inconsistencies around accessibility checks for interface implementations\n\nhttps://github.com/dotnet/roslyn/issues/60885\n\n[Previously](../2021/LDM-2021-05-19.md#protected-interface-methods), we relaxed restrictions around non-public interface methods. Unfortunately,\nthis now leaves us with inconsistencies around internal interface methods: implementations of the interface in another assembly end up implementing\nsuch internal methods implicitly, even when they lack visibility. This is particularly bad for virtual, non-abstract members, where an interface\ncould be perfectly legal to implement in another assembly, and then adding an internal virtual method could cause that other assembly type to end\nup overriding an interface member it did not intend to.\n\nIn general, we dislike all of the proposed solutions here. Checking to make sure that methods aren't implicitly implementing interface methods\ndoesn't solve the issue when the dependent assembly doesn't recompile. Relaxing the restriction for explicit implementations seems to fly in the\nface of accessibility in C#. Trying to emulate the exact behavior of class types has a number of holes in it. We think we need to brainstorm more\nabout what to do here.\n\n#### Conclusion\n\nNo action today. We will go back to the drawing board and revisit.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-04-27.md",
    "content": "# C# Language Design Meeting for Apr 27th, 2022\n\n## Agenda\n\n- [Default parameter values in lambdas](#default-parameter-values-in-lambdas)\n- [Null-conditional assignment](#null-conditional-assignment)\n\n## Quote of the Day\n\n- \"I don't like broccoli, don't make me eat it\"\n\n## Discussion\n\n### Default parameter values in lambdas\n\nhttps://github.com/dotnet/csharplang/issues/6051\n\nIn another iteration on lambdas, we looked at a gap that lambdas cannot expression, but local functions can: default parameter values.\nThere are two schools of thought on this feature, which differ by whether we generate custom delegate types for these lambdas or whether\nwe just use `Action`/`Func` and require runtime introspection of the delegate instance to determine default parameters. The former feature\nwill allow compile-time usage of the default parameter values, while the latter would mean that the main use case would be introspection\nfeatures, such as reflection or source-generators.\n\nThis latter proposal is interesting, but we think it's likely the wrong approach. A feature that can only be observed via reflection or\nsource generation doesn't seem like it integrates well with the rest of C#, and if we ever want to change it in the future the breaking\nchange would likely be quite painful. There is, however, one interesting case that was enabled with C# 10:\n\n```cs\nvar m = M; // Infers Action<int>\nm(); // Error: no value provided for arg0\n\nvoid M(int i = 1) {}\n```\n\nThis case doesn't generate a custom delegate type, and compiles today. We think that this isn't great behavior, and that we should change\nit in C# 11, before `var` for method groups has time to hugely penetrate large codebases.\n\nWe also thought about how strict we should be on matching default parameter values. For example, should this code be an error:\n\n```cs\nvar x = (int i = 1) => {};\nx = (int i = 2) => {}; // Reassigned with a different underlying default.\nx(); // What would this pass for i?\n```\n\nWe again have precedent with method groups, but with a slight difference: method groups converted to delegates are one _possible_ way to\ncall such methods. It is conceivable that there is intentionally a different default value for directly calling a method vs calling it\nvia some delegate type, or the method could come from assembly that the user doesn't control. Lambdas don't have this: they can only be\nconverted to a delegate type, and are defined by the user, not by some other library. Thus, we think it's worth a warning for lambda\ndefault parameter value mismatches; it's technically well-defined and the compiler understands what it means, but it's very likely the\nuser is doing something wrong. We could consider a warning wave for method groups mismatches as well, but that will have to depend on\nwhether we thing the signal-noise ratio would be high enough.\n\n#### Conclusion\n\nFeature is accepted. We will generate custom delegate types for these lambdas, and accept the breaking change to do the same for method groups.\nWe will warn when lambda parameter default values differ from a delegate type they are converted to, if the lambda is not being converted\nto its natural type.\n\n### Null-conditional assignment\n\nhttps://github.com/dotnet/csharplang/issues/6045\n\nWe're looking at old, well-upvoted request: allowing a null-conditional on the left side of an assignment. We generally think it's a good\nfeature, even if `a?.b ??= c` has a very different meaning from `a?.b ?? c`.\n\n#### Conclusion\n\nProposal accepted, moved into the working set.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-05-02.md",
    "content": "# C# Language Design Meeting for May 2nd, 2022\n\n## Agenda\n\n- [Effect of `SetsRequiredMembers` on nullable analysis](#effect-of-setsrequiredmembers-on-nullable-analysis)\n- [`field` questions](#field-questions)\n    - [Partial overrides of virtual properties](#partial-overrides-of-virtual-properties)\n    - [Definite assignment of manually implemented setters](#definite-assignment-of-manually-implemented-setters)\n\n## Quote of the Day\n\n- \"I think I've used goto in C# more than I've used a virtual auto property\"\n\n## Discussion\n\n### Effect of `SetsRequiredMembers` on nullable analysis\n\nhttps://github.com/dotnet/csharplang/issues/3630  \nhttps://github.com/dotnet/csharplang/issues/6081\n\nWe have an open question on required properties: what should the effect of `SetsRequiredMembers` be on nullable analysis? Should the property be taken as a tool to silence\nthe compiler, or should it restore the nullable warning to the current constructor?\n\nA key insight of required as a feature is that is orthogonal to nullable. It can move where a nullable warning is reported, but it does not suppress the warning: assigning\na not-null reference type property to null will still produce a warning. If `SetsRequiredMembers` started actually suppressing the nullable warning, that would mean that\nthis orthogonality is lost, and the two features become more entangled that we would otherwise want. While there could be some users confused why we aren't also warning or\nerroring on nullable or value type members that aren't set in the constructor, we think the right decision is to have `SetsRequiredMembers` move the nullable warning back to\nthe constructor, rather than suppressing it completely.\n\n#### Conclusion\n\nNullable warning will be moved back to the constructor when `SetsRequiredMembers` is applied.\n\n### `field` questions\n\nhttps://github.com/dotnet/csharplang/issues/140\n\n#### Partial overrides of virtual properties\n\nhttps://github.com/dotnet/csharplang/issues/6076  \nhttps://github.com/dotnet/csharplang/issues/6077\n\nFirst up in semi-auto properties, we have a couple of questions about the behavior of overriding a virtual property with a semi-auto property. There existing rules in C# that\nprevent an auto-property from overriding only one accessor of a virtual property, as it's a potential footgun in waiting. There are two possible viewpoints here:\n\n1. This is a restriction that applies to properties with generated fields. This property has a generated field, so the restriction should apply, as the footgun is still there.\n2. This restriction doesn't apply to properties with manually-implemented bodies, so it shouldn't apply here either.\n\nAfter some discussion, we're concerned that the footgun the rule exists to prevent is still here for semi-auto properties. We're also concerned about what the meaning of this\ncode is:\n\n```cs\nclass Base\n{\n    public virtual int Prop { get; set; }\n}\nclass Derived : Base\n{\n    public override int Prop { get => field; }\n\n    public Derived()\n    {\n        Prop = 1; // Does this call the setter from Base? Or does it assign to the backing field in Derived?\n    }\n}\n```\n\nWe don't have a good answer for what this code does: by the specification, it should likely assign to the backing field. But either behavior is surprising.\n\nWe also had a small side conversation on whether we should have done work with auto properties when they were first introduced to allow them to share storage across virtual\nhierarchies, but there are issues with this. If this could be done across assembly boundaries, it would be exposing that you have an auto-property as a part of the public\ncontract of a type, and that breaks the encapsulation that properties provide.\n\n##### Conclusion\n\nSemi-auto properties must override all accessors of a base property.\n\n#### Definite assignment of manually implemented setters\n\nhttps://github.com/dotnet/csharplang/issues/6080\n\nIn C# 11, we are changing structs to automatically default initialize fields if the struct is read before all fields are assigned, and we need to decide if this behavior\nshould apply to semi-auto properties as well. Our options are:\n\n1. Do not default initialize the struct if a manually-implemented semi-auto property setter is called. This could either be a blanket statement, or we could try to do some\ncross-method analysis to determine if we need to do the default initialization of the property.\n2. Default initialize as if it was a regular property setter.\n3. Default initialize as if it was a regular property setter and suppress the warning, as there's nothing the user can do about it.\n\nFor option 1, we don't think this is the right time to introduce cross-method analysis into C#. It would bring with it all the complexity of cross-method analysis for very\nlittle benefit; if we were going to introduce cross-method analysis, there are areas such as nullable analysis that would have the exact same set of problems, but would be\nmuch more beneficial. For option 3, we note that the uninitialized struct warning is not turned on by default, and users have to opt into it. For these users, there is indeed\nnothing that can be done about the warning except providing an explicit property initializer, or not using the feature. Most C# users will never see the warning, and for those\nthat do care, they should be aware of it in this case too.\n\n##### Conclusion\n\nDefault initialize when calling a manually implemented semi-auto property setter, and issue a warning when doing so, like a regular property setter.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-05-09.md",
    "content": "# C# Language Design Meeting for May 9th, 2022\n\n## Agenda\n\n1. [Numeric IntPtr](#numeric-intptr)\n2. [Ref readonly parameters](#ref-readonly-parameters)\n\n## Quote of the Day\n\n- \"Not all Unsafe is created equal\"\n\n## Discussion\n\n### Numeric IntPtr\n\nhttps://github.com/dotnet/csharplang/issues/6065\n\nThis C# change is mostly a reaction to a change in the BCL's thinking around `IntPtr`, and how generic math will apply to it. During the design of\n`nint`, we wanted to keep `nint` and `IntPtr` as distinct as possible, as the intent was not to enable general math on `IntPtr`s. However, as the\nBCL has rationalized their generic math designs, they've decided that the easiest way forward will be to remove this distinction, and enable\ngeneric math on `IntPtr`. We therefore want to update C# to similarly remove the distinction, and regard `nint` as simple alias for `IntPtr` (and\n`nuint` a simple alias for `UIntPtr`) to keep the language and runtime in sync.\n\n#### Conclusion\n\nAccepted.\n\n### Ref readonly parameters\n\nhttps://github.com/dotnet/csharplang/issues/6010\n\nWe wanted to revisit the decision we made [last time](LDM-2022-04-25.md#ref-readonly-method-parameters), as further discussion after the meeting\nrevealed that we had conflated a few features in the decision, and we wanted to break them out and be sure that we are comfortable with feature.\nIn particular, we did not explore the analyzer route enough, as further investigation revealed that, after the `in`/`ref` mismatch was dealt with,\nnothing prevented using an analyzer to prevent rvalues being passed to `in` parameters. There are 3 main components, therefore, that this proposal\nseeks to address:\n\n1. There is no way to move an existing API from `ref` to `in` without a source-breaking change. We addressed this issue by allowing `ref` to be used\nfor `in` parameters, and did not discuss changing this today.\n2. At the declaration site, there is no way to indicate that being passed an rvalue from the call site is likely an error. This was our main discussion\ntoday.\n3. At the call site, lack of required `in` makes it unclear that a ref is being captured. This was not covered today, and we'll try to squeeze a\ndiscussion in next meeting.\n\nOn the surface, points 2 and 3 appear to be a good fit for an analyzer, but we think there might an opportunity to address a lingering annoyance\nfrom the original design of `in` parameters: the `in` keyword does not correspond to `ref readonly`, the keyword we use everywhere else throughout\nthe language for a similar concept. We see an opportunity to retcon `in` to be a modifier with extra behavior on top of `ref readonly`, much like\n`out` is a modifier on top of `ref` with extra behavior on top. There is also the potential for an analyzer here to make the language _more_ complex,\nnot less, as now this spot in the table of declaration site modifiers/permitted call site forms would be taken by an analyzer, not by a native\nlanguage feature.\n\nThe history of `in` as a feature stretches back to the time some members of the LDT spent on the Midori project, where they had a custom version of\nC# that supported a number of features, including a version of `ref readonly`. Initially, they used `ref readonly` as both the declaration site and\nthe call site modifier, but user feedback, particularly on the call site side, was immediate and vocal. To combat this, they brainstormed and\nsettled on `in` (first just at the call site, then eventually as a parameter modifier), as it's the natural counterpart to `out` and has been used\nas a C# keyword since C# 1.0. This was then brought into C# in the C# 7 timeframe, as we added `ref struct`s based on Midori's experience in the\narea. Midori, however, didn't have as many of these APIs where passing an rvalue was incorrect, as it had an expanded permissions system for\nlifetime control. C# does not have this, so we think that `ref readonly` is a good change to make up for this.\n\nNext, we will look at how `ref readonly` should affect the call site, and whether it should require that `ref`, `in`, or some other specifier to\nbe explicitly provided.\n\n#### Conclusion\n\nWe upload the decision around `ref readonly` as a parameter modifier.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-05-11.md",
    "content": "# C# Language Design Meeting for May 11th, 2022\n\n## Agenda\n\n1. [Inconsistency around accessibility checks for interface implementations](#inconsistency-around-accessibility-checks-for-interface-implementations)\n2. [`ref readonly` method parameters](#ref-readonly-method-parameters)\n3. [Pattern matching with UTF-8 String Literals](#pattern-matching-with-utf-8-string-literals)\n\n## Quote of the Day\n\n- \"Did [redacted] turn their camera on? I'm in trouble.\"\n\n## Discussion\n\n### Inconsistency around accessibility checks for interface implementations\n\nhttps://github.com/dotnet/roslyn/issues/60885\n\nA small group went back and looked at this issue, to come up with a more palatable solution to the problem than the existing proposals. Unfortunately, our hands\nare somewhat tied here, as the runtime does not do any form of assembly accessibility checks. If the signature of a new interface member (DIM or not, `internal` or\nnot) lines up with an existing member of a type that implements that interface, the runtime will consider that existing member to be an implementation of the\ninterface member. We therefore think the best we can do is to perform a real accessibility check at compile-time. This isn't something we do today, and will prevent\nthe user unintentionally getting into this scenario at compile time. While it can still be observed at run-time due to an upgraded assembly version, this is no\ndifferent than other existing breaks when introducing new members into interfaces.\n\n#### Conclusion\n\nPerform a real accessibility check for implementations of internal interface methods, and error if the check fails.\n\n### `ref readonly` method parameters\n\nhttps://github.com/dotnet/csharplang/issues/6010\n\nFollowing up after the [last meeting](LDM-2022-05-09.md#ref-readonly-parameters) on `ref readonly` parameters, we discussed the call site rules for `ref readonly`\nparameters. We were dissatisfied with the rules we decided in our [first meeting](LDM-2022-04-25.md#ref-readonly-method-parameters) on the feature, which stated\nthat `ref readonly`'s \"natural\" calling convention would be `in`, and using `ref` at the call site would be supported, but have a warning. This felt off, as `in`\nat the declaration site has been redefined to be `ref readonly` + convenience features. Using `in` at the call site, therefore, is a mismatch. We also have\nprecedent in the language for `ref`, as that is what is required for `ref readonly` returns. At the same time, using `ref` at the call site doesn't always sit right\neither, as `ref` indicates danger: the method being called can see and modify your value. This danger signal is why `ref` is required at the call site in the first\nplace, instead of following the C++ pattern of implicit by-ref parameters. In some ways, we think that there's an argument for allowing `ref readonly` parameters to\nsimply be silent, rather than requiring any specifier; many of the same arguments for `in` apply to `ref readonly` at the call site as well. We have lifetime rules\nto flag truly unsafe value capturing, and `ref readonly` ensures that a call can't mutate the value from under the caller. That being said, however, the main use\ncases we are looking at the `ref readonly` feature will benefit from some marker at the call site. A key distinction of most of the APIs we're considering is that\nthey capture or return refs from these parameters, and a marker of some kind is a good thing for such scenarios.  We also need to consider that we will have APIs\nmigrating to `ref readonly` from both `ref` and from `in`, so existing code will have potentially any or no existing markers.\n\nTo resolve these constraints, we've come up with the following set of rules, which cover call site conventions for `ref`, `ref readonly`, and `in` parameters:\n\n| Call site annotation | `ref` parameter | `ref readonly` parameter | `in` parameter |\n|----------------------|-----------------|--------------------------|----------------|\n| `ref`                | Allowed         | Allowed                  | Warning        |\n| `in`                 | Error           | Allowed                  | Allowed        |\n| No annotation        | Error           | Warning                  | Allowed        |\n\n* `ref` and `ref readonly` parameters require lvalues at the call site.\n* `in` allows lvalues or rvalues at the callsite.\n\n#### Conclusion\n\nSee the above table and bullets.\n\n### Pattern matching with UTF-8 String Literals\n\nhttps://github.com/dotnet/csharplang/discussions/6036\n\nFinally today, we looked at pattern matching for UTF-8 string literals, particularly against inputs of `ReadOnlySpan<byte>`. This is similar to the work we did for\n`string` for C# 11, where you will be able to pattern match an input of `Span<char>` against string literals. We're generally supportive of this, and we have a broader\ngoal in mind: we'd eventually like `u8` literals to _be_ constants. The runtime would need to be updated to support this (as the CLI spec doesn't indicate that\nUTF-8 literals are supported as constant values today), but we are in support of steps along the journey of making `u8` literals appear as constants, including pattern\nmatching support. We don't think this is top priority, though, so while we would accept a community contribution to create a specification for how this would work, we\nwon't be actively working on it at this time.\n\n#### Conclusion\n\nWe will review a community-contributed specification for this feature.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-05-23.md",
    "content": "# C# Language Design Meeting for May 23rd, 2022\n\n## Agenda\n\n1. [Open issues for `ref` fields](#open-issues-for-ref-fields)\n\n## Quote of the Day\n\nNo particularly amusing quotes were said during this meeting, sorry.\n\n## Discussion\n\n### Open issues for `ref` fields\n\nhttps://github.com/dotnet/csharplang/issues/1147  \nhttps://github.com/dotnet/csharplang/issues/6149\n\nToday we looked at several open issues in `ref` fields.\n\n#### Parsing `scoped`\n\nThere is analogy here to other modifiers we are adding in C# 11, such as `required`. For that modifier, we said that we wanted to error\nwhen types names conflict. However, local variables are more of a concern, as the name `scoped` is a perfectly reasonable local variable\nname. We would like to take the same approach for `scoped` as we do for `required`.\n\n##### Conclusion\n\nWe will error when types are named `scoped`. We will do the parsing work to make `scoped` as a local name work.\n\n#### `ref` auto properties\n\nJust as auto-properties are a simplification on the private backing field + property scenario, a ref auto-property could be a simplification\non the private backing field + ref-returning property backing scenario for ref structs. While we think this is a scenario that makes sense,\nwe think it would require a setter/initer to actually be useful: otherwise, the user can only assign the backing ref field in their\nconstructor. We don't have a real way to emit setters for ref-returning properties as the runtime doesn't support setters with a `ref` `value`\nargument. We could potentially do some emit tricks to make it work, but we think that it would be better to wait for first-class runtime\nsupport for the scenario, which can then be picked up more generally by other languages.\n\n##### Conclusion\n\nWe will hold off on `ref` auto properties until we have `ref`-returning property setter support in the runtime.\n\n#### Allowing `ref` assignment in object initializers\n\nFinally, we looked at whether we should allow `ref` assignment in object initializers. We do have customers that want this: the runtime has\nbeen dogfooding a build of the feature, and this was one of their first requests. We do like it in general, but we need to think about the\nguardrails for requiring ref assignment will work. In particular, there could be multiple potential things that a user would want to do:\n\n* `required ref int Field;` - Consumers must ref assign a location to `Field`.\n* `ref required int Prop { get; }` - Consumers must assign a value to the storage location returned from `Prop`.\n\nWe punted on this question for `required` members previously, so we'll need to consider more at the next meeting.\n\n##### Conclusion\n\nTentatively accepted, but we need to think about guardrails before confirming.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-06-06.md",
    "content": "# C# Language Design Meeting for June 6, 2022\n\n## Agenda\n\n1. [Open issues for `ref` fields](#open-issues-for-ref-fields)\n2. [Open issues for static virtual members](#open-issues-for-static-virtual-members)\n3. [Concatenation of Utf8 literals](#concatenation-of-utf8-literals)\n\n## Discussion\n\n### Open issues for `ref` fields\n\nhttps://github.com/dotnet/csharplang/issues/6149\n\nWe discussed the questions out of order because of the way we perceived them to influence each other.\n\n#### Question 5: `scoped` differences in overrides and interface implementations\n\nWhen overrides or implementations differ from their base in terms of `scoped` what should we do? We seem to have the following options:\n\n1. Do nothing: no restrictions for 'scoped' in override/implementation (unsafe)\n2. Disallow use of 'scoped' in overrides/interfaces\n3. Disallow differences in 'scoped' in override/implementation\n4. Allow adding 'scoped', disallow dropping 'scoped' in override/implementation\n\nOption 1 and 2 do not seem helpful. Option 3 is simple, allows expressing reasonable things and is safe.Option 4 is a bit more involved, but is more expressive too, and seems more consistent with nullability etc.\n \n##### Conclusion\n\nWe lean to 4, but do not have important scenarios. We're fine if we only make it to 3 now and potentially do 4 later, which will be compatible. We'd need to spend the time to assure ourselves that 4 is safe.\n\n#### Question 6. `scoped` differences in delegate conversions\n\nSimilar question and similar options, but for conversion of lambdas and method groups to delegate types. \n\n##### Conclusion\n\nThis should do the same as in the previous question. Even for explicit conversion we should not break `scoped` safety. There are unsafe APIs for breaking the rules if people really want to.\n\nInferred delegate types will preserve `scoped` from their lambda or method group.\n\n#### Question 4. Constructor that does not set ref field\n\nShould we report a diagnostic on a constructor that doesn't initialize a ref field? It will lead to a null ref exception later.\n\nOn the one hand we have a set of rules for non-nullable reference types that we could probably adapt to ref fields. On the other hand this is an advanced feature set and this may not be worth it. Also we can't do anything about default values of the ref struct, which are likely to be common.\n\nThe runtime is planning to do work so that null ref dereference behavior is well defined, as no matter what, safe code can now create ref fields with nulls in them. The runtime will ensure that all locals with references will be zeroed even if `SkipLocalsInit` is specified.\n\n##### Conclusion\n\nNo diagnostics - it's not worth it, wouldn't save every case anyway, and this is an expert feature.\n\n#### Question 3. Ref assignment in object initializers\n\nConstructors allow ref parameters to be assigned to ref fields. Should object initializers also allow ref assignment?\n\n##### Conclusion\n\nYes. There's no reason not to, it's just a little bit of syntax and it's obvious what it does.\n\n### Open issues for static virtual members\n\nhttps://github.com/dotnet/csharplang/blob/main/proposals/static-abstracts-in-interfaces.md#unresolved-questions\n\n#### Adjusting the type argument rule\n\nShould we allow interfaces to be type arguments if they have virtual but not abstract static members - i.e. if all virtual static members have a default implementation?\n\nIf we don't allow this, adding a static virtual with a default implementation to an existing interface that has no static virtuals will break anyone currently passing that interface as a type argument. This breaks the principle that new interface members with default implementations don't break existing code.\n\n##### Conclusion\n\nLet's loosen the rule to preserve the value of default implementations,  assuming that we can loosen the corresponding rule in the runtime.\n\n#### Virtual equality and conversion operators\n\nShould virtual equality and conversion operators be allowed to have default implementations, and to provide implementations in overrides? If so are there any restrictions?\n\nCurrently interfaces are not allowed to declare *non*-virtual equality and conversion operators. The reason is that such operators too easily lead to confusing or conflicting behavior on the interfaces. However, *virtual* operators do not apply to the interfaces themselves but only to type parameters constrained by them, so they do not seem to have these same problems.\n\nNevertheless, an interface `IThing` with a declaration of the form\n\n``` c#\npublic interface IThing\n{\n    static virtual bool operator ==(IThing i1, IThing i2) => ...\n    ...\n}\n```\n\nwould be quite confusing, especially since it would not apply to instances of the interface itself:\n\n``` c#\nvar result = i1 == i2; // Reference equality\n```\n\nOn the other hand, a declaration that has \"self-type\" operands would probably be a lot harder to misunderstand in that way:\n\n``` c#\npublic interface IThing<TSelf> where TSelf : IThing<TSelf>\n{\n    static virtual bool operator ==(TSelf i1, TSelf i2) => ...\n    ...\n}\n```\n\nConversions are already not allowed to have interface operands directly.\n\n##### Conclusion \n\nBoth types of operand declarations should be allowed to have default implementations. \n\nWe will limit equality operators so that one of the operands cannot be the interface itself and has to be a self-constrained type parameter. The other can be anything (including an interface).\n\n### Concatenation of Utf8 literals\n\nhttps://github.com/dotnet/roslyn/issues/60896#issuecomment-1129362977\n\nThe motivating scenario is line breaking source code containing very large Utf8 string literals.\n\nShould we wait for a `+` operator for Utf8 strings (`ReadOnlySpan<byte>`) in general? Is such a thing even desirable? After all it would be expensive at runtime, and concatenation might not generally be the obvious semantics for `+` on spans - even on spans of bytes. However, on literals its meaning is obvious.\n\n#### Conclusion\n\nLet's do it. Let's make sure people get good error messages when they try to `+` non-literals.\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "meetings/2022/LDM-2022-06-29.md",
    "content": "# C# Language Design Meeting for June 29th, 2022\n\n## Agenda\n\n- [UTF-8 literal concatenation operator](#utf-8-literal-concatenation-operator)\n\n## Quote of the Day\n\n- \"This is an example of our admirable quality that no stone is left unturned\"\n\n## Discussion\n\n### UTF-8 literal concatenation operator\n\nhttps://github.com/dotnet/csharplang/issues/184  \nhttps://github.com/dotnet/csharplang/pull/6221\n\nToday, we looked at a small proposal update for UTF-8 strings, based on BCL dogfooding feedback: the ability to concatenate UTF-8 string literals\ntogether with the `+` operator so that long strings can be split across lines. This is similar to the work with interpolated string handlers, where\nwe similarly enabled the `+` operator for splitting strings across lines. We had two main discussion points:\n\nFirst, should we enable `+` as a general operator on all `ReadOnlySpan<byte>`s? For example, should the following code work?\n\n```cs\nReadOnlySpan<byte> M() => \"hello \"u8;\nvar helloWorld = M() + \"world\"u8;\n```\n\nWe don't think that is a general case we want to support: concatenation of literals can be done easily at compile time, but this would need a general\nability to add `ReadOnlySpan<byte>`s together, and we don't know how that would work. Where would the resulting byte sequence live, for example, and\nwhat would be its lifetime?\n\nSecond, we thought about whether this operator should have precedence over a user-defined operator `+` on `ReadOnlySpan<T>`? According to the C# spec,\nall existing predefined operators in C# _do not_ have precedence over user-defined operators. However, this is not how the compiler is actually\nimplemented: the native C# compiler had a bug that always used predefined operators, even when the underlying type defined a `+` operator itself, and\nRoslyn reimplemented that bug during its creation. When implementing the `+` predefined operator for `ReadOnlySpan<byte>`, however, we did not\ncarry that bug forward, so if a user defines their own `ReadOnlySpan<T>` with a `+(ReadOnlySpan<T> left, ReadOnlySpan<T> right)` operator defined on\nit, that operator will be preferred over this predefined one. We could go and reimplement the bug for this case as well, but we don't think the\nscenario is important enough to spend the time, and it will simplify the spec if we continue to specify predefined operators exactly as they are today,\nrather than carving out a special case for this `+` operator.\n\n#### Conclusion\n\nProposal accepted.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-07-13.md",
    "content": "# C# Language Design Meeting for July 13th, 2022\n\n## Agenda\n\n1. [Lambda default parameters](#lambda-default-parameters)\n\n## Quote of the Day\n\n- \"We love to point out failures, it's what we do\"\n\n## Discussion\n\n### Lambda default parameters\n\nhttps://github.com/dotnet/csharplang/pull/6274  \nhttps://github.com/dotnet/csharplang/issues/6051\n\nToday, we reviewed the draft specification for default lambda parameters. There are two main parts of this proposal we need to consider:\n\n1. The actual changes to lambdas themselves. These are relatively straightforward, with only a few nuanced sections we need to consider.\n2. Changing the natural type of method groups. This is more nuanced, as it will be a breaking change from C# 10.\n\nFor the first point, we had relatively few pieces of feedback. We think that we should indeed error when the default parameter value of an argument\ndiffers from the target type. For example, this should be an error:\n\n```cs\ndelegate void D(int i = 0);\nD d = (int i = 1) => {}; // Error: default parameter values differ.\n```\n\nThe one case that we think should be acceptable is when the lambda does not specify a default parameter value at all. This is an important backcompat\ncase as it as worked since lambdas were introduced, as well as being user convenience.\n\n```cs\ndelegate void D(int i = 0);\nD d1 = i => {}; // Fine: no value specified\nD d2 = (int i) => {}; // Fine: no value specified\n```\n\nFor the second part, we think we need a more detailed understanding of where the breaks can occur before we decide for sure that we will accept the\nbreak. We know from C# 10 how subtle and painful breaks here can be. While they would be more limited in scope, and we think that it would only breaks\nsince C# 10, not since lambdas were introduced, we want to understand the space more before committing.\n\nFinally, we briefly considered whether we should support `params` parameters as well. We think they're interesting, but didn't make a final decision today.\n\n#### Conclusion\n\nThe lambda rules themselves are accepted, with the error exception for lambdas that don't specify default parameters being converted to a type that does\nhave them. We will get a better understanding on method groups before making a decision.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-07-27.md",
    "content": "# C# Language Design Meeting for July 27th, 2022\n\n## Agenda\n\n1. [`scoped` for local declarations](#scoped-for-local-declarations)\n\n## Quote of the Day\n\n- *nervous chuckling* \"That's actually an interesting question!\" \"I know, it's just when you say scary things.\"\n\n## Discussion\n\n### `scoped` for local declarations\n\nhttps://github.com/dotnet/roslyn/issues/62039  \nhttps://github.com/dotnet/csharplang/issues/1147\n\nToday, we looked at allowing `scoped` as a local modifier in all local declaration context, such as `using`s, `foreach` iterator variables, and such. We like the idea in principle: users don't\nthink of the various different grammatical ways of creating a local variable differently, they think of them all as locals. There were a couple more in-depth points of discussion about the\nimplementation:\n\n* Is `scoped` or not something that `var` should be able to infer? This matters for deconstruction, as in `var (x, y) = MethodCall();`. After some consideration, we don't think scopedness is\nsomething we can or should infer. It might also vary between each of the deconstruction variables. Given this, we think that `scoped` needs to explicitly declared, not inferred in any local case.\n* The specification for `scoped` doesn't particularly line up with how we consider modifiers. We'd like to think of this as a new kind of modifier, a modifier that must go directly on a type, rather\nthan a modifier that can go anywhere in the modifiers list of a method. Unlike method modifiers, `scoped` is specifically a modifier on either the return value or a parameter value, and should be\napplied in those locations. `scoped unsafe Span<int> M() => ...;`, for example, isn't legal. The `scoped` affects the return, while the `unsafe` generally affects the method body. We therefore think\nthat the specification (and Roslyn implementation) should match this intuition.\n\n#### Conclusion\n\nWe approve the general concept in this issue, but the grammar specification needs to be updated.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-08-03.md",
    "content": "# C# Language Design Meeting for August 3rd, 2022\n\n## Agenda\n\n1. [`ref` fields specification updates](#ref-fields-specification-updates)\n\n## Quote of the Day\n\n- \"If anyone is confused by these rules, you can hit me up anytime. I advise caffeine before the meeting.\"\n\n## Discussion\n\n### `ref` fields specification updates\n\nhttps://github.com/dotnet/csharplang/issues/6337  \n\nToday, we looked at changes that have been made to the `ref` fields feature from implementation feedback. Changes 1 and 2 were approved with very little discussion. Point 3 generated much more\ndiscussion.\n\nIn particular, we discussed the change that `` `this` for `struct` instance methods `` is now implicitly `scoped`. Part of this overlaps with the next point, that `` `ref` parameters that refer to `ref struct` types ``\nshould be `scoped` by default, but it goes further, making it the default for all structs, `ref` or not. The general question is: should we narrow this to just `ref struct` types? This would be a breaking change, and\nwe've accepted a breaking change in this feature already with the updated escape rules under the principle of reducing confusion and having the language do the right thing. This case is less clear-cut though: for the\nescape rules, the general consensus is that the old defaults were wrong for nearly all methods, and real-world data indicated that very, very few such methods existed. That isn't the case for the `this` parameter on\n`struct` methods though: `ImmutableArray<T>.ItemRef(int index)`, for example, would be broken by having `this` be implicitly unscoped. If we were designing the system from scratch, we might have narrowed this rule,\nbut given that the compat concerns are larger and the benefit isn't clear cut, we don't think we should narrow this rule.\n\nWe also took a bit of time to think about whether we were cutting off our ability to make future innovations in the space of `ref struct`s with these rules, such as allowing them in generics, implementing interfaces,\nand future flow analysis improvements. We don't think that we're introducing any new problems in those spaces, so we'll proceed as is.\n\nWe did not get to points 4 and 5 today. We will discuss those over email and potentially in a future in-person LDM, if required.\n\n#### Conclusion\n\nPoints 1-3 are approved.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-08-10.md",
    "content": "# C# Language Design Meeting for August 10th, 2022\n\n## Agenda\n\n1. [`required` property default nullability](#required-property-default-nullability)\n\n## Quote of the Day\n\n- \"If I'm going on a long journey I always think I can get all this stuff done on the plane. I always end up watching a movie.\"\n\n## Discussion\n\n### `required` property default nullability\n\nhttps://github.com/dotnet/csharplang/issues/6359\n\nToday we looked at what the default state of required properties should be at the beginning of a constructor. As implemented and specified currently, properties\nwill be treated as if they have the null state they claim, so `public required string Prop { get; set; }` would have a not-null state at the start of a constructor.\nWe don't think this is a good idea: in C# 10, users could either count on a chained constructor having set all members, or will have the default state of all members\nset to not-null. We think `required` serves as a good heuristic indicator that the property should be set to `default(T)` at the start of the constructor. The exception\nto this is when the user chains to a constructor has specified `SetsRequiredMembers` on the constructor.\n\n#### Conclusion\n\nWe accept the following rules:\n\n1. When chaining to a constructor that does not have `SetsRequiredMembersAttribute`, all `required` members have a null state of `default(T)`, including those\nrequired members from a base type.\n3. At the end of a constructor that is attributed with `SetsRequiredMembersAttribute`, all `required` members must have the null state they are declared with,\nincluding those required members from a base type.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-08-24.md",
    "content": "# C# Language Design Meeting for August 24th, 2022\n\n## Agenda\n\n1. [C# feature triage](#c-feature-triage)\n\n## Quote of the Day\n\n- \"There will also be a debate about whether the next one will be 13 or 14\"\n\n## Disclaimer\n\nHi all, your friendly C# note taker here. [This time last year](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-08-30.md#discussion), when we did\nour initial C# 11 triage, I mentioned that readers should not try to use the meeting to \"read the tea leaves\" for what would be in C# 11. Most of our readers didn't, and\nfor that we are appreciative. However, a few blog posts did crop up on what features were going to be in C# 11, and they contained information about features the did not\nmake C# 11 (and missed some features that did make it). We'd ask, again, that you please not use these notes as a way of saying what will be in the next version of C#.\nWe are looking through our backlogs, user feedback, and other such areas to decide what areas we want to be focusing on, but we are not committing to anything just yet.\nWe are merely trying to get an understanding of our priorities, and any of these features could make C# next, make it in preview form, or not make it at all. Thanks.\n\n## Discussion\n\n### C# feature triage\n\nToday, we started our future C# feature triage. This is the first of at least 2-3 meetings where we will be looking at the big and small ticket items and feature areas\nto determine where our design focus will be for the next year. This year, we started the process by collecting topics from all members of the LDT. The recurring themes\nof these topics are:\n\n1. Discriminated unions and working with un/less-structured data. Nearly everyone brought up a topic in this broad area, be it looking at closed-type-hierarchy-style\ntagged unions or unstructured anonymous inline unions of data. We think there's a lot of potential here, and in particular potential for a holistic exploration of the\nspace in the same style as we did for pattern matching, where we used a broad internal vision to deliver 4+ releases of features to build out the space. We would like\nto spend time in the next cycles coming up with a similar vision for this space, and start delivering on features in it that will fit into this broader vision of making\ndata easier to work with in the language.\n2. Roles/extension everything. This is another big feature space that includes things both large and small that users have been asking about for years. Unlike DUs, we\nhave a better understanding of the specific areas this feature is trying to address, and an internal working group on roles has been persistently chipping away at a\ndesign for breaking up the larger feature into smaller components that can be shipped without breaking our future ability to innovate in this space. We hope to have\nresults from this group to share soon.\n3. Tooling improvements. A rarer suggestion from this group, but there is interest in investing more in the \"C#-adjacent\" tooling experience, and seeing what can be\ndone to further improve the polyglot notebooks and interactive scenarios and bring them to parity with regular C# projects. We'd also like to look at the experiences\nthat other languages bring in their tooling (specifically via language features) and see what lessons we can learn to make our own experiences better.\n4. Expression trees. As last year, discussions on how to modernize this experience have been continuing in the background, and we would like to address them. It's not\na small amount of work, but it needs to start somewhere.\n5. Community-driven features. We've been successful in the past few releases of having community members design and implement C# features, and we'd like to continue this\ntrend. `field` is an example of this we hope to see soon (there are outstanding design questions that need to be answered after implementation hit issues), but other\nfeatures in the Any Time bucket that receive community interest should also get some of our attention.\n6. Smaller nits, such as block expressions. We've talked about rounding off some smaller corners that have usability impacts, such as expanding our set of expressions\nin C# (making switch expressions have less of a cutoff, allowing returns in new places, etc). We are generally aligned on the idea, but there are some serious syntax\nbattles that need to be fought.\n\nWhen we look at the sets of features we're interested in, we see large emerging themes, and opportunities to break up the features into smaller things working groups\ncan investigate and bring back to the larger group. We've had good success with this approach in both `required` members and in the ongoing group working on roles, and\nwe think it's a strategy we should adopt more. Next time, we'll discuss these themes further, and see if we can break them up further into more concrete areas for\ninvestigation.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-08-31.md",
    "content": "# C# Language Design Meeting for August 31st, 2022\n\n## Agenda\n\n1. [Short term work triage](#short-term-work-triage)\n    1. [Partial properties](#partial-properties)\n    2. [Using aliases for any type](#using-aliases-for-any-type)\n    3. [Null-conditional assignment](#null-conditional-assignment)\n    4. [`await?`](#await)\n    5. [`params IEnumerable`](#params-ienumerable)\n    6. [Discriminated Unions](#discriminated-unions)\n    7. [Roles](#roles)\n    8. [`pragma warning enable`](#pragma-warning-enable)\n    9. [Ignored directives support](#ignored-directives-support)\n    10. [Primary constructors](#primary-constructors)\n    11. [Switch expression as a statement](#switch-expression-as-a-statement)\n\n## Quote of the Day\n\n- \"Features ready to eat\"\n\n## Discussion\n\n### Short term work triage\n\nThe LDM is going on break for 3 weeks due to member absences, and the compiler team is starting to wrap up on C# 11 bugs. We therefore took today to triage through smaller features\nand prototyping work we'd like to start on as we wrap up. The former should be simple features that don't need further design work, and the latter should be features where a prototype\nwould serve to further the design.\n\n**Important note**: This list is longer than the compiler team will be able to look at in the next few weeks. Think of it as a shortlist, nothing more.\n\n#### Partial properties\n\nhttps://github.com/dotnet/csharplang/issues/6420\n\nThis feature has not been looked at much by the full LDM, but the proposal seems straightforward, follows our existing rules for partial methods, and avoids complicated questions on\nwhat to do for fully-auto properties. We'll put it on the list.\n\n#### Using aliases for any type\n\nhttps://github.com/dotnet/csharplang/issues/4284\n\nWe originally wanted to look at this in conjunction with `global using`s, but didn't get to it. It's on the list.\n\n#### Null-conditional assignment\n\nhttps://github.com/dotnet/csharplang/issues/6045\n\nAnother one we wanted to get to during 11, but ran out of time. It's on the list.\n\n#### `await?`\n\nhttps://github.com/dotnet/csharplang/issues/35\n\nThis is our second-highest upvoted `Any Time` milestone issue, and continues C#'s operator monad over nulls (along with the previous issue). It's on the list.\n\n#### `params IEnumerable`\n\nhttps://github.com/dotnet/csharplang/issues/179\n\nThis issue is specifically for `params IEnumerable` parameters, not including `Span<T>` or other possible variations. And we think that's part of the problem with trying to approach\nthis right now: there's too many questions about what exactly to support. We think this has too many questions to be on the shortlist.\n\n#### Discriminated Unions\n\nhttps://github.com/dotnet/csharplang/issues/113\n\nObviously, this is not in the \"go implement in the next few weeks\" category. However, we think that starting to prototype will help inform our design choices in this space, and this is\nfeature is (by a large margin) the most up-voted issue on csharplang. Protoyping is on the list.\n\n#### Roles\n\nhttps://github.com/dotnet/csharplang/issues/5497\n\nThis is another area where we think prototypes will help drive the conversation, especially since our current questions are around feasibility of implementation. Prototyping/initial\nimplementation is on the list.\n\n#### `pragma warning enable`\n\nhttps://github.com/dotnet/csharplang/issues/3986\n\nThis is fairly simple and non-complicated. However, very rarely for a csharplang issue, this issue has no upvotes or activity of any kind, and some members of the LDT are conflicted on\nwhether the feature is worth it. Not on the list.\n\n#### Ignored directives support\n\nhttps://github.com/dotnet/csharplang/issues/3507\n\nWould be nice to have, but only in conjunction with the rest of the simple programs feature. Implementation might be one of the simplest ever features in the compiler, but without the\ntooling to accompany it we don't know that this is the right design. Not on the list.\n\n#### Primary constructors\n\nhttps://github.com/dotnet/csharplang/issues/2691\n\nThe last time these were brought up, we blocked on what exactly the primary constructor parameters _are_: fields, captures, or something else? We think a prototype to play around with might\nhelp us make progress, so this is on the prototyping shortlist.\n\n#### Switch expression as a statement\n\nhttps://github.com/dotnet/csharplang/issues/2860\nhttps://github.com/dotnet/csharplang/issues/3038\n\nThere are a few different directions we could take this space. We could take this approach, or look at modernizing switch statement syntax, or some other form. This space needs more design,\nso this is not on the list.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-09-21.md",
    "content": "# C# Language Design Meeting for September 21st, 2022\n\n## Agenda\n\n- [Unchampioned issue triage](#unchampioned-issue-triage)\n    - [Track subtype exhaustiveness for classes with only private constructors](#track-subtype-exhaustiveness-for-classes-with-only-private-constructors)\n    - [ReadOnlySpan initialization from static data](#readonlyspan-initialization-from-static-data)\n    - [Embedded Language Indicators for raw string literals](#embedded-language-indicators-for-raw-string-literals)\n    - [Implicit Parameters](#implicit-parameters)\n- [Unsafer Unsafeness](#unsafer-unsafeness)\n    - [Conclusion](#conclusion)\n\n## Quote(s) of the Day\n\n- \"Yeah, I'm only hearing positive reactions, I've got to shoot it down\"\n- \"Unsafer unsafeness\"\n- \"It's like a horror movie. It's terrifying, but you want to go see it, because it's also amazing.\"\n\n## Discussion\n\n### Unchampioned issue triage\n\n#### Track subtype exhaustiveness for classes with only private constructors\n\nhttps://github.com/dotnet/csharplang/issues/4032\n\nThis comes up often in the context of discriminated unions. It should be thought about when designing that feature. There are some potentially interesting\ncases in this with ref assemblies as well, since private constructors are normally dropped. Into the working set.\n\n#### ReadOnlySpan initialization from static data\n\nhttps://github.com/dotnet/csharplang/issues/5295\n\nWe like this idea. Into the working set.\n\n#### Embedded Language Indicators for raw string literals\n\nhttps://github.com/dotnet/csharplang/issues/6247\n\nWe intentionally left the door open for this proposal, but we'd like to design for more than just raw string literals. We're uncertain whether just multiline\nstrings provides a generalized-enough benefit beyond the existing comment format. Into the working set with this caveat.\n\n#### Implicit Parameters\n\nhttps://github.com/dotnet/csharplang/issues/6300\n\nThis community proposal is inspired by features from other languages, like implicit parameters in Scala 2. While we think the space is interesting, we think\nthere's several potential issues: first, Scala 2's implicit parameter support was not well received, and reworked as part of Scala 3. The way that binding\nworked in Scala 2 caused a number of understandability issues, and we don't want to repeat them in C#. Kotlin is also adding a similar feature, context receivers,\nand we'll be interested to see how it is received by that community. We're also not certain of how widely this would be adopted, especially in the BCL. Finally,\nthere is significant negative community sentiment on the issue. This will go into the backlog for now, pending further community requests.\n\n### Unsafer Unsafeness\n\nhttps://github.com/dotnet/csharplang/issues/6476\n\nWhile we're not a huge fan of this proposal as a general principle, we think it has merits. `unsafe` in C# is generally concerned with allowing users to express\npatterns that are _memory_ unsafe, and this proposal doesn't change that principle; it simply extends that memory unsafety to a new area. Importantly, users will\nhave a way to express these semantics, regardless of whether the language changes here, as `Unsafe` will still exist. This proposal ensures that for such code,\nusers will at least be warned, rather than silently getting no feedback whatsoever.\n\n#### Conclusion\n\nApproved for C# 11.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-09-26.md",
    "content": "# C# Language Design Meeting for September 26th, 2022\n\n## Agenda\n\n- [Working set triage](#working-set-triage)\n    - [Roles & Extensions](#roles--extensions)\n    - [Discriminated Unions](#discriminated-unions)\n    - [Bridging statements and expressions](#bridging-statements-and-expressions)\n    - [Construction improvements](#construction-improvements)\n    - [`ref struct` improvements](#ref-struct-improvements)\n    - [`params` improvements](#params-improvements)\n    - [Ungrouped](#ungrouped)\n\n## Quote of the day\n\n- *Makes a dad joke* \"We saw that look on your face.\"\n\n### Working set triage\n\nToday, we went through a significant portion of the current working set of items, and triaged them into a few categories:\n\n* Working group themes. We had good success with a smaller working group on `required` members, and we would like to extend the same\nstrategy to other larger items. For each such area, we'll create a working group to investigate all related issues.\n* Ungrouped features. These are generally smaller features or features with a relatively straightforward design that don't need large\namounts of design time to pursue.\n\nImportantly, we didn't get through everything in the working set today, so some of these categories are currently light. We'll finish our pass\nnext meeting.\n\n#### Roles & Extensions\n\nWe already have an internal working group for this topic, and they will be continuing to work on it. Related issues:\n\n* https://github.com/dotnet/csharplang/issues/110 - Type classes\n    * One of the motivating scenarios for roles\n* https://github.com/dotnet/csharplang/issues/5497 - Roles & Extensions\n\n\n#### Discriminated Unions\n\nThis is one of the biggest things that we think will benefit from a smaller group to make design progress. There are a number of\nareas to investigate, as demonstrated by the open related issues:\n\n* https://github.com/dotnet/csharplang/issues/113 - Discriminated unions\n* https://github.com/dotnet/csharplang/issues/485 - `closed` type hierarchies\n* https://github.com/dotnet/csharplang/issues/3179 - `closed` enums\n* https://github.com/dotnet/csharplang/issues/2926 - Target-typed name lookup\n    * We don't want to gate this on DUs, but it will be highly complementary\n\n#### Bridging statements and expressions\n\nWe think there are two main subcategories here: the general feature of block expressions, and more specific improvements and unification\nof switch statements and expressions. Related issues:\n\n* https://github.com/dotnet/csharplang/issues/377 - Sequence expressions\n* https://github.com/dotnet/csharplang/issues/3037 - Block-bodied switch expression arms\n* https://github.com/dotnet/csharplang/issues/3038 - Enhanced switch statements\n* https://github.com/dotnet/csharplang/issues/3086 - Expression blocks\n\n#### Construction improvements\n\nWe have a few issues related to general construction improvements, such as generalized support for factories, support for final initializers,\ngeneralized `with` support, and others. Related issues:\n\n* https://github.com/dotnet/csharplang/issues/162 - Pattern-based `with` expressions\n    * It is irksome, but do we have customers who really want it?\n    * Not sure we would spend time on this currently\n    * Moved to the backlog.\n\n#### `ref struct` improvements\n\nThere are three interrelated, major improvements that need to be done in parallel: `ref struct`s implementing interfaces, `ref struct`s in\ngenerics, and ref fields to ref structs\n\n* https://github.com/dotnet/csharplang/issues/1148 - `where T : ref struct`\n\n#### `params` improvements\n\nThis doesn't need a full group, just a single dev to investigate and bring back a list of all the things to support in `params`. The `Span<T>`\nis blocked on runtime support, but the other parts of the feature can proceed without waiting for it. Related issues:\n\n* https://github.com/dotnet/csharplang/issues/1757 - `params Span<T>`\n* https://github.com/dotnet/csharplang/issues/179 - `params IEnumerable`\n* https://github.com/dotnet/csharplang/discussions/6489 - Discussion on `params Span<T>`\n* https://github.com/dotnet/csharplang/discussions/6490 - Discussion on more `params` abilities\n* https://github.com/dotnet/csharplang/discussions/6491 - Discussion on pattern-based `params`\n\n#### Ungrouped\n\nFinally, these are the issues that we don't feel need a working group to drive them.\n\n* https://github.com/dotnet/csharplang/issues/133 - Property-scoped fields\n    * Still think it will be after `field`.\n    * Into the backlog, as we are currently focused on #140.\n* https://github.com/dotnet/csharplang/issues/140 - `field`\n    * Will proceed, try to get in for C# 12 after questions are resolved\n* https://github.com/dotnet/csharplang/issues/1358 - `default` in deconstruction\n    * Small and independent, but needs LDM input to proceed.\n* https://github.com/dotnet/csharplang/issues/2302 - Efficient `params` and string formatting\n    * Was split up into multiple issues, some of which are already done. Will close and link.\n* https://github.com/dotnet/csharplang/issues/2180 - Allow omitting unused parameters\n    * We don't think this is currently important. Will move to the backlog.\n* https://github.com/dotnet/csharplang/issues/2691 - Primary Constructors\n    * Still needs an agreed-upon proposal. We've been meaning to bring one for discussion.\n* https://github.com/dotnet/csharplang/issues/3507 - Ignored directive support\n    * Leaving as is\n* https://github.com/dotnet/csharplang/issues/3658 - Repeated Attributes in Partial Members\n    * We're unlikely to make progress on this ourselves, but would accept community contributions here. Moved to Any Time.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-09-28.md",
    "content": "# C# Language Design Meeting for September 28th, 2022\n\n## Agenda\n\n- [Working set triage](#working-set-triage)\n    - [Discriminated Unions](#discriminated-unions)\n    - [Collection literals](#collection-literals)\n    - [Nullability improvements](#nullability-improvements)\n    - [Ungrouped](#ungrouped)\n\n## Quote(s) of the Day\n\n- \"Instead of just skipping 13, we'll take a break for the whole year!\"\n- \"disjunctive junction, what's your function?\"\n- \"That's the sound of never\"\n- \"I do weird stuff in C#, and I've never wanted this\"\n\n## Discussion\n\n### Working set triage\n\nWe continue our triage from [last time](LDM-2022-09-26.md). For clarity on what we did today, the only issues listed below were actually covered today. We will update\nhttps://github.com/dotnet/csharplang/issues/4144 with the collated results when we are done with the triage.\n\n#### Discriminated Unions\n\n* https://github.com/dotnet/csharplang/issues/4032 - Track subtype exhaustiveness for classes with only private constructors\n    * Another one for the list\n\n#### Collection literals\n\n* https://github.com/dotnet/csharplang/issues/5354 - Collection literals\n    * Complex feature area that we think would benefit from a dedicated working group, even though there is only one issue in the group.\n        * It would be good to have some BCL representation as well.\n    * Could also be related to `init` methods as a method of implementation.\n\n#### Nullability improvements\n\nWe have some nullability issues that have been around for a few releases, and it would be good to turn the crank on nullability and make these pain points better.\n\n* https://github.com/dotnet/csharplang/issues/3950 - `Task<T>` nullability covariance\n    * One of the common complaints\n* https://github.com/dotnet/csharplang/issues/3951 - Nullable analysis of LINQ queries\n    * Another super common complaint\n    * Both LINQ as implemented in the BCL, and as done in 3rd-party libraries\n\n#### Ungrouped\n\nThe bulk of our meeting today covered smaller issues that are ungrouped.\n\n* https://github.com/dotnet/csharplang/issues/3885 - Support `readonly` modifier for classes and records\n    * We initially thought this might be an Any Time candidate, but discussion revealed it has some potential interactions with with `readonly` on interfaces.\n    * Backlog for now\n* https://github.com/dotnet/csharplang/issues/3980 - call local static functions in base constructor\n    * We're not going to make progress on this soon, but we think this is a good Any Time candidate.\n    * It still needs an accepted specification, but we think it should be relatively straightforward to define.\n* https://github.com/dotnet/csharplang/issues/3986 - `#pragma warning *enable*`\n    * This issue has been unchampioned by the current champion, and no one willing to step up and take it over.\n    * We think there could be potential bad performance interactions with the analyzer ecosystem.\n    * Moved to Likely Never.\n* https://github.com/dotnet/csharplang/issues/1502 - Five ideas for improving working with fixed buffers\n    * Most of these ideas are already implemented or broken out into separate issues.\n    * We will link the appropriate issues from this one and close it out.\n* https://github.com/dotnet/csharplang/issues/4018 - Permit variable declarations under disjunctive patterns\n    * There are still a few design decisions to make here, and it's been sitting on our docket for a while.\n    * C# 11 priorities have kept pushing it back.\n    * We hope to make progress in the near future.\n* https://github.com/dotnet/csharplang/issues/4024 - Direct constructor parameters\n    * This was a suggestion that arose as we were thinking about `record` types, but we're no longer interested in this approach.\n    * Moved to Likely Never.\n* https://github.com/dotnet/csharplang/issues/4121 - Metadata determination of whether a type is a record\n    * If we want to move towards records inheriting from non-records, then we need to think about this.\n    * Cross-inheritance is not currently in the working set, so this moves to backlog.\n* https://github.com/dotnet/csharplang/issues/4284 - using aliases for any types\n    * We still want this feature, and have a PR implementing the current design.\n    * There are a few design questions to resolve.\n    * We'll pursue this soon.\n* https://github.com/dotnet/csharplang/issues/4460 - Only Allow Lexical Keywords in the Language\n    * We've started down this path with the warning wave warning on lowercase type names, but we need to discuss this in more depth.\n    * Source generators are forcing our customers to deal with the pain of our choices, not just us, which is a more compelling reason than avoiding work for ourselves.\n* https://github.com/dotnet/csharplang/issues/4485 - async method exception filter\n    * The pain here is real, but we're not fans of this approach as the solution, as it's a narrow AOP solution.\n    * A smaller group will brainstorm other approaches, including whether a non-language solution would be possible.\n* https://github.com/dotnet/csharplang/issues/4748 - Directly invoked anonymous functions\n    * There is universal dislike of this feature on the LDM.\n    * Moved to Likely Never.\n* https://github.com/dotnet/csharplang/issues/5596 - Adding Index support to existing library types (redux)\n    * This needs BCL input on whether adding more overloads for Index/Range for these extra methods does not work.\n    * Backlog for now.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-10-05.md",
    "content": "# C# Language Design Meeting for October 5th, 2022\n\n## Agenda\n\n- [Review of `ref` fields](#review-of-ref-fields)\n    - [`RefSafetyRulesAttribute`](#refsafetyrulesattribute)\n    - [Return-only scope](#return-only-scope)\n\n## Quote(s) of the Day\n\n- \"We looked at that in 7.2 and said 'We can't imagine making that work in the compiler'\"\n- All the facial expressions various LDM members made as they wrapped their heads around the rules.\n\n## Discussion\n\nWe intend to post the slide deck that was shown to LDM at a later date, but it needs a few more revisions before posting.\n\n### Review of `ref` fields\n\nhttps://github.com/dotnet/csharplang/blob/main/proposals/low-level-struct-improvements.md\n\nThe `ref` fields feature has been going under significant and rapid revision as we approach the end of the C# 11 development cycle, based on\nfeedback from dogfooding the feature in (hopefully) its largest consumer, the BCL. RC1, however, had a few more internal and external partners\nintake the bits, see the breaking changes, and give us feedback on them. Today we wanted to go over the changes we've made in response to this\nlatest round of feedback. The team came with a [presentation](TODO) on the recent changes for us to go over today.\n\n#### `RefSafetyRulesAttribute`\n\nThis attribute will allow us to better recognize whether a module should be treated with the new ref safety rules, or with the pre-C# 11 safety\nrules. We did have some concerns about the particular format, but these were resolved through discussion:\n\n* This could be seen as a stamp of \"this module was compiled with language version X\", which isn't something we do today. However, we don't expect\nthe safety rules to increase every language version, so we don't expect that this will be a problem.\n* We also thought about using something other than an integer, in case we have a minor version that we want to rev the rules on. We don't think\nthis is likely, as we've moved away from minor releases at this point.\n* We thought about an analyzer to inform users about the breaking change on upgrading their assembly, this is tracked by\nhttps://github.com/dotnet/roslyn/issues/64344.\n\n#### Return-only scope\n\nIn response to breaking changes seen by customers with `ref` parameters, we added a new scope in between the method scope and the calling function\nscope: return-only. Something that is return-only is only allowed to escape by ref through a `ref`-return or an out parameter, and not through ref\nassignment to a `ref` parameter. The LDM members not steeped in the lingo of ref safety found this change particularly hard to understand, and the\nref fields group would like to brainstorm a bit on how to better explain the concept. Once the intuition was built, however, it was well-liked. In\nparticular, we are happy that constructors are no longer a special case, and just fall out of the new rules. We would like to see some improvement\nin the error messages the compiler gives, and that work is planned for VS 17.5.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-10-10.md",
    "content": "# C# Language Design Meeting for October 10th, 2022\n\n## Agenda\n\n- [Working set triage](#working-set-triage)\n    - [Static classes implementing interfaces](#static-classes-implementing-interfaces)\n    - [Null-conditional assignment](#null-conditional-assignment)\n    - [Lambda default parameters](#lambda-default-parameters)\n- [Working groups](#working-groups)\n- [`params` support for lambda default parameters](#params-support-for-lambda-default-parameters)\n    - [Conclusion](#conclusion)\n\n## Quote of the Day\n\n- \"Can we have multiple spread proposals and name them different things? Mayonnaise, Mustard?\" \"I can't believe it's not allocating\"\n\n## Discussion\n\n### Working set triage\n\nToday we wrapped up our triage of the working set. All of the remaining items are not in a working group.\n\n#### Static classes implementing interfaces\n\nhttps://github.com/dotnet/csharplang/issues/5783\n\nWe feel that there's about one design meeting's worth of open questions in this issue before we could reasonably let it be open for implementation,\neither from the compiler team or from the community, so we'll try to do that work at some point in the near future.\n\n#### Null-conditional assignment\n\nhttps://github.com/dotnet/csharplang/issues/6045\n\nThis one is fairly uncontroversial with little outstanding design work.\n\n#### Lambda default parameters\n\nhttps://github.com/dotnet/csharplang/issues/6051\n\nWork for this one is in progress, and later on in the meeting we talked about adding `params` support for this.\n\n### Working groups\n\nNow that we've gone through our working set, we've decided on the following working groups (listed in no particular order):\n\n* Roles and extensions\n* Collection literals\n* Nullability improvements\n* Discriminated unions\n* Bridging statements and expressions\n* Construction improvements\n* `ref struct` improvements\n* `params` improvements\n\nWe also decided on a set of norms for working groups to follow with respect to notes and keeping track of their progress: every working group\nwill add a folder under the [`meetings`](/meetings/) directory where they will put meeting notes. These notes will be anonymized, like LDM notes,\nbut are likely to be much rougher than dedicated LDM notes. We will not create dedicated discussions when posting these working group notes. Users\nthat want to comment on them can either comment on the issue for the group or create a discussion, as they choose. Working groups will each have\na leader, and that leader will be responsible for coordinating with the broader LDM on when things need to be brought back to the full group.\n\nSome statistics on the groups:\n\n* Smallest group size: 2 members\n* Largest group size: 10 members\n* Mean group size: 5.75 members\n* At current rate of working group increase (1 in 2021, 8 in 2022) we will have 64 working groups come October 2023.\n\n### `params` support for lambda default parameters\n\nhttps://github.com/dotnet/csharplang/issues/6051\n\nTo round out today, we discussed whether we should broaden the lambda default parameter work to include support for `params`, which sticks out\na bit for not being supported in the proposal today. While we don't have a direct use case, we think that if we want to make this change, we\nshould make it now as it is a breaking change for inferred delegate type scenarios when inferring from a method that has a `params` parameter.\nWe don't think that waiting for a use case would change the semantic design strategy here, as it needs to be consistent with the work already\napproved for default lambda parameters.\n\n#### Conclusion\n\nWe will add support for `params`, which will flow through the type system in the same way that default parameters do.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-10-12.md",
    "content": "# C# Language Design Meeting for October 12th, 2022\n\n## Agenda\n\n- [Keywordness of `field`](#keywordness-of-field)\n\n## Quote of the Day\n\n- \"You're muted\" \"Damn, I said it so well!\"\n\n## Discussion\n\n### Keywordness of `field`\n\nhttps://github.com/dotnet/csharplang/issues/140  \nhttps://github.com/dotnet/csharplang/issues/6530\n\nToday, we considered compiler implementation issues for semi-auto properties. The compiler has run into a few circularity issues during implementation which are proving tricky to work out, and\nwe wanted to revisit the decisions in LDM to see if there was an acceptable, easier option for implementation. After some initial discussion to understand the particular issue found here and\nbrainstorm other approaches to the problem, we came up with the following list of solutions:\n\n1. Make `field` a keyword\n    1b. Use a different keyword. Maybe something with two components to reduce chance of conflicts.\n2. Ignore scopes for determining if there's a `field`.\n    2b. Could we do a cheap bind of scopes and see if there's a `field` reference without a visible declaration?\n3. Add an introducer modifier\n4. Do more work in the compiler to implement the existing rules.\n5. Make an assumption when we're about to go into a cycle, and error if the assumption is broken later\n\nWe think 1 and 3 are too big of reimaginings for the feature as of right now: previous LDM work came to the current keyword and feature shape after a lot of investigation, and we don't think\nthat changing them up is warranted at this point, given that we don't think the engineering challenges are insurmountable. We also think option 5 will have unpredictable results: what assumptions\nthe compiler makes may end up feeling like implementation details that leak into the specification. This leaves us with options 2 and 4.\n\nFurther delving into option 2, we realized that it has many of the same problems as just keeping the original specification as is. All of the following scenarios should work with option 2, but\nwill still require the same engineering effort as 4:\n\n```cs\nclass C\n{\n    int Prop\n    {\n        get\n        {\n            var x = (field: 1, 2); // Tuple element named field, not a use of the field keyword\n            var y = new { field = 1 }; // Anonymous type property named field\n            var x = new Foo() { field = 1 }; // Regular type member named field\n            if (x is { field: 1 }) {} // Regular type member named field\n            return 1; // No usage of the field keyword, so a backing field should not be generated\n        }\n    }\n}\n```\n\nThis realization showed us that what we really need to do is to do the work in the compiler to determine if a `field` keyword is in an expression context, in a purely syntactic fashion. This will\nrequire some effort, but unless the effort comes back as being extremely challenging (forcing us to look at options 1 or 3), we'll proceed with option 4.\n\n#### Conclusion\n\nWe will continue pursuing the current work, and revisit if it proves to have a significant cost.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-10-17.md",
    "content": "# C# Language Design Meeting for October 17th, 2022\n\n## Agenda\n\n- [Primary Constructors](#primary-constructors)\n- [Permit variable declarations under disjunctive patterns](#permit-variable-declarations-under-disjunctive-patterns)\n\n## Quote of the Day\n\n- \"I'll do my darndest not to jinx in various ways... In the first hour we'll knock this out\"\n\n## Discussion\n\n### Primary Constructors\n\nhttps://github.com/dotnet/csharplang/issues/2691\n\nAs indicated [during triage](LDM-2022-09-26.md#ungrouped), the proposal for primary constructors has been updated with the latest thinking on the scenario,\nand we are now reviewing it. The new version uses capturing semantics for primary constructor parameters, and works for all types, not just records. In going\nover the proposal, we had a few comments:\n\n* [Last week](LDM-2022-10-12.md#keywordness-of-field), we talked about how knowing the backing fields of a type can be a problem for the compiler, and this\nproposal would introduce a similar concept. However, we think that this is solvable: `field` specifically needs to deal with backwards compatibility, while\nprimary constructors are all new. We can simply say that primary constructor parameters are _always_ treated as captures for these types of purposes, and the\nremoval of the parameters is an optimization strategy the compiler is free to use or not as it chooses.\n    * Interestingly, F# primary constructors will not optimize away the primary constructor parameters if the type is a struct to avoid similar circularity issues\n    when determining whether a type supports default values, and we may end up needing to do that in C#.\n* We're a little concerned about the potential for confusion when a field shadows a primary constructor parameter. For example:\n```cs\nclass C(int i)\n{\n    protected int i = i; // References parameter\n    public int I => i; // References field\n}\n```\n* We definitely feel that there at least needs to be a warning for the double-capture problem. It's fairly easy to accidentally code yourself into a hole here.\n* We need to think about how a `readonly` modifier on a `struct` will impact the primary constructor.\n* The `{ statements }` syntax as a primary constructor body is not particularly liked. There are two leading alternatives:\n    * `ClassName { }` - IE, just like a regular constructor, but minus the parentheses.\n    * `init { }` - More visually different from a constructor, which helps it stand out as being part of the primary constructor.\n\nOverall, we like the direction this proposal has taken, and would like to start playing with it. We're particularly interested in feedback on the double-capture\nissue, so a preview of the feature that users can try will help inform the capturing decision here.\n\n#### Conclusion\n\nWe will proceed with a prototype with the proposed semantics, and a warning for the double-capture problem.\n\n### Permit variable declarations under disjunctive patterns\n\nhttps://github.com/dotnet/csharplang/issues/4018\n\nWe took another look at updates to this proposal now that we have non-C# 11 time. The main thing we ended up debating was how \"exact\" should we make variable\nredeclaration need to be, as some edge cases can be hurt depending on our decisions. Some examples are:\n```cs\n// Example A\nif (e is C c || e is Wrapper { NullableReferenceTypeProp: var c }) { } // Should there be an error since `var` is `C?` here\n\n// Example B\nif (e is S s || e is Wrapper { NullableValueTypeProp: var s }) { } // Should there be an error since this is S vs Nullable<S>?\n\n// Example C\nif (e is C<(int a, int b)> c || e is Wrapper { Prop: var c }) { c.TupleProperty.a } // Is this ok? Where does the name a come from in the second example?\n\n// Example D\nif (e is Derived d) { d.DerivedMethod(); }\nelse if (e is Wrapper { BaseTypeProp: Base d }) { } // Should d be widened to `Base`? What happens to the above method access?\n```\n\nWe arrived at 4 possible options for the behavior:\n\n1. Types must exactly match.\n    1. Variant 1b: types must exactly match _except_ for top-level reference nullability. Nested reference nullability differences are subject to the same\n    nullability warnings as standard conversions.\n2. Types must be identity-convertible. This allows for tuple-name differences.\n3. We allow a special rule for `var`: `var` doesn't contribute type information when being unified across multiple declarations.\n4. We use best common type across all declarations, like ternaries.\n\nIn discussion, we started with 4. However, we were dissatisfied with the behavior of example D above with that rule, as it either means that a related `case` or\n`else if` can affect the meaning of the code inside the first `if` block, or it means that we need to introduce variables that change their type based on the\ncurrent execution flow. We felt that 3 wasn't particularly clear on the behavior, and 2 was potentially confusing: what if there are multiple sets of tuple names?\nHow should we decide which names to use? This was less strong, however, and we are open to allowing differences in the future. Ultimately, we felt that variant 1b\nis the best option, and we will look for user feedback to see if we should loosen the rules more.\n\n#### Conclusion\n\nVariant 1b of the rules accepted.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-10-19.md",
    "content": "# C# Language Design Meeting for October 19th, 2022\n\n## Agenda\n\n- [Open questions in list patterns on `IEnumerable`](#open-questions-in-list-patterns-on-ienumerable)\n    - [Allowing patterns after slices](#allowing-patterns-after-slices)\n    - [Allowing slicing to capture](#allowing-slicing-to-capture)\n\n## Quote of the Day\n\n- \"You should be able to criticize your own children.\" \"All your children are terrible\"\n\n## Discussion\n\n### Open questions in list patterns on `IEnumerable`\n\nhttps://github.com/dotnet/csharplang/issues/6574  \nhttps://github.com/dotnet/csharplang/pull/6365\n\nToday, we took a look at the list patterns on `IEnumerable` proposal, and looked through a few open questions on the topic.\n\n#### Allowing patterns after slices\n\nThe first open question is whether we should allow patterns to follow a slice, such as `enumerable is [1, 2, .., 3]`. There's a few main concerns with allowing this: it will\nsignificantly complicate the implementation of the emitted code, it could be a potential footgun for infinite `IEnumerable` scenarios, and, depending on implementation strategy,\nit could actually perform _worse_ than equivalent LINQ code would, as LINQ does typechecks for underlying types and uses indexing when possible. For the first point, we're not\noverly concerned: the user would have to write equivalent code, and has more opportunity to introduce bugs when doing so, whereas a generalized and tested compiler solution is\nlikely more robust. The second problem we're also somewhat okay with: the footgun has existed since .NET 1.0, with `IEnumerable` and `foreach`. New places things can be enumerated\ncontinue to have this footgun, but it's always the same one.\n\nThe last concern though, that using a list pattern might be less efficient than using LINQ, is a big one. We're okay with the infinite enumerable issue, but we don't want patterns\nto be avoided because they're seen as the least-efficient way to implement a check. We should be able to optimize these checks for when the underlying `IEnumerable` _doesn't_ need\nto be fully enumerated to retrieve individual elements. We were planning on implementing a helper for doing these enumerations, and we should work with the BCL team to ensure that\nit is as efficient as it can be. For example, LINQ has internal interfaces that it uses to back queries depending on whether the original enumerable was list-like, and it would be\ngood to have list patterns be able to take advantage of the same optimizations that Select or IndexOf can.\n\n##### Conclusion\n\nWe're okay with restricting patterns after slices for now, but we should plan on having them eventually, and work with the BCL team to put a helper (type or set of methods) into the\nstandard libraries that list patterns can use for being as efficient as possible without tying the language to implementation details of specific frameworks.\n\n#### Allowing slicing to capture\n\nFinally, we looked briefly at whether or not a slice pattern on an `IEnumerable` should be able to capture the sliced section. One concern with this is that it would violate the\nstandard way we do slicing: a `Slice` method should return an instance of the same type it was called on. Slicing an array returns an array, slicing a Span returns a Span, etc. But\nwe couldn't do that here, as the underlying `IEnumerable` could be anything. It would also be weird if we allowed this when we don't allow slicing to capture for any list pattern:\nwe only allow slicing for types that are countable, indexable, _and_ sliceable. We think that, after we work through a helper type to address the first point, we might be in a better\nposition to determine whether we should generally expand slicing support to all list patterns, or whether we don't think that should be generally supported in any non-sliceable\ninput context.\n\n##### Conclusion\n\nWe'll revisit after the helper type is designed and we have a better idea on efficiency.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-10-26.md",
    "content": "# C# Language Design Meeting for October 26th, 2022\n\n## Agenda\n\n- [Null-conditional assignment](#null-conditional-assignment)\n\n## Quote of the Day\n\n- \"Can you see this word I've highlighted?\" \"3..., 4..., 5..., 6..., 7..., 8..., 9..., 10..., 11..., 12..., 13..., 14..., 15! 15 second delay in the video\"\n\n## Discussion\n\n### Null-conditional assignment\n\nhttps://github.com/dotnet/csharplang/issues/6045\n\nToday we took a complete look at the proposal for null-conditional assignment. Overall, there were two points of concern with the feature:\n\n1. Is the intuition around what `a?.b = c();` actually does at runtime good? Most of the LDT was in agreement what the semantics of this would be without\n   discussion, which is a good sign. However, a few members did say that their first read was that `c()` would be executed regardless of whether `a` was null.\n   We think this is very similar to the reaction to `?.` in C#, where many found the behavior intuitive, but a few users had to learn. We're therefore ok with\n   the intuition of the behavior of this feature.\n2. We took a look at nested scenarios, such as `a?.b = c?.d = e?.f;`, and thought about whether the semantics would be confusing. There are a few possible\n   results from this nested assignment:\n    1. If `a` is `null`, nothing else will be evaluated.\n    2. If `a` is non-`null` and `c` is `null`, `a.b` will be assigned `null` and `e?.f` will not be evaluated.\n    3. If `a` and `c` are non-`null`, `e?.f` will be evaluated and the result will be assigned to `c.d` and `a.b`.\n\n   While we think this syntax form is probably not a good one, and we won't encourage users to use it, we think that it's a natural consequence of the way our\n   grammar works, and don't see any good reason to forbid it.\n\n#### Conclusion\n\nThe design is approved as is.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-11-02.md",
    "content": "# C# Language Design Meeting for November 2nd, 2022\n\n## Agenda\n\n- [Partial Properties](#partial-properties)\n- [Default parameter values in lambdas](#default-parameter-values-in-lambdas)\n\n## Quote of the Day\n\n- \"If only there was a way that could be the quote of the day without incriminating someone.\" \"I'm trying to make my jokes unquotable.\"\n\n## Discussion\n\n### Partial Properties\n\nhttps://github.com/dotnet/csharplang/issues/6420\n\nWe started today by going through the partial properties proposal in detail, and trying to address the open questions in the proposal. As part of the motivation,\nwe took a quick look at how popular the field-based approach to property generation is: CommunityToolkit.Mvvm, which added an INPC generator based on fields in\nversion 8.0.0, has over 159,000 downloads as of these notes, 50,000 more than the previous major version of the library. They've also started using diagnostic\nsuppressors to allow property-based attributes to be put on fields, suppressing the warnings about incorrect attribute targets and copying those attributes over\nto the implementation of the property. We don't think this is great: it's working around the language, rather than with the language, and we'd like to address it.\n\nWe considered whether we should support implementations being full auto-properties. There are some uses case for this: for example, the regex generator might want\nto be able to say `public Regex Prop { get; } = ...;` in the generated file. And, language-wise, the issues with allowing this are fairly minimal. However, we think\nthat there's a decent number of tooling and experience issues with it, as the tooling will need to pick a version to consider the declaration, and no matter what we\ndo it will likely feel arbitrary. With semi-auto properties the workaround is not hard either: it's just `public Regex Prop { get => field; } = ...;`. Given this,\nwe'll stick with the restriction that the implementation part cannot be a fully auto-property.\n\nWe looked at the open question on expanding the feature to cover indexers. We think this is a reasonable expansion: it raises no new questions, has fairly minimal\nimpacts on the implementation, and keeps the language regular. It does mean that we have only one non-field member type that can't be partial now: `event`s. We\nthink extending the feature to events goes a bit farther than we'd like for now. We've had no requests for the expansion, and adding it would bring a number of new\nquestions on field-like events, what to allow/disallow, and others that we're not ready to answer at this time.\n\nFinally, we think that while we're doing `partial` properties, there is opportunity to clean up some `partial` papercuts, such as modifier ordering. We will make\na list of these papercuts and bring them to a future LDM for consideration.\n\n#### Conclusion\n\nFeature is approved as specified, indexers will be included.\n\n### Default parameter values in lambdas\n\nhttps://github.com/dotnet/csharplang/issues/6051  \nhttps://github.com/dotnet/csharplang/issues/6651\n\nFinally today, we have a question that arose from implementation, around whether lambda default parameters can affect the existence of a conversion. We're a bit\nconcerned by the behavior as specified, as it means that changing a parameter default value will have an impact on overload resolution. We're not OK with this\nimpact, and want to revise the rules here to avoid that. After some discussion, we came to the conclusion that the conversion from lambda to delegate type should\nalways exist, regardless of `params`/default parameter value differences. We then considered whether those differences should cause a warning or an error later in\nthe pipeline, _after_ overload resolution. We're mostly in favor of a warning here, as the code the code is unambiguous in meaning, if not anything we expect to be\nwritten outside of compiler unit tests. We also think that, for method group conversions, we should not warn at all.\n\n#### Conclusion\n\nThe existence of conversions from lambdas to delegate types will be unaffected by `params` or default parameter values. Differences in those will cause a warning\nlater in the pipeline. Lambdas that do not have `params`/default parameter values will not warn when converted to delegate types with them. We will not warn for\nmethod group conversions that differ by `params` or default parameter values.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-11-30.md",
    "content": "# C# Language Design Meeting for November 30th, 2022\n\n## Agenda\n\n- [Revise `MemberNotNull` for `required`](#revise-membernotnull-for-required)\n- [`params Span<T>`](#params-spant)\n\n## Quote of the Day\n\n- \"I understand I'm broken.\"\n\n## Discussion\n\n### Revise `MemberNotNull` for `required`\n\nhttps://github.com/dotnet/csharplang/issues/6754  \nhttps://github.com/dotnet/csharplang/issues/3630\n\nToday we considered a revision to `required` members, part of the recently-shipped C# 11, before the current behavior gets too broadly used for us to\nmake changes without a language version bump. Specifically, we looked at whether we can use `MemberNotNullAttribute`s on member declarations to inform\nnullability error suppression for fields initialized by required properties. While we do think this will become less of an issue with future language\nversions that take up the `field` feature, we think this is a good workaround for the moment. It uses `MemberNotNullAttribute` as a linking mechanism,\nwhich was the intended purpose of the attribute, and we're in favor of making the change now while we still can.\n\n#### Conclusion\n\nProposed change is accepted, targeted at 7.0.200.\n\n### `params Span<T>`\n\nhttps://github.com/dotnet/csharplang/issues/1757  \nhttps://github.com/dotnet/csharplang/blob/6ab4bbf1ec5183c65ad63887b8ec9e73ca0aab67/proposals/params-span.md\n\nThe params improvements working group has come back from their initial investigations with some initial work. Of the potential work, they looked at\n`params ReadOnlySpan<T>` as the most interesting thing on the plate, as it makes for real performance improvements, while other ergonomic benefits\nwill potentially be addressed by collection literals. The performance benefits here are mainly targeted at new APIs, as existing APIs (such as\n`Console.WriteLine`) have already manually optimized these cases by introducing a number of overloads, each taking another argument, until finally\nleaving a last `params` API. While these APIs would likely still take advantage of them (the runtime is tracking what APIs will want to use the\nfeature in [this issue](https://github.com/dotnet/runtime/issues/77873)), the main improvement will be in new APIs that don't need to write so many\noverloads in the first place. Some questions we raised during discussion:\n\n* Why do we want to support `UnscopedAttribute` on `params`? We don't think this is a real scenario, and it adds significant complexity to the rules.\n* We need to make sure that our adjustments to Better Function Member aren't introducing any new ambiguities. We don't think they are at first look,\n  but this area often has hidden breaks so we need to make sure.\n* We spent a lot of time talking about the proposed strategy of always allocating on the stack. There was particular concern with how this interacts\n  with another major part of the feature: introducing `params ReadOnlySpan<T>` parameters and recompiling will prefer the span overload. For callsites\n  with large numbers of params parameters this could end up causing `StackOverflowExceptions`. There are a few possible mitigations:\n    * The runtime can introduce a side-stack for these allocations, so params backing storage is still on a stack, just a different stack.\n    * We could (and probably should) make the wording here much looser, allowing the compiler more latitude in choosing what to do here.\n    * This would then allow the compiler to call a runtime helper to make the decision, as different platforms have different stack sizes and that\n      would influence what they would want to be allocated where.\n    * Should users be able to turn off the feature at the compilation-level such that backing arrays are always heap allocated? This would give a good\n      way for users to test to see if the feature is causing issues for them.\n    * Ultimately we decided that we should lean on the runtime to make allocation location decisions, and we can look at a global switch if we end up\n      seeing problems in preview/release.\n\n#### Conclusion\n\nFeature is good to proceed to implementation.\n"
  },
  {
    "path": "meetings/2022/LDM-2022-12-14.md",
    "content": "# C# Language Design Meeting for December 14th, 2022\n\n## Agenda\n\n- [Breaking change for raw string literals](#breaking-change-for-raw-string-literals)\n- [Program as internal by default](#program-as-internal-by-default)\n\n## Quote of the Day\n\n- \"Give everyone the ability to quickly filibuster it\"\n\n## Discussion\n\n### Breaking change for raw string literals\n\nhttps://github.com/dotnet/roslyn/pull/65973\n\nAn email discussion approved this change. No significant concerns were raised in LDM or on email.\n\n### Program as internal by default\n\nhttps://github.com/dotnet/csharplang/issues/6769\n\nToday we revisited the defaults for top-level statements, looking at scenarios that are impacted by our [original decision](../2021/LDM-2021-07-12.md#speakable-names-for-top-level-statements).\nSome friction has been encountered because of this, particularly in scenarios around testing, and we are generally interested in addressing the scenario in some fashion. There is, however, some\ndebate on the best way to address these scenarios; language changes are big hammers, and we intentionally left knobs in the language (other partial declarations) to address concerns with the\ndefault accessibility of the `Program` type. There are visceral reactions to the statement \"Make this API public for testing\", as program authors generally want to be intentional with their\npublic surface area. This is true for executables too, as executables can be referenced by other programs. Given this, we will take the proposal back for more design, and perhaps find a\nsolution in tooling for the problem, rather than changing the language here.\n\n#### Conclusion\n\nProposal will be revisited after more design work (which may decide on a non-language solution to the problem).\n"
  },
  {
    "path": "meetings/2022/README.md",
    "content": "# C# Language Design Notes for 2022\n\nOverview of meetings and agendas for 2022\n\n## Wed Dec 14, 2022\n\n[C# Language Design Meeting for December 14th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-12-14.md)\n\n- Breaking change for raw string literals\n- Program as internal by default\n\n## Wed Nov 30, 2022\n\n[C# Language Design Meeting for November 30th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-11-30.md)\n\n- Revise `MemberNotNull` for `required`\n- `params Span<T>`\n\n## Wed Nov 2, 2022\n\n[C# Language Design Meeting for November 2nd, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-11-02.md)\n\n- Partial Properties\n- Default parameter values in lambdas\n\n## Wed Oct 26, 2022\n\n[C# Language Design Meeting for October 26th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-10-26.md)\n\n- Null-conditional assignment\n\n## Wed Oct 19, 2022\n\n[C# Language Design Meeting for October 19th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-10-19.md)\n\n- Open questions in list patterns on `IEnumerable`\n    - Allowing patterns after slices\n    - Allowing slicing to capture\n\n## Mon Oct 17, 2022\n\n[C# Language Design Meeting for October 17th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-10-17.md)\n\n- Primary Constructors\n- Permit variable declarations under disjunctive patterns\n\n## Wed Oct 12, 2022\n\n[C# Language Design Meeting for October 12th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-10-12.md)\n\n- Keywordness of `field`\n\n## Mon Oct 10, 2022\n\n[C# Language Design Meeting for October 10th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-10-10.md)\n\n- Working set triage\n    - Static classes implementing interfaces\n    - Null-conditional assignment\n    - Lambda default parameters\n- Working groups\n- `params` support for lambda default parameters\n    - Conclusion\n\n## Wed Oct 5, 2022\n\n[C# Language Design Meeting for October 5th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-10-05.md)\n\n- Review of `ref` fields\n    - `RefSafetyRulesAttribute`\n    - Return-only scope\n\n## Wed Sep 28, 2022\n\n[C# Language Design Meeting for September 28th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-09-28.md)\n\n- Working set triage\n    - Discriminated Unions\n    - Collection literals\n    - Nullability improvements\n    - Ungrouped\n\n## Mon Sep 26, 2022\n\n[C# Language Design Meeting for September 26th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-09-26.md)\n\n- Working set triage\n    - Roles & Extensions\n    - Discriminated Unions\n    - Bridging statements and expressions\n    - Construction improvements\n    - `ref struct` improvements\n    - `params` improvements\n    - Ungrouped\n\n## Wed Sep 21, 2022\n\n[C# Language Design Meeting for September 21st, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-09-21.md)\n\n- Unchampioned issue triage\n    - Track subtype exhaustiveness for classes with only private constructors\n    - ReadOnlySpan initialization from static data\n    - Embedded Language Indicators for raw string literals\n    - Implicit Parameters\n- Unsafer Unsafeness\n    - Conclusion\n\n## Wed Aug 31, 2022\n\n[C# Language Design Meeting for August 31st, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-08-31.md)\n\n1. Short term work triage\n    1. Partial properties\n    2. Using aliases for any type\n    3. Null-conditional assignment\n    4. `await?`\n    5. `params IEnumerable`\n    6. Discriminated Unions\n    7. Roles\n    8. `pragma warning enable`\n    9. Ignored directives support\n    10. Primary constructors\n    11. Switch expression as a statement\n\n## Wed Aug 24, 2022\n\n[C# Language Design Meeting for August 24th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-08-24.md)\n\n1. C# feature triage\n\n## Wed Aug 10, 2022\n\n[C# Language Design Meeting for August 10th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-08-10.md)\n\n1. `required` property default nullability\n\n## Wed Aug 3, 2022\n\n[C# Language Design Meeting for August 3rd, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-08-03.md)\n\n1. `ref` fields specification updates\n\n## Wed Jul 27, 2022\n\n[C# Language Design Meeting for July 27th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-07-27.md)\n\n1. `scoped` for local declarations\n\n## Wed Jul 13, 2022\n\n[C# Language Design Meeting for July 13th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-07-13.md)\n\n1. Lambda default parameters\n\n## Jun 29, 2022\n\n[C# Language Design Meeting for June 29th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-06-29.md)\n\n- UTF-8 literal concatenation operator\n\n## Jun 6, 2022\n\n[C# Language Design Meeting for June 6, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-06-06.md)\n\n1. Open issues for `ref` fields\n2. Open issues for static virtual members\n3. Concatenation of Utf8 literals\n\n## May 23, 2022\n\n[C# Language Design Meeting for May 23rd, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-05-23.md)\n\n1. Open issues for `ref` fields\n\n## May 11, 2022\n\n[C# Language Design Meeting for May 11th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-05-11.md)\n\n1. Inconsistency around accessibility checks for interface implementations\n2. `ref readonly` method parameters\n3. Pattern matching with UTF-8 String Literals\n\n## May 9, 2022\n\n[C# Language Design Meeting for May 9th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-05-09.md)\n\n1. Numeric IntPtr\n2. Ref readonly parameters\n\n## May 2, 2022\n\n[C# Language Design Meeting for May 2nd, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-05-02.md)\n\n- Effect of `SetsRequiredMembers` on nullable analysis\n- `field` questions\n    - Partial overrides of virtual properties\n    - Definite assignment of manually implemented setters\n\n## Apr 27, 2022\n\n[C# Language Design Meeting for April 27th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-04-27.md)\n\n- Default parameter values in lambdas\n- Null-conditional assignment\n\n## Apr 25, 2022\n\n[C# Language Design Meeting for April 25th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-04-25.md)\n\n- `ref readonly` method parameters\n- Inconsistencies around accessibility checks for interface implementations\n\n## Apr 18, 2022\n\n[C# Language Design Meeting for April 18th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-04-18.md)\n\n1. Issues with Utf8 string literals\n2. Ref and ref struct scoping modifiers\n\n## Apr 13, 2022\n\n[C# Language Design Meeting for April 13th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-04-13.md)\n\n1. Parameter null checking\n2. File-scoped types\n\n## Apr 11, 2022\n\n[C# Language Design Meeting for April 11th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-04-11.md)\n\n1. Relax restrictions on braces on raw interpolated strings\n2. Self-type stopgap attribute\n\n## Apr 6, 2022\n\n[C# Language Design Meeting for April 6th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-04-06.md)\n\n1. Unresolved questions for static virtual members\n2. Parameter null checking\n\n## Mar 30, 2022\n\n[C# Language Design Meeting for March 30th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-03-30.md)\n\n1. Definite assignment in struct constructors calling `: this()`\n2. `file private` accessibility\n\n## Mar 28, 2022\n\n[C# Language Design Meeting for March 28th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-03-28.md)\n\n1. Variable declarations under disjunctive patterns\n2. Type hole in static abstracts\n3. Self types\n\n## Mar 23, 2022\n\n[C# Language Design Meeting for March 23rd, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-03-23.md)\n\n1. Open questions in required members\n    1. Emitting `SetsRequiredMembers` for record copy constructors\n    2. Should `SetsRequiredMembers` suppress errors?\n    3. Unsettable members\n    4. Ref returning properties\n    5. Obsolete members\n\n## Mar 21, 2022\n\n[C# Language Design Meeting for March 21st, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-03-21.md)\n\n1. file private visibility\n2. Open question in semi-auto properties\n3. Open question in required members\n\n## Mar 14, 2022\n\n[C# Language Design Meeting for March 14th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-03-14.md)\n\n1. file private visibility\n\n## Mar 9, 2022\n\n[C# Language Design Meeting for March 9th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-03-09.md)\n\n1. Ambiguity of `..` in collection expressions\n2. `main` attributes\n3. `nameof(param)`\n\n## Mar 7, 2022\n\n- Design review. No published notes.\n\n## Mar 2, 2022\n\n[C# Language Design Meeting for March 2nd, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-03-02.md)\n\n1. Open questions in `field`\n    1. Initializers\n    2. Property assignment in structs\n\n## Feb 28, 2022\n\n[C# Language Design Meeting for February 28th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-28.md)\n\n1. Ref fields\n    1. Encoding strategy\n    2. Keywords vs Attributes\n    3. Breaking existing lifetime rules\n\n## Feb 23, 2022\n\n[C# Language Design Meeting for February 23rd, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-23.md)\n\n1. Pattern matching over `Span<char>`\n2. Checked operators\n\n## Feb 16, 2022\n\n[C# Language Design Meeting for February 16th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-16.md)\n\n1. Open questions in `field`\n2. Triage\n    1. User-defined positional patterns\n    2. Delegate type arguments improvements\n    3. Practical existential types for interfaces\n    4. Static abstract interfaces and static classes\n\n## Feb 14, 2022\n\n[C# Language Design Meeting for February 14th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-14.md)\n\n1. Definite assignment in structs\n2. Checked operators\n\n## Feb 9, 2022\n\n[C# Language Design Meeting for February 9th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md)\n\n1. Continue discussion of checked user-defined operators\n2. Review proposal for unsigned right shift operator\n3. Review proposal for relaxing shift operator requirements\n4. Triage champion features\n\n## Feb 7, 2022\n\n[C# Language Design Meeting for February 7th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-07.md)\n\n1. Checked user-defined operators\n\n## Jan 26, 2022\n\n[C# Language Design Notes for January 26th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md)\n\n1. Open questions in UTF-8 string literals\n\n## Jan 24, 2022\n\n[C# Language Design Notes for January 24th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-24.md)\n\n1. Required members metadata representation\n2. Default implementations of abstract statics\n3. Triage\n    1. Nested members in with and object creation\n    2. Binary Compat Only\n    3. Attribute for passing caller identity implicitly\n    4. Attributes on Main for top level programs\n\n## Jan 12, 2022\n\n[C# Language Design Notes for January 12th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-12.md)\n\n1. Open questions for `field`\n    1. Initializers for semi-auto properties\n    2. Definite assignment for struct types\n2. Generic Math Operator Enhancements\n\n## Jan 5, 2022\n\n[C# Language Design Notes for January 5th, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-05.md)\n\n1. Required Members\n\n## Jan 3, 2022\n\n[C# Language Design Notes for January 3rd, 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-03.md)\n\n1. Slicing assumptions in list patterns, revisited\n2. Parameterless struct constructors, revisited\n"
  },
  {
    "path": "meetings/2023/LDM-2023-01-09.md",
    "content": "# C# Language Design Meeting for January 9th, 2023\n\n## Agenda\n\n- [Working group re-evaluation](#working-group-re-evaluation)\n\n## Quote of the Day\n\n- \"Different variations of crazy come together to make a whole sane person.\"\n\n## Discussion\n\n### Working group re-evaluation\n\nWe've had a few months with working groups, and think now is a good time to do a small retrospective on whether the strategy is working well for us.\nOne concern that we have is that team members are feeling overloaded on working groups. Several members felt a good amount of FOMO (fear of missing\nout) during the sign up process, expecting that all the interesting discussions would occur in the working group, rather than at the LDM. This has lead\nto the working groups not actually being able to get anything done and taking up more development time that was intended. Some of the working groups\nhave also met a bit too often, when there wasn't enough driving interest. Working groups are creative effort, and trying to force creative effort when\nthere isn't enough enthusiasm doesn't accomplish anything. We've settled on some changes in our process to help the groups be more nimble:\n\n1. Reduce group memberships. While we're not putting constraints on minimum or maximum memberships, LDT members should aim to reduce their workload\n   with the number of groups they join. Group membership should not be a passive topic where you just listen in: it should be an active participant\n   effort.\n2. Working groups should bring their progress to the full LDM more often. A significant driver of the over-subscription was FOMO, but the working groups\n   weren't intended to replace the full LDM discussions on topics. Proposals will still be debated in full with the full LDM, and more frequent check-ins\n   will help make sure that the proposals are still a product of the entire group. While the working group can delve into spaces and form opinions,\n   authority is still with the LDM for the final shape of proposals.\n3. Reduce meeting frequency. Most groups went out and scheduled recurring meetings every week. This was too often for most groups, and resulted in\n   overburdening the group leaders who needed to establish topics and record notes. Teams should meet as often as makes sense for the team: if there's\n   been no progress on an idea, we shouldn't try to force the creative process. As part of this, some groups may stop meeting altogether, and that's ok.\n\nWe hope this set of changes will enable the working groups to be more effective, and make sure that LDT members have enough time to contribute to working\ngroups while continuing to work on their regular teams.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-01-11.md",
    "content": "# C# Language Design Meeting for January 11th, 2023\n\n## Agenda\n\n- [`using` aliases for any types](#using-aliases-for-any-types)\n    - [Pointer types in aliases](#pointer-types-in-aliases)\n    - [Reference nullability in aliases](#reference-nullability-in-aliases)\n    - [Value nullability in aliases](#value-nullability-in-aliases)\n\n## Quote of the Day\n\n- \"It feels like someone is going to write a blog post about this.\"\n\n## Discussion\n\n### `using` aliases for any types\n\nhttps://github.com/dotnet/csharplang/issues/4284\n\nToday, we took a look at expanded `using` aliases, and open questions in the area. The LDM is generally in favor of the topic, but there are a few questions\nto resolve around specific areas of the proposal.\n\n#### Pointer types in aliases\n\nFirst, we looked at pointer types in using aliases. We've heard from function pointer users, since before the first preview was publicly released, that they\nwould love to be able to `using` alias long function pointer types. This raises an interesting question: where are unsafety errors reported for such types?\nWe don't have a `using unsafe` today, so would we want to introduce that? Or would we want to check at the use-site, and not give any warning or error in the\n`using` itself? We enumerated a few options:\n\n1. Don't allow pointer types in `using` aliases, even with #4284 implemented.\n2. Allow pointer types in `using` aliases, but introduce `using unsafe` and require it be present.\n3. Always allow pointer types in `using` aliases, and check for unsafety at the use site.\n\nAn initial read was nearly unanimously in favor of 3, but further discussion revealed key concern: An unused `using` alias might never be checked for pointer\ntypes, even if the project doesn't have `unsafe` turned on. This felt dangerous and likely to become an odd C# quirk that we would end up regretting. There\nwas also some preference that we ensure that any pointer type syntactic usage is explicitly tied to `unsafe` in some fashion. We also think that `using unsafe`\nwill actually be easier to implement, as it will avoid some circularity issues that we'd otherwise need to be concerned about.\n\nGiven these concerns, we are planning to go with option 2, and potentially relax during preview or in a future version of C# based on user feedback.\n\n##### Conclusion\n\nOption 2, potentially relaxing in the future based on user feedback.\n\n#### Reference nullability in aliases\n\nNext, we turned our attention to reference type nullability in aliases. Nested nullability is already allowed: `using MyList = List<string?>;`, for example.\nHowever, should we allow `using NullableString = string?;`? There are some good reasons not to:\n\n1. Complicates implementation and conceptual load by forcing us to guard against `?` on nullable aliases.\n2. Usage in pattern matching is broken. These aliases couldn't be used directly, and `{ }` patterns would need to fall to the underlying type.\n    1. This might further change in `#nullable disable`d contexts.\n3. Display in quick info might change with nullable flow states: when an expression has been analyzed to be not null, it could require falling back to the\n   non-aliased underlying type, which we think is unexpected behavior. This behavior would also vary between `#nullable` contexts.\n\n##### Conclusion\n\nTop-level nullability cannot be specified in `using` aliases.\n\n#### Value nullability in aliases\n\nToday, `using NullableInt = Nullable<System.Int32>;` is legal. However, given our previous decision, do we want to also forbid `using NullableInt = int?;`,\nand require users to continue using `Nullable<T>` for such locations? After some discussion, we think this is different than the previous point: `string?` and\n`string` are the same runtime type, while `int` and `int?` are actually different runtime types; there is no difference in behavior around `#nullable`\ncontexts like there is for reference types.\n\n##### Conclusion\n\nAllowed.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-01-18.md",
    "content": "# C# Language Design Meeting for January 18th, 2023\n\n## Agenda\n\n- [Nullable post-conditions and `async`/`await`](#nullable-post-conditions-and-asyncawait)\n- [Semi-colon bodies for type declarations](#semi-colon-bodies-for-type-declarations)\n\n## Quote of the Day\n\n- \"I guess if I want to stay consistent with myself and not be a hypocrite for the third time today.\" \"You're counting the times?\" \"Yeah... I don't want to go for the hat trick.\"\n\n## Discussion\n\n### Nullable post-conditions and `async`/`await`\n\nhttps://github.com/dotnet/csharplang/issues/6888\n\nWe took a look at a proposal around enhancing nullable support for `async` methods that return `Task`-like types, as existing nullability attributes are often incorrectly\napplied for this type of method. There are some immediate concerns that come to mind:\n\n1. There are a lot of methods that defer awaiting a `Task` or `Task`-like type until after the returned thing. For example, `ConfigureAwait`, `ValueTask.AsTask`, `Task.WhenAll`,\n   user libraries to add awaiters to `ValueTuple`s of tasks, etc. We could special case the BCL methods in the compiler, but that is a lot of special cases and wouldn't help\n   any user-defined `Task`-like types or methods.\n2. Some post-condition attributes, such as `NotNull` on parameters, might be checked up front by the method, before it hits an `await`, and be perfectly fine today (particularly\n   since `async` methods cannot have `ref` parameters). The proposal currently suggests changing this, but that doesn't seem generally correct.\n3. We don't have a good way to know whether a method is `async` today, so we can only use a broad heuristic to determine whether to apply `MemberNotNull` and other attributes\n   before or after `await`ing the result. Further, whether or not a method is `async` isn't quite the heuristic we're looking for: what we're actually looking for is whether\n   or not the returned `Task`-like type needs to be `await`ed before the nullability conditions are propagated. For example, a helper method to fill in common parameters and\n   otherwise pass through a call to another member is very possibly not marked as `async`, but should have the same behavior as the `async` method it's proxying.\n\nAnother spitballed proposal gained a bit of traction as we were discussing the above 3 points: adding a new `RequireAwait` property to our nullability attributes, with some\nappropriate defaults, and using that to propagate information on nullability. This has some advantages in being very precise, and likely being easy to guide users towards\n(the warning for `await`ing without fulfilling a `MemberNotNull` could mention setting that property, for example, or if a user sets that property and doesn't need to we\ncould warn), and not requiring significant new amounts of metadata to put on every `async` method to mark it as such.\n\n#### Conclusion\n\nThis will go back to the working group for now to continue iterating on the above idea and address the other contention points.\n\n### Semi-colon bodies for type declarations\n\nhttps://github.com/dotnet/csharplang/discussions/6871\n\nThere was some initial confusion on this discussion, as the current implementation actually missed the quoted line in the spec forbidding `;` on non-`record` types. Further,\nwe realized that the spec, as written today, is actually a breaking change; it would make the following code illegal:\n\n```cs\nrecord R1; // Legal today\n```\n\nWe think there are potential cases where the `;` body would be useful, mainly in `partial` types that have generated implementations. There are some potential concerns with\nfuture interference on top-level statements, as we may someday allow statements to follow type declarations. That would change `class C; {}` from a guaranteed error to\npotentially introducing top-level statements in the file, likely causing confusing compilation errors. However, we trust ourselves to handle this when the time comes.\n\nWe also considered the two other declaration types that currently do not permit `;` bodies: `interface`s, and `enum`s. `interface`s have similar justification to `class`es\nand `struct`s, where a `partial` interface could add new attributes and generate the rest. `enum`s are not allowed to be `partial` today, so it is unlikely to get much use,\nbut at the same time we don't see a good reason to leave the syntax inconsistent and special case `enum`s here where no other `type` declaration is.\n\n#### Conclusion\n\nAllow semicolon bodies for all type declarations.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-02-01.md",
    "content": "# C# Language Design Meeting for February 1st, 2023\n\n## Agenda\n\n- [Position of `unsafe` in aliases](#position-of-unsafe-in-aliases)\n- [Roles and extensions](#roles-and-extensions)\n\n## Discussion\n\n### Position of `unsafe` in aliases\n\nhttps://github.com/dotnet/csharplang/blob/main/proposals/using-alias-types.md#supporting-aliases-to-types-containing-pointers\n\nAs part of allowing pointer types in using aliases, we want to enable aliases to carry the `unsafe` keyword. But where should it go - before or after the `using` keyword?\n\nToday, one modifier appears *before* the `using` keyword (`global`), and one appears after (`static`). Looking at these, `global` affects *where* the using takes effect, and applies to all forms of using directives. Conversely, `static` applies only to one form of using directive, and only has meaning for that one. It seems that `unsafe` aligns more with the second category, as it only applies to using *aliases*.\n\nAdditionally, it is useful for all `using`s (and `global using`s respectively) to align visually with the operative keyword(s) in the same horizontal position.\n\n#### Conclusion\n\nGo with `using unsafe` rather than `unsafe using`.\n\n### Roles and extensions\n\nhttps://github.com/dotnet/csharplang/pull/6880\n\nWe reviewed the roles and extension proposal in its current state to provide feedback to the working group. The below sections contains points for clarification and open questions for the group to pursue.\n\n#### Terminology\n\nWe are not necessarily in love with the term \"role\", and may well change it. It could e.g. be \"view\". However we'll save that discussion for later.\n\n#### Phases\n\nThe proposal operates with three phases:\n\n- \"A\" provides only static extension members (static methods, properties, fields, etc.)\n- \"B\" provides extensions and roles, allowing them to add all static and instance members, except for instance fields, auto-properties or field-like events. Constructors are also an open question.\n- \"C\" allows extensions and roles to implement interfaces\n\nThe phase A vs B split is not just there for potential sequencing over multiple releases: the phase A scenarios have potential for more downlevel friendly code gen, since they do not need to represent an underlying value. Even if we ship phase A and B at the same time, it may be worth ensuring that \"static only\" scenarios are more easily targeted to older runtimes.\n\n#### Syntax\n\nThe proposed syntax allows for multiple base roles, establishing an inheritance hierarchy among roles.\n\nType members can't be virtual (no virtual, abstract or override modifiers), because the underlying values exist independently of the roles, and therefore cannot have their behavior modified by role declarations.\n\nRoles can be nested in roles.\n\nShould there be prefix naming conventions for roles and extensions (e.g. `RCustomer`, `EOrder` - or `XOrder`?), like there are for interfaces and type parameters (`ICustomer`, `TOrder`)?\n\n#### Underlying type\n\nThe proposal doesn't use \"inheritance\" to describe the relationship to the underlying type, even though members are \"inherited\" in the sense that they are available on the role as well. This is so that we can distinguish where e.g. protected doesn't apply, and to emphasize that roles can augment even sealed types and structs. We need clear differentiating terminology, but this may or may not be the right one.\n\nSome of the listed restrictions on underlying types are likely temporary, and imposed by envisioned emit strategy (pointers, ref structs). Others are likely permanent (dynamic, nullable reference type). The doc should clarify that.\n\nThe rule about extension type parameters all being used by the underlying type is so that we can infer backwards when searching for extensions. We have similar needs for extension methods today.\n\n#### Conversions\n\nThere is an identity conversion between a role and its underlying type, as well as its base roles. The current proposal does not allow sideways identity conversion between roles with the same underlying type, which would mean identity conversion isn't transitive (unlike in the existing language). If this is a problem, we may consider always allowing identity conversion when the underlying type matches, but perhaps give a warning on sideways conversion to preserve some \"type safety\" across role hierarchies.\n\nDoes the identity conversion thing clash with the ability to overload methods on role parameter types? Not necessarily. Betterness has an \"exact match\" clause that would allow you to distinguish. It's desirable to have overload resolution on roles, and we hope it's possible from a metadata perspective, but that remains to be investigated.\n\n#### How is an extension \"activated\"\n\nWhoever declares an extension decides that it is an extension. Whenever it is in scope or imported with a `using` directive, the extension applies to its underlying type. This is equivalent to how extension methods work today. Another design would be to have just one kind of declaration, and have the user decide whether to apply the role as an extension. We tentatively agree that whoever declares an extension knows that it is going to be used as an extension, and designs it for that purpose. Also this is less of a deviation from today's behavior.\n\n#### Type tests\n\nWill you be able to tell roles apart with pattern matching? No, from a runtime perspective they represent the same underlying type, which is the thing we can check for at runtime.\n\n#### Why are extensions named types?\n\nWhy do we think extension types are important? Mostly disambiguation. You can explicitly convert from an underlying type to the extension, and now the extension's members go to the foreground, hiding other extensions. \n\nThis also underscores the close relationship between extensions and roles. Extensions are essentially roles that get automatically applied.\n\nIf/when we get to phase \"C\", this becomes more important, as an extension can implement additional interfaces on behalf of its underlying type, and therefore needs to be able to be passed as a type argument for type parameters constrained by such interfaces. Therefore it needs to be a type.\n\n#### Types and roles\n\nThe type of `this` within a role's instance members is the role type itself.\n\nA role satisfies the same constraints as the underlying type. That means value vs reference type (`struct` vs `class` constraint) depends on the underlying type, not the role itself.\n\n#### Interaction with extension methods\n\nOld-fashioned extension methods will have some restrictions in their interaction with roles and extensions. This is TBD.\n\n#### Member lookup\n\nToday you cannot call an extension method with a simple name, even if you're inside of the extended type. We're planning to keep that restriction: The lookup would get weirdly two-dimensional and it doesn't seem worth the trouble or potential surprises.\n\nMember lookup on a role goes to the role, then base roles, *then* the underlying type.\n\nMember lookup (on all types) is also augmented so that if we don't find anything, we'll look in compatible extensions.\n\nExtension member lookup is a generalization of today's extension method lookup, except that we can look for other kinds of members, and that we can look at enclosing types.\n\n#### Scenarios\n\nPrevious documents on roles describe several scenarios in more detail. It would be good to gather those (and more) scenarios, and evolve them with the proposal.\n\nExamples would also help make it a bit easier to follow the behaviors and restrictions. \n\n#### Conclusion\n\nWith the above feedback in mind, the working group is encouraged to continue fleshing out the proposal.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-02-15.md",
    "content": "# C# Language Design Meeting for February 15th, 2023\n\n## Agenda\n\n- [Open questions in primary constructors](#open-questions-in-primary-constructors)\n    - [Capturing parameters in lambdas](#capturing-parameters-in-lambdas)\n    - [Assigning to `this` in a `struct`](#assigning-to-this-in-a-struct)\n\n\n## Quote of the Day\n\n- \"Where did you think we put that? Magic?\"\n\n## Discussions\n\n### Open questions in primary constructors\n\nhttps://github.com/dotnet/csharplang/issues/2691  \nhttps://github.com/dotnet/csharplang/blob/2867220fe142dfefd47d8cb20fb88393e4156059/proposals/primary-constructors.md#open-questions\n\n#### Capturing parameters in lambdas\n\nWe first considered the question of what happens when a lambda in a field or property initializer captures a parameter that is also captured by the containing type. For example:\n\n```cs\npartial class C1\n{\n    public System.Func<int> F1 = Execute1(() => p1++); // Capture 1\n}\n\npartial class C1 (int p1)\n{\n    public int M1() { return p1++; } // Capture 2\n    static System.Func<int> Execute1(System.Func<int> f)\n    {\n        _ = f();\n        return f;\n    }\n}\n```\n\nTo follow standard capture rules, both `p1`s will need to refer to the same storage location, and observe the changes from one to the other. There's really two questions here:\nfirst, should we allow this at all? And second, how will we implement it (and do any implementation strategies have semantic implications)?\n\nFor the first question, we started by thinking about whether to disallow the scenario where a primary constructor parameter is captured by two locations at once. But we're concerned\nabout spooky action at a distance here, where adding a field initializer can cause compilation errors in a different location. We also don't think that the issue that the rule was\noriginally created to avoid is an issue in this area: `this` is not being generally exposed before the base constructor has been run, and there are no changes to virtual members that\ncan be invoked before the base constructor has run. We therefore lean towards allowing it.\n\nFor the second question, we thought about whether to do a double-closure technique, where we create an inner closure type that is then shared between the accesses, or whether to simply\nclose over `this` in the lambda. After some consideration, we think we're ok with just using `this`, particularly as the double-capture could potentially have some bleed-through effects\non whether an individual type is considered `unmanaged`, and potentially causes allocations that weren't expected. The main issue will be working with the runtime team to ensure that\nILVerify understands the pattern.\n\n##### Conclusion\n\nThis scenario is allowed, and we will work with the runtime team to make sure that ILVerify is updated for this scenario.\n\n#### Assigning to `this` in a `struct`\n\nFinally, we looked at whether allowing self-assignment in a struct to silently overwrite primary constructor parameter captures is a good thing, or if we should warn/error/something else\nfor the scenario. We think that this is the least surprising behavior that this could have, and that it would be more surprising if it didn't have this effect. A warning does not seem\nappropriate: either you didn't even know this syntax was possible, or you do know what this syntax means and you were expecting the state of `this` to be overwritten; primary constructor\nparameters are part of that state, so they should logically be overwritten.\n\n##### Conclusion\n\nAllowed, no warning.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-02-22.md",
    "content": "# C# Language Design Meeting for February 22nd, 2023\n\n## Agenda\n\n- [Primary Constructors](#primary-constructors)\n- [Extensions](#extensions)\n\n## Quote of the Day\n\n- \"I have made a critical error: I forgot to write down quotes of the day today.\"\n\n## Discussion\n\n### Primary Constructors\n\nhttps://github.com/dotnet/csharplang/issues/2691  \nhttps://github.com/dotnet/csharplang/blob/bff4265098ff92551a9cc6aef17b0210f737c42a/proposals/primary-constructors.md\n\nWe started today by going through the primary constructors specification, and verifying the feature we are going to ship in preview soon. There were few comments\non the specification, which is generally unchanged from the initial review. We do think that there is room to relax `ref` and `out` restrictions on `record` primary\nconstructors in the future, to align with primary constructors on non-`record` `class`es and `struct`s, but that is an orthogonal feature that we're not going to\ndo at this time. We also do think that we potential future work on primary constructors to address more scenarios. For example:\n\n* Primary constructor bodies\n* Generating public properties, and naming convention discussions that will inevitably occur when this happens.\n\nHowever, we don't think any of these future features are blocked by the current state of the proposal, and will continue with the plan to merge the feature branch\ninto an upcoming preview of VS and .NET.\n\n#### Conclusion\n\nWe will move forward with the preview.\n\n### Extensions\n\nhttps://github.com/dotnet/csharplang/issues/5497  \nhttps://github.com/dotnet/csharplang/pull/6880\n\nPrototype progress on extensions (formerly roles and extensions, formerly shapes) has been proceeding in the working group. We're bringing the recommendations and changes\nthe working group has suggested back to the LDM for debate and approval. In order to help the prototype proceed, today we are focussing on syntax questions. The working\ngroup explored a number of syntax options, including the original `role`/`extension`, `view`, `shape`, and `alias`, ultimately deciding on `extension` with a modifier:\n`explicit` and `implicit`. The LDT agreed that this feels like it unifies the proposal: where previously the distinction between an `extension` and a `role` was hard to\nremember and non-obvious, we feel that it is now much clearer. There is a single feature, extensions, which is about adding new functionality to an existing type. That\nextra functionality can be added implicitly (like existing extension methods are today, but with the ability to add more) or explicitly (completely new functionality).\nWe also went over the newly-added `for X` syntax for specifying the underlying type of an `extension`. This is necessary for partial `extension`s to work. An example\nwith the old syntax vs the new syntax:\n\n```cs\n// Old syntax - Which of these is the interface getting extended, and which is the interface getting added?\npartial explicit extension Ext1 : Interface1;\npartial explicit extension Ext2 : Interface2;\n\n// New syntax - Unambiguous for both human and computer compilers. Interface1 is the extended type, and Interface2\n// is the type being added.\npartial explicit extension Ext1 for Interface1;\npartial explicit extension Ext1 : Interface2;\n```\n\nOverall, the LDT is very happy with these syntax changes, and the prototype will be moving forward with them.\n\nWe also looked at another issue the working group has started to consider, `extension` conversions. This covers conversions in all directions: up/down (from extension to\nunderlying type and from underlying type to extension) as well as lateral conversions (from extension to extension with compatible underlying types). There is general\nsentiment that lateral implicit conversions might not be a great thing: moving from a `JsonViewExtension` to a `XmlViewExtension` is probably not something that should\nhappen unintentionally. At the same time, the initial proposal envisioned the conversion to/from an `extension` as an identity conversion: it would be odd if there were\nidentity conversions from a to b, and b to c, but not a to c. The working group will continue to consider these scenarios, as well as things such as validation on conversion\nto an `extension`, and come back to the LDM with a more complete view of the various pros and cons.\n\n#### Conclusion\n\nSyntax are changes, the working group will turn its attention to conversion questions.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-02-27.md",
    "content": "# C# Language Design Meeting for February 27th, 2023\n\n## Agenda\n\n- [Interceptors](#interceptors)\n\n## Quote of the Day\n\n- \"Interceptors, that sounds like those auxiliary ships to Star Destroyers\"\n\n## Discussion\n\n### Interceptors\n\nhttps://github.com/dotnet/csharplang/issues/7009\n\nToday the LDM took a look at a new proposal in collaboration with the ASP.NET team, interceptors. This feature is\nintended to help make code AOT-friendly by allowing source generation to replace runtime reflection. By doing static\nanalysis at compile-time and then hooking APIs, we can both improve performance and remove AOT-unfriendly code. This\nproposal generated significant discussion in the LDM, with roughly two ideological camps forming:\n\n1. Interceptors are intended to be a performance optimization step. Generalized aspect-oriented programming is not\n   a goal of the proposal, and the mechanism they work by is effectively an implementation detail. Users should not\n   need to know that a method has been intercepted, so long as the debugging experience works well.\n2. Interceptors are a generalized language feature, of which AOT-optimization is just one possible application. Users\n   should know when a method call has been intercepted: perhaps they need to indicate this by putting a sigil at the\n   callsite, such as `#` (ie, `controller.MapGet#(\"/\", CreateFeed)`).\n\nNot everyone fit into these precise camps, but these were the general sentiments. Some other ideas that were raised\nduring the meeting:\n\n* Can this be addressed by an IL AOT-rewrite tool instead of a C# language feature? By causing the C# compiler to\n  emit different IL, it needs to be a language feature; if it was instead an additional step after compilation, then\n  it no longer needs to affect the C# specification, and is not restricted to C#. As a C#-only feature, it could\n  negatively affect the F# and VB ecosystems.\n* These hooked functions are really much more powerful than what can be accomplished today: state from the entire program\n  can influence them. Maybe this calls for a different calling syntax entirely?\n    * Lots of examples in other languages both for and against this: Rust uses the `!` character, while LISP does not\n      have a different syntax.\n* Should we restrict these to just methods? Could you intercept properties, events, fields?\n* How general-purpose are we aiming for here, and is there any reasonable way to restrict it to only being a performance\n  optimization step even if we decide that it should only be used for that? As the saying goes, if all you have is a\n  hammer, everything is a nail...\n\nWe did not come to any conclusions today; indeed, this conversation generated more post-meeting chatter in our Teams\nchat than any LDM topic in recent memory. It's clear that we need to think more about the problems that were raised today\nand come back with a revised proposal that takes these questions into account.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-03-01.md",
    "content": "# C# Language Design Meeting for March 1st, 2023\n\n## Agenda\n\n- [Discriminated Unions Summary](#discriminated-unions-summary)\n\n## Quote of the Day\n\n- \"We're seconds from lattice theory references\"\n\n## Discussion\n\n### Discriminated Unions Summary\n\nhttps://github.com/dotnet/csharplang/discussions/7010\n\nToday, the working group took a summary of their discussions back to LDM and went over them with the group.\nThis took the entire session, and only clarifying questions were asked; the LDM will discuss thoughts on the\nproposal next week, after members have had some time to think about the topics presented today.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-03-08.md",
    "content": "# C# Language Design Meeting for March 8th, 2023\n\n## Agenda\n\n- [Discriminated Unions](#discriminated-unions)\n- [Limited Breaking Changes in C#](#limited-breaking-changes-in-c)\n\n## Quote(s) of the Day\n\n- \"It sounds like we're not unified on unions\"\n- \"Anyone feel like we found the weeds?\"\n- \"I shouldn't have used my pizza example\"\n\n## Discussion\n\n### Discriminated Unions\n\nhttps://github.com/dotnet/csharplang/discussions/7010  \nhttps://github.com/dotnet/csharplang/issues/7016\n\n[Last time](LDM-2023-03-01.md#discriminated-unions-summary), we looked at the summary of the discriminated union\nworking group's investigations. There's a lot there; we also had an additional proposal from a language design member\nemeritus, who lead the previous investigation into DUs, on a form of efficient tagged unions. One thing that is\napparent is that, even with the working group's summary, there is a massive design space here. Another point that\nbecomes obvious quickly is that generics throw many wrenches into any design: you either have a problem where things\nlike `List<(A | B)>` cannot be freely converted to `List<(A | B | C)>`, or there are inefficiencies in representing\nvalue types that likely preclude union usage in a number of places. Looking to the major .NET language with union\ntypes, F#, they implement tagged unions (though they are considering \n[anonymous type unions](https://github.com/fsharp/fslang-design/blob/0ff87d5ab3160366a96316f739ba31d9a61d0f4a/RFCs/FS-1092-anonymous-type-tagged-unions.md)).\n\nWe talked some about how tagged unions implemented via structs is effectively struct inheritance: indeed, it's hard\nto conceive of a struct inheritance implementation that would not effectively turn into a tagged discriminated union.\nThere are some interesting parts to this implementation strategy though: would a union with simple inline values be\nable to be more efficiently represented than a union with a nested struct value? For example:\n\n```\nunion { MyFourInts(int, int, int, int), MyThreeInts(int, int, int) }\nunion { MyFourInts(StructOfFourInts), MyThreeInts(StructOfThreeInts) }\n```\n\nIf those have different layouts that make the former more compact than the latter, that could be unfortunate,\nparticularly if the layout was guaranteed in such a way that we couldn't improve it in the future.\n\nWe also thought a bit about how tags will interact with pattern matching. The natural syntax we would want to use\nlikely conflicts with type patterns: can we make that work? And, in particular, will there be a way to declare a\nvariable that encapsulates all the state of a particular tag? The tags aren't types, but maybe we can paper over that\nfor the purposes of pattern matching, using tuples to contain all the state for a particular tag?\n\nWe ultimately think there is room for multiple types of unions in C#: a tagged, struct-based variant, and a reference\ntype variant. However, we aren't ready to make more progress yet; we'll work on determining the next steps for the\nworking group.\n\n### Limited Breaking Changes in C#\n\nhttps://github.com/dotnet/csharplang/discussions/7033\n\nContinuing in today's LDM theme of light, easy, non-controversial topics, we took a look at a proposal for making\nlimited breaking changes in C#. We posted this to csharplang a few days ago, and the response so far has been mostly\npositive; plenty of suggestions of how we might tweak it to add more granularity, suggestions to go further (a la\nRust editions), and questions on the cadence. There have only been a few negative reactions to the idea, however,\nwhich is an encouraging sign overall. GitHub can't be our only source of sentiment on this, though, as it's a\nself-selecting group; more user research will be needed via other avenues.\n\nWe brought up that this might change the way the C# compiler approaches certain problems. Today, the compiler tries\nvery hard to not change its semantic behavior while binding. When we see a user taking advantage of a language feature\nin a newer language version than what they are targeting, we simply produce an error and continue binding. This would\nchange the compiler to introduce new warnings in _lower_ language versions, and cause the compiler to potentially bind\nin different fashions for higher and lower versions. We need to be cognizant of that, and have an idea of how the compiler\nchange would work before committing to a design that we can't implement.\n\nWe also thought about the documentation issue. Today, our documentation is updated for new language versions, so if we\nmake breaking changes, users on older versions might slowly get left behind our documentation. Inversely, there are many\nnon-Microsoft sources of documentation (StackOverflow, blogs, tutorial videos, etc.) that never get updated for new\ncontent; users trying to copy and paste or learn from these sources might be hurt. This has already happened with\ntop-level statements; our tools and docs updated, but many popular 3rd-party intros and tutorials have not. The changes\nwe're discussing here might not be as much of a concern, however; the cases we've discussed so far are exceptionally\nnarrow cases of changing how an identifier is interpreted.\n\nA read of the room indicates that we should continue to pursue this topic, so the working group will continue to flesh\nout the proposal, gather feedback from user groups, and flesh out the proposal details for future review.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-03-13.md",
    "content": "# C# Language Design Meeting for March 13th, 2023\n\n## Agenda\n\n- [Unsafe in aliases hole](#unsafe-in-aliases-hole)\n- [Attributes on primary ctors](#attributes-on-primary-ctors)\n\n## Quote(s) of the Day\n\n- \"The quote of the day will be 'We have 2 small topics', and the agenda will only have 1 topic.\"\n- \"We only have 5 minutes left, let's see if we can do it really quickly.\" *everyone starts talking really fast*\n\n## Discussion\n\n### Unsafe in aliases hole\n\nhttps://github.com/dotnet/roslyn/issues/67281\n\nWe started today by looking at an existing hole in the enforcement of `unsafe` for pointer types, nested as the element type of an array in a type parameter\nto a generic type (such as `List<int*[]>`). This hole has existed for as long as generics have, but now presents us with an inconsistency in the C# 12 `using`\nenhancements feature, as it introduces `using unsafe`. In brainstorming, we came up with the following options:\n\n1. Keep the status quo. This will mean that most usages of `unsafe` types in `using` will require `unsafe`, _except_ those types contained inside type parameters.\n2. Produce an error across all language versions, and require `unsafe`. This will break older consumers that have aliases like this defined.\n3. Produce an error conditionally on language version 12. This has 2 suboptions:\n   1. Give warnings on lower language levels.\n   2. Do not give warnings on lower language levels.\n4. Make this a warning wave in C# 12. This will also result in inconsistent experience like #1, but there will be a diagnostic in all scenarios.\n5. Don't add `unsafe` to `using`s in general, and do not require them for `unsafe` types in `using`s.\n\nWe framed these options of what they do for the future and past of the language:\n\n* 1 would result in an inconsistent future for the language, and we have no reason to believe that code like this exists nearly anywhere at all. No search results\n  for it appear in any of our usual sources, when other breaking changes we've made _do_ sometimes appear in searches of GitHub or internal MS code.\n* 2 would be consistent for the future, but leave the past with no escape hatch.\n* 3 would be consistent for the future, and leave the past as it is; but the new warnings from a could potentially be an issue for users who are just upgrading\n  their toolsets.\n* 4, while not as inconsistent as 1, would still leave the future inconsistent, which we do not like.\n* 5 would be consistent with the past and the future, but the reasons we chose to have `using unsafe` in the first place are still relevant. We don't want to adjust\n  the future of the language based on a bug.\n\nBased on this discussion, we think 3b is the best option that maximizes forward direction while letting past code continue existing.\n\n#### Conclusion\n\nWe chose option 3b, producing an error on this code in C# 12 and up, and not giving warnings in lower language versions.\n\n### Attributes on primary ctors\n\nhttps://github.com/dotnet/csharplang/issues/7047\n\nIn our speedrun session for this issue, we briefly considered whether `method` in this location is obviously on the primary ctor: could it conceivably be confused\nwith the copy ctor or deconstructor. However, we already have documentation comments on the parameters, and those don't get applied in either of the aforementioned\nlocations. Attributes on the parameters are also only applied to the primary ctor, not to the deconstructor. Given those, we're ok with this proposal.\n\nWe then determined what bucket to put it in. For now, we'll bucket it with the primary constructor work we're doing in C# 12, which would put it in the working set.\nWe'll rebucket to Any time if it doesn't end up fitting in that bucket.\n\n#### Conclusion\n\nProposal is accepted, will be part of the primary ctor work in C# 12.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-04-03.md",
    "content": "# C# Language Design Meeting for April 3rd, 2023\n\n## Agenda\n\n- [Collection Literals](#collection-literals)\n- [Fixed-size buffers](#fixed-size-buffers)\n\n## Quote of the Day\n\n- \"These are now variadic tuple literals\"\n\n## Discussion\n\n### Collection Literals\n\nhttps://github.com/dotnet/csharplang/issues/7085  \nhttps://github.com/dotnet/csharplang/issues/5354\n\nWe started today by looking at open questions in collection literals, spending all of our time talking about the spread operator. We had a few questions we wanted answered about it:\n\n1. Is spread even an important thing to address in the initial collection literals proposal?\n2. How much is the compiler free to optimize the creation of these collection literals? Can intermediate literals be elided if a reasonable program wouldn't observe them?\n\nFor the first question, we universally agree that there is a concept to be explored there. There will be some syntax gremlins to iron out; some members believe that `..` is perfectly\nnatural, as it is the complement of slicing in list patterns and in accessing sub-ranges of existing collections, while other members believe that `..` is bad here because it\nintroduces confusion for collections of ranges. Despite that, we do think the space is worth exploring, and will do so.\n\nNext, we thought about compiler optimizations of spreads. There's a lot of interesting side-points on optimizations here that can have a big impact on the collection literal, such as:\n\n* If the collection literal is not going to be added to later, then presizing makes sense. If it is going to be added to later, though, presetting the size can have negative impacts\n  and force resizes where they might not otherwise be.\n* What is the order of evaluation of the creation of the list and the evaluation of the elements? For example, if the elements of the list are pre-evaluated, we could pre-size the\n  collection more accurately; on the other hand, if we have to pre-evaluate the entire element set before calling the constructor of the containing type, could we end up having more\n  stack/local usage and negatively impacting perf there?\n* What about intermediate collection literals? The proposal suggests using conditional expression spreads with empty collection literals for conditionally adding elements to the\n  containing collection, but do those nested collection literals need to actually be created? Can they be inlined into the containing creation? And if we do that, does that mean\n  that things like extract local can introduce silent perf impacts because intermediate collections are now considered real collections?\n\nThis last bullet brought up a new question that we then started delving into:\n\n3. Should list literals be thought of as more ephemeral until they're used? For example, if it's just being `foreach`'d over, we could just make it a `stackalloc`. Or, if it's\n   assigned to a `var` variable that is eventually passed to a `List` location, we could say that it's not really a list until that point, but is instead a lightweight list-like\n   thing.\n\nThis idea is both interesting (gives us lots of room to optimize the implementation for specific scenarios) and terrifying (what is the type of this variable? What does generic type\ninference do? Is it a quantum variable that needs to have the waveform collapse eventually?), and has lots of room to explore. We could say, for example, that `var` causes the type\nto collapse, and it's only when these are used as nested expressions in other expressions that they have this weird quantum state. We think this needs to be explored more, and the\nconsequences and impacts on other systems thought through, before we go further down this road.\n\nFinally, we also looked at the conditional expression used here. There are some [older discussions on csharplang](https://github.com/dotnet/csharplang/discussions/5588) about making\na conditional assignment as part of object initializers, we might be able to general purpose that to work in either of these cases. While we do think that the syntax originally proposed\nin the spec for collection literals should work and should ideally not produce excess allocations, it does feel ugly, and there's likely a feature to improve that for both collection\nliterals and other types of initializers.\n\n#### Conclusions\n\n1. We will continue trying to answer the spread questions and make an effort to include it in the initial feature.\n2. Leaning towards allowing optimization, but we need a better understanding of what optimizations are on the table and the consequences of them.\n3. We need more info about what the impacts of this change would be.\n\nWe'll come back after some more thinking on those topics has been done.\n\n### Fixed-size buffers\n\nhttps://github.com/dotnet/csharplang/pull/7064  \nhttps://github.com/dotnet/csharplang/issues/1314\n\nFinally today, we took an initial look through the first option proposed in 7064 for implementing safe fixed-size buffers. This is a more complicated proposal that builds off new\nruntime support for `InlineArrayAttribute`, allowing types defined with a specific pattern to be treated as if they are fixed-size buffers of an element type. Today was mostly an\noverview; next time we will go over the simpler version of the proposal (option 2) and discuss more about which option we want to go with.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-04-10.md",
    "content": "# C# Language Design Meeting for April 10th, 2023\n\n## Agenda\n\n* [Fixed Size Buffers](#fixed-size-buffers)\n\n## Quote of the Day\n\n- \"As a Tanner of the world\"\n\n## Discussion\n\n### Fixed Size Buffers\n\nhttps://github.com/dotnet/csharplang/pull/7064  \nhttps://github.com/dotnet/csharplang/issues/1314\n\nContinuing from [last time](LDM-2023-04-03.md#fixed-size-buffers), we took a look at the second of the possible fixed size buffer approaches\ntoday. This one is much simpler and is based on only exposing `Span` and `ReadOnlySpan` types to the user, instead of `BufferX<T>` types.\nThis ensures that users don't have new types to think about and can keep operating in terms of the types they already know. It also allows\nchanging the size of a fixed-size buffer to not be a binary-breaking change, as the only publicly-exposed types are `Span` and `ReadOnlySpan`,\nneither of which has an associated fixed length. This simplicity does bring some of its own downsides too, though:\n\n* That binary break could be a desired outcome: if a public fixed size buffer shrinks, it's important for that to break the API of anyone who\n  was accessing memory that no longer exists.\n    * On this note, we don't currently have anywhere that we plan to expose public fixed size buffers, outside native interop scenarios.\n* How do other languages consume these types? Do they have to understand an additional C# concept layered on top of the general runtime pattern?\n* Does this stifle our future language design space? We could want to reason about fixed-size arrays in the future, for example a `List<int[4]>`,\n  or even going further and allowing const generics as in `List<int[TSize]>`.\n    * Users might also simply want to pass these buffers around. If the buffer is typed as `Span` or `ReadOnlySpan`, then size information is\n      elided and compile-time bounds checking can be lost.\n\nAdditionally, using `Span` and `ReadOnlySpan` as the user-facing types doesn't prevent users from defining their own fixed size buffer types,\nas `InlineArrayAttribute` is a runtime feature. Should C# add support for consuming such types as if they are fixed size buffers, even if we\ndon't `int[4]` as one? This has its own set of complications. We're a bit concerned about whether it's worth the effort: how many users are\nactually going to define these types? And if they do, will these types conflict with each other? Unlike tuples, we somewhat expect that fixed\nsize buffers could be hundreds of elements long; even if the BCL were to define the first 32 sizes, there's still a good chance that two fixed\nsize buffers from different assemblies would be conflicting definitions, even though they wrap the same type and have the same length. Despite\nthese concerns, though, we think that there's enough benefit for the BCL in supporting these types that we should do so in C#. Next time, we\nwill pick this up again and try to determine whether we will have specific syntax for easily defining these types of buffers in the language\nitself (such as `int[4]`) or not.\n\n#### Conclusion\n\nC# will support using fixed size buffer types as if they are buffers. We will think more about whether to have syntactic sugar for defining them\nnext time.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-04-26.md",
    "content": "# C# Language Design Meeting for April 26th, 2023\n\n## Agenda\n\n- [Collection literals](#collection-literals)\n\n\n## Quote of the Day\n\n- \"Do we need dragon warnings?\"\n\n## Discussion\n\n### Collection literals\n\nhttps://github.com/dotnet/csharplang/issues/5354  \nhttps://github.com/dotnet/csharplang/blob/760e4a772a06723ea6ab3edabe14029623302ea2/proposals/collection-literals.md\n\nToday, we took a look at the current proposal for collection literals. The proposal is looking very good overall, but\nthere are some open questions around how it should behave in some scenarios.\n\nFirst, when the target-type of a collection literal is an `IEnumerable<>` of some kind, what type is emitted by the\ncompiler? As written today, it's always `List<>`, but this has the potential to cause allocations when they aren't\nneeded. It would be great, for example, if `IEnumerable<string> e = [];` could just be emitted as a call to\n`Enumerable.Empty<string>()`, avoiding the need for an allocation entirely. That can't happen today, though, as it's\nspecified to be `List<T>`. This would also mean that we couldn't do optimizations for scenarios that pass a fixed list\nof constants to an `IEnumerable<>` function: the consumer could downcast to `List<>` and add to it. We think that,\ngiven that we are talking about `IEnumerable<>` and not some more specific type, it should be fine to not guarantee\nwhat underlying type we end up using; indeed, that's the entire point of taking an interface, rather than a concrete\ntype.\n\nNext, we looked at KVPs turning the collection literal into a `Dictionary<>` automatically. We have some immediate\nconcerns with this provision: the user could just as easily want a `List<KVP<K, V>>` instead of `Dictionary<K, V>`.\nThere are also concerning differences in behavior with how such a dictionary would be constructed: a `Dictionary`\nwould be union semantics, where duplicate later keys can overwrite earlier keys (or, if specified slightly differently,\nit could throw instead of overwriting). A list would contain both duplicate keys, which is a large change in behavior\nwith very little to indicate that the behavior has changed. A bit more digging pulled up the important scenario that\nthis rule is trying to cover: `[.. dict1, .. dict2]` should result in a dictionary union of these two input dictionaries,\nor `[.. dict1, key: value]` should result in a copied dictionary, with `key` set to `value`. We therefore brainstormed\nan alternate rule, that would be useful not just for `Dictionary<>`, but also for any collection being splatted into\nanother collection: the type of a splat should impact the natural type of a collection literal. This is a rough idea\nthat the working group will need to further explore, but at first glance it seems both powerful and like it addresses\nthe concerns that created this rule in the first place.\n\nNo conclusions were reached today, but the working group has more feedback to go iterate on and come back to LDM with.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-05-01.md",
    "content": "# C# Language Design Meeting for May 1st, 2023\n\n## Agenda\n\n- [Fixed Size Buffers](#fixed-size-buffers)\n- [`lock` statement improvements](#lock-statement-improvements)\n\n## Quote of the Day\n\n- \"Oh my head hurts\" \"I'm glad I achieved my goal\"\n\n## Discussion\n\n### Fixed Size Buffers\n\nhttps://github.com/dotnet/csharplang/pull/7130  \nhttps://github.com/dotnet/csharplang/issues/1314\n\n[Last time](LDM-2023-04-10.md#fixed-size-buffers) we discussed fixed size buffers, we concluded\nthat we wanted to support manually defined inline array types in the language natively. This means, for example,\nbeing able to index them. Our next question is, should we support anonymous inline array types? The proposed syntax\nis `int[4]` for an anonymous inline array of 4 integers; this aligns well with existing array types in the language\nand is a natural extension. However, the ease with which it slots into the language is almost an issue in itself; inline arrays\nare not regular arrays and cannot be used where arrays can be. They do not unify across assemblies, and indeed the\nproposal forbids making them public at all. There are also concerns on what the syntax will end up looking like with\nnested arrays: a regular array of 4 element int arrays would end up looking like `int[][4]`. This is then complicated\nfurther by nullability: a non-null regular array of 4 element int nullable arrays would be `int[]?[4]`. There are even\npotential issues with `foreach`: an `int[4]` is only indexable via `Span`, which would potentially break usage in async\nmethods. Given all of these hidden gotchas and the lack of demand for anonymous inline arrays, we think the best\napproach for now is to avoid having them at all.\n\nWe also looked at initialization scenarios; the main questions here are whether we allow array initializers for these\nvalues, and whether we allow C# 12 collection literals for them. For array initializers, we think the answer should be\nno, as we have now said there are no anonymous inline arrays. We do think that collection literals are the future here,\nand they should work for inline arrays as well as other types of collections.\n\n#### Conclusion\n\nAnonymous inline arrays are rejected. Array initializers are not supported for inline arrays. Collection literals are\nsupported for inline arrays.\n\n### `lock` statement improvements\n\nhttps://github.com/dotnet/csharplang/issues/7104\n\nThe runtime will be adding a new `System.Lock` type, as an alternative to monitor-based locks. The API has a shape that\nworks well with `using`, but as it currently stands it will misbehave with a standard `lock` statement. This isn't the\nfirst type of lock this is true for; for example, `ReaderWriterLock`/`ReaderWriterLockSlim`/`SpinLock`. However, this\nis different in that all of those have caveats to their using with a regular `lock` statement: rwlocks need to enter\nin a specific mode that can't be inferred from just a `lock` statement, and `SpinLock` is very rarely used. This new\ntype, on the other hand, is part of an experiment to entirely replace monitor-based locks in .NET, and the hope is\nthat new development will use these instead of an `object` to perform mutual exclusion. Given that, having it do the\nwrong thing in a `lock` seems like an easy footgun for the language to solve. An open question is whether we want to\nconvince people to avoid monitor-based locks entirely; that seems like it would be best driven by the runtime, rather\nthan the language design team.\n\n#### Conclusion\n\nThe language will support using the new locking pattern for locking on `System.Lock`.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-05-03.md",
    "content": "# C# Language Design Meeting for May 3rd, 2023\n\n## Agenda\n\n- [Inline Arrays](#inline-arrays)\n- [Primary constructors](#primary-constructors)\n    - [Attributes on captured parameters](#attributes-on-captured-parameters)\n    - [Warning for shadowing base members](#warning-for-shadowing-base-members)\n- [Collection literal natural type](#collection-literal-natural-type)\n\n## Quote of the Day\n\n- \"It's our best chance of having a stem cell\"\n\n## Discussion\n\n### Inline Arrays\n\nhttps://github.com/dotnet/csharplang/issues/1314  \nhttps://github.com/dotnet/csharplang/pull/7130\n\nContinuing to [follow up](LDM-2023-05-01.md#fixed-size-buffers) on open questions, we turned our attention to\nvalidating `InlineArrayAttribute` applications and whether nested object initializers can use indexers on inline\narrays. For the former, we're unanimously in favor of the compiler validating that the attribute was applied correctly.\nThe latter proved to be a more interesting conversation; we brought up that arrays are supported, but this actually\nappears to be a spec violation of the C# compiler, as the syntax is supposed to require an indexer member to be defined\non the type being initialized while arrays do not define any such member. We also don't think there's any real demand for\nthis to be natively supported, and by leaving it out users can opt into the feature by defining their own indexer on\ntheir inline array types. This allows us to have our cake and eat it too: no implementation complexity for us, and users\ncan get the syntax they choose if they want it.\n\n#### Conclusion\n\nWe will validate `InlineArrayAttribute` applications. We will not natively support inline arrays for object initializer\nindex initialization, but we won't block it if the user defines their own indexer either.\n\n### Primary constructors\n\nhttps://github.com/dotnet/csharplang/issues/2691  \n\nWe considered a couple of open questions in primary ctors.\n\n#### Attributes on captured parameters\n\nhttps://github.com/dotnet/csharplang/blob/fe9915c0708cf95c308cce33983373641fc1b60d/proposals/primary-constructors.md#field-targeting-attributes-for-captured-primary-constructor-parameters\n\nWe're concerned about allowing attributes on captured parameters. From a language perspective, these are not fields,\nand don't have to be captured in fields. This would not be the only thing that a user might want to put on their\ncaptures; for example, there has been significant feedback that users would like their captures to be `readonly`.\nThis doesn't seem more important than that scenario, so why would this work while that does not? It seems like, if we\never get syntax for specifying more about how the parameter is captured, it would be appropriate to have this feature\nat that point, but until then we would like to hold off.\n\n##### Conclusion\n\nNot allowed.\n\n#### Warning for shadowing base members\n\nhttps://github.com/dotnet/csharplang/discussions/7109#discussioncomment-5666621\n\nOne piece of feedback that we've seen is that users are concerned about shadowing members from base types accidentally.\nWhile this is concerning, we're also concerned that a broad warning might impact a common scenario where the parameter\nis passed to the base to initialize the shadowing member. We need to think more about this conflict, so we'll do so\nand come back to the problem at a later meeting.\n\n##### Conclusion\n\nNo conclusion today.\n\n### Collection literal natural type\n\nhttps://github.com/dotnet/csharplang/issues/5354  \nhttps://github.com/dotnet/csharplang/blob/c8c1615fcad4ca016a97b7260ad497aad53ebc78/meetings/working-groups/collection-literals/CL-2023-04-28.md#should-a-collection-literal-have-a-natural-type-if-so-what-type\n\nFinally today, we considered whether collection literals should have a natural type. There are a couple of slightly\ndifferent versions of this scenario: `var`, and `IEnumerable<>`, but `var` is what we spent most of the time discussing.\nIn many ways, a natural type for a collection is going to be surprising, no matter what we choose. Some users will\nexpect such collections to behave like other C# literals: immutable and cacheable. Another segment might expect the\nliteral to be typed as an array: not immutable, but not growable either. A third would expect such literals to be a\ntype that can be added to later, such as `List<>`. No matter what we choose, if we choose a natural type, two of the\nsegments are going to be surprised by the decision.\n\nSo what if we didn't have a natural type at all? Today, users always need to think about the type of a collection when\nit is created. Either it needs to be assigned to a local or parameter that has a type, or it's being created by some\nfactory method or constructor that has to be typed. One of the goals of the proposal to simplify this, and that requires\nhaving a natural type. But it does feel odd that, for a proposal that goes so far to be optimal when we know the\ntarget type, it cannot be optimal in the natural type case. For the cohort of users that want these to be immutable,\nany mutability in the natural type means that the literals cannot be cached, resulting in lots of extra allocations. For\nthose that expect an array, using `List<>` or some other similar type means that extra overhead is incurred, and trivial\ncases like empty literals cannot be shared. For users who expect `List<>`, either of the other two means that they will\nhave to specify the collection type at creation, making it no longer a simple scenario. Unfortunately, not having a\ntarget type at the start and then adding one later is potentially a breaking change. We did it for lambdas, but it caused\nsignificant pain for implementation and has a number of caveats, so if we can avoid the same gymnastics that would be\nhelpful.\n\nWe also thought a bit about a middle ground, where a collection literal only has a natural type when it is observably\nstored in a location. For example, when iterated over in a `foreach`, a collection literal could be emitted however is\nmost efficient for the compiler. This does then introduce another risk of deoptimizing by extracting variables. This can\nalready happen with interpolated string handlers, but that is fairly rare. This might be similarly rare, but more such\ncases always need to be approached with caution.\n\nWe have no conclusions here this week. We'll come back and think about it more in a future LDM.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-05-08.md",
    "content": "# C# Language Design Meeting for May 8th, 2023\n\n## Agenda\n\n- [Primary Constructors](#primary-constructors)\n\n## Quote of the Day\n\n- \"Depending on how you interpret it, the results can be whatever you want\"\n\n## Discussion\n\n### Primary Constructors\n\nhttps://github.com/dotnet/csharplang/issues/2691  \nhttps://github.com/dotnet/csharplang/discussions/7109#discussioncomment-5666621\n\nToday we looked at one of the pieces of community feedback for primary constructors, around name shadowing from base types. A user might not\nexpect the output that this program will give:\n\n```cs\npublic class Base\n{\n    protected readonly string a = \"base\";\n}\n\npublic class Derived(string a = \"derived\") : Base\n{\n    public void M()\n    {\n        Console.WriteLine(a);\n    }\n}\n```\n\nThis code will print `base` when `Derived.M()` is called, because the base field shadows the primary constructor parameter. While this could be confusing\nfor this particular case, we don't think this is common case for this type of code; instead, the common case is something more like the following:\n\n```cs\npublic class Base(string a)\n{\n    protected readonly string a = a;\n}\n\npublic class Derived(string a = \"derived\") : Base(a)\n{\n    public void M()\n    {\n        Console.WriteLine(a);\n    }\n}\n```\n\nIn this example, `a` is passed through to `Base` via its constructor, and the protected field is referenced by the derived type ensuring that the value\nis not double-stored. There are a few possible options we can look for improving the first scenario:\n\n1. Warn whenever a base member shadows a primary constructor parameter at the use site. This would produce a warning in both of the above code samples.\n2. A variation on 1, produce a warning whenever a base member shadows a primary constructor parameter and that parameter wasn't passed to the base type.\n   There are 2 subvariants of this:\n   1. Ensure that names match when doing this. IE, passing `a` to a parameter named `b` would not count for the purposes of suppressing the warning.\n   2. Do no validation on the name of the parameter.\n3. Change the shadowing order: make the primary ctor parameter shadow the base member, so accessing the base member would require `base.` qualification.\n\nFor 1, we're concerned about the impact to the second code example: that seems the far more common case in the wild, and impacting it negatively isn't\ngreat. For 3, we're unsure whether the effective behavior being different than records will be confusing: `Derived` would not create a new member named\n`a`, it would use the existing one from the base. This leaves us with option 2.\n\nFor 2, we thought a bit about the subvariants. We're a bit concerned by field naming conventions differing from parameters: what guarantees are there\nthat a constructor parameter named `a` will actually assign to a field named `a`? There are none, of course, only long-standing conventions. Some\nusers prefer to name their fields with `_` prefixes (following the C# code-style guidelines), but many keep them exactly the same. We ultimately think\nthat there's enough signal of intent in passing the primary ctor parameter, no matter what the name of the base ctor parameter is, and we can suppress\nthe warning for this case.\n\n#### Conclusion\n\nOption 2.2: Produce a warning on usage when a base member shadows a primary constructor parameter if that primary constructor parameter was not\npassed to the base type via its constructor.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-05-15.md",
    "content": "# C# Language Design Meeting for May 15th, 2023\n\n## Agenda\n\n- [Breaking Change Warnings](#breaking-change-warnings)\n- [Primary Constructors](#primary-constructors)\n\n## Quote of the Day\n\n- \"The main point of closing the door is so that people who are slightly late feel that bit of embarrassment opening the door\"\n\n## Discussion\n\n### Breaking Change Warnings\n\nhttps://github.com/dotnet/csharplang/discussions/7033  \nhttps://github.com/dotnet/csharplang/blob/ab5afc419eed3d67bf064ec417f69a65aecbef5c/proposals/breaking-change-warnings.md\n\nOur previous issue on this feature had a large number of moving parts and generated a lot of interesting discussion. This discussion was good, but\nit left us wondering what a pared back and small-scale version of this proposal would look like: one where we simply did the break and very little\ninfrastructure around it, to avoid snowballing the proposal and adding many moving parts; in response, a small group sat down and made a minimal\nversion of this feature to see what that would actually look like. The minimal version of this is very simple; when using a newer .NET SDK with a\nnewer C# compiler targeting an older version of the language, warnings will be reported for any potential breaks detected. That's it, no flow\naround upgrading. LDM members had a few immediate concerns with this:\n\n* Is there any guarantee that users will actually enter this state? Particularly on systems where a new warning would fail the build, as opposed\n  to on a machine where a new warning in the list might be missed?\n* We have plenty of examples via MSBuild and NuGet where new warnings on toolset upgrade breaks our users. Is that something we're prepared to deal\n  with?\n    * All our new warnings on existing code (Warning Waves) are activated by an explicit user action; upgrading to a new version of .NET. This\n      would be the opposite.\n* If warnings are easily missed, should these be errors instead?\n    * There's some concern that this is too harsh: is it really necessary to break the build with no recourse other than downgrading the toolset?\n      There could be an opportunity to create a level between warning and error; diagnostics that appear as errors but are user-suppressible.\n* In general, catching the moment of upgrade in this system is hard.\n\nOne additional consideration that was raised is that we might be trying to force this in too quickly, for the purposes of getting `field` out in C#\n12 in its idealized form. If we instead made it so that C# 12 reported warnings, and the version after breaking the scenario. Unfortunately, this\nhas some of the same issues; there's no guarantee that C# 12 will actually be the migration target. It could be that user goes straight from 11, or\nfrom .NET Framework, or any other non-12 version. Even if we do LTS->LTS, there could still be missed warnings, and we'd also significantly delay\nnew features.\n\n#### Conclusions\n\nNo conclusions today. We've identified some significant problems with the minimal approach and need to keep thinking. We'll revisit again soon.\n\n### Primary Constructors\n\nhttps://github.com/dotnet/csharplang/issues/2691  \nhttps://github.com/dotnet/csharplang/blob/7bd6a9ff7f19df1e5fdbe18f593e5b18264b50da/proposals/primary-constructors.md#double-storage-warning-for-initialization-plus-capture\n\nFinally today, we looked at a small proposed potential double storage warning for primary constructors. We think this is completely inline with\nour previous decisions and approved it unanimously. Several members were surprised we hadn't already made this a warning.\n\n#### Conclusion\n\nApproved as proposed.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-05-17.md",
    "content": "# C# Language Design Meeting for May 17th, 2023\n\n## Agenda\n\n- [Inline arrays](#inline-arrays)\n\n## Quote of the Day\n\n- \"A strategy to hold ourselves hostage\"\n\n## Discussion\n\n### Inline arrays\n\nhttps://github.com/dotnet/csharplang/issues/1314  \nhttps://github.com/dotnet/csharplang/blob/7b5d0bbcd552e0541db4a5afdad3b75210037120/proposals/inline-arrays.md#the-foreach-statement\n\nFollowing up from a [previous discussion](LDM-2023-05-01.md#fixed-size-buffers) on inline arrays, we looked at `foreach` support for inline\narray types. The current implementation plan for `foreach` on these types is to do it via `Span<T>` or `ReadOnlySpan<T>`; as these are\n`ref struct` types, they cannot be `foreach`ed in an `async` method. This restriction makes sense for inline arrays sometimes, as they are\nmore likely to be passed around via `ref` than standard types. Refs can't live past an `await` boundary, so this makes sense for such\nvariables. However, it doesn't make as much sense for inline arrays that are local by value: for example, a local of an inline array type\nwould not be foreachable in an `async` method as proposed today. There are two possible improvements we could make here:\n\n1. Be more granular with `ref struct` usage in `async` methods. As long as the `ref struct` does not cross an `async` boundary, it should be safe\n   to reference. If we were smarter about `ref struct` usage in `async` methods, then inline arrays would simply come along for the ride. It's\n   not a perfect solution though, as there would still be errors for inline array values that can be safely lifted to a display class when a\n   `foreach` loop `await`ed in its body.\n2. Have special lowering for inline arrays for async methods. `ref`s to inline arrays would continue to be blocked in `async` methods, as today,\n   inline array values (mainly locals and parameters) can be safely lifted to a display class and iterated over across `await` boundaries\n   without any issues around observability of changes.\n\nThese solutions are not mutually exclusive; we can do either one, both, or none. What we are fairly certain of at this point, though, is that\nit is unlikely that we can fit either solution into C# 12. After some discussion, we decided that we are fine with shipping an initial version\nof inline arrays that restricts `foreach` in `async` methods, and later loosen restrictions on it as we can.\n\n#### Conclusion\n\nWe will support `foreach` over inline arrays, even if it starts as restricted in `async` methods. We will encourage alternate lowering strategies\nand smarter `ref` rules in async methods where we can, but that will be a longer-term effort.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-05-31.md",
    "content": "# C# Language Design Meeting for May 31st, 2023\n\n## Agenda\n\n- [Collection literals](#collection-literals)\n\n## Quote of the Day\n\n- \"You did not just say that\"\n\n## Discussion\n\n### Collection literals\n\nhttps://github.com/dotnet/csharplang/issues/5354  \nhttps://github.com/dotnet/csharplang/blob/main/meetings/working-groups/collection-literals/CL-LDM-2023-05-31.md\n\nToday we took a look at what the collection literals working group has been iterating on, and tried to answer a few of their open questions. We started by looking over\nthe list of preferable target-type construction patterns. The idea is to choose the most efficient construction pattern for a given collection literal, given that it\nhas a specific type. Importantly, while this list talks about preferable construction patterns, it does not talk about overload resolution and what a most-specific type\nwould be. Rather, the collection has already been typed by this point, and we are only trying to figure out how the collection will be constructed. There were a couple of\nconcerns brought up during this that the working group will take back to consider:\n\n1. Will there be potential breaking change issues here if we ever want to add a new type in the middle of this list, much like can happen in `foreach`?\n2. Should other non-BCL interfaces be able to participate in this mechanism? For example, could Rx.NET allow creating an `IObservable` sequence via a collection literal?\n\nWe also discussed what the behavior for `IEnumerable<T>` would be: what type should we emit here? Should it be a guaranteed concrete type like `List<T>`, or something\nelse? Or something entirely hidden? The main concern here is around downcasting and observability of that. It's important to note that while some downcasting is not an\nimportant scenario, some is entirely innocuous or even an important perf scenario: for example, `LINQ` will try to optimize known-length scenarios, which does involve\ntype testing and downcasts. Given that one of our focuses here is performance, we're not eager to have using collection literals introduce performance gotchas. However,\nif we said `List<T>` is guaranteed, that also removes some ability to do performance work; for example, representing `[]` with `Enumerable.Empty()`, or caching for\n`IEnumerable<int>`s composed of entirely `const` data. Given that, we don't think we want to commit to a single specific type. Instead, we want to work with the runtime\nto make sure that we can eke out every scrap of performance. The working group will explore the space of using unspeakable and/or immutable collection types here.\n\nFinally, we also looked at the `Create` method pattern proposed by the working group. We generally like the patterns, but think there potentially needs to be more.\nFor example, unknown-length collection construction does not work with the proposed patterns for `ImmutableArray`. We also considered whether these could just be static\nmethods on the type itself. The runtime is very against this, because these method patterns are somewhat unsafe for manual usage; for example, the `ImmutableArray` creation\nmethod returns a mutable `Span` to the backing storage, which is super dangerous. We keep these types of APIs on specific Marshal types today (`CollectionsMarshal`,\nfor example), specifically to avoid them appearing in the standard surface area of the type, and we want to continue this pattern.\n\nNo conclusions for today, but plenty for the working group to take back and continue iterating on.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-06-05.md",
    "content": "# C# Language Design Meeting for June 5th, 2023\n\n## Agenda\n\n- [Collection literals](#collection-literals)\n\n## Quote of the Day\n\nDue to an unfortunate notekeeping snafu, there are no records of funny things said today. They did exist, but they are lost to the annals of time.\n\n## Discussion\n\n### Collection literals\n\nhttps://github.com/dotnet/csharplang/issues/5354  \nhttps://github.com/dotnet/csharplang/blob/main/meetings/working-groups/collection-literals/CL-LDM-2023-05-31.md\n\nToday we [continued](LDM-2023-05-31.md#collection-literals) our review of the work the collection literals working group has been doing, this time\nlooking at dictionary creation patterns. We first thought about syntax, and the potential for ambiguous syntax. For example, this expresson would\nbe ambiguous:\n\n```cs\nDictionary<K, V> d = [a ? [b] : c]; // [a ? ([b]) : c)] or [(a ? [b]) : c]?\n```\n\nThere was also a question raised whether it might be useful to state from the literal itself whether it would be a dictionary or a sequence. For example,\n`[..dictionary1, ..dictionary2]` might want to prefer combining into a new dictionary, not a sequence of elements. To try and address these cases, we\nexplored whether there was some alternative syntaxes that would mark the literal as a dictionary literal and force dictionary semantics.\n\n* `[: a ? [b] : c]` - Leading `:`\n* `[: a ? [b] : c :]` - Leading and trailing `:`\n* `{ a ? [b] : c }` - Use `{}` for dictionary literals\n\nNone of these particularly resonated with the LDM. Further, no language that we can find that has dictionary literals differentiates them from collection\nliterals with an extra or different sigil, so there's no prior art to draw on. Given this, we don't think there needs to be a separate syntax for\ndictionary literals, and `[..dictionary1, ..dictionary2]` will have sequence semantics unless target-typed to a dictionary type (including dictionary\ninterfaces such as `IDictionary<TKey, TValue>`), or unless the literal contains a `key : value` element.\n\nNext, we thought about what semantics spreading dictionaries should have, when the literal will have dictionary semantics. For example, what would the\nfollowing code print?\n\n```cs\nusing System;\nusing System.Collections.Generic;\nDictionary<int, int> dictionary1 = [1 : 2];\nDictionary<int, int> dictionary2 = [1 : 3];\nM([..dictionary1, ..dictionary2]);\n\nvoid M(Dictionary<int, int> d)\n{ \n    foreach (var (k, v) in d) Console.WriteLine($\"{k} {v}\");\n}\n```\n\nThere are two possible behaviors: add behavior, where duplicate keys are error, or overwrite behavior, where the last instance of a key wins. There's two\ncompeting schools of thought here. In favor of add behavior, most of our existing methods have this behavior. `CreateRange`, the `Dictionary` constructor,\ncollection initializers as they exist today, etc. However, `[a : b]` looks more like an indexer, which does have overwrite semantics today. There also some\nconcern that, as we borrow this syntax from other languages, deviating too much from their behavior will introduce a quirk that is more gotcha than it is\nhelpful. Ultimately, we think that we should prefer overwrite semantics for this scenario.\n\n#### Conclusion\n\nNo special syntax for differentiating a dictionary literal beyond the `key : value` syntax for an individual element.  \nDictionary literals will use overwrite semantics, not add semantics.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-06-19.md",
    "content": "# C# Language Design Meeting for June 19th, 2023\n\n## Agenda\n\n- [Prefer spans over interfaces in overload resolution](#prefer-spans-over-interfaces-in-overload-resolution)\n- [Collection literals](#collection-literals)\n\n## Quote(s) of the Day\n\n- \"What's the second question?\" \"Type inference for collection literals.\" \"Oh that's easy\"\n- \"Second2, also known as third\"\n- \"Oh, I thought [redacted] was making a 'type inference walks into a bar' joke\"\n\n## Discussion\n\n### Prefer spans over interfaces in overload resolution\n\nhttps://github.com/dotnet/csharplang/issues/7276\n\nToday we looked at whether overload resolution should have special tie-breaking rules for the `Span<T>` vs `IEnumerable<T>` case. There are a\nfew cases that can this affect, and potentially blocks the runtime from adding overloads that take `ReadOnlySpan<T>` for fear of breaking users.\n\n```cs\nvar ia1 = ImmutableArray.CreateRange<int>(new[] { 1, 2, 3 }); // error: CreateRange() is ambiguous\nvar ia2 = ImmutableArray.CreateRange<char>(\"Test\"); // error: CreateRange() is ambiguous\n\npublic static class ImmutableArray\n{\n    public static ImmutableArray<T> CreateRange<T>(IEnumerable<T> items) { ... }\n    public static ImmutableArray<T> CreateRange<T>(ReadOnlySpan<T> items) { ... }\n}\n```\n\nFor both examples, these are types that are convertible to both a `Span<T>` and to `IEnumerable<T>`. There is no commonality between those two\ntypes, other than `object`, so the overloads are ambiguous. There are two questions here:\n\n* Do we want to mimic a subtype relationship between `IEnumerable<T>` and `Span<T>` as best we can without `Span<T>` actually implementing the\n  interface?\n* Is `Span<T>` special here? Are there other user-defined `ref struct`s that can run into this same problem with ambiguous overloads?\n\nWe're a bit concerned with chasing a subtype relationship here. Ideologically, `Span<T>` is indeed an `IEnumerable<T>`, but since `ref struct`s\ncannot implement interfaces today, the relationship isn't there. But that relationship plays in more than just overload resolution. Generics, for\nexample, which is another place `ref struct`s cannot be used today. It feels like trying to mimic the behavior as best as possible would be a\nlarge rabbit hole to go down, when we do want `ref struct`s to be able to implement interfaces at some point. Implementing that would solve this\nissue and in a more general fashion.\n\nWe also talked a bit about workaround the runtime could do for these cases. Defining more overloads is an obvious answer for some scenarios, such\nas the `ImmutableArray` case above. That could define `CreateRange<T>(T[] array)` and `CreateRange(string s)`; indeed, this is the solution that\n`DefaultInterpolatedStringHandler` used to avoid ambiguities in `AppendFormatted`. But that doesn't work in every case. For example, constructors\nof generic types cannot have specialized versions for a specific generic. In other words, `HashSet<char>` (and only `HashSet<char>`) cannot have\na constructor that takes a `string` to resolve that ambiguity. Extensions might be able to solve that, but it doesn't seem like it would give the\nactual end experience we want, namely the subtype relationship between `Span<T>` and `IEnumerable<T>`. Given this, we plan on waiting until\n`ref struct`s can implement interfaces and then all of these issues will work themselves out with no additional rules needed.\n\n#### Conclusion\n\nNo language change here.\n\n\n### Collection literals\n\nhttps://github.com/dotnet/csharplang/issues/5354  \nhttps://github.com/dotnet/csharplang/pull/7284\n\nWe also looked at the proposed type inference for collection literals. We explored our existing behavior here around several areas:\n\n* Collection initializers on arrays - Arrays are not target-typed today, so conversion-from-expressions do not carry through the collection\n  initializer here. We think this actually makes array collection initializers a _poor_ analogy for where to draw behavior from.\n* Switch expressions - These are target typed, and arm types can influence the type inference of a method.\n* Tuple literals - These might be the best analogy. They are target typed, and have a general desired behavior of \"you should be able to replace\n  the tuple with the elements and have the same behavior\". In other words, for a signature of `M<T>((T, T) tuple)`, passing a tuple literal\n  should have the same outcome as passing each element individually to a signature of `M<T>(T t1, T t2)`.\n\nWe like the tuple analogy for collection literals. The behavior we want is the equivalent, spelled out as:\n\nIf there is a signature `M<T>(T[] array)`, passing a collection literal of `[1, 2]` should have the same effect as if the signature was\n`M<T>(T t1, T t2)`.\n\n#### Conclusion\n\nTreat collection literals transparently for type inference.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-07-12.md",
    "content": "# C# Language Design Meeting for July 12th, 2023\n\n## Agenda\n\n- [Collection Literals](#collection-literals)\n    - [`Create` methods](#create-methods)\n    - [Extension methods](#extension-methods)\n- [Interceptors](#interceptors)\n\n## Quote of the Day\n\n- \"I prefer the correct pronunciation, in-foof\"\n\n## Discussion\n\n### Collection Literals\n\nhttps://github.com/dotnet/csharplang/issues/5354  \n\n#### `Create` methods\n\nhttps://github.com/dotnet/csharplang/blob/52b90748d1ebab0268468eb5dc8e954bc98c2834/proposals/collection-literals.md#create-methods\n\nWe started by looking at the initialization pattern the working group and the BCL team have been working on. This pattern has changed a bit from the last\ntime it was presented: now, instead of an `out Span` that the compiler would write into, the compiler passes in a `ReadOnlySpan`, which the collection will\nthen copy out of. Methods would be discovered by looking for a specific attribute on the target type, which then tells the compiler what the build type is\nand what method name to look for. This has some amount of `methodof` to it, but in a much more restrictive sense; overload resolution is not involved at all.\nThe compiler looks for a method in the type explicitly referenced, with the name explicitly specified, with exactly the parameter list `ReadOnlySpan<TElement>`.\nQuestions of things like default parameters or element type conversions don't play into it. Given these restrictions, we're ok with this pattern. It might be\nexpanded in the future, but we think that our bases on breaking changes are well covered.\n\n##### Conclusion\n\nPattern approved, modulo BCL naming feedback.\n\n#### Extension methods\n\nhttps://github.com/dotnet/csharplang/blob/e566e33620e3f6671a7042a3e23cd1120ff04c76/proposals/collection-literals.md#extension-methods\n\nNext, we turned our attention to extension methods on collection literals. There were a few components to our discussion. First, assumed that extensions were\nallowed, and thought about element type conversions; put simply, would this work?\n\n```cs\nvar byteArray = [4].ToArray<byte>(); // Converts from int->byte\n```\n\n[Previously](LDM-2023-06-19.md#collection-literals), we made an analogy between collection literals and tuples. We think that analogy applies here, as an\nequivalent extension method would not work on a tuple, nor would it work for just an integer literal.\n\nNext, we looked at the broader scenario. These extension methods really exist for two reasons:\n\n* Allowing the compiler to infer the element type of a collection, while still providing explicit information about the collection type.\n* Allowing the type information to be put on the right side of the collection.\n\nBoth features seem orthogonal to collection literals (https://github.com/dotnet/csharplang/issues/1349 is the former, and\nhttps://github.com/dotnet/csharplang/issues/4076 is very similar to the latter). Moreover, other typeless expressions seem like they could benefit from similar\ntreatment. There's therefore a 3rd possible orthogonal feature:\n\n* Allow extension methods on expressions with no natural type.\n\nIn any case, we think that this is a separate enough feature that we don't want to roll it in with collection literals, but instead want to take the time to\nexplore the 3 options here to their conclusions for C# 13.\n\n##### Conclusion\n\nExtension support specifically for collection literals rejected, we will explore the broader features for C# 13.\n\n### Interceptors\n\nhttps://github.com/dotnet/roslyn/blob/d71ec683082104e9122a4937abc768710c5f7782/docs/features/interceptors.md\n\nFinally today, we took another look at the current state of interceptors. When we last discussed them and decided that they should be a compiler feature, we\nchanged how we thought of the general idea; we now consider it effectively an instrumentation step, similar to inserting sequence points for debugging purposes.\nSince then, there's been a decent amount of development progress, one of the most controversial among the LDM is the removal of `InterceptableAttribute`. There's\ntwo main lines of argument here:\n\n* Opposing the change, there's concern about spooky action at a distance. In some ways, removing the attribute turns this feature into an unrestricted `comefrom`,\n  otherwise known as the satirical inverse to `goto`. There were also arguments that this is very similar to `InternalsVisibleTo` vs `IgnoreAccessChecksTo`; the\n  compiler supports the former, but not the latter.\n* Supporting the change, if a user came to the BCL and asked them to put `Interceptable` on some public API, when could the BCL realistically say no? These are\n  are public APIs, not like the internal implementation details that access checks exist to protect. The user _can_ work around them by just calling a different\n  method (possibly even just adding an extension with the same signature, just with `Interceptable` appended to the name), so the original method author being\n  involved in the decision is odd.\n\nAnother thing that's important to note is that this feature is very explicitly still experimental, and will still be experimental in .NET 8, so we're not locked\ninto any decision permanently if we determine that it's incorrect after some end-user testing.\n\nWe did not reach any conclusions here today, but the interceptors group has a good amount of feedback to go discuss and come back to in a couple of weeks.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-07-17.md",
    "content": "# C# Language Design Meeting for July 17th, 2023\n\n## Agenda\n\n- [Compiler Check-in](#compiler-check-in)\n- [`readonly` parameters](#readonly-parameters)\n\n## Quote of the Day\n\n- \"Entra (ɛntrə) or Entra (ɑːntrə)?\" \"Depends on where you're from\" \"I can azure you there will be no questions about pronunciation\"\n\n## Discussion\n\n### Compiler Check-in\n\nhttps://github.com/dotnet/roslyn/blob/673caaadc9780ad19d2295874607b635b017e0e3/docs/Language%20Feature%20Status.md\n\nTo start, we wanted to check in with the features that the compiler is currently working on, when they're going to be shipping, and\nwhether we need to rename any of them.\n\n* Inline Arrays\n    * We're good with the name of this one.\n    * Shipping in C# 12\n* nameof accessing instance members\n    * We're calling this `enhanced nameof` to a broader audience, but this is fine for a status page and for more specific documentation.\n    * Shipping in C# 12\n* Primary Constructors\n    * We have existing name precedence from records and from other languages, so we're good with this name.\n    * Will be shipping in C# 12.\n* Semi-auto props\n    * Unfortunately, this one won't make C# 12.\n    * Name isn't great. Many of us think it should have `field` in it somewhere, as that's what we've been internally calling it.\n    * `field access for auto properties` is the proposal.\n* `params Span`\n    * This won't make 12, as it needs inline arrays to be implemented.\n    * There are also potential issues around https://github.com/dotnet/csharplang/issues/7276 when adding new overloads that take `params Span<T>`\n      that we'll need to address.\n    * We're ok with the name of the feature at least.\n* lambda default parameters\n    * We're fine with this name.\n    * Will be shipping in C# 12.\n* Default in deconstruction\n    * Fine with the name, there are still some LDM questions to answer.\n    * Not shipping in C# 12.\n* Collection literals\n    * We're worried that using the word literal here conveys the wrong first impression. Literals in C# are immutable (`unsafe` string buffer manipulation\n      nonwithstanding), while these expressions are not; they give you a collection that is as mutable as the target type allows for. We suggested a few\n      alternatives, and settled on Collection Expressions.\n    * Will be shipping in C# 12.\n* Roles/extensions\n    * The name in this file needs to be renamed to catch up to the current feature name `extensions`, but as this will only be in preview for C# 12 we\n      aren't tied to the name yet.\n    * In preview for C# 12.\n* Interceptors\n    * The name is the least controversial thing about this feature.\n    * In preview for the C# 12 compiler.\n* ref readonly parameters\n    * Name works for the specific feature, though some of the broad docs might put it in a general ref enhancements bucket.\n    * Will be shipping in C# 12.\n\n### `readonly` parameters\n\nhttps://github.com/dotnet/csharplang/issues/188  \nhttps://github.com/dotnet/csharplang/blob/ee2c62fbacf3e84457198624c71abdca326c2cd8/proposals/readonly-parameters.md\n\nFinally today, we looked at a proposal for `readonly` parameters. This is a long-requested and highly-upvoted issue on the csharplang repo, but various\nmembers of the LDM have pushed back on it as not delivering enough value for the level of change it would bring. In particular, much of the LDM is\nconcerned that adding `readonly` to parameters and locals changes what default \"good C#\" looks like. This is similar to initial designs of the nullable\nreference type feature, where we indicated non-nullability with a `!`, instead of indicating nullability with a `?`; for that feature, we felt that the\nideal version of code requiring `!` modifiers everywhere was surprising and not where we wanted the language to be in 5 years. In the case of nullable,\nthe scope of the problem being addressed was big enough that we felt comfortable adding an entire new dialect (via the `#nullable` directives) to move\nthe language over to the new defaults. For `readonly` on parameters and locals, we feel similarly that we don't want the default of the language to be\nlong modifiers on all parameters and locals, but are unconvinced that the scale of the problem is large enough to warrant language dialects like we did\nfor nullable, given the narrow scope of locals and parameters.\n\nThis calculus changes in the face of primary constructor parameters. These can get captured into the state of an entire type, potentially spread across\nmultiple partial parts, and the safety benefits are therefore more substantial. We've received significant feedback, both internally and externally, that\ncapturing primary constructor parameters is being considered \"off limits\" until they can be marked `readonly`. Given the previous concerns about the look\nof \"good\" C#, we are very inclined to restrict this to just primary constructors, at least initially, though the proposal does somewhat dictate the course\nof what both locals and parameters would look like if we were to do so. There's also an interesting question on `readonly struct`s, as we make the\nall the parameters implicitly `readonly` today; we require `readonly` on all fields in such a struct, do we need to require it on all parameters as well?\n\nAnother question raised was whether we should re-examine the default mutability of primary constructor parameters. Perhaps the least surprising thing is\nto have the parameters as immutable, and require explicit field declaration when mutability is desired. There's some conflict here: how does that interact\nwith `record struct`s, where the generated properties are mutable by default? And will that impact future designs in this space?\n\nFinally, we want to make sure that we don't lock ourselves out of any future feature work here. There's some feeling in the LDM that we'll eventually\nallow ways of declaring that a primary constructor parameter is a part of the class state, either as a field or as a property. We need to more completely\nexplore this space and make sure that allowing `readonly` on a primary constructor parameter does not lock us out of such a future feature.\n\n#### Conclusion\n\nEnough interest to look at this in more depth, but in a more restricted form than initially proposed.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-07-24.md",
    "content": "# C# Language Design Meeting for July 24th, 2023\n\n## Agenda\n\n- [Method group natural types with extension members](#method-group-natural-types-with-extension-members)\n- [Interceptors](#interceptors)\n\n## Quote of the Day\n\n- \"This conversation feels like it's gotten a little too much information\"\n\n## Discussion\n\n### Method group natural types with extension members\n\nhttps://github.com/dotnet/csharplang/issues/7364\n\nFirst up today, we looked at a potential source of confusion that was brought up during the prototyping of extensions. Our current rule was\ncreated to protect against a potential breaking change in this scenario:\n\n```cs\nvar c = new C();\nvar d = new D();\nd.Del(c.M); // Today, this calles DExt.Del. With the change, it would call D.Del\n\npublic class C\n{\n    public void M() { }\n}\n\npublic static class CExt\n{\n    public static void M(this C c, object o) {}\n}\n\npublic class D\n{\n    public void Del(Delegate d) {}\n}\n\npublic static class DExt\n{\n    public static void Del(this D d, Action<object> action) {}\n}\n```\n\nHowever, this seems like an unlikely scenario, and it's inconsistent with how extensions behave in this same scenario when all the signatures line up.\nIt is also in conflict with general extension lookup, which goes scope by scope. We are generally in favor of making this change, though we do need to\nvalidate that it is not breaking to ASP.NET scenarios. The other remaining question is whether we can make this change retroactively, or if it needs to\nbe a full language change in C# 13. We do have some precedence for making \"spec bugfixes\" after the initial release of the feature, but those are nearly\nalways done within months of the initial release of a feature; we're over a year and a half past the release of C# 10 at this point, and there are very\nrealistic scenarios where developers could have VS 17.8/9 on their local machines, observing one behavior, and then have the .NET 6 SDK in CI, where a\ndifferent behavior would be observed. We therefore don't think we can make this change as a bugfix, and that it will need to be a gated change in C# 13.\n\n#### Conclusion\n\nChange is approved for C# 13.\n\n### Interceptors\n\nhttps://github.com/dotnet/csharplang/issues/7009  \nhttps://github.com/dotnet/csharplang/discussions/7373\n\n[Continuing](LDM-2023-07-12.md#interceptors) our review of interceptors, we looked at where experimental feature is being depended on in .NET 8.\nASP.NET is planning on shipping it as part of their AOT scenario work, and has committed to doing the servicing work in the .NET 8 SDK to make sure\nthat they adapt to any potential breaking changes that the compiler may introduce in the feature, up to and including falling back to extension method\noverload resolution tricks if the feature is pulled entirely. Such tricks do have cost, particularly in startup time of ASP.NET apps; given that AOT\nand startup time will continue to be a big focus of .NET, this would be an option of last resort.\n\nPrevious LDM meetings suggested that we wanted to look at interceptors as a compiler feature, rather than a language feature. Unfortunately, the general\nspace is basically impossible to make such a distinction with. It still needs to have tooling support at some point, is still C# specific, and is basically\nhijacking overload resolution. This approach is necessitated for all the reflection-based scenarios that use information that exists outside the type\nsystem to affect runtime code; because these scenarios use information not statically available during compilation, it is hard to make them AOT-compatible.\nTo address this, we think that we need to take another look at the scenarios that are considering interceptors and see if we can put that information back\ninto the type system: are there features like string value types that we could leverage to avoid needing these type-system adjacent features? We will be\nforming a working group to drill down to the specific cases looking at interceptors, dive more deeply into what exactly they need, and what we can do to\naddress them within the language.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-07-26.md",
    "content": "# C# Language Design Meeting for July 26th, 2023\n\n## Agenda\n\n- [Primary constructor parameters and `readonly`](#primary-constructor-parameters-and-readonly)\n\n## Quote of the Day\n\n- \"`record`s, the other white meat\"\n\n## Discussion\n\n### Primary constructor parameters and `readonly`\n\nhttps://github.com/dotnet/csharplang/issues/2691  \nhttps://github.com/dotnet/csharplang/issues/188  \nhttps://github.com/dotnet/csharplang/discussions/7377  \nhttps://github.com/dotnet/csharplang/blob/bc2c69e6f2bd28373e341effaa1182ebcb7ea72c/proposals/readonly-parameters.md\n\nContinuing on from [last Monday](LDM-2023-07-17.md#readonly-parameters), we took a look at the broader space of primary constructor parameters,\ntheir default mutability, and how we want to address community feedback in this space. With the exception of `!!`, this is the most feedback we've\never gotten on a preview feature, and if we want to address this in any way other than adding a `readonly` modifier at a later date, we need to\ndecide that very soon. Broadly speaking, the feedback we've seen is requesting that users want to be able to be confident that type state is not\nbeing modified, and that the compiler will help them enforce this. We see a few ways of addressing this:\n\n1. Do nothing. Leave primary constructors as mutable, and do not plan on addressing this. If a user wants to enforce readonly class state, they should\n   declare a class member (field or property), explicitly assign into that member, and use that member, not the parameter.\n2. Plan on adding a `readonly` keyword. This keyword may come with C# 12, but might also be delayed until C# 13. There are open questions as to\n   what this keyword would mean: would it follow field `readonly`, where the parameter capture would actually be mutable during initialization, or not?\n   But by default, primary constructor parameters would always be mutable unless otherwise specified.\n3. Follow the default established by record primary constructors. This would mean that all primary constructor parameters would be mutable during\n   initialization (as in all `record` types today), but for `class`es and `readonly struct`s, they would be readonly after construction.\n4. Have all primary constructor parameters on non-record types be always `readonly`.\n\nThis is a big list of options, and worse, they come with various correspondences to existing things in the language. Option 1 is parameters as they\nexist today: they're always mutable, for better for or for worse. Option 2 corresponds with thinking of primary constructor parameters as baby type\nmembers: they start with the same set of defaults that normal type members have, and then we might at some point add the ability to promote them inline\nto full type members, with all the same defaults that other type members get. Option 3 corresponds to records as they exist today, and if we take an\nopinionated stance on primary constructor parameters now, it might allow us to continue to take an opinionated stance for future features more easily.\nFor example, maybe `public int I`, as a primary constructor parameter, could always mean a `get`-only property. Option 4 is the one the stands out here,\nas it doesn't really correspond to existing language principles in any way today. It is a position that many LDM members might wish we'd taken from the\nstart of the language, but isn't really in line with any prior art in the language, which we feel would be a negative surprise.\n\nAny form of readonly by default is proving to be a contentious topic. There is a nasty footgun that comes with this for mutable value type parameters,\nwhere silent copies can occur without an explicit `readonly` somewhere in the user's code. This is something that can bite even experienced users with\ntoday's semantics where `readonly` must be opted into, and it seems likely that a `readonly`-by-default decision might make that worse. At the very\nleast, we may want to consider a warning when calling a non-`readonly` member on a primary constructor parameter.\n\nAnother point of concern is when `readonly` comes into force. It seems likely to us that some amount of validation and value clamping may want to\nbe done as part of initialization; should that require declaring a full member? Or should the parameter be mutable during initialization, so that\nvalidation steps can occur? This is more of a future correspondence question than it is a concern for C# 12/13; if we do choose to allow `readonly`\nprimary constructor parameters to be modified during initialization, that sets a precedent for what `readonly` on a parameter means. This then informs,\nand potentially harms, the ability to use `readonly` as a general parameter modifier later on in the language's lifetime, since it would have a\ndifferent meaning there. While the LDM's opinion on that feature hasn't changed, it is something important to consider.\n\nWe also looked at the topic of boilerplate, and how much we would harm the general reduction of boilerplate by making things `readonly` by default. We're\npretty universally against adding a new `mutable` keyword to C#; that would mean that, in order to get mutable state, users would be required to fall back\nto using a full field. In the other direction, in order to have `readonly`ness in a feature where mutable parameters are the default, users would be required\nto put `readonly` on the parameter, just as they are required to do for fields. While we do think that more object state is effectively readonly than is\nnot, some members are concerned that enough state is mutable (and actually mutated) that the `readonly`-by-default solution would not help as many users\nas the mutable-by-default version. Importantly, this isn't just a war on boilerplate for the sake of brevity: there is mental tax that comes with repetitive\nboilerplate that we would like to avoid.\n\nAnother argument (yes, there's still more to go) in the future evolution space was how far we're prepared to go with primary constructor parameters. We've\nlooked at promotion to members: what about when those members need to have more complicated logic? Where is the dividing line between \"This can be a\nprimary constructor parameter\" and \"this must be a full member\"? We don't want to ship something that needs a decoder ring to understand, which is something\nthat we're concerned about if we did option 3 and then allowed promoting to full type members. We think we'd have reasonable and understandable defaults for\n`private` and `public`: `private` fields, `public` properties. But we are worried about `protected`; sometimes they're effectively part of the public\nAPI, and properties are the best choice. Other times, they're effectively `private protected`, and fields are the better choice. There's a potential soup\nof modifiers and features here that could be extremely confusing to readers, which is something we want to be very careful of.\n\nConsidering all of this, we are about split between options 2 (add `readonly` as a modifier) and 3 (match records). This means that option 1 (do nothing)\nand option 4 (always `readonly`) can be excluded. We think we need a few days to consider these options before coming back as a group on Monday to make a\nfinal decision.\n\n#### Conclusion\n\nWe've eliminated two options. We'll come back Monday to conclude on this topic.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-07-31.md",
    "content": "# C# Language Design Meeting for July 31st, 2023\n\n## Agenda\n\n- [Primary constructor parameters and `readonly`](#primary-constructor-parameters-and-readonly)\n\n## Quote of the Day\n\n- \"Maybe I damaged my brain in the sun\"\n\n## Discussion\n\n### Primary constructor parameters and `readonly`\n\nhttps://github.com/dotnet/csharplang/issues/2691  \nhttps://github.com/dotnet/csharplang/issues/188  \nhttps://github.com/dotnet/csharplang/discussions/7377  \nhttps://github.com/dotnet/csharplang/blob/bc2c69e6f2bd28373e341effaa1182ebcb7ea72c/proposals/readonly-parameters.md\n\nWe picked up again from [last Wednesday](LDM-2023-07-26.md#primary-constructor-parameters-and-readonly). To restate the options we'd started with in that meeting:\n\n1. Do nothing. Leave primary constructors as mutable, and do not plan on addressing this. If a user wants to enforce readonly class state, they should\n   declare a class member (field or property), explicitly assign into that member, and use that member, not the parameter.\n2. Plan on adding a `readonly` keyword. This keyword may come with C# 12, but might also be delayed until C# 13. There are open questions as to\n   what this keyword would mean: would it follow field `readonly`, where the parameter capture would actually be mutable during initialization, or not?\n   But by default, primary constructor parameters would always be mutable unless otherwise specified.\n3. Follow the default established by record primary constructors. This would mean that all primary constructor parameters would be mutable during\n   initialization (as in all `record` types today), but for `class`es and `readonly struct`s, they would be readonly after construction.\n4. Have all primary constructor parameters on non-record types be always `readonly`.\n\nWe'd eliminated option 1 and 4 during that meeting (4 very decisively, 1 not very decisively), leaving options 2 and 3. One important clarification we made in this\nmeeting, though, was that 1 and 2 are not actually mutually exclusive. Many members of the LDM would be fine shipping C# 12 with 1, and then doing a `readonly` keyword\nin C# 13. So we're really debating between 2 and 3, but not necessarily committing to doing 2 before C# 12 ships.\n\nThe main thrust of the debate between 2 and 3 is the presence of opinion in mainline C# code that is different than C# opinion elsewhere in mainline code. Parameters\nare always mutable by default in C#, as are fields; it's only in automatically generated `record class` that we default to `readonly` (or more specifically, `init`).\nSo no matter where we end up on this issue, we have a decoder ring for users: either we need to explain why we chose to make primary constructor parameters `readonly`,\nor why we chose to make `record`s different than the rest of the language. This distinction revealed an important point in the debate, however: are we bringing primary\nconstructors, as created by `record`s, back to the rest of the language, or are we bringing existing creation patterns forward with primary constructors, and viewing\n`record`s as a step further?\n\nOne thing LDM was immediately unanimous on was not wanting a `mut` or `mutable` keyword, even if we were to go with option 3. We don't have such a concept elsewhere\nin the language, and needing to add it here is immediately concerning. We also investigated whether we can confidently promote primary constructor parameters to full\ntype members in a simple fashion: could we, for example, have `private` automatically turn into a `private readonly` field, and `public` automatically turn into a\n`public { get; init; }` property? We're not sure about this either: `private` seems fine, but the `public` version feels iffy. Is `init`, as in `record`s, the right\ndefault? And if it's not, is that yet another area where we'll need to explain the differences between `record`s and non-`record`s?\n\nIn terms of evolution, there also a number of LDM members who are concerned about the slippery slope that is evolution in the first place. How far should we plan on\ntaking this? We start with simple member declarations, but then those declarations might need validation, default values, differing public and private names, the\nability to specify partial when we eventually allow `partial` properties, etc. At what point do we say that we've gone far enough and that any further member-like\nthings need to be actual type members? It's clear that will be a question for our future selves, and that it's unclear where we'll land when we get there.\n\nWe finally turned back to the question of what direction of evolution we are intending for primary constructor parameters. Another way of looking at this question is:\nif we had flipped the design order, delivering primary constructor parameters before `record`s, instead of the other way around, would we be doing anything differently?\nWe don't think so: when we look at how we want to explain the language, we think that there's a core set of rules around mutation that apply everywhere in the language,\n_except_ for `record`s. `record`s exist to allow C# users to work with data more easily, and they contain a number of opinions that make this easier, from value-based\nequality to `readonly`ness for reference types. We think that this is the C# we want to explain; the alternative would be explaining that primary constructors differ\nfrom the rest of C# by bringing in opinions from `record` types. It would potentially be easier to explain to existing users, but harder to explain the language\nphilosophy as a whole. We therefore conclude that primary constructor parameters will ship in C# 12 as is. We will prioritize work on a `readonly` modifier for primary\nconstructor parameters, including figuring out whether this modifier will mean `readonly` like it does for fields, where it is mutable during initialization, or if\nwill mean fully `readonly`, with no ability to mutate at all. This may not make it into C# 12, but we will target early previews of C# 13.\n\n#### Conclusion\n\nPrimary constructor parameters will ship as mutable-by-default, and we will investigate the `readonly` parameter modifier shortly.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-08-07.md",
    "content": "# C# Language Design Meeting for August 7, 2023\n\n## Agenda\n\n- [Improvements to method group natural types](#improvements-to-method-group-natural-types)\n\n## Quote of the Day\n\n- \"I've never said I'm not a hypocrite\"\n\n## Discussion\n\n### Improvements to method group natural types\n\nhttps://github.com/dotnet/roslyn/issues/69222\n\nThe proposal is a possible improvement over the mechanism decided on [July 24th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-07-24.md#method-group-natural-types-with-extension-members), where the uniqueness of a method group that allows it to have a natural type is determined scope by scope rather than across all possible instance and extension methods.\n\nIn that proposal, an instance or extension method can still be considered to apply, even if it would later be rejected by subsequent checks. For instance, type arguments might not satisfy constraints:\n\n``` c#\nvar x = new C().M<int>; // CS8917\tThe delegate type could not be inferred.\n\npublic class C\n{\n    public void M<T>() { }\n    public void M<T>(object o) where T : class { }\n}\n```\n\nThe proposal is to move these checks earlier, removing failing candidates so another candidate can be unique.\n\nThis additional pruning would cause us to depend on more details: It would succeed in more scenarios but at the cost of being more vulnerable to changes in those details. However, we accepted those same tradeoffs in method invocation scenarios several versions ago during a round of overload resolution improvements. This seems equivalent.\n\nThe proposal would incur slight breaking changes. They seem fairly negligible, but we should give it time in preview to confirm that we are not missing scenarios. \n\n#### Conclusion\n\nChange is approved. It will not be in C# 12, as we need bake time in preview to confirm that breaks are acceptable.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-08-09.md",
    "content": "# C# Language Design Meeting for August 9, 2023\n\n## Agenda\n\n- [Lambdas with explicit return types](#lambdas-with-explicit-return-types)\n- [Target typing of collection expressions to core interfaces](#target-typing-of-collection-expressions-to-core-interfaces)\n- [Loosening requirements for collection builder methods](#loosening-requirements-for-collection-builder-methods)\n\n## Discussion\n\n### Lambdas with explicit return types\n\nhttps://github.com/dotnet/roslyn/issues/69093\n\nFor method arguments that are lambdas with explicit return types (and hence also explicit parameter types), this proposal removes the requirement that the lambda body bind correctly from overload resolution. As best we can tell, the requirement is vacuous, and no breaking behavior would come of this change. \n\nThe check is known to be algorithmically heavy in nested scenarios, and can cause an IDE to be bogged down for a considerable time. This is the case for implicit lambdas as well, but by removing the check from explicit lambdas, those could be a fallback for code that currently runs into this problem.\n\n#### Conclusion\n\nApproved. We couldn't think of any way this would cause a change in semantics.\n\n### Target typing of collection expressions to core interfaces\n\nhttps://github.com/dotnet/csharplang/blob/main/meetings/working-groups/collection-literals/Core-interface-target-type-proposal.md\n\nWhat should C# do when a collection expression is target typed (implicitly converted) to one of the core interface types (\n`IEnumerable<T>`, \n`IReadOnlyCollection<T>`,\n`IReadOnlyList<T>`,\n`ICollection<T>` and \n`IList<T>`, plus their non-generic counterparts)?\n\n``` c#\nIEnumerable<int> numbers = [ 1, 2, .. otherNumbers, 3 ];\n```\n\nIf we allow this at all, we need to decide how a value of a concrete type is obtained for each interface. Our choice here will impact several key aspects of the design:\n\n- Simplicity - it's easy to explain.\n- Universality - it works everywhere.\n- Brevity - you rarely need to embellish (with casts or the like).\n- Performance - it maintains or improves performance compared to manually written creation code.\n- Safety - avoids unwanted and surprising mutations through downcasting.\n\nWe considered the following general approaches:\n\n1. Do not allow target typing to interfaces\n2. Specify and guarantee corresponding concrete types\n3. Transparently pick concrete types as an implementation detail\n\nThe argument for supporting target typing to the core interfaces is that it will be very common. Especially many APIs (about 25% of all collection-taking APIs) take `IEnumerable<T>`. If we go with option 1, collection expressions will not satisfy the goal of replacing the overwhelming majority of collection creation scenarios.\n\nWe've postponed other aspects of collection expressions (natural types, dictionary expressions) to future versions of the language, but this scenario seems much more mainline, and would be hard to live without.\n\nThe language already has special knowledge of these interfaces: Arrays are allowed to implicitly convert to them, and the `IEnumerable` interfaces are consumed by `foreach` and produced by iterators. So building specific behavior into the language for them would be nothing new.\n\nOption 1 would only be the best option if we cannot make a good choice on behalf of the user. Option 2 and 3 are different strategies for how to make that default choice for them.\n\nWith option 2 we specify exactly which type gets instantiated for each interface. The option is very simple to understand if we pick a single type across all interfaces (e.g. `List<T>`), but that is not great for performance (`List<T>` always comes with two allocations, extra space to support mutation, etc.) or for safety (you can cast and mutate from the read-only interfaces). Alternatively we can pick different concrete types for each interface, but now it's a lot less simple! Also, for the read-only interfaces (including `IEnumerable<T>`) we don't actually have ideal concrete types in the BCL today.\n\nOption 3 gives us full freedom to pick ideal concrete types for each interface, or even different types for the same interface, depending on specific circumstances. In fact, the compiler can synthesize a brand new type for a given occurrence if that's the right trade-off, or the runtime can provide specifically optimized types that aren't in the normal public line-up. We could change our minds on the specifics from release to release, since users can't (easily - and definitely shouldn't!) take a dependency on the specific choices we make.\n\nFor the readonly interfaces, we could probably get significant performance optimizations. We could inline values, eliminate the count, reuse the object as its own enumerator to save an allocation (we use this trick in iterators today), etc. For empty collections we could reuse the same object every time.\n\nFor the mutable interfaces, `List<T>` would actually be a fine choice. However, even if we use it, we wouldn't guarantee it version over version.\n\nThe approach of not telling you the exact type already has precedence in the language in the form of iterators, as well as in the BCL through LINQ query operators. The philosophy is also similar to pattern matching, where the logic of a `switch` is highly optimized, and usually faster than what the user would have manually written.\n\nLooking to the future, there aren't good existing dictionary types to implement `IReadOnlyDictionary<TKey, TValue>`, and the optimal implementation strategy would depend heavily on e.g. the size of the dictionary. We could probably generate much better ones than could be provided in the BCL, because we can let the circumstances decide.\n\nWith option 3 users can't get a clear answer to what type we create. On the other hand, being able to tell people we will give them *a really good one* has its own simplicity! The upshot is that option 3 is simple only if the user can trust us to do so remarkably well in the overwhelming majority of cases that they never have to think about it.\n\nWe can't ignore the non-generic core interfaces (`IEnumerable`, `ICollection` and `IList`). They probably don't change the overall decision, but they should be handled. Many APIs and frameworks, especially older ones, rely on these, but not actually often as a target type. More commonly they come in as `object` and are type-tested against these interfaces at runtime. So while target typing *should* of course work for the non-generic interfaces, it is in fact more important that the concrete types we provide for the *generic* interfaces  also implement the appropriate corresponding *non*-generic interfaces. That way, those type-discovery scenarios would work well over collections generated from collection expressions.\n\nThere's a more general question about type tests in option 3. If we do use a public type, people could discover it. Or they could discover any other collection interfaces that the thing implements. The latter might not be uncommon, so we should make deliberate decisions about that.\n\nAs a final consideration, this decision might intuitively seem linked to the (currently postponed) question about natural types for collection expressions - what do you get when you use `var`?. However, the situations are different: With interfaces there's a clearly stated surface area to match, and it's ok for the concrete type not to be able to do anything else. For natural types there's a much more complex decision about what surface area to provide by default when people don't give a type, and there's no particular reason for that design choice to be linked to target typing.\n\n### Conclusion\n\nWe unanimously support option 3. We don't want to give even the most performance-conscious users any reason to shun collection expressions. We like the wiggle room for further optimizations in the future, and we think it is simplifying for the user not to have to care about exactly what gets generated. It fits the declarative motto of saying the \"what\", not the \"how\".\n\nThe working group will decide on the specifics for each target interface. \n\n### Loosening requirements for collection builder methods\n\nhttps://github.com/dotnet/csharplang/issues/7396\n\nOne of the ways types can support collection expressions is through a builder pattern. An example in the BCL is `ImmutableArray<T>`. We put a `[CollectionBuilder(...)]` attribute on it to say where to find a suitable factory method, in this case the existing `ImmutableArray.Create` static method.\n\nIn the BCL we have an interface `IImmutableList<T>` as well. The BCL could choose to point it to *another* factory method, but not the same one as above, because our current rule says the method must return the *exact* target type. This seems overly restrictive, and the proposal is to allow certain implicit conversions from the return type of the method to the type carrying the attribute. There's a range of choices around which conversions to allow. In order from loosest to tightest:\n\n1. Allow any implicit conversion.\n2. Allow standard conversions (excludes user-defined conversions).\n3. Allow reference and boxing conversions.\n4. Allow identity conversions only (i.e., don't fix the scenario).\n\n#### Conclusion\n\nWe support option 3, reference and boxing conversions. It's a reasonable but conservative compromise that solves the scenario we have today, without forcing us to think through too much weirdness.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-08-14.md",
    "content": "# C# Language Design Meeting for August 14, 2023\n\n## Agenda\n\n- [Betterness for collection expressions and span types](#betterness-for-collection-expressions-and-span-types)\n- [Type inference from collection expression elements](#type-inference-from-collection-expression-elements)\n- [Collection expression conversions](#collection-expression-conversions)\n\n## Discussion\n\n### Betterness for collection expressions and span types\n\nhttps://github.com/dotnet/csharplang/blob/main/meetings/working-groups/collection-literals/CL-LDM-2023-08-14.md#overload-resolution\n\nOverload resolution will generally consider a more \"specific\" overload better. Normally \"specificity\" is expressed through the existence of an implicit conversion from the more to the less specific, but occasionally we need another measure of specificity in the betterness rule. One previous example of this is [interpolated string handlers](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated#compilation-of-interpolated-strings).\n\nThe proposal is to explicitly declare the span types `Span<T>` and `ReadOnlySpan<T>` more specific - \"better\" - than arrays and the core collection interfaces when targeted by a collection expression, even though an implicit conversion does not exist.\n\nThe motivation is that picking a span overload is likely to be more efficient, since the span created from the collection expression may potentially be allocated on the stack instead of the heap.\n\nOne question is whether this should apply only to the \"official\" span types, or whether it should generalize to all ref structs that satisfy the requirements for being created by a collection expression? After all, it is not unreasonable to expect that other people have ref struct collection types of their own.\n\nAlso, should this apply only when compared to arrays and interfaces, as currently formulated, or also against concrete (class or struct) types like `List<T>`? Would an ambiguity error better match expectations?\n\n#### Conclusion\n\nYes to the overall proposal: Span types should be better. The working group will come back with recommendations for the open questions.\n\n### Type inference from collection expression elements\n\nhttps://github.com/dotnet/csharplang/blob/main/meetings/working-groups/collection-literals/CL-LDM-2023-08-14.md#type-inference\n\nThe proposal allows type inference to recursively inspect the element expressions of a collection expression, similar to tuples and lambdas. This allows for better inference results, and fewer meaningful cases that lead to errors.\n\nIt gracefully handles empty collections, and \"coordinates\" better with other parameters. \n\n#### Conclusion\n\nAdopted!\n\n### Collection expression conversions\n\nhttps://github.com/dotnet/csharplang/blob/main/meetings/working-groups/collection-literals/CL-LDM-2023-08-14.md#conversions\n\nThere are five ways in which types can qualify for having a conversion from collection expression. For four of them, there must be an implicit conversion from each element expression, and from the iteration type of each spread element, to the iteration type of the target type.\n\nFor the fallback case of collection initializer types, however, the iteration type is not used, because the expression is instead mapped to individual `Add` calls, and each could resolve to a different overload.\n\n(Are there situations where a collection expression conversion should be considered an identity conversion in order to be allowed as an `in` argument? The working group will explore this question.)\n\nThis does not support \"legacy\" collection initializer scenarios where `Add` methods take more than one value. This is mostly used for dictionaries today, and when we start supporting dictionaries we would include those scenarios.\n\n#### Question 1\n\nShould the list of core collection interfaces for which conversions a supported be given as an explicit list, or simply \"the generic interfaces implemented by `List<T>`\"?\n\n##### Conclusion\n\nIt should be an explicit list. This should not \"automatically\" grow in the future if `List<T>` implements new interfaces, but each should be a result of a deliberate decision.\n\n#### Question 2\n\nShould conversions to `Memory<T>` and `ReadOnlyMemory<T>` be supported?\n\n##### Conclusion\n\nThis doesn't fall out automatically. The working group should explore this further.\n\n#### Question 3\n\nShould conversions to [inline arrays](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/inline-arrays.md) be supported?\n\n##### Conclusion\n\nYes, but it is low priority to expose in this release. Efficient implementation of interface target types will probably use inline arrays under the covers regardless, so this might not be all that expensive to implement.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-08-16.md",
    "content": "# C# Language Design Meeting for August 16th, 2023\n\n## QOTD\n\n- \"We're done voting so can I finally start making cracks about 2B or not 2B?\"\n- \"That is the question!\"\n\n## Agenda\n\n- [Ref-safety scope for collection expressions](#ref-safety-scope-for-collection-expressions)\n- [Experimental attribute](#experimental-attribute)\n\n## Discussion\n\n### Ref-safety scope for collection expressions\n\nhttps://github.com/dotnet/csharplang/blob/main/meetings/working-groups/collection-literals/LDM-questions-2023-08-15.md#ref-safety\n\nWhen a collection expression is targeted to a ref struct type, such as `Span<T>` and `ReadOnlySpan<T>`, what should be the ref-safety scope - the \"lifetime\" - of the created value?\n\nTake code like this:\n\n``` c#\nSpan<int> s = [x, y, z];\n```\n\nThere is a fundamental trade-off between efficiency and usefulness. If we make the scope local then `s` can't escape, and we can e.g. allocate on the stack. If we make the scope global, then it will be allowed to escape, in which case we need to allocate it on the heap.\n\nIf we decide on global scope, there is an option to try to be smart about this, deducing from usage that the value does not in fact escape and still allocating on the stack in those cases: we'd effectively be inferring the scope from usage.\n\nSo this leaves us with the following options:\n\n1. Try to be smart and infer scope from usage\n2. Decide scope from declaration alone\n    A. Make the scope always local\n    B. Make the scope always global\n\nOption 1 seems immediately attractive, as it supposedly minimizes the set of situations where this becomes an issue. However, it really means global scope with potential optimizations. How can a user reason about whether the optimizations kick in? How can they trust that a subtle code change doesn't suddenly lead to heap allocations? In that sense it is almost the worst of both worlds.\n\nAn analyzer could help catch when this leads to allocations. It would in practice have to be implemented in the compiler, even if it isn't presented that way, because of the complexity of the analysis.\n\nIf we do go down the path of optimizing implicitly, then people will justifiably take a dependency on the performance profile of that, so we would be bound by our behavior here even if we didn't specify it. We could only ever improve, not deteriorate.\n\nFor option 2 we need to look at what a developer can do if we make the \"wrong\" choice for them:\n\n- If we pick local and they want global, they would have to explicitly allocate it as an array rather than a span (using an array creation expression `new [] { ... }` or casting a collection expression to an array type `(int[])[ ... ]`), then implicitly convert to the span type in question. This leads to less than elegant code, and may be hard to discover the need for.\n- If we pick global and they want local, in the example of the local variable `s` above, they could explicitly add `scoped` to the variable declaration. However, in other scenarios, e.g. when passing the collection expression as a method argument, there is no place to put `scoped`. They would need to factor it out to a local variable or something to achieve that.\n\nBoth are pretty inconvenient. How to choose?\n\nWhen dealing with span types, it feels like people generally expect optimal behavior, i.e., no allocations. They would like to be told if they can't get that, and make any allocations explicit. This certainly points in the direction of option 2B.\n\nThe fact that the scope of a ref struct variable is currently set based on what it's initialized to is surprising to many people who aren't used to spans, but that is something you just have to get used to. If we said collection expressions assigned to ref structs are always local scope, the performance community would just say okay.\n\nIt does feel like it is relatively rare that ref struct arguments escape, so 2B would be a good default. However, the syntactic choices for when you need to go against the default are unappetizing. The array creation expression approach also has subtly different type inference from collection expressions! Perhaps we could have a new keyword (`global`? `new`?) that you could put in front of a collection expression to force globalness? That could be added later if this turns out to be a bigger problem than we expect.\n\n#### Conclusion\n\n2B: always local. We'll keep an eye on how inconvenient this choice becomes in practice, and consider better options for switching to global scope in the future if necessary.\n\n### Experimental attribute\n\nhttps://github.com/dotnet/csharplang/blob/2c86608e9326845a94438fd512cb3df54e1170fd/proposals/csharp-12.0/experimental-attribute.md\n\nThe intent of the `[Experimental]` attribute is to signal that an API is experimental, and force clients to explicitly opt in to the risks of that dependency, e.g. the risk of breaking changes.\n\nIt's mostly the same as obsolete in behavior, with the difference that when you're in the context of an `Experimental` attribute it turns off warnings about the use of experimental things inside. Also it can be provided at the assembly/module level to apply to a whole library.\n\nThe attribute takes a diagnostic id as a parameter, so that it's not all or nothing: You can turn on or off on a per-experimental-API level. That is expected to typically be done in project files, not using pragmas in code. It would be used equally for BCL features and third party libraries.\n\nA library author that depends on an experimental feature should either shield their consumers from breaking changes in the feature, or in turn advertise the attribute to *their* users.\n\nUnlike `[Obsolete]` the expectation is that you would eventually remove `[Experimental]` from an API. Are there thoughts on how a client can clean up their suppression when that happens? It's probably hard to tool, because of the combinations of versions that would go into it.\n\nAs a potential slight hole, if you somehow get your hands on a value of an experimental type without mentioning the type itself, you get to use it without warning. This is especially observable through extension methods, which are often usable without their containing type being explicitly mentioned: If the containing type is marked experimental but not the extension method itself, the consumer will then not get a warning.\n\n#### What do assembly-level attributes mean?\n\nShould assembly-level use of `[Experimental]` apply recursively to members and nested types, or just to top-level types? \n\nOptions:\n\n1. apply to both types and members\n2. only apply to types (including nested types)\n3. only apply to top-level types\n\n##### Conclusion\nWe prefer option 1: both types and members.\n\n#### Warnings or errors\n \nAt the language level, the diagnostics about use of experimental APIs cannot be errors, since errors cannot be silenced. However, it's desirable that these warnings are promoted to error severity by default, as unintended dependency on an experimental API is quite bad.\n\nFor other attributes, such promotion to error can be done in e.g. an editor config file, but because this one trades in an open-ended set of custom diagnostic IDs for each experimental API, it seems infeasible to list them all in a file.\n\nCould we have an overarching diagnostic ID that refers collectively to all experimental features? If so, we can use existing tools to get the desired severity.\n\n##### Conclusion\n\nKeep the language-level diagnostic a warning and use an overarching diagnostic ID to allow changing the severity of all experimental API use.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-09-18.md",
    "content": "# C# Language Design Meeting for September 18th, 2023\n\n## Agenda\n\n- [Collection expression questions](#collection-expression-questions)\n    - [Optimizing non-pattern collection construction](#optimizing-non-pattern-collection-construction)\n    - [Avoiding intermediate buffers for known-length cases](#avoiding-intermediate-buffers-for-known-length-cases)\n\n## Quote of the Day\n\n- \"I want to know why you're laughing\" \"Just the concept of making 100 temps\"\n\n## Discussion\n\n### Collection expression questions\n\nhttps://github.com/dotnet/csharplang/issues/5354  \nhttps://github.com/dotnet/csharplang/issues/7542\n\n#### Optimizing non-pattern collection construction\n\nOur first topic today was a discussion around whether we can or should call `.ctor(int capacity)` constructors for collection types, when available. This is a bit different from other\nmethod-based patterns that we've used in the past, as we would need to look for the actual parameter name `capacity`; our previous examples in this space do not look for parameter names,\nor even require the parameter to be named at all. However, we definitely have some examples of where not looking for the name would be a problem for existing collection types.\n`System.Collections.Concurrent.BlockingCollection<T>`, for example, has a single-`int` constructor that does not do what the user would want here. There's some concern, though, that even\nchecking for `capacity` isn't good enough. For example, the BCL has a type called `System.Net.CookieContainer` with a constructor with a single `int` parameter `capacity`. This type _isn't_\nconstructible with a collection expression, as it's not `IEnumerable` and doesn't implement the new collection builder pattern, but it's concerning how close it is to being adversely affected\nby this change.\n\nThere are a few options we could take to mitigate this. The first is some sort of opt-out attribute, as we've discussed [before](https://github.com/dotnet/csharplang/discussions/5278),\n[2](https://github.com/dotnet/csharplang/issues/3211). We could also take an opt-in approach instead, where type authors need to add some sort of attribute to their types or constructors in\norder to allow them to participate in this pattern. However, there's a tension with this change around how much we want to change/can change from older-style collection initializers. On the\none hand, most of the time that users will hit this optimization, it'll be because they're using a type that hasn't adopted the new builder pattern. For those types, this is more likely to\nmean that it wouldn't have seen _any_ modifications to work with the new feature, so would an opt-in approach actually help anyone? Potentially, but certainly less than if the optimization\nwas more broadly applied.\n\nUltimately, we don't think we're at the right point in the release cycle to make a large assumption about `capacity` at this time. We'll look at special casing some well-known BCL types that\nwon't be moving to the collection builder pattern, but won't make broad assumptions in the C# 12 timeframe. We'll look at it as part of the collection expression changes we're planning for\nC# 13.\n\n##### Conclusion\n\nWe'll optimize well-known BCL types, not all types at this time.\n\n#### Avoiding intermediate buffers for known-length cases\n\nSecond, we looked at whether or not the compiler needs to guarantee that intermediate buffers are avoided for cases with spreads where we need to evaluate the spread to get the length. This\ncould cause the compiler to need a large number of temp variables to ensure that left-to-right semantics are preserved for the expression. We boiled this down to a set of questions about the\nprinciples that we want the language spec to declare, given this example: `[a, b, c, .. d, e, .. f]`\n\n* What is the ordering of evaluating the expressions themselves? Do we guarantee that `a`, `b`, and `c` are evaluated before `d` is evaluated?\n    * This is pretty historically ingrained in C#.\n* What is the ordering of evaluating implicit expansions, namely the enumerations? Do we guarantee that `d` is enumerated before `e` or `f` is evaluated at all?\n    * Guaranteeing this would mean that using multiple spreads in a collection expression would be a performance hit, as we can't find out what the length of `f` unless we fully enumerate `d`.\n      We'd need to either have temporary storage for the elements of `d`, or couldn't presize the collection.\n* What is the ordering of the constructor call of the target type during all of this? Do we guarantee that it will always be called after `f` has been evaluated?\n    * We have some prior art with changing existing code semantics here: interpolated string handlers in C# 10 caused `StringBuilder.AppendFormatted` to change evaluation orders slightly.\n      We have seen a bit of user confusion around that, but not big. And, importantly, that was changing _existing_ code. This change would not affect existing code, only new code.\n\nWe unanimously felt that we need to at least guarantee LTR ordering of the expressions themselves. It seems perfectly reasonable that someone might have side-effecting expressions inside a later\nexpression that would affect an earlier expression if run out of order, especially given our strong legacy around LTR semantics in C#. We're more conflicted on requiring _enumeration_ of the\ncollection, however; it feels particularly weird that a collection that exposes a `Length` would have an enumerator that would have a side effect on a later element in the containing collection\nexpression. We also feel comfortable not specifying exactly when the collection expression constructor occurs within the collection expression; we do have prior art here with interpolated strings,\nand this isn't nearly as concerning a case given the explicit step users need to take to move to the new semantics. Given all of this, we think we're fine with requiring that collection expressions\nguarantee the ordering of expression evaluation, but not exactly when spreads will be enumerated, or exactly when the constructor will be called. We are also comfortable not requiring the compiler\nto avoid all intermediate collections for large numbers of temps; the compiler is free to do what it can determine is best for the scenario. If it heuristically believes that it would be better\nto allocate a temp array on the heap, it is free to do so.\n\n##### Conclusion\n\nCompiler is free to use temp buffers if it believes it should, and is not required to enumerate spreads before evaluating arguments following a spread. It is required to ensure that expressions\nare otherwise evaluated from left-to-right.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-09-20.md",
    "content": "# C# Language Design Meeting for September 20th, 2023\n\n## Agenda\n\n- [Collection expressions](#collection-expressions)\n    - [Type inference from spreads](#type-inference-from-spreads)\n    - [Overload resolution fallbacks](#overload-resolution-fallbacks)\n\n## Quote of the Day\n\n- \"I live in a double-wide future\"\n\n## Discussion\n\n### Collection expressions\n\nhttps://github.com/dotnet/csharplang/issues/5354  \nhttps://github.com/dotnet/csharplang/issues/7542\n\n#### Type inference from spreads\n\nOur first question for today is around type inference from spread elements contributing to inferring the element type of a collection expression. This is how the working group spec'd the feature,\nand how it was implemented, but we're confirming with LDM that the rules behave as we'd desire. We do have some concerns with the specificity needed for this feature: it seems like we have a similar\nfeature in tuples, and it would be great if there was a general rule about inferring element types from nested element expressions that subsumed all of these cases. We do generally think that behavior\nspecified is correct, however, and will proceed with spec'ing it as having a single set of rules that can affect all the scenarios like this in the language.\n\n##### Conclusion\n\nBehavior is approved. We will work on making a general spec rule that covers this, tuple cases, and other similar scenarios without having to make bespoke rules for each location.\n\n#### Overload resolution fallbacks\n\nOur second and final topic today relates to overload resolution in ambiguous scenarios with the ref struct preferencing rule. For example, this scenario is ambiguous today:\n\n```cs\nstatic void A(Span<object> value) { }\nstatic void A(string[] value)     { }\n\nA([string.Empty]); // error: ambiguous\n```\n\nThere's some precedent for this type of behavior in the language, with how conversions are handled between an API like this:\n\n```cs\nstatic void B(IReadOnlyList<object> e) => Console.WriteLine(\"List<object>\");\nstatic void B(IEnumerable<string> e) => Console.WriteLine(\"IEnumerable<string>\");\n\nB(new List<string>() { \"one\", \"two\" });\n```\n\nFor both of these scenarios, the LDM is in general agreement that we don't want the scenario to work. It's not immediately obvious to anyone, reader or compiler, which of these two overloads is the\nbetter one to call. We also don't believe API patterns like this are realistic. However, there are similar scenarios where we _do_ need to have some sort of element convertibility rule in order to\nhave the right API chosen. As an example of this:\n\n```cs\nstatic void C(ReadOnlySpan<string> r);\nstatic void C(object[] r);\n\nC([\"1\", \"2\"]); // Ambiguous today, because object[] and ROS<string> cannot be converted between\n```\n\nIn this scenario, the LDM believes it's perfectly reasonable for such an API pattern to arise as a library evolves. We also believe that it's unambiguous which one is the \"better\" API; the\n`ReadOnlySpan<string>` can be allocation free, and the inner type is also more specific than the element type of `object[]`. However, since we cannot convert between `ReadOnlySpan<string>` and\n`object[]`, the rules as written today would make this ambiguous. We have a few different rule proposals that might make this possible, given our previous rule of preferencing ref structs over\nother types:\n\n1. Require that there be an identity conversion between the iteration types. This would enable `string[]` vs `ReadOnlySpan<string>`, but would prevent `object[]` and `ReadOnlySpan<string>`.\n2. Require that there be an implicit conversion from the ref struct's iteration type to the other type's iteration type. This would enable `object[]` vs `ReadOnlySpan<string>`, but not\n   `string[]` vs `ReadOnlySpan<object>`, as there is no implicit conversion from `object` to `string`.\n3. Always prefer the ref struct, no consideration of element type convertibility at all.\n4. No special casing whatsoever.\n\nAfter some deliberation, we settled on 2, feeling that it's a good match for user expectations of the feature. However, we then looked at how far we want to apply this rule. So far, all of the\nexamples we've looked at relate to `(ReadOnly)Span` vs one of the interfaces that arrays implement. We're concerned that applying the rule more broadly, particularly with so little time left in C#\n12, will have some unintended consequences. We don't think we can categorically say that all ref structs should be preferred over non-ref struct counterparts, so we'll restrict the rule to just\nbeing for `(ReadOnly)Span` vs arrays and all the interfaces arrays implement.\n\n##### Conclusion\n\nWe will prefer `(ReadOnly)Span` over arrays and interfaces implemented by arrays in overload resolution for an argument with a collection expression conversion when there is an implicit conversion from the element type of the `Span` to the element type\nof the array or array interface.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-09-25.md",
    "content": "# C# Language Design Meeting for September 25th, 2023\n\n## Agenda\n\n- [Primary constructors](#primary-constructors)\n- [Defining well-defined behavior for collection expression types](#defining-well-defined-behavior-for-collection-expression-types)\n\n## Quote(s) of the Day\n\n- \"So we're finally going to have the highlander betterness rule?\"\n- \"Let them live in fear if they're going to do something like this\"\n\n## Discussion\n\n### Primary constructors\n\nhttps://github.com/dotnet/csharplang/issues/2691  \nhttps://github.com/dotnet/csharplang/blob/960ffda90c05c212870d509a45651197a6cd1791/proposals/csharp-12.0/primary-constructors.md#lookup-order-for-type-parameters\n\nFirst up today we looked at an issue with lookup order of type parameters, and how our existing `record`s work conflicts with the rules we decided on for non-`record` primary constructors.\nWe have 4 options for addressing this discrepancy:\n\n1. Adjust the rules to match the behavior of the implementation (which is the same between `record` and non-`record` types).\n2. Adjust the behavior to match the rules in all cases (a possible breaking change for `record`s).\n3. Disallow a primary constructor parameter to use a type parameter's name (a possible breaking change for `record`s).\n4. Do nothing, accept the inconsistency between the spec and implementation.\n\nWe quickly determined that we don't think 2 or 4 are the correct answers, and instead felt divided between 1 and 3. Importantly, the LDM feels that this scenario is a pathological case,\nand not representative of C# code outside the compiler's test suite, so we don't feel the cost of a breaking change is hard. However, because this case is so pathological, we also are\nunsure whether it's worth spending the effort that taking a breaking change would require: updating the compiler error detection code, documenting the breaking change, and dealing any\nfallout from the change, and all this within the next month when C# 12 releases. We ultimately think that the best choice we can make here is to simply update the spec to match the\nbehavior of the compiler, and revisit in the future if we have sufficient motivation from real world scenarios.\n\n#### Conclusion\n\nOption 1, update the primary constructors spec to match the existing compiler behavior and align with `record`s.\n\n### Defining well-defined behavior for collection expression types\n\nhttps://github.com/dotnet/csharplang/issues/5354  \nhttps://github.com/dotnet/csharplang/issues/7542\n\nFor our second and last issue today, we looked at defining what behavior the compiler can assume from a collection type. This is important for allowing the compiler room to change emit\nof collection expressions for performance, and there's a tension here between what could be reasonably observed by a user program vs what should be able t reordered. One thing we think is\niron-clad is that anything the user has explicitly written needs to be evaluated in traditional C# fashion. It is reasonable that `[i++, i++, i++]` would result in a collection of\n`[0, 1, 2]` with `i == 3` afterwards, and not any other order. However, enumeration of nested collections is not an explicit user action, and we want to able to control the location that\noccurs in; enumeration should be able to occur before evaluating subsequent elements, or after evaluating subsequent elements, as needed by the compiler to support efficient intermediate\nstorage allocation.\n\nWe like the spirit of the proposed rules in 7542 but think that they need to explicitly spell out these conditions. Right now, they imply that the compiler can reorder the location that\nnested enumeration can occur, but don't explicitly state it. Rather than leaving this as undefined and letting the compiler fill in the blanks, we'd rather explicitly carve it out that\nthe compiler is free to optimize assuming that `IEnumerable` instances can be enumerated at any time, so long as the element expressions that the user writes are evaluated in left-to-right\norder. We also don't feel that we should specify that the compile needs to enumerate spreads in the order they appear; while we currently don't have any plans for enumerating a later spread\nbefore an earlier spread, we don't think that we should restrict ourselves from optimizations in the space in the future if we find them. We support spreading `IEnumerable`s, not\n`IEnumerator`s, and those should be iterable multiple times without producing different results each time.\n\n#### Conclusion\n\nThe compiler is allowed to reorder spread enumerations assuming that `IEnumerable` implementations don't have side effects, and the rules should be updated to explicitly call this out.\n\n"
  },
  {
    "path": "meetings/2023/LDM-2023-09-27.md",
    "content": "# C# Language Design Meeting for September 27th, 2023\n\n## Agenda\n\n- [Collection expressions](#collection-expressions)\n\n## Quote of the Day\n\n- \"Note today's date. Today is a historical day when we finish collection expressions\" *collective laughter*\n\n## Discussion\n\n### Collection expressions\n\nhttps://github.com/dotnet/csharplang/issues/5354  \nhttps://github.com/dotnet/csharplang/issues/7542\n\nToday in our wrapping up of the last issues in collection expressions, we took a look at what optimizations the compiler is allowed to make. There's a tension here\nbetween allowing the compiler to make user code fast, and how understandable the feature will be. There are a number of features that we want the compiler to be able\nto take advantage of that might not normally be visible, or not be chosen, at the location of the collection expression. For example, .NET 8 is introducing a new set\nof `AddRange` extension methods on `List<T>` for adding a `ReadOnlySpan` to a `List` efficiently. We'd like to pick these methods for spreading an array into a collection\nexpression target-typed to a `List`, but because `AddRange` is an extension method, it's never even discovered before the instance `AddRange(IEnumerable)` method is picked.\nThis is not just a problem for collection expressions, of course; it's a problem for regular invocations as well. But do we want to limit collection expressions to\nbehaving exactly as if the user had written the `AddRange` call themselves, or can we make it better? And if we can make it better, where do we limit ourselves? For\nuser-defined collection types, should we search non-imported namespaces for better extension `AddRange` methods? If so, where do we stop? And how do API authors know how\nto design their collections to take advantage of these rules?\n\nOne thing we wanted to do as part of determining what APIs can be taken advantage of is to determine what our definition for the Base Class Library, or BCL, actually is.\nWith input from the runtime team, we determined that what we should consider the BCL is anything in the `System.*` namespace. With that definition, we decided to split up\nour decisions: should we be allowed to assume well-behavedness and call any method at all for BCL types? And, as a separate question, should we be allowed to do that for\nnon-BCL types? For BCL types, we think this is fairly safe. The `System` namespace has been \"special\" to the .NET ecosystem since the very beginning, and we feel ok with\nassuming that we can call things like the extension `AddRange` for BCL types in collection expression spreads. We're also ok with calling things like `CopyTo` on BCL types.\nWe're more wary about non-BCL types, particularly around type author discoverability. How do we make sure that type authors know what their collections should do to get\noptimal performance, for example, or how do we know that a random `AddRange` method would actually do what we expect for specific BCL types like `List`? After much debate,\nwe think we need to be more specific for non-BCL types, provide a specific list of things that we will call, and respect the normal rules that users will see if they write\nout the code manually.\n\nSeparately, we would like to address some of the problems that caused `AddRange` to be an extension in the first place. Because arrays and `string`s are both convertible\nto `ReadOnlySpan<T>` and implement `IEnumerable<T>`, adding that `AddRange` as an instance method would create ambiguities when passing a parameter of that type to `AddRange`.\nThe array problem can be fixed with another more specific overload, but the `string` case cannot, as it would require generic specialization. This is a problem that we\nkeep running into with various language features, and we think it's time to address it in C# 13.\n\n#### Conclusion\n\nThe compiler can rely on all implementation details of BCL types, and potentially call methods that would not normally be preferred by the language in that location. For\nuser types, we need to enumerate the list of methods that the compiler can call, and respect the normal language rules in those locations. This include methods from well-known\nBCL interfaces implemented by non-BCL types. We will look at potential ways to unify this behavior in C# 13.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-10-02.md",
    "content": "# C# Language Design Meeting for October 2nd, 2023\n\n## Agenda\n\n- [Collection expressions](#collection-expressions)\n\n## Quote(s) of the Day\n\n- \"Can I add a 4th bullet? Don't design it now, do it now\" \"This isn't a Punnett square\"\n- \"Ok, that was three deep breaths\" \"I only did 2\" \"I have small lungs, what can I say\"\n- _<redacted> posts a picture of the IEnumerable hierarchy_ \"Thank you, <redacted>, that was... horrifying. Horrifying and super useful\"\n\n## Discussion\n\n### Collection expressions\n\nhttps://github.com/dotnet/csharplang/issues/5354  \nhttps://github.com/dotnet/csharplang/issues/7542\n\nToday, we looked at how the conversion for collection expressions is defined for `IEnumerable` types. This is the rule that allows collection expressions to be fully\ncompatible with types that can be initialized by a collection initializer today; because of this broad compatibility, it has some issues that we think may cause the feature\nto be brittle in the face of user interaction. Specifically, determining whether the conversion exists requires the compiler to attempt to bind the call to the constructor,\nand every `Add` or `AddRange` call, before determining that a conversion exists. This can potentially lead to unstable behavior in the editor in the face of user errors, and\nit's a problem we've seen before. In particular, interpolated string handlers were originally specified this way, but we revised the specification after considering this issue.\nWe are therefore considering updating the spec here to avoid the same problem. The new rules do have a marked disadvantage: they aren't fully compatible with all types that\ncan use a collection initializer types today. If there are extension `Add` methods that convert inputs to the element type of the collection, they would not be considered by\nthis new rule. We do expect that these cases are somewhat rarer though, and that we can address this later if it becomes a problem.\n\nThese rules also prompted a discussion on support for non-generic `IEnumerable`. The WG was unclear on the exact outcome from a\n[prior LDM](LDM-2023-08-09.md#target-typing-of-collection-expressions-to-core-interfaces), and whether the non-generic `IEnumerable` and descendent interfaces (such as `ICollection`)\nneed to be supported for target-typing as well. We clarified that we don't think we can make a decision about whether to consider the non-generic `IEnumerable` \"deprecated\" by\nourselves; it would need to be a larger decision among all the .NET teams. We also don't think supporting the non-generic types will cause any new ambiguities that didn't already\nexists: for example, if an API is overloaded on `ICollection` vs `ICollection<object>` today, it's already ambiguous, because `ICollection<T>` doesn't inherit from `ICollection`.\n\nAs part of this consideration, we also confirmed that we do want to be able to target the non-generic interfaces with collection expressions. IE, this should work:\n\n```cs\nICollection c = [\"a\", 2, null];\n```\nHowever, we think we may not be able to get this in C# 12, and it may have to wait for C# 13 and be considered in tandem with natural types for collection expressions.\n\nFinally, we thought about how the new rules apply to `string`s. There are two core scenarios to think about here:\n\n```cs\n// Scenario 1\nvoid M1(string s) {}\nvoid M1(ReadOnlySpan<char> r) {}\nM1(['a', 'b', 'c'])\n\n// Scenario 2\nvoid M2(string s);\nvoid M2(char[] characters);\nM(['a', 'b', 'c']);\n```\n\nScenario 1 is extremely realistic, and in fact already exists in the BCL. We'd much prefer that it call the `ReadOnlySpan` API, which does not need to allocate; the `string` API\nneeds an instance of a `string`, which could very well allocate if the items were not constant. To accomplish this, we need to update the betterness rule from a\n[previous LDM](LDM-2023-09-20.md#overload-resolution-fallbacks) to consider `Span` better than both array _and_ `string`, or it will become ambiguous.\n\nThe second API, though, is not ambiguous by today's rules, as `string` is not constructable and therefore no conversion exists. By the new rules though, `string` is a valid\ntarget type for collection expressions, and will simply fail at a later stage. This makes the `M2` API ambiguous. After some more consideration, we think that there's good\nreasoning for making `string`s constructable with collection expressions. List patterns already work on them, and we think that syntax could be useful for combining multiple\nstring slices together. Support for this, though, is likely not going to make C# 12, and will be considered for future C# versions.\n\n#### Conclusions\n\nThe proposed change to the collection expression rules is adopted as worded.  \nCollection expressions can be converted to `string`s, though the conversion will fail to compile today. We will hope to make it work in the future.  \nWe update the overload resolution betterness rules to consider `Span` and `ReadOnlySpan` better than `string`, just as we did for array and interfaces implemented by arrays.  \nWe will support non-generic collection interfaces as target types, but possibly not until C# 13 in tandem with natural types for collection expressions.\n\n\n"
  },
  {
    "path": "meetings/2023/LDM-2023-10-04.md",
    "content": "# C# Language Design Meeting for October 4th, 2023\n\n## Agenda\n\n- [Trimming and AOT](#trimming-and-aot)\n\n## Quote of the Day\n\n- \"PHONE ALERT TIME\"\n\n## Discussion\n\n### Trimming and AOT\n\nToday, we mostly listened to a presentation from the AOT lead and C# LDM emeritus Andy Gocke, which can be viewed [here](LDM-2023-10-04%20Intro%20to%20Trimming%20and%20AOT.pdf).\nWe had a few small discussions during and after the presentation, which will be summarized here, but we'll let the slides speak for themselves for the majority of the content.\n\nOn alpha-renaming with attributes (slides 9 and 10), Andy pointed out that our closure renaming strategy today doesn't preserve attributes on type parameters, which makes it hard for AOT\nannotations to be preserved for lambda scenarios. We agreed that this is something that the compiler can likely address; how lambdas are lowered is not well-specified in the C# language,\ngiving us the freedom to add more information if needed. However, this is a double-sided blade: because it's unspecified, it's not necessarily a good idea for an AOT framework to take advantage\nof a specific lowering strategy, even if more advantageous. We may want to think about whether we can specify enough to get AOT the information it needs without over-constraining the compiler.\n\nThe serialization models adopted by newer systems, particularly Rust and Swift, are attractive, and potentially doable in C# when we add extensions that can implement interfaces on unowned types.\nBut there's a few potential problems we'll need to think about:\n\n1. Rust has an orphan rule for trait implementation, preventing users from implementing traits they don't own on types they don't own. They get away with the trait-based deserialization models\n   in part due to the fact that they've been implementing serialization traits like this from the very beginning, so the whole ecosystem has effectively opted itself in. C# doesn't have that\n   weight of momentum, so an orphan rule might kill any attempts by users to mix new serialization patterns in with existing code they don't own. However, we also don't think we need an orphan\n   rule currently, as C# extensions will be actual named types, unlike in Rust. It is still something that needs to be investigated more in depth, however.\n2. The momentum argument also has impact on broader adoption: just like with nullable reference types, this would be a gradual adoption of a new serialization pattern across the entire ecosystem.\n   Even if individual users can gracefully bring old, outdated patterns into new serialization patterns, it's going to be a long road before users wouldn't have to introduce lots of adapter\n   interface extensions, and that's not including any frameworks that may simply decide to avoid the new patterns.\n\nRegardless of these problems though, we think that the extensions working group needs to keep this use case in mind and prioritize it as a potential use case for the feature.\n\nThere's also some concern about compiler structures that aren't represented at runtime, and how AOT would be able to view these things. Currently, .NET AOT only works with C#, which is a detriment\nto the feature. Any further addition of language features that doesn't have real runtime representation makes it harder to work with from a cross-language perspective; for example, one possible\nimplementation of reference could be simply treat it as `object` (or some other base type of the hierarchy) with some additional metadata to say which cases are possible. Would this then constrain\nhow an AOT-compatible serialization framework needs to behave, and lock out other .NET languages besides C#? Similar issues exist for AOT based purely on source generating from C# syntax. These are\nhard questions that need to be dug more into, and we would like to do so.\n\nThere are no conclusions here today; serialization is an interesting scenario that we will continue to look at more.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-10-09.md",
    "content": "# C# Language Design Meeting for October 9th, 2023\n\n## Agenda\n\n- [Triage](#discussion)\n    - [ReadOnlySpan initialization from static data](#readonlyspan-initialization-from-static-data)\n    - [Embedded Language Indicators for raw string literals](#embedded-language-indicators-for-raw-string-literals)\n    - [list-patterns on enumerables](#list-patterns-on-enumerables)\n    - [Make generated \\`Program\\`\\` for top-level statements public by default](#make-generated-program-for-top-level-statements-public-by-default)\n    - [CallerCharacterNumberAttribute](#callercharacternumberattribute)\n    - [Add private and namespace accessibility modifiers for top-level types](#add-private-and-namespace-accessibility-modifiers-for-top-level-types)\n    - [Require await to apply nullable postconditions to task-returning calls](#require-await-to-apply-nullable-postconditions-to-task-returning-calls)\n    - [`is` expression evaluating `const` expression should be considered constant](#is-expression-evaluating-const-expression-should-be-considered-constant)\n\n## Quote of the Day\n\n- \"I think the disagreement was primarily around Javascript, so we'll leave that out\"\n\n## Discussion\n\nToday was a triage day. We went through championed issues without a milestone to assign them an appropriate milestone for future work. The query we use for this is\nhttps://github.com/dotnet/csharplang/issues?q=is%3Aopen+is%3Aissue+label%3A%22Proposal+champion%22+no%3Amilestone.\n\n### ReadOnlySpan initialization from static data\n\nhttps://github.com/dotnet/csharplang/issues/5295\n\nMuch of the desire for specific syntax here has been addressed by a combination of things in C# 12:\n\n* Collection expressions provide a syntax that doesn't contain `new` and necessarily imply that it is actually creating a new collection.\n* Collection expressions for this scenario have a set of promises enshrined in the spec for when they won't allocate, and we have a warning for when that's violated.\n* There are additional scenarios that the compiler does not allocate today, and we have a hidden diagnostic that users that care about this scenario can turn on to ensure that\n  they aren't violating these rules, either now or in the future. This set of rules is implementation-defined, which is why the diagnostic must be opted into by users, but it\n  does cover the scenario.\n\nWe could in the future think about potential `const` expansions to ensure that nothing is violated, such as `const [1, 2, 3]`, but that's a much bigger proposal and potentially\ngets into the larger weeds of broad constexpr support in C#, and can be revisited later.\n\n#### Conclusion\n\nRejected, request subsumbed by C# 12 features.\n\n### Embedded Language Indicators for raw string literals\n\nhttps://github.com/dotnet/csharplang/issues/6247\n\nThis is, in terms of compiler work, an extremely small feature. However, the broader concern is tooling support. If we enshrine this in the language itself, we may then need a\ntooling support bar we currently don't have. Colorization of languages today is driven by comments or `StringSyntaxAttribute`, and there's a bit of a chicken-and-egg problem here.\nIf the language had more explicit support for the feature, this may drive more investment into tooling; but because we don't have super broad adoption of the existing feature, it\ncan be hard to justify the investment. We think the feature would be a good one to have, but that we're not going to prioritize it at this time.\n\n#### Conclusion\n\nBacklog\n\n### list-patterns on enumerables\n\nhttps://github.com/dotnet/csharplang/issues/6574\n\nThis is follow-up work from C# 11 that we did not have time in C# 12 to invest in. We intend to continue the work here now; collection expressions supporting more than just indexable\nand countable types show where our list pattern support falls short.\n\n#### Conclusion\n\nWorking set\n\n### Make generated `Program`` for top-level statements public by default\n\nhttps://github.com/dotnet/csharplang/issues/6769\n\nThe primary argument for this feature is improving testability, but we think this feature alone wouldn't be enough to fix testing. For example, users wanting to test their entrypoint\nstill can't do so, because it's unnameable. We think a more holistic look at the testing space is required before we move forward with this one.\n\n#### Conclusion\n\nNeeds more work\n\n### CallerCharacterNumberAttribute\n\nhttps://github.com/dotnet/csharplang/issues/3992\n\nThis is an interceptors-adjacent feature. As we continue to develop interceptors or possible replacements for C# 13, we will want to consider this alongside it. It shouldn't be\nconsidered alone.\n\n#### Conclusion\n\nGrouped with https://github.com/dotnet/csharplang/issues/7009.\n\n### Add private and namespace accessibility modifiers for top-level types\n\nhttps://github.com/dotnet/csharplang/issues/6794\n\nThis is in many ways a follow-on to the improvements we made with `file`, but this time targeted more at standard users, and less at source-generator authors. We think that there's\nroom to improve the story around encapsulating functionality, particularly for larger codebases, and want to flesh this proposal out and see where it leads us.\n\n#### Conclusion\n\nWorking set\n\n### Require await to apply nullable postconditions to task-returning calls\n\nhttps://github.com/dotnet/csharplang/issues/6888\n\nThis still needs to be updated to address feedback from the last time that it was\n[brought up](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-01-18.md#nullable-post-conditions-and-asyncawait).\n\n#### Conclusion\n\nNeeds more work\n\n### `is` expression evaluating `const` expression should be considered constant\n\nhttps://github.com/dotnet/csharplang/issues/6926\n\nThis is a consistency issue: you can use `==` in a constant expression, but not `is`. We think this can be addressed, but needs a complete specification. It should probably also\nlook at `switch` expressions at the same time.\n\n#### Conclusion\n\nAny time, needs an approved specification.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-10-11-specification-update.md",
    "content": "# Status of C# 7 standard\n\nIn our last meeting, the ECMA committee voted to submit the C# 7.3 standard to ECMA for final approval. This is the first version we've created in the open, on GitHub.Now that we've completed the work on the standard, the `draft-v7` branch has been renamed `standard-v7`.\n\n> GitHub redirects any links to the `draft-v7` branch to the updated name. There's no need to updated any existing proposals due to that change. The default branch has already changed to the `draft-v8` branch. Merging v7 into the v8 branch is in progress.\n\n## Nomenclature changes, and how to handle them going forward\n\nThe committee changed some of the nomenclature used in the C# 7 specs. The original terms were either confusing, or some words in a multi-word term were already used in the standard with a different meaning.\n\nNotably, *safe-to-escape-scope* and *ref-safe-to-escape-scope* became *safe-context* and *ref-safe-context* respectively. The possible values are now *declaration-block*, *function-member*, and *caller-context*. (The speclet didn't use standard terms).\n\nQuestion: Should we update the speclets from C# 7.2 and later to use the standard terms? Or wait until the standard incorporates all these versions? Or add a note in each relevant speclet of the changed terms? \n\nThe first provides consistency now. The second preserves the historical nature of the speclets. The third is a compromise position.\n\n## A look at C# 8 efforts and beyond\n\nRex has been creating draft PRs for C# 8 (and later) features. None of these are completed. We will start assigning work to committee members at our next meeting. We're making some [process changes](https://github.com/dotnet/csharpstandard/issues/960) that we believe will help us move faster.\n\nYou can see the mapping from any speclet to the corresponding standard text in the [admin folder](https://github.com/dotnet/csharpstandard/blob/draft-v8/admin/v8-feature-tracker.md) on the csharpstandard repo.\n\n## Looking back\n\nC# 7.3 was likely the longest cycle the committee has or will have. There were a number of reasons:\n\n1. *New process*: This was the first version using Markdown and GitHub. We were finding issues with the conversion from Word, in addition to fixing existing spec bugs and adding new features.\n1. *No Microsoft standard*: This was the first release where the Microsoft version of the C# spec wasn't updated. That's a positive because we're not trying to reconcile different descriptions, and we don't introduce regressions when fixes didn't make both version of the spec. On the other hand, it was our first experience working with feature specs and writing the standard language from the feature specs.\n1. *Long release and point releases*: The committee decided to work up through 7.3 instead of 7.0 for two reasons:\n   1. C# 7.3 is the last version compatible with .NET Framework.\n   1. Small fixes introduced in point releases were easier.\n1. *Spelunking LDM notes and roslyn repo*: The C# 7 timeframe also including creating the `csharplang` repository, and building the culture to update the specifications. Some notes were in `roslyn`, in issues or docs. Some in LDM notes, in either repo, and some in the speclets.\n1. *Smaller committee*: The committee has room for more members. (Microsoft is under-represented at this point).\n \nThe newer feature specs have more language directly tied to the specification language. Other ongoing improvements have been noted above.\n\n## Other questions for LDM\n\n1. *Branch cleanup in csharplang*: Rex and I had used a [branch in csharplang](https://github.com/dotnet/csharplang/tree/standard-proposals) for some initial C# 7 integration with the Microsoft spec. That was abandoned some time ago. Is anyone using it? If not, I'll delete branch.\n2. *Do we want to direct customer issues in speclets directly to csharplang?*: I sent mail about this a week ago. We have a new feedback mechanism in docs where I can configure a link to use a YML template for new issues in the C# lang repo. Currently, they go to the docs repo, and I triage them before moving or just fixing them.\n "
  },
  {
    "path": "meetings/2023/LDM-2023-10-11.md",
    "content": "# C# Language Design Meeting for October 11th, 2023\n\n## Agenda\n\n- [C# spec update](#c-spec-update)\n- [Collection expressions](#collection-expressions)\n\n## Quote(s) of the Day\n\n- \"I think that's a great segue, because \\<redacted's\\> voice has always reminded me of cardamom syrup.\" \\<redacted\\>: \"_what_?\"\n- \"The chat has descended into madness\" \"We're solving \\<redacted's\\> coffee problem\" \"\\<redacted\\> and \\<redacted\\> are about to open a Starbucks franchise in the C# team room\"\n\n## Discussion\n\n### C# spec update\n\n[C# 7 specification update](LDM-2023-10-11-specification-update.md)\n\nThe specification effort for C# 7.3 has completed, and the formal spec has been submitted to ECMA for ratification. Following this effort, the committee will be moving onto\nC# 8, but there were a few questions to clarify with the LDM before getting started on that:\n\n1. The committee renamed `safe-to-escape` and `ref-safe-to-escape` in the specification for clarity. Should we update the existing documents with this info, and if so, should\n   we update the C# 7 speclets as well as the C# 8+ speclets?\n    * After some deliberation, we think the right answer is to update the C# 8+ speclets with this info. The C# 7 speclets are now effectively obsolete; the features have been\n      integrated into the real specification, and we don't link to them from the documentation anymore. We'll put a note in the root of the C# 7 speclet folder on csharplang\n      that the speclets there are outdated, and that should be all we need to do. For the C# 8+ speclets that refer to the outdated names, these are still active documents, so\n      we'll update them with the new names. We'll also include a note that the term was renamed for past readers who look at the document again. We don't plan on updating issues\n      or notes with these new terms.\n2. There are a few outdated branches on csharplang from before the ECMA committee moved to the csharpstandard repo. These need to be cleaned up.\n3. Finally, we currently have docs issues on the C# speclets opened on the dotnet/docs repo. This usually means that we go through a multi-level ping before getting to the right\n   person to answer the question. The content itself is hosted from the csharplang repo, so should we move the issues to be filed on csharplang repo as well?\n    * We think we should do this. The volume of issues is pretty low, and it will remove a level of indirection for getting questions answered or docs fixed.\n\n### Collection expressions\n\nhttps://github.com/dotnet/csharplang/issues/5354  \nhttps://github.com/dotnet/roslyn/issues/70318\n\nFinally today, we considered whether collection expressions should prefer `ReadOnlySpan` over `Span` for APIs that are overloaded on these two types. This isn't a super common\ncase, but it can happen. Some examples include extension methods (these may be overloaded because extensions on `ReadOnlySpan` do not appear on `Span` receivers), or\n`ImmutableArray.Create`. Our existing rules prefer `Span` here, because it can be converted to `ReadOnlySpan`, and is thus the \"more specific\" type. And, at least conceptually,\nit's possible that `Span` is the better type in some scenarios: perhaps the API that's being called can be more efficient if it can mutate the input buffer. However, looking at\nthe existing ecosystem, this isn't the case; the cases we see would indeed prefer an allocation-less `ReadOnlySpan` if at all possible, rather than `Span`. We also think that we\nhave more leeway with collection expressions to choose the better type if possible; unlike, say, `new[] { 1, 2, 3 }`, we're not explicitly allocating new space with `[1, 2, 3]`.\nWe also considered what exact wording to use here; we ended up at very similar wording to how we specified the `Span` vs array type betterness, requiring an implicit conversion\nbetween the element types to avoid the same problems we discussed [here](LDM-2023-09-20.md#overload-resolution-fallbacks).\n\n#### Conclusion\n\n`ReadOnlySpan<T1>` will be preferred over `Span<T2>` in overload resolution for a collection expression parameter when `T1` is implicitly convertible to `T2`.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-10-16.md",
    "content": "# C# Language Design Meeting for October 16th, 2023\n\n## Agenda\n\n- [Triage](#discussion)\n    - [Breaking change warnings](#breaking-change-warnings)\n    - [Determine natural type of method group by looking scope-by-scope](#determine-natural-type-of-method-group-by-looking-scope-by-scope)\n    - [u8 string interpolation](#u8-string-interpolation)\n    - [Lock statement pattern](#lock-statement-pattern)\n    - [String/Character escape sequence \\\\e as a short-hand for \\\\u001b ()](#stringcharacter-escape-sequence-e-as-a-short-hand-for-u001b-)\n    - [New operator %% for canonical Modulus operations](#new-operator--for-canonical-modulus-operations)\n\n## Quote of the Day\n\n- \"If you have a ref struct as a synchronization primitive that's pretty useless\" \"Hey, we were discussing readonly setters today, just because it's useless doesn't mean we shouldn't do it\"\n\n## Discussion\n\nToday we continued with triage of championed issues without a milestone.\n\n### Breaking change warnings\n\nhttps://github.com/dotnet/csharplang/issues/7189\n\nWe continue to work on this, but it was filed after our last triage session so it didn't have a milestone.\n\n**Conclusion**: Added to the working set.\n\n### Determine natural type of method group by looking scope-by-scope\n\nhttps://github.com/dotnet/csharplang/issues/7364\n\nWe've determined this is a duplicate of https://github.com/dotnet/csharplang/issues/7429. Closing out.\n\n**Conclusion**: Closed as a duplicate.\n\n### u8 string interpolation\n\nhttps://github.com/dotnet/csharplang/issues/7072\n\n.NET 8 has mostly addressed this request with some JIT work to make `TryWriteUtf8` extremely efficient. The remaining work here would be allowing usage outside of that\nAPI, and we're unsure whether the existing are addressed with this new work. We'll wait to see if the new work has sufficiently addressed requests here before proceeding\nwith more design work.\n\n**Conclusion**: To the backlog.\n\n### Lock statement pattern\n\nhttps://github.com/dotnet/csharplang/issues/7104\n\nSome initial discussion revealed that there are some split opinions in the LDM on whether we think `lock` should natively support this new type, or if a new language feature\nshould be used (or if it should be done via `using`). However, what's clear is that we do need to have more discussions on this in the .NET 9 timeframe, or our ability to\naddress this request without potential breaking changes will slip us by.\n\n**Conclusion**: Into the working set for .NET 9 discussions.\n\n### String/Character escape sequence \\e as a short-hand for \\u001b (<ESCAPE>)\n\nhttps://github.com/dotnet/csharplang/issues/7400\n\nThis is one of the smallest possible language features that could possibly exist, and we're generally fine with the idea, especially as there is prior art in other languages\nfor `\\e` as an escape (regex, for example, uses `\\e` for \\u001b as well). We think the existing issue is sufficiently well-specified to proceed to put this into the needs\nimplementation bucket of any time, open for community contribution.\n\n**Conclusion**: Into Any Time, needing an implementation.\n\n### New operator %% for canonical Modulus operations\n\nhttps://github.com/dotnet/csharplang/issues/7599\n\nWe think this request is better served by library functions. There's a large number of potential follow-on requests here: requests for floored division, requests for\nother types of remainder operations, and we don't think that adding increasing numbers of `%` or `/` characters to other operators is a sustainable path forward for these\nrequests, either for human understanding of the operators or for the language to continue designing. We think that extension methods are probably the best path forward for\ngetting an infix-style calling pattern for these operations.\n\n**Conclusion**: Likely never.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-11-15.md",
    "content": "# C# Language Design Meeting for November 15th, 2023\n\n## Agenda\n\n- [`params` improvements](#params-improvements)\n- [Nullability analysis of collection expressions](#nullability-analysis-of-collection-expressions)\n- [Evaluation of implicit indexers in object initializers](#evaluation-of-implicit-indexers-in-object-initializers)\n\n## Quote of the Day\n\n- \"That is a divide by object error\"\n\n## Discussion\n\n### `params` improvements\n\nhttps://github.com/dotnet/csharplang/issues/7700  \nhttps://github.com/dotnet/csharplang/pull/7661\n\nWe started today by reviewing the latest proposal for improving `params`. This has morphed several times over the past few years; previous issues included\nhttps://github.com/dotnet/csharplang/issues/179 and https://github.com/dotnet/csharplang/issues/1757; this proposal encompasses both of these, and tries to\nunify with the C# 12 feature collection expressions. The general driving principle of this proposal, and how the LDM is thinking of the feature, is that if\nthe user can make a collection of the type, they should be able to mark it `params`. This may require some spec work between the two features to extract out\ncommon elements without requiring invasive changing of everywhere that `params` exists today, but it's a good driving principle.\n\nOverall, we are very interested in the feature. It's a rare example of something that both adds expressivity to C# while actually _simplifying_ the language:\nwith this change and a bit of spec work, we have a much simpler story around collections in the language. You can deconstruct them via pattern matching,\nindex into them, construct them via collection expressions, and provide implicit construction via `params`. We consider whether we could simply not do this\nfeature and let collection expressions fill the gap, but there's one clear problem we need to solve: the BCL would like to add `params (ReadOnly)Span` overloads\nto many APIs to make them more efficient. This isn't a gap that can be solved by collection expressions, and we think that, if we're going to make a change to\n`params`, we should do the entire feature to make reasoning about collections in the language easier, rather than just changing the special cases users need\nto think about.\n\nWe also considered some ref-struct specific design questions. In terms of allocations, we think the right approach is to again align with collection expressions;\nif a collection expression wrapping the arguments passed to a `params Span` allocates, then the expanded invocation form should behave the same. We left a lot\nof leeway in the language for optimizations here, so we think continuing to keep to the same guarantees is the obvious thing to do. It also helps prevent\nsurprise behavioral differences if a user passes a collection expression to a `params` parameter vs calling in expanded form. The other question we considered\nis whether to have the `params` parameter be `scoped` by default. Some members were concerned that `params` is not an obvious enough indicator of `scoped`ness,\nbut we have somewhat already crossed this bridge with `out` parameters. We also don't have any current scenarios that need an unscoped `params` parameter, only\nones that need `scoped`. Given that, we think we should start with `scoped` by default, and let feedback inform whether we've made the right decision.\n\nFinally, we noticed that the overload resolution tiebreaking rules may be missing a few clauses that collection expressions have around non-ref struct comparisons,\nso we'll make sure that's in the spec if needed.\n\n#### Conclusion\n\nProposal is accepted. We will follow the same allocation guarantess as collection expressions, and `ref struct` `params` parameters will be `scoped` by default.\n\n### Nullability analysis of collection expressions\n\nhttps://github.com/dotnet/csharplang/issues/5354  \nhttps://github.com/dotnet/csharplang/issues/7626\n\nThis issue came up late in the design cycle and presented somewhat of a challenge to the compiler. In particular, some types may violate what we'd otherwise\nconsider an idiomatic implementation, having an `Add` method that allows `T?` while the collection iteration type is `T`. While we don't think that's a totally\nunreasonable pattern, it does generally violate our pre-existing rules for collection expressions. For example, if a collection iteration type is `T1`, we don't\nallow using an unrelated `T2` as an expression, even if the collection type technically has an `Add(T2)` method. This differs from collection initializers, and\nwe think that we should carry that difference through here. This also means that any collection expression that are used with older collection types that only\nimplement `IEnumerable` will not get nullability warnings; this is because `IEnumerator.Current` is unannotated. Given that we already skip nullability warnings\nthere for `foreach`, we're ok with skipping them on construction as well.\n\n#### Conclusion\n\nWe will do nullability analysis based on the iteration type of the collection expression.\n\n### Evaluation of implicit indexers in object initializers\n\nhttps://github.com/dotnet/csharplang/issues/7684\n\nThis is more of a bugfix clarification to the range feature in C# 8. For scenarios where an indexer is used in a nested member initializer, we need to decide\nwhat counts as the \"indexer\" as defined in the spec:\n\n> When an initializer target refers to an indexer, the arguments to the indexer shall always be evaluated exactly once. Thus, even if the arguments end up never\n> getting used (e.g., because of an empty nested initializer), they are evaluated for their side effects.\n\nThe question becomes: is the \"indexer\" here the virtual `Index`-based indexer, or is it the real `int`-based indexer that is called under the hood? This ends\nup having an effect on whether we call `Length` on the collection multiple times or not. While pathological, this _could_ potentially be observable if the nested\nmember initializer appends to the containing collection in some fashion. If we treat the `Index`-based indexer as the indexer referred to in the spec here, then\nappends will be observed. If we instead say the `int`-based indexer is the indexer referred to by the spec, appends would not be observed, as `Length` would only\nbe evaluated once. This has an even further wrinkle for empty nested initializers: do such initializers actually evaluate `Length`? If the `int`-based indexer is\nthe \"indexer\" in the above, the wording would suggest yes, as it is an \"argument\" to the indexer. However, we also think that there's a line of reasoning where\n\"argument\" is only referring to the user-written code: `Length` is not user written code, so by that logic, it would be safe to elide in the empty case. That leaves\nus with a few options:\n\n1. Cache the argument to the virtual `Index` indexer. Revaluate `Length` on every nested member initializer.\n2. Cache the argument to the real indexer. Evaluate `Length` even when the nested object initializer is empty.\n3. Cache the argument to the real indexer. Do not evaluate `Length` when the nested object initializer is empty.\n4. Adopt more aggressive caching across the board.\n\nWhile we think that, if we were redoing the feature today, we'd pick option 4, we don't think that we can make such a change at this point in the language evolution.\nAfter some discussion, we settled on option 3, falling back to 2 if it ends up being too complicated to implement.\n\n#### Conclusion\n\nOption 3, cache the argument to the real indexer, do not evaluate `Length` when the nested object initializer is empty, falling back to option 2 if it proves an\nimplementation challenge.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-11-27.md",
    "content": "# C# Language Design Meeting for November 27th, 2023\n\n## Agenda\n\n- [Pattern order optimizations](#pattern-order-optimizations)\n- [Subarray slicing breaking change](#subarray-slicing-breaking-change)\n- [Making patterns constant expressions](#making-patterns-constant-expressions)\n\n## Quote of the Day\n\n- \"Dark mode is hard to see, can you switch to light mode?\" *switches to light mode* \"Aaaargh!\"\n\n## Discussion\n\n### Pattern order optimizations\n\nhttps://github.com/dotnet/roslyn/issues/60091\n\nCurrently, Roslyn generates less-than-optimal code for list patterns, doing more expensive slicing before attempting to see if easily-accessible\nelements of a collection match. This is because, today, we emit the collection expression tests LTR (at least when considering a single pattern).\nThe language has always reserved the space to reorder pattern tests as it sees fit, but this is the first time that we're actually looking at a\nspecific case within a single pattern where we think we should reorder for performance reasons. There are certain cases where the guarantees around\nreordering can be painful: for example, `immutableArray is { IsDefault: false, Length: > 1 }` is not guaranteed to check `IsDefault` first, and the\n`Length` check could null ref if it was checked on a default immutable array. However, we don't think that this is one of those cases. There could\nbe some collection types where slicing is actually cheaper than indexing (a linked list, for example, needs to walk the whole thing anyway), but\nwe don't think that this is the majority case. At the same time, we do think that we should take another look at our ordering rules sometime during\nthe C# 13 timeframe and see if we can make stronger guarantees. We're not sure about this; in particular, the way that we deduplicate checks across\npatterns in a switch statement or expression makes it extremely hard to guarantee anything if properties are checked in different orders across those\npatterns. But we think it's worth a bit of effort to see if we can make it better.\n\n#### Conclusion\n\nWe are ok with reordering collection pattern testing. We will see if we can be more specific about the types of reordering in general.\n\n### Subarray slicing breaking change\n\nhttps://github.com/dotnet/roslyn/issues/69053\n\nThere's an interesting issue with array variance that was introduced in .NET 7 that breaks some expectations of pattern matching; when getting the\nsubarray of a variantly-converted array, the runtime will now make the subarray the variantly-converted type, not the original type of the array. This\nbreaks code that was type testing the subarray against the original type. Morever, we think the code that was broken was perfectly reasonable. We'll\ntalk with the runtime team to understand what the costs for reverting this change would be, and how we might be able to work around it in the compiler\nif we cannot revert it.\n\n#### Conclusion\n\nWe will follow up after talking with the runtime team around the behavior here.\n\n### Making patterns constant expressions\n\nhttps://github.com/dotnet/csharplang/issues/6926  \nhttps://github.com/dotnet/csharplang/pull/7589\n\nFinally today, LDM looked at a community-proposed specification for making `is` expressions constant when possible. On initial look, we didn't find much\nobjectionable in the specification, just a few comments on how it could be cleaned up to be more general. We also were interested in expanding the\nproposal to switch expressions. However, when we started drilling down on the existing subsumption behavior, we started to be a bit more concerned about\nbehavioral complexity. Specifically, we looked at some examples like this:\n\n```cs\npublic const int A = 4;\npublic  bool B1 = A is 4; // warning CS8520: The given expression always matches the provided constant.\n\npublic bool B2 = A switch { 4 => true }; // warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '0' is not covered.\npublic bool B3 = true is true and false; // error CS8518: An expression of type 'bool' can never match the provided pattern\n```\n\nToday, these warnings and errors are all sensible (except perhaps `B2`), as they would affect the code that the compiler would generate. However, if we\nstarted making patterns constant expressions everywhere, these warnings and errors might go away in more places than we expect, as the language would be\nunable to tell when we should warn about subsumption and when we shouldn't. There could be a version of this where we suppress these warnings when the\nexpression occurs within a location that must be a constant expression; ie, when in a `const` variable initializer, parameter default value, or other such\nlocation, but we're a little concerned about the potential complexity of such a change compared to the potential benefit of using patterns in these locations.\nAfter all, there's no new behavior with these patterns, it would just be a more concise way of expressing existing constant expressions. Given that, we think\nwe want to see an updated version of the specification with these rules to understand how big of a change it would be, and decide whether we're comfortable with\nit at that point.\n\n#### Conclusion\n\nWe need to see an updated specification with rules for dealing with subsumption before making a final decision on this feature.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-12-04.md",
    "content": "# C# Language Design Meeting for December 4th, 2023\n\n## Agenda\n\n- [Lock statement pattern](#lock-statement-pattern)\n- [`BinaryCompatOnlyAttribute`](#binarycompatonlyattribute)\n\n## Quote(s) of the Day\n\n- \"New syntax?\" \"`lock(ness) // monster`\"\n- \"Protect against Murphy, not Machiavelli.\"\n\n## Discussion\n\n### Lock statement pattern\n\nhttps://github.com/dotnet/csharplang/issues/7104\n\nWe started today by looking at an update for locking in .NET. .NET 9 is looking at adding a new locking primitive, `System.Threading.Lock`, and we need to\ndecide what, if anything, the language needs to do to react to this change. There are three main points of contention here:\n\n1. Should we do anything at all?\n2. If we do, do we try to protect against accidentally observing the wrong behavior?\n3. Do we support a general pattern here, or just one specific type?\n\nTo the first question, there is some question as to whether we're ok with adding a new behavior for the `lock` keyword. For users of C#, does `lock` specifically\nmean `Monitor.Enter()`, as it has for the entire lifetime of C#, or does it have a broader meaning? There are certainly other types of locks in the BCL that do\nnot do anything special with `lock` today; for example, `System.Threading.SpinLock` will not actually do a spin lock if `lock (spinLockInstance)` is done, but\nwill just call `Monitor.Enter()`. This may confuse some users, but it's worked this way since the type was introduced (.NET 4.0). Is `System.Threading.Lock`\nspecial enough that it needs separate handling? After some discussion, we think the answer is not only yes, we think it's unfortunate that `SpinLock` doesn't do\nsimilar. Instead of \"`lock` calls a specific API\", we think the general user intuition is \"`lock` enters a mutual exclusion zone and helps keep me safe from races\",\nwhich is a much broader intuition. We also think it would be generally unfortunate if the advice we give to users is \"Don't use the built-in `Lock` type with the\n`lock` keyword.\"\n\nNext, we looked at the immediate concerns brought up by 1: what about times when the lock is observed as an `object`, rather than as a `Lock`? The compiler cannot\nhandle this case in codegen, so the options for dealing with it are having the runtime handle it in `Monitor.Enter()` somehow, or performing some static analysis to\ntry and warn/error about when `Lock` is upcast to `object`. Having the runtime magically handle it is attractive from a language design standpoint, but unfortunately\nnot realistic from an implementation standpoint, particularly not unless we want to penalize all the existing locking code in .NET. Therefore, we turned to looking\nat static analysis. One thing that comes to the top of mind here is that, while there are lots of fun corner cases (unconstrained generics, for example), most of\nthese corners aren't likely anything that a user will actually do with a `Lock`. The use pattern for these types of objects is to simply store them as a class field\nand `lock(this.lock)` where necessary. Locks usually don't get passed around through generics or other such areas, as that generally violates encapsulation. So the\nnumber of bugs that errors for upcasting will prevent are likely small. That being said, we don't think we should just brush this potential risk off as being not\nrealistic either. Instead, we think that the compiler should perform some amount of static analysis, and warn where possible; this will catch most potential issues,\nbut leave an escape hatch for when users really want to do something more clever.\n\nFinally, we thought about generalizations. As mentioned earlier, we think it's unfortunate types like `SpinLock` aren't able to participate in `lock` as might be\nexpected. That being said, we don't particularly like the pattern-based approach this proposal is taking. This is something that could be an interface with a type\nparameter, except for the fact that the `Scope` type is a `ref struct` and cannot go in an interface. Given that we are investigating allowing `ref struct`s into\ngenerics, and that the runtime doesn't plan on changing anything but `System.Threading.Lock` for C# 13/.NET 9, we think we should just special case the new type for\nnow, and look at a broader pattern later when we have more use cases.\n\n#### Conclusion\n\nWe generally accept the changes for special casing how `System.Threading.Lock` interacts with the `lock` keyword, but we will not adopt the full pattern at this time.\nWe will look at static analysis warnings to help make sure that accidental missuse of the type does not occur.\n\n### `BinaryCompatOnlyAttribute`\n\nhttps://github.com/dotnet/csharplang/issues/7706  \nhttps://github.com/dotnet/csharplang/pull/7707\n\nFinally today, we took a (very) brief look at this proposal. There was strong support from LDM for a general feature, and the BCL also would make heavy usage of this\nif it was added. There are still plenty of open questions to be answered (and indeed, we need to answer if this is quite the right feature, or if the feature we really\nwant is a knob to control overload resolution at a finer grain), but we think we should take those questions on in the near term.\n\n#### Conclusion\n\nFeature moves into the working set.\n"
  },
  {
    "path": "meetings/2023/LDM-2023-12-11.md",
    "content": "# C# Language Design Meeting for December 11th, 2023\n\n## Agenda\n\n- [Extensions](#extensions)\n\n## Quote(s) of the Day\n\n- \"Welcome to the last regular LDM of the year.\" \"You missed the chance to do last explicit meeting.\" *Sigh* \"No, **you** could have done that\" \"I wanted you to pick it up implicitly.\"\n  \"If you keep making bad jokes we may have to extend the meeting.\"\n\n## Discussion\n\n### Extensions\n\nhttps://github.com/dotnet/csharplang/issues/5497\nhttps://github.com/dotnet/csharplang/issues/7771  \n\nNow that we're entering the next cycle of C# design, we're bringing back issues that have been on the backburner while we focused on C# 12. First on the docket is extensions; we started\nLDM with a quick recap on the general proposal, then dove straight into looking at the progress on lowering that has been made in the past few months. This design has evolved a great deal\nsince we initially looked at it, and has undergone multiple iterations as we discuss with runtime architects on what is feasible and what is not. Rather than restating the lowering document,\nthese notes will just point out some comments that we had while going over it.\n\n* We're unsure about the Punnett Square of extension inheritance, in particular whether implicit->implicit inheritance is actually necessary. The only question is whether we'll need that\n  for multiple implicit interface implementation; if there are multiple implicit extensions that implement different interfaces on a type, and then that type is used in a locaton that\n  constrains to both of those interfaces, will we need to synthesize a new implicit extension that inherits from each original extension to combine them? Will the user need to manually\n  introduce that extension?\n* We continue to have no good ideas on how to solve nested generics in the general case that can also handle extensions that add interfaces. The representation we've chosen currently\n  is representation-preserving at the top level, but `List<U>` cannot be easily converted to `List<E>` without an allocation somewhere.\n    * We could consider erasure here, but that will only postpone the problem, as extensions can add interfaces (eventually).\n* Interface member lookup through extensions will be tricky. If the runtime definition of an interface adds a member, and the underlying type has a method that would normally be automatically\n  hooked up to that member at runtime, what will do that for an extension implementation and its underlying type?\n    * May need some runtime help for this one.\n\nUltimately, there are no conclusions today. We'll keep iterating on these questions and bring lowering back to LDM for continued discussion in future sessions.\n"
  },
  {
    "path": "meetings/2023/README.md",
    "content": "# C# Language Design Notes for 2023\n\n## Mon Dec 11, 2023\n\n[C# Language Design Meeting for December 11th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-12-11.md)\n\n- Extensions\n\n## Mon Dec 4, 2023\n\n[C# Language Design Meeting for December 4th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-12-04.md)\n\n- Lock statement pattern\n- `BinaryCompatOnlyAttribute`\n\n## Mon Nov 27, 2023\n\n[C# Language Design Meeting for November 27th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-11-27.md)\n\n- Pattern order optimizations\n- Subarray slicing breaking change\n- Making patterns constant expressions\n\n## Wed Nov 15, 2023\n\n[C# Language Design Meeting for November 15th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-11-15.md)\n\n- `params` improvements\n- Nullability analysis of collection expressions\n- Evaluation of implicit indexers in object initializers\n\n## Mon Oct 16, 2023\n\n[C# Language Design Meeting for October 16th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-10-16.md)\n\n- Triage\n    - Breaking change warnings\n    - Determine natural type of method group by looking scope-by-scope\n    - u8 string interpolation\n    - Lock statement pattern\n    - String/Character escape sequence \\\\e as a short-hand for \\\\u001b \n    - New operator %% for canonical Modulus operations\n\n## Wed Oct 11, 2023\n\n[C# Language Design Meeting for October 11th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-10-11.md)\n\n- C# spec update\n- Collection expressions\n\n## Mon Oct 9, 2023\n\n[C# Language Design Meeting for October 9th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-10-09.md)\n\n- Triage\n    - ReadOnlySpan initialization from static data\n    - Embedded Language Indicators for raw string literals\n    - list-patterns on enumerables\n    - Make generated \\`Program\\`\\` for top-level statements public by default\n    - CallerCharacterNumberAttribute\n    - Add private and namespace accessibility modifiers for top-level types\n    - Require await to apply nullable postconditions to task-returning calls\n    - `is` expression evaluating `const` expression should be considered constant\n\n## Wed Oct 4, 2023\n\n[C# Language Design Meeting for October 4th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-10-04.md)\n\n- Trimming and AOT\n\n## Mon Oct 2, 2023\n\n[C# Language Design Meeting for October 2nd, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-10-02.md)\n\n- Collection expressions\n\n## Wed Sept 27, 2023\n\n[C# Language Design Meeting for September 27th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-09-27.md)\n\n- Collection expressions\n\n## Mon Sept 25, 2023\n\n[C# Language Design Meeting for September 25th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-09-25.md)\n\n- Primary constructors\n- Defining well-defined behavior for collection expression types\n\n## Wed Sept 20, 2023\n\n[C# Language Design Meeting for September 20th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-09-20.md)\n\n- Collection expressions\n    - Type inference from spreads\n    - Overload resolution fallbacks\n\n## Mon Sept 18, 2023\n\n[C# Language Design Meeting for September 18th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-09-18.md)\n\n- Collection expression questions\n    - Optimizing non-pattern collection construction\n    - Avoiding intermediate buffers for known-length cases\n\n## Wed Aug 16 2023\n\n[C# Language Design Meeting for August 16th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-08-16.md)\n\n- Ref-safety scope for collection expressions\n- Experimental attribute\n\n## Mon Aug 14, 2023\n\n[C# Language Design Meeting for August 14th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-08-14.md)\n\n- Betterness for collection expressions and span types\n- Type inference from collection expression elements\n- Collection expression conversions\n\n## Wed Aug 9, 2023\n\n[C# Language Design Meeting for August 9th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-08-09.md)\n\n- Lambdas with explicit return types\n- Target typing of collection expressions to core interfaces\n- Loosening requirements for collection builder methods\n\n## Mon Aug 7, 2023\n\n[C# Language Design Meeting for August 7th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-08-07.md)\n\n- Improvements to method group natural types\n\n## Mon Jul 31, 2023\n\n[C# Language Design Meeting for July 31st, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-07-31.md)\n\n- Primary constructor parameters and `readonly`\n\n## Wed Jul 26, 2023\n\n[C# Language Design Meeting for July 26th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-07-26.md)\n\n- Primary constructor parameters and `readonly`\n\n## Mon Jul 24, 2023\n\n[C# Language Design Meeting for July 24th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-07-24.md)\n\n- Method group natural types with extension members\n- Interceptors\n\n## Mon Jul 17, 2023\n\n[C# Language Design Meeting for July 17th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-07-17.md)\n\n- Compiler Check-in\n- `readonly` parameters\n\n## Wed Jul 12, 2023\n\n[C# Language Design Meeting for July 12th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-07-12.md)\n\n- Collection Literals\n    - `Create` methods\n    - Extension methods\n- Interceptors\n\n## Mon Jun 19, 2023\n\n[C# Language Design Meeting for June 19th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-06-19.md)\n\n- Prefer spans over interfaces in overload resolution\n- Collection literals\n\n## Mon Jun 5, 2023\n\n[C# Language Design Meeting for June 5th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-06-05.md)\n\n- Collection literals\n\n## Wed May 31, 2023\n\n[C# Language Design Meeting for May 31st, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-05-31.md)\n\n- Collection literals\n\n## Wed May 17, 2023\n\n[C# Language Design Meeting for May 17th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-05-17.md)\n\n- Inline arrays\n\n## Mon May 15, 2023\n\n[C# Language Design Meeting for May 15th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-05-15.md)\n\n- Breaking Change Warnings\n- Primary Constructors\n\n## Mon May 8, 2023\n\n[C# Language Design Meeting for May 8th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-05-08.md)\n\n- Primary Constructors\n\n## Wed May 3, 2023\n\n[C# Language Design Meeting for May 3rd, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-05-03.md)\n\n- Inline Arrays\n- Primary constructors\n    - Attributes on captured parameters\n    - Warning for shadowing base members\n- Collection literal natural type\n\n## Mon May 1, 2023\n\n[C# Language Design Meeting for May 1st, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-05-01.md)\n\n- Fixed Size Buffers\n- `lock` statement improvements\n\n## Wed Apr 26, 2023\n\n[C# Language Design Meeting for April 26th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-04-26.md)\n\n- Collection literals\n\n## Mon Apr 10, 2023\n\n[C# Language Design Meeting for April 10th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-04-10.md)\n\n* Fixed Size Buffers\n\n## Mon Apr 3, 2023\n\n[C# Language Design Meeting for April 3rd, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-04-03.md)\n\n- Collection Literals\n- Fixed-size buffers\n\n## Wed Mar 15, 2023 (No notes)\n\n- Discriminated Unions\n- Interceptors\n\n## Mon Mar 13, 2023 (Shorter meeting)\n\n[C# Language Design Meeting for March 13th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-03-13.md)\n\n- Unsafe in aliases hole\n- Attributes on primary ctors\n\n## Wed Mar 8, 2023\n\n[C# Language Design Meeting for March 8th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-03-08.md)\n\n- Discriminated Unions\n- Limited Breaking Changes in C#\n\n## Wed Mar 1, 2023 (Shorter meeting)\n\n[C# Language Design Meeting for March 1st, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-03-01.md)\n\n- Discriminated Unions Summary\n\n## Mon Feb 27, 2023\n\n[C# Language Design Meeting for February 27th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-02-27.md)\n\n- Interceptors\n\n## Wed Feb 22, 2023\n\n[C# Language Design Meeting for February 22nd, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-02-22.md)\n\n- Primary Constructors\n- Extensions\n\n## Wed Feb 15, 2023\n\n[C# Language Design Meeting for February 15th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-02-15.md)\n\n- Open questions in primary constructors\n    - Capturing parameters in lambdas\n    - Assigning to `this` in a `struct`\n\n## Wed Feb 1, 2023\n\n[C# Language Design Meeting for February 1st, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-02-01.md)\n\n- Position of `unsafe` in aliases\n- Roles and extensions\n\n## Wed Jan 18, 2023\n\n[C# Language Design Meeting for January 18th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-01-18.md)\n\n- Nullable post-conditions and `async`/`await`\n- Semi-colon bodies for type declarations\n\n## Wed Jan 11, 2023\n\n[C# Language Design Meeting for January 11th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-01-11.md)\n\n- `using` aliases for any types\n    - Pointer types in aliases\n    - Reference nullability in aliases\n    - Value nullability in aliases\n\n## Mon Jan 9, 2023\n\n[C# Language Design Meeting for January 9th, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-01-09.md)\n\n- Working group re-evaluation\n"
  },
  {
    "path": "meetings/2024/LDM-2024-01-08.md",
    "content": "# C# Language Design Meeting for January 8th, 2024\n\n## Agenda\n\n- [Collection expressions](#collection-expressions)\n    - [Iteration type of `CollectionBuilderAttribute` collections](#iteration-type-of-collectionbuilderattribute-collections)\n    - [Iteration type in conversions](#iteration-type-in-conversions)\n\n## Quote of the Day\n\n- \"Can we do another one in 15 minutes?\" \"I think it'll take another whole meeting\"\n\n## Discussion\n\n### Collection expressions\n\n#### Iteration type of `CollectionBuilderAttribute` collections\n\nhttps://github.com/dotnet/csharplang/issues/5354  \nhttps://github.com/dotnet/csharplang/blob/1f55d3c05d549edc817589502bfee90db887d56e/proposals/csharp-12.0/collection-expressions.md#specification-of-a-constructible-collection-type-utilizing-a-create-method-is-sensitive-to-the-context-at-which-conversion-is-classified\n\nFirst up today, we looked at a change to how collection expressions determine the iteration type of a collection expression, motivated by our work on `params` improvements.\nOur specification for `CollectionBuilder` types does not require that they define their own iteration types, but can instead pick them up through extension methods; this means\nthat it is possible that a `params` parameter is only valid as `params` in some contexts, not all. This is potentially undesirable for users, and it means that it is very hard\nto give correct errors for `params` parameters. The current behavior was intentional, as it is mirror to `foreach`, but we are sympathetic to the idea that, if a type can be\ncreated by a collection expression, it should also be generally foreachable. Extension `GetEnumerator` can be used to add `foreach`ability to a type, but we are fine with saying\nthat such types cannot be constructed with a collection expression, and that types that use `CollectionBuilder` should actually define their own iteration types. We will take this\nfor a C# 12 update (in the 8.0.2xx or 8.0.3xx branch of .NET 8), not hold it until C# 13.\n\nWe also thought about whether to require that the `Create` method specified by the `CollectionBuilder` attribute is public, for symmetry with `GetEnumerator`. We're not convinced\nof this one: it seems like perfectly reasonable public API policy to expose a type that is publicly foreachable, but not publicly buildable. It does mean that users can put `params`\non a parameter in a method that is more visible than the `Create` method for creating the parameter, but that seems squarely a mistake of API design, and not something that C#\nshould prevent.\n\n##### Conclusion\n\nWe will require that types with a `CollectionBuilder` have a public iteration type. This means either implementing one of the `IEnumerable` interfaces, or providing a `GetEnumerator`\nmethod. We will not require that their `Create` methods are any particular visibility, as today.\n\n#### Iteration type in conversions\n\nhttps://github.com/dotnet/csharplang/issues/5354  \nhttps://github.com/dotnet/csharplang/blob/1f55d3c05d549edc817589502bfee90db887d56e/proposals/csharp-12.0/collection-expressions.md#the-notion-of-iteration-type-is-not-applied-consistently-throughout-conversions\n\nThe wording of how collection expression conversions are determined can lead to some confusion in particularly weird scenarios, when a type that implements `IEnumerable<T>` does so\nprivately and its iteration type is actually completely different. We will therefore change the wording to reflect the iteration type directly, rather than special casing the various\n`IEnumerable` interfaces. This has the benefit of simplifying the specification, and we expect that it will affect no real user code except the compiler test base.\n\n##### Conclusion\n\nChange is accepted. We will reword the conversion existence part of the specification to be based on iteration type directly.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-01-10.md",
    "content": "# C# Language Design Meeting for January 10th, 2024\n\n## Agenda\n\n- [Collection expressions: conversion vs construction](#collection-expressions-conversion-vs-construction)\n\n## Quote of the Day\n\n- Nothing particularly amusing was said today\n\n## Discussion\n\n### Collection expressions: conversion vs construction\n\nhttps://github.com/dotnet/csharplang/issues/5354  \nhttps://github.com/dotnet/csharplang/blob/d7bbc5456e51bf29ece89112a2bb10153e98a524/proposals/csharp-12.0/collection-expressions.md#should-collection-expression-conversion-require-availability-of-a-minimal-set-of-apis-for-construction\n\nToday we looked at another scenario in collection expressions brought up by our work on `params` improvements. This time, we considered scenarios\nthat would be an error when used as `params`, but due to how collection expressions were specified, cannot be considered an error at definition, only\nat usage; basically any type that implements `IEnumerable` or `IEnumerable<T>` is valid to be used as a `params` type, even if it cannot be constructed\nin any real scenario. This means that, rather than the method author getting an error that their `params` parameter is invalid, the end user gets a worse\nerror about being unable to construct the parameter type. To address that, we are looking at two potential changes: require that the type has an accessible\nconstructor, and an accessible `Add` method that can be invoked with the _iteration type_ of the collection expression. We would then further restrict\n`params` to require that these are as accessible as the method itself, to ensure that if something is defined as `params`, it can be used as `params` when\nseen.\n\nWe do, however, have some concerns, particularly around API evolution. There's a tension here between what we want to be considered convertible to collection\nexpressions, and what we want to prevent. A prime example is `System.Collection.ImmutableArray<T>`; this type has always supported collection initializers\nat compile-time, because it has an `Add` method, but it then blows up at runtime because `Add` doesn't actually mutate the underlying array, it instead\nreturns a new `ImmutableArray`, and produces a `NullReferenceException` when doing so on a `new ImmutableArray<T>()`. We could try to prevent the compiler\nfrom recognizing invalid `Add` methods, but we _do_ still want to recognize the older version of `ImmutableArray<T>` for collection expressions. By doing\nso, we ensure that overload resolution gives good errors (`ImmutableArray<T>` isn't constructible), rather than giving errors that no applicable methods\ncould be found; worse, not recognizing older versions of `ImmutableArray<T>` as valid conversion targets for collection expressions could then mean that\nupgrading `System.Collections.Immutable` potentially causes a source-breaking change in overload resolution. The point is somewhat moot for `ImmutableArray<T>`,\nas it has already been upgraded and the compiler has taken a bit of liberty with older versions to mark them as bad at compile-time, but we have no guarantees\nthat other community-created types that have similar construction foibles have indeed upgraded to use `CollectionBuilderAttribute`. We debated a few different\npossible restrictions:\n\n* Only allow `Add` methods that return `void` or `bool`.\n    * This would mean that older collection types like `ImmutableArray<T>` version 7.0 wouldn't be considered convertible.\n* Only forbid `Add` methods that return the type itself, like `ImmutableArray<T>.Add` does.\n    * This doesn't solve the v7.0 problem from the above problem.\n    * It may still exclude valid types that have a fluent calling style.\n* What if we made the existence of a conversion only look for an accessible `Add`, and then further restrict \"creatability\" further down the line?\n    * This would us to keep overload resolution stable for older APIs, and then let them upgrade to `CollectionBuilderAttribute` in new versions without\n      potentially introducing a source-breaking change.\n\nWe distilled an important characteristic from these discussions: we don't think that `IEnumerable<T>`, by itself, is enough of a signal to make a type\nbe a creatable collection type. Instead, what we're looking for is a set of restrictions that signal the intent of the type author that users should be able\nto construct the collection type. For `CollectionBuilderAttribute`, that is enough of a signal by itself. However, we need a similar rule for `IEnumerable<T>`,\nand we think the existing signal for collection initializers serves as a good, well-established signal. Given this, we re-examined our handling of `string`.\nWe intentionally left `string` as a valid conversion target for collection expressions, but under the newly proposed rules it would not be. After some more\nthinking, we're fine with this. In particular, we think that, even if we were to implement support for collection expressions to create `string`s in the future,\nwe'd need to deprioritize it in overload resolution compared to `char[]`. Given that, it doesn't make sense to hold a place for it, and we'll let the new rules\nmark it as not a valid conversion target.\n\nFinally today, we looked at additional restrictions for `params` parameters, on top of what we considered today. In particular, we want to make sure that, when\na user declares a method with a `params` parameter, you don't have to have a specific `using` in order to use it in that format. To that end, we will require\nthat the accessible `Add` method for `params` be an instance member, rather than an extension method.\n\n#### Conclusions\n\nWe accept the proposed rules for collection expressions:\n\n> For a struct or class type that implements System.Collections.IEnumerable and that does not have a create method conversions section should require presence of at least the following APIs:\n>\n> * An accessible constructor that is applicable with no arguments.\n> * An accessible Add instance or extension method that can be invoked with value of iteration type as the argument.\n\nWe will not save a spot for `string`.\n\nFor `params` parameters, we additionally require that the `Add` method be an instance method.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-01-22.md",
    "content": "# C# Language Design Meeting for January 22nd, 2024\n\n## Agenda\n\n- [Ref struct interfaces](#ref-struct-interfaces)\n- [Interceptors](#interceptors)\n\n## Discussion\n\n### Ref struct interfaces\n\nhttps://github.com/dotnet/csharplang/blob/main/proposals/ref-struct-interfaces.md\n\nRef structs are not currently allowed to implement interfaces. The reason is that we cannot allow them to be boxed, because they are not permitted in heap memory. \n\nHowever, this prevents ref structs from participating in the core abstraction mechanism we use to describe patterns and shapes of types in C#. For example, `Span<T>` cannot implement `IEnumerable<T>`, and methods that rely on that need to have dedicated span overloads with virtually the same implementation.\n\nThe proposal allows ref structs to implement interfaces, but does not allow them to be boxed to those interfaces. Default implementations cannot be called, because that involves boxing the receiver. \n\nThe way you can take advantage of the interface is by using it to satisfy a generic constraint. Generic code today does allow type parameters to be converted to their constraints, which would again lead to boxing of ref structs used as type arguments. So the proposal introduces the idea of an \"anti-constraint\", whereby a type parameter explicitly permits ref structs at the cost of not being able to box it inside the generic code. Such a type parameter would also participate in the lifetime tracking that we apply to refs and ref structs.\n\nThe proposal anticipates other possible \"anti-constraints\" in the future - extra permissions on a type parameter allowing type arguments that wouldn't be admissible by default - and suggests a syntax for them that can grow to encompass these over time. Here's an example from the proposal:\n\n``` c#\nT Identity<T>(T p)\n    allow T : ref struct\n    => p;\n\n// Okay\nSpan<int> local = Identity(new Span<int>(new int[10]));\n```\n\nWe discussed where we would add the `allow T : ref struct` anti-constraint in our existing libraries. The answer is, probably nearly all our core abstractions. There might be breaking changes here, but we haven't thought of any serious ones, beyond the overload-resolution-with-lambdas ones that we usually accept. If we were to add anti-constraints to existing library types we would need to check for problems in VB and F# too.\n\nThe feature requires runtime support, and the runtime team has already done some work on this, but we need to make sure things line up.\n\nCould we use this to make LINQ work with span types as source collections? That's complicated because many query methods store the source for later - deferred - query evaluation, and we can't store ref structs in objects! It may be disappointing to users that this feature doesn't enable LINQ scenarios.\n\nOn the syntax front, we have some skepticism: One problem is that \"allow\" and \"where\" aren't the same kind of word, grammatically, and so reading the proposed syntax may get confusing and inelegant. Another is that you now sometimes need two separate clauses that talk about the same type parameter; a `where T : ...` and an `allow T : ...` clause. Perhaps we could address both of those problems by folding the anti-constraint syntax into the constraint syntax as an optional suffix:\n\n``` c#\nwhere T : IEnumerable<T>, allows ref struct\n```\n\nFinally, a more nebulous concern is how this could interact with other things we might do with generics in the future - the \"unknown unknowns\".\n\n#### Conclusion\n\nThere are several open questions around the specifics of the design, but we think the feature is valuable and want to keep working through it.\n\n### Interceptors\n\nhttps://github.com/dotnet/csharplang/issues/7009\n\nWe've had an early prototype of interceptors out with C# 12/.NET 8, and are now looking at making the feature stable.\n\nThe prototype relies on the use of file paths in a way that has turned out to be problematic, since it makes the source code not portable. To that end we want to allow relative paths - in practice you'd rarely have a situation where that won't suffice. \n\nAnother current problem with using file paths is that files sometimes aren't emitted to disk (yet). We could address this by making such files identifiable using the path that they *would* be emitted to. \n\nAn alternative to file paths would be to have a more opaque location token that doesn't have source-level \"meaning\". If we recognize that interceptors will always be generated, why does this need to be something that can be written and understood by a human? However, such an approach comes with its own challenges when you try to implement it in practice. We'll keep investigating it as a possible future addition, but for now the file-path-based approach is what we'll aim at shipping.\n\nIt's important that tools can identify that a given call is intercepted, so there needs to be good APIs for that which don't incur the cost of binding everything.\n\nThis feature relies on source generation, but where many other source generators are about enhancing the surface area for the developer, it's desirable that interceptors are *hidden* from being manually called, and only affect the call site that they are intercepting. This can also lower the cost of the source generation, and the frequency at which it runs.\n\n#### Conclusion\n\nThis is not a feature area that is primarily driven from the language. There is no new proposed syntax, but there is some language-level behavior. We should keep the LDM in the loop as this feature area evolves, so that language-level concerns continue to be factored in."
  },
  {
    "path": "meetings/2024/LDM-2024-01-29.md",
    "content": "# C# Language Design Meeting for January 29th, 2024\n\n## Agenda\n\n- [`params` collections](#params-collections)\n  - [Better function member changes](#better-function-member-changes)\n  - [`dynamic` support](#dynamic-support)\n- [`dynamic` and `ref` local function bugfixing](#dynamic-and-ref-local-function-bugfixing)\n\n## Quote of the Day\n\n- \"I got a new webcamera, I think I look kinda washed out... Insert C# joke\"\n\n## Discussion\n\n### `params` collections\n\nhttps://github.com/dotnet/csharplang/issues/7700  \n\n#### Better function member changes\n\nhttps://github.com/dotnet/csharplang/blob/7a506890f909ea06d8b8396eb5e86a92c8482ade/proposals/params-collections.md#better-function-member\n\nWe started today by reviewing the proposed rules for how `params` collections will handle better function member. These rules generally try to apply the pre-existing\nrules we have around `params` arrays to the new scenarios of `params` collections. However, we can't just think of these as \"wrap the arguments with `[]`, and that's\nthe result you should get, as that already doesn't work for `params` arrays. As an example:\n\n```cs\nTest([1,2,3]); // error CS0121: The call is ambiguous between the following methods or properties: 'Program.Test(params int[])' and 'Program.Test(params long[])'\nTest(1, 2, 3); // We pick 'static void Test(params int[] x)'\n\npartial class Program\n{\n    static void Test(params int[] x) {}\n    static void Test(params long[] x) {}\n}\n```\n\nThere are also some scenarios where `params` may be ambiguous where an explicit collection expression would not be, such as:\n\n```cs\nstatic void Test3()\n{\n    M3(\"3\", [\"4\"]); // Span overload is used, better on the first argument conversion, none is better on the second\n    M3(\"3\", \"4\");   // Ambiguity, better-ness of argument conversions goes in opposite directions.\n                    // Since parameter types are different (\"object, string\" vs. \"string, object\"), tie-breaking rules do not apply\n}\n\nstatic void M3(object x, params string[] y) {}\nstatic void M3(string x, params Span<object> y) {}\n```\n\nHowever, we don't think these are common scenarios that need to be particularly concerned about, and they don't significantly affect the overall goal of making the\nway that users conceive of the language simpler, even if some of the nitty-gritty edge cases will be more complex than they appear.\n\n##### Conclusion\n\nThe rules are approved as proposed. We will watch early adopters (particularly the BCL) to make sure that there's no cases in the real world that we didn't think of\nduring this work.\n\n#### `dynamic` support\n\nhttps://github.com/dotnet/csharplang/blob/7a506890f909ea06d8b8396eb5e86a92c8482ade/proposals/params-collections.md#dynamic-vs-static-binding\n\nNext, we looked at `dynamic` support. We don't expect the runtime binder to be updated to understand `params` collections, so we need to consider how to handle when we detect\nthat users are potentially going to encounter a runtime exception. We overall think that it's a good idea to try give warnings or errors when we know that candidates\nwill either be excluded or that there are no callable candidates.\n\n##### Conclusion\n\nThe rules around `dynamic` binding are accepted as proposed.\n\n### `dynamic` and `ref` local function bugfixing\n\nhttps://github.com/dotnet/roslyn/issues/71399\n\nFinally today, we looked at a bug in the C# compiler that was uncovered during the investigation into `params` collections. The decision on the previous section makes\nfixing this more important, as it affects what \"applicable\" candidates appear during overload resolution. The main question we have is not whether to fix the bug, but\nhow broad to make the fix; do we report the error in _all_ language versions, or just in C# 13? This seems fairly low-risk: the compiler only has 1 test that is affected\nby this, and the test covers a scenario that will fail at runtime anyway. We can revisit this later if it turns out to be a more broad breaking change.\n\n#### Conclusion\n\nWe will fix this bug in all language versions.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-01-31.md",
    "content": "# C# Language Design Meeting for January 31st, 2024\n\n## Agenda\n\n- [Relax \"enumerable\" requirement for collection expressions](#relax-enumerable-requirement-for-collection-expressions)\n- [`params` collections evaluation orders](#params-collections-evaluation-orders)\n\n## Quote of the Day\n\n- \"It doesn't matter so much because it's already so bad\"\n\n## Discussions\n\n### Relax \"enumerable\" requirement for collection expressions\n\nhttps://github.com/dotnet/csharplang/issues/7744\n\nWe started today by looking at a proposal to relax the requirement that types attributed with `CollectionBuilderAttribute` be enumerable in some fashion, as defined by `foreach`.\nThis was done because want the type to \"signal\" that it is a collection type, and to give the specification some way of determining the element type of the collection, which we\ndo by looking at the iteration type from enumeration. However, a few cases have since been brought up of what are essentially collection builder types; they cannot be directly\nenumerated, but can be materialized into iterable collections, and it may be idiomatic for us to allow using collection expressions to construct them. We could therefore use\n`CollectionBuilderAttribute` as an explicit signal that the type it's applied to is a collection of some kind. We then need to figure out how we update the spec to account for\nthis, given our current heavy use of the \"iteration type throughout. We also need to consider what to do when the iteration type and the type of a create method don't line up.\nFor both of these scenarios, we're currently thinking that we should maintain backwards compat; ie, if the collection defines an iteration type, then that's the one that's\npreferred, as today. This would just be a fallback rule in the case that no iteration type was defined. However, the exact rules to flow through the rest of the spec will need\nto be looked at by the collection expressions working group and brought back as a more complete proposal, as they're more complex than what was initially brought today.\n\n#### Conclusion\n\nThe proposal is approved and put in the working set, and we will work on the specific wording as part of the collection expression changes in C# 13.\n\n### `params` collections evaluation orders\n\nhttps://github.com/dotnet/csharplang/issues/7700  \nhttps://github.com/dotnet/csharplang/blob/951276cbc2f0ec3d688747109e904a3ddd6b29c5/proposals/params-collections.md#order-of-evaluation-with-non-array-collections-in-non-trivial-scenarios\n\nLastly today, we looked at evaluation orders for `params` collections in several non-trivial nested examples. In general, we approved the proposed rules without significant\ndiscussion. The main point of evaluation was around how reuse of the collection will differ from how `params` arrays work in nested indexers in object initializers. The existing\n`params` array behavior is, as far as we can tell, actually unspecified behavior in C#; the spec appears to permit reuse of the array instance, but it does not require it. We think\nthat for `params` collections, we can do better, but we do not currently intend on changing the behavior of `params` arrays.\n\n#### Conclusion\n\nRules are adopted as written.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-02-05.md",
    "content": "# C# Language Design Meeting for February 5th, 2024\n\n## Agenda\n\n- [First-class span types](#first-class-span-types)\n- [Collection expressions: inline collections](#collection-expressions-inline-collections)\n\n## Quote of the Day\n\n- \"Did I spell legite correctly? My Memory<spelling> isn't that great\" \"No, it's legit. Trailing e would make it like vegemite.\"\n\n## Discussion\n\n### First-class span types\n\nhttps://github.com/dotnet/csharplang/issues/7905  \nhttps://github.com/dotnet/csharplang/pull/7904\n\nWe started today by looking over a new proposal aimed at addressing a few pain points with `Span` and `ReadOnlySpan` that the language and library authors\nhave encountered since their introduction. These are areas that arrays work well in, but `Span` and `ReadOnlySpan` do not. To that end, we reviewed a\nproposal for treating these types more specially in the language, much as we do for array types. We had a few thoughts on specific parts of the proposal:\n\n* Even though `ReadOnlySpan<T>` exposes the `T` by `ref`, it's always a `readonly ref`, so we're fine to treat it as if it's covariant. If the `T` was just\n  by `ref`, it wouldn't be safe.\n* We're fine with `is` not working covariantly. This is the same thing as `int` to `long` conversions: C# can do it, but the runtime doesn't know about the\n  conversion in type checking.\n* We thought about whether this should extend to `Memory<T>`, but are wary of it. `Memory<T>` does not have an implicit conversion to `Span<T>`/`ReadOnlySpan<T>`\n  because, depending on the backing storage, it can have a cost to convert, and we'd be worried about suddenly creating such conversions in the language.\n    * At the same time, though, we are also sympathetic to the concern that, if a code path needs to be `async`ified and converted to `Memory<T>`, that may\n      necessitate more changes to allow what works for `Span<T>` to work in the `async` world.\n* We may need to keep special cases for betterness to keep `ReadOnlySpan<T>` better than `Span<T>`; in the psuedo type hierarchy, `Span<T>` is better than\n  `ReadOnlySpan<T>`, because it is more specific. However, this is not what we want overload resolution to choose, since `Span<T>` offers worse performance\n  in most cases.\n\nOverall, we like the direction of this proposal, and want to proceed with it. We'll answer open questions as implementation progresses.\n\n#### Conclusion\n\nProposal is accepted.\n\n### Collection expressions: inline collections\n\nhttps://github.com/dotnet/csharplang/issues/7913  \nhttps://github.com/dotnet/csharplang/pull/7864\n\nNext, we looked at one of the collection expression topics we want to handle in C# 13, inline collection expression usage. These are scenarios where a collection\nexpression is immediately used and never observed outside an expression, usually to handle some kind of conditional addition to a collection, or to enumerate\nin a `foreach`. The main question here is whether we should rely purely on natural typing for these scenarios, or whether target element typing should flow in\nsomehow. For example:\n\n```cs\n// If `byte` doesn't flow into the conditional as an element type, the natural element type will be `int`, and the conversion will fail\nbyte[] x = [1, .. b ? [2] : []];\n\n// If `bool?` doesn't flow into the iteration expression, there will be a compile error because no natural type can be found\nforeach (bool? b in [true, false, null]) {}\n```\n\nWe do have some disagreements on how exactly that information would flow into the expression to give it a final type: do we have to have some stopgap solution\nuntil we have a natural type concept, or can we just integrate with that? We're generally in agreement that these examples should be able to compile, meaning\nthat we are generally in favor of flowing in an element type in some fashion. With this direction, we think the working group can take the lead on integrating\nwith natural typing work and then propose the final approach to LDM (or propose that it doesn't integrate with specific reasoning for why it shouldn't).\n\n#### Conclusion\n\nWe are in favor of target element typing flowing into collection expressions.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-02-07.md",
    "content": "# C# Language Design Meeting for February 7th, 2024\n\n## Agenda\n\n- [Partial type inference](#partial-type-inference)\n- [Breaking change warnings](#breaking-change-warnings)\n\n## Quote of the Day\n\n- \"It's easy to dismiss as well, that's just math\"\n\n## Discussion\n\n### Partial type inference\n\nhttps://github.com/dotnet/csharplang/issues/1349  \nhttps://github.com/dotnet/csharplang/pull/7582\n\nWe started today by looking at an Any Time proposal being worked on by a community member, @TomatorCZ, for partial type inference. He's been working on this proposal as\npart of his master's thesis, and it's now at the point that LDM can take an initial look. One important thing that we wanted to establish was the motivation of the proposal.\nWe're not just trying to put `_` or `var` in more places; instead, what we're trying to do is ease the cliff between scenarios where the compiler can fully infer a type, vs\nwhen it needs a bit of prodding to get the desired result. Thus, we are interested in the nested levels of type inference, because they allow the user to prod the compiler\ninto, for example, choosing a specific type of collection (`IEnumerable<T>` over `List<T>`) for a specific generic method, while not forcing the user to restate the element\ntype that is forced by some other input to the generic method.\n\nOne immediate concern, though, is that while this nesting of inference is very powerful, it could also lead to unbounded computation if not done carefully. The proposal has\nbeen crafted with this in mind, as it is designed to ensure:\n\n* Inference is bounded by the statement level. Statements cannot have inference effects on other statements except through lambda bodies, as can happen today.\n* Inference cannot visit a single expression more than twice when calculating types.\n\nThis ensures that we aren't looking at a Hindley-Milner level of complexity, and hopefully helps keep the error scenarios constrained enough to offer good diagnostics. The\nC# compiler already has some issues with giving good diagnostics in lambda scenarios, and we don't want to make it worse across the board by having non-local analysis failures.\n\nFinally, we briefly considered the tooling aspect of this feature; like `var`, some users may wish to explicitly turn inference off, or turn it off unless the type inferred\nis apparent. We think this is mostly a tooling problem, and that it should be solvable, though defining what \"is apparent\" will mean here may take some tweaking over time.\n\nWe're happy with this proposal as a starting point and want to keep working on it. It's not going to make C# 13, but we have high hopes for the proposal, and think it's heading\nin the right direction. We'll tackle specific open questions and design points in later sessions.\n\n#### Conclusion\n\nProposal will keep moving forward.\n\n### Breaking change warnings\n\nhttps://github.com/dotnet/csharplang/issues/7189  \nhttps://github.com/dotnet/csharplang/issues/7918\n\nNext, we looked at the newest proposal for breaking change warnings. We had a few decisions we wanted to make here:\n\n1. Are the set of breaking change criteria generally reasonable?\n2. Do they apply to `field`?\n3. Are we ok with changing or removing the `latest` language version?\n\nFor the 1, we think we're ok with the criteria laid out here, but we do want to go even further: we'd like to have users be able to opt-in to warnings _after_ an upgrade, in\ncase they did not migrate using whatever garden-path approach we create. In other words, to apply to `field`, we'd like a warning after the user is on C# 13 for \"there was a\n`field` in scope that we're not binding to anymore, did you mean to do that?\" warning.\n\nNext, we looked at applying the criteria specifically to `field`. We didn't come to any hard conclusions here: there is some amount of verbal consensus that `field` would fit,\nbut we also do want to make sure that we're not holding the feature hostage for breaking changes any more than we already have.\n\nFinally, we thought a bit about changing the `Latest` langversion. This ended up being a spirited discussion; there are ~6000 usages of the flag on GitHub, with a decent number\nin internal repos as well. We're not entirely certain that changing it would meet the breaking change criteria we laid out in 1.\n\n#### Conclusions\n\nWe're generally in favor of the criteria, but we want to look at post-upgrade opt-in warnings as well to help with non-linear upgrade paths as well.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-02-21.md",
    "content": "# C# Language Design Meeting for February 21st, 2024\n\n## Agenda\n\n- [Declaration of ref/out parameters in lambdas without typename](#declaration-of-refout-parameters-in-lambdas-without-typename)\n- [`params` collections](#params-collections)\n    - [Metadata format](#metadata-format)\n    - [`params` and `scoped` across `override`s](#params-and-scoped-across-overrides)\n    - [`required` members and `params` parameters](#required-members-and-params-parameters)\n\n## Quote of the Day\n\n- \"People just stopped coming in\" \"I stopped coming in on Mondays. Today\" \"is not a Monday!\"\n\n## Discussions\n\n### Declaration of ref/out parameters in lambdas without typename\n\nhttps://github.com/dotnet/csharplang/issues/338  \nhttps://github.com/dotnet/csharplang/blob/main/proposals/simple-lambda-parameters-with-modifiers.md\n\nWe started today by looking at an Any Time proposal specification to address a common cliff: when using a delegate type with a modifier of any kind, users are required to spell out the parameter types\nof that lambda. This is a change that the LDM has long mentioned in passing, but has never actually gone through and specified. In addition to the main proposal, we also discussed few potential\nalternatives:\n\n* We could potentially infer the `ref`/`out` modifiers, rather than having the user restate them. We don't like this option; C# thinks that changes in calling convention are very important, to the point\n  that we require `ref` or `out` at callsites. We think this would be the same cliff, and that therefore it should require the modifiers be stated explicitly.\n* We could go further, and allow some lambda parameters to be fully stated, and others to be just names. We don't currently have any real driving use cases for such a feature though, and it would be\n  quite complex. It would also likely want to be designed at the same time as thinking about the partial type inference proposal.\n\nWe therefore wish to move forward with this proposal. We turned to thinking about the open questions. For both of them, we think that there are some implementation complexities that, while not insurmountable,\nwould be challenging. Given this, and the lack of requests for either feature, we think that we should simply say that neither attributes nor default parameter values will be supported without a fully-typed\nlambda, as it works in C# 12. We do note that the specese will need to be cleaned up a bit: _implicit_anonymous_function_parameter_ex_ isn't a great name to put in the spec, but that can be fixed up without\nblocking the feature.\n\n#### Conclusion\n\nThe proposed specification is approved as proposed. Both open questions are rejected.\n\n### `params` collections\n\nhttps://github.com/dotnet/csharplang/issues/7700\n\nIn the second half of the meeting today, we went over the remainder of the `params` collections specification and open issues.\n\n#### Metadata format\n\nhttps://github.com/dotnet/csharplang/blob/9d12a983190ba5d25fb037a2566bb1e99d486c49/proposals/params-collections.md#metadata\n\nThe `params` collections proposal suggests using a new attribute type to declare when a non-array type is `params`, in order to avoid potential interop issues with non-C# compilers. After looking at\nthe proposal and the reasons for it, the LDM is fine with this approach. The attribute will need to go through the BCL's design review.\n\n##### Conclusion\n\nProposed metadata format is approved.\n\n#### `params` and `scoped` across `override`s\n\nhttps://github.com/dotnet/csharplang/blob/9d12a983190ba5d25fb037a2566bb1e99d486c49/proposals/params-collections.md#consider-enforcing-scoped-or-params-across-overrides\n\nNext, we looked at a potential area of confusion: `scoped` across overrides can potentially be confusing because `params` can be inferred. Specifically, because `params` can be implicitly inferred, and\nit implicitly implies `scoped`, `scoped` can be inferred a way that it cannot be today. While there is no safety issue here, we are concerned about potential for user confusion. The `scope`dness here is\nvery different than the existing meaning of `params` because unlike `params`, which has no effect inside the method body, `scoped` _does_ have an effect inside the method body; it changes where the\nparameter can be used or returned. Given this, we think that it would be best to require overrides to specify either `params` or `scoped` if they would have otherwise been required to do so. As an example\nof the proposed rules:\n\n```cs\nclass Base\n{\n    internal virtual Span<int> M1(scoped Span<int> s1, params Span<int> s2) => throw null!;\n    internal virtual void M2(scoped Span<int> s1) => throw null!;\n    internal virtual void M3(params Span<int> s2) => throw null!;\n}\n\nclass Derived : Base\n{\n    internal override Span<int> M1(Span<int> s1, // Today: error, missing `scoped` on override\n                                   Span<int> s2  // Proposed: error, missing `scoped` or `params`\n                                  ) => throw null!;\n    internal override void M2(Span<int> s1) => throw null!; // Today: no error\n    internal override void M3(Span<int> s2) => throw null!; // Proposed: no error\n}\n```\n\n##### Conclusion\n\nWe will require explicitly stating `scoped` or `params` on override of a `params` parameter when a non-`params` parameter would be required to do so.\n\n#### `required` members and `params` parameters\n\nhttps://github.com/dotnet/csharplang/blob/9d12a983190ba5d25fb037a2566bb1e99d486c49/proposals/params-collections.md#should-presence-of-required-members-prevent-declaration-of-params-parameter\n\nFinally, we looked at an edge case of when a collection type has `required` members. We don't expect this to be commonly hit (or even hit at all outside the compiler test base), but we do want to consider\nit. Given that we have already mandated that `params` collections types must have an applicable parameterless constructor, we think this is appropriate to use for validation at the declaration point\nof such a parameter. The call site may end up using a different constructor due to the binding rules of `params` collections, but we don't think that it's necessary to try and validate this; the call site\nwill do its own checking, and the pathological case of a collection type that can be used as a `params` parameter because it has a parameterless constructor with `SetsRequiredMembers` applied but the\nother constructors that would be used at the call site is not something we need to try and account for.\n\n##### Conclusion\n\nWe will validate `required` members against the constructor that is used to determine eligibility to be a `params` parameter at the declaration site.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-02-26.md",
    "content": "# C# Language Design Meeting for February 26th, 2024\n\n## Agenda\n\n- [`ref struct`s in generics](#ref-structs-in-generics)\n- [Collection expressions](#collection-expressions)\n\n## Quote(s) of the Day\n\n- \"Sorry, I had a meeting run over\" \"Unacceptable\" \"Yeah, that never happens here\"\n- \"Do it British style. allouws\"\n\n## Discussion\n\n### `ref struct`s in generics\n\nhttps://github.com/dotnet/csharplang/issues/7608\n\nWe started today with a timeboxed conversation to allow the implementation work on `ref struct` in generics to proceed with parsing work, and hopefully not need to\nredo much work later when the LDM makes more complete decisions. We looked at a couple different syntax proposals for how the anti-constraint of allowing `ref struct`s\ncould work:\n\n* `where T : allows ref struct` - Put a new keyword inside the existing `where` clause.\n* `allows T : ref struct` - Add a new clause that can go beside a `where` clause.\n\nThe crux of which form to choose comes down to the question of what we think the existing form actually means: is it _only_ narrowing information about `T`, or is more\ngenerally \"information about `T`\". If we think it's the former, then a separate clause for widening `T` would be appropriate; if the latter, then we can include widening\ninformation in the `allows`. After some quick debate, we lean very heavily towards the latter view. We also think that it will simplify reading and understanding method\ndefinitions, as the user won't have to keep track of multiple sets of information about `T`.\n\nWe then looked at what keyword to use. We have two real options that were suggested: either `allow`, or `allows`. This choice was much murkier: does the constraint section\nreflect the author saying \"I allow T to be a ref struct\", or is it reflecting the user reading a constraint and saying \"This allows T to be a ref struct\". We have a slight\nlean towards the latter, but ran out of time in the box before coming to a definitive solution. The major parsing choice is the constraint form, while the keyword choice\nis fairly minor and easily changed later before shipping, so we called it in favor of `allows` for now, and will revisit later.\n\n#### Conclusion\n\nWe will go with the \"put the anti-constraint in the `where` clause\" form, and we will use the keyword `allows` for now.\n\n### Collection expressions\n\nhttps://github.com/dotnet/roslyn/issues/72098  \nhttps://github.com/dotnet/csharplang/issues/5354\n\nFinally, we looked at some of the consequences of our [previous decision](LDM-2024-01-10.md#collection-expressions-conversion-vs-construction) with how the impact a few\nreal-world types in WinForms and WPF. These are very old collection types; their design predates many of our modern collection designs. Specifically, they implement\n`System.Collections.IList`, and not any generic version. However, they try to add a bit of type safety by hiding `IList.Add(object)`, and instead expose strongly-typed\n`Add` methods that take the specific type they care about. For example, `ListView.ColumnHeaderCollection` exposes an `Add(ColumnHeader)` method. However, because it\ndoes not implement `IList<T>`, its iteration type is `object`; this means, for the purposes of determining whether a collection expression conversion exists, we look\nspecifically for the `Add(object)` method and don't find it. We have a few ideas to address this:\n\n1. Remove the restriction we added previously for `IEnumerable` cases for non-`params` scenarios.\n2. Do nothing and leave the rules as they are. These collections are:\n   1. Not modified, and collection expressions simply do not work for them.\n   2. Updated to include `IEnumerable<T>` implementations, giving them a more specific iteration type.\n3. Allow looking for `Add` methods that take a subtype of the iteration type.\n4. Use the strongly-typed indexer of such types to narrow the iteration type.\n5. Include explicit `Add` implementations in the search for the `Add(object)` method for the purposes of conversion.\n\nComplicating this discussion is a further wrinkle: these collections often have other `Add` methods that take other types that can effectively be converted to the\neffective iteration type of the collection. For example, `ListView.ColumnHeaderCollection` has an `Add(string)` method that constructs a `ColumnHeader` out of the `string`\nfor ease of use. Some of the solutions we're looking at here wouldn't solve that scenario: 1 would work, as would 3, and possibly 5, but 4 would not. 2 likely would, but\nwe also think it extremely unlikely that we'd be able to do 2.2, specifically adding an implicit conversion from `string` to `CollectionHeader`. Conceptually, there is\nan implicit conversion there; that's what the various `Add` methods are simulating. But adding a new implicit user-defined conversion to a type is always a risk, particularly\na type that has been around as long as some of these WinForms and WPF types, and we think it's extremely unlikely that 2.2 would ever happen because of this.\n\nOne important note for all of these options around loosening the requirements is that this would be a divergence from what we want to work for `params` scenarios; because\nwe're very concerned about the effect of nested overload resolution on looking for unbounded `Add` methods on determining the applicability of expanded `params` methods,\nwe don't have any plans to adjust the behavior for that feature. It will be an unfortunate difference in behavior, but we think it's a necessary one to avoid making overload\nresolution even more complex than it already is. This means that if we did option 1 or 3, there would be a difference in behavior. 4 or 5 may be able to apply to `params`, but\nwe'd need to consider it before confirming that it will.\n\nWe did not reach any conclusions on this topic today. We want the working group to more fully explore these options and come back with examples of where they will work, where\nthey will fall over, and what the impact would be to various scenarios.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-02-28.md",
    "content": "# C# Language Design Meeting for February 28th, 2024\n\n## Agenda\n\n- [Extensions](#extensions)\n\n## Quote of the Day\n\n- \"If we just don't make any mistakes it'll be fine\"\n\n## Discussion\n\n### Extensions\n\nhttps://github.com/dotnet/csharplang/issues/5497  \nhttps://github.com/dotnet/csharplang/pull/7179/commits/520a2a40fc5a0fdb572e5f20f593f9eac59a88da\n\nToday we looked over the proposed set of lookup rules for extensions. Much of the meeting was going over the rules as proposed, which I won't reiterate in these notes; they can be found\nin the linked pull request commit above. We made a few comments along the way:\n\n* It may be a bit interesting that you can look up extension members without a qualifier when you're within the extension type that contains the members. We think this is fine, as this is\n  a new context that gets to redefine what `this` binds to; `this` for such scenarios is not the underlying type, it's the current extension type.\n* We think that the proposed form of doing lookup when in an extension type as if the extension type's underlying type is an inheritance relationship is the correct decision.\n* Lookup order proved to be a contentious topic. The proposed rules prioritize one type of extension method over the other, but we think that this is likely a mistake. Users may start naturally\n  migrating over to the new extensions slowly, and this may cause potential scenarios where the \"wrong\" version of an extension is picked; there's no clear answer to us whether the old or new\n  should win beyond the overload resolution rules that we already have in the language. For example:\n  ```cs\n  static class Extensions\n  {\n      public static X ToX<Y>(this IEnumerable<Y> values) => ...\n  }\n\n  implicit extension ImmutableArrayExtensions<Y> for ImmutableArray<Y>\n  {\n      public X ToX() => ...\n  }\n\n  // or reverse:\n\n  static class Extensions\n  {\n      public static X ToX<Y>(this ImmutableArray<Y> values) => ...\n  }\n\n  implicit extension IEnumerableExtensions<Y> for IEnumerable<Y>\n  {\n      public X ToX() => ...\n  }\n  ```\n  For either of these cases, it seems that the best solution is simply to give both `ToX` methods to overload resolution and let it sort out which one is preferred, erroring if neither is\n  preferred. The precise details of this, and whether there will be any disambiguation of old vs new as a final tiebreaker, will need to come in a future meeting; what we are certain of at\n  this point is that the proposed version, where there is a preference of one version for lookup, isn't workable.\n* There are also some disambiguation scenarios that we will need to consider that can't occur today, such as what will happen in the scenario where a simple name binds to both an extension\n  property and an old-style extension method. We can likely look to similar scenarios that can occur for instance members in metadata today, but it's a scenario to think about. Example:\n  ```cs\n  class TableIDoNotOwn : IEnumerable<Item> { }\n\n  static class IEnumerableExtensions\n  {\n      public int Count<T>(this IEnumerable<T> t);\n  }\n\n  implicit extension MyTableExtensions for TableIDoNotOwn\n  {\n      public int Count { get { ... } }\n  }\n\n  // What happens here?\n  var v = table.Count; // Let's get a read from LDM\n  ```\n\n\n#### Conclusion\n\nLookup in extension types should treat the underlying type as if it is the base type of the extension type. We need to go back and redesign the rules for lookup of extension members from\noutside of an extension type to mix old and new style extensions.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-03-04.md",
    "content": "# C# Language Design Meeting for March 4th, 2024\n\n## Agenda\n\n- [Breaking changes: making `field` and `value` contextual keywords](#breaking-changes-making-field-and-value-contextual-keywords)\n- [Overload resolution priority](#overload-resolution-priority)\n\n## Quote of the Day\n\n- \"I think it's actually a good think to have that onericity. Onericity? I think that's a word I just made up.\"\n\n## Discussion\n\n### Breaking changes: making `field` and `value` contextual keywords\n\nhttps://github.com/dotnet/csharplang/issues/7964  \nhttps://github.com/dotnet/csharplang/issues/7918\n\nWe started today by exploring a piece of community feedback on the previous proposal for introducing breaking changes: what if, instead of trying to make `field` behave like `value` does today, we try\nto make it a contextual keyword when in a property accessor? One thing that became clear here, after multiple discussion directions, was that we needed to determine what the most important bit to the LDM\nis here: is it most important to the LDM that `field` behaves identically to `value` (whether that's as a contextual keyword or an implicit parameter), or can we view them as unrelated concepts? We mostly\nthink the former, but there are some members of the LDM that would prefer to have `field` have their desired semantics, even if that means it differs from `value`. There is a potential that, by changing\n`value`, we will break a concept that is understood by a large number of our users. We do hear more about people misunderstanding the meaning of `value` than not, but this could simply be a biased opinion\nbecause we only ever hear the complaints.\n\nWe then turned to talking about the advantages and disadvantages of using contextual keywords in these scenarios, and how broad we want to make the context. A number of LDM members were happy with the\nfairly constrained scope of the breaks and fixes here, and think that they end up being fairly straightforward. There are a few interesting wrinkles that need to be worked out:\n\n* What is the behavior of `nameof(value)`? Today, it's the string `\"value\"`, `value` is actually a parameter named `value`. We didn't arrive at a concrete conclusion on this today.\n* How does this behave for indexers? `value` is a legal parameter for get-only indexers, does it need to remain so? And does it need to continue to be illegal for settable properties? We also did not arrive\n  at a conclusion for this today.\n\nAfter discussion, we are most in favor of `field` and `value` as contextual keywords. We then discussed the scope of this: does every usage of `field` and `value` within a property need to be escaped, just\nthe simple names, or somewhere in between? The example we looked at for these is:\n\n```cs\nint Prop\n{\n    get\n    {\n        int field = 1; // If it's only simple names that need to be escaped, this is legal\n        field = 2; // This needs to be escaped in every version; are we ok with the inconsistency between declaration and usage?\n        this.field = 3; // This is unambiguous, but does it need to be escaped anyways?\n    }\n}\n```\n\nWe ended up with 3 options:\n\n1. Only simple names need to be escaped. `int field = 1` is legal, as is `this.field`, but `field = 2` would need to be escaped to refer to the local or class field.\n2. Simple names and declarations need to be escaped. `int field = 1;` needs to be escaped, but `this.field` does not.\n3. All usages need to be escaped. Both `int field = 1;` and `this.field` need to be escaped.\n\nConsistency is again a key point here. Existing contextual keywords, such as `await` within an `async` method body, must always be escaped, no matter how it's used. `this.await`, for example, must be\nwritten as `this.@await`. This ultimately convinced us that option 3 is right: if the goal here is to take breaks to make the language simpler, let's not introduce another set of rules around when a\ncontextual keyword is legal to use unescaped.\n\n#### Conclusion\n\nWe will move forward with the proposal to treat `field` and `value` as contextual keywords. We will treat them as contextual keywords in all usages within accessor bodies. More work will need to be done\nto determine the behavior of indexers, `nameof(value)`, and whether `value` is a contextual keyword within a `get` body.\n\n### Overload resolution priority\n\nhttps://github.com/dotnet/csharplang/issues/7706  \nhttps://github.com/dotnet/csharplang/pull/7906/commits/aa6ab11c7df001e807e956f5b056785588e8b12e\n\nFinally today, we took a brief look at the proposal for overload resolution priority. We've previously looked at it in the form of `BinaryCompatOnlyAttribute`, but some particularly gnarly challenges\nwith OHI convinced us that it was not the right approach. Instead, we went with a narrower approach of allowing an API author to adjust the relative priority of their methods to ensure that something\nthat is better for a given domain, such as the `Debug.Assert` overload that takes a `CallerArgumentExpressionAttribute`, is preferred over what C# would normally choose. The LDM appreciated the specificity\nand narrow target of the new proposal, though there are likely some finer details to work out with where exactly the specification needs to be modified, and how it will interact with extension lookup in\nthe new extension type world. We also did a quick dive on some of the open questions around inheritance with this new attribute: with the exception of a few things like parameter names and default values,\nthe original definition of a virtual method is always the one used for determining applicability, and it seems likely that we'd want to do the same here, and not allow derived overrides to change the\npriority of a member; we did not concretely decide this, however, so we'll need to confirm when implementation starts.\n\n#### Conclusion\n\nProposal is approved, and we'll work on it in the upcoming development cycle.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-03-11.md",
    "content": "# C# Language Design Meeting for March 11th, 2024\n\n## Agenda\n\n- [Dictionary expressions](#dictionary-expressions)\n\n## Quote of the Day\n\n- _Someone in the room picks up a knife to slice some bread_ \"That is going to make it impossible for the people online to hear\"\n \"Thank you for advocating for us\" \"Thank you for also drawing attention to the fact that we don't have any bread\"\n\n## Discussion\n\n### Dictionary expressions\n\nhttps://github.com/dotnet/csharplang/issues/7822  \nhttps://github.com/dotnet/csharplang/blob/dcf46ba377e1ce356f69f981f36b2273c3179ca3/proposals/dictionary-expressions.md\n\nToday, we took a look at the first proposal for dictionary expressions. There are a number of open questions that need to be answered, including syntax decisions;\nhowever, in order to make progress on the more thorny semantics questions, we are using the `[key: value]` strawman syntax from the proposal for now. We will make\nconcrete decisions on the syntax at a later time. The syntax we end up with is important, of course, but fairly unconnected to the semantics we need to delve into\nat the moment.\n\nThe first two questions we looked at are highly related. They are:\n\n1. Should we allow KeyValuePair expression elements in dictionary expressions?\n2. Should we allow spreading an enumerable of KeyValuePair in a dictionary expression?\n\nThe first question can even be expressed in terms of the second: after all, if we allow the second, and we give collection expressions a natural type, then users\ncould just do `[.. [keyValuePairExpression]]` even if we don't allow 1. This question brought up a recurring theme through the rest of the open questions we looked\nat: we're currently calling these dictionary expressions, because that's a catchy name that immediately conveys the general target of these. However, what are they\nactually? Are they dictionary expressions, or are they actually collections of associated keys and values? The LDM is unanimously in favor of supporting both these\nscenarios.\n\nNext, we looked at whether these expressions should be able to initialize generalized collection types, or just \"dictionary\" types. Specifically, can these types\ninitialize a `List<KeyValuePair<TKey, TValue>>` and things like it, or are they stuck initializing things like `Dictionary<TKey, TValue>`. This is a trickier\nquestion; our correspondence principle for creation and consumption does not generally hold up for such scenarios. As an example:\n\n```cs\nList<KeyValuePair<string, int>> list = [\"mads\": 21];\nConsole.Write(list[\"mads\"]); // Can't consume like this because it's a List\n```\n\nNo matter what syntax we choose for the initialization form, there won't be a correspondence with usage here, as `List<>` is accessed by index, not by key. This\ngives a few members of the LDM pause, but overall, we're in favor of allowing this.\n\nThe next topic was on how restrictive we should be on `KeyValuePair` itself; namely, must the type involved be exactly\n`System.Collections.Generic.KeyValuePair<TKey, TValue>`, or should it be expanded? One example is `(TKey string, TValue value)`. This tuple type is conceptually a\nKVP, and some collections use it or other similar tuple types instead of KVP. For example, `PriorityQueue<TElement, TPriority>` exposes an `UnorderedItems` property\nthat is an `IReadOnlyList<(TElement Element, TPriority Priority)>`. We may want to enable merging of 2 queues by doing \n`PriorityQueue<TElement, TPriority> p = [.. originalQueue1.UnorderedItems, .. originalQueue2.UnorderedItems];`. This example raises several questions of its own\n(what APIs would we use, since there's neither `Add` nor indexers on `PriorityQueue`?), but there is at least some merit in considering the idea.  \nThere's another question here, too: what about conversions between keys and values in the source collection expression and the destination? For example:\n`Dictionary<int, int> d = [shortKey: shortValue];`, where the key and value need to be subjected to a `short->int` conversion. Are conversions like this acceptable?\nThis plays back into the question of what these collections actually are: if they're conceptually collection expressions, then the conversions around the keys and\nvalues may be less acceptable. However, if they're collections of associated keys and values, then subjecting the individual parts may be fine.  \nUltimately, LDM did not reach a decision on this question today. We'll need to dig more into it in future meetings.\n\nFinally, we looked at the semantics of how a dictionary expression will build its resulting value: does it overwrite existing values, or does it error when there are\nduplicate keys? There are few different interesting points here: we're currently calling these dictionary expressions. That, combined with how collection expressions\nare specified around `Add` methods, may give users a natural intuition that we'll be calling `Add` on the dictionary, which will throw when a duplicate is encountered.\nHowever, `System.Collection.Generics.Dictionary<,>` may not be the only dictionary a user would key off of, and .NET has very inconsistent behavior for what `Add` on\na dictionary-like type will do. `ImmutableDictionary<,>` will not throw, and will keep the original value if the new value compares equal to the original value.\n`FrozenDictionary<,>` immediately throws `NotSupportedException`s; the list goes on, but the only consistent bit is that we're inconsistent in behavior. These\ndiscrepancies had us reconsider the question from another direction: rather than \"What is the behavior\", we instead want to consider \"What APIs are we calling\"; this\nwill allow each scenario to tailor its APIs to handle the question directly, rather than forcing a single behavior on all collection types.  \nThere's some concern among members that using an indexer, rather than calling an `Add` method, will lead to concerning behavioral differences if a user decides to\nrefactor existing collection initializers to dictionary expressions. We do have existing behavior in our IDE fixers that can help convey that a refactoring is not\nexactly semantics-preserving, but it would require the user understanding the exact difference and examining usages to ensure that they're not falling afoul of bad\nbehavior in the presence of indexer assignment. However, a larger portion of the LDM is more concerned that, in the presence of spreads (which have no collection\ninitializer analogy), `Add` is more often the wrong thing to call than using an object initializer. That is the direction we'll go with for now, and explore how we\nspecify the rules given indexer usage instead of `Add` calls.\n\n#### Conclusions\n\nQuestions 1 and 2 are wholeheartedly approved; KVP expressions and spreads of KVP collections will work in dictionary expressions.  \nQuestion 3 is approved; dictionary expressions will be able to convert to collection types that have a KVP element type.  \nQuestion 4 needs more time to be considered.  \nQuestion 5 settled on using indexers as the lowering form.  \n"
  },
  {
    "path": "meetings/2024/LDM-2024-03-27.md",
    "content": "# C# Language Design Meeting for March 28th, 2024\n\n## Agenda\n\n- [Discriminated Unions](#discriminated-unions)\n\n## Quote of the Day\n\n- \"I think [redacted LDT member] is a decent person... oh wait, did you turn the mic back on?\"\n- `public sealed enum Planets { Earth, Jupiter, Mars, Mercury, Neptune, Pluto, Saturn, Uranus, Venus }`\n\n## Discussion\n\n### Discriminated Unions\n\nhttps://github.com/dotnet/csharplang/issues/113\n\nToday, we took a look at the areas the discriminated unions working group has been investigating. A significant portion of the meeting was going over slides,\nwhich have been included [here](./LDM-2024-03-27-presentation.pdf). These slides have been helpfully annotated with speaking notes, so this set of notes won't\ngo deep into the points covered in the presentation itself.\n\nWe had a few reads of the room during the meeting, particularly at the end, to try and help focus on the next direction for the working group to move. One clear\nresult from these reads was that we need to support existing \"closed\" type hierarchies in some fashion, even if it's just in exhaustiveness in pattern matching.\nThis already has a [championed issue](https://github.com/dotnet/csharplang/issues/485), and we don't think that we necessarily need to tie it to DUs specifically,\nbut that we should understand how the broader DU feature will behave so that we can integrate these existing hierarchies into that feature set, rather than having\nmultiple sets of behaviors depending on how such a hierarchy was defined.  \nWe were also unable to clearly come to a decision around implementation strategies after this meeting; we have a much better understanding now of the tradeoffs\nthat various strategies will have, both from a performance perspective, and from a versioning perspective, but we still need to narrow the scenarios we're trying\nto address further before we can determine what weights to put on those tradeoffs.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-04-01.md",
    "content": "# C# Language Design Meeting for April 1st, 2024\n\n## Agenda\n\n- [Async improvements (Async2)](#async-improvements-async2)\n\n## Quote of the Day\n\n- _Andy gets to the CancelScope slide_ \"There's this idea called structured concurrency\" _Disconnects_ \"He definitely awaited an `async void`\"\n\n## Discussion\n\n### Async improvements (Async2)\n\nhttps://github.com/dotnet/runtimelab/blob/e69dda51c7d796b8122d0f55b560bc44094a4bec/docs/design/features/runtime-handled-tasks.md  \n[Presentation](./LDM-2024-04-01-presentation.pdf)\n\nToday, we looked at a proposal for improving `async` in .NET. The runtime has been experimenting with several different approaches here. Their first prototype, green threading, was designed to try\nand solve the metastability issue where sync-over-async can cause threadpool exhaustion. While this was an interesting experiment, their ultimate conclusion was to not move forward with this\nexperiment, and instead focus on improving the overall performance of `async` methods; their results can be viewed [here](https://github.com/dotnet/runtimelab/issues/2398).\n\nTo that end, we're looking at what language or compiler changes may be required if we were to update the `async` state machine generation. For the purposes of discussion, we refer to this new format as\n`async2`; this does not mean that we expect to introduce a literal `async2` keyword, it's simply a shorthand. The current runtime experiment moves the state machine generation directly into the runtime,\nrather than having the C# compiler do it.\n\nThis can be done entirely without breaking changes in the behavior of code, but there is one major concern; `SyncContext`s and `AsyncLocal`s. The saving of the execution context today ensures that, when\nan async method returns, its modifications to an `AsyncLocal` are not observed by callers, because of the compiler's saving and restoring of execution contexts. It is possible to have the `async2` machinery\nbehave in the same way as `async` here, but doing so is a potential perf hit, of ~30% or more of the gain in some cases. These scenarios will still be faster than the existing `async` mechanisms, but if we\ncan take a breaking change here, we can make the performance gains with `async2` even greater. There's some argument that the current behavior of these methods is actually very unexpected, but even if\nthat's the case, it's a potential break. One idea that was floated repeatedly was making this configurable; we could opt for behavior-preserving semantics by default, and let users opt-in to the breaking\nchange if they chose to do so.\n\nAnother point we considered is how to trigger the new generation strategy. The current prototype adjusted the compiler to simply put `async2` into the signature of the method; we don't think this is\nsomething we want to do long term. In fact, we think that specific syntax is likely the wrong solution to triggering the new generation strategy. We like our current `async` syntax, and think that it should\ncontinue to be the main syntax for the future. The goal with this change is that there's little-to-no semantic change in the meaning of `async` methods, and is instead just a code generation strategy change.\nThis isn't something we want users to have to opt-in to, it should just be an improvement that they get as they move forward with the platform. There's also some concern about users who multi-target\nbetween various platforms; would users who target both .NET Standard 2.0 and modern .NET need to `#ifdef` their `async` methods so that they can take advantage of new features where they're available?  \nAll of this leads us to consider a very rarely used strategy; a configuration flag. We have very few of these in C#, intentionally, as we don't want to create language dialects. The good thing for us here\nis that we're not actually creating a language _dialect_; the emit strategy may be different, but the code inside the `async` method body means the same thing, semantically, whether the flag is on or off.\nThere will be a cost to pay in compiler testing; we will forever have to test both `async` code generation strategies, which adds a _lot_ of new tests to the test matrix. But it seems like a cost we'd be\nwilling to pay for the improvements we're looking at here. Further, we don't think we have to concern most users with the existence of a switch here. Instead, the compiler can simply look for a `RuntimeFeature`\nflag, and turn on the new strategy if it's available. The switch could be limited to simply being an escape hatch for users who need to switch back to the old generation strategy for some reason.\n\nThe only wrinkle with this strategy is the potential `SyncContext` behavior change. This isn't something that really reflects in C# code itself, or in the code generated by the compiler at all. Instead,\nit affects the code that the JIT generates for the `async` method at runtime, as it converts the body to the `async` state machine. We therefore think it would be possible to leave this behavior change to\na configuration option at runtime, either through some attribute on the assembly, or through runtime flags.\n\nAnother topic we discussed briefly was `ConfigureAwait`. This issue may end up being the tipping point that forces an assembly-wide configuration solution, as we don't want to force developers to realize\nthe `Task` return by calling `ConfigureAwait`. The `async2` mechanism avoids realizing `Tasks` when not necessary; this is where most of the performance gain comes from, as most `async` callstacks actually\nhave very few true suspension points. If we have `ConfigureAwait` calls throughout the stack, it could force us to materialize the `Task`s where we otherwise wouldn't have to, costing a large part of the\nperformance gains. It's possible that we could have the JIT recognize the scenario and elide the `Task` allocation, but that may end up being somewhat expensive to implement, so we will need to do the\nexercise of costing to determine what we do there.\n\nFinally, there were a few other topics mentioned:\n* While we're changing the async state machines, perhaps we could consider exposing a structured concurrency model, similar to F#'s `async` or `task` computation expression, or Kotlin's `CoroutineContext`.\n  This would require new APIs from the runtime, and potentially change the way that asynchronous workflows are constructed, but if we're going to make such a change, perhaps now is the time. Moving to\n  such a model may obviate the main use case of https://github.com/dotnet/csharplang/issues/6300 as well, as the cancellation could be implicitly checked during asynchronous calls by the runtime.\n* We also briefly mentioned debugging; in addition to the large changes in the runtime, debugging engines will also have to adapt to the new IL structure here.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-04-08.md",
    "content": "# C# Language Design Meeting for Apr 8, 2024\n\n## Agenda\n\n- [Implementation-specific documentation](#implementation-specific-documentation)\n\n## Quote of the day\n\n\"if `true == 1` then why is that an error?\"\n\"cause u forgot parens\"\n\n## Discussion\n\n### Implementation-specific documentation\n\nhttps://github.com/dotnet/csharplang/issues/7898\n\nThe proposal is for Roslyn to consistently specify behaviors that aren't covered by the [C# Standard](https://github.com/dotnet/csharpstandard/tree/standard-v7/standard#readme).\n\nThere are various differences between what the C# Standard says and what the Roslyn C# compiler does. Some of these are places where the spec offers leeway - implementation-specific and implementation-defined. Others are deviations where the compiler doesn't follow the spec, e.g. because of a bug. Sometimes there are good reasons for such bugs not getting fixed; for instance there may be reasonable code depending on the current non-standard behavior, and it would be a breaking change to fix.\n\nThe Standards committee is in the process of standardizing nullable reference types, which is quite unique in that much of its impact is through warnings, which often aren't considered the purview of the specification. The rules for when exactly the warnings are issued are quite intricate. How much of that behavior should be in the Standard? For the parts that wouldn't be, to what level of detail should the Roslyn behavior be specified elsewhere?\n\nCollection expressions are an example where the compiler needs wiggle-room around which exact types it creates and how it populates them, and reserves the right to change its choices without warning. The spec - and standard - should simply say what is guaranteed and what isn't.\n\nThe Standard has an [annex](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/portability-issues) that lists undefined, implementation-defined and unspecified behaviors.\n\nRoslyn already has a [document](https://github.com/dotnet/roslyn/blob/main/docs/compilers/CSharp/Deviations%20from%20Standard.md) (although incomplete) listing known deviations from the Standard. We could expand that, or add sibling documents next to it, to include other Roslyn-specific behavior as suggested in the proposal.\n\n#### Conclusion\n\nFor the issues in [section B3](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/portability-issues#b3-implementation-defined-behavior) of the annex, \"Implementation defined behavior\", we want to document Roslyn's approach, since these are gaps deliberately left by the Standard for the implementation to fill. \n\nIn addition, with respect to [section B4](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/portability-issues#b4-unspecified-behavior), \"Unspecified behavior\", we want to specify the behavior of item 2 on the representation of the `true` value, since Roslyn has made decisions here that are observable and affect interoperability with other languages."
  },
  {
    "path": "meetings/2024/LDM-2024-04-15.md",
    "content": "# C# Language Design Meeting for April 15, 2024\n\n## Agenda\n\n- [Non-enumerable collection types](#non-enumerable-collection-types)\n- [Interceptors](#interceptors)\n- [Relax `Add` requirement for collection expression conversions to types implementing `IEnumerable`](#relax-add-requirement-for-collection-expression-conversions-to-types-implementing-ienumerable)\n\n## Non-enumerable collection types\n\n- Championed issue: [#7744](https://github.com/dotnet/csharplang/issues/7744)\n- Requested details: [#7895](https://github.com/dotnet/csharplang/pull/7895)\n\nShould collections that are not enumerable be usable in collection expressions and `params` collections, if they have a `CollectionBuilder` attribute that defines a single `Create` method?\n\nIn this case, the element type of the collection can be determined from the `Create` method if it is not already known.\n\nChanges to the spec had been previously discussed and the details changes were reviewed, as shown in #7895 and #7744. This discussion was to confirm approval of the spec change.\n\n### Conclusion\n\nThese proposed changes were approved.\n\n## Interceptors\n\n- [Open issues for interceptors](https://github.com/dotnet/csharplang/blob/ff2c82c8d702d70e2704cd9265c97859cc2eb296/proposals/interceptors-issues-2024-01.md)\n\n### File location\n\nInterceptors must identify the location in code where interception occurs. The issue is how to identify that location for use in the interceptor attribute.\n\nThings that have been tried or considered for identifying the file:\n\n* Absolute paths, per the preview, are bad for portability.\n* Relative paths required the context be passed around or a project base path.\n\nThe proposed arguments to `[InterceptsLocation]` are a version number and an opaque data string. The opaque data string is not intended to be human readable. It is expected that this string will be inserted by a generator that retrieves it via a call into the interceptors API that requests an interceptible location.\n\nThe proposal is to create the opaque string by combining a checksum of the file contents, an integer location of the call in the syntax and a string file name for error reporting. Hand authoring interceptor locations is an unsupported scenario.\n\nA version identifier is included to allow future change to be made in the calculation of the data string.\n\n### Other public API changes\n\nThe team also mentioned that there is an experimental public API that lets you determine whether syntax is being intercepted and who is intercepting. This might be used in an analyzer, for example.\n\n### Conclusion\n\nThe proposed approach to identifying the file location was approved, including the proposed handling of version.\n\n## Relax `Add` requirement for collection expression conversions to types implementing `IEnumerable`\n\n[#8034](https://github.com/dotnet/csharplang/issues/8034)\n\nWe introduced a breaking change in 17.10 which had a larger impact than anticipated. The proposal is to resolve that breaking change. It occurs when:\n\n* Types that implement `IEnumerable` but not `IEnumerable<T>` and have a strongly-typed `Add(T)`.\n* Types that implement `IEnumerable<T>` and have a strongly-typed `Add(U)` where `U` is implicitly convertible to `T`. This is a generic form of category 1.\n* Types that implement `IEnumerable<T>` and have a strongly-typed `Add(U)` where `U` and `T` are unrelated.\n\nThe breaking change added in 17.10 was the additional restriction:\n\n* `Add` needs to have one parameter of the iterator type\n\nThe proposal is to keep the `Add` method, still require a single `Add` parameter but no statement about the type of the argument.\n\n### Conclusion\n\nNo conclusion reached and this will be discussed again in the April 17 meeting.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-04-17.md",
    "content": "# C# Language Design Meeting for April 17, 2024\n\n## Agenda\n\n*  [Relax `Add` requirement for collection expression conversions to types implementing `IEnumerable`](#relax-add-requirement-for-collection-expression-conversions-to-types-implementing-ienumerable)\n* [Extensions](#extensions)\n\n## Relax `Add` requirement for collection expression conversions to types implementing `IEnumerable`\n\n[#8034](https://github.com/dotnet/csharplang/issues/8034)\n\n### Discussion\n\nThis was a continuation of Monday's conversation on the conversion rules for collection expressions. \n\nThese rules were tightened at LDM-2024-01-10 to require target types that implement `IEnumerable`, and that do not have create method, to have an accessible `Add` instance or extension method that can be invoked with value of iteration type as the argument. That is a breaking change for collection types where the `Add` method has a parameter type that is implicitly convertible but not identical to the iteration type.\n\nThe proposal was to relax the requirement (for conversion) and simply require an instance or extension `Add` method that can be invoked with a single argument, but without requirements on the method parameter type. Later method resolution will reject any `Add` methods that will not work with the type.\n\n### Conclusion\n\nThe LDM ratified the proposal that was already checked in, which rolls back some of the changes from January and better aligns the three features: collection expressions, collection initializers, and `params` collections.\n\n## Extensions\n\n### Discussion\n\nToday we looked at [the syntax for extension types](https://github.com/dotnet/csharplang/blob/main/meetings/working-groups/roles/roles-2023-02-15.md#what-keyword-for-underlying-type).\n\nThis is the information that the syntax needs to be able to express:\n\n1. It's an extension\n2. Implicit vs explicit concept\n3. It has an underlying type\n4. (Later: base extensions and interfaces)\n\nThe current interim syntax implementation is:\n\n```csharp\nimplicit extension Extension for UnderlyingType : BaseExtension, Interface { }\n```\n\nProposed syntax alternatives for the declaration of type:\n\n- (implicit | explicit) extension\n- (role | extension)\n- view\n- shape\n- alias\n- this (as in this E of U)\n- ??\n- \nProposed alternatives for the keyword options for underlying type:\n\n- for\n- of\n- extends\n- on\n- over\n- is\n- override\n- using\n- from\n- parentheses or other glyph\n- after the colon with base extensions and interfaces\n\nSeveral other syntax ideas were also presented in the meeting.\n\n### Other thoughts\n\n#### Extension methods vs. extension type members\n\nWe have an open question around how lookup works when there are both implicit extension members and old-style extension methods in the mix. We need to make sure our decisions don't handcuff the BCL or others from adopting the feature.\n\nTraditional extension methods could infer type arguments from all arguments, but extension types can only use the receiver to determine compatible extension types and substitute them.\n\n### Priorities\n\nPriorities: static -> instance -> inheritance -> interfaces\n\n### Questions that were tabled for now:\n\n* Can `implicit` or `explicit` be omitted? What's the default?\n* What's the naming convention\n\n### Conclusion\n\nWe will move forward with the current syntax:\n\n```csharp\nimplicit extension Extension for UnderlyingType : BaseExtension, Interface { }\n```\n"
  },
  {
    "path": "meetings/2024/LDM-2024-04-22.md",
    "content": "# C# Language Design Meeting for Apr 22, 2024\n\n## Agenda\n\n- [Effect of language version on overload resolution in presence of `params` collections](#effect-of-language-version-on-overload-resolution-in-presence-of-params-collections)\n- [Partial type inference: '_' in method and object creation type argument lists](#partial-type-inference-_-in-method-and-object-creation-type-argument-lists)\n\n## Effect of language version on overload resolution in presence of `params` collections\n\n(https://github.com/dotnet/csharplang/issues/8061)\n\nIssues were encountered when earlier C# versions were specified.  For example, the runtime team added `params ReadOnlySpan<object>` and users that combined .NET 9 and C# 12, such as with the `.csproj` fragment that follows, received an error:\n\n```dotnetcli\n<LangVersion>12</LangVersion>\n<TargetFramework>net9.0</TargetFramework>\n```\n\n> The feature 'params collections' is currently in Preview and unsupported. To use Preview features, use the 'preview' language version.\n\nThis happens because the changes we made to overload resolution to prefer params `ReadOnlySpan<T>` are unconditional but using the feature is guarded by `LangVersion`.\n\nLooking at how we have handled guarding other features on `LangVersion` finds variations where different features have been handled differently and features have been handled differently at different points in C# history.\n\nA primary reason for `LangVersion` was included in Roslyn is to support teams where some members are on a later version of the compiler - for example because they are using a later version of Visual Studio. \n\nFor at least much of the Roslyn history, if using a feature would cause an error if used with an earlier compiler (SDK/VS version), then consumption was not supported. Otherwise it was.\n\nAvailable options for handling overload resolution in this case are given below.\n\n#### Ignore language version on consumption\n\nThere are concerns on ignoring language version on consumption because of how much it is tied to collection expressions. We expect the compiler would inject C# 11+ code patterns into C# 10 (or early) code bases which would not be expecting collection expressions.\n\n#### Guard applicable function member changes on LangVersion\n\nThis approach would result in the new rules only applying to C# 13 and above.\n\n_Applicable function member_ refers to expanding `params` at the callsite to act as a collection expression.\n\nYou could still explicitly call the method, but it would not be chosen during overload resolution for `params`.\n\n#### Guard all overload changes on LangVersion\n\nThis is a variation of the previous option.\n\n### Breaking Changes\n\nWhile selecting a different overload is a breaking change,  we sometimes take this kind of change.\n\nIf code starts working in the C# 13 compiler's version of C# 11, that can create an issue in teams. And also, if the selected overload changes when you do not change your compiler, but upgrade your language version and call a different overload, that's a break.\n\nAdditional language version guards in the compiler add complexity and increasing the test matrix. But not applying the guard means that if a user upgrades their compiler they could see different overload resolution, even if they continue to use the same lower version of C#. Since we have said we will evolve the behavior of collection expressions to make them better, you could get a change in code (although not a semantic change) every year.\n\n### Conclusion\n\nWe will guard based on language version - approach [Guard applicable function member changes on LangVersion](#guard-applicable-function-member-changes-on-langversion).\n\n## Partial type inference: '_' in method and object creation type argument lists\n\n(https://github.com/dotnet/csharplang/pull/7582)\n\n### Discussion\n\nWe reviewed a proposal for skipping inferrable type arguments in the type argument list for invocation expressions and object creation expressions.\n \nIn addition to type arguments, there are other potential uses (more in the proposal):\n\n```csharp\n// This code is to show the possible application\n// and is not an indication of syntax.\nG<_,>\n_[] // arrays\n_? // nullable types\n```\n\n### Possible syntax\n\n```csharp\n- `_` (underscore)\n- `var`\n- `` (empty)\n- `..`\n- `*`\n- `__`\n```\n\n### Conclusion\n\nWe will continue to explore top level type inference.\n\nIt is too early to make a decision on syntax, but we lean to using `var` as the most semantically correct.\n\nTo preserve this space, we may begin disallowing `_` as a type name. If you wish to use it as a type name, you would need to prefix: `@_`.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-04-24.md",
    "content": "# C# Language Design Meeting for Apr 24, 2024\n\n## Agenda\n\n- [Adjust dynamic binding rules for a situation of a single applicable candidate](#adjust-dynamic-binding-rules-for-a-situation-of-a-single-applicable-candidate)\n\n## Quotes of the day\n\n\"Once people are in dynamic-land they've already chosen\"\n\n## Adjust dynamic binding rules for a situation of a single applicable candidate\n\n(https://github.com/dotnet/csharplang/pull/8027)\n\nThe params collection work includes some changes to how binding occurs if either the primary expression or an argument is dynamic. When there is only one candidate, it could be used.\n\nThis change caused [unexpected breaking changes in certain cases](https://github.com/dotnet/roslyn/issues/72750):\n\n> ```csharp\n> using System.Text.Json;\n> \n> public class C\n> {\n>     public static C M(IFoo foo, dynamic value)m\n>     {\n>         var result = foo.Bar(\"name\", value);\n>         return JsonSerializer.Deserialize<C>(result);\n>     }\n> }\n> \n> public interface IFoo\n> {\n>     object Bar(string name, object value);\n> }\n> ```\n> \n> After the recent changes around dynamic, the type of result is now object whereas previously it was dynamic.\n\n\n### Discussion\n\nIt is desirable to use use static binding to make more things possible with dynamics. This can be done when there is only one applicable candidate.\n\n#### Dynamic or static result\n\nWe do not plan to change things that work today, such as local functions. We are only considering whether new cases should have a static result or be \"dynamified\"\n\nThere were concerns about returning static results from operations with dynamic being surprising. Constructors do this, but that is because you are stating the return type explicitly in the call to `new`.\n\nThere are some some opinions voiced that we should avoid to avoid unnecessary dynamic proliferation (although what is unnecessary may be opinion).\n\nIt was pointed out that part of the core of the design of dynamic that it is contagious. There is worry about needing a decoder ring to know when the results are static or dynamic. \n\nGeneral feeling that consistency along with back compatibility considered is desirable.\n\nPrior art: VB has had runtime dynamic since V1. `Object` in VB is dynamic. It delays resolution to runtime. When there is only a single candidate that is applicable it would do static binding and not change the result to `Object'. It does not proliferate dynamic.\n\nVB might also be considered a lesson learned because of ambiguity between dynamic and the base type. The dual role of object may drive VB being static when possible, dynamic when necessary.\n\nWhether we should use static or dynamic result types when we use static binding with dynamic arguments in new scenarios was not resolved today. We will return to this question.\n\n#### Static binding can uncover more errors during compilation\n\nThere are cases where static binding allows us to know that certain cases, like assigning to void, would fail at runtime. We can now give a compile time error for these cases and it would be desirable to do so.\n\n#### Scenarios from proposal\n\nThese scenarios from the proposal framed the discussion and conclusions:\n\n> 1. the candidate is not a local function;\n> 2. the candidate returns a value (doesn't have type `void`, doesn't return a `ref`);\n> 3. there is an implicit conversion from result type to `dynamic`;\n> 4. the receiver and argument list would be supported for dynamically bound invocation.\n\n- Bullet 1 is an existing scenario that is enshrined.\n- Bullet 2 and 3 are moving errors from runtime to compile time.\n- Bullet 4 is under discussion because success scenarios have non-dynamic results that we may choose to \"dynamify\".\n\n\n## Conclusions\n\nWe can use static binding as an implementation strategy when dynamic binding isn't supported. (From 30,000 feet - taking something that would have always failed, and making it work.)\n\nWe can change runtime error scenarios to compile-time error scenarios.\n\nWe should tie these changes to language version.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-05-01.md",
    "content": "# C# Language Design Meeting for May 1st, 2024\n\n## Agenda\n\n- [Adjust binding rules in the presence of a single candidate](#adjust-binding-rules-in-the-presence-of-a-single-candidate)\n\n## Quote of the Day\n\n- \"I'm going to release you all early. I know your parents aren't here to pick you up yet.\" \"So we should all go to the playground and stay there?\" ... \"Or if we're older we go to the library.\"\n\n## Discussion\n\n### Adjust binding rules in the presence of a single candidate\n\nhttps://github.com/dotnet/csharplang/pull/8027\n\n[Last time](LDM-2024-04-24.md#adjust-dynamic-binding-rules-for-a-situation-of-a-single-applicable-candidate), we looked at an adjustment to the rules of dynamic binding that would see the compiler\nissue more errors for cases where `dynamic` operations could be resolved as never possible to work at compile-time. The new proposal suggests that, for assignments, we can statically bind during\ncompile and issue errors for scenarios where no valid assignment is possible. For example, we'd error for this scenario:\n\n```cs\nvar c2 = new C2();\nc2.M(0, 1);\n\npublic class C2\n{\n    public void M(dynamic d, object o)\n    {\n        this[d] += o; // Would error, += cannot be applied to operands of type Base and object\n    }\n\n    Base this[int x]\n    {\n        get => new Base();\n        set {}\n    }\n}\n\nclass Base { }\n```\n\nIt was hoped that this narrow restriction, only affecting assignments and not affecting invocations, would be small enough to provide meaningful compile-time errors while avoiding runtime breaks.\nHowever, we were able to come up with several counterexamples for this scenario. One such example:\n\n```cs\n// Succeeds and prints 1\nvar c2 = new C2();\nc2.M(0, 1);\n\npublic class C2\n{\n    public void M(dynamic d, object o)\n    {\n        this[d] += o; // Succeeds today because `Derived.operator +` is found at runtime by dynamic\n    }\n\n    Base this[int x]\n    {\n        get => new Derived();\n        set {}\n    }\n}\n\nclass Base { }\n\nclass Derived\n{\n    public static Derived operator+(Derived x, object y)\n    {\n        System.Console.Write(1);\n        return x;\n    }\n}\n```\n\nThe proposed rules would break this scenario, because `Base` has no `+` operator; at runtime, though, the dynamic binder would see that the return of `this[d]` is a `Derived`, and find the operator\nit defines. We're also concerned about interactions with `IDynamicMetaObjectProvider`, as those can also break in similar fashions with this scheme. Given these issues, we don't think that we're\ncomfortable with even this narrow set of errors. Ultimately, use of `dynamic` in these scenarios intentionally moves errors from compile-time to runtime, and we don't think that the potential for\nbreaking existing code is worth the additional validation here. We'll shelve this change for now, and revisit in the future if we have a better idea for how to avoid potential breaks.\n\n#### Conclusion\n\nProposal is rejected.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-05-08.md",
    "content": "# C# Language Design Meeting for May 8th, 2024\n\n## Agenda\n\n- [`readonly` for primary constructor parameters](#readonly-for-primary-constructor-parameters)\n\n## Quote of the Day\n\n- \"It'll work\" \"That doesn't sound like a ringing endorsement.\"\n\n## Discussion\n\n### `readonly` for primary constructor parameters\n\n**Champion Issue**: https://github.com/dotnet/csharplang/issues/8105  \n**Related Issue**: https://github.com/dotnet/csharplang/issues/188  \n**Proposal Link**: https://github.com/dotnet/csharplang/blob/db6cac459463fdcb53e87eb6f2f41ca534e44b43/proposals/readonly-parameters.md\n\nToday, we took a look at whether we should constrain the\n[existing `readonly` parameter proposal](https://github.com/dotnet/csharplang/blob/db6cac459463fdcb53e87eb6f2f41ca534e44b43/proposals/readonly-parameters.md)\nto just be for primary constructor parameters. Notably, we're not looking whether we should do `readonly` in general; we're only looking at whether we want to\ndo `readonly` for primary constructor parameters separately and first. The full proposal takes the view that primary constructor parameters should be treated\nas parameters fully and completely, so marking one `readonly` would mean that no assignment of the parameter is possible (outside `unsafe` code), even in locations\nthat can modify instance `readonly` members like instance member initializers or constructor bodies. Given this, and a general lack of belief that primary\nconstructor parameters should be mutable in those locations, makes us wonder why we'd break `readonly` apart into multiple stages here.\n\nWe did also discuss other approaches to the problem that some users are facing here; mainly, is there an analyzer approach that can work such that users can\neffectively get `readonly` by default, and then be able to opt into mutability? We think there is, and the idea is worth exploring, but it's important to note that\nwhen we've previously added `readonly` to new locations, it's been driven by codegen needs. The ability to mark `struct` members as `readonly`, for example, allowed\nthe compiler to avoid `dup` instructions where it would otherwise need to make defensive data copies. The same is true for `readonly` on `ref`s. There's no real\ncodegen advantages to speak of here; given that we don't guarantee that primary constructor parameters are even captured as fields, there's no guarantee we could\nmake that `readonly` will be applied to any instance members that are generated from primary constructor parameters marked `readonly`. It may be worth exploring the\nanalyzer avenue further, though we do want to be very cautious about effectively shipping a language feature as an analyzer, rather than a core part of C#, especially\none that would affect a core way the language feels.\n\nGiven these sentiments, we feel comfortable rejecting the narrow version of this proposal. We are not rejecting the overall proposal; there is still plenty of debate\nto be had on whether `readonly` on parameters is a general thing we want to have in C#. But we are confident that we don't want to do the narrow version where it\nonly applies to primary constructor parameters.\n\n#### Conclusion\n\nNarrow proposal is rejected.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-05-13.md",
    "content": "# C# Language Design Meeting for May 13th, 2024\n\n## Agenda\n\n- First-class span types questions\n    - Delegate conversions\n    - Variant conversion existence\n- Overload resolution priority questions\n    - Attribute shape and inheritance\n    - Extension overload resolution\n\n## Quote(s) of the Day\n\n- \"That's my interpretation, and you can't check my math anyways.\"\n- \"[Who's on first](https://www.youtube.com/watch?v=sShMA85pv8M) should be on the citizenship test\"\n\n## Discussion\n\n### First-class span types questions\n\nhttps://github.com/dotnet/csharplang/issues/7905\n\n#### Delegate conversions\n\nhttps://github.com/dotnet/csharplang/blob/4e88fd3f9cb305b467bdc9c4f54f691733093cf5/proposals/first-class-span-types.md#delegate-signature-matching\n\nFirst up, we considered whether we should try and replicate covariance in method group assignment conversions. On the one hand, the example code seems sensible enough, and would certainly work today\nwith arrays. However, we don't have precedent  for emitting thunks for delegate assignments. Further, while we could make the initial conversion work easily enough, we couldn't then make converting from\n`Func<ReadOnlySpan<string>>` to `Func<ReadOnlySpan<object>>` transparent, like converting from `Func<string[]>` to `Func<object[]>` is seamless and preserves reference identity. Looking at the BCL use cases\nfor this, we don't see anything that is planning to take advantage of this type of method-group variance; given these caveats, we have decided to not support variance in method-group assignment here.\n\n##### Conclusion\n\nVariance in delegate assignment is not supported.\n\n#### Variant conversion existence\n\nWe next considered whether we should support covariance in `ReadOnlySpan<T>` when the helper method, `ReadOnlySpan<T>.CastUp<TDerived>`, is not present. Supporting this down-level could be potentially quite\ncomplicated. We considered a few different approaches:\n\n1. We could consider the conversion to only exist when `CastUp<TDerived>` exists. This ensures that if anyone depends on the behavior, it must be present, but it causes overload resolution to be unstable\n   within a single language version, and increases the decoder ring of what a user would need to know to understand why a particular overload was or wasn't picked. It avoids breaking changes when a user\n   turns on C# 13 and doesn't upgrade to .NET 9, but the complexity tradeoff seems like it will not be worth it.\n2. We could consider the conversion to always exist, but issue an error when we cannot find the required `CastUp<TDerived>` method. This is fairly in-line with what we do for other language features that\n   require specific features, but we're concerned about the breaking change potential here. When a user upgrades to C# 13, these new conversions may cause overload resolution to pick a new member. That\n   resolution could then cause an error because `CastUp<TDerived>` doesn't exist.\n3. We could generate a `<PrivateImplementationDetails>` method for converting the span. On platforms with built-in `ReadOnlySpan<T>` support, and in particular .NET Core 2.2 and later, this seems like it would\n   work fine. However, we're concerned about other platforms; users can bring their own `ReadOnlySpan<T>` implementations, and there's no guarantee that whatever bit-blit strategy the compiler choses would be\n   safe for that implementation. We also aren't prepared to make strong statements on whether this would always be safe on the .NET Framework implementation of `ReadOnlySpan<T>`.\n4. We thought about whether we could ship an update to `System.Memory`. However, this would be quite complicated; we'd actually need to ship a new package, perhaps `System.MemoryEx` or `System.Memory2`,\n   otherwise code that compiled against .NET Standard 2.0 and depended on the new functionality might break when run on .NET 8.\n5. We considered whether we should abandon variance entirely. After all, the main thrust of the proposal is not variance; that's a \"nice to have\" on top of the type inference and extension method features. However,\n   we think it would be a shame to avoid a useful language feature because we may issue an error down-level; especially given that the feature is a corner case scenario and users that want to use newer C# features\n   on down-level platforms have to contend with far more obvious missing things.\n\nGiven all these options, we eventually settled on 2: when in C# 13+, the conversion will always exist, but the compiler will issue an error when it cannot find `CastUp<TDerived>`.\n\nFinally, we thought about whether extensions should be able to provide `ReadOnlySpan<T>.CastUp<TDerived>`. That method is a static method on `ReadOnlySpan<T>`, so it could theoretically be provided by extension\ntypes. However, we don't think we're ready to decide, in case or in general. We'll have to consider extension types more generally with compiler pattern matching; for today, we'll simply say it cannot be provided\nby an extension type, and revisit when we're ready to consider the question holistically across C#.\n\n##### Conclusion\n\nIn C# 13, the variance conversion will always exist, and the compiler will issue an error if it cannot find `ReadOnlySpan<T>.CastUp<TDerived>`.\n\n### Overload resolution priority questions\n\nhttps://github.com/dotnet/csharplang/issues/7706\n\n#### Attribute shape and inheritance\n\nhttps://github.com/dotnet/csharplang/blob/4e88fd3f9cb305b467bdc9c4f54f691733093cf5/proposals/overload-resolution-priority.md#systemruntimecompilerservicesoverloadresolutionpriorityattribute\n\nFirst up in overload resolution priority, we considered the shape of the attribute. As part of this, we need to consider the inheritance behavior, to at least some degree, in order to decide what the `Inherited`\nattribute usage property should be. For this, we looked to prior art in C#: method types, `params`, parameter names, and default values. Unfortunately, there's no singular consistent rule here, but we do have\nthe principles to guide us; most things look at the least-derived members. For parameter names and default values, however, we look at the most-derived, which keeps us consistent with the semantics VB already\nhad for these scenarios. We don't think that there's reason to use that most-derived logic here; if anything, we think that would run counter to the proposal itself, which is designed to only be used within a\nsingle type. Allowing overrides to change the priority of a member would defeat this; derived types can always hide the member and create their own version if they wish to adjust priority, as they can today.\nGiven this, `Inherited` should be false, as we don't want it to show up in reflection on overriding members when it's not permitted in source.\n\n##### Conclusion\n\nWe are satisfied with the proposed shape of the attribute. Overload resolution will always look at the least-derived member definition for its priority. We still have open questions on whether we should hard-block\nthe attribute application on overrides, and what we will do for implementations of interface members that have a priority.\n\n#### Extension overload resolution\n\nhttps://github.com/dotnet/csharplang/blob/4e88fd3f9cb305b467bdc9c4f54f691733093cf5/proposals/overload-resolution-priority.md#overload-resolution-priority-1\n\nFinally today, we considered the question of whether overload resolution should behave identically for instance and extension lookups, or if we should not group extension methods by type before doing overload\nresolution priority sorting. We don't have any current use-cases for inter-extension priority, and we also think that not grouping would again run against the \"this is a tool within a type only\" principle from\nthe proposal.\n\n##### Conclusion\n\nWe will always group by declaring type before removing lower priority overloads. The given example will print `\"Ext2 ReadOnlySpan\"`.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-05-15-KeyValuePairCorrespondence.md",
    "content": "# KeyValuePair correspondence\n\nIn .NET, dictionary types and the `KeyValuePair<TKey, TValue>` (aka KVP, or KeyValuePair) types are intertwined.  A dictionary is commonly defined as a collection of elements of that KVP type, not just a mapping from some `TKey` to some `TValue`.  Indeed, this duality allows one to treat the two spaces mostly uniformly.  For example:\n\n```c#\nvar dictionary = new Dictionary<string, int>();\nvar collection = (ICollection<KeyValuePair<string, int>>)dictionary;\ncollection.Add(new KeyValuePair<string, int>(\"mads\", 21));\n```\n\nWhat is special about dictionaries, over standard element-based collection expressions, is that the dictionary types have a general view that any particular key will only be contained once, and can be used to then more efficiently map to its associated value over doing a linear scan.  Put more intuitively: A \"dictionary type\" is a \"collection type\" whose \"element type\" is some `KeyValuePair<K, V>` and which has an available `V this[K key] { get; }` indexer.\n\nBecause of this correspondence, we believe that dictionary expressions should not be considered very special and distinct from existing collection expressions.  Rather, the \"dictionary expression\" language feature is actually a feature that allows KeyValuePairs to be naturally expressed within collection expressions, along with a sensible and uniform set of rules to allow KeyValuePairs to naturally initialize collection types.  This \"natural expression\" happens both syntactically and semantically.\n\nSpecifically:\n\n1. There is a new special syntax for declaring a KeyValuePair within a collection expression:\n\n    ```c#\n    X x = [k: v];\n    ```\n\n1. It can be used with dictionary types:\n\n    ```c#\n    Dictionary<string, int> nameToAge = [\"mads\": 21];\n    ```\n\n1. And also with existing collection types:\n\n    ```c#\n    List<KeyValuePair<string, int>> pairs = [\"mads\": 21];\n    ```\n\n1. And, while the syntax allows for easy specification of the particular key and value, usage of that syntax is optional.  Semantically, the feature works equally with normal KeyValuePair instances:\n\n    ```c#\n    KeyValuePair<string, int> kvp = new(\"mads\", 21);\n    Dictionary<string, int> nameToAge = [kvp];\n    ```\n\n1. The above allows for *uniformity* of processing KeyValuePair values, which we consider desirable so that users can expect them to work for all collection expressions elements:\n\n    ```c#\n    // Both 'spread' elements and 'expression' elements that evaluate \n    // to KeyValuePair values work with dictionary types\n    Dictionary<string, int> nameToAge = [.. defaultValues, otherMap.Single(predicate)];\n    ```\n\n    Here, being able to 'spread' in another collection (which would normally be some `IEnumerable<KeyValuePair<,>>`) is desirable.  Similarly, being able to add individual pairs found through some means, without having to decompose into `k: v` syntax, is equally preferable.\n\n## KeyValuePair transparency\n\nThe existing \"Collection Expression\" feature has a guiding principle that elements and spreads can be thought of as being lowered to `Add` calls. This enables things to be included or spread into the final collection that have a more specific type than the collection's element type itself.  For example:\n\n```c#\n// The collection expression can be comprised of `int` values\n// despite the element type being `int?`.\nList<int?> ages = [18, .. Enumerable.Range(21, 10)];\n```\n\nThis allowance is implied by the lowered representation, where implicit conversions enable a straightforward scenario to appear equally straightforward in code without onerous explicit casts:\n\n```c#\nvar ages = new List<int?>();\nages.Add(18);\nforeach (var value in Enumerable.Range(21, 10))\n    ages.Add(value);\n```\n\nDictionary expressions have a corollary. Both the key and the value can be more specific types than the key and value types of the dictionary being built, when lowered in the same manner:\n\n```c#\nvar map1 = new Dictionary<object, int?>();\nmap1[\"mads\"] = 21;\n// Etc\n```\n\nTo achieve this principle in dictionary expressions, we expect the exact type of the KeyValuePair values to be generally transparent.  Rather than being strictly that type, the language will generally see *through* it to be a pair of some `TKey` and `TValue` types.  This transparency is in line with how tuples behave and serves as a strong intuition for how we want users to intuit KeyValuePairs in the context of collection expressions.\n\nHow does this transparency manifest?  Consider the following scenario:\n\n```c#\nDictionary<object, int?> map1 = [\"mads\": 21];\n```\n\nThe above expression would certainly be expected to work.  While `\"mads\"` is a string, and `21` an `int`, the target-typed nature of collection expressions would push the `object` and `int?` types through the constituent key and value expressions to type them properly.  We would *not* disallow this, despite `KeyValuePair<string, int>` and `KeyValuePair<object, int?>` being incompatible.\n\nThis would also be expected to work in the following case:\n\n```c#\nDictionary<object?, int?> map2 = [null: null];\n```\n\nKeyValuePair transparency means that just as we expect the code for `map1` to be legal, we should consider the following legal as well:\n\n```c#\nKeyValuePair<string, int> kvp = new(\"mads\", 21);\nDictionary<object, int?> map1 = [kvp];\n```\n\nAfter all, why would that be illegal, while the following became legal?\n\n```c#\nKeyValuePair<string, int> kvp = new(\"mads\", 21);\nDictionary<object, int?> map1 = [kvp.Key: kvp.Value];\n```\n\nRequiring explicit deconstruction of the constituent key and value portions of a KVP, just to satisfy the compiler so it could target-type them, adds extra, painful steps.  It would become doubly worse once all collection element expressions are considered. We would like users to be able to write:\n\n```c#\n Dictionary<object, int?> map = [.. nameToAge, otherMap.Single(predicate)];\n\n// Not:\n\nvar singleElement = otherMap.Single(predicate);\nDictionary<object, int?> map = [.. nameToAge.Select(kvp => new KeyValuePair<object, int?>(kvp.Key, kvp.Value), singleElement.Key: singleElement.Value];\n```\n\n## Tuple analogy\n\nIt turns out that this sort of behavior is *exactly* what already exists in the language today for tuples.  Consider the following:\n\n```c#\nList<(object? key, int? value)> map = [(\"mads\", 21)];\n```\n\nThis already works today.  The language transparently sees through into the tuple expression to ensure that the above is legal.  This is also not a conversion applied to some `(string, int)` tuple type.  That can be seen here which is also legal:\n\n```c#\nList<(object? key, int? value)> map = [(null, null)];\n```\n\nHere, the types of the destination flow all the way through (including recursively through nested tuple types) into the tuple expression in the initializer.  This transparency is not limited to *tuple expressions* either.  All of the following are legal as well, despite non-matching *ValueTuple types*:\n\n```c#\n(string x, int y) kvp = (\"mads\", 21);\n\n// (string, int) and (object?, int?) are not compatible at the runtime\n// level.  The language enables this at the C# level.\nList<(object? key, int? value)> map = [kvp];\n```\n\nAnd\n\n```c#\n(string? x, int? y) kvp = (null, null);\nList<(object? key, int? value)> map = [kvp];\n```\n\nThe language always permissively views tuples as a loose aggregation of constituent elements, each with their own type.  Conversions and compatibility are all performed on those constituent element types, not on the top level `ValueTuple<>` type which would normally not be compatible based on .NET type system rules.\n\n## KeyValuePair inference\n\nThe tuple analogy above serves as an analogous system we can look to in order to see how we would like KeyValuePair to behave in collection expressions.  For example:\n\n```c#\nvoid M<TKey, TValue>(List<(TKey key, TValue value)> list1, List<(TKey key, TValue value)> list2);\n\n// Note: neither tuple1 nor tuple2 are assignable/implicitly convertible\n// to each other. Each has an element that has a wider type than the \n// corresponding element in the other.\n(string x, int? y) tuple1 = (\"mads\", 21);\n(object x, int y) tuple2 = (\"cyrus\", 22);\n\n// Infers `M<object, int?>`\nM([tuple1], [tuple2]);\n```\n\nThis works today and correctly infers `M<object, int?>`.  Given the above, we would then desire the following to work:\n\n```c#\nvoid M<TKey, TValue>(Dictionary<TKey, TValue> d1, Dictionary<TKey, TValue> d2);\n\n// Note: neither kvp1 nor kvp2 would ever be assignable/implicitly convertible to each other.\nKeyValuePair<string, int?> kvp1 = new(\"mads\", 21);\nKeyValuePair<object, int> kvp2 = new(\"cyrus\", 22);\n\n// Would like this to infer `M<object,int?>` as well.\nM([kvp1], [kvp2]);\n```\n\n## Tuple analogy (cont.)\n\nThe analogous tuple behavior serves as a good *bedrock* for our intuitions on what we want for KeyValuePairs.  However, how far we want to take this analogy is up to us, and we can consider several levels of increasing transparency support.  Those levels are:\n\n1. No transparency support.  Do not treat KVPs like tuples.  Force users to explicitly convert between KVP types to satisfy type safety at the KVP level itself.  For example:\n\n    ```c#\n    KeyValuePair<string, int> kvp = new(\"mads\", 21);\n    Dictionary<object, int?> map1 = [kvp]; // illegal.  user must write:\n    Dictionary<object, int?> map1 = [kvp.Key: kvp.Value];\n\n    Dictionary<object, int?> map1 = [.. nameToAge, otherMap.Single(predicate)]; // illegal.  user must write:\n\n    var temp = otherMap.Single(predicate);\n    Dictionary<object, int?> map1 = [.. nameToAge.Select(kvp => new KeyValuePair<object, int?>(kvp.Key, kvp.Value)), temp.Key: temp.Value];\n    ```\n\n1. Transparent only when targeting some dictionary type, but not non-dictionary types:\n\n    ```c#\n    KeyValuePair<string, int> kvp = new(\"mads\", 21);\n    Dictionary<object, int?> map1 = [kvp]; // legal.\n\n    List<KeyValuePair<object, int?>> map1 = [kvp]; // not legal.  User must write:\n    List<KeyValuePair<object, int?>> map1 = [kvp.Key: kvp.Value]; // or\n    List<KeyValuePair<object, int?>> map1 = [new KeyValuePair<object, int?>(kvp.Key, kvp.Value)];\n    ```\n\n1. Transparent in any collection expression, but no further:\n\n    ```c#\n    KeyValuePair<string, int> kvp = new(\"mads\", 21);\n    Dictionary<object, int?> map1 = [kvp]; // legal.\n    List<KeyValuePair<object, int?>> map1 = [kvp]; // legal.\n\n    KeyValuePair<object, int?> kvp2 = kvp1; // not legal.  User must write:\n    KeyValuePair<object, int?> kvp2 = new KeyValuePair<object, int?>(kvp1.Key, kvp.Value);\n    ```\n\n1. Transparent everywhere:\n\n    ```c#\n    KeyValuePair<string, int> kvp = new(\"mads\", 21);\n    Dictionary<object, int?> map1 = [kvp]; // legal.\n    List<KeyValuePair<object, int?>> map1 = [kvp]; // legal.\n    KeyValuePair<object, int?> kvp2 = kvp1; // legal.\n    ```\n\nThese four options form a spectrum, starting with doing nothing special, then only handling dictionaries, then handling any collection, all the way to the maximum support which effectively puts KeyValuePair handling at the same level as tuples for the language.\n\nOpen question 1: How far would we like to take this transparency?  All the way to full analogy with tuples?  No transparency at all?  Somewhere in the middle?\n\n## Deconstruction\n\nAll of the above so far has been about how the language would enable working more conveniently with the KeyValuePair type.  And, there are good arguments to be made that KeyValuePair needs to allow these important scenarios to light up, due to how integral it is to the dictionary-type space to begin with.  However, fundamentally, all of the above could be reformulated, enabling the same scenarios without specializing KeyValuePair at all.  Specifically, all of the above works by stating that KeyValuePair can be seen transparently as a pair of two typed values (the `TKey Key` and the `TValue Value`).  Fundamentally, as that's all that is truly required, a relaxation could be performed that restates all of the above as:\n\n> Any type that is *constructible* and *deconstructible* into two elements would be transparently supported in the context of collection expressions and the `k: v` element.\n\nThat relaxation would consume all the KeyValuePair support.  But would also then enable tuples to be used in all those cases *as well as* any appropriate type supporting two-element construction/deconstruction.  As such, all of the below would be legal:\n\n```c#\nDictionary<string, int> nameToAge1 = [(\"mads\", 21)];\n\nList<(string, int)> pairs = ...;\nDictionary<string, int> nameToAge2 = [.. pairs];\n\nrecord struct NameAndAge(string Name, int Age);\nDictionary<string, int> nameToAge3 = [nameToAge1, nameToAge2];\n\nList<NameToAge> pairs = [\"mads\": 21, \"cyrus\": 22, \"joseph\": 23];\n// etc.\n```\n\nOpen question 2: How far would we like to take this? \n\n1. Only support KeyValuePair.  2-element tuples and other 2-element deconstructible types have no special meaning in a collection expression.\n\n    ```c#\n    Dictionary<string, int> nameToAge = [kvp]; // legal\n\n    Dictionary<string, int> nameToAge = [(\"mads\", 21)]; // not legal\n\n    record NameAndAge(string Name, int Age);\n    NameAndAge nameAndAge = new(\"mads\", 21);\n    Dictionary<string, int> nameToAge = [nameAndAge] // not legal\n    ```\n\n1. Support KeyValuePair and 2-element tuples, but not other 2-element deconstructible types.\n\n    ```c#\n    Dictionary<string, int> nameToAge = [kvp]; // legal\n\n    Dictionary<string, int> nameToAge = [(\"mads\", 21)]; // now legal!\n\n    record NameAndAge(string Name, int Age);\n    NameAndAge nameAndAge = new(\"mads\", 21);\n    Dictionary<string, int> nameToAge = [nameAndAge] // not legal\n    ```\n\n1. Support any 2-element deconstructible types?\n\n    ```c#\n    Dictionary<string, int> nameToAge = [kvp]; // legal\n\n    Dictionary<string, int> nameToAge = [(\"mads\", 21)]; // legal\n\n    record NameAndAge(string Name, int Age);\n    NameAndAge nameAndAge = new(\"mads\", 21);\n    Dictionary<string, int> nameToAge = [nameAndAge] // now legal!\n    ```\n"
  },
  {
    "path": "meetings/2024/LDM-2024-05-15.md",
    "content": "# C# Language Design Meeting for May 15th, 2024\n\n## Agenda\n\n- [`field` and `value` as contextual keywords](#field-and-value-as-contextual-keywords)\n  - [Usage in `nameof`](#usage-in-nameof)\n  - [Should `value` be a keyword in a property or indexer get? Should `field` be a keyword in an indexer?](#should-value-be-a-keyword-in-a-property-or-indexer-get-should-field-be-a-keyword-in-an-indexer)\n  - [Should `field` and `value` be considered keywords in lambdas and local functions within property accessors?](#should-field-and-value-be-considered-keywords-in-lambdas-and-local-functions-within-property-accessors)\n  - [Should `field` and `value` be keywords in property or accessor signatures? What about `nameof` in those spaces?](#should-field-and-value-be-keywords-in-property-or-accessor-signatures-what-about-nameof-in-those-spaces)\n- [Dictionary expressions](#dictionary-expressions)\n\n## Quote of the Day\n\n- \"What the lowering implies here\" _screen goes blank_ \"Oh, you lowered too far\"\n\n## Discussion\n\n### `field` and `value` as contextual keywords\n\nProposal: https://github.com/dotnet/csharplang/issues/7964  \nRelated: https://github.com/dotnet/csharplang/issues/8130, https://github.com/dotnet/csharplang/issues/140\n\nWe started today by looking at a number of open questions in the `field` and `value` as contextual keywords proposal.\n\n#### Usage in `nameof`\n\nFirst up today, we considered whether `field` and `value` should be allowed in `nameof`. `nameof(value)` already works today, and there was no real pushback on keeping it\nworking; it has an obvious value to return (no pun intended), and is an easy way to mitigate some of the scope of the breaking change. More controversial was `nameof(field)`.\nFirst, if we do allow it, what does it evaluate to? We have precedence with type aliases; `nameof(MyAliasForList)` will evaluate to the string `\"MyAliasForList\"`, not `\"List\"`,\nbut there will no doubt be at least a few users who expect it to evaluate to the actual IL name of the backing field. We're also a bit unsure about what the use case for\n`nameof(field)` would be in this case; it wouldn't be used for argument validation, since there is no argument. It also wouldn't be used in something like `MemberNotNull`,\nsince it isn't accessible outside the property. We did discuss whether we should simply allow it to make `field` and `value` consistent, but given the lack of motivating scenarios,\nwe feel that it would be better to start with a tighter restriction we can loosen later if we hear feedback.\n\n##### Conclusion\n\n`nameof(value)` is legal, and will evaluate to `\"value\"`. `nameof(field)` will not be legal.\n\n#### Should `value` be a keyword in a property or indexer get? Should `field` be a keyword in an indexer?\n\nThe question at the heart of this is \"should these be keywords where they will never work\"? We quickly and unanimously said \"no\", even before finding an\n[example](https://github.com/dotnet/runtime/blob/19467dccf4e6786296eecd8007f90e6dafe01818/src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XAttribute.cs#L158-L172)\nof where such a change would be unnecessarily breaking.\n\n##### Conclusion\n\n`value` will not be a keyword in property or indexer `get`s. `field` will not be a keyword in indexers.\n\n#### Should `field` and `value` be considered keywords in lambdas and local functions within property accessors?\n\nWe have prior art here, both in `await` inside an `async` function, and in LINQ query syntax within a nested lambda. In both of those cases, the context isn't further in\ninterpreted; it's inside an `async` method or a LINQ query, so the keywords exist. We think that these keywords should behave exactly the same way; that both simplifies the\nlanguage, and also feels like the logical conclusion.\n\n##### Conclusion\n\nYes, `field` and `value` will be contextual keywords within nested contexts when they exist.\n\n#### Should `field` and `value` be keywords in property or accessor signatures? What about `nameof` in those spaces?\n\nWe split this question into two parts:\n\nFirst, the property signature itself. Conceptually `field` could be in scope here, but `value` definitely wouldn't be; it isn't today, and we don't think it should be tomorrow.\nFor `field` in this position, we don't see a reason to enable it, so it also won't be visible in the property declaration.\n\nSecond, inside accessor declarations, we have prior art of what we allow with `value` today. As an example:\n\n```cs\npublic class C(string s) : Attribute\n{\n    public int P\n    { \n        get;\n        [param: C(nameof(value))] set;\n    }\n}\n```\n\nThis is existing, legal C# code, where `value` is permitted in the attribute list of a property setter. Further complicating our existing rules is this example:\n\n```cs\nclass value(string type) : Attribute\n{    \n    value I\n    {\n        get;\n        [param: value(nameof(value))] set;\n    }\n}\n```\n\nIn this case, the `value` type shadows the parameter name, including for the `nameof(value)`. This scenario is, we hope, non-existant; our search for types named `value`\nor `field` encountered nothing for the former, and only a test case in the mono/mono codebase for the latter. We therefore don't think we need to be concerned about breaking\nthe behavior in this case; we therefore settled on `field` and `value` being contextual keywords in the signatures of accessors where they exist, including in attributes.\n\n##### Conclusion\n\n`field` is a keyword in property `get` and `set` accessors. `value` is a keyword in property and indexer `set` accessors. Neither is a keyword in the main property or indexer\nsignature.\n\n### Dictionary expressions\n\nProposal: https://github.com/dotnet/csharplang/issues/7822\nRelated: [KeyValuePair Correspondence](./LDM-2024-05-15-KeyValuePairCorrespondence.md)\n\nToday we looked at an outline of how `KeyValuePair` (`KVP`) corresponds to `Tuple<T1, T2>`, and principles of how much we should let the latter shape our direction for the former.\nWhile we didn't get down to any hard decisions today, we did have a few comments during the overview to record:\n\n* This proposal for making `KVP` transparent doesn't address how recursive to make it. For example, `KVP<string, KVP<int, int>>`.\n* Proposal 4, where `KVP` is fully transparent everywhere in the language, is a potential breaking change.\n* The meaning of adding a `KVP` changes when you consider target-typing a dictionary-like type vs a list-like type; the former will either overwrite or throw, and the latter will\n  simply append.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-06-03.md",
    "content": "# C# Language Design Meeting for June 3rd, 2024\n\n## Agenda\n\n- [Params collections and dynamic](#params-collections-and-dynamic)\n- [Allow ref and unsafe in iterators and async](#allow-ref-and-unsafe-in-iterators-and-async)\n\n## Discussion\n\n### Params collections and dynamic\n\nIssue: https://github.com/dotnet/roslyn/issues/73643\n\nThe issue describes an existing scenario where we started issuing warnings although we didn't use to. The scenario seems mainline: It's in Razor, and it combines the use of dynamic and params, both of which are common in the context. This seems an easy situation to get into.\n\nThe warning is about one or more candidates not being able to be understood by the runtime binder, which will therefore ignore them. The warning means that new overloads, in this case params collection overloads, can \"poison the pot\", even for cases where the runtime binder could have still handled things just fine, only with a possibly different outcome than the compile-time binder.\n\nWe do have some existing warnings of the same type, but they were grandfathered in. The problem here is that the combination of a new language feature that the runtime binder can't handle plus new overloads that use that feature cause *new* warnings in existing code.\n\nThis seems like the first of potentially several situations like this going into the future. What should our general philosophy be going forward?\n\nIf we are certain that something is not going to work out at runtime, we can give compile-time *errors*. But is there ever a case where a *warning* is the right thing for dynamic? After all, use of the feature in and of itself signals a willingness to risk things going awry at runtime.\n\n#### Conclusion\n\nIn the particular case in question, the warning does not serve a useful purpose and is not worth the break in behavior that it causes.\n\nFurthermore, we feel in general that warnings are not useful with dynamic. They are a signal that something *might* not work, and with dynamic people are already bought in to that outcome. All else equal we should avoid adding such warnings in the future also.\n\nWe are fine with compile-time errors when we're certain things don't work out at runtime. We're even fine adding *new* compile-time errors for *existing* scenarios that break at runtime, since people are already broken, and getting the error earlier is helpful.\n\n### Allow ref and unsafe in iterators and async\n\nProposal: https://github.com/dotnet/csharplang/blob/main/proposals/ref-unsafe-in-iterators-async.md\n\nThe proposal loosens the restrictions on having ref variables and unsafe blocks in iterators and async methods. The reason for earlier restrictions is that ref variables and unsafe code need their state on the stack, and don't mix well with `yield` and `await` which need to squirrel away state in the heap. However, there is no problem with ref and unsafe being used *between* `yield`s and `await`s, as long as the ref or unsafe state does not need to be persisted across them. This is what the proposal allows.\n\nThe feature is already implemented - this is a review of the speclet to verify that we remain in agreement with all the decisions.\n\nSome specific points of discussion:\n\n#### Lock statements in iterators\nCurrently, `yield` statements are allowed inside `lock` statements in iterators. This keeps a lock while the iterator is suspended, which is highly dubious, and the proposal calls for a new warning on this pattern of code.\n\nAdditionally, there is a new variant of the `lock` statement (https://github.com/dotnet/csharplang/blob/main/proposals/lock-object.md) specifically for the `System.Threading.Lock` type. Since this type is a ref struct, such a lock statement constitutes a use of a ref across a `yield` and is therefore an error.\n\n#### Breaking change because of Roslyn bug: \nUp until now, local functions inside unsafe async methods were erroneously allowed to have unsafe behavior, even though the top-level method body was safe due to other rules. The proposal calls for breaking this with an error going forward. Such an error is already issued for unsafe operations inside of lambda expressions - we just missed implementing it for local functions when we added those to the language.\n\n#### Conclusion\nWe like this. Each design point seems well argued and balanced. We're provisionally ok with the breaking change on the local functions. We'll keep an eye on fallout and discuss if consequences turn out worse than we're able to anticipate.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-06-10.md",
    "content": "# C# Language Design Meeting for June 10th, 2024\n\n## Agenda\n\n- [`ref struct`s implementing interfaces and in generics](#ref-structs-implementing-interfaces-and-in-generics)\n\n## Quote of the Day\n\n- No particularly amusing quotes occurred today. Sorry.\n\n## Discussion\n\n### `ref struct`s implementing interfaces and in generics\n\nChampion Issue: https://github.com/dotnet/csharplang/issues/7608  \nProposal: https://github.com/dotnet/csharplang/blob/f2db071d1ccd4f69edf9c3186e13c4331630fa7b/proposals/ref-struct-interfaces.md\n\nToday we went through the current version of the `ref struct` improvements specification to catch up LDM on all the implementation decisions that have been made\nby team during development, as well as any wrinkles that the core libraries team ran into while absorbing the feature. Most of the changes were approved without issue;\n\n* We confirmed that `allows` is the syntax we will go with for the feature, over `allow`.\n* We discussed the implications of default interface members not being supported on `ref struct`s; it's an unfortunate limitation, but we can't think of any way around it.\n  The boxing of the receiver is done by the runtime, so we can't try and allow it for specific DIMs that don't violate rules. We also don't see much of a use case for a DIM\n  that doesn't call an instance member on the type immediately anyways.\n* One of the marquee original intentions for `ref struct`s implementing interfaces was for `Span<T>` and `ReadOnlySpan<T>` to implement `IEnumerable<T>`. This would help\n  solve a number of betterness issues with adding new APIs, but because `IEnumerable<T>.GetEnumerator()` returns an `IEnumerator<T>`, we can't implement it in an allocation-free\n  manner. That would cause any `IEnumerable` API to become a performance trap for `Span<T>`, which is extremely undesirable.\n\nLooking further at this last point, we realize that this means that we don't have any major use-cases for `ref struct`s implementing `interface`s at present. The core libraries\nteams do not currently have plans to use the functionality; they do intend to make heavy use of `allows ref struct`, but this will mainly be on \"transparent\" types, such\nas `Action` or `Func`. The implementation of these types don't require specialization based on functionality, but instead serve as abstractions for user code that may want to\nabstract over `ref struct`s as well. Given that we don't have example use cases for interface implementation to validate our rules against, we are a bit concerned about\nshipping the feature in release without the ability to ensure that we are actually shipping a useful feature; it would not be good to ship something that consumers eventually\ncome back and say is unusable because we missed some critical design flaw. Given this, we're currently considering holding back that half of the feature in preview until we have\nscenarios to validate against. We'd like to hear from the community here as well; what are your use cases for `ref struct`s implementing `interface`?\n\n#### Conclusion\n\nRules for `ref struct`s in generics are approved. Rules for `ref struct`s implementing interfaces generally look good, but need validation against real world scenarios before we\nallow this part of the feature to ship in anything more than preview.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-06-12.md",
    "content": "# C# Language Design Meeting for June 12th, 2024\n\n## Agenda\n\n- [`params Span` breaks](#params-span-breaks)\n- [Extensions](#extensions)\n\n\n## Quote(s) of the Day\n\n- \"When I share on Teams I lose my mouse.\" \"You're a VIM user, you shouldn't be using your mouse anyway.\"\n- \"I was expecting this to tear us apart.\" <2 people post gifs of The Room> \"Someone got the reference. He's my totem actor.\"\n\n## Discussion\n\n### `params Span` breaks\n\nChampion Issue: https://github.com/dotnet/csharplang/issues/7700  \nIssue: https://github.com/dotnet/roslyn/issues/73743\n\nWe started today with a shorter discussion on a potential upgrade trap with `params` collections in C# 13. Because `params Span<T>` is preferred over `params T[]`, it will mean\nthat, on upgrade, call sites start preferring newly-introduced `Span<T>` overloads; these overloads cannot be used in expression trees, however, so code that worked fine previously\nwill now start failing. To work around this, consumers will have to explicitly create an array with `new[] { }`, instead of letting `params` work as expected. While unfortunate, this\nis much the same flavor of breaking change we have encountered in other instances where we introduce new conversions; we think it would be more unfortunate to try and handle this\nspecially, and then later need to make still more changes if we update expression trees. Given that, we think the best approach is to simply document the potential breaking change\nand leave this as is. We'll let this sit over the weekend and think on it, and come back on Monday to make a final decision.\n\n#### Conclusion\n\nNo conclusion today.\n\n### Extensions\n\nChampion Issue: https://github.com/dotnet/csharplang/issues/5497  \nRelated: https://github.com/dotnet/csharplang/pull/8121\n\nFinally, we're back on extension codegen, this time with unfortunate news; our codegen strategy for extensions, and in particular using `Unsafe.As`, was rejected by the .NET runtime\narchitects as fundamentally unsafe. There are potential aliasing issues that could cause parts of the JIT to become confused, particularly in rarer optimization scenarios, and they\ncannot guarantee that it will always be safely handled given our intended usage patterns; they would need to teach the runtime to handle these scenarios. Given that one of the goals\nof the current emit strategy is that it would need no runtime participation until a later date when we look at interface implementation, this is unfortunate; it would even mean that\nwe couldn't ship any form of extensions in the .NET 9 timeframe, not even in preview. This is a long-lead feature and will need bake time with real users before we're fully confident\nthat we have the right design, so we wanted to head back to the drawing board for emit. We see two main approaches:\n\n1. Fully commit to runtime support. If we wanted to go the runtime support route, we wouldn't just rely on `Unsafe.As`; we'd update the runtime to just directly allow ref assignment of an\n   underlying type to an extension type. This would be safer at a runtime level, as it gives it a primitive it can verify. It may also give us a better starting point for later support\n   of interface members. However, we also think that it's unfortunate that we wouldn't be able to get any previewing during the .NET 9 timeframe. While we don't want to be afraid of not\n   shipping features that were promised if they're not ready, this would likely mean that extensions wouldn't be shipped in a stable form until at least .NET 11.  This is pretty\n   unpalatable to the LDM.\n2. Fall back to treating extensions as sugar over static methods on extension types, much like standard extension methods today. There's increased difficulty with the compiler\n   representation here; the public model and internal emit models of these types would have to sugar and desugar to convert between them. It's certainly something that we know how to\n   do today, as we do it with extension methods. That experience tells us that further expanding the sugar is possible, but will have some complicated edges. It will also require more\n   rewrites of member bodies in order to mimic the semantics of instance methods, particularly for nested closures. It is possible, though, and has a couple of advantages:\n    1. A version of this could actually ship in the .NET 9 timeframe, at least in preview. That will let developers get their hands on it to validate our designs.\n    2. Existing extension methods may actually be convertible to the new extension form in a binary-compatible fashion. This could help resolve a concern the LDM has had for a while,\n       that new types would need to be introduced to allow the new style of extension method. It wouldn't be perfect; in particular, any holder of extension methods that has extensions\n       for multiple types likely couldn't work.\n\n   We also don't think the runtime work to support extensions implementing interfaces for these types would be prohibitively more expensive than option 1; to the runtime, a static method\n   that takes an object as its first parameter is very similar to an instance method on that object. While it wouldn't be as immediately straightforward as an instance member on an\n   extension type, we also don't think it will be too challenging, especially since we expect to need runtime support for the interface implementation part anyways.\n\nUltimately, we settled on option 2 here. The binary-compat story is something we want to investigate more with this approach, and the approach still allows for the original goals of the\nrejected codegen proposal.\n\n#### Conclusion\n\nWe change the codegen strategy for extensions to be based on static methods, much like current extension methods, rather than `struct` types and `Unsafe.As`.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-06-17.md",
    "content": "# C# Language Design Meeting for June 17th, 2024\n\n## Agenda\n\n- [`params` Span breaks](#params-span-breaks)\n- [Overload resolution priority questions](#overload-resolution-priority-questions)\n    - [Application error or warning on `override`s](#application-error-or-warning-on-overrides)\n    - [Implicit interface implementation](#implicit-interface-implementation)\n- [Inline arrays as `record struct`s](#inline-arrays-as-record-structs)\n\n## Quote of the Day\n\n- \"I don't want to jinx it, but this is the last open question\"\n\n## Discussion\n\n### `params` Span breaks\n\nChampion Issue: https://github.com/dotnet/csharplang/issues/7700  \nIssue: https://github.com/dotnet/roslyn/issues/73743\n\nToday, we followed up from [last time](LDM-2024-06-12.md#params-span-breaks), now that the LDM has had some time to consider options. To recap, we left the last meeting feeling that our best course of\naction would be to not attempt to mitigate this in the compiler, but instead document the breaking change. We still think this is the case; attempting to mitigate this, either by changing how the\ncompiler binds for expression trees, or using some kind of attribute, will just lead to us eventually needing to figure out how to undo the change later if we ever are able to modernize expression\ntrees. We do think we should invest a bit more in the error experience; having the compiler detect when such an overload is used in an expression tree and issue a specific diagnostic, and having the\nIDE offer to add an explicit array creation will go a long way to making the experience understandable. But ultimately, we will not be trying to ensure the code will compile exactly as is, unchanged.\n\n#### Conclusion\n\nDo not change the compiler. Improve the error reporting experience.\n\n### Overload resolution priority questions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/7706  \nSpec: https://github.com/dotnet/csharplang/blob/a50814bc5d5dacc9bc9b45db4d29c97ce91d2f1c/proposals/overload-resolution-priority.md#open-questions\n\nNext, we went through the 2 open questions in overload resolution priority.\n\n#### Application error or warning on `override`s\n\nFollowing up from the [last time](LDM-2024-05-13.md#overload-resolution-priority-questions), we need to decide what do when a user puts an `OverloadResolutionPriorityAttribute` on an overriding\nmethod. These attributes are always ignored on overrides, so while it isn't necessarily an error in and of itself, such an application has no effect. We don't necessarily think that there's a\nspecific future scenario we want to preserve here, but we still think that such an application is a sign of a user misunderstanding the feature. Given that, we want to hard error in scenarios\nwhere a user applies an `OverloadResolutionPriorityAttribute` that will be ignored by the compiler.\n\n##### Conclusion\n\nIt is an error to put `OverloadResolutionPriorityAttribute` in a location that would be ignored by the compiler, such as method overrides.\n\n#### Implicit interface implementation\n\nNext, we looked at a related open question: should we try and have implicit interface implementations inherit priorities automatically? We don't think this is a good idea; concrete methods can\nactually implement multiple interface members, with potentially different priorities. How they implement various interfaces can also be quite complicated, especially in the presence of `modopt`s\non interface members; the compiler sometimes needs to emit bridge methods that explicitly implement interface members and then forward to the class implementation, should those get the attribute\nautomatically as well? We think it's ultimately simpler and more understandable for everyone if we continue the existing C# precedent that non-signature components, such as parameter names, `params`,\nand attributes, are not inherited by implementations.\n\n##### Conclusion\n\nWe will not inherit `OverloadResolutionPriorityAttribute` from interface definitions.\n\n### Inline arrays as `record struct`s\n\nChampion issue: https://github.com/dotnet/csharplang/issues/7431  \nIssue: https://github.com/dotnet/roslyn/issues/73504\n\nFinally today, we looked at an overlooked scenario from C# 12; applying `InlineArrayAttribute` to a `record struct` type. We never addressed this scenario, so we generate default codegen for `record struct`s\nthat are actually inline arrays. This means that for all the code we generate, such as `Equals`, `GetHashCode`, and `ToString`, we don't do any enumeration of all the array elements. Instead, we just\nlook at the first element. While this is likely something that we could update the C# compiler to handle correctly, we also question the value of doing so; inline array types have very specific\nrequirements, and `record struct` doesn't bring a ton of advantages for them. There's not a potentially changing list of fields to keep up to date, as inline arrays can only have a single field.\nThus, we think the right solution is actually to just make it an error to apply `InlineArrayAttribute` on a `record struct`. If there is demand after making this change, we can always revisit at a later\ndate, but until then, we will leave this as an error.\n\n#### Conclusion\n\nApplying `InlineArrayAttribute` to a `record struct` will be an error.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-06-24.md",
    "content": "# C# Language Design Meeting for June 24th, 2024\n\n## Agenda\n\n- [First-Class Spans](#first-class-spans)\n- [`field` questions](#field-questions)\n    - [Mixing auto-accessors](#mixing-auto-accessors)\n    - [Nullability](#nullability)\n\n## Quote of the Day\n\n- Nothing particularly amusing was said today, sorry.\n\n## Discussion\n\n### First-Class Spans\n\nChampion issue: https://github.com/dotnet/csharplang/issues/7905  \nSpec link: https://github.com/dotnet/csharplang/blob/dd326f7fb0c282825ed1b2ffbe8180b6c54afa1c/proposals/first-class-span-types.md#conversion-from-type-vs-from-expression\n\nWe started today by looking at an open question in the first-class span feature. The question at hand is about a minor difficulty that the compiler team has run into while implementing the feature; by making\nthe conversion a conversion from type, rather from an expression, we've actually run into a novel scenario in the compiler. Currently, all the special-cased types that participate in conversions from the\ncore library itself (ie, the assembly that defines `System.Object`), not from other assemblies. This fact has led to some of the structure of the compiler around conversions. `(ReadOnly)Span`, on the other\nhand, may not come from core library, but may instead come from `System.Memory.dll`, or the user may define it themselves in source. This means we need to decide how the compiler finds the `(ReadOnly)Span`\ntype that considered for the conversions defined by this feature. We have a few options for this:\n\n1. Require that the `System.Span` and `System.ReadOnlySpan` considered for the feature come from the core library, like all other types that have special conversion rules.\n2. Restructure the compiler to plumb our existing logic for finding these types into the conversion logic.\n3. Simply match by the full name of the type.\n\nOption 2 is the most consistent with all the rest of the compiler's handling around `(ReadOnly)Span`, but we're also concerned about the investment cost here. It's potentially a big restructure; not impossible\nby any means, but it has a fairly low return-on-investment in the long term. Option 1 is the easiest to implement, but we're somewhat concerned about the inconsistencies, particularly with other features that\nwill allow the user to override `System.Span` with a type defined in source. Finally, option 3 is easier to implement than 2, and likely to be the most consistent with it. It's not perfect; in particular, it\nwill potentially apply to _all_ definitions of `System.(ReadOnly)Span`, regardless of what assembly they come from, while things like collection expression rules only apply to the canonical definition (regardless\nof whether that canonical definition comes from source, corelib, or `System.Memory.dll`). We think that, for 99.9% of users, this will result in identical behavior to 2. Given that, we think option 3 is the best\nbalance here.\n\n#### Conclusion\n\nWe will go with option 3, match `System.Span` and `System.ReadOnlySpan` by full name.\n\n### `field` questions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/140  \nQuestions: https://github.com/dotnet/csharplang/blob/dd326f7fb0c282825ed1b2ffbe8180b6c54afa1c/proposals/semi-auto-properties.md#open-ldm-questions\n\n#### Mixing auto-accessors\n\nThe first question up is a simple confirmation question. While the proposal has long included the ability to have one half of a semi-auto property be a `set;` or `get;`, we've never explicitly confirmed it\nin LDM. After a brief discussion, we confirmed that we do indeed want to be able to leave one half of a semi-auto property as an auto accessor.\n\n##### Conclusion\n\nConfirmed.\n\n#### Nullability\n\nThe next issue took up the rest of our time today, without reaching a final conclusion. Nullability of the backing field here is very tricky: we do almost no inter-procedural analysis of methods today\n(except for local functions), and it very much seems like we will need to do this type of analysis to get the nullability correct. There's also a lot of edge cases to consider, particularly around lazy\ninitialization. One thing that became very clear was that the proposed `[field: NotNull]` approach wasn't an acceptable tradeoff to the LDM. Nullability does make a lot of pragmatic cuts where it is possible\nto observe `null` values, such as arrays. However, we think that this isn't a place where we could accept that type of tradeoff; arrays are a local and obvious source of nulls. Lazy initialization through\nmultiple constructors or methods is hard to get right and much subtler to debug. We are somewhat concerned about having a magic solution though, especially given our experience with `var`. While there are no\nsafety holes introduced from our treatment of `var` as allowing null assignments, we do know that a non-zero percentage of our users are confused by the behavior; even if it's completely safe, there's a\nperception that the guardrail is too loose, and it causes these users to lose their trust of the feature. If we did fancy cross-method analysis for `field`, and allowed `null` assignments to the backing field\neven when it's provably perfectly safe, is that ok? Or will that confuse users and cause them to distrust the feature? We want to kick these questions back to a small group to noodle on, so we will leave\nthese for now and revisit in the near future.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-06-26.md",
    "content": "# C# Language Design Meeting for June 26th, 2024\n\n## Agenda\n\n- [Extensions](#extensions)\n\n## Quote of the Day\n\n- \"You only get one first impression, unless you're like me and you forget things all the time.\"\n\n## Discussion\n\n### Extensions\n\nChampion Issue: https://github.com/dotnet/csharplang/issues/5497  \nFormat proposal: https://github.com/dotnet/csharplang/pull/8242\n\nWe spent today looking over the proposed format for static member translation for extension types. The format discussion revolves around how much compatibility we want to maintain with existing extension\nmethods, and whether we want to force other languages to do explicit work to support them. There are two real extremes here:\n\n1. Completely require that non-C# languages must do work to support new extension types. This means putting `modreq`s on the types, or using `CompilerFeatureRequired`, to force compilers that don't understand\n   to pretend those members don't exist. This would ensure that we don't have to support any amount of back-compat work with new extensions, but also means that we'd rule out a migration story entirely.\n2. Fully support usage in other compilers in static form with no changes. This would possibly mean that C# would need to support calling these extensions in static form as well; if an older C# compiler could see\n   and understand these static members, and emit calls to them, then upgrading and not supporting calling in static form would be a breaking change. The advantage of this form would be compatibility with some\n   older extension methods, and permit upgrading older static classes to extension types, which is an attractive ability.\n\nAfter some discussion, we ended up pulling the extremes into separate parts; instance method extensions, and everything else. For everything else, LDM is strongly against allowing them to be called in static\nform by other languages unless they do the work to explicitly support that form. For instance methods (ie, `static void M(this int i)` methods today), we're very interested in allowing back-compat. This would\nmean a few concrete things for the proposal to go chase down:\n\n1. We would have to support calling these instance methods in both `instance.M()` and `E.M(instance)` form, since the latter is valid today for existing extension methods defined on a `static` type.\n2. There are some areas of extension type resolution that do not behave the same as extension method resolution today. Those areas will need to be overhauled.\n3. Signature uniqueness still needs to be explored. How would the `E.M(instance)` format behave when `E` has both `void M()` and `static void M(Instance i)` defined on it?\n\nWe want to take these questions back and look at how complicated they will be to solve before making a final decision on the migration story.\n\n#### Conclusion\n\nWe will block consumption in other languages without explicit support for extension types for all extension members except instance members. For instance members, we will explore making the emit binary-compatible,\nand how much we will have to overhaul to get that to work, then come back and make a final decision on whether to block consumption.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-07-15-usage-data.md",
    "content": "Building a large internal repo with `this.field/value` style of breaking changes had 100+ errors. Hit every variation of the diagnostic:\n- `field` as field\n- `value` as field\n- `this.that.value` in accessor\n\nExample:\n\n```csharp\npublic int Value\n{\n  get { return this.value; }\n  set\n  {\n    this.value = value;\n    this.valuePtr = &value;\n  }\n}\n```\n\nRandom repos found with GH queries\n- [this.value](https://github.com/search?q=%22this.value%22+language%3AC%23&type=repositories&l=C%23) 209K results, 20% hit rate of real bug through 2 pages\n    - https://github.com/DotNetAnalyzers/StyleCopAnalyzers\n    - https://github.com/VodeoGames/VodeoECS\n    - https://github.com/NeoforceControls/Neoforce-Mono\n    - https://github.com/askeladdk/aiedit\n    - https://github.com/YuhangGe/DLX-System\n    - https://github.com/GameDiffs/TheForest\n    - https://github.com/alexsteb/GuitarPro-to-Midi\n- [this.that.value](https://github.com/search?q=%2Fthis%5C.%5Ba-z%5D%2B%5C.value%2F+language%3AC%23&type=code) 106K results, 8% hit rate of real bug through 4 pages\n    - https://github.com/Real-Serious-Games/Unity-Editor-UI\n    - https://github.com/VeeamHub/SuperEdit\n    - https://github.com/moto2002/mobahero_src\n- [this.field](https://github.com/search?q=%22this.field%22+language%3AC%23&type=code) 41K results, 8% hit rate of real bugs through 3 pages\n    - https://github.com/HaloMods/Halo1AnimationEditor\n    - https://github.com/Team-COCONUT/Minotaur\n    - https://github.com/moto2002/mobahero_src\n    - https://github.com/Toskyuu/TPW\n    - https://github.com/graehu/SON\n\nI only dug in the first 4-5 pages for each query as I felt it was representative at that point. Possible I'm wrong but I doubt the numbers would change if we dug any deeper.\n\nMore GH queries:\n\n- [\\_field](https://github.com/search?q=%2F%28%5E%7C%5CW%29_field%28%24%7C%5CW%29%2F+language%3AC%23&type=code) as a field name. 6K results, near 100% hit rate\n- [\\_value](https://github.com/search?q=%2F%28%5E%7C%5CW%29_value%28%24%7C%5CW%29%2F+language%3AC%23&type=code) as a field name. 137K results, near 100% hit rate\n\nLargest intentional breaking change we've in last ~5 years was lambda inference and overload changes:\n- Had a very long lead and got plenty of preview feedback about it. \n- In total we had ~20-30 bugs filed against it.\n- That is number of customers who did not self correct. Let's assume for sake of argument that total number of users that hit this problem is 10x reported. So 200-300\n\nMy conclusions from data:\n\n1. Generated code is a challenge for our fixer\n2. `field` and `_field` are uncommon but not rare field names\n    - The use of `field/_field` is a style decision\n    - Breaking change is about the style in which it is declared and accessed: `this.field =` vs. `field =`\n3. `value` and `_value` are common field names\n    - The use of `value/_value` is a style decision\n    - Breaking change is about the style in which it is declared and accessed: `this.value` vs. `value =`\n4. Ratio of field:value virtually every query is 1:8-1:12\n5. Breaks on `this.value` or `this.field` are not viable \n    - In the range of 20K and 10K impacted GH samples\n    - That is roughly 2 orders of magnitude greater than the upper bound of our highest breaking change\n6. It is very hard to quantify what the breaks on naked field / value would be. \n    - Hard to construct a GH query to narrow down to uses of field / value without keywords. \n    - Metadata queries can't distinguish between this.field and simply field in an accessor \n \n"
  },
  {
    "path": "meetings/2024/LDM-2024-07-15.md",
    "content": "# C# Language Design Meeting for July 15th, 2024\n\n## Agenda\n\n- [`field` keyword](#field-keyword)\n- [First-Class Spans Open Question](#first-class-spans-open-question)\n\n## Quote of the Day\n\n- \"Obviously what the data means is that after we make `field` a keyword, usage of it as the name of a field will skyrocket, because that's what correlation means, right?\"\n\n## Discussion\n\n### `field` keyword\n\nChampion issue: https://github.com/dotnet/csharplang/issues/140  \nSpecification: https://github.com/dotnet/csharplang/blob/e44ebf7095e462ef5f9bbd869386a70cbd85e6d0/proposals/field-keyword.md#syntax-locations-for-keywords  \n[Usage data](LDM-2024-07-15-usage-data.md)\n\nWe started today by looking at real world usage data for `field` and `value` as keywords, to allow us to evaluate how breaking of a change we are looking at. Our current strategy, making both `field` and `value`\nkeywords within property accessors, even when used as a nested expression, turns out to be extremely breaking. Internal repos show hundreds of errors, with more waiting further in the build process; the errors stopped\nthe build in root projects, which would have to be fixed up to then allow the build to progress further. Surprisingly (to the LDM, at least), `value` is actually _more_ breaking than `field` is, and by a pretty big\norder of magnitude: our analyses find that, across various sources, `value` is used in a way that would break with this proposal 8-12 times more than `field` is. We're pretty concerned by the level of break here, even\nwith fixers, for a couple of reasons:\n\n* A decent amount of the break was in generated (either through a separate tool or through a Roslyn source generator) code. Even with a fixer, that generated code would likely just be overwritten the next time the\n  generator runs.\n* Our original supposition that, because `value` already has special meaning in property bodies it would be fairly simple to unify with `field`, turns out to be completely false.\n\nGiven these issues, we have a few proposals on how to deal with this, scaling back the break to have less of an impact:\n\n1. Accept the break, exactly as shown.\n2. Scale back the keyword recognition to only consider _primary\\_expressions_. For `value`, this fixes a lot of the errors; in Roslyn at least, it only results in a single build error, where `value` was used in a lambda\n   inside the getter body.\n3. 2, but separate out `value` entirely, and leave it alone. Just make the breaking change for `field`, and only in the _primary\\_expression_ scenario.\n\nTo tackle this question, we started by looking at the two separate parts: should we scope the break down, and should we remove any breaks on `value`? Our first pass here was maximally breaking, as we wanted to see how\nbad the reality actually would be. It turns out to be unacceptably breaking, so we are in strong agreement to scope down the break to just _primary\\_expressions_. Next, we took a second look at `value`. While scoping\ndown the break would eliminate a very large percentage of the real-world breaks that we see here, it wouldn't eliminate them; Roslyn itself would break, just as the very first example. Our breaking change philosophy\nwas that any breaking changes need to be well-motivated, and looking at the actual data in comparison to our original suppositions, we now think that we don't have enough motivation to take a change to `value`. Even\nthough changing `value` would make it more consistent with `field`, we don't think we have enough justification to make it worth it. Therefore, we go with option 3.\n\n#### Conclusion\n\n`field` will only be recognized as a keyword when used as a _primary\\_expression_ within an accessor body. Any changes to `value` will be removed from this proposal and its behavior will continue unaffected.\n\n### First-Class Spans Open Question\n\nChampion issue: https://github.com/dotnet/csharplang/issues/7905  \nSpecification: https://github.com/dotnet/csharplang/blob/4578db732a7d4aece52a07d1c822846b381f40b2/proposals/first-class-span-types.md#delegate-extension-receiver-break\n\nFinally today, we took a look at a potential breaking change that could be caused first-class spans, and the proposed mitigation for it. This is a somewhat complicated case: the main issue is that because method group\nresolution of an extension method called in extension form can actually apply a conversion to the receiver, that conversion could potentially be something that can't be boxed. This isn't really a problem today, because\nthe only conversions allowed here are identity, reference, or boxing conversions; these are all things that are already on the heap, so capturing the receiver into the method closure is perfectly fine. `Span`s, though,\ncannot be captured into the method group closure, so if there is ever a method group converted to a delegate type, and it uses a span conversion on the receiver, that _will_ be an error. Since these conversions can be\nprioritized, it means that currently valid code will become an error, particularly as the BCL adds new `Span`-taking overloads. Given the 100% error rate of the scenario, we are fine with adding a special rule to exclude\n`Span` conversions when doing method group overload resolution on an extension method called in extension form.\n\n#### Conclusion\n\nMitigation is approved.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-07-17.md",
    "content": "# C# Language Design Meeting for July 17th, 2024\n\n## Agenda\n\n- [Overload resolution priority open questions](#overload-resolution-priority-open-questions)\n- [Better conversion from collection expression with `ReadOnlySpan<T>` overloads](#better-conversion-from-collection-expression-with-readonlyspant-overloads)\n\n## Quote of the Day\n\n- \"I don't know what shortstop is\" \"It's Abbott and Costello!\" (proceeds to play Who's on First for the LDM during break)\n\n## Discussion\n\n### Overload resolution priority open questions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/7706  \nPR: https://github.com/dotnet/csharplang/pull/8296\n\nWe started today by looking at a couple of open questions for overload resolution priority, to confirm and/or revise implementation decisions made by the feature. First, we looked at whether\nto disallow the attribute on a few more locations. We'd [previously](LDM-2024-06-17.md#application-error-or-warning-on-overrides) decided that the attribute shouldn't be allowed in locations where\nit would be an error to apply it. A few more locations came up during implementation. The only one of these that had mild discussion was local functions. However, ultimately, we decided that the\nsimple and pragmatic solution is to just disallow the attribute on local functions; even though they go through overload resolution, they do not allow overloads, so the attribute will have no impact.\n\nNext, we looked at the desired behavior for language version. The proposal suggests 3 options for handling:\n\n1. Don't have the attribute do anything when `LangVersion` is set to < 12.\n2. Issue an error when the attribute impacts overload resolution behavior when `LangVersion` is set to < 12.\n3. Silently honor the attribute when `LangVersion` is set to < 12.\n\nOption 2 was discarded as a non-starter basically immediately, as it would block the runtime from adopting the feature. This leaves options 1 and 3. Option 1 better favors those who encounter the new\nfeature as they scout out new versions of VS for their coworkers, as it will ensure that new tooling versions continue to build their existing code exactly the same as it was. Option 3 better favors\nthose that upgrade to .NET 9, but keep themselves on C# 12 for the time being. After some discussion, we think that option 1 better serves the purpose of langversion, and will proceed with that approach.\n\n#### Conclusion\n\nWe will error on all 5 locations: conversion operators, lambdas, destructors, static constructors, and local functions. We will ignore the attribute when the compiler is set to language version 12 or less.\n\n### Better conversion from collection expression with `ReadOnlySpan<T>` overloads\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8297  \nRelated issue: https://github.com/dotnet/roslyn/issues/73857\n\nFinally today, we took a look at what we could do around collection expression conversions to handle some issues that the BCL will be running into when they ship .NET 9. New overloads of `string.Concat`\ncan break collection expressions because we don't have a betterness tiebreaker around `ReadOnlySpan<T>` vs `ReadOnlySpan<U>`, and first-class spans can't serve this gap because collection expressions have\na different preferred span type than the rest of the language.\n\nDiscussion in LDM showed a general reluctance to go with the narrow proposal, and we much preferred the version that applied better conversion from element recursively to solve this problem. That version\ngets us closer to unification with `params` collections and is more complete. While we do think this will be a problem in .NET 9, we're hopeful that we can use `OverloadResolutionPriorityAttribute` to solve\nthe BCL issues. We'll therefore take this back and verify that `OverloadResolutionPriorityAttribute` can solve this in a way that is acceptable; if it can't, then we can pick this back up and make a decision\non what to do here in the short term, or whether we should pull the methods from the BCL for .NET 9.\n\n#### Conclusion\n\nWe will look at `OverloadResolutionPriorityAttribute` to solve this for .NET 9, and then look at the more comprehensive better conversion approach for a future release.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-07-22-ref-struct-interface-examples.md",
    "content": "# ref struct interfaces\n\n[Proposal](https://github.com/dotnet/csharplang/blob/main/proposals/ref-struct-interfaces.md)\n\n## Questions\n\n1. Move forward with ref struct interfaces out of preview\n2. Do we want to introduce a warning in the DIM case?\n3. Do we want to limit the constraint language?\n\n## Concrete Usages\n\n### Needed for `ITensor<T>`\n\nThe tensor team wants to ship the following interface that is meant\n\n```csharp\ninterface ITensor<T>\n{\n    [UnscopedRef]\n    ReadOnlySpan<nint> Lengths { get; }\n}\n```\n\n### Comparer Interfaces\n\nThis is now used by the runtime in the [comparer][comparer] interfaces.\n\n```csharp\npublic static int BinarySearch<T, TComparer>(this System.ReadOnlySpan<T> span, T value, TComparer comparer)\n    where TComparer : System.Collections.Generic.IComparer<T>, allows ref struct;\n\npublic static int BinarySearch<T, TComparable>(this System.ReadOnlySpan<T> span, TComparable comparable)\n    where TComparable : System.IComparable<T>, allows ref struct;\n```\n\n\n[comparer]: https://github.com/dotnet/runtime/pull/103604\n\n### Enumerator\n\nRuntime wants to have existing `ref struct` based enumerators inherit `IEnumerator<T>`\n\n### Math interfaces \n\nRuntime is considering them for the math related interfaces:\n\n- `IAdditionOperators`\n- `IParsable`\n- `ISpanParsable`\n- `IUtf8SpanParsable`\n\n### Customer Scenarios\n\n- [U8String project](https://github.com/dotnet/csharplang/discussions/8211#discussioncomment-9883809) alows for unification\n- [Asset Ripper](https://github.com/AssetRipper/AssetRipper.Text.Html) makes [heavy use](https://github.com/AssetRipper/AssetRipper.Text.Html/pull/1/files) of this already\n\n\n## Warn on DIM case?\n\nThe runtime doesn't, and never will, support calling a default implemented member (DIM) when the receiver type is a `ref struct`. The  compiler will require that a `ref struct` implement all members. Could also choose to warn at the point the code invites this problem if we wanted to. \n\n\n```csharp\ninterface I1\n{\n    // Virtual method with default implementation\n    void M() { }\n}\n\n// Invocation of a virtual instance method with default implementation in a generic method that has the `allows ref struct`\n// anti-constraint\nvoid M<T>(T p)\n    where T : allows ref struct, I1\n{\n    p.M(); // Warn?\n}\n```\n\n## Limit Constraint Language?\n\nThe language allows for us to do this today\n\n```csharp\nvoid M<T>(T t) where T : IDisposable, allows ref struct { }\n```\n\nThat is strange if there is no way `T` can be `ref struct` but not also implement interfaces\n"
  },
  {
    "path": "meetings/2024/LDM-2024-07-22.md",
    "content": "# C# Language Design Meeting for July 22n, 2024\n\n## Agenda\n\n- [Extensions](#extensions)\n- [Ref structs implementing interfaces](#ref-structs-implementing-interfaces)\n\n## Quote of the Day\n\n- \"A catscade of errors\"\n\n## Discussion\n\n### Extensions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/5497  \nSpec change: https://github.com/dotnet/csharplang/pull/8305\n\nWe started today by looking at the latest proposed changes for extensions. There was no real pushback on the string-based encoding erasure form, but we did bring up some concerns that may need to be addressed:\n\n* How will the format work for local functions?\n* We don't think that function pointers are necessary to support right now; extensions already have limited interactions with pointer types in general. If we can come up with specific scenarios, we could look\n  at them at that point.\n* We talked briefly about simply upgrading the `Type` format to allow encoding type parameters. However, that runs into the issue that the extension types would not satisfy type constraints. Any solution that involves concrete\n  `Type` instances would likely break reflection in some way.\n* We also briefly discussed whether we need to invest in a way to shrink the amount of metadata we emit. For now, we don't think we need to. The concern with nullable was that every member across an entire project\n  would implicitly get new attributes. We're nowhere near that level here.\n\nOverall, the encoding format here is generally approved.\n\n### Ref structs implementing interfaces\n\nChampion issue: https://github.com/dotnet/csharplang/issues/7608  \nRelated: [Ref struct interfaces examples](LDM-2024-07-22-ref-struct-interface-examples.md)\n\nFinally today, we are following up on a [previous meeting](LDM-2024-06-10.md#ref-structs-implementing-interfaces-and-in-generics) where we asked for examples of using `ref struct`s in interfaces that we could\nuse as validation that the feature was designed and working as we hoped. We received a number of examples, and we'd like to thank all the readers of these notes who responded. There were a few examples in particular\nthat proved especially helpful, and they're called out in the linked examples file. Given these examples, we're happy with the feature at this point, and are ready to ship it for C# 13. We then took another look\nat the DIM scenario for `ref struct`s, and whether we should consider a warning at the call site. We don't think that this is generally beneficial; the consumer doesn't really have an option for avoiding it, and we\ncan't catch all instances where this would happen. Instead, we think the onus is on the person who is implementing an interface on a `ref struct`; if the `interface` is updated, the implementor needs to go\nrecompile with the new interface member and publish a new version.\n\n#### Conclusion\n\nWe are comfortable with shipping `ref struct`s implementing interfaces, and we will not warn on calling an interface member that has a DIM.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-07-24.md",
    "content": "# C# Language Design Meeting for July 24th, 2024\n\n## Agenda\n\n- [Discriminated Unions](#discriminated-unions)\n- [Better conversion from collection expression with `ReadOnlySpan<T>` overloads](#better-conversion-from-collection-expression-with-readonlyspant-overloads)\n\n## Quote of the Day\n\n- \"I put that there so people will complain\"\n\n## Discussion\n\n### Discriminated Unions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/113  \nProposal: https://github.com/dotnet/csharplang/blob/18a527bcc1f0bdaf542d8b9a189c50068615b439/proposals/TypeUnions.md\n\nFirst up today, the discriminated unions working group presented the proposal they've been working on for a while to the broader LDM. This was a broad overview session, rather than a deep dive into nitty-gritty\nquestions; there are still plenty of little details that will need to be filled in, but we're cautiously optimistic about this proposal and moving forward with it. There was some concern about some of the\nternary behavior, but we can dig more into that as we bring this proposal back for detailed follow ups in the future.\n\n### Better conversion from collection expression with `ReadOnlySpan<T>` overloads\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8297  \nRelated issue: https://github.com/dotnet/roslyn/issues/73857\n\nWe followed up from [last Wednesday](LDM-2024-07-17.md#better-conversion-from-collection-expression-with-readonlyspant-overloads), revisiting an even narrower proposal; just looking at implicit reference\nconversions, rather than all implicit conversions except numeric conversions. However, LDM still does not prefer the narrow fix; it has edge cases and isn't generalizable. There is some concern that rules around\n`OverloadResolutionPriority` might not work here; `string.Concat` has 15 overloads in .NET 9, and this isn't the type of break-glass scenario `OverloadResolutionPriority` was designed for. Given this, we reaffirm\nthat we want to look into doing the recursive approach, ie better conversion from element.\n\n#### Conclusion\n\nContinue looking into option 3, better conversion from element.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-08-14.md",
    "content": "# C# Language Design Meeting for August 14th, 2024\n\n## Agenda\n\n- [`field` keyword](#field-keyword)\n    - [`field` nullability](#field-nullability)\n    - [`field` in event accessor](#field-in-event-accessor)\n    - [Scenarios similar to `set;`](#scenarios-similar-to-set)\n\n## Quote of the Day\n\n- \"That feels a bit like letting the wolf into the hen house.\"\n\n## Discussion\n\n### `field` keyword\n\nChampion issue: https://github.com/dotnet/csharplang/issues/140  \nSpec: https://github.com/dotnet/csharplang/blob/d80d82e87e26412c2f5f3ef55c5253f474ad5049/proposals/field-keyword.md\n\n#### `field` nullability\n\nNullability proposal: https://github.com/dotnet/csharplang/issues/8360\n\nToday, we discussed a proposal for how nullable reference types could be handled for `field`. This proposal has a decent amount of magic in it, defining a new concept of \"null-resilient getters\", and\nusing that to determine whether the backing field should be considered nullable if it is not a value type. We have somewhat mixed feelings on this. The user code is ultimately something we think is\nreasonable: `string Prop { get => field ??= \"\"; }` is a perfectly reasonable property definition. However, this is effectively a narrow case of the different backing field question, proposal\nhttps://github.com/dotnet/csharplang/issues/133. The LDM has also expressed interest in that proposal, so the question we need to resolve is: does the nullability proposal move the cliff far enough to\nwarrant including the language? It certainly can't handle anything related to nullable value types, or anything related to `Lazy<T>` initialization. It will handle lazy initialization using `??=` or\n`Interlocked.CompareExchange`, but the latter pattern is certainly not common outside of a few specific codebases. After discussion on this point, we have a slight lean towards nullability as proposed\nin 8360, but this is a smaller LDM session and we don't feel that we have the unity to make a final call today. We'll let this ruminate in our brains for the weekend and then come back next week to\nmake a final decision.\n\n##### Conclusion\n\nNo conclusion today. Will revisit next week.\n\n#### `field` in event accessor\n\nQuestion: https://github.com/dotnet/csharplang/blob/d80d82e87e26412c2f5f3ef55c5253f474ad5049/proposals/field-keyword.md#field-in-event-accessor\n\nWe next looked at whether we can scope `field` down to not being usable in `event`s. We don't see a use case; generally speaking, either the standard field-like events are sufficient, or the user\nwill want some kind of separate backing field, like a `List<Action>`, to store all the delegates so they can do something with them, rather than using `MulticastDelegate`. Absent scenarios, we\nwill not allow this.\n\n##### Conclusion\n\nDisallowed.\n\n#### Scenarios similar to `set;`\n\nhttps://github.com/dotnet/csharplang/blob/d80d82e87e26412c2f5f3ef55c5253f474ad5049/proposals/field-keyword.md#scenarios-similar-to--set-\n\nFinally today, we considered whether to disallow scenarios that are _similar_ to, but not exactly, `{ set; }`. After some brief discussion, we think that we should keep with the status quo, and\nonly disallow `set;`-only properties. We don't want to try and get into the business of recognizing when a property does or does not have side-effects in the general case; it's either `set;`, which\nis trivially vacuous, or it's something else, and we'll let the user do what they want.\n\n##### Conclusion\n\nWe will keep the status quo: auto-`set;`-only properties are disallowed. Anything else is fair game.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-08-19.md",
    "content": "# C# Language Design Meeting for August 19th, 2024\n\n## Agenda\n\n- [Better conversion from collection expression](#better-conversion-from-collection-expression)\n\n## Quote of the Day\n\n- \"So you're saying that element type is more equal than collection type?\"\n\n## Discussion\n\n### Better conversion from collection expression\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8374  \nSpecification: https://github.com/dotnet/csharplang/blob/915dce8cd2a87a390904044ddada2d0794a15a24/proposals/collection-expressions-better-conversion.md\n\nToday, we followed up from the [last time](LDM-2024-07-24.md#better-conversion-from-collection-expression-with-readonlyspant-overloads) we discussed collection expressions. This is a matter\nwith some urgency, as we want to try and solve the `ReadOnlySpan<string>` vs `ReadOnlySpan<object>` issue before .NET 9 ships. To do this, we looked at a proposal for introducing a new algorithm\nfor better conversion from expression, as it applies to collection expressions. The proposal tries to stick close to one of our\n[previous principles](../2023/LDM-2023-09-20.md#overload-resolution-fallbacks) around collection expressions, which is that we didn't want to get pulled in opposite directions from the collection\ntype and the element type. To do this, and still enable disambiguation between `List<int>` and `List<byte>`, or other similar scenarios, we had to introduce a new concept around collection type\ncomparison, without type arguments. This concept is new to the language, and there is some amount of spec work that needs to be done on it. However, further discussion led us to question something\nlarger: the entire principle we previously stated, where we said we wanted scenarios like `IEnumerable<int>` and `List<object>` to produce an ambiguity error. This principle was based around the\nidea that with collection expressions, both the type of the collection itself, as well as the type of the elements, are equal in priority. On further reflection, we're not sure this is actually\ntrue. The collection expression doesn't have a type, and even when we eventually add a natural type, target-typing will always win, just like it does with switch expressions. On the other hand,\nthe elements _do_ have natural types, and those natural types can say a lot. Given `[1, 2, 3]`, we've come around to the idea that `IEnumerable<int>` is better than `List<object>`, based purely\non element type. This radically changes our thoughts on the direction this proposal needs to move; we'll come back next LDM with an updated proposal that takes this changed principle in mind,\nprioritizing collection element type betterness over the collection type itself.\n\n#### Conclusion\n\nWe will revisit an adjusted proposal that prioritizes element type over collection type betterness.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-08-21.md",
    "content": "# C# Language Design Meeting for August 21st, 2024\n\n## Agenda\n\n- [Better conversion from collection expression](#better-conversion-from-collection-expression)\n- [`field` keyword nullability](#field-keyword-nullability)\n\n## Quote of the Day\n\n- \"We can get rid of that whole T' business\" \"But you like tea!\" \"No, we still have T, we just don't have T'\"\n\n## Discussion\n\n### Better conversion from collection expression\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8374  \nSpecification: https://github.com/dotnet/csharplang/blob/24aac29f7af589f5aa6242629642821df4cea422/proposals/collection-expressions-better-conversion.md\n\nFollowing up from [last time](LDM-2024-08-19.md#better-conversion-from-collection-expression), we brought back the proposal with the requested tweaks for review by the LDM. The overall\nproposal is what we expected to see, and we will move forward with it.\n\nWith that out of the way, we then looked at the open question around how much we should prefer span types over other types. The existing wording of the rule, as shipped in C# 12, also makes\n`ReadOnlySpan<T>`/`Span<T>` vs `List<T>` ambiguous, which is strong motivation for us to not solve that here; we have heard lots of feedback around the various aspects of collection expressions\nthat we needed to adjust, and this ambiguity has not come up among them. Further, given that this is ambiguity, it is an area that we will able to adjust in the future if we hear more feedback\naround it, as we've done when we've adjusted other ambiguity rules in the past with betterness, better betterness, and bestest betterness. Additionally, API authors that have such an ambiguity\ncan make their APIs usable via `OverloadResolutionPriorityAttribute` in C# 13, by prioritizing the `ReadOnlySpan`/`Span` variant. Given this, we feel comfortable with the specification as written.\n\n#### Conclusion\n\nSpecification is accepted as written.\n\n### `field` keyword nullability\n\nChampion issue: https://github.com/dotnet/csharplang/issues/140  \nSpec: https://github.com/dotnet/csharplang/blob/d80d82e87e26412c2f5f3ef55c5253f474ad5049/proposals/field-keyword.md  \nNullability proposal: https://github.com/dotnet/csharplang/issues/8360\n\nFinally today, we took another look at the proposal for making the `field` keyword handle nullability automatically. Last time, we were leaning towards adopting the proposal, but hadn't quite\ndeveloped the unity we need to adopt the proposal, so we spent today talking through our reasoning more. The arguments are very similar to last time: is there too much magic going on here, or\nis this something that users will expect to just work? One important argument that came up during this was a thought experiment to reorder `field` and nullable-reference types as features: if\nwe presume that `field` had existed before we did NRT, it would be nearly certain that this code would have existed. One goal of NRT was to allow perfectly safe and idiomatic code to continue\nexisting exactly as it had before with a minimal amount of changes. After more discussion on this point, we decided to move forward with the proposal, but will still need to dig into some of\nthe details. In particular, the tradeoff between \"getters with no nullability warnings\" or \"getters that have _more_ nullability warnings than when `field` starts as null\"; this is the\ndifference between having a `string unrelated = null;` in the getter or not. We'll need to think through how complex we want to make our rules here; simpler rules are easier to explain, but\nthey might also still cause some confusion. We'll consider these details again in a future LDM.\n\n#### Conclusion\n\nGeneral proposal is adopted. Specific behavior still needs more review.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-08-26.md",
    "content": "# C# Language Design Meeting for August 26th, 2024\n\n## Agenda\n\n- [`field` keyword open questions](#field-keyword-open-questions)\n    - [`field` in property initializers](#field-in-property-initializers)\n    - [Interaction with partial properties](#interaction-with-partial-properties)\n    - [`readonly` field](#readonly-field)\n\n## Quote of the Day\n\n- \"Whenever I want to thumbs up, I see the open hand and I click it\"\n\n## Discussion\n\n### `field` keyword open questions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/140  \nSpec: https://github.com/dotnet/csharplang/blob/ce7bd40ee26432ba085c5ba9d8ad3be6d4f7fa9a/proposals/field-keyword.md#open-ldm-questions\n\n#### `field` in property initializers\n\nhttps://github.com/dotnet/csharplang/blob/ce7bd40ee26432ba085c5ba9d8ad3be6d4f7fa9a/proposals/field-keyword.md#field-in-property-initializer\n\nWe started by looking at whether `field` should be visible in the property initializer. This would diverge in behavior from how `this` is generally inaccessible in accessors,\nand most of our debate centered not around whether we should disallow this, but whether we should have a specific error if the user does try to do this. Ultimately, we decided\nto let the compiler implementation decide whether to have a specific error, but to otherwise not adjust the behavior. If there is an actual class field named `field`, then it\nwill be visible in the initializer (and potentially be an error to reference); in all cases, the synthesized backing field of the property will not be visible.\n\n##### Conclusion\n\nWe will bind the initializer as in previous versions of C#. We won't put the backing field in scope, nor will we prevent referencing other members named `field`.\n\n#### Interaction with partial properties\n\nhttps://github.com/dotnet/csharplang/blob/ce7bd40ee26432ba085c5ba9d8ad3be6d4f7fa9a/proposals/field-keyword.md#interaction-with-partial-properties\n\nNext, we thought about how partial properties and `field` should interact. There's two main interactions to consider: where to allow initializers, and whether to allow auto-implemented\naccessors in the implementation side of the property.\n\nFor the first question, we considered the use cases for partial `field`-backed properties. We foresee most of these properties being used by source generators, in one of two possible ways:\n\n1. A hint to a source generator (likely combined with an attribute) that the generator should implement the body of this property.\n2. A hint from a source generator to the user that the machinery of the generator requires the user to write a property; using a partial property here would give the user a better\n   error than \"undefined member `Name`\", and convey to the user the shape of what they need to implement.\n\nIn both scenarios, it is useful for the user to be able to put an initializer on the property to indicate what the backing field should be initialized to. We are also in agreement\nthat we don't want to try and allow putting the initializer in both locations, even if it is semantically identical; attempting to determine whether the initializers are identical\nis difficult for both the compiler and a human reading the code. Thus, we conclude that initializers will be allowed on either the declaration or the implementation, but not both\nat the same time.\n\nFor the second question, we again thought about our example scenarios; the scenarios are generally locations where one or both of the accessors can't just be a simple auto-accessor.\nThey need to have some kind of side effect, such as triggering an INPC notification, logging, etc. However, we _do_ think that the \"only one accessor is complex\" scenario is common\nenough to allow one of the implementing accessors to be an auto-implemented accessor. Allowing both accessors to be automatically implemented is not currently on the table, as it's\ncomplex for the compiler to implement and we don't have any scenarios to drive the design.\n\n##### Conclusion\n\nEither declaring or implementing property locations can use an initializer, but not both at the same time. At least one implementing accessor must be manually implemented, but the\nother accessor can be automatically implemented.\n\n#### `readonly` field\n\nhttps://github.com/dotnet/csharplang/blob/ce7bd40ee26432ba085c5ba9d8ad3be6d4f7fa9a/proposals/field-keyword.md#readonly-field\n\nOur final question today is around the `readonly`ness of the backing field. This is mostly unobservable; reflection can see it, but it doesn't have a real impact on user code. Given\nthe lack of observability, we think the right decision is to rely on the containing context; if the containing type or property is `readonly`, then the backing field will be too.\nPractically, this means that when the containing type is a `struct`, and either it or the property is marked `readonly`, then the synthesized backing field will also be `readonly`.\n\n##### Conclusion\n\nWhen the containing type is a `struct`, and either it or the property is marked `readonly`, then the synthesized backing field will also be `readonly`.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-08-28.md",
    "content": "# C# Language Design Meeting for August 28th, 2024\n\n## Agenda\n\n- [Nullable in `ref` ternaries](#nullable-in-ref-ternaries)\n- [Block-bodied switch expression arms](#block-bodied-switch-expression-arms)\n\n## Quote of the Day\n\n- \"I want to go meta meta for a second\"\n\n## Discussion\n\n### Nullable in `ref` ternaries\n\nIssue: https://github.com/dotnet/csharplang/issues/8379\n\nFirst up today, we looked at an issue that was originally raised as a Roslyn bug; nullable suppression of `ref` ternaries didn't work as expected. In fixing this bug, our testing showed\nthat the experience was not very polished overall, and should be revisited to be more consistent. One important note about this is that the original bug _is_ a compiler bug; a nullable\nwarning was being reported, but it couldn't be suppressed. However, we think this is a good opportunity to align `ref` ternaries with both regular ternaries, and method argument behavior.\nGiven that, we decided to go with option 1: use best common type and type inference.\n\n#### Conclusion\n\nGo with proposed option 1, using best common type and type inference.\n\n### Block-bodied switch expression arms\n\nChampion issue: https://github.com/dotnet/csharplang/issues/3037  \nRelated issue: https://github.com/dotnet/csharplang/issues/3086\n\nFinally today, we took a look at an older issue that occasionally comes up, to see if we wanted to make any more progress on it in the nearer term. Switch expression arms, and by extension\nany expression location, occasionally want to have side-effects. These often force users to fall back to much more verbose patterns; moving to a switch statement, rewriting an expression\ninto a series of multiple statements, etc. While the specific issue we discussed today is only for switch expressions, it really is a backdoor to the whole space, as we need to design far\nenough ahead to know how the whole space would work. Otherwise, we'd risk ending up in a space where we have diverging statement-within-expression syntaxes, which is something we absolutely\nwant to avoid. Ultimately, the LDM is very much in favor of continuing to explore this space, but we're far less unified on the specifics. We discussed a few different possible syntaxes for\nthe \"produce a value from this expression block\":\n\n* `break value` - as in the proposal. This has some advantages in not being legal syntax today, but some members are concerned about the confusion it could bring if you mix `break`, `break value`,\n  and `continue`. There's also some concern that it is not intuitive as to what is actually happening.\n* `return value` - an alternate option that would make `return` mean something different when in an expression block. Some members mentally model expression blocks as lambda expressions that\n  are immediately invoked, and this interpretation naturally complements this. However, other members are concerned that it implies that the user will leave the method, not the containing\n  expression block, and that it would also block the ability to actually do just that.\n* `out value` - like `break`, this has the advantage of not being legal syntax today in the locations you'd use it. But, like with break, there's concern about how understandable of a keyword\n  it is.\n* No keyword - As in https://github.com/dotnet/csharplang/issues/3086, we could also just leave the last `;` off a statement and have that be what the block evaluates to. There's some compelling\n  examples of this in the real world already, such as Rust or F# (F#'s `|> ignore` is the equivalent of a more obvious `;` in this case). But there's some concern about the subtlety of this,\n  and whether it would force users to write expression blocks in a particular pattern; how might a user produce a value from the middle of a `foreach` if they found the value they're looking\n  for, for example.\n\nUltimately, we are far too fractured, and talking about too many hypotheticals, to make a decision today. We need to go back and do more research; look at other languages that have concepts like\nthis and see what they do, how their solutions might apply to C#, and come up with sets of examples around it to inform our decision making.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-09-04.md",
    "content": "# C# Language Design Meeting for September 4th, 2024\n\n## Agenda\n\n- [Triage (no milestone)](#triage-no-milestone)\n    - [Type inference using method group natural type](#type-inference-using-method-group-natural-type)\n    - [Collection Expressions Next (C#13 and beyond)](#collection-expressions-next-c13-and-beyond)\n    - [Dictionary expressions](#dictionary-expressions)\n    - [Extending patterns to \"as\"](#extending-patterns-to-as)\n    - [`params in` parameters](#params-in-parameters)\n- [Triage (working set)](#triage-working-set)\n    - [Only Allow Lexical Keywords in the Language](#only-allow-lexical-keywords-in-the-language)\n    - [Permit variable declarations under disjunctive patterns](#permit-variable-declarations-under-disjunctive-patterns)\n    - [CallerCharacterNumberAttribute](#callercharacternumberattribute)\n    - [`Task<T>` nullability covariance](#taskt-nullability-covariance)\n    - [Nullable analysis of LINQ queries](#nullable-analysis-of-linq-queries)\n\n## Quote of the Day\n\n- \"The power I have is that I get to interpret\"\n\n## Discussion\n\n### Triage (no milestone)\n\nToday we triaged our championed issues without milestones, and started going through our working set.\n\n#### Type inference using method group natural type\n\nIssue: https://github.com/dotnet/csharplang/issues/7687\n\nWe need to investigate and make sure we didn't intentionally not do this in C# 10. Once we figure that out, we think it can to into Any Time. Until then, Needs More Work.\n\n#### Collection Expressions Next (C#13 and beyond)\n\nIssue: https://github.com/dotnet/csharplang/issues/7913\n\nThis is an epic tracking multiple smaller improvements, and the champion is currently on vacation so we can't talk through all the individual things. We'll come back when the issue\nchampion is back from vacation.\n\n#### Dictionary expressions\n\nIssue: https://github.com/dotnet/csharplang/issues/7822\n\nWe've actively worked on this in the past year and continue to think about it. Working set.\n\n#### Extending patterns to \"as\"\n\nIssue: https://github.com/dotnet/csharplang/issues/8210\n\nWe don't like that this would collapse the success and failure branches of an `is` into _null_ and _not null_, that would then need to be checked again to actually use the value; part\nof the point of `is` is to get rid of that type of code. We think the expanded versions of the examples are more readable. This proposal is rejected.\n\n#### `params in` parameters\n\nIssue: https://github.com/dotnet/csharplang/issues/8301\n\nThere's some interesting design work here around `ref struct`s that would push us to further expand our lifetime tracking, but we're not sure that this issue, by itself, would meet\nthe bar of doing that work. We don't think that it's a bad idea to add, particularly if we start by blocking `ref struct`s from participating, so we'll put this in the working set.\n\n### Triage (working set)\n\nNext, we started going through our working set issues to see if there's anything we should pull out. We didn't get through the whole thing; we stopped after 3590. The notes below\nonly include issues that we decided to change something about.\n\n#### Only Allow Lexical Keywords in the Language\n\nIssue: https://github.com/dotnet/csharplang/issues/4460\n\nThis issue was a forcing function to get us to think about breaking changes. We've thought about breaking changes, and our approach to `field`, while breaking, is significantly less\nbreaking than this issue proposes. We may pull it out of our back pocket in a future release where we're more comfortable with breaking changes in general, but until then, this is\nmoved to the backlog.\n\n#### Permit variable declarations under disjunctive patterns\n\nIssue: https://github.com/dotnet/csharplang/issues/4018\n\nWe do still want this feature, but aren't doing any active design work on it right now. Therefore, we'll move it to the backlog.\n\n#### CallerCharacterNumberAttribute\n\nIssue: https://github.com/dotnet/csharplang/issues/3992\n\nThis was a proposal for how we might implement interceptors. We don't plan on doing this, this proposal is rejected.\n\n#### `Task<T>` nullability covariance\n\nIssue: https://github.com/dotnet/csharplang/issues/3950\n\nWe do still want this feature, but aren't doing any active design work on it right now. Therefore, we'll move it to the backlog.\n\n#### Nullable analysis of LINQ queries\n\nIssue: https://github.com/dotnet/csharplang/issues/3951\n\nWe do still want this feature, but aren't doing any active design work on it right now. Therefore, we'll move it to the backlog.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-09-11.md",
    "content": "# C# Language Design Meeting for September 11th, 2024\n\n## Agenda\n\n- [Better conversion from collection expression and `params` collections](#better-conversion-from-collection-expression-and-params-collections)\n- [First-class span types](#first-class-span-types)\n    - [`Reverse`](#reverse)\n    - [New ambiguities](#new-ambiguities)\n    - [Covariant arrays](#covariant-arrays)\n\n## Quote of the Day\n\n- \"I think I have the record for how many times my brain stumbled on this today.\"\n\n## Discussion\n\n### Better conversion from collection expression and `params` collections\n\nChampion issues: https://github.com/dotnet/csharplang/issues/8374, https://github.com/dotnet/csharplang/issues/7700  \nSpec change: https://github.com/dotnet/csharplang/pull/8393\n\nWe started today by looking at an explicit consequence of our better conversion from collection expression changes and ensuring that we were ok with it. In our view of element type being the most important thing,\nthis is a natural consequence and we're ok with it. We're also ok with how it aligns more with how `params` arrays has always worked; for example, `params int[]` has always been ambiguous with `params int?[]`\nwhen called with 0 elements, and this lines up with that behavior. We also looked at the proposed change to `params` collections. This is also in the name of consistency; we want to make the rules for the new\nfeature consistent with the new rules for the old feature. All together, these changes bring everything together with near-complete consistency, which we strongly like.\n\n#### Conclusion\n\nProposed rules are adopted.\n\n### First-class span types\n\nChampion issue: https://github.com/dotnet/csharplang/issues/7905\n\nFinally today, we went over some possible breaking changes that will be caused by first-class spans. We knew going into this that there would be breaking changes, so that we have them isn't a surprise, but in\nthe name of due diligence we want to go through them and make sure that we're comfortable with them.\n\n#### `Reverse`\n\nhttps://github.com/dotnet/csharplang/blob/38c28b88c3e9ea9fb076b39c8d204f2b189b6796/proposals/first-class-span-types.md#calling-reverse-on-an-array\n\nThe word `Reverse` is unfortunately too useful; it's both in `LINQ`, as \"Please give me a stream that is the reverse of my input stream\", as well as in `MemoryExtensions` as \"Please in-place reverse this `Span`\".\nCurrently, only the former thing is applicable. After this feature, both will be applicable, and the `Span` version will win. There is a workaround for the BCL (add `Reverse(array)` to `Enumerable`), which we\nexpect them to do to address this break. Ultimately, we're ok with this break; it's the way that we'd have wanted it to be in the first place, and the overall likelihood that there are identically named methods\nwith different semantics is pretty low, as that usually breaks the guidance in the API design guidelines: https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/member-overloading.\n\n#### New ambiguities\n\nhttps://github.com/dotnet/csharplang/blob/38c28b88c3e9ea9fb076b39c8d204f2b189b6796/proposals/first-class-span-types.md#ambiguities\n\nFor this case (which arises in assert methods like `Assert.Equals` in xUnit, NUnit, and MSTest), it's a bit unfortunate, but there are also several options available to API authors. In many ways, this is simply\na historical design artifact of the lack of `ReadOnlySpan` and the lack of this conversion in the first place: if these APIs were to be rewritten just with this feature, then they could just have exposed `ReadOnlySpan`\noverloads and been done with it. We see two possible avenues for these APIs:\n\n* Apply `OverloadResolutionPriority(-1)` to their array-based overloads, so everything goes through `ReadOnlySpan`.\n* Expose an `Assert.Equals<T>(ReadOnlySpan<T> expected, T[] actual)`, which will be preferred for `Assert.Equals([1, 2], somethingThatIsAnArray)`.\n\n#### Covariant arrays\n\nhttps://github.com/dotnet/csharplang/blob/38c28b88c3e9ea9fb076b39c8d204f2b189b6796/proposals/first-class-span-types.md#covariant-arrays\n\nCovariant arrays, our favorite feature, strikes again. However, we're unsure that this is a real case that users will hit. We'll certainly document it, but this particular code example came from our unit tests,\nwhich aren't always reflective of real things users will write. Given this, we're also ok with this break.\n\n#### Conclusion\n\nWe accept all of these breaks.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-09-18.md",
    "content": "# C# Language Design Meeting for September 18th, 2024\n\n## Agenda\n\n- [Nullability in `field`](#nullability-in-field)\n- [Extensions naming](#extensions-naming)\n\n## Quote of the Day\n\n- \"Rename roles to frijoles\"\n\n## Discussion\n\n### Nullability in `field`\n\nChampion issue: https://github.com/dotnet/csharplang/issues/140  \nDiscussed proposal: https://github.com/dotnet/csharplang/issues/8425\n\nWe started today by looking at how we're going to deliver nullability rules for the `field` preview that ships in November with .NET 9. While we still want a full inference system,\nwe don't think that we reasonably have time to implement it before the first preview goes out. Therefore, we need to plan what our initial preview will ship with for options. We\nhave:\n\n1. No special support. To suppress nullability warnings, `= null!;` will be required.\n2. Support for the nullability attributes with the `field` attribute target, allowing a user to mark the backing field as `[field: MaybeNull, AllowNull]`.\n3. Leave the backing field oblivious, and do not report nullability warnings on it for now.\n\nAfter some discussion, we like option 2. Both option 1 and 2 do leave some cruft for the user to clean up after we have inference, but option 1 leaves the code in a potentially unsafe\nstate; option 2 is planned to be supported in the inference scenario anyways, and it leaves the user's code in a safe state. Option 3 doesn't leave any cruft, but it does mean that\nusers will be operating in a null-unsafe state before they get the new warnings.\n\n#### Conclusion\n\nWe will attempt to ship option 2, support for `field`-targeted nullability attributes. If we do not have enough runway however, we will end up shipping 1 by pure virtue of it requiring\nno additional compiler work.\n\n### Extensions naming\n\nChampion issue: https://github.com/dotnet/csharplang/issues/5497\nRename proposal: https://github.com/dotnet/csharplang/blob/1e8255a438517bc3ad067c726c28cfa20cb60f1e/meetings/working-groups/extensions/rename-to-roles-and-extensions.md\n\nFinally today, we are reopening the topic of naming for the feature that has alternately been known as \"shapes\", \"roles & extensions\", and now \"extensions\". When we\n[previously settled](../2023/LDM-2023-02-22.md#extensions) on the `implicit extension` and `explicit extension`, we felt that we'd reached a breakthrough; this was a name and category\nsystem that jibed well with the LDT, and we felt it added clarity and would help explain this feature to customers. However, now that we've had a year and a half to use this name with\nthe broader C# community, we no longer feel that this connection adds clarity to the feature; most of us feel that some kind of different noun for `explicit extension` would be better.\nOne example where some of us find issue: naming conventions for these types. Many existing `static class`es that are used for extension methods are named something like `ArrayExtensions`,\nand while such a convention works just fine for `implicit extension` types, we're not convinced that would work well for `explicit extension`s; we think of those as something like `Person`,\nnot `JsonObjectPersonExtension` or the like. And by tying these features to the same noun, we then imply that these naming conventions _should_ be related. These types of ties continue\nthroughout the feature, and a read of the room after this discussion was particularly telling; the vast majority of the LDT thought that separate nouns was the correct path. A couple of\nmembers were unsure, and no one was convinced that a single noun + modifier was the correct path forward. Given this, we will plan on going back to separate nouns. Of course, that\nthen immediately opened the floor for which noun to use. We're not ready to make decisions on nouns today, but we did brainstorm a list to do some initial preferencing:\n\n* `role` - The original proposal. We like that it's clear that the underlying object is assuming a \"role\"; it's all it was before, but more specific. Some members do have a gut feeling\n  that there's something wrong with it, but haven't yet been able to put it into words.\n* `adapter` - Lots of initial dislike for this one. Adapter as a pattern implies that maybe you could use it to adapt one class to be another, which this feature will not allow.\n* `alias` - This doesn't imply anything about the additive nature of the feature, which feels like a bit of a misstep.\n* `view` - This one is also decently well-liked, but there's some concern that the word `view` is already too overloaded, even within the .NET ecosystem. Database views, our various\n  UI frameworks, etc; it gives us pause that we'd be able to explain this well, which is the concern that brought us back here in the first place.\n* `shape` - This one has a lot of previous baggage around implicit implementation, and we don't want to imply that we're introducing generalized structural typing to C#.\n* `extension type` - Very wordy. It does relate to what was previously known as `implicit extension`s, which is now just `extension`s, but as discussed previously, we're not sure that's\n  a benefit.\n* `layer` - Wasn't discussed in depth, no one had strong feelings on this one.\n* `facade` - Wasn't discussed in depth, no one had strong feelings on this one.\n* `abstraction` - Wasn't discussed in depth, no one had strong feelings on this one.\n* `augmentation`/`augment` - This is what F# calls their extension methods, though they don't use it as a keyword. We're a bit wary of conflating that.\n* `intent` - This makes some people think of Android first, rather than a type system thing.\n\nOf these, we had 2 clear standouts during initial preferencing: `role`, with most of the LDM liking it, and `view`, with a majority at least being ok with it, but not as many liking it as\n`role`. We'll let this one sit for a couple of weeks, and then come back with more thoughts.\n\n#### Conclusion\n\nThe general idea is approved. `implicit extension` is now just `extension`. We don't yet have a name for `explicit extension`, but `role` is a standout leader, with `view` being another\npossible contender.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-09-30.md",
    "content": "# C# Language Design Meeting for September 30th, 2024\n\n## Agenda\n\n- [Extensions](#extensions)\n\n## Quote of the Day\n\n- \"Are you converting the topic?\" \"Yes, I'm explicitly converting it, so it's kinda dangerous\"\n\n## Discussion\n\n### Extensions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/5497  \nRelated: https://github.com/dotnet/csharplang/blob/1e8255a438517bc3ad067c726c28cfa20cb60f1e/meetings/working-groups/extensions/extensions-as-static-types.md\n\nToday, we looked at a proposal for scoping the work involved in extensions to something more manageable for initial previews. Extensions being able to be used as types adds\nmany complexities to the design, and by forbidding this, we may be able to get previews out sooner for earlier feedback. Extensions depend on this their typeness in two major\ncases:\n\n* The type of `this` inside the extension\n* Their disambiguation syntax\n\nThe latter is something that we've had more general proposals around before, particularly around calling DIMs from implementing types. Such a syntax could serve us here as well,\nand if we go with the restriction, is something that we want to seriously investigate. While a majority of the LDM is ok with allowing extensions to ship without an explicit\nsyntax for disambiguation, a plurality is not ok with this. We prefer to reach consensus, rather than simply doing majority rules, so we'll definitely be investigating this and\nbringing back results to the LDM for further discussion.\n\n The type of `this` is a bit harder, particularly if we ever want to re-expand back to allowing `extension`s to be able to be local types. For example:\n\n```cs\nextension E for object\n{\n    public void M()\n    {\n        Console.WriteLine(Identity(this));\n\n        string Identity<T>(T t) => typeof(T).Name;\n    }\n}\n```\n\nIf we change the type of `this` at a later date, then this goes from printing `object` to printing `E`. While we may end up being ok with such a breaking change, we still need to\nacknowledge that it is a breaking change.\n\nAnother part of making `this` be the underlying type is that it means that, when shadowing a base type member, it's very difficult to call the shadowing member. Consider:\n\n```cs\nextension E for string\n{\n    public int Length => 10;\n\n    public void M()\n    {\n        Console.WriteLine(this.Length); // This calls `string.Length`, not `E.Length`\n    }\n}\n```\n\nWe should consider warning in these scenarios, to let the user know that they're doing something that is almost certainly useless and not what they intended to do (or at the very\nleast, likely will not work the way they expected it to).\n\nUltimately, we think we're ok with continuing to explore this restricted space. We want to be able to get previews out into our user's hands sooner rather than later, and this seems\nlike a viable approach to managing the large complexity of the feature.\n\n#### Conclusion\n\nRestricting `extension`s from being instance types is tentatively approved. We will also investigate disambiguation syntax for calling specific members, a more general feature than\njust for `extension`s.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-10-02.md",
    "content": "# C# Language Design Meeting for October 2nd, 2024\n\n## Agenda\n\n- [Open questions in field](#open-questions-in-field)\n    - [`readonly` contexts and `set`](#readonly-contexts-and-set)\n    - [`Conditional` code](#conditional-code)\n    - [Interface properties and auto-accessors](#interface-properties-and-auto-accessors)\n- [Extensions](#extensions)\n\n## Quote of the Day\n\n- \"Attempting to find my way to this room was like navigating the Severance basement\"\n\n## Discussion\n\n### Open questions in field\n\nChampion issue: https://github.com/dotnet/csharplang/issues/140  \nQuestions: https://github.com/dotnet/csharplang/blob/3cca17a650e40d787629e52a8d46e59459cb2b74/proposals/field-keyword.md#open-ldm-questions\n\n#### `readonly` contexts and `set`\n\nThere could be scenarios for this where you're implementing a `set` accessor on a `readonly` struct and either passing it through, or throwing. Recommendation is accepted, we will\nallow this.\n\n#### `Conditional` code\n\n`Conditional` code can have effects on non-conditional code, such as `Debug.Assert` changing nullability. It would be strange if `field` didn't have similar impacts. It is also\nunlikely to come up in most code, so we'll do the simple thing and accept the recommendation.\n\n#### Interface properties and auto-accessors\n\nStandardizing around the instance field itself being the cause of the error is consistent with partial properties in classes, and we like that outcome. The recommendation is accepted.\n\n### Extensions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/5497  \nRelated: https://github.com/dotnet/csharplang/blob/1e8255a438517bc3ad067c726c28cfa20cb60f1e/meetings/working-groups/extensions/extensions-as-static-types.md, https://github.com/dotnet/csharplang/pull/8472\n\nToday, we continued our thinking around extensions from [last time](./LDM-2024-09-30.md#extensions), and around how we want to approach the complex issues standing in the way of\nus getting previews out. Unfortunately for us, this ended up raising far more questions than answers. The focus today was around aligning with method type inference for existing\nextension methods. As an example:\n\n```cs\npublic class C\n{\n    public void M(I<string> i, out object o)\n    {\n        i.M(out o); // infers E.M<object>\n        i.M2(out o); // error CS1503: Argument 1: cannot convert from 'out object' to 'out string'\n    }\n}\npublic static class E\n{\n   public static void M<T>(this I<T> i, out T t) { t = default; }\n}\npublic static extension E2<T> for I<T>\n{\n   public static void M2(out T t) { t = default; }\n}\npublic interface I<out T> { }\n```\n\nAs currently envisioned, extension types have a 2-stage type inference approach. The first stage deduces the type parameter for the extension type, based on the receiver, and the second\ndeduces any type parameters on the method (if there are any). This is very different to how today's extension methods work; since all type parameters are on the method, they're all inferred\nat the same time, and the receiver is just one of the parameters. This is an example of a behavior difference that we'd incur between old and new extension methods, and we want to see if\nwe can solve it. One possibility is a single pass, that pretends the type parameters from the extension type are part of the method signature. Then we do the same single pass as in extension\nmethods today, and it all behaves the same.\n\nThis comes with its own downsides, however, which is breaking a _different_ expectation from C# users around how type parameters work. There is no place in C# today where type parameters\nfrom different definitions are smashed together and inferred at the same time. A single-stage inference pass will look and feel different to how the syntax implies that it would work. Some\nmembers feel that the two-stage approach is the more logical approach in general, and actually appreciate that VB did this with classic extension methods.\n\nWe then further got into discussions around compat, and how/if existing extensions methods could move to the new form. As an example, could `LINQ` be written in the new form? We're somewhat\nconcerned that it couldn't be, at least not as designed today; there's an `Enumerable` class with a large number of extensions in it, many on differing types. Adopting the new form would\nof course at least break binary compat, since we can't define all those methods in a single extension type. We'd then further be concerned that this would block the BCL from using the new\nform in conjunction with the old form, due to concerns about the differing inference methodology, as well as other behavioral differences between the forms.\n\nThis has finally brought us squarely back to the questions on syntax. If the current syntax implies a particular behavior, and that behavior would block adoption, perhaps a different form\nis needed. We could consider a more member-centric approach, rather than a type-centric approach. We're definitely not ready to make any calls on this today, but we shall examine these ideas\nfurther in the next LDM.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-10-07-extension-compat.md",
    "content": "# Extension compat\n\n1. To what extent can new extension methods replace old ones without a change in behavior?\n2. What are your options when they can't?\n\n\n## Kinds of compat\n\n1. Binary compat - code compiled against old extension methods works the same way against new ones\n2. Source compat - code that compiled against old extension methods compiles and works the same way against new ones\n    a. When used as extension methods\n    b. When used as static methods\n\n\n## Priority between old and new extension methods\n\nWe have three options for how to handle lookup between competing old and new extension methods in a given scope, giving preference to either the former, the latter or neither.\n\n### Neither is preferred\nThis is only an option if we can somehow get old and new extension methods into the same candidate set. If we do this, old extension methods must be removed as soon as new replacements are made - coexistence would result in ambiguities.\n\nCompat breaks would arise when the new method doesn't apply in the same circumstances, or behaves differently when it does.\n\nIt is possible that we could mitigate this with an attribute like `[OverloadResolutionPriority]`, deferring to one only when the other doesn't apply.\n\n### New extensions are preferred\nThis would allow old extension methods to stay around as backup methods. \n\nCompat breaks would arise whenever a new extension method does not - or cannot - behave exactly as the old one. It is possible for migrated extension methods to start silently shadowing unrelated old ones that would have previously been the best fit.\n\n### Old extensions are preferred\nThis would allow new versions of extension methods to be declared alongside other extension members in the new style, even as old ones would be preferred for compat reasons, if kept around. This might allow a mitigation period while compat breaks are identified and addressed: old ones could be brought into scope in a given file until compat issues have been dealt with.\n\n\n## Preference/disambiguation syntax\n\nNew extension methods will likely have a different disambiguation approach that the old ones, where you just call the static method. \n\nAny such calls would possibly be broken when using the new declaration syntax, both from a source and binary compat point of view.\n\nIt's possible that we could promise to generate static methods with exactly the same signature from new extension methods, at least in a large and well-defined number of cases. Alternatively, the old extension methods could be kept around as ordinary static methods for this purpose.\n\n## Type inference\n\nThe current design of new extensions splits generic type inference into two parts: one for a generic underlying type (which needs to be improved somewhat) and one for a generic extension method. \n\nThis leads to different results in corner cases, including whether the extension method applies to a given receiver, and which type arguments are inferred when it does. Those situations constitute source compat breaks.\n\nThere is a proposal to rejoin the two phases into one in the new approach. Chances are that if we did, few people would notice a difference. For any non-method extension members there probably wouldn't *be* a difference, since only the underlying type would be potentially generic anyway. So this would be a possible mitigation.\n\n## Name of enclosing class\n\nOld extension methods of different receiver types can be grouped together in one static class. The current design for extension types requires a different extension type declaration for each underlying type. In such situations, when porting old extension methods, some will end up in a generated class with a different name than before.\n\nThis compromises binary compat of callsites, as well as source compat when used directly as static methods.\n\nIt is possible that attributes could be used to force generated extension methods onto a different class than the one they are declared in. Or extension members could have a syntax to override the underlying type specified by the extension type.\n\n\n## Refness of receiver\n\nOld extension methods allow receivers to be `ref` or `in` parameters only on value types. New extensions automatically manage ref-ness so that it matches the behavior of `this` in type declarations: In reference types it is a value parameter, and value types it is a `ref` parameter. This is the case even when the underlying type is an unconstrained type parameter - callsites are generated to manage this at runtime! The generated method itself in these cases takes a ref parameter as the receiver, and the callsite will take a copy when the type argument is a reference type.\n\nThis means that there is no compatible way to port an extension method that has a value-parameter receiver of a value type or unconstrained generic type, and unconstrained generic extension methods would be generated with a ref instead of a value parameter.\n\nWe could potentially mitigate this with an attribute on the member to prevent ref generation, or as part of a feature to allow extension members to \"override\" their underlying type.\n\n\n## Nullability of receiver\n\nOld extension methods can - and very occasionally do - have nullable reference types as receiver types, whereas the current design for new extension methods does not allow for that. Even if `for C?` syntax was allowed for underlying reference types, it's unlikely that you would want the underlying type to be nullable for every extension member on that type.\n\nWe could mitigate this through a memberwise attribute, or as part of a feature to allow extension members to \"override\" their underlying type."
  },
  {
    "path": "meetings/2024/LDM-2024-10-07.md",
    "content": "# C# Language Design Meeting for October 7th, 2024\n\n## Agenda\n\n- [Extensions](#extensions)\n\n## Quote(s) of the Day\n\n- \"If I had a penny `foreach` code-based dad joke...\"\n- \"If we can have our cake and eat it too, I love it. I like cake, and I like eating.\"\n\n## Discussion\n\n### Extensions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/5497  \nRelated: https://github.com/dotnet/csharplang/blob/1e8255a438517bc3ad067c726c28cfa20cb60f1e/meetings/working-groups/extensions/extensions-as-static-types.md, https://github.com/dotnet/csharplang/pull/8472\n\nContinuing our discussion from [last time](LDM-2024-10-02.md#extensions), we started to explore the pros and cons of moving to a per-member syntax, instead of per-type.\nPer-member would naturally lead to a single-pass generic inference algorithm, since everything is in the same signature, but brings its own complexities. Today, properties\nand operators cannot introduce type parameters; in order to extend generic types, a per-member syntax would need to come up with a way to introduce that; it seems unlikely\nthat we would want to require that any extension properties or operators must be on substituted generic types (to put it mildly). However, we're concerned that per-member\nsyntax could be worse overall; it doesn't improve on how a series of extension methods today are required to repeat the same type over and over. It also looks closer to\nwhat an actual member of the original type looks like. This, of course, then leads to its own set of problems, such as the inability to specify whether `this` is `ref` or\n`scoped` for structs. And the compat story becomes, as previously discussed, more complex.\n\nOne thing we clarified during discussion is that, even though we've arrived at the idea that extension types aren't actually types and can't be the type of an instance\nvariable today, we haven't ruled out that extension types could implement interfaces in the future, allowing the user to implicitly treat the underlying type as having\nimplemented that interface without having to do any casts.\n\nTo try and help drive conversation, we also went through some discussion on what compat means in the context of extensions, reviewing\n[this document](LDM-2024-10-07-extension-compat.md). Compat can mean \"keep your existing methods as they are, unchanged, and put new stuff in a new extension type\", or it\ncould mean \"everything can move forward to the new form\". Along the latter line, we also started thinking about whether there's a unifying `for` clause that can applied\nto members as well as on types, and then have some sort of grow-up story between them. The story would likely still be complex; the generic inference question is still\ngnarly. But we think that this is the next area to explore, and will come back next meeting with proposals on it to consider.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-10-09.md",
    "content": "# C# Language Design Meeting for October 9th, 2024\n\n## Agenda\n\n- [Extensions](#extensions)\n\n## Quote of the Day\n\n- \"And then I had a final point that is evading me right now and I was trying to stretch my words to see if it pops in there, but it hasn't quite yet, so I'm going to give it over to <redacted>\"\n\n## Discussion\n\n### Extensions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/5497  \nRelated: https://github.com/dotnet/csharplang/blob/d5b8e7808998024e4aa6b380acdccac30aa03b60/proposals/extensions_v2.md, https://github.com/dotnet/csharplang/blob/1e8255a438517bc3ad067c726c28cfa20cb60f1e/meetings/working-groups/extensions/Compatibility%20through%20coexistence%20between%20extension%20types%20and%20extension%20methods.md\n\nComing back from [last time](LDM-2024-10-07.md#extensions), we wanted to explore different compatibility stories for extensions, and look at what a member-based syntax would look like.\nWe spent the first half of the meeting listening to presentations about the 2 different explorations that came from this; the first exploration is maximally binary compatible, using a\nmember-based `for` syntax that enables all current extension methods to move to a newer form while still being 100% binary compatible with their existing form. The second proposal we\nwent over was how interop would work in a world where we don't do this, and instead say that existing extension methods are here to stay, forever; the new way is the new way, and if a\nuser wants perfect binary compat, the only way they get it is through keeping their existing methods as they are.\n\nWe came up with a few concerns for each proposal through discussion in the second half.\n\n* Even if there's a fully compatible new syntax, we can't eliminate old style extension methods from the world. Old codebases will continue to exist, and many users will simply not move\n  forward for a variety of reasons.\n* The fully compatible proposal will also leave us in a world with 3 different types of extensions: old style, new member style, and eventually, new type style. We will likely still need\n  to have the discussion on how generic inference will work in the new type style extensions, as all our previous arguments around looking more like types than like members will still\n  apply.\n* The least compatible proposal ends up exposing each decision through refactorings. There will undoubtedly be fixers from both the Roslyn team and other environments to help users move\n  forward to the new form wherever possible, and anywhere the fixers can't run because the meaning changes exposes design decisions.\n* It's possible that the second proposal is somewhat of a subset of the first; is it possible that we could do the second, get that into preview, then wait for feedback on whether a fully\n  compatible form is necessary?\n* On the other hand, it's possible that we may want to avoid a type syntax entirely for extensions if we went with the member approach, as it would muddy understanding of what the feature\n  is: a fancy place to put a parameter, that's it.\n* Finally, if we go with the member approach, we need to discuss whether we want to support generic properties and operators in general, since it's an obvious next question if we allow\n  extension operators and properties to be generic.\n\nWe didn't come to any conclusions today, so we'll be back again with more extensions in the future.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-10-14-Enumerable-extension.cs",
    "content": "namespace System.Linq;\n\npublic extension Enumerable<T> for IEnumerable<T>\n{\n    public T Aggregate(Func<T, T, T> func);\n    public TAccumulate Aggregate<TAccumulate>(TAccumulate seed, Func<TAccumulate, T, TAccumulate> func);\n    public TResult Aggregate<TAccumulate, TResult>(TAccumulate seed, Func<TAccumulate, T, TAccumulate> func, Func<TAccumulate, TResult> resultSelector);\n\n    public IEnumerable<KeyValuePair<TKey, TAccumulate>> AggregateBy<TKey, TAccumulate>(Func<T, TKey> keySelector, TAccumulate seed, Func<TAccumulate, T, TAccumulate> func, IEqualityComparer<TKey>? keyComparer = null) where TKey : notnull;\n    public IEnumerable<KeyValuePair<TKey, TAccumulate>> AggregateBy<TKey, TAccumulate>(Func<T, TKey> keySelector, Func<TKey, TAccumulate> seedSelector, Func<TAccumulate, T, TAccumulate> func, IEqualityComparer<TKey>? keyComparer = null) where TKey : notnull;\n\n    public bool All(Func<T, bool> predicate);\n\n    public bool Any();\n    public bool Any(Func<T, bool> predicate);\n\n    public IEnumerable<T> Append(T element);\n\n    public IEnumerable<T> AsEnumerable();\n\n    public float? Average(Func<T, float?> selector);\n    public double? Average(Func<T, long?> selector);\n    public double? Average(Func<T, int?> selector);\n    public double? Average(Func<T, double?> selector);\n    public decimal? Average(Func<T, decimal?> selector);\n    public double Average(Func<T, long> selector);\n    public double Average(Func<T, int> selector);\n    public double Average(Func<T, double> selector);\n    public decimal Average(Func<T, decimal> selector);\n    public float Average(Func<T, float> selector);\n\n    public IEnumerable<T[]> Chunk(int size);\n\n    public IEnumerable<T> Concat(IEnumerable<T> other);\n\n    public bool Contains(T value);\n    public bool Contains(T value, IEqualityComparer<T>? comparer);\n\n    public int Count();\n    public int Count(Func<T, bool> predicate);\n    public IEnumerable<KeyValuePair<TKey, int>> CountBy<TKey>(Func<T, TKey> keySelector, IEqualityComparer<TKey>? keyComparer = null) where TKey : notnull;\n\n    public IEnumerable<T?> DefaultIfEmpty();\n    public IEnumerable<T> DefaultIfEmpty(T defaultValue);\n\n    public IEnumerable<T> Distinct();\n    public IEnumerable<T> Distinct(IEqualityComparer<T>? comparer);\n    public IEnumerable<T> DistinctBy<TKey>(Func<T, TKey> keySelector);\n    public IEnumerable<T> DistinctBy<TKey>(Func<T, TKey> keySelector, IEqualityComparer<TKey>? comparer);\n\n    public T ElementAt(Index index);\n    public T ElementAt(int index);\n    public T? ElementAtOrDefault(Index index);\n    public T? ElementAtOrDefault(int index);\n\n    public IEnumerable<T> Except(IEnumerable<T> other);\n    public IEnumerable<T> Except(IEnumerable<T> other, IEqualityComparer<T>? comparer);\n    public IEnumerable<T> ExceptBy<TKey>(IEnumerable<TKey> other, Func<T, TKey> keySelector);\n    public IEnumerable<T> ExceptBy<TKey>(IEnumerable<TKey> other, Func<T, TKey> keySelector, IEqualityComparer<TKey>? comparer);\n\n    public T First(Func<T, bool> predicate);\n    public T First();\n    public T FirstOrDefault(Func<T, bool> predicate, T defaultValue);\n    public T FirstOrDefault(T defaultValue);\n    public T? FirstOrDefault();\n    public T? FirstOrDefault(Func<T, bool> predicate);\n\n    public IEnumerable<TResult> GroupBy<TKey, TResult>(Func<T, TKey> keySelector, Func<TKey, IEnumerable<T>, TResult> resultSelector, IEqualityComparer<TKey>? comparer);\n    public IEnumerable<TResult> GroupBy<TKey, TElement, TResult>(Func<T, TKey> keySelector, Func<T, TElement> elementSelector, Func<TKey, IEnumerable<TElement>, TResult> resultSelector, IEqualityComparer<TKey>? comparer);\n    public IEnumerable<TResult> GroupBy<TKey, TElement, TResult>(Func<T, TKey> keySelector, Func<T, TElement> elementSelector, Func<TKey, IEnumerable<TElement>, TResult> resultSelector);\n    public IEnumerable<TResult> GroupBy<TKey, TResult>(Func<T, TKey> keySelector, Func<TKey, IEnumerable<T>, TResult> resultSelector);\n    public IEnumerable<IGrouping<TKey, T>> GroupBy<TKey>(Func<T, TKey> keySelector, IEqualityComparer<TKey>? comparer);\n    public IEnumerable<IGrouping<TKey, TElement>> GroupBy<TKey, TElement>(Func<T, TKey> keySelector, Func<T, TElement> elementSelector);\n    public IEnumerable<IGrouping<TKey, TElement>> GroupBy<TKey, TElement>(Func<T, TKey> keySelector, Func<T, TElement> elementSelector, IEqualityComparer<TKey>? comparer);\n    public IEnumerable<IGrouping<TKey, T>> GroupBy<TKey>(Func<T, TKey> keySelector);\n\n    public IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> resultSelector);\n    public IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> resultSelector, IEqualityComparer<TKey>? comparer);\n\n    public IEnumerable<(int Index, T Item)> Index();\n\n    public IEnumerable<T> Intersect(IEnumerable<T> other);\n    public IEnumerable<T> Intersect(IEnumerable<T> other, IEqualityComparer<T>? comparer);\n    public IEnumerable<T> IntersectBy<TKey>(IEnumerable<TKey> other, Func<T, TKey> keySelector);\n    public IEnumerable<T> IntersectBy<TKey>(IEnumerable<TKey> other, Func<T, TKey> keySelector, IEqualityComparer<TKey>? comparer);\n\n    public IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector);\n    public IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector, IEqualityComparer<TKey>? comparer);\n\n    public T Last(Func<T, bool> predicate);\n    public T Last();\n    public T LastOrDefault(Func<T, bool> predicate, T defaultValue);\n    public T LastOrDefault(T defaultValue);\n    public T? LastOrDefault();\n    public T? LastOrDefault(Func<T, bool> predicate);\n\n    public long LongCount();\n    public long LongCount(Func<T, bool> predicate);\n\n    public decimal Max(Func<T, decimal> selector);\n    public double Max(Func<T, double> selector);\n    public TResult? Max<TResult>(Func<T, TResult> selector);\n    public int Max(Func<T, int> selector);\n    public long Max(Func<T, long> selector);\n    public int? Max(Func<T, int?> selector);\n    public double? Max(Func<T, double?> selector);\n    public long? Max(Func<T, long?> selector);\n    public float? Max(Func<T, float?> selector);\n    public float Max(Func<T, float> selector);\n    public decimal? Max(Func<T, decimal?> selector);\n    public T? Max(IComparer<T>? comparer);\n    public T? Max();\n    public T? MaxBy<TKey>(Func<T, TKey> keySelector, IComparer<TKey>? comparer);\n    public T? MaxBy<TKey>(Func<T, TKey> keySelector);\n\n    public double Min(Func<T, double> selector);\n    public int Min(Func<T, int> selector);\n    public long Min(Func<T, long> selector);\n    public decimal? Min(Func<T, decimal?> selector);\n    public double? Min(Func<T, double?> selector);\n    public decimal Min(Func<T, decimal> selector);\n    public long? Min(Func<T, long?> selector);\n    public float? Min(Func<T, float?> selector);\n    public float Min(Func<T, float> selector);\n    public TResult? Min<TResult>(Func<T, TResult> selector);\n    public int? Min(Func<T, int?> selector);\n    public T? Min(IComparer<T>? comparer);\n    public T? Min();\n    public T? MinBy<TKey>(Func<T, TKey> keySelector, IComparer<TKey>? comparer);\n    public T? MinBy<TKey>(Func<T, TKey> keySelector);\n\n    public IOrderedEnumerable<T> Order(IComparer<T>? comparer);\n    public IOrderedEnumerable<T> Order();\n    public IOrderedEnumerable<T> OrderBy<TKey>(Func<T, TKey> keySelector);\n    public IOrderedEnumerable<T> OrderBy<TKey>(Func<T, TKey> keySelector, IComparer<TKey>? comparer);\n    public IOrderedEnumerable<T> OrderByDescending<TKey>(Func<T, TKey> keySelector);\n    public IOrderedEnumerable<T> OrderByDescending<TKey>(Func<T, TKey> keySelector, IComparer<TKey>? comparer);\n    public IOrderedEnumerable<T> OrderDescending(Comparer<T>? comparer);\n    public IOrderedEnumerable<T> OrderDescending();\n\n    public IEnumerable<T> Prepend(T element);\n\n    public IEnumerable<T> Reverse();\n\n    public IEnumerable<TResult> Select<TResult>(Func<T, int, TResult> selector);\n    public IEnumerable<TResult> Select<TResult>(Func<T, TResult> selector);\n\n    public IEnumerable<TResult> SelectMany<TCollection, TResult>(Func<T, int, IEnumerable<TCollection>> collectionSelector, Func<T, TCollection, TResult> resultSelector);\n    public IEnumerable<TResult> SelectMany<TResult>(Func<T, int, IEnumerable<TResult>> selector);\n    public IEnumerable<TResult> SelectMany<TResult>(Func<T, IEnumerable<TResult>> selector);\n    public IEnumerable<TResult> SelectMany<TCollection, TResult>(Func<T, IEnumerable<TCollection>> collectionSelector, Func<T, TCollection, TResult> resultSelector);\n\n    public bool SequenceEqual(IEnumerable<T> other);\n    public bool SequenceEqual(IEnumerable<T> other, IEqualityComparer<T>? comparer);\n\n    public T Single();\n    public T Single(Func<T, bool> predicate);\n    public T? SingleOrDefault();\n    public T SingleOrDefault(T defaultValue);\n    public T? SingleOrDefault(Func<T, bool> predicate);\n    public T SingleOrDefault(Func<T, bool> predicate, T defaultValue);\n\n    public IEnumerable<T> Skip(int count);\n    public IEnumerable<T> SkipLast(int count);\n    public IEnumerable<T> SkipWhile(Func<T, bool> predicate);\n    public IEnumerable<T> SkipWhile(Func<T, int, bool> predicate);\n\n    public float Sum(Func<T, float> selector);\n    public int Sum(Func<T, int> selector);\n    public long Sum(Func<T, long> selector);\n    public decimal? Sum(Func<T, decimal?> selector);\n    public double Sum(Func<T, double> selector);\n    public int? Sum(Func<T, int?> selector);\n    public long? Sum(Func<T, long?> selector);\n    public float? Sum(Func<T, float?> selector);\n    public double? Sum(Func<T, double?> selector);\n    public decimal Sum(Func<T, decimal> selector);\n\n    public IEnumerable<T> Take(Range range);\n    public IEnumerable<T> Take(int count);\n    public IEnumerable<T> TakeLast(int count);\n    public IEnumerable<T> TakeWhile(Func<T, int, bool> predicate);\n    public IEnumerable<T> TakeWhile(Func<T, bool> predicate);\n\n    public T[] ToArray();\n\n    public Dictionary<TKey, TElement> ToDictionary<TKey, TElement>(Func<T, TKey> keySelector, Func<T, TElement> elementSelector, IEqualityComparer<TKey>? comparer) where TKey : notnull;\n    public Dictionary<TKey, TElement> ToDictionary<TKey, TElement>(Func<T, TKey> keySelector, Func<T, TElement> elementSelector) where TKey : notnull;\n    public Dictionary<TKey, T> ToDictionary<TKey>(Func<T, TKey> keySelector, IEqualityComparer<TKey>? comparer) where TKey : notnull;\n    public Dictionary<TKey, T> ToDictionary<TKey>(Func<T, TKey> keySelector) where TKey : notnull;\n\n    public HashSet<T> ToHashSet();\n    public HashSet<T> ToHashSet(IEqualityComparer<T>? comparer);\n\n    public List<T> ToList();\n\n    public ILookup<TKey, TElement> ToLookup<TKey, TElement>(Func<T, TKey> keySelector, Func<T, TElement> elementSelector);\n    public ILookup<TKey, TElement> ToLookup<TKey, TElement>(Func<T, TKey> keySelector, Func<T, TElement> elementSelector, IEqualityComparer<TKey>? comparer);\n    public ILookup<TKey, T> ToLookup<TKey>(Func<T, TKey> keySelector);\n    public ILookup<TKey, T> ToLookup<TKey>(Func<T, TKey> keySelector, IEqualityComparer<TKey>? comparer);\n\n    public bool TryGetNonEnumeratedCount(out int count);\n\n    public IEnumerable<T> Union(IEnumerable<T> other);\n    public IEnumerable<T> Union(IEnumerable<T> other, IEqualityComparer<T>? comparer);\n    public IEnumerable<T> UnionBy<TKey>(IEnumerable<T> other, Func<T, TKey> keySelector);\n    public IEnumerable<T> UnionBy<TKey>(IEnumerable<T> other, Func<T, TKey> keySelector, IEqualityComparer<TKey>? comparer);\n\n    public IEnumerable<T> Where(Func<bool> predicate);\n    public IEnumerable<T> Where(Func<int, bool> predicate);\n\n    public IEnumerable<(T First, TSecond Second)> Zip<TSecond>(IEnumerable<TSecond> second);\n    public IEnumerable<TResult> Zip<TSecond, TResult>(IEnumerable<TSecond> second, Func<T, TSecond, TResult> resultSelector);\n    public IEnumerable<(T First, TSecond Second, TThird Third)> Zip<TSecond, TThird>(IEnumerable<TSecond> second, IEnumerable<TThird> third);\n}\n\npublic extension Enumerable for IEnumerable\n{\n    public IEnumerable<TResult> Cast<TResult>();\n    public IEnumerable<TResult> OfType<TResult>();\n\n    // Non-extension static methods - can they live here too?\n    public abstract static IEnumerable<TResult> Empty<TResult>();\n    public abstract static IEnumerable<int> Range(int start, int count);\n    public abstract static IEnumerable<TResult> Repeat<TResult>(TResult element, int count);\n}\n\npublic extension OrderedEnumerable<T> for IOrderedEnumerable<T>\n{\n    public IOrderedEnumerable<T> ThenBy<TKey>(Func<T, TKey> keySelector);\n    public IOrderedEnumerable<T> ThenBy<TKey>(Func<T, TKey> keySelector, IComparer<TKey>? comparer);\n    public IOrderedEnumerable<T> ThenByDescending<TKey>(Func<T, TKey> keySelector);\n    public IOrderedEnumerable<T> ThenByDescending<TKey>(Func<T, TKey> keySelector, IComparer<TKey>? comparer);\n}\n\npublic extension KeyValuePairEnumerable<TKey, TValue> for IEnumerable<KeyValuePair<TKey, TValue>>\n    where TKey : notnull\n{\n    public Dictionary<TKey, TValue> ToDictionary();\n    public Dictionary<TKey, TValue> ToDictionary(IEqualityComparer<TKey>? comparer);\n}\n\npublic extension KeyValueTupleEnumerable<TKey, TValue> for IEnumerable<(TKey, TValue)>\n    where TKey : notnull\n{\n    public Dictionary<TKey, TValue> ToDictionary();\n    public Dictionary<TKey, TValue> ToDictionary(IEqualityComparer<TKey>? comparer);\n}\n\npublic extension IntEnumerable for IEnumerable<int>\n{\n    public double Average();\n    public int Max();\n    public int Min();\n    public int Sum();\n}\n\npublic extension LongEnumerable for IEnumerable<long>\n{\n    public double Average();\n    public long Max();\n    public long Min();\n    public long Sum();\n}\n\npublic extension FloatEnumerable for IEnumerable<float>\n{\n    public float Average();\n    public float Max();\n    public float Min();\n    public float Sum();\n}\n\npublic extension DoubleEnumerable for IEnumerable<double>\n{\n    public double Average();\n    public double Max();\n    public double Min();\n    public double Sum();\n}\n\npublic extension DecimalEnumerable for IEnumerable<decimal>\n{\n    public decimal Average();\n    public decimal Max();\n    public decimal Min();\n    public decimal Sum();\n}\n\npublic extension NullableIntEnumerable for IEnumerable<int?>\n{\n    public double? Average();\n    public int? Max();\n    public int? Min();\n    public int? Sum();\n}\n\npublic extension NullableLongEnumerable for IEnumerable<long?>\n{\n    public double? Average();\n    public long? Max();\n    public long? Min();\n    public long? Sum();\n}\n\npublic extension NullableFloatEnumerable for IEnumerable<float?>\n{\n    public float? Average();\n    public float? Max();\n    public float? Min();\n    public float? Sum();\n}\n\npublic extension NullableDoubleEnumerable for IEnumerable<double?>\n{\n    public double? Average();\n    public double? Max();\n    public double? Min();\n    public double? Sum();\n}\n\npublic extension NullableDecimalEnumerable for IEnumerable<decimal?>\n{\n    public decimal? Average();\n    public decimal? Max();\n    public decimal? Min();\n    public decimal? Sum();\n}\n"
  },
  {
    "path": "meetings/2024/LDM-2024-10-14-Enumerable-extensions.cs",
    "content": "namespace System.Linq;\n\nextension Enumerable\n{\n    public TSource Aggregate<TSource>(Func<TSource, TSource, TSource> func) for IEnumerable<TSource> source;\n    public TAccumulate Aggregate<TSource, TAccumulate>(TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func) for IEnumerable<TSource> source;\n    public TResult Aggregate<TSource, TAccumulate, TResult>(TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func, Func<TAccumulate, TResult> resultSelector) for IEnumerable<TSource> source;\n\n    public IEnumerable<KeyValuePair<TKey, TAccumulate>> AggregateBy<TSource, TKey, TAccumulate>(Func<TSource, TKey> keySelector, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func, IEqualityComparer<TKey>? keyComparer = null) for IEnumerable<TSource> source where TKey : notnull;\n    public IEnumerable<KeyValuePair<TKey, TAccumulate>> AggregateBy<TSource, TKey, TAccumulate>(Func<TSource, TKey> keySelector, Func<TKey, TAccumulate> seedSelector, Func<TAccumulate, TSource, TAccumulate> func, IEqualityComparer<TKey>? keyComparer = null) for IEnumerable<TSource> source where TKey : notnull;\n\n    public bool All<TSource>(Func<TSource, bool> predicate) for IEnumerable<TSource> source;\n\n    public bool Any<TSource>() for IEnumerable<TSource> source;\n    public bool Any<TSource>(Func<TSource, bool> predicate) for IEnumerable<TSource> source;\n\n    public IEnumerable<TSource> Append<TSource>(TSource element) for IEnumerable<TSource> source;\n\n    public IEnumerable<TSource> AsEnumerable<TSource>() for IEnumerable<TSource> source;\n\n    public float? Average<TSource>(Func<TSource, float?> selector) for IEnumerable<TSource> source;\n    public double? Average<TSource>(Func<TSource, long?> selector) for IEnumerable<TSource> source;\n    public double? Average<TSource>(Func<TSource, int?> selector) for IEnumerable<TSource> source;\n    public double? Average<TSource>(Func<TSource, double?> selector) for IEnumerable<TSource> source;\n    public decimal? Average<TSource>(Func<TSource, decimal?> selector) for IEnumerable<TSource> source;\n    public double Average<TSource>(Func<TSource, long> selector) for IEnumerable<TSource> source;\n    public double Average<TSource>(Func<TSource, int> selector) for IEnumerable<TSource> source;\n    public double Average<TSource>(Func<TSource, double> selector) for IEnumerable<TSource> source;\n    public decimal Average<TSource>(Func<TSource, decimal> selector) for IEnumerable<TSource> source;\n    public double? Average() for IEnumerable<double?> source;\n    public float? Average() for IEnumerable<float?> source;\n    public double? Average() for IEnumerable<long?> source;\n    public double? Average() for IEnumerable<int?> source;\n    public float Average<TSource>(Func<TSource, float> selector) for IEnumerable<TSource> source;\n    public decimal? Average() for IEnumerable<decimal?> source;\n    public double Average() for IEnumerable<long> source;\n    public double Average() for IEnumerable<int> source;\n    public double Average() for IEnumerable<double> source;\n    public decimal Average() for IEnumerable<decimal> source;\n    public float Average() for IEnumerable<float> source;\n\n    public IEnumerable<TResult> Cast<TResult>(this IEnumerable source);\n\n    public IEnumerable<TSource[]> Chunk<TSource>(int size) for IEnumerable<TSource> source;\n\n    public IEnumerable<TSource> Concat<TSource>(IEnumerable<TSource> second) for IEnumerable<TSource> first;\n\n    public bool Contains<TSource>(TSource value) for IEnumerable<TSource> source;\n    public bool Contains<TSource>(TSource value, IEqualityComparer<TSource>? comparer) for IEnumerable<TSource> source;\n\n    public int Count<TSource>() for IEnumerable<TSource> source;\n    public int Count<TSource>(Func<TSource, bool> predicate) for IEnumerable<TSource> source;\n\n    public IEnumerable<KeyValuePair<TKey, int>> CountBy<TSource, TKey>(Func<TSource, TKey> keySelector, IEqualityComparer<TKey>? keyComparer = null) for IEnumerable<TSource> source where TKey : notnull;\n\n    public IEnumerable<TSource?> DefaultIfEmpty<TSource>() for IEnumerable<TSource> source;\n    public IEnumerable<TSource> DefaultIfEmpty<TSource>(TSource defaultValue) for IEnumerable<TSource> source;\n\n    public IEnumerable<TSource> Distinct<TSource>() for IEnumerable<TSource> source;\n    public IEnumerable<TSource> Distinct<TSource>(IEqualityComparer<TSource>? comparer) for IEnumerable<TSource> source;\n\n    public IEnumerable<TSource> DistinctBy<TSource, TKey>(Func<TSource, TKey> keySelector) for IEnumerable<TSource> source;\n    public IEnumerable<TSource> DistinctBy<TSource, TKey>(Func<TSource, TKey> keySelector, IEqualityComparer<TKey>? comparer) for IEnumerable<TSource> source;\n\n    public TSource ElementAt<TSource>(Index index) for IEnumerable<TSource> source;\n    public TSource ElementAt<TSource>(int index) for IEnumerable<TSource> source;\n\n    public TSource? ElementAtOrDefault<TSource>(Index index) for IEnumerable<TSource> source;\n    public TSource? ElementAtOrDefault<TSource>(int index) for IEnumerable<TSource> source;\n\n    public IEnumerable<TResult> Empty<TResult>();\n\n    public IEnumerable<TSource> Except<TSource>(IEnumerable<TSource> second) for IEnumerable<TSource> first;\n    public IEnumerable<TSource> Except<TSource>(IEnumerable<TSource> second, IEqualityComparer<TSource>? comparer) for IEnumerable<TSource> first;\n\n    public IEnumerable<TSource> ExceptBy<TSource, TKey>(IEnumerable<TKey> second, Func<TSource, TKey> keySelector) for IEnumerable<TSource> first;\n    public IEnumerable<TSource> ExceptBy<TSource, TKey>(IEnumerable<TKey> second, Func<TSource, TKey> keySelector, IEqualityComparer<TKey>? comparer) for IEnumerable<TSource> first;\n\n    public TSource First<TSource>(Func<TSource, bool> predicate) for IEnumerable<TSource> source;\n    public TSource First<TSource>() for IEnumerable<TSource> source;\n\n    public TSource FirstOrDefault<TSource>(Func<TSource, bool> predicate, TSource defaultValue) for IEnumerable<TSource> source;\n    public TSource FirstOrDefault<TSource>(TSource defaultValue) for IEnumerable<TSource> source;\n    public TSource? FirstOrDefault<TSource>() for IEnumerable<TSource> source;\n    public TSource? FirstOrDefault<TSource>(Func<TSource, bool> predicate) for IEnumerable<TSource> source;\n\n    public IEnumerable<TResult> GroupBy<TSource, TKey, TResult>(Func<TSource, TKey> keySelector, Func<TKey, IEnumerable<TSource>, TResult> resultSelector, IEqualityComparer<TKey>? comparer) for IEnumerable<TSource> source;\n    public IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, Func<TKey, IEnumerable<TElement>, TResult> resultSelector, IEqualityComparer<TKey>? comparer) for IEnumerable<TSource> source;\n    public IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, Func<TKey, IEnumerable<TElement>, TResult> resultSelector) for IEnumerable<TSource> source;\n    public IEnumerable<TResult> GroupBy<TSource, TKey, TResult>(Func<TSource, TKey> keySelector, Func<TKey, IEnumerable<TSource>, TResult> resultSelector) for IEnumerable<TSource> source;\n    public IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(Func<TSource, TKey> keySelector, IEqualityComparer<TKey>? comparer) for IEnumerable<TSource> source;\n    public IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector) for IEnumerable<TSource> source;\n    public IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey>? comparer) for IEnumerable<TSource> source;\n    public IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(Func<TSource, TKey> keySelector) for IEnumerable<TSource> source;\n\n    public IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> resultSelector) for IEnumerable<TOuter> outer;\n    public IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> resultSelector, IEqualityComparer<TKey>? comparer) for IEnumerable<TOuter> outer;\n    public IEnumerable<(int Index, TSource Item)> Index<TSource>() for IEnumerable<TSource> source;\n    public IEnumerable<TSource> Intersect<TSource>(IEnumerable<TSource> second) for IEnumerable<TSource> first;\n    public IEnumerable<TSource> Intersect<TSource>(IEnumerable<TSource> second, IEqualityComparer<TSource>? comparer) for IEnumerable<TSource> first;\n    public IEnumerable<TSource> IntersectBy<TSource, TKey>(IEnumerable<TKey> second, Func<TSource, TKey> keySelector) for IEnumerable<TSource> first;\n    public IEnumerable<TSource> IntersectBy<TSource, TKey>(IEnumerable<TKey> second, Func<TSource, TKey> keySelector, IEqualityComparer<TKey>? comparer) for IEnumerable<TSource> first;\n\n    public IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector) for IEnumerable<TOuter> outer;\n    public IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector, IEqualityComparer<TKey>? comparer) for IEnumerable<TOuter> outer;\n    \n    public TSource Last<TSource>(Func<TSource, bool> predicate) for IEnumerable<TSource> source;\n    public TSource Last<TSource>() for IEnumerable<TSource> source;\n\n    public TSource LastOrDefault<TSource>(Func<TSource, bool> predicate, TSource defaultValue) for IEnumerable<TSource> source;\n    public TSource LastOrDefault<TSource>(TSource defaultValue) for IEnumerable<TSource> source;\n    public TSource? LastOrDefault<TSource>() for IEnumerable<TSource> source;\n    public TSource? LastOrDefault<TSource>(Func<TSource, bool> predicate) for IEnumerable<TSource> source;\n\n    public long LongCount<TSource>() for IEnumerable<TSource> source;\n    public long LongCount<TSource>(Func<TSource, bool> predicate) for IEnumerable<TSource> source;\n\n    public decimal Max<TSource>(Func<TSource, decimal> selector) for IEnumerable<TSource> source;\n    public double Max<TSource>(Func<TSource, double> selector) for IEnumerable<TSource> source;\n    public TResult? Max<TSource, TResult>(Func<TSource, TResult> selector) for IEnumerable<TSource> source;\n    public int Max<TSource>(Func<TSource, int> selector) for IEnumerable<TSource> source;\n    public long Max<TSource>(Func<TSource, long> selector) for IEnumerable<TSource> source;\n    public int? Max<TSource>(Func<TSource, int?> selector) for IEnumerable<TSource> source;\n    public double? Max<TSource>(Func<TSource, double?> selector) for IEnumerable<TSource> source;\n    public long? Max<TSource>(Func<TSource, long?> selector) for IEnumerable<TSource> source;\n    public float? Max<TSource>(Func<TSource, float?> selector) for IEnumerable<TSource> source;\n    public float Max<TSource>(Func<TSource, float> selector) for IEnumerable<TSource> source;\n    public decimal? Max<TSource>(Func<TSource, decimal?> selector) for IEnumerable<TSource> source;\n    public TSource? Max<TSource>(IComparer<TSource>? comparer) for IEnumerable<TSource> source;\n    public float? Max() for IEnumerable<float?> source;\n    public int Max() for IEnumerable<int> source;\n    public TSource? Max<TSource>() for IEnumerable<TSource> source;\n    public float Max() for IEnumerable<float> source;\n    public long? Max() for IEnumerable<long?> source;\n    public int? Max() for IEnumerable<int?> source;\n    public double? Max() for IEnumerable<double?> source;\n    public decimal? Max() for IEnumerable<decimal?> source;\n    public long Max() for IEnumerable<long> source;\n    public decimal Max() for IEnumerable<decimal> source;\n    public double Max() for IEnumerable<double> source;\n\n    public TSource? MaxBy<TSource, TKey>(Func<TSource, TKey> keySelector, IComparer<TKey>? comparer) for IEnumerable<TSource> source;\n    public TSource? MaxBy<TSource, TKey>(Func<TSource, TKey> keySelector) for IEnumerable<TSource> source;\n\n    public double Min<TSource>(Func<TSource, double> selector) for IEnumerable<TSource> source;\n    public int Min<TSource>(Func<TSource, int> selector) for IEnumerable<TSource> source;\n    public long Min<TSource>(Func<TSource, long> selector) for IEnumerable<TSource> source;\n    public decimal? Min<TSource>(Func<TSource, decimal?> selector) for IEnumerable<TSource> source;\n    public double? Min<TSource>(Func<TSource, double?> selector) for IEnumerable<TSource> source;\n    public decimal Min<TSource>(Func<TSource, decimal> selector) for IEnumerable<TSource> source;\n    public long? Min<TSource>(Func<TSource, long?> selector) for IEnumerable<TSource> source;\n    public float? Min<TSource>(Func<TSource, float?> selector) for IEnumerable<TSource> source;\n    public float Min<TSource>(Func<TSource, float> selector) for IEnumerable<TSource> source;\n    public TResult? Min<TSource, TResult>(Func<TSource, TResult> selector) for IEnumerable<TSource> source;\n    public int? Min<TSource>(Func<TSource, int?> selector) for IEnumerable<TSource> source;\n    public TSource? Min<TSource>(IComparer<TSource>? comparer) for IEnumerable<TSource> source;\n    public decimal Min() for IEnumerable<decimal> source;\n    public long Min() for IEnumerable<long> source;\n    public TSource? Min<TSource>() for IEnumerable<TSource> source;\n    public float Min() for IEnumerable<float> source;\n    public float? Min() for IEnumerable<float?> source;\n    public long? Min() for IEnumerable<long?> source;\n    public int? Min() for IEnumerable<int?> source;\n    public double? Min() for IEnumerable<double?> source;\n    public decimal? Min() for IEnumerable<decimal?> source;\n    public double Min() for IEnumerable<double> source;\n    public int Min() for IEnumerable<int> source;\n\n    public TSource? MinBy<TSource, TKey>(Func<TSource, TKey> keySelector, IComparer<TKey>? comparer) for IEnumerable<TSource> source;\n    public TSource? MinBy<TSource, TKey>(Func<TSource, TKey> keySelector) for IEnumerable<TSource> source;\n\n    public IEnumerable<TResult> OfType<TResult>(this IEnumerable source);\n\n    public IOrderedEnumerable<T> Order<T>(IComparer<T>? comparer) for IEnumerable<T> source;\n    public IOrderedEnumerable<T> Order<T>() for IEnumerable<T> source;\n\n    public IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(Func<TSource, TKey> keySelector) for IEnumerable<TSource> source;\n    public IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(Func<TSource, TKey> keySelector, IComparer<TKey>? comparer) for IEnumerable<TSource> source;\n\n    public IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey>(Func<TSource, TKey> keySelector) for IEnumerable<TSource> source;\n    public IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey>(Func<TSource, TKey> keySelector, IComparer<TKey>? comparer) for IEnumerable<TSource> source;\n    public IOrderedEnumerable<T> OrderDescending<T>(IComparer<T>? comparer) for IEnumerable<T> source;\n    public IOrderedEnumerable<T> OrderDescending<T>() for IEnumerable<T> source;\n\n    public IEnumerable<TSource> Prepend<TSource>(TSource element) for IEnumerable<TSource> source;\n\n    public static IEnumerable<int> Range(int start, int count);\n\n    public IEnumerable<TResult> Repeat<TResult>(TResult element, int count);\n\n    public IEnumerable<TSource> Reverse<TSource>() for IEnumerable<TSource> source;\n\n    public IEnumerable<TResult> Select<TSource, TResult>(Func<TSource, int, TResult> selector) for IEnumerable<TSource> source;\n    public IEnumerable<TResult> Select<TSource, TResult>(Func<TSource, TResult> selector) for IEnumerable<TSource> source;\n\n    public IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(Func<TSource, int, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector) for IEnumerable<TSource> source;\n    public IEnumerable<TResult> SelectMany<TSource, TResult>(Func<TSource, int, IEnumerable<TResult>> selector) for IEnumerable<TSource> source;\n    public IEnumerable<TResult> SelectMany<TSource, TResult>(Func<TSource, IEnumerable<TResult>> selector) for IEnumerable<TSource> source;\n    public IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(Func<TSource, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector) for IEnumerable<TSource> source;\n\n    public bool SequenceEqual<TSource>(IEnumerable<TSource> second) for IEnumerable<TSource> first;\n    public bool SequenceEqual<TSource>(IEnumerable<TSource> second, IEqualityComparer<TSource>? comparer) for IEnumerable<TSource> first;\n\n    public TSource Single<TSource>() for IEnumerable<TSource> source;\n    public TSource Single<TSource>(Func<TSource, bool> predicate) for IEnumerable<TSource> source;\n\n    public TSource? SingleOrDefault<TSource>() for IEnumerable<TSource> source;\n    public TSource SingleOrDefault<TSource>(TSource defaultValue) for IEnumerable<TSource> source;\n    public TSource? SingleOrDefault<TSource>(Func<TSource, bool> predicate) for IEnumerable<TSource> source;\n    public TSource SingleOrDefault<TSource>(Func<TSource, bool> predicate, TSource defaultValue) for IEnumerable<TSource> source;\n\n    public IEnumerable<TSource> Skip<TSource>(int count) for IEnumerable<TSource> source;\n\n    public IEnumerable<TSource> SkipLast<TSource>(int count) for IEnumerable<TSource> source;\n\n    public IEnumerable<TSource> SkipWhile<TSource>(Func<TSource, bool> predicate) for IEnumerable<TSource> source;\n    public IEnumerable<TSource> SkipWhile<TSource>(Func<TSource, int, bool> predicate) for IEnumerable<TSource> source;\n\n    public float Sum<TSource>(Func<TSource, float> selector) for IEnumerable<TSource> source;\n    public int Sum<TSource>(Func<TSource, int> selector) for IEnumerable<TSource> source;\n    public long Sum<TSource>(Func<TSource, long> selector) for IEnumerable<TSource> source;\n    public decimal? Sum<TSource>(Func<TSource, decimal?> selector) for IEnumerable<TSource> source;\n    public double Sum<TSource>(Func<TSource, double> selector) for IEnumerable<TSource> source;\n    public int? Sum<TSource>(Func<TSource, int?> selector) for IEnumerable<TSource> source;\n    public long? Sum<TSource>(Func<TSource, long?> selector) for IEnumerable<TSource> source;\n    public float? Sum<TSource>(Func<TSource, float?> selector) for IEnumerable<TSource> source;\n    public double? Sum<TSource>(Func<TSource, double?> selector) for IEnumerable<TSource> source;\n    public decimal Sum<TSource>(Func<TSource, decimal> selector) for IEnumerable<TSource> source;\n    public double? Sum() for IEnumerable<double?> source;\n    public float? Sum() for IEnumerable<float?> source;\n    public long? Sum() for IEnumerable<long?> source;\n    public int? Sum() for IEnumerable<int?> source;\n    public decimal? Sum() for IEnumerable<decimal?> source;\n    public long Sum() for IEnumerable<long> source;\n    public int Sum() for IEnumerable<int> source;\n    public double Sum() for IEnumerable<double> source;\n    public decimal Sum() for IEnumerable<decimal> source;\n    public float Sum() for IEnumerable<float> source;\n\n    public IEnumerable<TSource> Take<TSource>(Range range) for IEnumerable<TSource> source;\n    public IEnumerable<TSource> Take<TSource>(int count) for IEnumerable<TSource> source;\n\n    public IEnumerable<TSource> TakeLast<TSource>(int count) for IEnumerable<TSource> source;\n\n    public IEnumerable<TSource> TakeWhile<TSource>(Func<TSource, int, bool> predicate) for IEnumerable<TSource> source;\n    public IEnumerable<TSource> TakeWhile<TSource>(Func<TSource, bool> predicate) for IEnumerable<TSource> source;\n\n    public IOrderedEnumerable<TSource> ThenBy<TSource, TKey>(this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector);\n    public IOrderedEnumerable<TSource> ThenBy<TSource, TKey>(this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey>? comparer);\n\n    public IOrderedEnumerable<TSource> ThenByDescending<TSource, TKey>(this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector);\n    public IOrderedEnumerable<TSource> ThenByDescending<TSource, TKey>(this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey>? comparer);\n\n    public TSource[] ToArray<TSource>() for IEnumerable<TSource> source;\n\n    public Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey>? comparer) for IEnumerable<TSource> source where TKey : notnull;\n    public Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector) for IEnumerable<TSource> source where TKey : notnull;\n    public Dictionary<TKey, TSource> ToDictionary<TSource, TKey>(Func<TSource, TKey> keySelector, IEqualityComparer<TKey>? comparer) for IEnumerable<TSource> source where TKey : notnull;\n    public Dictionary<TKey, TSource> ToDictionary<TSource, TKey>(Func<TSource, TKey> keySelector) for IEnumerable<TSource> source where TKey : notnull;\n    public Dictionary<TKey, TValue> ToDictionary<TKey, TValue>([TupleElementNames(new[] { \"Key\", \"Value\" })] this IEnumerable<(TKey Key, TValue Value)> source) where TKey : notnull;\n    public Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> source, IEqualityComparer<TKey>? comparer) where TKey : notnull;\n    public Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> source) where TKey : notnull;\n    public Dictionary<TKey, TValue> ToDictionary<TKey, TValue>([TupleElementNames(new[] { \"Key\", \"Value\" })] this IEnumerable<(TKey Key, TValue Value)> source, IEqualityComparer<TKey>? comparer) where TKey : notnull;\n\n    public HashSet<TSource> ToHashSet<TSource>() for IEnumerable<TSource> source;\n    public HashSet<TSource> ToHashSet<TSource>(IEqualityComparer<TSource>? comparer) for IEnumerable<TSource> source;\n\n    public List<TSource> ToList<TSource>() for IEnumerable<TSource> source;\n\n    public ILookup<TKey, TElement> ToLookup<TSource, TKey, TElement>(Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector) for IEnumerable<TSource> source;\n    public ILookup<TKey, TElement> ToLookup<TSource, TKey, TElement>(Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey>? comparer) for IEnumerable<TSource> source;\n\n    public ILookup<TKey, TSource> ToLookup<TSource, TKey>(Func<TSource, TKey> keySelector) for IEnumerable<TSource> source;\n    public ILookup<TKey, TSource> ToLookup<TSource, TKey>(Func<TSource, TKey> keySelector, IEqualityComparer<TKey>? comparer) for IEnumerable<TSource> source;\n\n    public bool TryGetNonEnumeratedCount<TSource>(out int count) for IEnumerable<TSource> source;\n    \n    public IEnumerable<TSource> Union<TSource>(IEnumerable<TSource> second) for IEnumerable<TSource> first;\n    public IEnumerable<TSource> Union<TSource>(IEnumerable<TSource> second, IEqualityComparer<TSource>? comparer) for IEnumerable<TSource> first;\n\n    public IEnumerable<TSource> UnionBy<TSource, TKey>(IEnumerable<TSource> second, Func<TSource, TKey> keySelector) for IEnumerable<TSource> first;\n    public IEnumerable<TSource> UnionBy<TSource, TKey>(IEnumerable<TSource> second, Func<TSource, TKey> keySelector, IEqualityComparer<TKey>? comparer) for IEnumerable<TSource> first;\n\n    public IEnumerable<TSource> Where<TSource>(Func<TSource, bool> predicate) for IEnumerable<TSource> source;\n    public IEnumerable<TSource> Where<TSource>(Func<TSource, int, bool> predicate) for IEnumerable<TSource> source;\n\n    public IEnumerable<(TFirst First, TSecond Second, TThird Third)> Zip<TFirst, TSecond, TThird>(IEnumerable<TSecond> second, IEnumerable<TThird> third) for IEnumerable<TFirst> first;\n    public IEnumerable<(TFirst First, TSecond Second)> Zip<TFirst, TSecond>(IEnumerable<TSecond> second) for IEnumerable<TFirst> first;\n    public IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> resultSelector) for IEnumerable<TFirst> first;\n}\n"
  },
  {
    "path": "meetings/2024/LDM-2024-10-14.md",
    "content": "# C# Language Design Meeting for October 14th, 2024\n\n## Agenda\n\n- [Extensions](#extensions)\n\n## Quote of the Day\n\n- \"I know I might be jinxing myself by saying this\"\n- \"That is _not_ the quote of the day\"\n- \"I think it would be a little narcissistic if I was my favorite person.\" \"Oh, I would totally say that though. That's why I shouldn't be anybody's favorite, because I'm my favorite person. I'm just a terrible narcissist.\"\n- \"That is _also_ not the quote of the day\"\n\n## Discussion\n\n### Extensions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/5497  \nRelated: https://github.com/dotnet/csharplang/blob/d5b8e7808998024e4aa6b380acdccac30aa03b60/proposals/extensions_v2.md, https://github.com/dotnet/csharplang/blob/1e8255a438517bc3ad067c726c28cfa20cb60f1e/meetings/working-groups/extensions/Compatibility%20through%20coexistence%20between%20extension%20types%20and%20extension%20methods.md\n\nWe started today by making sure that everyone has clarity on the different approaches here, devoting the first section of the meeting to that. To help with that, we did an exercise on\n\"converting\" LINQ to the respective new forms. The fully compatible version is [here](LDM-2024-10-14-Enumerable-extensions.cs), and the least compatible version is\n[here](LDM-2024-10-14-Enumerable-extension.cs). One thing that this revealed is that there's a difference in philosophy between the two approaches that can be expressed with one letter.\nThe fully compatible version is `extensions`, where it's a collection of different extensions for various types. The least compatible version is `extension`, where the user is writing an\nextension to a given type, extending with a bunch of new members.\n\nOne of the things that was brought up in response to this exploration is some concern that maybe the smaller, special cases for slightly different receivers aren't all that uncommon. In a type\nfirst approach, each of these small special cases would need its own container name; is it that uncommon that someone might want to have a series of extensions on a generic type, and then\nalso one or two extensions on a specific substitution of that generic type? Should those latter two need their own container to be declared? A member first approach would not require this,\nbut a type first approach would.\n\nWe also discussed a bit about generic properties and operators. Adding generics in these locations would be new, and require its own set of designs; what if we avoided this by saying that,\nif a user wants to put a generic in a place it can't go today, would they need to use a type-centric approach? IE, this would ensure that if a user wanted to want an extension property on\n`List<T>`, they would need to use a type extension, and couldn't use a member extension. This was pushed back on as a bad place to put the cliff; the underlying type being generic is a\nrather arbitrary place to put the line, and it would mean that LINQ couldn't use the member centric approach.\n\nWe also looked at possible other forms of syntax. One possibility is a grouping syntax like:\n\n```cs\nextension E\n{\n    for IEnumerable<T> where T\n    {\n        public void M1() { ... }\n    }\n\n    for IList<T> where T\n    {\n        public void M2() { ... }\n    }\n}\n```\n\nWe're unsure what this would imply: would people think that it adds a local type parameter to the methods, or to the containing type, or to some other nebulous area? One of the reasons\nwe're so cautious here is that C# has, to this point, not really messed with the basic metadata of signatures. Type parameters appear in IL exactly where they appear in syntax, parameters\nappear in IL where they appear in syntax, and so on. The only times we violate this are areas that cannot be part of any public API, such as lambdas and local functions. This would be a\nnew type of modification, so we're wary to start down the path.\n\nAnother point we thought about is human compatibility, not just source/binary compatibility. Our users know what modifiers on a parameter mean. They know what method type parameters are.\nThey know how to say that a nullable value is accepted for a given parameter. A type based approach that still allowed adjusting these things would require a new set of syntax to do the\nsame thing that users already know how to do, which isn't great for overall language cohesiveness.\n\nThe LDM currently has a slight leaning towards the member based approach here, but plenty of us are still unsure and need more time to think about this. So once again, we will come back\nto this again in a future meeting.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-10-16.md",
    "content": "# C# Language Design Meeting for October 16th, 2024\n\n## Agenda\n\n- [Simple lambda parameters](#simple-lambda-parameters)\n- [Unbound generic types in `nameof`](#unbound-generic-types-in-nameof)\n- [`typeof` string constants](#typeof-string-constants)\n\n## Quote(s) of the Day\n\n- \"Wacky Generics is the name of my new band focused on kids music.\"\n- \"Today is apparently an 'everyone is in violent agreement' day.\" \"And let me tell you how this solves extensions\"\n- \"Thanks <redacted> for bringing more controversy. It was too easy, we needed something to rile people up.\"\n\n## Discussion\n\n### Simple lambda parameters\n\nChampion issue: https://github.com/dotnet/csharplang/issues/338  \nQuestions: https://github.com/dotnet/csharplang/blob/53a58b04790ab20fadb7214827de3a91fe828121/proposals/simple-lambda-parameters-with-modifiers.md#open-ldm-questions\n\nWe started today by looking at a simple proposal that we've previously approved and trying to answer a few open questions that came up during implementation.\n\nFor the first question, on types named `scoped`, we're ok with breaking that in simple lambda parameters. We've previously done that in cases like `record` and `required`, and it makes\nsense to do so here as well. We also don't think the case is pathological, like `field`, and we already warn on types named with all lowercase characters anyway.\n\nFor the second question, we're fine with accepting the recommendation of the implementation. The previous support for attributes on simple lambda parameters was intentional, and it would\nbe weird to end up in another location where we'd fall off the cliff to full parameters, rather than fixing that too.\n\n#### Conclusion\n\nBoth recommendations are accepted; we will now interpret `scoped` as a modifier for simple lambda parameters, not a type name, and we will allow attributes on simple lambda parameters.\n\n### Unbound generic types in `nameof`\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8480\n\nWe went through this new proposal. We're generally fine with it, but the implementation hasn't been rigorously reviewed yet. Given that, we're not 100% certain that all the semantic dark\ncorners that were previously mentioned have been fully solved. We're fine with the spec as is if a rigorous review finds that it satisfies all of these corners, but if it doesn't, then we\napprove a more limited form in principle, where we cut off those dark corners and simply make them an error for our future selves to solve.\n\n#### Conclusion\n\nApproved in principle. If the implementation proves to be much more challenging than it currently appears, we will make those more challenging locations an error.\n\n### `typeof` string constants\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8505\n\nFinally today, we did a bit of triage, and looked at this proposal on allowing a limited constant expression form for the fully qualified metadata name string. One immediate concern we have\nis that the format here is not documented; in fact, some constrained environments in the past have actually stripped out reflection APIs entirely. We're also not particularly sure about\nthe scenarios that would require this to be a constant; attributes, for example, could just take a `Type` instead, rather than needing to take the full name of the type. That is far more\nrobust, as it's an assembly-qualified name that then causes the runtime to probe for that exact type, while a string that lacks assembly qualification is ambiguous. Instead, we think that\nan easy option here is a source generator where the user puts a `[GenerateTypeName<MyType>()]` attribute on a class, and a source generator fills in a partial part with a constant string\nrepresenting the full type name. We're not unsympathetic to more general constant evaluation in C#, but this is too narrow of a usecase to drive it.\n\n#### Conclusion\n\nRejected.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-10-28.md",
    "content": "# C# Language Design Meeting for October 28th, 2024\n\n## Agenda\n\n- [Increment and Decrement Operators in null conditional access](#increment-and-decrement-operators-in-null-conditional-access)\n- [`yield` in `try` / `catch`](#yield-in-try--catch)\n\n## Discussion\n\n### Increment and Decrement Operators in null conditional access\n\nChampion issue: https://github.com/dotnet/csharplang/issues/6045  \nSpec: https://github.com/dotnet/csharplang/blob/28d016c4d9fc8cbbedfeb75c539e6bebbedc4292/proposals/null-conditional-assignment.md#incrementdecrement-operators\n\nAn issue came up during implementation of null conditional access, which allows null conditionals as the target of an assignment.\n\nThe question is whether to allow prefix/postfix increment/decrement operators, and the proposal is not to allow them. The alternative when increment or decrement is needed is to use compound assignments. Technically, the prefix operators would be difficult, and the outcome may not be what the programmer anticipated. Doing postfix, but not prefix operators may seem odd.\n\n#### Conclusion\n\nWe decided to disallow these operators. If folks find scenarios where they need these operators, we might revisit this decision in the future.\n\n### `yield` in `try` / `catch`\n\nChampion Issue: https://github.com/dotnet/csharplang/issues/8414  \nSpec: https://github.com/dotnet/csharplang/pull/8413\n\nThe proposal is to allow `yield` inside `try`/`catch` blocks in iterators, which is a longstanding user request. There are challenges, both technically and in matching programmer expectations. These particularly arise during `dispose`. The proposal is for only `finally` blocks, and not `catch` blocks to execute during dispose, even when an error is thrown in the `finally` block.\n\nWe went through the details of the behavior, and there are concerns that the programmer may expect `catch` to be executed during dispose. We also discussed the behavior of `yield` during dispose.\n\nNo conclusion was reached. We'll reconsider this in a future meeting after offline work and discussions.\n\n"
  },
  {
    "path": "meetings/2024/LDM-2024-10-30.md",
    "content": "# C# Language Design Meeting for October 30th, 2024\n\n## Agenda\n\n- [Extensions](#extensions)\n\n## Quote of the Day\n\n- \"Part of me wants to trust you <redacted>, but part of me does not\" \"I would recommend not\"\n\n## Discussion\n\n### Extensions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/5497  \nDocuments:\n* https://github.com/dotnet/csharplang/blob/e84c2c9711c269243bb2084700512e3f002fec8b/meetings/working-groups/extensions/extensions-an-evolution-of-extension-methods.md\n* https://github.com/dotnet/csharplang/blob/e84c2c9711c269243bb2084700512e3f002fec8b/meetings/working-groups/extensions/compromise-design-for-extensions.md\n\nToday, we took a look at another set of proposals around moving forward on extension types; one taking a more member-centric approach, and the other taking a more type-centric\napproach. These proposals also tried to lay out visions for how we might balance tradeoffs. Most the meeting was simply spent reading over and clarifying these proposals. We\nalso went and collected some statistics around extensions from a few popular libraries, using https://github.com/DustinCampbell/ExtensionMethodDumper. This data covers how many\ntypes are used as a `this` parameter in a given extension type. If we then assume that each of those static classes would need to be split up into extension types for each receiver,\nwe get:\n\n* .NET libraries: 496 types goes to 1165 types. Ratio: 2.35\n* ASP.NET: 536 types goes to 640: Ratio 1.19\n* Roslyn: 782 types goes to 1753 types: Ratio 2.24\n* FluentAssertions: 43 types goes to 170 types: Ratio 3.95\n\nFluentAssertions is a particular outlier in our data here. More than half of that increase comes from a single type, `FluentAssertions.AssertionExtensions`, which has 85 receiver\ntypes on 97 methods.\n\nAnother point that was brought up during the meeting is that we're trying to weigh several different types of \"complexity\", given our existing language. A type-based extension\nworld would very likely require fewer overall concepts in the language, if we were starting from scratch. However, we're not starting from scratch; we're starting from C# as it\nexists. We already have member-based approaches in the language, and repurposing them may give us a future with a lower concept count given where we're starting.\n\nThis gives us a lot more to think about, so we'll come back in a couple of weeks to discuss yet again.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-11-04-patterns.md",
    "content": "Levi [pointed out](https://github.com/dotnet/roslyn/issues/75506) that many users misunderstand the precedence of `not` and `or` pattern combinators and write faulty code as a result.\nHe found many instances on GitHub and internally.\n\nFor example: `is not 42 or 43` or `is not null or Type`.  \nIn such cases, the `or` pattern is superfluous.  \nThe user most likely intended to write `is not (42 or 43)` or `is not (null or Type)` instead.\n\nWe considered two possible solutions:  \n1. a syntax analyzer that would require parens on either the `not` or around the `or`, so that precedence is explicit\n2. a compiler diagnostic when we can detect that the `or` was redundant in a `not ... or ...` pattern (the goal would be to catch the most common cases, not necessarily 100%)\n\nI'm pursuing the latter (PR).  \nThe diagnostic is implemented as a regular warning, so it introduces a compat break.  \nFor example: `is not 42 or 43 // warning: the pattern 43 is redundant. Did you mean to parenthesize the `or` pattern?`\n\nNote: we're okay with catching specific/known bad patterns, and do not require to catch every possible bad pattern.\n\nFew questions:  \n1. confirm we prefer this compiler-based detection over an analyzer\n2. confirm that a regular warning (ie. compat break) is preferrable to a warning-wave warning or a LangVer-gated warning\n\n\nNote: here are some examples where the `or` pattern is not redundant, which Levi saw in the wild and internally:  \n`is not BaseType or DerivedType`  \n`is not bool or true`  \n`is not object or { Prop: condition }`  \n`is not { Prop1: condition } or { Prop2: condition }`  \n`is not Type or Type { Prop: condition }`  \n"
  },
  {
    "path": "meetings/2024/LDM-2024-11-04.md",
    "content": "# C# Language Design Meeting for November 4th, 2024\n\n## Agenda\n\n- [`not` and `or` patterns](#not-and-or-patterns)\n- [Notes on notes](#notes-on-notes)\n\n## Quote of the Day\n\n- \"Whoever fixed the team room, thanks for helping it see sharp.\" \"[unamused] No\"\n\n## Discussion\n\n### `not` and `or` patterns\n\nIssue: https://github.com/dotnet/roslyn/issues/75506  \nDocument: [LDM-2024-11-04-patterns.md](LDM-2024-11-04-patterns.md)\n\nToday, we took a look at an issue with precedence in `not` patterns, when combined with `or` patterns. This is an area where unfortunate Englishisms get in the way of understanding\nsyntax; when a native English-speaking person says \"x is not 1 or 2\", they usually mean that x is not 1, and it's also not 2. However, C# uses the same precedence as\nthe standard unary operators for the pattern operators, so the same thing written in a pattern actually means `x is (not 1) or 2`. Our initial hope was that this would not be a\nmajor issue. However, we now have good evidence that it is; in internal scans, the error rate was nearly 90%. While we certainly can't go change the precedence from the past, we\nthink that we can detect this and introduce a warning for the scenario. We will issue a warning when a `not` pattern causes a subsequent `or` pattern to be subsumed; while we\nwouldn't mind extending subsumption to an entire pattern, not just for this specific scenario, we think that will be significantly more complicated, and we don't want to delay\nfixing this.\n\n#### Conclusion\n\nWe will add a warning for when a `not` pattern causes a subsequent `or` pattern to be subsumed.\n\n### Notes on notes\n\nThe outcome of this session was a restructure of how we approach record-keeping on csharplang. The results were documented in the process changes in\n[this PR](https://github.com/dotnet/csharplang/pull/8578), with the goal to improve the visibility of issue status on the repo.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-11-13.md",
    "content": "# C# Language Design Meeting for November 13th, 2024\n\n## Agenda\n\n- Extensions\n\n## Quote(s) of the Day\n\n- \"These were my opinions, or at least they were a week ago\"\n- \"What's the entymology of rathole?\" \"It's etymology\" \"Oh right, entymology is the study of living trees\" \"You just caused my brain to segfault\"\n\n## Discussion\n\n### Extensions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/5497  \nDocuments:\n* https://github.com/dotnet/csharplang/blob/e84c2c9711c269243bb2084700512e3f002fec8b/meetings/working-groups/extensions/anonymous-extension-declarations.md\n* https://github.com/dotnet/csharplang/blob/e84c2c9711c269243bb2084700512e3f002fec8b/meetings/working-groups/extensions/extending-extensions-a-guide-to-relaxation.md\n\nWe once again return to extensions, today with a compromise proposal to rule them all: a grouping approach that allows many of the advantages of the type-based approach\n(lack of repeating types, appears closer to a regular member definition) while also giving us the flexibility of the member-based approach, where a single `Extensions`\ntype can contain all of a user's extensions. After going through the proposal, we were overall very positive on the approach, and think we have something specific that\nwe can start to solve specific problems in and flesh out more. We noted a few things that need to be thought about more:\n\n* There's a bit of split-brain logic going on with the receiver parameter in the proposal. It's referred to as `this` in member bodies, but the attribute syntax uses\n  `param`. It's also referable to with parameter modifiers in the `extension` block, which looks like a parameter declaration. Which is it; `this`, or a parameter? While\n  there's definitely some amount of hybridization going on here, we think we want to lean towards the `param` side, rather than the `this` side, because parameter names\n  an provide valuable context. For example, `source` and `destination` are likely clearer names for a mapping method than `this` and `destination`.\n* Along similar lines, how is the receiver documented in XMLDoc?\n* Not an issue, but we pointed out that this proposal does not permit new forms of generic specialization: it does not allow indexers to take generic type parameters, for\n  example.\n\nAfter this discussion, we were able to come to a few key decisions that will help us flesh out this proposal further.\n\n#### Conclusions\n\n* We want to be able to generate compatible extension methods with this syntax. We're not committing to absolute 100% compatibility with existing extension methods, but\n  we'd like to be able to express 99% of existing extension methods in the new format.\n* Along similar lines, we think we should generate visible methods from extension declarations.\n* Finally, we think that we should lean more towards treating the receiver as a parameter, rather than as `this`, for the next iteration of the proposal.\n\n\n"
  },
  {
    "path": "meetings/2024/LDM-2024-11-20.md",
    "content": "# C# Language Design Meeting for November 20th, 2024\n\n## Agenda\n\n- [Extensions](#extensions)\n- [Dictionary Expressions](#dictionary-expressions)\n\n## Quote of the Day\n\n- \"I don't think we should go boldly, I think we should boldly go\"\n\n## Discussion\n\n### Extensions\n\nChampion Issue: https://github.com/dotnet/csharplang/issues/5497  \nDocument: https://github.com/dotnet/csharplang/blob/a372f702e6f8f8fbbb0845611715cbfe4450cbd5/meetings/working-groups/extensions/extension-members-unified-proposal.md\n\nToday, we looked through the unified extension proposal to see whether the compiler team can move forward in this general direction. While we're not fully agreed on precise syntax here,\nwe are agreed that this proposal, and the semantics that it implies, are the way forward for extensions in C#. There are a few things that definitely need to be directly addressed around\nthe compat story. There was lots of uneasiness about using `this` as the indicator for backwards compatible generation. Nothing about the keyword implies compatibility, so we think that\nit's likely too \"cute\" and we need a different approach. In particular, there's some thought that we could just always emit in the legacy format, rather than forcing users to understand\nhow or why they might want to do this.\n\n#### Conclusion\n\nGeneral proposal is accepted.\n\n### Dictionary Expressions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8659  \nSpecification: https://github.com/dotnet/csharplang/blob/a372f702e6f8f8fbbb0845611715cbfe4450cbd5/proposals/dictionary-expressions.md  \nOpen question: https://github.com/dotnet/csharplang/blob/a372f702e6f8f8fbbb0845611715cbfe4450cbd5/proposals/dictionary-expressions.md#question-types-that-support-both-collection-and-dictionary-initialization\n\nFinally, we went over the proposal to add dictionary expressions to the language. Like extensions, we know that there's still plenty of design work to do here, but we want enough of a\nspecification agreed on that the compiler team can start work and discover the more interesting questions. We spent quite a bit of time on key comparers, and there's clearly more design\nwork that needs to happen before the LDM is ready to fully approve the direction. We are in general agreement that allowing users to provide a comparer to a dictionary expression is part\nof the \"minimum required feature set\" before dictionary expressions can be shipped; what we're not in agreement about is how we should go about doing that. We brainstormed several different\nsyntaxes, such as `new(...) with [... elements]`, `[.. elements] with (Comparer)`, `[comparer; .. elements]`, `[comparer: comparerInstance, .. elements]`, and others. Nothing clearly stuck\nout as being a preference, so more design will be needed. Additionally, we're unsure whether we should just limit to a key comparer, or whether we should extend to general arguments. For\nexample, `ImmutableDictionary` takes both key and value comparers, should we have a way to set both? What about something like `HashSet`, which isn't a \"dictionary\"; should there be a way\nto provide a comparer to that type? While we don't necessarily think such support is part of a minimum bar, we do want to make sure that we're keeping such support in mind and not designing\nsomething that can't be extended to support these scenarios.\n\nWe also took a first look at the question on \"hybrid\" types, that support both the standard collection expressions and dictionary expression semantics. We are very unsure as an LDM at this\npoint. We don't have good examples of where these patterns might exist, or a good understanding of _whether_ these patterns exist in practice. Therefore, we don't have a good feel for which\nis generally the more prominent part of such a type's design: collectionness, or dictionaryness. To give the compiler team a direction, we'll start with dictionaryness for now, as there's a\nvery slightly leaning in that direction among LDM members, but we'll definitely need to revisit this in the future.\n\n#### Conclusion\n\nGeneral proposal is accepted. More work will need to happen on dictionary construction arguments and hybrid type semantics.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-12-04.md",
    "content": "# C# Language Design Meeting for December 4th, 2024\n\n## Agenda\n\n- [First-class span open questions](#first-class-span-open-questions)\n    - [Preferring `ReadOnlySpan<T>` over `Span<T>` conversions](#preferring-readonlyspant-over-spant-conversions)\n    - [Conversions in expression trees](#conversions-in-expression-trees)\n\n## Quote of the Day\n\n- \"Anything else for you?\"\n\n## Discussion\n\n### First-class span open questions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8714  \n\n#### Preferring `ReadOnlySpan<T>` over `Span<T>` conversions\n\nSpec: https://github.com/dotnet/csharplang/blob/1754aaafffe270c19d8578af30a2eb768de3ee49/proposals/first-class-span-types.md#prefer-converting-from-t-to-readonlyspant-over-spant-in-overload-resolution\n\nThe first issue we looked at today was around how array covariance can impact conversions to `Span<T>`. Because .NET has array\ncovariance, the conversion from an array to a `Span<T>` has to check to make sure that the array is a `T[]`, not some subtype\nof `T[]`; if this is the case, then the conversion will throw. This is a footgun for usages of this implicit conversion, and\none that was hit immediately on upgrade to C# 14 preview by Roslyn because of the triplet of `IEnumerable<T>`, `Span<T>`, and\n`ReadOnlySpan<T>` in test assert APIs. It is fairly common for some expected data to be an array of some specific subtype, while\nthe actual data being converted is a supertype. Previously this would have gone through `IEnumerable<T>`, which was perfectly\nfine with covariant arrays. `Span<T>` is now the preferred overload, and that isn't fine with covariant arrays.\n\nThis issue, where an implicit conversion can throw, isn't entirely new to the language; after all, `dynamic` can be implicitly\nconverted to any type, and that can throw. But it is likely more prominent than `dynamic`, as with that feature, the user usually\nintentionally started at `dynamic` and went to a specific type, rather than starting at array and then invisibly going to a `Span<T>`\nwhere `IEnumerable<T>` used to be fine. While we don't think that we have reason to entirely remove the array->`Span` conversion\nfrom the feature, we do think that this merits some work to make sure that when there is a safer conversion available that likely\nhas the same intended meaning, we prefer that conversion instead.\n\nThe proposal here is to make `ReadOnlySpan<T>` preferred over `Span<T>` for first-class span. From an immediate type theory\nperspective, this is an exception how most-specific type normally works. Since `Span<T>` can be converted to `ReadOnlySpan<T>`,\nbut not the other way around, our standard most-specific type logic would indicate that `Span<T>` should be preferrable. However,\nfor these types of APIs that overloaded across `Span<T>` and `ReadOnlySpan<T>`, we think that the only reason they're overloaded\nis because we currently _don't_ have first-class spans as a language feature. Both overloads were added to make the API usable,\nbut the only thing the API needs is read access, and the `Span<T>` API usually just forwards to the `ReadOnlySpan<T>` version.\nThe only time this reasoning doesn't hold up is when we consider extension methods across multiple different types; such overloads\ncould indeed have different behavior, where one overload really does need mutable access, while the other only reads from the array.\nDespite this, we think the overall feature is better served by preferring `ReadOnlySpan<T>` over `Span<T>`.\n\nWe also considered the question of whether we should take a bigger step. Our proposed rules only impact when arrays are converted\nto span types. This is yet another element to a decoder ring, another special case that users need to know to understand how\noverload resolution will be applied to their APIs. Could we instead make a broader, simpler rule, where we just always prefer\n`ReadOnlySpan<T>` over `Span<T>`? We don't think we have enough data to make such a decision today. We don't know of any APIs that\nthis would negatively affect, but more investigation needs to be done before making a call.\n\nFinally on this topic, we considered how restrictive to make the preference on type parameters. It seems a little suspicious to\nus to prefer `ReadOnlySpan<object>` over `Span<string>`; can we really make the assertions we said earlier about the expected behavior\nof the API for this type of shape? We'll investigate this as well, and see whether there are examples of this pattern in the wild.\n\n##### Conclusion\n\nWe adopt the rule preferring `ReadOnlySpan<T>` over `Span<T>` for array conversions. We will investigate broader rules as well, and\ntheir potential impact on the BCL.\n\n#### Conversions in expression trees\n\nSpec: https://github.com/dotnet/csharplang/blob/1754aaafffe270c19d8578af30a2eb768de3ee49/proposals/first-class-span-types.md#ignore-span-conversions-in-expression-trees\n\nOur last topic of the day was considering whether we should try and handle the conversion specially in expression trees, as this\ncan be a breaking change. We had a\n[similar discussion](https://github.com/dotnet/csharplang/blob/1754aaafffe270c19d8578af30a2eb768de3ee49/meetings/2024/LDM-2024-06-17.md#params-span-breaks)\nwith `params ReadOnlySpan`, and we continue to find our reasoning from that issue compelling. Therefore, we will not make any\nchanges to how binding occurs in expression trees; they will potentially pick up new span-based overloads and users may have to\ninsert explicit casts to get old behavior back.\n\n##### Conclusion\n\nNo special cases for expression trees.\n"
  },
  {
    "path": "meetings/2024/LDM-2024-12-09.md",
    "content": "# C# Language Design Meeting for December 9th, 2024\n\n## Agenda\n- [First-class span open questions](#first-class-span-open-questions)\n- [Simple Lambda Parameters](#simple-lambda-parameters)\n- [Collection expression arguments](#collection-expression-arguments)\n\n## Quote of the Day\n\n- \"Array covariance is like spice girls, no one admits to liking them but someone is buying the albums\"\n\n## Discussion\n\n### First-class span open questions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8714  \nSpec diff: https://github.com/dotnet/csharplang/commit/7e964ef0ca8620eb4e7129396e867059d6c26be4#diff-e5dfbc21202c1a2f879f6221ecd9105efde1815d69cbe2db81189b1a667db328\n\nFirst up today, we took a look at the specific proposed wording for our rule from [last time](LDM-2024-12-04.md#preferring-readonlyspant-over-spant-conversions).\nWe're happy with this direction, though the specific wording needs to be reworded: by the proposed rule, multiple bullets could be true at the same time in opposite\ndirections, leading to an ambiguity. The intent behind the rule, though is correct and agreed on. We continue to stand by our reasoning that `ReadOnlySpan` should\nbe preferred over `Span`, and the intent of these rules is to enable precisely that.\n\n#### Conclusion\n\nDirection is approved, modulo a bit of wordsmithing to remove ambiguities.\n\n### Simple Lambda Parameters\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8637  \nOpen questions: https://github.com/dotnet/csharplang/blob/9cca9e78ac7c35af896bf4643a5c3cd2aef828b2/proposals/simple-lambda-parameters-with-modifiers.md#open-questions\n\nNext, we took a look at a couple of open questions for simple lambda parameters. The first seemed reasonable; making the definition of `scoped` depend on whether\nthere's a default value for the parameter seems much worse to us than a minor breaking change that we've already made in other locations. However, the second question\nis more thorny. After discussion, we realized that we don't have an intuition of what `params` and `scoped` will do in terms of overload resolution. Will it cause\noverloads to be thrown out? Or will it only have an impact after an overload has been chosen, potentially issuing an error because the modifier can't be applied\nto the parameter? We're not comfortable making a decision with an imprecise understanding of the consequences today. Therefore, we'll come back next time with a\ncomplete understanding of the rules that are being proposed and figure out if we need to cut any modifiers at that point.\n\n#### Conclusion\n\n`scoped` break is approved in theory, but we'll come back next time to determine if we will include `scoped` and `params` in this work.\n\n### Collection expression arguments\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8887  \nSpec: https://github.com/dotnet/csharplang/blob/9cca9e78ac7c35af896bf4643a5c3cd2aef828b2/proposals/collection-expression-arguments.md\n\nFinally, we took a look at a proposed extension to collection expressions, that will also be used for dictionary expressions. We didn't have enough time left to get\ninto specifics of the proposal; the proposed syntax, in particular, didn't resonate with a lot of the LDM. In particular, we think this may be too indirect of a\nusage of `with`, as it's not really related to the current usage of `with` in the language. However, we think there's promise in the general idea, and want to move\nforward with the idea. We'll work on syntax at a later point.\n\n#### Conclusion\n\nGeneral feature is approved to move forward, with the specifics to be discussed in the coming months.\n"
  },
  {
    "path": "meetings/2024/README.md",
    "content": "# C# Language Design Notes for 2024\n\n### Mon Dec 9, 2024\n\n[C# Language Design Meeting for December 9th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-12-09.md)\n\n- First-class span open questions\n- Simple Lambda Parameters\n- Collection expression arguments\n\n### Wed Dec 4, 2024\n\n[C# Language Design Meeting for December 4th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-12-04.md)\n\n- First-class span open questions\n    - Preferring `ReadOnlySpan<T>` over `Span<T>` conversions\n    - Conversions in expression trees\n\n### Wed Nov 20, 2024\n\n[C# Language Design Meeting for November 20th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-11-20.md)\n\n- Extensions\n- Dictionary Expressions\n\n### Wed Nov 13, 2024\n\n[C# Language Design Meeting for November 13th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-11-13.md)\n\n- Extensions\n\n### Mon Nov 4, 2024\n\n[C# Language Design Meeting for November 4th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-11-04.md)\n\n- `not` and `or` patterns\n- Notes on notes\n\n### Wed Oct 30, 2024\n\n[C# Language Design Meeting for October 30th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-10-30.md)\n\n- Extensions\n\n### Mon Oct 28, 2024\n\n[C# Language Design Meeting for October 28th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-10-28.md)\n\n- Increment and Decrement Operators in null conditional access\n- `yield` in `try` / `catch`\n\n### Mon Oct 21, 2024\n\nCanceled\n\n### Wed Oct 16, 2024\n\n[C# Language Design Meeting for October 16th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-10-16.md)\n\n- Simple lambda parameters\n- Unbound generic types in `nameof`\n- `typeof` string constants\n\n### Mon Oct 14, 2024\n\n[C# Language Design Meeting for October 14th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-10-14.md)\n\n- Extensions\n\n### Wed Oct 9, 2024\n\n[C# Language Design Meeting for October 9th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-10-09.md)\n\n- Extensions\n\n### Mon Oct 7, 2024\n\n[C# Language Design Meeting for October 7th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-10-07.md)\n\n- Extensions\n\n### Wed Oct 2, 2024\n\n[C# Language Design Meeting for October 2nd, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-10-02.md)\n\n- Open questions in field\n    - `readonly` contexts and `set`\n    - `Conditional` code\n    - Interface properties and auto-accessors\n- Extensions\n\n### Mon Sep 30, 2024\n\n[C# Language Design Meeting for September 30th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-09-30.md)\n\n- Extensions\n\n### Wed Sep 25, 2024\n\n- C# 14 (no notes)\n\n### Mon Sep 23, 2024\n\n- *Design review* (no notes)\n\n### Wed Sep 18, 2024\n\n[C# Language Design Meeting for September 18th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-09-18.md)\n\n- Nullability in `field`\n- Extensions naming\n\n### Wed Sep 11, 2024\n\n[C# Language Design Meeting for September 11th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-09-11.md)\n\n- Better conversion from collection expression and `params` collections\n- First-class span types\n    - `Reverse`\n    - New ambiguities\n    - Covariant arrays\n\n### Wed Sep 4, 2024\n\n[C# Language Design Meeting for September 4th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-09-04.md)\n\n- Triage (no milestone)\n    - Type inference using method group natural type\n    - Collection Expressions Next (C#13 and beyond)\n    - Dictionary expressions\n    - Extending patterns to \"as\"\n    - `params in` parameters\n- Triage (working set)\n    - Only Allow Lexical Keywords in the Language\n    - Permit variable declarations under disjunctive patterns\n    - CallerCharacterNumberAttribute\n    - `Task<T>` nullability covariance\n    - Nullable analysis of LINQ queries\n\n### Wed Aug 28, 2024\n\n[C# Language Design Meeting for August 28th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-08-28.md)\n\n- Nullable in `ref` ternaries\n- Block-bodied switch expression arms\n\n### Mon Aug 26, 2024\n\n[C# Language Design Meeting for August 26th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-08-26.md)\n\n- `field` keyword open questions\n    - `field` in property initializers\n    - Interaction with partial properties\n    - `readonly` field\n\n### Wed Aug 21, 2024\n\n[C# Language Design Meeting for August 21st, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-08-21.md)\n\n- Better conversion from collection expression\n- `field` keyword nullability\n\n### Mon Aug 19, 2024\n\n[C# Language Design Meeting for August 19th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-08-19.md)\n\n- Better conversion from collection expression\n\n### Wed Aug 14, 2024\n\n[C# Language Design Meeting for August 14th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-08-14.md)\n\n- `field` keyword\n    - `field` nullability\n    - `field` in event accessor\n    - Scenarios similar to `set;`\n\n### Wed Jul 24, 2024\n\n[C# Language Design Meeting for July 24th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-07-24.md)\n\n- Discriminated Unions\n- Better conversion from collection expression with `ReadOnlySpan<T>` overloads\n\n### Mon Jul 22, 2024\n\n[C# Language Design Meeting for July 22nd, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-07-22.md)\n\n- Extensions\n- Ref structs implementing interfaces\n\n### Wed Jul 17, 2024\n\n[C# Language Design Meeting for July 17th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-07-17.md)\n\n- Overload resolution priority open questions\n- Better conversion from collection expression with `ReadOnlySpan<T>` overloads\n\n### Mon Jul 15, 2024\n\n[C# Language Design Meeting for July 15th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-07-15.md)\n\n- `field` keyword\n- First-Class Spans Open Question\n\n### Wed Jun 26, 2024\n\n[C# Language Design Meeting for June 26th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-06-26.md)\n\n- Extensions\n\n### Mon Jun 24, 2024\n\n[C# Language Design Meeting for June 24th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-06-24.md)\n\n- First-Class Spans\n- `field` questions\n    - Mixing auto-accessors\n    - Nullability\n\n### Mon Jun 17, 2024\n\n[C# Language Design Meeting for June 17th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-06-17.md)\n\n- `params` Span breaks\n- Overload resolution priority questions\n    - Application error or warning on `override`s\n    - Implicit interface implementation\n- Inline arrays as `record struct`s\n\n### Wed Jun 12, 2024\n\n[C# Language Design Meeting for June 12th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-06-12.md)\n\n- `params Span` breaks\n- Extensions\n\n### Mon Jun 10, 2024\n\n[C# Language Design Meeting for June 10th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-06-10.md)\n\n- `ref struct`s implementing interfaces and in generics\n\n### Mon Jun 3, 2024\n\n[C# Language Design Meeting for June 3rd, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-06-03.md)\n\n- Params collections and dynamic\n- Allow ref and unsafe in iterators and async\n\n### Wed May 15, 2024\n\n[C# Language Design Meeting for May 15th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-05-15.md)\n\n- `field` and `value` as contextual keywords\n  - Usage in `nameof`\n  - Should `value` be a keyword in a property or indexer get? Should `field` be a keyword in an indexer?\n  - Should `field` and `value` be considered keywords in lambdas and local functions within property accessors?\n  - Should `field` and `value` be keywords in property or accessor signatures? What about `nameof` in those spaces?\n- Dictionary expressions\n\n### Mon May 13, 2024\n\n[C# Language Design Meeting for May 13th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-05-13.md)\n\n- First-class span types questions\n    - Delegate conversions\n    - Variant conversion existence\n- Overload resolution priority questions\n    - Attribute shape and inheritance\n    - Extension overload resolution\n\n### Wed May 8, 2024\n\n[C# Language Design Meeting for May 8th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-05-08.md)\n\n- `readonly` for primary constructor parameters\n\n### Wed May 1, 2024\n\n[C# Language Design Meeting for May 1st, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-05-01.md)\n\n- Adjust binding rules in the presence of a single candidate\n\n### Wed Apr 24, 2024\n\n[C# Language Design Meeting for Apr 24th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-04-24.md)\n\n- Adjust dynamic binding rules for a situation of a single applicable candidate\n\n### Mon Apr 22, 2024\n\n[C# Language Design Meeting for Apr 22nd, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-04-22.md)\n\n- Effect of language version on overload resolution in presence of `params` collections\n- Partial type inference: '_' in method and object creation type argument lists\n\n### Wed Apr 17, 2024\n\n[C# Language Design Meeting for Apr 17th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-04-17.md)\n\n- Relax `Add` requirement for collection expression conversions to types implementing `IEnumerable`\n- Extensions\n\n### Mon Apr 15, 2024\n\n[C# Language Design Meeting for Apr 15th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-04-15.md)\n\n- Non-enumerable collection types\n- Interceptors\n- Relax `Add` requirement for collection expression conversions to types implementing `IEnumerable`\n\n### Mon Apr 8, 2024\n\n[C# Language Design Meeting for Apr 8th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-04-08.md)\n\n- Implementation specific documentation\n\n### Mon Apr 1, 2024\n\n[C# Language Design Meeting for Apr 1st, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-04-01.md)\n\n- Async improvements (Async2)\n\n### Wed Mar 27, 2024\n\n[C# Language Design Meeting for Mar 27th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-03-27.md)\n\n- Discriminated Unions\n\n### Mon Mar 11, 2024\n\n[C# Language Design Meeting for Mar 11th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-03-11.md)\n\n- Dictionary expressions\n\n### Mon Mar 4, 2024\n\n[C# Language Design Meeting for Mar 4th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-03-04.md)\n\n- Breaking changes: making `field` and `value` contextual keywords\n- Overload resolution priority\n\n### Wed Feb 28, 2024\n\n[C# Language Design Meeting for Feb 28th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-02-28.md)\n\n- Extensions\n\n### Mon Feb 26, 2024\n\n[C# Language Design Meeting for Feb 26th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-02-26.md)\n\n- `ref struct`s in generics\n- Collection expressions\n\n### Wed Feb 21, 2024\n\n[C# Language Design Meeting for Feb 21st, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-02-21.md)\n\n- Declaration of ref/out parameters in lambdas without typename\n- `params` collections\n    - Metadata format\n    - `params` and `scoped` across `override`s\n    - `required` members and `params` parameters\n\n### Wed Feb 7, 2024\n\n[C# Language Design Meeting for Feb 7th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-02-07.md)\n\n- Partial type inference\n- Breaking change warnings\n\n### Mon Feb 5, 2024\n\n[C# Language Design Meeting for Feb 5th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-02-05.md)\n\n- First-class span types\n- Collection expressions: inline collections\n\n### Wed Jan 31, 2024\n\n[C# Language Design Meeting for January 31st, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-01-31.md)\n\n- Relax \"enumerable\" requirement for collection expressions\n- `params` collections evaluation orders\n\n### Mon Jan 29, 2024\n\n[C# Language Design Meeting for January 29th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-01-29.md)\n\n- `params` collections\n  - Better function member changes\n  - `dynamic` support\n- `dynamic` and `ref` local function bugfixing\n\n### Mon Jan 22, 2024\n\n[C# Language Design Meeting for January 22nd, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-01-22.md)\n\n### Wed Jan 10, 2024\n\n[C# Language Design Meeting for January 10th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-01-10.md)\n\n- Collection expressions: conversion vs construction\n\n### Mon Jan 8, 2024\n\n[C# Language Design Meeting for January 8th, 2024](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-01-08.md)\n\n- Collection expressions\n    - Iteration type of `CollectionBuilderAttribute` collections\n    - Iteration type in conversions\n"
  },
  {
    "path": "meetings/2025/LDM-2025-01-06.md",
    "content": "# C# Language Design Meeting for January 6th, 2025\n\n## Agenda\n\n- [Ignoring `ref struct`s in `Expression`s](#ignoring-ref-structs-in-expressions)\n- [Extensions](#extensions)\n\n## Quote of the Day\n\n- \"I'm also of many minds on this, maybe more than 2\"\n\n## Discussion\n\n### Ignoring `ref struct`s in `Expression`s\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8714  \nProposal: https://github.com/dotnet/csharplang/blob/1393601a2a4c45222f027983a248a08996d8ff05/meetings/working-groups/ref-improvements/ignore-overloads-in-expressions.md\n\nToday, we looked at a proposal to change how overload resolution works in expression trees. This isn't a step we want to\ntake lightly; our previous positions here, such as for `params ReadOnlySpan`, has been to let them exist, and then error if they\ncouldn't be used. Unfortunately in this case, there's a very good chance that instead of being a compile-time error, it will end\nup being a runtime error instead. This has happened in the past, but as we increase our usage of `ref struct`s in C#, it keeps\ncoming up; the latest example is first-class spans, which causes breaks in the EF query provider when unexpected versions of\nquery methods get called. There are three options:\n\n1. We could make overload resolution in expression trees in expression trees ignore `ref struct`s, as this proposal suggests.\n2. We could more strongly enforce the restriction on `ref struct`s in expression trees, and error when one is used implicitly,\n   like in these scenarios.\n3. Do nothing and have EF's query provider understand the new methods.\n\nOf these options, the only one we're ok with is option 3. For option 1, it will break scenarios that work perfectly fine today;\nindirect usage of `ref struct`s can often work in `Expression`s that are compiled on CoreCLR. For option 2, it will force all of\nour users to update their code to handle the new breaking change. For 3, it does mean that some users who are on older versions of\nEF will face runtime errors when they update to C# 14, but don't update their reference to EF. However, those users will face such\nissues in general, not just because of increased `ref struct` issues. For example, EF is adding support for new types of joins,\nexpressed through new query methods, and older query providers cannot handle those new methods just as they cannot handle these\n`ref struct` overloads. We do not think that it is burdensome to ask EF to handle these new overloads, and thus that is our plan.\n\n#### Conclusion\n\nProposed change is rejected. We will make no changes to how overload resolution in expression trees occurs.\n\n### Extensions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8697  \nProposal: https://github.com/dotnet/csharplang/blob/dc2672a9fb93dc2c5d782b3c5600eea469a9c581/meetings/working-groups/extensions/extension-member-disambiguation.md\n\nFinally today, we looked at a proposal for how we might introduce a generalized disambiguation syntax. While this is useful for\nextensions, we think it may also be more generally useful, such as allowing calling default interface members from class members.\nWhile LDM likes the general direction, there was a lot of mixed feedback on the specific syntax forms shown here. Two potential\nalternative directions were brought up:\n\n* Use `in` instead of `as`, `at`, or `@`. This may more clearly define that we are looking for a specific member as implemented\n  _in_ a specific type.\n* Change the paradigm to instead qualify the member, rather than the receiver. For example, `e.(MyExtension.Prop)` or \n  `e1 (MyExtension.+) e2`. This may better qualify that the member is being bound in a specific manner, rather than the receiver.\n\nA number of LDT members liked this second direction, but it will introduce some challenges for things such as constructors, which\ndon't have a syntax that can be referred to after a `.` today. `MyExtension.new` is a possibility, but we'll have to consider more.\nUltimately, we didn't come to any conclusions today, and will revisit again in a future meeting.\n\n#### Conclusion\n\nNo conclusion here today.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-01-13.md",
    "content": "# C# Language Design Meeting for January 13th, 2025\n\n## Agenda\n\n- [Discriminated Unions](#discriminated-unions)\n\n## Quote of the Day\n\n- \"I'm apparently nothing\"\n\n## Discussion\n\n### Discriminated Unions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8928  \nProposal: https://github.com/dotnet/csharplang/blob/b6d1f4b3d132ce648299c75f3b9e2961151996b0/proposals/TypeUnions.md  \nWorking Group Status: https://github.com/dotnet/csharplang/blob/b6d1f4b3d132ce648299c75f3b9e2961151996b0/meetings/working-groups/discriminated-unions/Union%20implementation%20challenges.md\n\nToday we heard from the discriminated unions working group, which has been hard at work exploring the various tradeoffs of how\ndifferent types of union structures can be implemented in C#. We started with a refresher of the various options, and worked in\nexplanations of the tradeoffs the group has discovered. On the whole, we agree with the conclusions of the group; there is some\ndifference in opinion on the severity of some of the pitfalls, such as the `OfType<Cat or Dog>()` issue in adhoc unions, but\nwe don't have any additional cases or examples to add to the group's conclusions. We are very much in favor of proceeding with a\nsingle part of the proposal; while we want to keep the other parts in mind during design to ensure that we can add them at a later\ndate and have them still feel at home in the language, we view unions as a feature that we can and should deliver over time, rather\nthan all at once, much as we have done with patterns. Therefore, we will proceed with deep design work on just class unions for\nnow, drilling deep into just that section and working on a design that has the detail level necessary to be implemented in the\nlanguage. We want to make sure that, even if v1 of the feature doesn't have a story to grow from a simple union declaration to full\nclasses with the ability to declare members, implement interfaces, etc., that there is a plan for how to get that full\nfunctionality in the future.\n\n#### Conclusion\n\nWe will proceed with in-depth design work on class unions.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-01-15.md",
    "content": "# C# Language Design Meeting for January 15th, 2025\n\n## Agenda\n\n- [`fieldof`](#fieldof)\n- [Simple lambda parameters](#simple-lambda-parameters)\n- [Interpolated string handler method names](#interpolated-string-handler-method-names)\n\n## Quote of the Day\n\n- \"First mute of 2025. Made it to 1/15. New record.\"\n\n## Discussion\n\n### `fieldof`\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9031  \nSpecification: https://github.com/dotnet/csharplang/blob/7bf02aafb8fc623b5d21075514440b7e9fd4d94c/proposals/fieldof.md\n\nWe started today by looking a proposal around backing field access outside of a property accessor. This scenario is being driven\nprimarily through a few early adopters of the `field` feature, and the scenarios are interesting enough that we think exploration\nof the area is worth it. However, LDM is much more mixed on this specific solution; several members were unsure of how well `fieldof`\nfit in with `typeof` and `nameof`, and felt that it was too specialized to this specific problem, and not obvious where it should\nend. One other option we floated was the ability to specify both `init` and `set`, so a property could look like this:\n\n```cs\npublic int Prop\n{ \n    get;\n    private init;\n    set => SetAndNotifyIfChanged(ref field, value);\n}\n```\n\nThere are definitely some issues to work out with such a proposal, but we like that it seems more generalizable and fits in better\nwith property declarations today. We didn't conclude on this topic today, but will come back in a future LDM after exploring this\nsecond approach more.\n\n#### Conclusion\n\nThis proposal will go into the working set to be actively considered.\n\n### Simple lambda parameters\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8637\nSpec: https://github.com/dotnet/csharplang/blob/7bf02aafb8fc623b5d21075514440b7e9fd4d94c/proposals/simple-lambda-parameters-with-modifiers.md#open-questions\n\nWe picked this up from the [last time](../2024/LDM-2024-12-09.md#simple-lambda-parameters) simple lambda parameters came up, around\nwhether `scoped` or `params` should be allowed without a type. These modifiers are slightly different on their impact: `params`\ncan only impact the call site, while `scoped` impacts both the call site and the body of the lambda. We're ok with `scoped`, because\nof that reason. However, we're not ok with `params`; it can never narrow overload resolution, and we'll have to do extra checks to\nmake sure that `params` is allowed with the type that is inferred. Rather than having that extra check and potential for confusion,\nwe think it's a better idea to simply disallow `params` without a type. If we ever hear from users that this would be useful, we can\nrevisit at that point.\n\n#### Conclusion\n\nWe allow `scoped` to be used without an explicit type. We forbid `params` without an explicit type.\n\n### Interpolated string handler method names\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9046  \nSpecification: https://github.com/dotnet/csharplang/blob/a970d01597886d84d7498e1b6a9d8e8e8ebf02c1/proposals/interpolated-string-handler-method-names.md\n\nFinally today, we started triage for some newer issues. For this one, we think that we need a full hour in LDM to debate the\napproach and alternatives, but are interested in moving forward, so it will go into the `Working Set` milestone.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-01-22.md",
    "content": "# C# Language Design Meeting for January 22nd, 2025\n\n## Agenda\n\n- [Partial events and constructors](#partial-events-and-constructors)\n- [Collection expression arguments](#collection-expression-arguments)\n- [Extensions disambiguation syntax](#extensions-disambiguation-syntax)\n\n## Quote of the Day\n\n- Nothing particularly amusing or memorable today, sorry\n\n## Discussion\n\n### Partial events and constructors\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9058  \nSpecification: https://github.com/dotnet/csharplang/blob/305c5195ce36c9fe66e83235a15c5b9b885e77ab/proposals/partial-events-and-constructors.md\n\nFirst up today, we did a very quick check in on partial events and constructors. When we looked at partial properties in C# 13,\nwe gave a brief consideration of the remaining member types, but decided to wait until we had use cases. We now have those use\ncases, and we agree that they're sufficient motivation and validation to move forward with. We'll review the complete\nspecification at a later point, but this proposal is approved and moved into Working Set.\n\n#### Conclusion\n\nApproved, moved into Working Set\n\n### Collection expression arguments\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8887  \nSpecification: https://github.com/dotnet/csharplang/blob/305c5195ce36c9fe66e83235a15c5b9b885e77ab/proposals/collection-expression-arguments.md#construction\n\nNext, we took a look at some of the semantics around collection expression arguments. We did not go over syntax today; that will\nbe saved for a future LDM. Instead, we wanted to unblock the implementation's thornier semantic questions around overload\nresolution. We had no comments on the standard constructor scenario; it seemed fine. What was more controversial were the second\nand third scenarios. For the `Create` method scenario, there's a concern that some of the existing methods that the BCL would\nwant to use are not in the form that the proposal requires: some of them use `params`, so their collections are the last argument\nto the `Create` method, not the first. While the BCL _could_ add another method that just reorders the parameters, we're not a\nfan of the idea; we may want to relax the requirements here to allow those methods. We then looked at interface implementations,\nand whether we want to expose \"constructors\" for collection expressions target-typed to these interface types. Unfortunately, one\nthing that came during discussion here is a discrepancy in the checked-in specification and the notes; the notes from\n[August 9th](../2023/LDM-2023-08-09.md#target-typing-of-collection-expressions-to-core-interfaces) indicate that we don't guarantee\nwhat the underlying type of these interfaces is, while the checked-in specification appears to reflect an older initial approach\nfrom the working group that guaranteed the concrete type to be `List<T>`. We didn't fully debate the implications of this\ndiscrepancy on the current proposal, but the LDM did tend to lean either towards exposing the underlying constructors of the used\ntype, or to simply stating that a few constructors were presumed to exist, regardless of the underlying type that ends up being\nused. For now, the group will proceed in that direction, and we'll need to bring this back again for further discussion to confirm.\nFinally, we thought briefly about `dynamic` arguments; we don't see any current use cases, and think that there are going to be\nsome particularly gnarly challenges (for example, if we allow `Create` methods to have the collection either before or after the\nother arguments, how does that impact dynamic binding?). Given this, we will block it for now.\n\n#### Conclusion\n\nConstructor rules are approved. `Create` rules are approved, with some caveats that we may need to bring back a looser version\nafter we do more investigation in the BCL for `Create` methods we want to approve. The implementation will proceed with interface\nconstructors for now, but will need to come back to ratify the decision and determine exactly how this works in the future.\n`dynamic` arguments are disallowed.\n\n### Extensions disambiguation syntax\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8697  \nSpecification: https://github.com/dotnet/csharplang/blob/e145230405eabef04a460003a20825fecce7f4d5/proposals/extensions.md  \nSyntax examples: https://github.com/dotnet/csharplang/blob/8e5e055737bf8f278adf79176fdd370708e23d23/meetings/working-groups/extensions/disambiguation-syntax-examples.md\n\nIn our last topic for the day, we dived right into syntax options for disambiguating extension types.\n[Last time](LDM-2025-01-06.md#extensions) we talked about syntax, we decided we wanted to explore member-focused approaches, and\nsee what that ended up looking like. Now we're back with the results of those explorations, and it runs into a few problems.\nSpecifically, there are some types of members that just don't have existing ways of being referred to in C#. For example,\nindexers, constructors, operators, and casts cannot be captured into method references today, and we'd have to invent a new\nsyntax to even permit them to be referenced. This causes the member-focused approach to be fairly heavy-weight; it's a big piece\nof new syntax for a scenario we don't expect will be used much. One possible view is that this syntax could be viewed more broadly;\nwhat if we were to use this syntax to allow taking references to members that cannot be referenced today? That would bring\nunification to the feature and help justify the weight of the new syntax forms. However, we're not certain that this is a road\nwe want to go down, and are wary of even more scope creep on the extensions feature. We're pretty split on this approach.\n\nWe then looked at the other example forms that were brought. The LDM is fairly split on the casting form; some think it's a natural\nextension, others think that it's too far removed from the existing meaning of casting, as it does not modify the receiver.\nAdditionally, there is no real opportunity for a cast-like syntax to be useful to other disambiguation scenarios, such as calling\na DIM or an explicit implementation on a `struct` without boxing. Invocation-like syntax was more positively received, as was\n`in` and `at`. `using` was pretty strongly disliked for introducing yet _another_ new meaning for `using`, which is already\nheavily overloaded. `@` was also concerning for what impacts it could have on other tooling ecosystems such as Razor.\n\nWe did consider a couple more approaches that were not in the document as well:\n\n* Could we allow `using MyExtension { range.Where (i => i < 10); }`? This is not a _new_ meaning for `using`, it's just a new\n  location that an existing import syntax can be used. This is still potentially quite confusing, however, so we're not\n  enamored with it.\n* What if we just leaned into the static-method nature and just required disambiguation to call using the emitted name. For\n  example, `range = MyExtension.op_Plus(range, 5);`. This has the advantage of requiring absolutely no new syntax, but does mean\n  that we need to lean further into the \"this is just sugar over static methods\" approach.\n\nUltimately, we did not make a final decision today. We've expressed some initial opinions, and will come back later with\nrefinements. Ultimately, we do not think an initial preview of extensions is gated on this decision, so we are fine with not\nhaving a concrete syntax today.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-02-12.md",
    "content": "# C# Language Design Meeting for February 12th, 2025\n\n## Agenda\n- [User-defined instance-based operators](#user-defined-instance-based-operators)\n- [Left-right join in query expressions](#left-right-join-in-query-expressions)\n\n## Quote of the Day\n\n- \"That's how I shall influence the LDM, with cats. Unless you're a dog person, in which case that's terrible.\"\n\n## Discussion\n\n### User-defined instance-based operators\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9101  \nSpecification: https://github.com/dotnet/csharplang/blob/5a627e44b33f6c8765f11f3007de379b526684a0/proposals/user-defined-compound-assignment.md\n\nWe started today by reviewing the proposal for user-defined compound assignment, which we are looking at for the first time. As we went over the spec, we had a couple of\nconcerns around corner cases with instance vs static operators: we don't want type authors to accidentally push their users into odd scenarios where a `+=` may work, but\n`+` won't (or vice versa) because one form declares extra operators than the other. Other than that, though, we think this is an excellent proposal, and will move forward\nwith it.\n\n#### Conclusion\n\nProposal is approved.\n\n### Left-right join in query expressions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8947  \nSpecification: https://github.com/dotnet/csharplang/blob/5a627e44b33f6c8765f11f3007de379b526684a0/proposals/left-right-join-in-query-expressions.md\n\nFinally today, we looked at a proposal for a new LINQ query-syntax operator. There's concern here, both in the LDM and in the discussion thread, about where the line for\nnew features is. We can't really avoid query providers failing on these new joins; the methods will exist in the BCL regardless, and various query providers might fail on\nthem no matter what. While query syntax support might widen that gap, it's very possible that lack of it will hurt users who need the new operator more than it would cause\nusers to hit query provider errors, since users who need this will have to drop the entire query back to method syntax. Given this, we're cautiously optimistic about moving\nforward with this. We may want to expand further in the future; for example, C# does not support `distinct` in query syntax today, like VB does, but if increased `join`\noptions are successful, that may be enough of a signal to add further operators; conversely, if this ends up causing significant increases in errors for users and lots of\npain, we know that further changes here are harder than they appear at first glance. The LDM is unanimously in favor of moving forward with this, and a slight majority\nthink we should try to get it in for C# 14, to coincide with the new methods being added to the BCL.\n\n#### Conclusion\n\nWe will proceed with this proposal, hopefully in the C# 14 timeframe (barring any other time constraints).\n"
  },
  {
    "path": "meetings/2025/LDM-2025-02-19.md",
    "content": "# C# Language Design Meeting for February 19th, 2025\n\n## Agenda\n\n- [Extensions](#extensions)\n\n## Quote of the Day\n\n- \"But, SHOULD we throw the baby out with the bath water?\"\n\n## Discussion\n\n### Extensions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8697  \nSpecification: https://github.com/dotnet/csharplang/blob/e25de8eaaa30470ecd1202c1b1ce840512b0ff0c/proposals/extensions.md  \nReviewed document: https://github.com/dotnet/csharplang/blob/e25de8eaaa30470ecd1202c1b1ce840512b0ff0c/meetings/working-groups/extensions/extensions-lookup.md\n\nToday, we went over continuing proposals for how to do extension method lookup. This topic is both persistent and difficult, particularly since how extension method\nlookup was originally specified is not how it was actually implemented. As originally specified, extension methods invoked in extension form would have been subject\nto a 2-phase lookup approach, where first the receiver is used to find compatible extension methods, and then overload resolution would be performed among those\nmethods. As the LDM, we generally prefer this approach; it is the most consistent with how lookup works for actual instance members. It would also ensure that\n\"weird\" results, like the `out` examples shown in [extensions-lookup], behave as a user might naively expect, failing to unify because the extension is being\ncalled on `I<string>`, not `I<object>`. This potentially gets even more odd for static scenarios:\n\n```cs\nvar e = IEnumerable<string>.M(out object o); // What type is e? Does this line compile?\n\npublic static class Ext\n{\n    extension<T>(IEnumerable<T>)\n    {\n        public static IEnumerable<T> M(out T t) => ...;\n    }\n}\n```\n\nHowever, in C# 3.0, this is _not_ what was implemented. The examples in [extensions-lookup] do not error, they compile, giving `IEnumerable<object>` as the\nreceiver type. Given the 20 years of history here, and how any change to lookup is nearly certain to break _someone_, we don't feel comfortable breaking existing\nextension methods, and may even want to simply update the specification to cover what was really implemented in C# 3.0, rather than what was originally intended.\nFurther, every attempt we've made during the design process of new extensions at breaking compatibility has led to us scaling back the breaks. At this point,\nwe're aware of 3 major categories of extension methods that cannot be ported to the new syntax form 1-1 given the current design:\n\n1. Generic extensions that have a receiver that uses one or more of the type parameters and, at the call site, specify the type arguments. This is because they must\n   specify _all_ the type arguments, including any for the receiver, and that's not possible with the current design, as the receiver type parameters cannot be\n   specified.\n2. Generic extensions that have a receiver that uses one or more of the type parameters and specify their type parameters in a non-idiomatic order. For example, a\n   hypothetical `TReturn Select<TReturn, TThis>(this TThis t, Func<TThis, TReturn> selector)`. We are not aware of real-world examples of this pattern, and are more\n   comfortable ignoring it.\n3. The `out` inference issue that was brought up today.\n\nWe are, at the very least, concerned about categories 1 and 3. Given this, we want the working group to investigate what a compatibility mechanism would look like\nthat handles these cases, potentially by changing how lookup works for such members, and whether we can get to a place that needs no explicit compatibility switch,\nbut instead bakes the compatibility into the language.\n\n[extensions-lookup]: https://github.com/dotnet/csharplang/blob/e25de8eaaa30470ecd1202c1b1ce840512b0ff0c/meetings/working-groups/extensions/extensions-lookup.md#aligning-with-implementation-of-classic-extension-methods\n"
  },
  {
    "path": "meetings/2025/LDM-2025-02-24.md",
    "content": "# C# Language Design Meeting for February 24th, 2025\n\n## Agenda\n\n- [Extensions](#extensions)\n- [Interpolated string handler method names](#interpolated-string-handler-method-names)\n\n## Quote of the Day\n\n- Nothing particularly funny was said today, sorry.\n\n## Discussion\n\n### Extensions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8697  \nSpecification: https://github.com/dotnet/csharplang/blob/3ee9dcaae3800cdbbf16bc50dffc483de16576af/proposals/extensions.md  \nReviewed document: https://github.com/dotnet/csharplang/blob/3ee9dcaae3800cdbbf16bc50dffc483de16576af/meetings/working-groups/extensions/Extension-API-docs.md\n\nToday, we took a break on extensions from talking about deep philosophical questions, to simply looking at what the docs team is proposing for how new extensions\nare going to be displayed. Unfortunately, a few of the major decisions that we still need to resolve around compat will likely impact what the docs team displays;\ncan they just always use the new format, or will knowing whether an extension is new or old style be relevant to a user? That will hold up some of their work, but\nwe otherwise don't have any particular notes on the current proposal.\n\n### Interpolated string handler method names\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9046  \nSpecification: https://github.com/dotnet/csharplang/blob/a970d01597886d84d7498e1b6a9d8e8e8ebf02c1/proposals/interpolated-string-handler-method-names.md\n\nFinally, we took a look at this proposal around expanding interpolated string handler arguments to handle a logging scenario. There's consternation among the LDM\naround the relative lack of purity in this approach; after all, names aren't the real thing that the type author wants, it's the log level. And it would potentially\nlimit reuse of handlers built with this approach, since users who want to reuse such handlers from the BCL would need to name their methods exactly as the BCL methods\nare named, otherwise it wouldn't work. On the other hand, some members of the LDM are concerned about the investment here, and whether we're going to reach our old\nstandby of 100 points digging further into this problem. The existing workaround of copy/pasting the handler 7ish times isn't pretty, but these handlers are not a\nlarge maintenance burden and are not touched very often after creation, and this approach _would_ provide that reusability guarantee that the BCL needs. Given the\ndivide on this issue, then, we'll put it into the \"Needs Work\" milestone, and if we have time in the future, we might consider revisiting it; at that point, we can\ncompare what the more complex solution would look like with the simple approach in this proposal.\n\n#### Conclusion\n\nNeeds work. If we find time to look at alternatives, we may bring them back in the future.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-02-26.md",
    "content": "# C# Language Design Meeting for February 26th, 2025\n\n## Agenda\n\n- [Extensions](#extensions)\n\n## Quote of the Day\n\n- \"I tried to chase the pony... the lesson is that it's too hard.\" \"I think that's the thing that scared me about this, we kept coming up with examples where the pony got hurt.\"\n\n## Discussion\n\n### Extensions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8697  \nSpecification: https://github.com/dotnet/csharplang/blob/688ef1e9d1646597f2be9dd56b674a06b0f20c13/proposals/extensions.md  \nReviewed document: https://github.com/dotnet/csharplang/blob/688ef1e9d1646597f2be9dd56b674a06b0f20c13/meetings/working-groups/extensions/implicit-compatibility-for-ported-extension-methods.md\n\n[Last time](./LDM-2025-02-19.md#extensions), we asked the working group to go look at compatibility mechanisms for bridging old extension lookup and new extension\nlookup, and to come back with the implications of this. The working group has done so, and we are looking at the results of that investigation today. The first thing\nthat we wanted to be clear about is that the potential breaks listed here aren't exhaustive: they're what we've found so far, some of them even as recently as the\nmorning of the meeting. We do think that these breaks are likely to be edge cases in general, but we can't claim that for certain.\n\nWe ultimately need to decide on what form of semantics we want to go with for extension lookup. We see 4 different possible options:\n\n1. Use the 2-stage lookup process, and make no attempt to bridge semantics for compat.\n2. Use the 2-stage lookup process, and have an explicit opt-in for users to get compat.\n3. Use the 2-stage lookup process, and have an implicit fixup for compat.\n4. Use the 1-stage lookup process, which comes with built-in compat because it's the same lookup process as existing extensions.\n\nWe're particularly concerned about user experience in the future of C# here. We don't want to get to a world in 5 years where users need to understand the difference\nbetween old and new extensions, when to prefer the newer form over other, what overload resolution minutiae apply to either form, how to document the old form vs\nthe new form, etc. We think any of the first two has that problem: authors will either need to know when to pick one or the other, or they will need to know when to\nopt-in to compat. Further, the users of libraries will need to know whether they are using the old or new extension form, which means figuring out a way to document\nthis. Option 3 would be nice if we could figure it out, but we think we've sufficiently proven that this would be extremely difficult.\n\n4 does mean that we abandon some niceties that we'd get with a new form. For example, it means that we couldn't let type parameters that come from the receiver of\nan extension method be inferred. However, we have a separate proposal (https://github.com/dotnet/csharplang/issues/8968) for allowing some type parameters to be\ndropped, and it would be more broadly applicable. Given all of this, we prefer option 4, and will proceed with having new instance extension methods use the same\nlookup algorithm that current instance extensions use.\n\n#### Conclusion\n\nInstance extension methods in `extension` blocks will use the same lookup mechanism as current extension methods do.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-03-03.md",
    "content": "# C# Language Design Meeting for March 3rd, 2025\n\n## Agenda\n\n- [Extensions](#extensions)\n\n## Quote(s) of the Day\n\n- \"Ah ... you all think I'm a person and not a robot\" \"You've always passed the Turing test, as far as I can tell.\" \"So can ChatGPT\"\n- _deep conversation on when an extension is actually an extension_ _lemur yell in the room as a phone notification_ \"What was that?! It sounded like a fire alarm!\" _more pandemonium occurs_\n\n## Discussion\n\n### Extensions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8697  \nSpecification: https://github.com/dotnet/csharplang/blob/975ef97651519ccfdcb569c92c74d695afc054c1/proposals/extensions.md\n\nToday, we looked at more open issues in extensions. This time, we looked at a few specific questions from the proposal.\n\n#### Static method overloading\n\nQuestion: https://github.com/dotnet/csharplang/blob/975ef97651519ccfdcb569c92c74d695afc054c1/proposals/extensions.md#metadata  \n> We should follow-up on \"factory scenario\" where multiple extension declarations have static factory methods with same parameter types but different return types.\n\nThis scenario looks something like this:\n\n```cs\npublic static class Factory\n{\n    extension(A)\n    {\n        public static A Create() => ...;\n    }\n\n    extension(B)\n    {\n        public static B Create() => ...;\n    }\n}\n```\n\nBy the existing rules, this would be blocked: C# methods cannot differ just by return type (though they can in IL). There may even be\nscenarios where two static methods on different underlying types may have exactly the same signature, with the same return type, which\nis definitely not expressible in IL without help, namely in the form of a `modopt` or `modreq` on the signature to differentiate them.\nIf we wanted to try and allow this in the future via `modopt`/`modreq`s on the return type, we would have to start doing that now; it is\na binary-breaking change to change the `modopt`/`modreq`s on a member, and we do not want to end up in a scenario where a user might\nbreak binary compat simply by adding an entirely unrelated member. There's also a concern that using `modopt`s would mean that you can't\nmove from an extension static method to a regular static method (or vice versa) without a binary break. Making the static extension\nmember a regular static member on the type (perhaps in response to a downstream library adding the method you were polyfilling) would\nbecome a binary breaking change, and we have some hesitance about doing that. Another option would be to mangle the names of these members\nsomehow, however we think that these static extension members should be speakable for disambiguation purposes, and we don't want to have\nto expose some bespoke mapping from what appears to be a standard static method to a complex naming scheme.\n\nPart of what's driving this scenario is that `extension` blocks _feel_ like different scopes. They have braces, so we believe that it's\nnatural to assume that you can overload across them without issue. This does break down somewhat when examined closely: you can have\nmultiple extension blocks for the same type, so would that mean that each block can overload on the same extended type? However, this\nnatural inclination seems somewhat reasonable to us, as does having a single static class devoted to having factory methods for a number\nof different underlying types. Given this, we want to explore the `modopt` approach. The working group will do so, and come back to us\nwith the consequences of this decision. That being said, we do feel that we are leaning towards blocks not actually being different\nscopes. They do seem like it at first glance, but the decisions we've made around them so far are leaning towards them not being real\nscopes.\n\n#### Method and property resolution\n\nQuestion: https://github.com/dotnet/csharplang/blob/975ef97651519ccfdcb569c92c74d695afc054c1/meetings/working-groups/extensions/extensions-lookup.md#extension-methods-proposal  \n\nNext, we turned our attention to member lookup, especially for `static` methods, and for when properties are combined with methods.\nWe largely agree with the rules proposed, and our discussion from the first question and from [last time](./LDM-2025-02-26.md#extensions).\nWe want these to be standard methods, so applying standard rules in other aspects makes sense and is consistent. We value that consistency\nargument, and so we want to use the same rules as much as possible. This means standard lookup for static extensions scenarios, and if\nlookup finds both properties and methods in the same set, that's an error. We can potentially look at improvements to the method vs\nproperty scenario later, if we find that it is a problem in practice, but we don't expect it to be. We'll have a formal specese version\nof these rules to review later, but for now, they are tentative accepted as proposed.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-03-05.md",
    "content": "# C# Language Design Meeting for March 5th, 2025\n\n## Agenda\n- [Dictionary expressions](#dictionary-expressions)\n- [Target-typed static member lookup](#target-typed-static-member-lookup)\n\n## Quote of the Day\n\n- \"I'm sure there are some funky types out there like in old .NET\" \"I plead the 5th\"\n- \"Give the dot a shot\"\n\n## Discussion\n\n### Dictionary expressions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8659  \nSpecification: https://github.com/dotnet/csharplang/pull/9158/files#diff-342dab893eaa8c901a2fafe92e2c6c13aaee9e42adcbd9115fac92ac0d1b9a22\n\nWe reviewed the proposed conversion and construction rules for concrete dictionary types that don't use `CollectionBuilderAttribute`.\n\n__The conversion rules__ pertain to how we decide that a given type is a dictionary type. For the pertinent situation, where the type is not an interface and does not provide a `CollectionBuilderAttribute`, the proposal requires the type to have an iteration type of `KeyValuePair<TKey, TValue>` for some `TKey` and `TValue`, as well as a matching get-set indexer.\n\nIf the type explicitly implemented e.g. `IDictionary<TKey, TValue>` we wouldn't recognize it as a dictionary - the type itself needs to have the right members.\n\nWhen a type is a dictionary type, collection expressions will be implemented using its indexer rather than `Add` methods.\n\n__The construction rules__ pertain to how we bind to the indexer on such a type.\n\nFor _key value pair elements_ `e1:e2` the proposal invokes the setter of the best applicable indexer, based on the key and value expressions in each pair. This means that the invoked indexer is not necessarily the one that qualifies the type as a dictionary type in the first place, by the conversion rules above. An alternative would be to always use the indexer that matches the iteration type - the one that made the type a dictionary type.\n\nFor collection expressions we needed more nuance, because there were existing expectations around what would work, based on collection initializers. However, for indexers there is not a corresponding existing initializer case to be consistent with. \n\nFor _expression elements_ `e` and _spread elements_ `..e` the proposed rules require elements to implicitly convert to `KeyValuePair<TKey, TValue>`, exactly matching the iteration type of the dictionary type. There was some concern that this is too restrictive. \n\nA more permissive alternative would be to allow elements to be `KeyValuePair<...>` (\"`KVP`\" for short) with different type arguments, as long as those type arguments are implicitly convertible to `TKey` and `TValue` respectively. This would be restrictive in a different way, since the elements would have to _be_ a KVP, not just implicitly convert to one. This could even lead to breaking changes, where ordinary collection expressions have worked for dictionary types in the past due to user-defined conversions to KVP.\n\nA combined alternative would look for any KVP types that the element is implicitly convertible to, and _if there is exactly one_ check that its type arguments have implicit conversions to `TKey` and `TValue`. This would mitigate the potential breaking change, but searching for a unique implicit conversion seems a bit dubious.\n\n#### Conclusion\n\n* The rules for when a type is considered a dictionary are approved as proposed.\n* The indexer used in dictionary expressions should be the one that qualifies the type as a dictionary type, not the best fit based on overload resolution.\n* In expression and spread elements we'll allow them to be KVPs with different key and value types, as long as those are in turn implicitly convertible to the key and value types of the dictionary. For now the elements have to _be_ KVPs, not just implicitly convertible to them. If that becomes a problem we are open to loosening the rules, but we don't have a good proposal for that yet.\n\n\n### Target-typed static member lookup\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9138  \nSpecification: https://github.com/dotnet/csharplang/blob/e2e957687cf2a165fb1a0fb05f1d72ddfbe8f932/proposals/target-typed-static-member-lookup.md\n\nThe feature allows the static members of a type to be accessed directly without qualification when the expression is target typed by that type:\n\n``` c#\ntype.GetMethod(\"Name\", .Public | .Instance | .DeclaredOnly); // BindingFlags.Public | ...\n```\n\nThe proposal meshes well with some proposals  for discriminated unions, but is useful for today's classes or enums.\n\nIt supports the common case where a type has static members _of_ that type. Enums are common, and nested derived types are a way to express DUs today. Also, special values or factories are often exposed this way.\n\nThis is a place where a lot of redundancy and repetition exists today, especially when types are large and/or generic. Static usings aren't really an adequate response. They bring the members into scope _everywhere_, which can be very noisy, and for generic types they only allow specific instantiations to be included.\n\nUsing a sigil (`.`) in front of the name helps avoid breaking changes or convoluted lookup rules. It helps narrow the field of possible completions and may improve understanding of the code. \n\nAt the same time there's also a lot of resistance to having a sigil instead of just a name. It feels like users may have difficulty realizing _when_ they could choose to use this feature. Without the dot it would feel like the compiler just knows what you mean.\n\nPerhaps there is a path we can take that allows us to get feedback from the ecosystem on this question?\n\nFinally there's also an argument that the whole feature makes code harder to read, and the meaning of names too complex to understand, regardless of syntax.\n\n#### Conclusion\n\nMost of us feel the feature is valuable, and we want to continue investigating and debating. The syntax question is a stumbling block for sure.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-03-10.md",
    "content": "# C# Language Design Meeting for March 10th, 2025\n\n## Agenda\n\n- [Extensions](#extensions)\n    - [Property method calling](#property-method-calling)\n    - [Scoping and Shadowing](#scoping-and-shadowing)\n    - [Type parameter inferrability](#type-parameter-inferrability)\n    - [Accessibility](#accessibility)\n\n## Quote of the Day\n\n- \"We're starting the boring part of the meeting now\"\n\n## Discussion\n\n### Extensions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8697  \nSpecification: https://github.com/dotnet/csharplang/blob/82157ff229f6c1bd2954a96ec2acb47064a48bad/proposals/extensions.md\n\nWe looked at a few questions in extensions today.\n\n#### Property method calling\n\nThe first question we looked at was whether to allow extension property underlying methods to be called directly on an instance. For\nexample:\n\n```cs\n_ = new object().Prop; // Allowed\n_ = C.get_Prop(new object()); // Previously said this is allowed\n_ = new object().get_Prop(); // Should this be allowed?\n\npublic static class C\n{\n    extension (object o)\n    {\n        public int Prop { get => 1; }\n    }\n}\n```\n\nWe're not sure what the use case for this form is. We allow the `get_Prop` syntax on `C` itself to serve as a disambiguation syntax, but\nwe don't know why `get_Prop` should be visible as a method on `object` itself. We don't do this for regular properties, so we don't have a\nreason to allow it for extension properties either. Given this, we will disallow it.\n\n##### Conclusion\n\n`get_Prop` form is disallowed in extension method form.\n\n#### Scoping and Shadowing\n\nNext, we looked at a couple of questions around scoping and shadowing. First, should extension parameter names be in scope in static\nmembers, even if they'd be an error to reference, and even if they shadow a field? And second, should instance methods be able to shadow\nthe extension parameter in their own parameter lists? As an example:\n\n```cs\npublic static class E\n{\n    static string s;\n    extension(string s)\n    {\n        public int M(int i)\n        {\n            return s.Length + i;\n        }\n        public static string P => s; // Does this error that the extension parameter s can't be used, or bind to E.s?\n        public void M2(string s) { ... } // Should we allow this to shadow the extension parameter?\n        public static void M3(string s) { ... } // Should we allow this to shadow the extension parameter, since there's no implicit s?\n        public static void M4() { s.ToString(); } // Does this bind to the extension receiver parameter and error, or to E.s?\n    }\n}\n```\n\nThere are a couple of sets of rules we can look to for inspiration here: existing parameter rules, and primary constructor rules. After\nsome thought, we think existing parameter rules are the right inspiration; as mentioned in the previous topic, we keep leaning further\ntowards the extension block being just another parameter. This means it should follow the same rules for other parameters, and when we\nconsider instance extension methods, `M2` isn't shadowing anything, it's literally declaring 2 parameters with the same name, which is just\nnot permitted by C#'s rules. On the other hand, local functions or lambdas inside `M2` would be allowed to shadow the parameter `s`, just\nlike they can with other parameters today.\n\nMore interesting is the `static` question: should we allow the parameter list in a `static` member to shadow the extension parameter?\nThe LDM is fairly split here between allowing or disallowing it. We therefore think we'll start most restrictive, disallowing the parameter\nlist to shadow, and wait for feedback. There is a workaround for users who want to do this, as they can just declare a new parameterless\nextension block and declare the method in that block, so this isn't a hard blocker for code, but we'd rather start as more restrictive and\nloosen when we have real examples, rather than starting with a loose rule that we may regret later.\n\n##### Conclusion\n\nExtension block parameters will be lexically in scope in all members declared within the block, and will be treated as if they were declared\nin the parameter list of each extension member for the purposes of naming collisions and shadowing.\n\n#### Type parameter inferrability\n\nQuestion: https://github.com/dotnet/csharplang/blob/82157ff229f6c1bd2954a96ec2acb47064a48bad/proposals/extensions.md#extension-declaration-validation (first bullet)\n\nWe next looked at whether we should loosen the requirement that any type parameters in the extension block declaration had to be inferrable\nfrom the extension parameter. We don't think that we have the examples that would be necessary to lift this restriction today: we can think\nof a couple of hypotheticals, such as an out-of-order `TResult, TSource`, or a set of type parameters where `TSource` needed to be\nconstrained based on `TResult`, but we don't have any concrete examples of this. Given that, we think we should start most restrictive, and\nwait for users to bring examples to us.\n\n##### Conclusion\n\nWe will not loosen the restriction, all type parameters in the extension block declaration must be inferrable from the extension parameter.\n\n#### Accessibility\n\nQuestion: https://github.com/dotnet/csharplang/blob/82157ff229f6c1bd2954a96ec2acb47064a48bad/proposals/extensions.md#accessibility\n\nFinally today, we took a brief look at accessibility to get an initial gut feeling. The expressed sentiment in the room leaned towards\n`private` being with respect to the entire static class, not towards an individual extension block, but we did not have time to deeply\ndive into this topic, so no conclusions were made.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-03-12.md",
    "content": "# C# Language Design Meeting for March 12th, 2025\n\n## Agenda\n\n- [Optional and named parameters in expression trees](#optional-and-named-parameters-in-expression-trees)\n- [Collection builder method parameter order](#collection-builder-method-parameter-order)\n- [Ignored directives](#ignored-directives)\n\n## Quote of the Day\n\n- \"I'm here for 5 minutes of [redacted] before everyone gets back!\" _no one speaks for the 5-minute bio break_ \"That was an exciting 5 minutes.\"\n- \"I think we should accept C#'s age of over 25 years and go with octothorpe\"\n\n## Discussion\n\n### Optional and named parameters in expression trees\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9246  \nSpecification: https://github.com/dotnet/csharplang/blob/b200d0a075dbeaff5a5b2eaab7b529102d5483af/proposals/optional-and-named-parameters-in-expression-trees.md\n\nFirst up today, we took a look at a change around expression trees to support something that seems like it should just fall out. This isn't\na broad change, nor is it any kind of new node: it's simply removing an error. Doing searches through the history of C#, we're unsure why\nthis is even restricted in the first place; our notes from the C# 4 timeframe don't indicate that any consideration was put into this\ntopic, and no one still in the LDM who was present at the time can remember any discussions about blocking this. Likely, it was simply\njust forgotten about.\n\nGiven that, we have a few approaches we can take:\n\n1. Do nothing and keep the status quo.\n2. Allow optional arguments. These will be filled in by the compiler, and emitted as if they had been called by the user.\n3. Allow named arguments in-order. These will have no impact on the shape of the tree.\n4. Allow named arguments out-of-order. This would potentially have impacts on the shape of the tree. While we likely could avoid adding\n   new nodes for this, it would mean the compiler would start emitting existing node types that were never emitted before, which would\n   be a breaking change for linq providers.\n\nWe think we're fine with 2, and with 3. 4 is more complicated; the compiler doesn't emit any `BlockExpression`s today, if we were to\nhave the C# compiler support out-of-order named parameters, it would need to do so in order to replicate C# named argument behavior, by\nsaving the out of order results and then passing them to the method call so side effects happen in the correct order. We don't like this,\nand don't think the potential risk is worth it. Therefore, we plan to proceed with options 2 and 3. We don't think 4 is entirely out of\nthe question, but it would need to be a detailed investigation into where and how query providers would break or support this node.\n\n#### Conclusion\n\nWe will allow optional parameters in expression trees, and we will allow named arguments, so long as the arguments are supplied in\nparameter order (a la the C# 7.2 feature rules for non-trailing named arguments).\n\n### Collection builder method parameter order\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8887  \nSpecification: https://github.com/dotnet/csharplang/blob/0d5e1f2c0864e65c6163e4a06405720493ba018a/proposals/collection-expression-arguments.md#collection-builder-method-parameter-order\n\nNext, we looked at a small open question in collection expressions around the `Create` method, and where it will expect parameters to be\nlocated. We have a standard pattern in the BCL for such create methods, which is to have arguments such as the comparator first, and then\nthe actual contents of the collection to be created. We'd prefer to stick with this pattern for now, absent examples that need some other\npattern. If we do find examples that need a different order, we can consider some way for a type author to explicitly indicate which\nparameter is the \"collection contents\" parameter in the future, such as an attribute or other piece of metdata on the parameter. Until we\nhave such examples, though, we'll go with the simple solution of the contents must be the last parameter.\n\n#### Conclusion\n\nThe `ReadOnlySpan` of collection contents must be the last parameter of the `Create` method.\n\n### Ignored directives\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8617  \nSpecification: https://github.com/dotnet/csharplang/blob/a71774147c58d45efb5c6515c41665267684c9c5/proposals/ignored-directives.md\n\nFinally today, we took a look at this proposal for ignored directives. This was a proposal opened a number of years ago in anticipation\nof `dotnet run file.cs` eventually becoming a thing, and now that that effort is moving forward, it's time to talk about how the C# file\nwill interact with this system.\n\nWe want the system to be able to iterate without needing direct input from the compiler for every change. Given that, we think the bespoke\n`#sdk`, `#package`, and other directives shouldn't exist. We also think that just using `#!` for everything is a bad idea; it would\ncomplicate parsing and set up scenarios where the first line of the file isn't actually a valid `#!` directive for running the file.\nFor now, we like the `#:` proposal; use the `#!` directive specifically for shell communication as the first line in the file, and `#:`\nfor SDK communication otherwise. We like the brevity of the directive for this purpose, but would potentially be open to other syntaxes\nbased on feedback from initial usage.\n\n#### Conclusion\n\nWe accept `#!` and `#:` as the directive syntaxes for this feature, and look forward to working with the SDK and ecosystem on driving this\nfeature forward.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-03-17.md",
    "content": "# C# Language Design Meeting for March 17th, 2025\n\n## Agenda\n\n- [Collection expression arguments](#collection-expression-arguments)\n    - [`with` breaking change](#with-breaking-change)\n    - [Collection expression arguments and conversions](#collection-expression-arguments-and-conversions)\n- [Dictionary expressions](#dictionary-expressions)\n- [Extensions](#extensions)\n    - [Accessibility](#accessibility)\n    - [Static factory scenarios](#static-factory-scenarios)\n\n## Quote of the Day\n\n- \"I hope no one was confused by me saying coversion instead of conversion\" \"Contraversion\"\n\n## Discussion\n\n### Collection expression arguments\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8887  \nSpecification: https://github.com/dotnet/csharplang/blob/d139d200cfe8ffe45536cdcc8b17ee7f25b5757b/proposals/collection-expression-arguments.md\n\n#### `with` breaking change\n\nQuestion: https://github.com/dotnet/csharplang/blob/d139d200cfe8ffe45536cdcc8b17ee7f25b5757b/proposals/collection-expression-arguments.md#with-breaking-change\n\nWe started today by looking at whether, and if so where, to take a breaking change around the meaning of `with()` in a collection\nexpression. We don't want `[with(1), with(2)]` to have different meanings for what `with` binds to, so we're ok with a breaking change\nin general. However, we haven't yet had the in-depth debate on whether `with` is the final syntax; given this, we don't want to risk\nanything on lower language versions at this time.\n\n##### Conclusion\n\nWe will take the breaking change around `with` inside a collection expression, but only in language version preview for now.\n\n#### Collection expression arguments and conversions\n\nQuestion: https://github.com/dotnet/csharplang/blob/753119dee9eb5e5a4bd36072559b25d9064c63e6/proposals/collection-expression-arguments.md#should-arguments-affect-collection-expression-conversion\n\nWe think that the precedent around `new()` is good here. It's possible that we could relax the language here in the future, but we think\nthat if we do so, it should be done holistically, for both `new()` and collection expressions, rather than just for collection expressions.\n`new()` doesn't do this because of the concern that it would mean adding a new constructor to a type could become a source-breaking change,\nand we think that we'd have to delve into that concern for both constructs at the same time.\n\n##### Conclusion\n\nCollection expression arguments will not be used as part of determining whether a collection expression conversion exists.\n\n### Dictionary expressions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8659  \nSpecification: https://github.com/dotnet/csharplang/blob/main/proposals/dictionary-expressions.md\nQuestion: https://github.com/dotnet/csharplang/blob/d139d200cfe8ffe45536cdcc8b17ee7f25b5757b/proposals/dictionary-expressions.md#conversion-from-expression-element-for-keyvaluepairk-v-collections\n\nFollowing up from [last time](./LDM-2025-03-05.md#dictionary-expressions), the working group brought a proposal around key/value pair\nconversions in dictionary expressions. We're a bit concerned about the broad applicability of the proposed rules: they block off\nuser-defined conversions when the iteration type is a KVP, even if we're not converting to a dictionary expression. That seems wrong to\nus; the user indicated how to convert a given type to a KVP, so why would we ignore that information? Our desire for covariance in KVP\ndoes make this more complicated than a standard conversion though. For example, what if the type specifies 2 UDCs to different KVP\ninstantiations? Which one would we prefer for a variance conversion to the iteration type? After some discussion, we think that such\n\"multiple conversion path\" types are a sufficiently small corner of a corner that we don't have to worry about it: either better conversion\nwill return an exact conversion to the element type of the collection expression, or we'll get an ambiguity.\n\nWe also briefly re-examined whether we actually want to support these variance scenarios outside of pure dictionary types, and our\nconclusion is that we do. There are thousands of examples of `IEnumerable<KeyValuePair>` APIs on GitHub, for methods that take any form\nof dictionary or list of KVPs, and we would like to support simple syntax for such APIs.\n\n##### Conclusion\n\nWe will allow all standard element type conversions that we allow in normal collection expressions when the element type is a KVP. We will\nallow KVP covariance in all collection expressions.\n\n### Extensions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8697  \nSpecification: https://github.com/dotnet/csharplang/blob/b484275c4369638c2c5f9305716582c76a1c9335/proposals/extensions.md\n\n#### Accessibility\n\nQuestion: https://github.com/dotnet/csharplang/blob/b484275c4369638c2c5f9305716582c76a1c9335/proposals/extensions.md#accessibility\n\nFirst up today, we continued from [a previous LDM](./LDM-2025-03-10.md#accessibility) on the topic of accessibility. We think our initial\ngut feeling was correct; extension blocks are not real items. You can declare multiple extension blocks for a single type, would `private`\nbe private just to a single block, or to all shared blocks? There are also other decisions that we'd need to revisit if we started giving\nblocks a stronger identity here.\n\n##### Conclusion\n\nAccessibility in extension blocks is relative to the containing static class.\n\n#### Static factory scenarios\n\nQuestion: https://github.com/dotnet/csharplang/blob/b484275c4369638c2c5f9305716582c76a1c9335/proposals/extensions.md#static-factory-scenario\n\nThe working group took a look at the [previous decision](./LDM-2025-03-03.md#static-method-overloading) around static method overloading,\nand has come to the conclusion that there are current technical limitations around `modopt`/`modreq`s in the compiler that would make using\nthem to permit overloading here difficult; today, Roslyn does not support using anything but a named type in a `modopt` or `modreq`. This\nis a compiler restriction, not a runtime restriction, but would be a somewhat involved change to fix up. However, we're also questioning\nwhether we should support this type of overloading at all in extensions: sure, we can figure out how to emit such methods, but what would\nthe disambiguation syntax be? We've already walked back from adding new syntax in other places for this, and while we do think that the\nscenario where a user wants to define the same static method on several types isn't unreasonable, we also think that we might be able to\nstart restrictive for a preview period, and then listen for feedback.\n\n##### Conclusion\n\nWe will enforce standard overloading rules across extension blocks, so static methods on different underlying types in the same static class\nwill not be able to share the same name and parameter types.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-03-19.md",
    "content": "# C# Language Design Meeting for March 19th, 2025\n\n## Agenda\n\n- [Readonly setters on non-variables](#readonly-setters-on-non-variables)\n\n## Quote of the Day\n\n- \"Sorry for the shorter meeting today\"\n\n## Discussion\n\n### Readonly setters on non-variables\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9174  \nSpecification: https://github.com/dotnet/csharplang/blob/d139d200cfe8ffe45536cdcc8b17ee7f25b5757b/proposals/readonly-setter-calls-on-non-variables.md\n\nToday, we looked at a proposal to lift an error scenario around `readonly`. One interesting thing with this is that we're already in an\ninconsistent state; we permit `readonly` setters to be called on the result of a `ref`-returning method, for example. This is likely an\nunintended \"bug\" in the implementation of `ref`-readonly methods, but at initial glance we could just make that the explicitly-allowed\nbehavior and standardize on that.\n\nThere was some discussion on named indexers; this is one of the primary use cases given to enable this language feature, but is that\nmotivation enough for this language feature? Or should we just do named indexers directly? However, as we previously noted, we want the\ncompiler to get to a consistent state; there are a few other motivating scenarios that we can discuss extending this feature to as well\nin future design sessions.\n\nWe also brought up some concerns that this could potentially enable new dropped value scenarios, where the struct is creating a new\nreference type under the hood and then being dropped. However, there's nothing unique to `struct`s here; the same type of issue as might\nhappen when a user uses an expression-bodied property of `{ get; } = new();` instead.\n\nGiven all of this, we think that we're fine with this proposal to move forward. We'll put it in \"Any Time\" for now, and revisit potential\nextensions to it at a later date.\n\n#### Conclusion\n\nProposal is accepted, put into \"Any Time\".\n"
  },
  {
    "path": "meetings/2025/LDM-2025-03-24.md",
    "content": "# C# Language Design Meeting for March 24th, 2025\n\n## Agenda\n\n- [Dictionary Expressions](#dictionary-expressions)\n    - [Support dictionary types as `params` type](#support-dictionary-types-as-params-type)\n    - [Type inference for `KeyValuePair<K, V>` collections](#type-inference-for-keyvaluepairk-v-collections)\n    - [Overload resolution for `KeyValuePair<K, V>` collections](#overload-resolution-for-keyvaluepairk-v-collections)\n- [Extensions](#extensions)\n    - [Signature conflict rules](#signature-conflict-rules)\n    - [`extension` vs `extensions`](#extension-vs-extensions)\n\n## Quote(s) of the Day\n\n- \"A syntax question with no hands? That's impossible\" ... \"I'm going to mis-spell whichever one we choose anyways\"\n- \"What is snoisnestringsxEg?\" \"Something happened in liveshare\" \"Oh, that's not the syntax suggestion?\"\n\n## Discussion\n\n### Dictionary Expressions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8659  \nSpecification: https://github.com/dotnet/csharplang/blob/bcc689fafe8c2d226b8a3034eb7f66f48495e3aa/proposals/dictionary-expressions.md\n\n#### Support dictionary types as `params` type\n\nQuestion: https://github.com/dotnet/csharplang/blob/bcc689fafe8c2d226b8a3034eb7f66f48495e3aa/proposals/dictionary-expressions.md#support-dictionary-types-as-params-type\n\nOur first topic today is about whether we should support `params` parameters of dictionary types. This is really a breaking change, as it means that we would potentially use\nan indexer for a dictionary-like type, where we currently use an `Add` method. That would likely result in a change from throwing semantics to overwrite semantics, so anyone\ndepending on potential exception behavior will see a behavioral difference. However, that's nothing specific to `params`, as the same is true for any other collection expression\ntargeted to a dictionary-like type, so we're not concerned about the potential for breaks in this specific corner.\n\nWe like this change overall, as it keeps the language simpler, even if the compiler is more complex. The goal we had with expanding `params` was that anything you could use a\ncollection expression for, you could `params`. Rather than re-adding the decoder ring of \"what can be `params`'d vs collection expression'ed\", we keep the correspondence simple,\nthough at the expense of more compiler developer work.\n\n##### Conclusion\n\nWe will allow use of `params` on dictionary-like types that can be targeted with a collection expression, and constructing those types will prefer using indexers when available,\njust like when using a collection expression to create that same type.\n\n#### Type inference for `KeyValuePair<K, V>` collections\n\nQuestion: https://github.com/dotnet/csharplang/blob/bcc689fafe8c2d226b8a3034eb7f66f48495e3aa/proposals/dictionary-expressions.md#type-inference-for-keyvaluepairk-v-collections\n\nWe like these proposed rules, as they honor the goal of making KVP as transparent as tuples for these types of targets. There is a minor breaking change here as well, in that\ntype inference can now succeed where it previously failed, meaning that overload resolution may find a nearer applicable method (for example, not going out to extensions\nbecause there's now an applicable instance method). We're ok with this type of break, so we'll accept these rules as written.\n\n##### Conclusion\n\nRules accepted as written.\n\n#### Overload resolution for `KeyValuePair<K, V>` collections\n\nQuestion: https://github.com/dotnet/csharplang/blob/bcc689fafe8c2d226b8a3034eb7f66f48495e3aa/proposals/dictionary-expressions.md#overload-resolution-for-keyvaluepairk-v-collections\n\nAgain, we like the analogy with tuple behavior that is happening here. If we ever run into a scenario where these rules behave differently than tuples would in this same\narea, we should bring that back for discussion. Otherwise, this is approved.\n\n##### Conclusion\n\nRules are accepted as written\n\n### Extensions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8697  \nSpecification: https://github.com/dotnet/csharplang/blob/bcc689fafe8c2d226b8a3034eb7f66f48495e3aa/proposals/extensions.md\n\n#### Signature conflict rules\n\nQuestion: https://github.com/dotnet/csharplang/blob/bcc689fafe8c2d226b8a3034eb7f66f48495e3aa/proposals/extensions.md#extension-declaration-validation  \n> The current conflict rules are:\n>  1. check no conflict within similar extensions using class/struct rules,\n>  2. check no conflict between implementation methods across various extensions declarations.\n>\n> Do we stil need the first part of the rules?\n\nFirst up in extensions, we looked at whether we still need/want both parts of the extension validation rules. The 2 rules serve different purposes. The second rule covers our\nability to actually emit method signatures; this is the rule that prevents two extension blocks on different types from having the same static method. The first rule is more\nabout preserving class experience; this is the rule that prevents having a static and instance method with the same name and parameters on the same type. We're hesitant to\nremove this rule without further examples of where it would be useful, and more exploration of where it would be problematic. This rule also protects things like being unable\nto declare both `int Prop { get; }` and `void set_P(int i) { }` in the same type, and is intended to help prevent concerning consumption scenarios. For example:\n\n```cs\nclass C\n{\n    static Color Color { get; }\n\n    static void Main()\n    {\n        Color.M(); // What M is called?\n    }\n}\n\nclass Color\n{\n    public static void M() {}\n    public void M() {}\n}\n```\n\nWe don't want to mess with validation of so-called `Color`/`Color` scenarios now, so absent further evidence, we will keep the rules as is.\n\n##### Conclusion\n\nBoth rules are retained.\n\n#### `extension` vs `extensions`\n\nQuestion: https://github.com/dotnet/csharplang/blob/bcc689fafe8c2d226b8a3034eb7f66f48495e3aa/proposals/extensions.md#open-issues\n\nFinally today, we have a syntax bikeshed; do we prefer `extension` or `extensions` as the keyword? After some debate, we boiled this down to whether we think of the entire block\nas a true group of items or not. Or, in other words, can we think of moving the parameter down to the individual methods involved and have everything still be exactly the same?\nWe have repeatedly concluded that yes, we do not think of the block as a construct with true meaning; writing out 10 extension blocks on the same underlying type, or grouping\nthem together into a single block, has the same meaning. Therefore, we will continue with the name `extension`.\n\nWe also had a small discussion on what to name the grouping of extension methods itself; we'd like to have a consistent name to use in documentation, in compiler API names, etc.\nWe spitballed a number of options:\n\n* extension declaration\n* extension block\n* extension body\n* extensions\n* extension group\n* extension container\n\nOnly \"extension group\" and \"extension block\" attracted any support, and of them \"extension block\" was heavily preferred, and not disliked by anyone. Therefore, we will call this\ngrouping an \"extension block\".\n\n##### Conclusion\n\nThe keyword is `extension`, and the term for the entire set of extension methods is an \"extension block\".\n"
  },
  {
    "path": "meetings/2025/LDM-2025-04-02.md",
    "content": "# C# Language Design Meeting for April 2nd, 2025\n\n## Agenda\n\n- [User Defined Compound Assignment Operators](#user-defined-compound-assignment-operators)\n    - [Should readonly modifier be allowed in structures?](#should-readonly-modifier-be-allowed-in-structures)\n    - [Should shadowing be allowed](#should-shadowing-be-allowed)\n    - [Should we have any consistency enforcement between declared += and + operators?](#should-we-have-any-consistency-enforcement-between-declared--and--operators)\n- [Readonly setters](#readonly-setters)\n    - [Expansions](#expansions)\n\n## Quote(s) of the Day\n\n```csharp\nvar csharp14 = [improvement1, improvement2, improvement3]\n```\n\n* There isn't a deep need to rescue people here.\n\n## Discussion\n\n### User Defined Compound Assignment Operators\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9101  \nSpecification: [User Defined Compound Assignment Operators.](https://github.com/dotnet/csharplang/blob/f0c692748ee5067fd59ed0ece46d79a408fe50d0/proposals/user-defined-compound-assignment.md)  \nDiscussion: https://github.com/dotnet/csharplang/discussions/9100\n\n#### Should readonly modifier be allowed in structures?\n\nQuestion: https://github.com/dotnet/csharplang/blob/f0c692748ee5067fd59ed0ece46d79a408fe50d0/proposals/user-defined-compound-assignment.md#should-readonly-modifier-be-allowed-in-structures\n\nOur first topic today is about whether we should allow a `readonly` modifier for compound assignments. The current specification requires the target of the operator to be a variable. In some cases, these could be beneficial - such as in wrapper classes that expose a subset of a type's surface. Also, there was concern about `readonly` structs needing to have all members `readonly`.\n\nFull support would require additional design work. \n\n##### Conclusion\n\nWe will allow `readonly` modifiers, but we will not relax the target requirements at this time.\n\n#### Should shadowing be allowed\n\nQuestion: https://github.com/dotnet/csharplang/blob/f0c692748ee5067fd59ed0ece46d79a408fe50d0/proposals/user-defined-compound-assignment.md#should-shadowing-be-allowed\n\nWe discussed that the implementation of user-defined operators is via methods and that behavior that did not match methods may seem strange.\n\n##### Conclusion\n\nShadowing will be allowed with the same rules as methods.\n\n#### Should we have any consistency enforcement between declared += and + operators?\n\nQuestion: https://github.com/dotnet/csharplang/blob/f0c692748ee5067fd59ed0ece46d79a408fe50d0/proposals/user-defined-compound-assignment.md#should-we-have-any-consistency-enforcement-between-declared--and--operators\n\nThis was a follow-up on concerns raised in [LDM-2025-02-12](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-02-12.md#user-defined-instance-based-operators). Authors may accidentally push their users into odd scenarios where a += may work, but + won't (or vice versa) because one form declares extra operators than the other.\n\nThere were concerns about enforcing such a rule.\n\n##### Conclusion\n\nChecks will _not_ be done on consistency between different forms of operators.\n\n### Readonly setters\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9174  \nSpecification: [Readonly setter calls on non-variables](https://github.com/dotnet/csharplang/blob/e34ecf622058b53f0fb37705baa8597ea045d378/proposals/readonly-setter-calls-on-non-variables.md)  \nDiscussion: https://github.com/dotnet/csharplang/discussions/2068\n\n#### Expansions\n\nQuestion: https://github.com/dotnet/csharplang/blob/e34ecf622058b53f0fb37705baa8597ea045d378/proposals/readonly-setter-calls-on-non-variables.md#expansions\n\nThere are cases where it is appropriate to error if a non-readonly setter is called, that may be reasonable when a `readonly` setter is called. We explored two of those cases that currently error with _CS1918 Member of property ... cannot be assigned with an object initializer because it is of a value type._ Should we include allowing readonly setters in these cases as part of the broader feature.\n\nA change would be needed to the C# spec on object initializers ([§12.8.16.3](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/expressions.md#128163-object-initializers)), which will be added to this proposal.\n\nIt was noted that expansions could be split off and done after the rest of the work in this proposal.\n\n##### Conclusion\n\nWe will include expansions in the _Readonly Setter calls on non-variables_ proposal\n\n"
  },
  {
    "path": "meetings/2025/LDM-2025-04-07.md",
    "content": "# C# Language Design Meeting for April 7th, 2025\n\n## Agenda\n\n- [Breaking change discussion: making partial members in interfaces virtual and/or public](#breaking-change-discussion-making-partial-members-in-interfaces-virtual-andor-public)\n- [Interpolated string handler argument values](#interpolated-string-handler-argument-values)\n\n## Quote of the Day\n\n- \"We can have multiple arguments about it, further down the road\"\n\n## Discussion\n\n### Breaking change discussion: making partial members in interfaces virtual and/or public\n\nBreaking change: [Compiler breaking changes](https://github.com/dotnet/roslyn/blob/db643157d8c64d47beb0a7d627244629a5116cd1/docs/compilers/CSharp/Compiler%20Breaking%20Changes%20-%20DotNet%2010.md#extended-partial-members-are-now-implicitly-virtual-and-public)  \nPull request: [dotnet/roslyn#77379](https://github.com/dotnet/roslyn/pull/77379)\n\nFirst up today, we looked at a potential bugfix for a longstanding behavior, since enhanced partial members were introduced into the language. This behavior was\ninitially noticed when implementing partial events, and further investigation has shown that it affects all partial members in interfaces. While we don't like\nthis inconsistency, we also don't think this behavior is particularly affecting anyone; we were the ones to discover it, rather than a bug being reported, and\nthe behavior in methods has been around for a long time. While we're fine with what is effectively a bug fix for partial properties, which have not been out\nfor long, we're not of the opinion that changing the behavior for partial methods in interfaces is worth the effort or risk potential. Instead, we'd rather just\nleave that as is.\n\n#### Conclusion\n\nWe will take this bugfix for partial properties and events, but not for methods. Since partial properties are so new, we will not tie it to\nlanguage version unless divisional breaking change procedures require us to do so.\n\n### Interpolated string handler argument values\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9046  \nSpecification: https://github.com/dotnet/csharplang/blob/4df926c14494c5990bd1c27380180eab90c56cb3/proposals/interpolated-string-handler-argument-value.md\n\nFollowing up from [February 24th](./LDM-2025-02-24.md#interpolated-string-handler-method-names), we have a new proposal around how to pass constant values to\ninterpolated string handlers for parameterization. This version of the proposal allows passing a single constant value via the attribute, which will be added\nafter anything passed via `InterpolatedStringHandlerArgumentAttribute`. We thought about whether we would want to support multiple values, but we currently\ndon't have any scenarios that need such capabilities, and we don't want to design that without a use case to validate the design against. To ensure that we have\nfuture ability to design this, though, we will disallow arrays as arguments, in case that is the approach we decide to take in the future.\n\n#### Conclusion\n\nProposal is approved. Arrays are disallowed as argument values to preserve design space.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-04-09.md",
    "content": "# C# Language Design Meeting for April 9th, 2025\n\n## Agenda\n\n- [Dictionary expressions](#dictionary-expressions)\n- [Collection expression arguments](#collection-expression-arguments)\n\n## Quote of the Day\n\n- \"Because we test everything, to our credit and our horror\"\n\n## Discussion\n\n### Dictionary expressions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8887  \nSpecification: https://github.com/dotnet/csharplang/blob/9735444553fbfaacdff76e77ef6ef0c14f1fcccb/proposals/dictionary-expressions.md#concrete-type-for-ireadonlydictionaryk-v\n\nFirst up today, we reviewed a question on what the default type for dictionary expressions targeted at `IDictionary` and `IReadOnlyDictionary` types. For this, we needed to\nuntangle our previous design work around collection expressions: in 2023, we'd\n[decided to not guarantee `List<T>`](https://github.com/dotnet/csharplang/blob/9735444553fbfaacdff76e77ef6ef0c14f1fcccb/meetings/2023/LDM-2023-08-09.md#conclusion-1), but\nthis is not what was specified. This was due to some misunderstandings between the working group and the broader LDM; we wanted to start by understanding the principles the\nworking group used to decide on the current rule, and then apply that to dictionary expressions. There are two aspects:\n\n1. For the readonly interfaces (namely, `IEnumerable<T>`), we wanted users to be able to rely on that readonly-ness. It was important to the group that it wouldn't be possible\n   to downcast and mutate the collection.\n2. For the mutable interfaces, it wasn't clear what the benefit of not guaranteeing `List<T>` would be. This is the BCL's flagship collection type, and the one that has the\n   largest optimization effort throughout the BCL.\n\nGiven these reasons, we accept that as the new motivating set of rules for collection expressions, and we have a clear guideline of how to apply the same rules for dictionary\ninterfaces as well. For `IReadOnlyDictionary<TKey, TValue>`, the compiler should guarantee readonly-ness. It is free to use any implementation it so desires, so long as it's\na \"conforming\" implementation, much like the specification for collection expression talks about conforming implementations. The precise rules for conformance should be\nbrought to LDM for approval, but they need to ensure that the dictionary is truly readonly and cannot be mutated, even if viewed through an interface that may optionally\nallow mutation (for example, returning `True` for `ICollection.IsReadOnly`, and throwing on `ICollection.Add`, if it does in fact implement `ICollection`). For the mutable\ndictionary interfaces, we don't see a reason to not just guarantee `Dictionary<TKey, TValue>`; it is the flagship dictionary type of .NET, and the one that has the largest\noptimization effort throughout the BCL. If this changes at some point in the future, we can look at it then.\n\n#### Conclusion\n\nWe will guarantee `Dictionary<TKey, TValue>` for the mutable dictionary interfaces. We will allow the compiler to use any compliant BCL or synthesized type for the readonly\ndictionary interfaces, where compliant means that it must ensure that the dictionary cannot be mutated by downcasting or alternate interface views.\nWe update the assumptions for collection expressions that constructing an `IList<T>` or `ICollection<T>` uses a `List<T>`.\n\n### Collection expression arguments\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8887  \nSpecification: https://github.com/dotnet/csharplang/blob/9735444553fbfaacdff76e77ef6ef0c14f1fcccb/proposals/collection-expression-arguments.md#arguments-for-interface-types\n\nWe did not have enough time to do more than give an overview of this question today and hear some initial sentiment. However, the initial sentiment seemed positive for two\nreasons:\n\n1. For the mutable dictionary types, the first question today specified that `Dictionary<TKey, TValue>` is the concrete type used. Why would you not be able to use the\n   constructors from that type then?\n2. For the readonly dictionary types, the first question today specified that a \"compliant\" implementation must be used. Why couldn't we make \"compliant\" include a \"must\n   be able to be constructed with a comparer argument\"?\n\nAgain, no conclusions here today, but we've primed the discussion for next week.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-04-14.md",
    "content": "# C# Language Design Meeting for April 14th, 2025\n\n## Agenda\n\n- [Dictionary expressions](#dictionary-expressions)  \n- [Collection expression arguments](#collection-expression-arguments)  \n\n## Discussion\n\n### Dictionary expressions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8887  \nSpecification: https://github.com/dotnet/csharplang/blob/e2e62a49d32f0d659b8baf0f23ee211b69563c65/proposals/dictionary-expressions.md#open-questions  \n\n#### Parsing ambiguity\n\nShould `[a ? [b] : c]` be parsed as `[a ? ([b]) : (c)]` or `[(a?[b]) : c]`?\n\n##### Conclusion\n\nParse as `[a ? ([b]) : (c)]`. If the user intends to use the conditional operator, they can use parentheses and `[(a?[b]) : c]`.\n\n#### Implement non-generic `IDictionary` when targeting `IReadOnlyDictionary<,>`\n\nThe existing types we might use to implement `IReadOnlyDictionary` implement `IDictionary` and implementing the interface on future types is not onerous.\n\n##### Conclusion\n\nThe type used when target typing `IReadOnlyDictionary<,>` should implement IDictionary.\n\n### Collection expression arguments\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8887  \nSpecification: https://github.com/dotnet/csharplang/blob/e2e62a49d32f0d659b8baf0f23ee211b69563c65/proposals/collection-expression-arguments.md#open-questions  \n\n#### Target types where arguments are required\n\nTypes that require at least one argument in all constructors and factory methods can't be used for `params` collections. We discussed whether conversions should be supported for collection expressions for these types.\n\nWe also discussed whether to require the presence of `with` to allow these conversions.\n\n##### Conclusion\n\nYes, conversions will be supported.\nYes, require `with` to allow these conversions.\n\n#### Arguments for interface types\n\nFor concrete types, we support the arguments available on constructors or factory methods. \n\nBut, should we support arguments for interface target types, and if so, what method signatures should be used binding the arguments.\n\nUsing the available constructors may result in signatures that are not particularly helpful. For example, when including a collection in a collection expression, a spread operator seems more clear than a `with` parameter. And  depending on the types involved, what's allowed may be unexpected:\n\n```csharp\nList<int> list1  = [with(otherList)]; // allowed.\nIList<int> list2 = [with(otherList)]; // not allowed.\nIList<int> list3 = (List<int>)[with(otherList)]; // allowed.\n```\n\nThere are a small number of constructor args that are very useful in collection expressions, such as:\n\n- Capacity and comparer for mutable (the capacity might change)\n- Comparer only for immutable (we know the capacity)\n\nNow that we understand the implications of a generalized solution for comparer and capacity, we are less certain that the generalized solution is the correct approach - so we will reconsider this. The team will explore what arguments are useful and return with a curated list and recommendation. We can add support for additional arguments as use cases arise.\n\n#### __arglist\n\nWe see very little value in supporting `__arglist` in collection expression arguments.\n\n##### Conclusion\n\nWe will not support `__arglist` unless they are \"free\" to support.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-04-16.md",
    "content": "# C# Language Design Meeting for April 16th, 2025\n\n## Agenda\n\n- [Extension-open issues](#extension-open-issues)  \n- [Collection expression arguments](#collection-expression-arguments)  \n\n## Discussion\n\n### Extensions-open issues\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8697  \nSpecification: https://github.com/dotnet/csharplang/blob/feb7a075739e81393def6c28ab12eb7b8fdc3bb6/proposals/extensions.md#open-issues  \n\n#### Nullability attributes\n\nNullability attributes there are some scenarios where the attributes can be placed on the receiver parameter but may feel odd or be inappropriate. For example, if an attribute refers to a method parameter name, like `NotNullIfNull`, `nameof` cannot be used. The name of the parameter has to be used.\n\nThese attributes can be placed on extension methods with the traditional syntax.\n\nIf the attribute includes a name, and the name does not exist on one of the extension methods in the block, it will be ignored. This is consistent with existing behavior for nullability attributes.\n\n##### Conclusion\n\nWe will copy these attributes to the lowered version of the extension method, in the same way we copy any other attribute. We will do no special work for these cases. This avoids breaking changes for people moving from the traditional syntax to the new syntax, except in the case where they used `nameof` on a parameter other than the receiver parameter.\n\n#### Should skeleton methods throw `NotSupportedException` or `null`?\n\nThese methods should not be called, and are marked as special methods. However, `NotSupportedException` better explains the intent.\n\n##### Conclusion\n\n`NotSupportedException` is preferred.\n\n#### Should we accept more than one parameter in marker method in metadata?\n\nA future version might add more parameters.\n\n##### Conclusion\n\nThis is an implementation detail the team can choose. We do not have scenarios where we would need a second parameter. \n\n#### Should the extension marker of speakable implementation methods br marked with special name flag?\n\nThis is a discussion of the compiler special name. It's up to the compiler to decide what is appropriate.\n\nThe implementation method also are currently marked with special name. This may not be appropriate since the implementation has switched to speakable names.\n\n##### Conclusion\n\nThe extension method will be marked with special name.\n\nThe implementations method will not be marked with special name.\n\n#### How should ORPA apply to new extension methods?\n\nOverload resolution priority attribute (ORPA) is meant to differentiate overloads within the same type. For the new extension syntax, \nwhat does the notion of the containing type mean?\n\nUsing the containing static class, rather than the extension block is compatible with traditional extension methods, and supports the case where extensions with the same receiver parameter appear in different extension blocks. Given:\n\n```csharp\npublic static class Extensions\n{\n    extension(Type1)\n    {\n        [OverloadResolutionPriority(1)]\n        public void Overload(...)\n    }\n    extension(Type2)\n    {\n        public void Overload(...)\n    }\n\n    // same bucket/ same \"containing type\"\n    public static void Overload(this Type3, ...)\n}\n```\n\nIf the containing type is the static `Extensions` class, all three overloads  considered together.\n\n##### Conclusion\n\nThe containing type is the static class. The extension block is not considered.\n\n#### Should we apply the \"inconsistent accessibility\" check on the receiver parameter even for static members?\n\n```csharp\npublic static class Extensions\n{\n    extension(PrivateType p)\n    {\n        // We report inconsistent accessibility error, \n        //   because we generate a `public static void M(PrivateType p)` implementation in enclosing type\n        public void M() { } \n\n        public static void M2() { } // should we also report here, even though not technically necessary?\n    }\n\n    private class PrivateType { }\n}\n```\n\nWe don't strictly need the to give an error here, but it is not a helpful since the underlying type is inaccessible.\n\nProviding the error would be consistent with the general behavior of accessing private types within public methods.\n\n##### Conclusion\n\nApply the \"inconsistent accessibility\" check on the receiver parameter.\n\n#### Confirm whether init-only accessors should be allowed in extensions\n\n`init` accessors are intended for use during object creation and limited to that timeframe.\n\nIf we do not do this now, we could do this later. We could consider it in relation to other enhancements to object creation.\n\n##### Conclusion\n\nWe will not allow `init` accessors on extension properties.\n\n#### Extension static member lookup on generic types does not work\n\nThis is a discussion of [Extension static member lookup on generic types does not work](https://github.com/dotnet/roslyn/issues/78129).\n\n```csharp\nstatic void Test<T>()\n{\n    T.Hello(); // error CS0704: Cannot do non-virtual member lookup in 'T' because it is a type parameter\n}\n\nstatic class Ext\n{\n    extension<T>(T)\n    {\n        public static void Hello()\n        {\n            Console.WriteLine(\"Hello\");\n        }\n    }\n}\n```\n\nYou cannot currently call static members on type parameters in non-extension code. A constraint is available and the static method can be called on the constraint.\n\nCalling static extension members with type parameters may be more useful than non-extensions.\n\nDesign work would be needed to support this.\n\n##### Conclusion\n\nThis may be a valuable scenario, but we are going to wait for feedback.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-04-23.md",
    "content": "# C# Language Design Meeting for April 23rd, 2025\n\n## Agenda\n\n- [Extensions](#extensions)\n    - [Extension operators](#extension-operators)\n    - [Overload resolution priority](#overload-resolution-priority)\n- [Dictionary Expressions](#dictionary-expressions)\n\n## Quote of the Day\n\n- \"This is worse, that's lambda calculus\" \"Is [redacted] in the meeting yet? Maybe they can explain it to us\" \"Not in one minute they can't\"\n\n## Discussion\n\n### Extensions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8697  \nSpecification: https://github.com/dotnet/csharplang/blob/feb7a075739e81393def6c28ab12eb7b8fdc3bb6/proposals/extensions.md\n\n#### Extension operators\n\nProposal: https://github.com/dotnet/csharplang/blob/feb7a075739e81393def6c28ab12eb7b8fdc3bb6/meetings/working-groups/extensions/extension-operators.md\n\nWe started today by looking through the latest proposal on how we want to work with extension operators. We like the proposal in general, and spent time talking\nabout the open question: whether to put restrictions on scenarios where the operator could potentially \"lose\" to a built-in conversion. For example, if an\nextension operator `+` is on a type parameter `T`, then when `int` is substituted for `T`, that operator could potentially silently lose to a language-default\noperator. While this is true, we don't think we need to try and come up with a set of rules to protect users from this possibility; if it happens, it happens.\nUnlike other types of restricted operators, there's no potential for the \"wrong\" thing to happen, where a built-in operator would be overridden by an extension\noperator. Given this, we're happy with the proposal, and will not put restrictions on type parameter extensions.\n\n##### Conclusion\n\nApproved. We will not restrict extensions on type parameters with more rules about what operators are valid.\n\n#### Overload resolution priority\n\nQuestion: https://github.com/dotnet/csharplang/blob/feb7a075739e81393def6c28ab12eb7b8fdc3bb6/proposals/extensions.md#lookup\n\nNext, we looked at a brief question on whether `OverloadResolutionPriorityAttribute` should apply to properties in extensions. This scenario can occur when\na single static class contains more than one extension block, which define an overloaded set of properties. In such a scenario, authors might want to use something\nlike ORPA to avoid ambiguity errors for their users. We think this is a good idea; there might be some discoverability issues with this solution, given that ORPA\ncan usually only be used on indexers, but ORPA itself is generally pretty niche and not well-known anyways. It's intended as an uncommon, last-ditch tool, not a\ngeneralized solution for any lookup problem. The main question is timing: we don't think this is critical for v1 of extensions, so if it has to slip to the next\nversion of C# to get more important bits of extensions out the door, so be it.\n\n##### Conclusion\n\nWe will allow ORPA to be used on extension properties, and the containing type of the extension property is the static class that contains the extension block.\n\n### Dictionary Expressions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8659  \nSpecification: https://github.com/dotnet/csharplang/blob/feb7a075739e81393def6c28ab12eb7b8fdc3bb6/proposals/dictionary-expressions.md#question-special-case-comparer-support-for-dictionaries-and-regular-collections\n\nWe [previously](./LDM-2025-04-14.md#arguments-for-interface-types) talked about what collection expression arguments should do on interface types, and as part of\nthat discussion, wanted to explore a more specialized syntax for just providing comparers. This syntax would potentially entirely replace the generalized\ncollection expression argument feature, so the working group went off and explored the idea. After looking at the results, we don't think a specialized syntax\nfor just comparers is the right approach. Even within the BCL, there's potential for more than just `capacity` and `comparer` arguments. `ImmutableDictionary`,\nfor example, has both `keyComparer` and `valueComparer` parameters. We also don't want to invent 2 ways to specify parameters for dictionaries, one that needs to\nbe used when the target type is an interface, and one for when the target type is any other concrete type. Given that, we want to proceed with the full collection\nexpression arguments feature, even for interfaces. Our main question at this point is whether to use a curated list of constructors for the dictionary interfaces,\nor let the full set of constructors of the underlying type show through. For `IDictionary`, it seems like it might be ok; after all, we guarantee what the concrete\ntype used to create one is. However, for `IReadOnlyDictionary`, we do not guarantee this, we only say that a compatible implementation must be used. Therefore, for\nnow, we will curate the constructors to just the ones that take a comparer, capacity, or both, and no others. We can expand in the future if there are motivating\nscenarios, rather than being very lax now and potentially regretting our inability to change later.\n\n#### Conclusion\n\nSpecialized comparer-only syntax is abandoned. We will move forward with collection expression arguments for interface types, using a curated set of constructors\nthat take either a comparer, capacity, or both.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-05-05.md",
    "content": "# C# Language Design Meeting for May 5th, 2025\n\n## Agenda\n\n- [Extensions](#extensions)\n    - [XML Docs](#xml-docs)\n    - [Participation in pattern-based constructs](#participation-in-pattern-based-constructs)\n    - [Skeleton type metadata](#skeleton-type-metadata)\n    - [Single-phase consequences](#single-phase-consequences)\n\n## Quote of the Day\n\n- \"If you change your source from release to release, which people typically do\"\n\n## Discussion\n\n### Extensions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8697  \nSpec: https://github.com/dotnet/csharplang/blob/555aeea68ef3ce29c313ddd68d4a0fdd68d84420/proposals/extensions.md\n\n#### XML Docs\n\nQuestions: https://github.com/dotnet/csharplang/blob/555aeea68ef3ce29c313ddd68d4a0fdd68d84420/proposals/extensions.md#xml-docs  \nRelated: https://github.com/dotnet/csharplang/blob/555aeea68ef3ce29c313ddd68d4a0fdd68d84420/meetings/working-groups/extensions/Extension-API-docs.md\n\nWe started today by reviewing the proposed structure of XML doc comments. This review raised a few new questions as we confirmed various\ncomponents. First, should we permit overriding the `param` documentation for the receiver parameter on individual members? Our common\nexample, `Enumerable.cs`, does have different `this` parameter documentation throughout the file. `The source of elements to be cast` vs\n`The source of elements to be filtered`, etc. However, we don't know that this is critical functionality, or that `Enumerable.cs` would\nhave wanted to take advantage of this if it was being rewritten from scratch today. There is already a workaround in declaring a new\nextension block. This is the same workaround that we advise for other things that cannot be overridden, such as nullability annotations,\nattributes, `this` parameter names, etc. Therefore, we are ok with simply adding the documentation comment to the list of things that\ncannot be overridden on individual members, for now, and can revisit later if the demand for this proves itself.\n\nRelated, we also thought about the summary on the extension blocks themselves. In particular, we're not sure that this block would\nactually appear anywhere in the IDE or docs experience. We want to revisit this support and make sure that we actually have a use case\nfor it before shipping.\n\nAnother related issue we briefly mentioned is missing documentation comment warnings; we want to make sure that adding parameter\ncomments to one member won't virally create missing parameter documentation comments on all the rest of the members in an extension\nblock; the example here would be adding parameter documentation to one member, but not having documentation on the extension parameter.\nThe user then gets a warning that the extension parameter is missing a comment. Then, when the user adds that comment, now every _other_\nmember in the block that has additional parameters is missing comments on those parameters. We need to cut off that cycle somewhere to\nstrike a usability balance, which will we think about and come back with.\n\nFinally, we raised a question of how users can `cref` an extension property itself. The current design allows referring to either the\ngetter or setter by using the disambiguation syntax, but has no way to refer to the entire property itself. We will need to design this\nand come back with a proposal.\n\n##### Conclusion\n\nXML approach is generally approved, with a few open questions around extension block summaries, warning virality, and property crefs.\n\n#### Participation in pattern-based constructs\n\nQuestion: https://github.com/dotnet/csharplang/blob/555aeea68ef3ce29c313ddd68d4a0fdd68d84420/proposals/extensions.md#pattern-based-constructs\n\nNext, we took a look at what contexts we want new extensions to work in. For methods, the answer is straightforward: everywhere they\nwork today. For properties, it's more subtle. We wanted to start by refining the \"why\" of our current rules, so we can apply that why\nto properties and have it naturally fall out. Roughly speaking, we generally allow extensions where the extension is not about state in\nthe underlying object. For example, we allow an extension `GetAwaiter`, which returns a new object that can track the state of an\nunderlying object and implement the `await` pattern. However, we do not then allow an extension `GetResult` on the object returned by\n`GetAwaiter`, because our expectation is that the Result is intrinsic to the awaiter's state. Similarly, we do not allow extension\n`Dispose`, because that is intrinsic to the state of an object. We acknowledge, however, that this principle is not universally\napplied. We're not sure that we'd exclude `Slice` methods implemented as extensions today, for example, and `GetPinnableReference` is\nvery related to an object's state. Given this, we'll also draw from any related patterns in a given area.\n\nWe are ok with the list of areas as proposed here: allowing them in object/dictionary/`with` initializers, and property patterns. For\nnow, we think we should not include `Count`/`Length` properties in the determination of whether or not an object is countable, meaning\nthey won't participate in list patterns or in implicit `Range`/`Index` indexers. We think this because of our prior art around `Slice`,\nand while we think we might want to revisit that entire space, we want to do that as a whole item, not an individual piece.\n\nWe are not settled on when delegate-returning properties will be accepted. We have conflicting prior art; `LINQ` works as a syntactic\nrewrite, and thus delegate-returning properties are accepted without question. Other areas are not syntactic rewrites, and do not\naccept delegate-returning properties. More thought needs to go into the space before we can make a decision.\n\n##### Conclusion\n\nNew extensions methods will behave like old extension methods in pattern-based locations. Extension properties will participate in\nin object/dictionary/`with` initializers and property patterns for now, with further expansion on the table for later.\n\n#### Skeleton type metadata\n\nQuestion: https://github.com/dotnet/csharplang/blob/555aeea68ef3ce29c313ddd68d4a0fdd68d84420/proposals/extensions.md#namingnumbering-scheme-for-skeleton-type\n\nPublic API tools that verify our unspeakable extension metadata have an issue with how we currently decide on names. Our current\napproach has some issues around determinism that we need to address, but even if we adjust this, it seems very likely that the public\nAPI validation tools are going to need to adjust. We don't think that we consider the names of the skeleton structures to be\npart of the API; they're not referred by implementations, and purely exist for the compiler to be able to understand underlying\nstructure. We don't think there's a naming structure that we can come up with that won't run into collisions of some kind unless we\nhave an incrementing number somewhere, which would then break if something is reordered. Given this, we believe the tool will still\nneed to update to understand when the name isn't important.\n\n##### Conclusion\n\nThe compiler algorithm does need to be double-checked and verified, but we expect tooling that validates public APIs from release to\nrelease will need to update as well.\n\n#### Single-phase consequences\n\nQuestion: https://github.com/dotnet/csharplang/blob/555aeea68ef3ce29c313ddd68d4a0fdd68d84420/proposals/extensions.md#new-generic-extension-cast-method-still-cant-work-in-linq  \nRelated: https://github.com/dotnet/roslyn/issues/78415\n\nFinally, we looked at an outcome of moving back to single-phase generic resolution. The BCL had been hoping to fix an issue with\n`Cast<TSource, TResult>` on `IAsyncEnumerable`, where since `TResult` cannot be inferred from the parameters, both generic type\nparameters must be explicitly supplied, so things like `from Type t in asyncEnumerable`, which gets translated into\n`asyncEnumerable.Cast<Type>()`, cannot work due to differing arity. The first thing we considered was whether LINQ could do something\nabout this, potentially specifying both type parameters in this case. We think that would be especially difficult given the current\nstructure of query expressions; they're defined as pure syntactic rewrites, not involving semantics. This fallback would have to be\nbased on semantic information.\n\nWe also briefly talked about two-phase inference again. We do think that this scenario is something that we want to support in the\nlanguage, but as in previous LDMs, we don't think that this limitation is specific to extensions. Instead, we want to investigate a\nmore general approach that can work regardless of extension-ness.\n\n##### Conclusion\n\nThis is not the straw that breaks the camel's back. We will continue to investigate what we can do to make this scenario better in\ngeneral.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-05-07.md",
    "content": "# C# Language Design Meeting for May 7th, 2025\n\n## Agenda\n\n- [Collection Expression Arguments](#collection-expression-arguments)\n    - [Interface target type](#interface-target-type)\n    - [Constructor binding behavior](#constructor-binding-behavior)\n    - [Syntax](#syntax)\n\n## Quote of the Day\n\n- \"`with(out var x)` sounds like we're leaving `var x` behind\"\n\n## Discussion\n\n### Collection Expression Arguments\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8887  \nSpec: https://github.com/dotnet/csharplang/blob/0eddbeca5dc6edfbf91f915ecea3379b8e337cc7/proposals/collection-expression-arguments.md\n\n#### Interface target type\n\nSpec section: https://github.com/dotnet/csharplang/blob/0eddbeca5dc6edfbf91f915ecea3379b8e337cc7/proposals/collection-expression-arguments.md#interface-target-type\n\nWe started today by looking at the proposed set of constructors for interface types to ratify the list. The main bit of feedback here was on the readonly types; the proposal\ndoes not accept capacity for any of these types, and we briefly explored whether it might be useful to do so. We don't know of any examples where this would be useful from a\nruntime perspective, but we did want to consider whether it would allow lower code churn when switching from a mutable interface to a readonly interface. Ultimately, we don't\nthink that this is useful, and we approve the constructors as proposed.\n\n##### Conclusion\n\nInterface constructor list approved as proposed.\n\n#### Constructor binding behavior\n\nSpec section: https://github.com/dotnet/csharplang/blob/0eddbeca5dc6edfbf91f915ecea3379b8e337cc7/proposals/collection-expression-arguments.md#constructors\n\nNext, we looked at the rules for binding constructors and create methods in general. A particular wart that has come up as part of this is that we may end up skipping optional\nparameters as part of a signature without any user-specificity; further, users may decide that they need to mark parameters as optional even if they normally wouldn't do so, so\nthat they can mark the collection as optional in their `Create` methods. For example, a user might have a method like this:\n\n```cs\npublic static MyCollection<T> Create<T>(IComparer<T> comparer = null, ReadOnlySpan<T> elements = default);\n```\n\nHere, users are forced to mark `elements` as optional so that they can mark `comparer` as optional, even though they might not want to do so. Namely, this design might force\nAPI designers into non-standard approaches so that their methods compile. There are also questions around `Create` methods that take multiple `ROS` elements: which should be the\none we use for the elements? While there were good reasons to try and prefer the ROS as the last element in the argument list, we do also think that moving it to be the first\nelement would be beneficial for these questions, so we want the working group to go and take a look at this question again.\n\nWe also looked at `out` parameters and `params` parameters. We're ok with the meaning of these being the same in collection expression arguments. as currently defined, `params`\nis mainly useful in constructors, not in `Create` methods. We will not allow `params` parameters to be split across collection expression arguments and the collection expression\nitself.\n\n##### Conclusion\n\n`out` and `params` are approved. The working group will revisit the rules around collection builder signature matching, and whether we can put the ROS first.\n\n#### Syntax\n\nFinally, we got to a long-simmering question: what is the real syntax we want to use for collection expression arguments. `with` was intended as a way to move forward with the\nvarious semantics, without needing to block implementation. We have always intended to revisit it, and now we're doing so. We threw a lot of syntaxes into a block to give\ninspiration:\n\n```cs\n// Trailing arguments\n[a, b, c] with (comparer)\n\n// Leading arguments\nnew(comparer, ......) [...]\nwith(comparer, ......) [...]\ninit(comparer, ......) [...]\nargs(comparer, ......) [...]\n\n// Direct parentheses - conflicts with tuples in the wild\n[ (a, b, c), 1, 2, 4]\n\n// new as the keyword - conflicts with target-typed new in the wild\n[  new(a, c, c), 1, 2, 4]\n\n// Sigils - no conflict, but is it confusing?\n[ @(a, b, c), 1, 2, 4]\n\n// Already used for record mutation\n[ with(a, b, c), 1, 2, 4]\n\n// Already used for property setters\n[ init(a, b, c), 1, 2, 4]\n\n// Already used for main method arguments in top-level statements\n[ args(a, b, c), 1, 2, 4]\n\n// Previous examples, using semi-colons instead of commas\n[ (a, b, c); 1, 2, 4]\n[ with(a, b, c); 1, 2, 4]\n[ init(a, b, c); 1, 2, 4]\n[ args(a, b, c); 1, 2, 4]\n```\n\nTo make it easier to start whittling down our options, we created some broad categories. First up, we looked at the location of the arguments; before the expression, inside the\nexpression, or after the expression? We don't like after, due to order of operations, as it implies that the collection contents have to be evaluated entirely before the\narguments can be evaluated. Before is better, but we don't like the mental stutter that is involved: you start reading an argument list, then see the `[` and realize what you\nread previously were the arguments for a collection expression, not a method call. Inside was the clear winner in our eyes.\n\nNext, we looked using a sigil, or a keyword. We very unanimously felt that a sigil was not C#-y, and too cryptic. Therefore, we will use a keyword.\n\nNext, we looked at the separation sigil. Our two leading contenders are `,` and `;`. `:` was eliminated early because it is used as the dictionary expression `key:value`\nseparator. Between `;` and `,`, we lean slightly towards the `,`. The `;` is a harder separation, but we also don't have any usage of `;` inside an expression today, besides\nstatements inside block-bodied lambdas, and we're not sure that this is a good location to change that. `,` does come with less visual separation, but we're very used to using\n`,`s inside expressions, which is a positive. We're leaning in the `,` direction, and will come back next time to settle for certain.\n\nFinally, in the waning minutes of the meeting, we looked at the various keywords that were proposed. The first choice of most LDT members was either `with` or `args`, and `init`\nas a distant 3rd. We'll come back next time as well to settle between `with` and `args`.\n\n##### Conclusion\n\nThe syntax will definitely be inside the collection expression at the front, and use a keyword of some kind. We've narrowed separator options to `,` vs `;`, and keyword options\nto `with` vs `args`. We will settle those choices next time.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-05-12.md",
    "content": "# C# Language Design Meeting for May 12th, 2025\n\n## Agenda\n\n- [Collection expression arguments](#collection-expression-arguments)\n    - [Empty argument lists](#empty-argument-lists)\n    - [Constructor binding behavior](#constructor-binding-behavior)\n    - [Syntax](#syntax)\n- [Dictionary expressions](#dictionary-expressions)\n\n## Quote of the Day\n\n- \"Why would you say that?\" \"Look, hubris is my thing\" [much later] \"Hey, I didn't jinx it after all!\"\n\n## Discussion\n\n### Collection expression arguments\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8887  \nSpec: https://github.com/dotnet/csharplang/blob/efb435c829ca6917dbdd34ca30eab4a47ff66c22/proposals/collection-expression-arguments.md\n\n#### Empty argument lists\n\nQuestion: https://github.com/dotnet/csharplang/blob/efb435c829ca6917dbdd34ca30eab4a47ff66c22/proposals/collection-expression-arguments.md#empty-argument-lists\n\nFirst up, we looked at when to permit empty argument lists. We want a simple rule here, something easy to explain to users. One option is just \"allowed for everything\", which is\ncertainly easy to explain. However, it may run into friction in the spec and compiler; what does it actually mean, particularly for arrays and spans? Neither of those have a\ntraditional \"constructor\" that can accept arguments, so what does the `with()` actually bind to? Another simple option is to permit it when there exists a constructor or `Create`\nmethod that can accept the empty argument list. For such a rule, the main question is then whether interfaces can accept an empty argument list. We think this might be slightly\nmore common than for arrays or spans; it is reasonable for an API author to move from a specific type to an interface to abstract things in a breaking update or internally. It\nwould mean that we would need to amend the list of accepted constructors for interface types to include the empty constructor as well, but that seems reasonable. A final option\nwould be to simply disallow an empty `with()` entirely, but that feels too heavy-handed; being explicitly about not passing arguments is a perfectly reasonable thing to do.\nTherefore, we will allow `with()` for constructor types and builder types that can be called without arguments at all, and we will add empty constructor signatures for the\ninterface types.\n\n##### Conclusion\n\nWe will allow `with()` for constructor types and builder types that can be called without arguments at all, and we will add empty constructor signatures for the\ninterface types. Arrays and spans will not allow `with()`, as there are no signatures that would fit them.\n\n#### Constructor binding behavior\n\nQuestion: https://github.com/dotnet/csharplang/blob/efb435c829ca6917dbdd34ca30eab4a47ff66c22/proposals/collection-expression-arguments.md#collectionbuilderattribute-methods\n\nFollowing up from [last week](./LDM-2025-05-07.md#constructor-binding-behavior), we're revisiting the rules for create method binding. We have a new proposal that regularizes\nthe approach by creating projection signatures: chopping off the last parameter of the builder method, then doing standard overload resolution rules, creating a signature that\nis similar in approach to a constructor signature for types that use constructor-based creation. This does nicely regularize the approach, and solves the questions around which\nROS to use if multiple are in a signature, but does still present the question of what do users do to use optional parameters? After some discussion, we've hit on the mental\nmodel that users are likely to not know exactly what they're calling: a `Create` method, a constructor, a synthetic constructor for an interface, they all appear the same from\na mental model perspective. The projection also fits in with that model, and that's what we intend to proceed with.\n\n##### Conclusion\n\nProjection-based approach is approved.\n\n#### Syntax\n\nAlso [last week](./LDM-2025-05-07.md#syntax), we had 2 syntax choices to finish on: whether to use `;` or `,` as the separator for collection arguments, and whether to use `with`\nor `args` as the keyword. We did very little discussion today, and instead went straight into a read of the room. This revealed that, while there is still some support for both\n`;` and `init`, both are in the minority. We will approve `with(),` as the syntax for collection expression arguments.\n\n##### Conclusion\n\n`with` is the keyword chosen for collection expression arguments, and `,` is the separator.\n\n### Dictionary expressions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8659  \nSpec: https://github.com/dotnet/csharplang/blob/efb435c829ca6917dbdd34ca30eab4a47ff66c22/proposals/dictionary-expressions.md#support-keyvaluepair-variance-with-params\n\nFinally today, we took a look at a question in dictionary expressions: should we support KVP variance in `params`. This pulls in two directions: as a bare parameter, KVP has no\nvariance. However, if the user were to surround the provided `params` argument with a collection expression, it would start to work. We've further said in the past that we want\nto try and minimize the differences between what collection expressions can do, and what `params` can do.\n\nThat being said, there are also good arguments for disallowing this. The general idea behind `params` is that the user doesn't know that they're calling something that accepts\na collection, and they get the same experience they'd get if they called a method that just had a signature with however many parameters they provided. There are also other\naspects of collections expressions and `params` that differ, such as extension `GetEnumerator`. We also aren't adding generalized KVP variance; it's specifically a feature of\ncollection expressions. We therefore think we should keep it limited to just collection expressions.\n\n#### Conclusion\n\nVariance is limited to explicit collection expressions, `params` does not perform it.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-05-28.md",
    "content": "# C# Language Design Meeting for May 28th, 2025\n\n## Agenda\n\n- [Nominal type unions](#nominal-type-unions)\n\n## Quote of the Day\n\n- \"The general rule of LDM is what happens in chat stays in chat\" <sup>unless it serves as fodder for the quote of the day</sup>\n\n## Discussion\n\n### Nominal Type Unions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9411  \nProposal: https://github.com/dotnet/csharplang/blob/402e0a75e53b6c1a301b1e75b58115b7b7315e8f/proposals/nominal-type-unions.md\n\nToday we reviewed the latest output from the unions working group: a proposal for nominal type unions. We spent most of our time examining the proposal\nand discussing its various limitations in certain scenarios. As with previous proposals, generic contexts remain a concern, as do reflection scenarios.\nJSON serialization presents particular challenges, where the natural representation for some scenarios would be a union type (such as `OneOf<int, string>`),\nbut this would fail when encountering specific cases instead of the union wrapper. We also raised concerns about the fragility of the emit approach,\nespecially across assembly boundaries; optimizations would need to be curtailed to prevent undefined behavior during assembly upgrades. Ultimately, the\nLDM is not ready to move forward with this version of the proposal, and we need to return to the drawing board to continue designing.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-06-04.md",
    "content": "# C# Language Design Meeting for June 4th, 2025\n\n## Agenda\n\n- [Extensions](#extensions)\n    - [Should extension operators on nullable of extended type be disallowed](#should-extension-operators-on-nullable-of-extended-type-be-disallowed)\n    - [Applicability of bitwise operators during evaluation of user-defined conditional logical operators](#applicability-of-bitwise-operators-during-evaluation-of-user-defined-conditional-logical-operators)\n    - [Extension user-defined conditional logical operators](#extension-user-defined-conditional-logical-operators)\n    - [Extension compound assignment operators](#extension-compound-assignment-operators)\n    - [Delegate returning properties](#delegate-returning-properties)\n    - [Extension declaration validation](#extension-declaration-validation)\n    - [Cref references](#cref-references)\n\n## Quote of the Day\n\n- \"2b or not 2b?\" \"That was the question\"\n\n## Discussion\n\n### Extensions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8697  \nSpecifications:\n* https://github.com/dotnet/csharplang/blob/9ecaa5ad2cf7700cb837fac84dc89eb7a1c655de/proposals/extension-operators.md\n* https://github.com/dotnet/csharplang/blob/9ecaa5ad2cf7700cb837fac84dc89eb7a1c655de/proposals/extensions.md\n\nWe spent today reviewing open questions in the extension space, starting first with extension operators specifically, then\nmoving on to more general questions.\n\n#### Should extension operators on nullable of extended type be disallowed\n\nQuestion: https://github.com/dotnet/csharplang/blob/9ecaa5ad2cf7700cb837fac84dc89eb7a1c655de/proposals/extension-operators.md#should-extension-operators-on-nullable-of-extended-type-be-disallowed\n\nWe started by thinking about whether we should allow nullable value type operators to be defined as extensions in an extension\nblock for their underlying type. There are a few technical challenges in the specification and compiler to allowing this, and a\nclear workaround of simply defining the operators in an extension block on the actual nullable value type. Given that, we are\nfine with the proposed restriction for now, and can revisit at a later time if we get enough feedback on the restriction.\n\n##### Conclusion\n\nRestriction accepted: extension operators can only be declared for the type being extended in an extension block, not for the\nnullable underlying type.\n\n#### Applicability of bitwise operators during evaluation of user-defined conditional logical operators\n\nQuestion: https://github.com/dotnet/csharplang/blob/9ecaa5ad2cf7700cb837fac84dc89eb7a1c655de/proposals/extension-operators.md#applicability-of-bitwise-operators-during-evaluation-of-user-defined-conditional-logical-operators\n\nAn original principle of this rule is that `&` and `&&` should call the same `&` operator, which this proposal would violate.\nWhile there is some precedent for us allowing operators to change between similar operations (the new `+=` overloads vs `+`,\nfor example), we don't think we have the use cases to justify this change at this point.\n\n##### Conclusion\n\nWe're not doing anything here for now. Rejected until we see use cases.\n\n#### Extension user-defined conditional logical operators\n\nQuestion: https://github.com/dotnet/csharplang/blob/9ecaa5ad2cf7700cb837fac84dc89eb7a1c655de/proposals/extension-operators.md#extension-user-defined-conditional-logical-operators\n\nWe don't have any additional comments on this proposal. It seems logical and straightforward, and is accepted.\n\n##### Conclusion\n\nProposal accepted.\n\n#### Extension compound assignment operators\n\nQuestion: https://github.com/dotnet/csharplang/blob/9ecaa5ad2cf7700cb837fac84dc89eb7a1c655de/proposals/extension-operators.md#extension-compound-assignment-operators\n\nThere is definitely value in allowing anything to work here, despite the potential for footguns, but we think there will be more\ndesign work needed that we do not currently have the bandwidth to do. Therefore, at least for now, the restriction is adopted.\n\n##### Conclusion\n\nRestriction adopted, we can look at it again in the future when there is more bandwidth.\n\n#### Delegate returning properties\n\nQuestion: https://github.com/dotnet/csharplang/blob/9ecaa5ad2cf7700cb837fac84dc89eb7a1c655de/proposals/extensions.md#delegate-returning-properties\n\nFirst up in extensions proper, we took a quick look at the proposed rules for delegate-returning properties. We have no issues\nwith the proposed rules, and adopt them as written.\n\n##### Conclusion\n\nRules adopted as written.\n\n#### Extension declaration validation\n\nhttps://github.com/dotnet/csharplang/blob/9ecaa5ad2cf7700cb837fac84dc89eb7a1c655de/proposals/extensions.md#extension-declaration-validation\n\nNext up, we looked at one of the more controversial restrictions of the current proposal, that only type parameters that are\ndirectly used in the extension parameter are allowed on the extension block itself. This ends up being a blocker for several\nscenarios in both the BCL and our early adopters. Given this, we want to lift the restriction, but the question then becomes\n\"to what extent\". The restriction does provide some useful guardrails, particularly for non-methods members that do not have a\nlocation to provide type parameters. We don't think there's any harm in fully lifting the restrictions on actual methods, but\nfor non-methods, we think we need to keep a form of the restriction: the type parameters must be used within all parameters of\nthe member.\n\n##### Conclusion\n\nRestriction is loosened to \"No restriction on extension methods. Other extension members must use all type parameters in their\nparameter types.\"\n\n#### Cref references\n\nQuestion: https://github.com/dotnet/csharplang/blob/9ecaa5ad2cf7700cb837fac84dc89eb7a1c655de/proposals/extensions.md#cref-references\n\nFinally today, we looked at the proposed cref syntax for referencing extensions. There's a wrinkle in this of which member a\ncref actually references: the implementation, or the skeleton facade. Both will have different IDs in the actual documentation\nfile. However, this is a question in itself: should C# normalize this so users don't need to understand the difference between\nthe two? There's a good argument for doing this, but we then need to decide which thing to normalize to. Another question that\ncame up is whether there should be an entirely bespoke syntax here, or if users can just refer to things in extension or\ndisambiguation form directly, ie as `<see cref=\"int.M()\" />` or `<see cref=\"E.M(int)\" />`. This form would encourage thinking\nof the implementation vs skeleton separately, which could be a problem, but is also more straightforward without needing to\nintroduce new formats. A further item to consider is whether we want to allow linking directly to an extension block in\na doc comment.\n\nWe did not come to a decision here today, and will need to come back next week on it.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-06-09.md",
    "content": "# C# Language Design Meeting for June 9th, 2025\n\n## Agenda\n\n- [Extensions](#extensions)\n\n## Quote of the Day\n\n- \"It really feels like a Monday morning\"\n\n## Discussion\n\n### Extensions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8697  \nSpecification: https://github.com/dotnet/csharplang/blob/435111275ae5f8f949cbfa9c918645738ccf38a0/proposals/extensions.md#cref\n\nToday, we followed up on the cref questions from [last time](LDM-2025-06-04.md#cref-references), after the working group took another look at\nthe area. An unfortunate detail here is that the skeleton implementation keeps surfacing: we try to paper over the implementation details for\nusers, but in areas where it bleeds through, particular groups will likely need to understand the difference between the actual\nimplementation of the extension member and the skeleton that exists to inform the language about the structure. This is true for anything that\nwants to interact with real structures, including both documentation comments and other things like reflection. After extensive discussion,\nwe don't think there's a way around this in the end, particularly given our desire to keep `ExtensionType.Method` references working for\nexisting `cref`s to extension methods in the new form. Another argument in favor is that doc comment XML does not reflect the structure\nof C#; it reflects the structure of metadata. Any tooling interacting with doc comment XML today already needs to know about the structure\nof metadata and how to map it back onto C# structure for output, and this would be no different. Therefore, we approve the following decisions\ntoday:\n\n* There will be one syntax to refer to extension skeleton members: `ExtensionType.extension(type).Member`. We will not offer \"reduced\" forms\n  such as `type.Member` in `cref`s in the language for simplicity.\n* There will be one syntax to refer to extension implementation members: `ExtensionType.Member`. This will work for methods and things that\n  reduce into methods, such as `E.extension(int).Prop` and `E.get_Prop`/`E.set_Prop`.\n* Extension blocks themselves are not able to be referred to at this time. `E.extension(int)`, on its own, is not a valid `cref` location.\n  We have no examples of where we'd actually want to do this and currently think that it would not be a good idea to expose this concept,\n  as extension blocks are not named entities in and of themselves in C#.\n\nThis last point ended up being somewhat contentious, as we intend to allow `param` elements to be documented on the extension block itself.\nDo users expect to be able to write other documentation comments in that same area and have them reflected somewhere? Where would users\nassume such comments live? On the block itself, or on the members inside the block? We think conceptually we want to reinforce the idea that\nextension parameters and type parameters are copied to the members themselves, not to the block, and the same will extend to documentation on\nthem.\n\n#### Conclusion\n\nThe proposed `ExtensionType.extension(Type).Member` syntax is approved. Implementation members will be referenceable using\n`ExtensionType.Member`. Extension blocks are not referenceable entities.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-06-11.md",
    "content": "# C# Language Design Meeting for June 11th, 2025\n\n## Agenda\n\n- [Extensions](#extensions)\n    - [Dynamic resolution of operator `true`/`false`](#dynamic-resolution-of-operator-truefalse)\n    - [Extension operators in LINQ expression trees](#extension-operators-in-linq-expression-trees)\n    - [Built-in operator protection rules](#built-in-operator-protection-rules)\n    - [Extension module initializers](#extension-module-initializers)\n    - [Extension methods as entry points](#extension-methods-as-entry-points)\n    - [Langversion behavior for new extensions](#langversion-behavior-for-new-extensions)\n    - [`nameof`](#nameof)\n\n## Quote of the Day\n\nNothing particularly amusing was said today, sorry.\n\n## Discussion\n\n### Extensions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8697  \nSpecifications:\n* https://github.com/dotnet/csharplang/blob/fdc35c9c2c2ff4fd532c9733a9ade5f89d37018e/proposals/extension-operators.md\n* https://github.com/dotnet/csharplang/blob/fdc35c9c2c2ff4fd532c9733a9ade5f89d37018e/proposals/extensions.md\n\n#### Dynamic resolution of operator `true`/`false`\n\nQuestion: https://github.com/dotnet/csharplang/blob/fdc35c9c2c2ff4fd532c9733a9ade5f89d37018e/proposals/extension-operators.md#dynamic-evaluation\n\nWe think the proposed restriction makes sense. The C# spec says that when one or both operands of a binary operator is dynamic, the entire operation, including lookup of\noperator `true`/`false`, occurs at runtime. The compiler performing the lookup at compile-time for operator `true`/`false` for the non-dynamic operand is an optimization, nothing\nmore, and the dynamic binder would not be able to find extension `true`/`false` operators, just as it can't find instance extension methods today.\n\n##### Conclusion\n\nRestriction accepted. Extension operator `true`/`false` are not used for `dynamic` `&&` or `||`.\n\n#### Extension operators in LINQ expression trees\n\nQuestion: https://github.com/dotnet/csharplang/blob/fdc35c9c2c2ff4fd532c9733a9ade5f89d37018e/proposals/extension-operators.md#use-of-extension-operators-in-linq-expression-trees\n\nThe proposal was accepted without further discussion beyond what is in the question itself.\n\n##### Conclusion\n\nAccepted.\n\n#### Built-in operator protection rules\n\nSpecification: https://github.com/dotnet/csharplang/blob/fdc35c9c2c2ff4fd532c9733a9ade5f89d37018e/proposals/extension-operators.md#is-the-rule-an-extension-operator-may-not-have-the-same-signature-as-a-predefined-operator-worth-having-as-specified\n\nFurther testing of our proposed rules for protecting built-in operators has revealed holes in our proposal, namely when conversions to built-in types are involved, bypassing\nthe existing rule. While we could create a more complicated rule to address this, involving overload resolution, we don't like the end result: it's a complicated rule that we\ndon't feel carries sufficient weight to justify the complexity. We could reduce this to a warning instead, and conceptually don't have an issue with it, but we don't\nthink that such a warning must be present; we think that when a predefined operator is chosen over an extension operator, it will be fairly obvious what is happening.\n\n##### Conclusion\n\nRule is abandoned. We will not have built-in errors or warnings here.\n\n#### Extension module initializers\n\nQuestion: https://github.com/dotnet/csharplang/blob/fdc35c9c2c2ff4fd532c9733a9ade5f89d37018e/proposals/extensions.md#open-issues\n\nThe question here is whether to permit extension implementation members to be module initializers. We don't have any motivating scenarios here and don't have a proposal\nfor how the attribute would be applied to either skeleton or implementation members. Therefore, we will reject this until we have motivation to implement it.\n\n##### Conclusion\n\nRejected.\n\n#### Extension methods as entry points\n\nQuestion: https://github.com/dotnet/csharplang/blob/fdc35c9c2c2ff4fd532c9733a9ade5f89d37018e/proposals/extensions.md#open-issues\n\nWe must keep the implementation methods for instance extension methods as entry point candidates, as it works today and we have a strong back-compat goal here. Therefore,\nwe intend to continue permitting methods that end up having an implementation method with a valid entry point signature to be considered in the set of possible entry points.\n\n##### Conclusion\n\nImplementation methods that have a valid signature will be considered among the possible entry point candidates.\n\n#### Langversion behavior for new extensions\n\nQuestion: https://github.com/dotnet/csharplang/blob/fdc35c9c2c2ff4fd532c9733a9ade5f89d37018e/proposals/extensions.md#open-issues\n\nAfter some consideration, we don't think we need to have lookup consider language version for the actual lookup process itself. The scenarios in which a user could\nrun into issues are:\n\n* A delegate-returning property gets ahead of an old-style extension method, so `obj.M()` becomes an invocation of the delegate returned from the property `M`.\n* A method group used as an assignment/argument gets superseded by an extension property, so `M(e.MethodGroup)` goes from a method to a property.\n\nIn either of these cases, we will issue a LangVersion diagnostic but won't otherwise complicate lookup with exceptions around excluding new-style extensions. The main\nconcern is that we can't issue a diagnostic for instance extension methods, since you can already have them today and going from old to new style is not otherwise a breaking\nchange.\n\n##### Conclusion\n\nWe will issue LangVersion diagnostics on successful lookups/overload resolutions that pick a non-instance extension method.\n\n#### `nameof`\n\nQuestion: https://github.com/dotnet/csharplang/blob/fdc35c9c2c2ff4fd532c9733a9ade5f89d37018e/proposals/extensions.md#nameof\n\nFinally today, we took a look at `nameof` rules. There's a bit of tension here: we want to allow referencing an extension property in a `nameof`, but we want to be\nconsistent with current rules around extension-based lookup in `nameof`. Today, extension methods cannot be referenced in `nameof` off their extended type or an instance\nof their extended type. They must be looked up on the extension container. This restriction was mostly about cutting design time to get extension methods shipped, and we're mixed\non whether to keep it long term. We don't think that this is the entire solution though, as ambiguity once again raises its head. We came up with 3 main approaches to the\nlookup:\n\n1. `ExtensionContainer.extension(param).Member` - Essentially borrow the cref syntax. We think this is too heavy-handed for just `nameof` and want to avoid it.\n2. `ExtendedType.Member` - Allow this form and likely lift the restriction on all extension members. Do nothing to provide disambiguation syntax.\n3. `ExtensionContainer.Member` - Simply make this lookup work, even for extension properties and events.\n\nWe think we want option 3; it's the most consistent with the current approach and ensures that there isn't multiple ways to reference the member. At the same time, though,\nwe know that we likely will not have time to design and implement this lookup for C# 14; after design, we may even decide that we don't like how the rules turn out and need\nto go back to the drawing board. Given this, we've decided that we will likely not support `nameof` on extension properties for C# 14. We will revisit and take up\nthe design pen again as soon as we can here, but do not want to jeopardize shipping the feature over `nameof` support.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-06-18.md",
    "content": "# C# Language Design Meeting for June 18th, 2025\n\n## Agenda\n\n- [Iterators in lambdas](#iterators-in-lambdas)\n- [Extensions](#extensions)\n\n## Quote of the Day\n\n- \"A manager isn't on the hook\" \"Oh they are, they're just on the hook for making sure someone else is on the hook\"\n\n## Discussion\n\n### Iterators in lambdas\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9467  \nSpecification: https://github.com/dotnet/csharplang/blob/ca5b8eb445846c2f5aa394a48cd0992bef76c277/proposals/iterators-in-lambdas.md\n\nWe started today with a look at a proposal, allowing lambdas to be iterators. We are overall in support of this proposal, though several\nopen questions will need further looks. The main questions we have are:\n\n* How close should we align with Visual Basic's behavior?\n* What should the default return type of an iterator be? `IEnumerable`, or `IEnumerator`?\n    * We do think that once we decide on that, sync vs async should be easier: lambdas marked `async` should be `IAsyncEnumera(ble|tor)`,\n      and non-`async` lambdas would be `IEnumera(ble|tor)`.\n\nWe will accept this proposal into the working set for future work.\n\n#### Conclusion\n\nProposal accepted, moved to the working set.\n\n### Extensions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8697  \nSpecification: https://github.com/dotnet/csharplang/blob/ca5b8eb445846c2f5aa394a48cd0992bef76c277/proposals/extensions.md  \nReviewed Document: https://github.com/dotnet/csharplang/blob/ca5b8eb445846c2f5aa394a48cd0992bef76c277/meetings/working-groups/extensions/content-based-naming.md\n\nWe spent most of the meeting reviewing the new proposal for how extension metadata is preserved in naming. One of the key issues we want to address is stability; while these\nare mostly implementation details to end users, there are various implementation details in the middle that need to care. `cref`s, for example, or public API tracking across\nlibrary versions. These intermediates need to understand the metadata layout in order to provide good tracking, and by adjusting our proposed mechanisms, we can better serve\nthese applications while still providing the same end user experience.\n\nOne thing we've realized, as we delved into the details here, is that we don't know how to entirely have our cake and eat it too. The runtime does not allow us to overload on\nconstraints, so that means that constraints must be included in the generated names that we end up using. But that also means that removing a constraint becomes a breaking\nchange for these intermediary tools, which is not something that has been true in C# before. We think we're ok with this; for things like the API tracking tools, this is\nsomething they can adapt to, and is easier to adapt to than the larger changes that would have happened in the previous versions of the tooling. For crefs, it's unfortunate,\nbut we don't think that crefs are a large enough issue to need further design here. We also considered whether to adopt a version of the encoding that would allow methods to\navoid the breaks; properties and events can't avoid it, but methods could. We don't think the tradeoff in complexity is worth it, so we will stick with the initial proposal.\n\nWe also considered hashing algorithms for a bit. We're ok with the proposal, particularly the reason for avoiding hashes used in cryptographic scenarios.\n\n#### Conclusion\n\nNew approach is accepted.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-06-23.md",
    "content": "# C# Language Design Meeting for June 23rd, 2025\n\n## Agenda\n\n- [Extensions](#extensions)\n    - [Use of extension operators in LINQ expression trees](#use-of-extension-operators-in-linq-expression-trees)\n    - [`ref` encoding and conflict checks](#ref-encoding-and-conflict-checks)\n    - [Extern support](#extern-support)\n    - [Lookup](#lookup)\n\n## Quote of the Day\n\n- \"So we pick the method\" \"But the spec says that should have been an ambiguity\"\n- \"That can't be it, we have 20-odd minutes left in the meeting. That's illegal!\"\n\n## Discussion\n\n### Extensions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8697  \nSpecifications:\n* https://github.com/dotnet/csharplang/blob/d9aac41d8b0ff4d2bb322ffb8f85a4a4a14690df/proposals/extensions.md\n* https://github.com/dotnet/csharplang/blob/d9aac41d8b0ff4d2bb322ffb8f85a4a4a14690df/proposals/extension-operators.md\n\n#### Use of extension operators in LINQ expression trees\n\nQuestion: https://github.com/dotnet/csharplang/blob/main/proposals/extension-operators.md#use-of-extension-operators-in-linq-expression-trees\n\nPreviously, we'd decided to use the existing `Expression` factory methods for expression trees. This works in most cases, but\nfalls over in scenarios that need multiple extension operators, such as `&&` or `||`. For these scenarios, the ideal fix would\nbe to add a new factory method, but we don't think this is something that we can do at this time. Therefore, we'll simply note\nthe issue in documentation, and if we make future changes to expression trees, we could potentially address this shortcoming then.\n\n##### Conclusion\n\nProposed rules approved. `&&` and `||` implemented via extensions will not be allowed in expression trees.\n\n#### `ref` encoding and conflict checks\n\nQuestion: https://github.com/dotnet/csharplang/blob/d9aac41d8b0ff4d2bb322ffb8f85a4a4a14690df/proposals/extensions.md#metadata\n\n> Confirm that `ref` should not be included in extension type name\n\nAfter some discussion here, we realized that the question has some fundamental issues that need to go back to the working group.\nhttps://github.com/dotnet/roslyn/issues/79043 demonstrates an issue with our current conflict checking rules; because we do not\nconsider `ref`ness when doing signature conflict checking, we prevent this scenario from migrating to new extensions. We also\ndon't think this is particularly edge case code; it's certainly not mainstream, but it's not a truly niche thing. The proposed rules\nfor `ref` name encoding would be at odds with allowing this code to be valid C#; while that particular scenario would be okay\nbecause the constraints would force the creation of two different skeleton containers, the constraints are not the important bit\nthat allows the code to be valid. What allows the code to be valid is the `ref`ness, and it would be odd to have a form that is\nallowed in C# but we can't actually emit in many cases. Given this, the working group will take another look at the conflict rules\nand bring back a new proposal for how to encode these bits.\n\n#### Extern support\n\nQuestion: https://github.com/dotnet/csharplang/blob/d9aac41d8b0ff4d2bb322ffb8f85a4a4a14690df/proposals/extensions.md#extern\n\nWe confirmed support here. Existing extensions support `extern`, so the new ones will too.\n\n#### Lookup\n\nQuestion: https://github.com/dotnet/csharplang/blob/d9aac41d8b0ff4d2bb322ffb8f85a4a4a14690df/proposals/extensions.md#lookup\n\n##### Question 1\n\n> Confirm that we want betterness rules to apply even when the receiver is a type\n\nNext, we looked at the proposed static member betterness rules. The existing rules are based on the model that there is an implicit\nparameter here, the type itself, and that therefore everything that goes into standard parameter checking should go into\nbetterness for static invocations. We don't feel that this is a convincing argument, as there is no value to applying refness to here.\nFurther, it would mean that users would need to understand that it would be a source-breaking change to move an extension from an\n`extension(in int)` block to an `extension(int)` block, because it could affect the tiebreaking with another library's extensions.\nWe therefore conclude that static extension lookup will only look at the type being extended when doing resolution, not any other\ntiebreaking criteria.\n\n###### Conclusion\n\nFor static extension members, we will only use the type for the extra \"parameter\".\n\n##### Question 2\n\n> Confirm that we don't want some betterness across all members before we determine the winning member kind\n\nWe're concerned here that if we don't support some form of betterness, it will block users from being able to move things that are\ncurrently written as extension methods but would be better written as extension properties. These APIs are expressed as well as\nthey can be today, given that we don't have extension properties today. We feel strongly that these APIs should be able to work,\nbut we are also uncertain as to whether we can reasonably deliver this experience before C# 14 releases. The status quo does\nprotect our ability to design rules that by and large do the \"right\" thing by default, invoking methods where appropriate and\ncalling properties when appropriate. We'll therefore proceed with this, and work on a design for making this \"just work\".\n\n###### Conclusion\n\nAmbiguity rules will be left in place while we work on creating rules for making code work as the user would expect.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-06-25.md",
    "content": "# C# Language Design Meeting for June 25th, 2025\n\n## Agenda\n\n- [Unions](#unions)\n    - [Stand-alone issues](#stand-alone-issues)\n    - [Mutually exclusive issues](#mutually-exclusive-issues)\n\n## Quote of the Day\n\n- \"Runtime typo unions\"\n\n## Discussion\n\n### Unions\n\nChampion issue(s):\n* Closed enums: https://github.com/dotnet/csharplang/issues/9011\n* Nominal type unions: https://github.com/dotnet/csharplang/issues/9411\nDocuments:\n* https://github.com/dotnet/csharplang/blob/0809d6632e3f8d15d3ead205bfc83bd35816aa8f/meetings/working-groups/discriminated-unions/Trade%20Off%20Matrix.md\n\nToday, we took a dive into unions. The unions working group has come back with a set of discrete proposals to try and help narrow the\npotential options for where we should invest in unions in C#. There are 5 discrete proposals here, 3 of which stand on their own, and\nthen 2 of which are likely mutually exclusive. We did not dig into syntax or precise semantics for any of these today.\n\n#### Stand-alone issues\n\n* https://github.com/dotnet/csharplang/blob/0809d6632e3f8d15d3ead205bfc83bd35816aa8f/meetings/working-groups/discriminated-unions/Closed%20Enums.md\n* https://github.com/dotnet/csharplang/blob/0809d6632e3f8d15d3ead205bfc83bd35816aa8f/meetings/working-groups/discriminated-unions/Closed%20Hierarchies.md\n* https://github.com/dotnet/csharplang/blob/0809d6632e3f8d15d3ead205bfc83bd35816aa8f/meetings/working-groups/discriminated-unions/Case%20Classes.md\n\nThese are closed enums, closed hierarchies, and case classes. We feel that these are fairly orthogonal to the type union proposals\nbelow, and make sense on their own. Closed enums and hierarchies are mainly about getting users the ability to be exhaustive in such\na way that they will get explicit source-breaking changes when new cases are added, and case classes are then a syntax sugar to allow\ndeclaring such type hierarchies in a more ergonomic fashion. We strongly believe that these should be a priority for the LDM in the\nnear term.\n\n#### Mutually exclusive issues\n\n* https://github.com/dotnet/csharplang/blob/0809d6632e3f8d15d3ead205bfc83bd35816aa8f/meetings/working-groups/discriminated-unions/Runtime%20Type%20Unions.md\n* https://github.com/dotnet/csharplang/blob/0809d6632e3f8d15d3ead205bfc83bd35816aa8f/meetings/working-groups/discriminated-unions/Nominal%20Type%20Unions.md\n\nThe other two proposals are likely mutually exclusive. We're not certain that C# has room for two different sets of semantics here.\nThere is an elegance in the nominal approach in the way that it does not try to pretend about the cases, and that there is no `is-a`\nrelationship that would either leak through or need runtime support for. The timelines for it are also shorter, as runtime support\nwould take some non-trivial amount of time. Given these, we lean towards nominal type unions here.\n\n#### Conclusion\n\nWe will continue working on 4/5 of these proposals: closed enums, closed hierarchies, case classes, and nominal union types.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-06-30.md",
    "content": "# C# Language Design Meeting for June 30th, 2025\n\n## Agenda\n\n- [Type parameter inference from constraints](#type-parameter-inference-from-constraints)\n- [Target-typed static member lookup](#target-typed-static-member-lookup)\n\n## Quote(s) of the Day\n\n- \"You need to get better at ventriloquism\"\n- \"When you said messy field, were you referring to the `field` keyword?\" \"I was seeing if anyone would stoop that low\"\n\n## Discussion\n\n### Type parameter inference from constraints\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9453  \nSpecification: https://github.com/dotnet/csharplang/blob/746d354ce523385ab4f36a94792d4acd64f3b531/proposals/type-parameter-inference-from-constraints.md\n\nWe started today by looking at a proposed breaking change for C#: allowing the type inference phase to use constraints when doing type inference. This is a longstanding\ncommunity request that has been previously rejected due to the risk of breaking changes. However, we feel that in the time since it was rejected, other breaking changes\nin similar areas, most closely the lambda/method group natural type change in C# 10, have given us a blueprint for how to proceed here. In particular, long preview\nperiods will be essential in collecting comprehensive examples of where the breaks will end up happening. In particular, this is an area where we don't have great tools\nto find potential breakage today, as this is not something that is easily searchable via regex. That being said, we are unanimously in support of moving forward with this\nchange, and look forward to seeing it in a future version of C#. Future meetings will need to review the exact rules being proposed, as we did not get into the nitty\ngritty of type inference dependency changes today.\n\n#### Conclusion\n\nApproved in principle, into the working set.\n\n### Target-typed static member lookup\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9138  \nSpecification: https://github.com/dotnet/csharplang/blob/746d354ce523385ab4f36a94792d4acd64f3b531/proposals/target-typed-static-member-lookup.md\n\nNext and last, we looked at another new proposal: target-typed static member lookup. This one is more controversial, both in the community and in the LDM itself. There's\ndefinite tension around a few points:\n\n* How far do we want to take this? There are various cut points we could consider, such as enum members, properties, methods, etc. The more permissive we are, the greater\n  the chance for this to be used to make unreadable code. On the other hand, there are legitimate use cases that we would also like to support. For example, union types\n  may want to be able to infer methods from their containers for creation. We think we need more examples here; both good and bad. This is a gut feeling area, and while\n  we can look to some adjacent ecosystems for inspiration, such as Swift and Dart, ultimately we need to make the decision about what is best in C#.\n* What type of sigil should we use, or should we not use a sigil at all? Again, contemporaries here seem to use `.` as the sigil, and there are some definite benefits\n  to using a discrete sigil. It would ensure that we can't run into `Color Color` problems where we would have to decide whether `Color` is target-typed member access, or\n  a reference to the type named `Color`, or a reference to the member in the current type named `Color`. This area is already complex for both humans and compilers, and\n  making it more so is concerning. One analogy we liked during the meeting was an analogy to `new()`: when you remove the type from expression, `new()` is what remains.\n  Similarly for this feature, when you remove the type from the expression, `.Member` is what remains. We also considered the `_.` syntax as an additional option, but it\n  got no real support after initial suggestion.\n\nAfter some lively debate on this subject, we are moving forward on this topic, with most of the LDM preferring an explicit sigil in `.`, a small contingent preferring\nto not take the feature, and a general need to see more examples and think through the impact they will have further.\n\n#### Conclusion\n\nTopic is moved to the working set, will continue to be reviewed further.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-07-30.md",
    "content": "# C# Language Design Meeting for July 30th, 2025\n\n## Agenda\n\n- ['/main' and top-level statements](#main-and-top-level-statements)\n- [Union proposals overview](#union-proposals-overview)\n- [Add type parameter restriction to closed hierarchies](#add-type-parameter-restriction-to-closed-hierarchies)\n- [Standard unions](#standard-unions)\n- [Union interfaces](#union-interfaces)\n- [Custom unions](#custom-unions)\n- [Non-boxing access pattern](#non-boxing-access-pattern)\n\n## Quote(s) of the Day\n\n- (Attendee lifting their cat) \"is having their Lion King moment!\"\n\n## Discussion\n\n### '/main' and top-level statements\n\nPull request: https://github.com/dotnet/csharplang/pull/9546\n\nShould we allow specification of an entry point with `/main` even when there are top-level statements? This would help some scenarios using the new single-file `app.cs` capability.\n\nThe core concern is that the top-level program cannot then be called programmatically from other entry points, because it is generated with an unspeakable name. Arguably, this should be paired with a proposal to make top-level programs callable.\n\n#### Conclusion\n\nWe're ok adopting the proposal now, so that scenarios can start lighting up, and then likely embracing a design for callable top-level programs in the future.\n\n### Union proposals overview\n\nAs a PSA, the [Union proposals overview](https://github.com/dotnet/csharplang/blob/main/meetings/working-groups/discriminated-unions/union-proposals-overview.md) is a useful document to follow the many union-related proposals currently being investigated and adopted.\n\n### Add type parameter restriction to closed hierarchies\n\nPull request: https://github.com/dotnet/csharplang/pull/9560\n\nThis attempts to plug a hole in the current [Closed hierarchies](https://github.com/dotnet/csharplang/blob/main/proposals/closed-hierarchies.md) proposal where \"fresh\" type parameters on a class deriving from a closed class can hamper exhaustiveness in switches:\n\n```csharp\nclosed class C<T> { ... }\nclass D<T> : C<T> { ... }\nclass E<T, U> : C<T> { ... }\n\nC<int> c = ...;\n_ = c switch\n{\n    D<int> d => ...,\n    E<int, ???> e => ..., // Can't put anything as '???' to exhaust all instantiations of `E`\n}\n```\n\nWhile there only exists one instantiation of `D<...>` that is implicitly convertible to `C<int>` (namely `D<int>`), there's an infinite number of instantiations of `E<...>` (anything where the first type argument is `int`) that are. So even though `C` is closed, it is not possible to write an exhaustive switch without a fallback clause, undermining the point of declaring `C` closed in the first place.\n\nWe would like to catch this problem at the declaration of `E<T, U>`. The proposal suggests doing this by requiring all type parameters of a class deriving from a closed class to be used in the base class specification. E.g. in `class D<T> : C<T>` all type parameters (`T`) are being used in `C<T>`, whereas in `E<T, U> : C<T>` only `T` is used in `C<T>`, not `U`.\n\nWe think the proposed rule goes a long way to plug the hole, but are not entirely convinced it is enough. We discussed adding stronger rules, e.g. requiring type parameters to be used *as*, not just *in*, type arguments to the base class, or preventing derived classes from being explicitly generic altogether (they would have to be nested).\n\nWe also touched on generic variance. Class type parameters cannot be variant today, but in the future we might extend the closed hierarchies feature to interfaces, or even allow classes to express variance. If we were to do either we would need to reevaluate whether we have the right rules in place here: With variance, more than one generic instantiation of a derived type could still be implicitly convertible to the base type; however there might be one that is the base type of all the other instantiations and could be used in exhaustive switches.\n\n#### Conclusion\n\nWe adopted the proposal as an improvement; however, we need to keep thinking about this; in particular, a constructive description of how to get from a generic instantiation of the closed class to at most one of each derived class would be useful. \n\nWe think the proposed tighter restrictions are too draconian and affect real scenarios. As for variance, we can cross that bridge when we get there; as a fallback we can always forbid variant type parameters in a closed type.\n\n### Standard unions\n\nSpecification: https://github.com/dotnet/csharplang/blob/5736dbf3d4008498acb120669a4ede96dd69e104/meetings/working-groups/discriminated-unions/standard-unions.md\n\nThe proposal is to offer standard generic `Union<...>` types in the BCL, similar to e.g. `Action` and `Func` types:\n\n```csharp\npublic union Union<T1, T2>(T1, T2);\npublic union Union<T1, T2, T3>(T1, T2, T3);\n... // etc\n```\n\nUnlike e.g. `ValueTuple<...>` the current proposal does not bother with a \"nesting\" scheme, but just caps the number of case types offered in this way.\n\nThe benefit is similar to e.g. `Func`: Smaller scenarios, where a named abstraction isn't really helpful, can just grab a standard union type \"off the shelf\".\n\nThere is a small concern that it won't be intuitive that these don't unify across different orders of the case types; e.g., `Union<string, bool>` vs `Union<bool, string>`. However, since the types are not special language syntax but just library types, hopefully it will be unsurprising that they act as such.\n\n#### Conclusion\n\nAdopted as proposed, with the understanding that the .NET library team has final say in the shape of these types.\n\n### Union interfaces\n\nSpecification: https://github.com/dotnet/csharplang/blob/5736dbf3d4008498acb120669a4ede96dd69e104/meetings/working-groups/discriminated-unions/union-interfaces.md\n\n#### Non-generic 'IUnion' interface\n\nThe proposal is to add an `IUnion` interface that simply enshrines the `Value` property of unions: \n\n```csharp\npublic interface IUnion\n{\n    object? Value { get; }\n}\n```\nUnion declarations in C# would automatically add this interface to the lowered type. \n\nThis allows code to dynamically test if something is of a union type, and if so, get at its contained value. It also can be used as a marker for e.g. the compiler to treat a type as a union type; see [Custom unions](#custom-unions) below.\n\nIn some ways this is analogous to `ITuple` which allows tuple values to be dynamically discovered and interacted with.\n\n##### Conclusion\n\nAdopted as is.\n\n#### Generic 'IUnion' interface\n\nThe proposed interface declares a static method to test whether an incoming value could be contained in the implementing union type, and if so creates such a union value from it:\n\n```csharp\npublic interface IUnion<TUnion> : IUnion where TUnion : IUnion<TUnion>\n{\n    static abstract bool TryCreate<TValue>(TValue value, [NotNullWhen(true)] out TUnion union);\n}\n```\n\nAgain union declarations in C# would automatically add this interface to the lowered type. \n\nWe noted that the method is a \"GVM\" - a generic virtual method, which is bad for AOT compilation and generally avoided, especially in widely-used library types. The type is generic only so that it can avoid boxing when the incoming value is of a value type. We could instead declare the method non-generically as:\n\n```csharp\npublic interface IUnion<TUnion> : IUnion where TUnion : IUnion<TUnion>\n{\n    static abstract bool TryCreate(object? value, [NotNullWhen(true)] out TUnion union);\n}\n```\n\n##### Conclusion\n\nWe're on board with the value of the proposal, but want to go with the non-GVM version of the `TryCreate` method.\n\n#### 'IUnionUnboxed' interface\n\nThe proposed interface would allow a general means of querying union types for content of a given type, without causing boxing of the value. This is as an alternative to asking though the `IUnion.Value` property described above, which would cause boxing of value types.\n\n##### Conclusion\n\nWe summarily dismissed this proposal, as it relies fundamentally on a GVM. As with the previous interface we want to start from a position of preferring potential boxing to the risks of GVMs.\n\n### Custom unions\n\nSpecification: https://github.com/dotnet/csharplang/blob/5736dbf3d4008498acb120669a4ede96dd69e104/meetings/working-groups/discriminated-unions/custom-unions.md\n\nThe overall proposal is to allow developers to write their own union types \"manually\" instead of having them generated by the new `union` syntax. When following the proposed pattern (implement the non-generic `IUnion` interface and offer a public constructor for each case type), the compiler would allow the type to be consumed equally to a compiler-generated union type, in terms of:\n\n- Implicit conversion from each case type to the union type,\n- Pattern matching that implicitly indirects through the `Value` property, and\n- Exhaustiveness in switch expressions.\n\nThis allows existing types that are already effectively union types to be imbued with first-class language behavior, as well as new union types that for various reasons use other strategies for e.g. content storage.\n\n#### Conclusion\n\nAdopted. It's possible the specific pattern will evolve slightly as we build the feature, but this is a great place to start from.\n\n### Non-boxing access pattern\n\nSpecification: https://github.com/dotnet/csharplang/blob/5736dbf3d4008498acb120669a4ede96dd69e104/meetings/working-groups/discriminated-unions/non-boxing-access-pattern.md\n\nFor efficiency, some custom unions may store their contents in a non-boxing manner. However, such efficiency gains are thwarted if the value can only be accessed through the `Value` property, which would just box them anyway.\n\nThe proposal is for the compiler to recognize an optional alternative access pattern on unions that avoids boxing. With this pattern, the custom union type offers a `HasValue` property for null checking, and a `TryGetValue` method for each case type, e.g.:\n\n```csharp\npublic struct MyUnion : IUnion\n{\n    public bool HasValue => ...;\n    public bool TryGetValue(out Case1 value) {...}\n    public bool TryGetValue(out Case2 value) {...}\n    \n    object? IUnion.Value => ...;\n}\n```\n\nPattern matching will then be implemented in terms of these members rather than the `Value` property when possible.\n\n#### Conclusion\n\nAdopted."
  },
  {
    "path": "meetings/2025/LDM-2025-08-13.md",
    "content": "# C# Language Design Meeting for August 13th, 2025\n\n## Agenda\n\n- [Unions](#unions)\n\n## Quote of the Day\n\n- \"The operation succeeded, but the patient died\"\n\n## Discussion\n\n### Unions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8928  \n\nUnion overview:\n* https://github.com/dotnet/csharplang/blob/c3325533e57dec6aec3266e066e39abf7260e87a/meetings/working-groups/discriminated-unions/union-proposals-overview.md\n\nSpecs:\n* https://github.com/dotnet/csharplang/blob/eb5381bf21b884a0dca53c9e127c0f527503fdfc/proposals/closed-hierarchies.md\n* https://github.com/dotnet/csharplang/blob/eb5381bf21b884a0dca53c9e127c0f527503fdfc/proposals/nominal-type-unions.md\n* https://github.com/dotnet/csharplang/blob/eb5381bf21b884a0dca53c9e127c0f527503fdfc/proposals/case-declarations.md\n\nReviewed document:\n* https://github.com/dotnet/csharplang/blob/eb5381bf21b884a0dca53c9e127c0f527503fdfc/meetings/working-groups/discriminated-unions/to-nest-or-not-to-nest.md\n\nWe spent the meeting discussing union type nesting. There are two axes to consider: closed hierarchies vs. unions, and nested vs. non-nested types. We examined all four\ncombinations and, while we did not reach a decision, several ideas emerged:\n\n1. For closed hierarchies, we're unsure whether we actually need a \"brief\" syntax. We think these are scenarios that are naturally more complex and\n   don't have built-in assumptions, so we might not benefit much from an opinionated, more succinct syntax.\n2. We're also unsure whether unions need a brief syntax for top-level cases. We think these might be the more opinionated types, much like records\n   are more opinionated than classes, and that nesting might be the opinion that unions have.\n3. For type inference, we aren't too concerned by this given the above defaults, but we are open to the new type inference improvements being\n   proposed as part of this feature. We don't think they are blockers, though.\n4. There's some similarity between the designs we've arrived at and Scala 3's design decisions, so we do have some prior art that we can examine\n   further.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-08-18.md",
    "content": "# C# Language Design Meeting for August 18th, 2025\n\n## Agenda\n\n- [C# 15 Kickoff and Themes](#c-15-kickoff-and-themes)\n    - [Unions](#unions)\n    - [Extensions](#extensions)\n    - [Dictionary expressions](#dictionary-expressions)\n    - [Type inference](#type-inference)\n    - [Continuing the null monad](#continuing-the-null-monad)\n    - [Object initialization](#object-initialization)\n    - [Top-level methods](#top-level-methods)\n    - [Caller type name](#caller-type-name)\n    - [Switch statement/expression improvements](#switch-statementexpression-improvements)\n\n## Quote of the Day\n\n- \"Well, now I can't unsee that.\" \"I can't unsee that either.\" \"Well, it used to be a you problem.\"\n\n## Discussion\n\n### C# 15 Kickoff and Themes\n\nToday we took a look through some active topics on the minds of various LDM members for C# 15, which follow below in a somewhat raw form.\n\n> [!NOTE]\n> While we will be working on many/most of these topics during the C# 15 timeframe, no release timeframe or guarantee is given at this time.\n> Particularly for highly requested topics like unions, please keep in mind: we'll get there when we get there.\n\n#### Unions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8928  \n\nWe have a lot of union work in progress, and an overview can be found at\nhttps://github.com/dotnet/csharplang/blob/c3325533e57dec6aec3266e066e39abf7260e87a/meetings/working-groups/discriminated-unions/union-proposals-overview.md.\nWe'll be continuing design work here and are hopeful that C# 15 will at least have preview versions of features in this area.\n\n#### Extensions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8697  \n\nC# 14 will deliver the next iteration of extension members, but we did not get to all the member types we want yet. We expect to turn the\ncrank on this in C# 15. Of particular interest are the other basic member types that we haven't implemented yet and disambiguation on methods\nvs. properties.\n\n#### Dictionary expressions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8659  \n\nA decent amount of design work went into dictionary expressions in C# 14, but time constraints ultimately meant we did not get to ship them. We'd\nlike to get them over the line for C# 15.\n\n#### Type inference\n\nChampion issues:\n* https://github.com/dotnet/csharplang/issues/9453\n* https://github.com/dotnet/csharplang/issues/9626\n* https://github.com/dotnet/csharplang/issues/9627\n\nSeveral type inference proposals have come up at this point, both on their own and as part of unions. We're starting to think there may be a theme\nof type inference improvements we could make for C# 15.\n\n#### Continuing the null monad\n\nWe have a few proposals around `foreach?` and `await?`, maybe it's time to revisit these.\n\n#### Object initialization\n\nThere are a few improvements around object initialization that have been considered for a few years, such as expanded object initializers,\n`init` fields, final validators, and more abilities in `with` expressions.\n\n#### Top-level methods\n\nA few LDM members have been looking at a proposal around allowing top-level methods more broadly, and also expanding where extension blocks can be\ndeclared. We may end up delving further into this.\n\n#### Caller type name\n\nOf all the caller info attributes, `CallerTypeName` is one of the most requested.\n\n#### Switch statement/expression improvements\n\nBlock bodies for switch expressions and improvements to the switch statement have been on our minds for a while.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-08-20.md",
    "content": "# C# Language Design Meeting for August 20th, 2025\n\n## Agenda\n\n- [Discussion](#discussion)\n    - [Union interfaces](#union-interfaces)\n    - [Target-type inference improvements](#target-type-inference-improvements)\n\n## Quote of the Day\n\n- \"So essentially, we have 1007 votes for\"\n\n## Discussion\n\n### Union interfaces\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9566  \nUnions overview: https://github.com/dotnet/csharplang/blob/c3325533e57dec6aec3266e066e39abf7260e87a/meetings/working-groups/discriminated-unions/union-proposals-overview.md  \nSpecification: https://github.com/dotnet/csharplang/blob/c3325533e57dec6aec3266e066e39abf7260e87a/proposals/union-interfaces.md\n\nWe started today by looking at a proposal for a set of interfaces that would allow existing union-like types to be considered unions by the\nlanguage. This proposal is somewhat complicated, and after some discussion, we're not sure that the problem of adapting existing union-like types\nneeds to be part of the initial set of union features we ship. We have some concerns about whether this will be confusing for new union types to\nimplement, as these interfaces would be preferred even when explicitly implemented on a type, and we're not convinced that these interfaces would\nonly be used by older types. Given this, we want to keep this in our back pocket for now and wait to see user scenarios and explicitly design\naround them, rather than trying to solve it now.\n\n#### Conclusion\n\nTabled for now; we will pick this back up with explicit scenarios in mind.\n\n### Target-type inference improvements\n\nChampion issues:\n* https://github.com/dotnet/csharplang/issues/9626\n* https://github.com/dotnet/csharplang/issues/9627\n\nSpecifications:\n* https://github.com/dotnet/csharplang/blob/c3325533e57dec6aec3266e066e39abf7260e87a/proposals/target-typed-generic-type-inference.md\n* https://github.com/dotnet/csharplang/blob/c3325533e57dec6aec3266e066e39abf7260e87a/proposals/inference-for-constructor-calls.md\n\nNext and last, we looked at proposals for type inference improvements. These affect two main scenarios:\n* When calling generic members and providing a target type, and\n* When calling the constructor of a generic type.\n\nWhile these scenarios are initially motivated by our work in unions, they are by no means only applicable to them. For example, a number of generic\nfactory methods exist only because generic type inference can be performed from the arguments of methods, but not on constructors. We are in favor\nof improvements here, but there will be some difficult compat needles to thread. On the one hand, we want users to be able to apply rules that are\nalready understood to other locations; methods, for example, can be overloaded on generics today. It would be nice if the same intuition that has\nbeen built up around this scenario could apply to types overloaded on generics in constructor calls. On the other hand, we didn't do this back in\nC# 2 because of concerns about breaking changes, and it has been a long time since then. However, we are agreed that we need to do some\ninvestigation and experimentation to find the correct point on the dial for compat, and we do think that these are improvements we would like to\nsee in C#.\n\n#### Conclusion\n\nProposals accepted for the working set.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-08-27.md",
    "content": "# C# Language Design Meeting for August 27th, 2025\n\n## Agenda\n\n- [Type inference in patterns](#type-inference-in-patterns)\n- [Type value conversion](#type-value-conversion)\n- [Union syntax](#union-syntax)\n\n## Quote of the Day\n\n- \"Boiled frogs taste delicious.\" \"Not if you're the frog.\"\n\n## Discussion\n\n### Type inference in patterns\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9630  \nSpecification: https://github.com/dotnet/csharplang/blob/12e6f5b0d512d15d32c8e7ae95674bd070b2758f/proposals/inference-for-type-patterns.md\n\nFirst up today, we looked at the next proposal in the list for type inference improvements. These proposals arise from\nthe general unions discussion but can also be useful outside of unions. In this case, we're looking at type inference\ninside patterns. Unlike the previous two proposals, which were easier sells, LDM is more skeptical about this one. In\nparticular, type inference has more latitude for patterns than it does for constructor calls, since you can start with a\nbase type and narrow to a derived type. In constructors, the `new` must refer to something that either is the same type\nas the target, or has a direct conversion to the target. In patterns, that isn't the case. You can have a pattern that\ndowncasts, upcasts, or checks a completely unrelated interface, which affords much more freedom. We also know of users who\nwill explicitly state types to serve as a `null` check in their patterns, even if that's an identity conversion. There are\nmitigations though: if a user has a generic type in hand and they're pattern matching on it, we think it's unlikely that\nthey would upmatch to the non-generic base rather than to a more derived type. The main scenario we can think\nof in this category would be something like:\n\n```cs\nIEnumerable<string> e = ...;\nif (e is IList) { ... }\n```\n\nUnder the current proposal, this would continue to match `System.Collections.IList`, and not infer\n`System.Collections.Generic.IList<string>`, but should it? Would we consider breaking this behavior? There's also concern\nthat it may be surprising that a pattern, which is supposed to match against a type, might do type inference that isn't\nimmediately visible at the pattern site.\n\nOne potential option would be to always require some sigil or syntax to inform both the compiler and the user that inference\nis happening and expected. For example, `Type<>`. This particular syntax didn't immediately resonate with everyone though;\na few LDT members preferred no syntax at all, and others felt that it might be confusing given that open types in `typeof`\nrequire commas to differentiate how many omitted type parameters exist.\n\nAnother topic we briefly considered was whether to push inference further. An `is Type` check is effectively an `as`\ncombined with an immediate `null` check, and an `as` is just one form of cast. Should both `as` casts and hard casts also\nsupport this? It seems reasonable that if `option is Some` would benefit, `(Some)option` would similarly benefit.\n\n#### Conclusion\n\nWe came up with more questions than answers. This will need further investigation; we see value in the proposal, but\nwe need to think about it more.\n\n### Type value conversion\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8928  \nDocument: https://github.com/dotnet/csharplang/blob/12e6f5b0d512d15d32c8e7ae95674bd070b2758f/meetings/working-groups/discriminated-unions/type-value-conversion.md\n\nNext, we looked at yet another union-related proposal, this time on allowing type expressions to be directly converted to\ninstances. While we think this is useful for singleton union cases, we also think it has applicability outside of unions.\n\nWe think there are at least three approaches we can take to this problem:\n\n1. A conversion, as specified right now. The main disadvantage of this is that conversions generally can't happen in the\n   middle of a dotted expression, except on extension receivers. The advantage, though, is that we don't need to solve\n   a new `Color Color` problem, since we wouldn't be introducing a new spot where type and instance confusion can occur.\n2. Allowing users to define a property with the same name as a nested type. This is the real root of the specific problem\n   that this proposal is solving: we want to allow things like `Option<T>.None` as a value. If that was just a property with\n   the same name as the nested type, then it would work fine. That would give us a new instance of the `Color Color`\n   problem, though, as we'd need to determine, every time we see `Option<T>.None`, whether `None` refers to the property or\n   the type.\n3. Introduce a general operator for this (not a conversion) that can occur in the middle of dotted expressions. This would\n   also require us to solve the general `Color Color` problem, but it is more generally useful than option 2 for non-nested\n   singleton types.\n\nAfter discussion, we preferred option 3: it's the most generally useful and can solve this for both nested and non-nested\ntypes. There are still plenty of design decisions to make, but we like the direction.\n\n#### Conclusion\n\nWe'll work on specifying option 3 more completely.\n\n### Union syntax\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9411  \nUnion overview issue: https://github.com/dotnet/csharplang/issues/8928  \nSpecification: https://github.com/dotnet/csharplang/blob/12e6f5b0d512d15d32c8e7ae95674bd070b2758f/proposals/nominal-type-unions.md\n\nFinally, we took a brief look at our union syntax again. A few members of the LDM and some members of the community are not\nsatisfied with the current `union Pet(Cat, Dog, Bird);` syntax. Much of the current concern can be summarized as \"it looks\nlike a primary constructor that implies order, which it's not.\" One thing we want to make sure of is that we're not\nover-indexing on making new syntax stand out; is this a real consistency issue, or is this just an initial confusion that\nwill fade with usage? We brainstormed a few other syntax options:\n\n1. The original: `union Pet(Cat, Dog, Bird);`\n2. Using bars: `union Pet(Cat | Dog | Bird);`\n3. Using or: `union Pet(Cat or Dog or Bird);`\n4. Using enum bodies:\n```cs\nunion Pet\n{\n    Cat, Dog, Bird\n}\n```\n\nOption 2 received little support. Option 3 provides a nice symmetry with how consumption in patterns will be structured.\nOption 4 has a nice symmetry with enums and potentially provides a single syntax we could use for defining members on both\nunions and enums. We didn't make a decision today, but we do think it's clear that there's enough here to warrant revisiting\nthe syntax decision.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-09-10.md",
    "content": "# C# Language Design Meeting for September 10th, 2025\n\n## Agenda\n\n- [Unions overview](#unions-overview)\n\n## Quote of the Day\n\n- \"I will say 'case' 100 times where no pun is intended, except this one time, where it was intended.\"\n\n## Discussion\n\n### Unions overview\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9662  \nSpecification:\n* https://github.com/dotnet/csharplang/blob/dab5b33a0b41a95cdc0a8a7b9c5bd33d60eb224b/proposals/unions.md\n* https://github.com/dotnet/csharplang/blob/dab5b33a0b41a95cdc0a8a7b9c5bd33d60eb224b/meetings/working-groups/discriminated-unions/union-proposals-overview.md\n\nToday, we took time for a broad overview of the various union proposals being considered for C#, as compiler team members\nare about to start implementation. We need general agreement on the direction and scope of what is being proposed, using\nthe overview linked above and the proposals linked from it. What follows are the points brought up during discussion:\n\n* Union interfaces are still a debated topic, including:\n    * Do we need them at all, or should we wait for concrete use cases?\n    * If we don't add them in the first ship cycle, can we ever add them later?\n    * Do we need both `IUnion` and `IUnion<TUnion>`? We don't have both `IAsyncEnumerable` and `IAsyncEnumerable<T>`; only the generic version exists.\n    * We need to revisit these questions during the first ship cycle, but we'll keep the interfaces as defined for now\n      to avoid blocking compiler work.\n* The specification likely can't claim that a struct union with a single field of a reference type is set/read atomically.\n  C# and ECMA-335 do not guarantee this for non-primitive types, and regardless of whether current implementation realities\n  make it effectively true, nothing stops a compliant runtime implementation from adding padding or otherwise changing the\n  layout of a struct to make reads and writes non-atomic. We may need helpers to ensure this atomicity.\n* Union conversions need more detail, such as whether they are standard conversions and where they participate.\n* Union constructors and their assumptions around well-formedness may need another look: would it be simpler for users and\n  type authors if they received errors instead of the compiler presuming that, given multiple constructors, any will work?\n* There are still general syntax questions; we expect to have full proposals to compare and contrast soon.\n* We may want to start more restrictively regarding user-defined versions of generated properties. It's better to start\n  stricter and loosen later rather than the other way around.\n\n#### Conclusion\n\nWe have a strong opening proposal to start implementation. There are still plenty of decisions to make, but we are confident\nwe can proceed and start getting this into people's hands for feedback.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-09-17.md",
    "content": "# C# Language Design Meeting for September 17th, 2025\n\n## Agenda\n\n- [Unsafe evolution](#unsafe-evolution)\n\n## Quote of the Day\n\n- \"I looked at the MITRE CVEs, and this is the bad stuff they classify as memory safety. Let's have none of that.\"\n\n## Discussion\n\n### Unsafe evolution\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9704  \nProposal: https://github.com/dotnet/designs/blob/656ade997fceb32d6ff1c3ebd5a8ef10e798361e/proposed/caller-unsafe.md\n\nToday, we took a look at a proposal on expanding the definition of unsafety in C#. This was a very broad overview session; we did not dig heavily into specifics of how it would\nactually work, other than a bit of digression around inheritance. The proposal is far more complex than we have gone over today and will need much more detail to be formalized\nbefore LDM can truly sign off on the specifics. On inheritance, we had some discussion around what `unsafe` means on a type in this new world, and whether overrides can\nadd `unsafe` where the overridden method is not marked `unsafe`. Initial reactions here suggest that we may block both of these things; in this new proposal on unsafety, types\nare not inherently unsafe in and of themselves. Just having a pointer field is not unsafe by itself; the unsafety occurs when that pointer is dereferenced, or passed to a location\nthat the compiler cannot verify for safety (such as interop).\n\nOverall, we are positive on the direction of this feature, but we'll definitely need to dig into specifics of the language proposal as it becomes clearer and more filled out.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-09-24.md",
    "content": "# C# Language Design Meeting for September 24th, 2025\n\n## Agenda\n\n- [Union Syntax Thunderdome Part 1](#union-syntax-thunderdome-part-1)\n\n## Quote(s) of the Day\n\n- \"You'll all choke on your own bile and say that can't possibly be the solution\"\n- \"I got a head start on showing [redacted] that they're wrong. You know, I gotta get my hand up there and make sure I'm first in line.\"\n- \"Let's get a yummy rare steak in the ground\"\n\n## Discussion\n\n### Union Syntax Thunderdome Part 1\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9662  \nSpecification: https://github.com/dotnet/csharplang/blob/38fd5f33d285cb190268f98cea16223cc0a5b8bc/proposals/unions.md  \nProposals:\n* https://github.com/dotnet/csharplang/blob/38fd5f33d285cb190268f98cea16223cc0a5b8bc/meetings/working-groups/discriminated-unions/allows.md\n* https://github.com/dotnet/csharplang/blob/38fd5f33d285cb190268f98cea16223cc0a5b8bc/meetings/working-groups/discriminated-unions/brace-syntax.md\n\nToday we begin the syntax thunderdome for unions: while we don't expect to make every decision today (and spoiler alert, we did not), we need to make enough progress today and\nin the next couple of meetings for the compiler team to start implementation without later needing to significantly redesign the parsing stages. We have a few different options\non the table, and we started to break them down by philosophies. Specifically, we have 2 main flavors of union here: a union that states that its cases are pre-existing\ntypes, and a union that states that its cases are types that should be generated inline. One major question, therefore, is whether or not we expect these different flavors to\nmix; do we expect users to often declare intermixed unions of both pre-existing types and new types, or do we expect it to be homogenous. And, if we often expect it to be\nhomogenous, do we really need a syntax that allows both flavors in a single union declaration? One key insight is that the union of newly created types is just sugar over the\nunion of pre-existing types; we can likely formalize the former as literally desugaring into the latter, with the new types declared as nested types within the union. This then\npotentially allows us to nicely relate this back to `enum`s; we can say that `enum`s are for declaring _new_ cases (whether that's numeric cases or types cases), and `union` is\nspecifically for bundling a group of existing types. We could then potentially allow a grow-up story for `enum`s where they can add new types of members. Some difficult hurdles\nremain in that area though:\n\n* How does the language decide whether an `enum` is number-based or type-based? Is the difference just in whether any of the cases has nested values? Is that too subtle?\n    * Other languages do use just this nested value presence in similar fashions, like Swift and Rust, but neither are quite like C# enums.\n    * Could we perhaps use a modifier like `enum class` or `enum struct` to convey this difference?\n* How would such enums interact with `System.Enum`? Would we change the runtime to allow them to inherit from `System.Enum`? Would that be too large of a breaking change?\n    * If they don't interact with `System.Enum`, is that too large a divergence to continue using the `enum` keyword?\n\nWe do think that this idea has some merit and needs to be explored, and several LDM members plan to do just that ahead of Monday's meeting. We also took some initial reads of\nthe room on the basic building blocks of unions. So far, LDM leans towards unions not having a dedicated shorthand syntax for declaring new types; they are made up of existing\ntypes. We are not ruling out the separate `enum` of types idea that would desugar into a `union` with nested declarations, but to use an analogy to `class`es and `record`s,\n`union`s would be the more general building block on which a potential `enum` of types feature would build, just as `class`es are the building block on which `record`s build.\n\nWe also thought about whether the cases of `union`s should be inside or outside the curly braces of the body. Again, there are no easy options here. If they are outside the\ncurly braces, our precedent for scoping visibility suggests that any nested types from inside the `union` are not visible without being qualified by the type of the `union`,\nincluding any generic type arguments. However, in order to implement closed type hierarchies, we may need to have a list of the allowed implementations, similar to Java's\n`permits` clause, both for compiler performance and for reader comprehension. If we do need to have such a clause for that case, it might be a good idea to unify that with\n`union`s. On the other hand, `union`s could also reuse the `enum` syntax; again, if we expect to allow other member types to be defined in an `enum`, we will need to solve\nthe syntax question of both listing the cases and other members in the body of the enum, and `union` could potentially reuse that same syntax. Subjectively, we do have a\nslight leaning that by writing the members inside the body, rather than at the declaration level, it implies that they are _new_ things, rather than existing things. Given\nthat, we have a very slight lean towards outside the body of the `union`, but will explore more proposals on Monday and hopefully make further concrete progress on this very\ngnarly question.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-09-29.md",
    "content": "# C# Language Design Meeting for September 29th, 2025\n\n## Agenda\n\n- [Union Syntax Thunderdome Part 2](#union-syntax-thunderdome-part-2)\n- [Enums vs Unions](#enums-vs-unions)\n\n## Quote of the Day\n\n- \"Only this option here can have llamas in it, so that's its claim to superiority\"\n\n## Discussion\n\n### Union Syntax Thunderdome Part 2\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9662  \nSpecification: https://github.com/dotnet/csharplang/blob/38fd5f33d285cb190268f98cea16223cc0a5b8bc/proposals/unions.md  \nProposals:\n* https://github.com/dotnet/csharplang/blob/38fd5f33d285cb190268f98cea16223cc0a5b8bc/meetings/working-groups/discriminated-unions/allows.md\n* https://github.com/dotnet/csharplang/blob/38fd5f33d285cb190268f98cea16223cc0a5b8bc/meetings/working-groups/discriminated-unions/brace-syntax.md\n\nToday we are following up from [last time](./LDM-2025-09-24.md#union-syntax-thunderdome-part-1). We've decided that we want to have syntax outside of the body of\nthe union for the list of allowable cases, and today we need to decide what the initial form of that will be. This is by no means a truly final decision, and part\nof the reason for front-loading this decision is so that we can get previews into user hands for feedback. We gathered a number of possible syntaxes here, though\nwe did not discuss the merits of every single one.\n\n```cs\nunion Pet(Cat, Dog, Bird);\nunion Pet[Cat, Dog, Bird];\nunion Pet(Cat | Dog | Bird);\nunion Pet(Cat or Dog or Bird);\nunion Pet allows Cat, Dog, Bird;\nunion Pet includes Cat, Dog, Bird;\nunion Pet contains Cat, Dog, Bird;\nunion Pet has Cat, Dog, Bird;\nunion Pet with Cat, Dog, Bird;\nunion Pet of Cat, Dog, Bird;\nunion Pet switch Cat, Dog, Bird;\nunion Pet case Cat, Dog, Bird;\nunion Pet is Cat, Dog, Bird;\nunion Pet is Cat or Dog or Bird;\n```\n\nBroadly speaking, our ideas fall into two categories: a list surrounded by some kind of delimiter, such as `()` or `[]`, and a list started by some keyword, more\nsimilar to generic constraint clauses. When we considered these, we also wanted to make sure we thought about them in the broader context of what a `union` type\nwill be able to do: have generic type parameters, constraints, implement interfaces, have a body with declarations, etc. Below are some assorted notes from\ndiscussions of a few of these syntaxes:\n\n* `union Pet(Cat, Dog, Bird)` looks like primary constructor syntax at first glance, will it conflict with actual primary constructors if we add them?\n* `union Pet(Cat or Dog or Bird)` has a nice initial symmetry with patterns, but is that actually a good thing? If we matched on a pattern with\n  `val is (Dog or Cat) dogOrCat`, `dogOrCat` isn't going to magically become an anonymous union of `Dog or Cat`, it will still be a `Pet`.\n* `allows` means the opposite in C# today; it is \"everything normally _and also_ ref structs\". In this context, it would mean \"only the types listed\".\n* `case` does have some symmetry with the proposed `case` classes, but those are also currently being used to actually declare a new case type. Here, it would just\n  be the valid options of `Pet`, not declaring a new case.\n* `is` has the same issues as the parenthesized `or` case above.\n\nAfter discussion here, we have a leaning towards the first option: `union Pet(Cat, Dog, Bird)`. We do want to hear from users on this decision though, so we will make\nsure to revisit this with feedback in mind to determine if that's the final form, particularly if we also decide to support primary constructors in this area.\n\n#### Conclusion\n\nWe are moving forward with the `union Pet(Cat, Dog, Bird)` syntax form.\n\n### Enums vs Unions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9662  \nSpecifications:\n* https://github.com/dotnet/csharplang/pull/9711\n* https://github.com/dotnet/csharplang/pull/9713\n\nFor our second topic today, we discussed the evolution of ADT hierarchies in C#. There are two possible approaches on the table at the moment: expanding out the\n`union` feature to allow declaration of cases implicitly, or expanding out the existing `enum` features to allow declaring non-numeric cases. While these both sound\ndissimilar at first description, one thing that we realized after discussion is that these ideas are extremely compatible at the semantic level, with different skins\naround the same general concept of having a shorthand for declaring an ADT. This is validating for the kernel of the idea itself, as no one is pushing back that this\nis generally a thing that we want C# to have. However, it again puts us in a thunderdome of syntax, of `union` vs `enum`. One nicety about `enum` is that it already\nhas the implication that the cases are newly-declared constructs; for us to use `union` as the keyword, we'd have to either have an additional modifier on the\n`union` declaration itself, or we'd have to have `case` or some similar modifier on the type declarations. The `enum` approach would also give us precedent to\nexpand `enum`s in other directions; [`string` `enum`s](https://github.com/dotnet/csharplang/discussions/8804), for example, are a very highly-requested item that we\nhave thus far avoided due in part to this issue. There is also an opportunity to use this as the point when we refresh `enum`s, allowing the declaration of other\nmember types that cannot exist in traditional `enum`s today.\n\nThis doesn't come without consequences. Today, `enum`s mean numbers. It's going to be a large adjustment for users if this is no longer true, and is generally a very\nlarge shift in the way we think about these things. But we like the direction, and while we haven't settled on exact syntax (is it just `enum`? Is it `enum union`? Is\nit `enum class`? Are the cases declared with `case`? and other such debates), we feel confident in this direction. We expect this to come after the `union` feature,\nbuilding on that as the way that these `enum`s get translated into actual types, but we do expect it to happen.\n\n#### Conclusion\n\nWe will move forward with the enum-centric approach.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-10-01.md",
    "content": "# C# Language Design Meeting for October 1st, 2025\n\n## Agenda\n\n- [Closed enums](#closed-enums)\n- [Closed Hierarchies](#closed-hierarchies)\n\n## Quote of the Day\n\n- \"Have a good vacation Mads!\"\n\n## Discussion\n\n### Closed enums\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9011  \nSpecification: https://github.com/dotnet/csharplang/blob/7603e3bee2ea3edb53e6a3b27efbaf24949b609f/proposals/closed-enums.md\n\nFirst up today, we took another look at the current proposal for closed enums, to verify that after all of our related work on unions, we are still interested in this feature.\nUltimately, we are, but there are definitely some thorny questions to answer around just how strict we can or should make this. One example is in the BCL: do the various\n`Enum` members need to behave differently in the face of a closed enum? What about exhaustiveness in switch statements; presumably we want it to handle not needing a `default`\ncase for returning, but how will that interact with `switch` statements that are intentionally not exhaustive, or in `void`-returning methods where there isn't a \"you\nforgot to return\" error?\n\nWe do think that this is still an area we want to pursue, so we will keep working on these questions.\n\n#### Conclusion\n\nWe will be pursuing closed enums.\n\n### Closed Hierarchies\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9499  \nSpecification: https://github.com/dotnet/csharplang/blob/7603e3bee2ea3edb53e6a3b27efbaf24949b609f/proposals/closed-hierarchies.md\n\nNext up, we did the same pass for closed hierarchies, making sure that we are still interested in this now that we have a better understanding of our goals for unions. Again,\nwe are still interested in the feature, and we want to pursue implementation. One question that we will need to answer is around performance; one major argument for having an\nexplicit list of allowed subtypes is for compiler performance, to ensure that we don't have to scan the entire compilation for potential subtypes. This is something that we\nneed to play with in real code to see what the performance is in reality, to ensure that we're not basing a language decision on pessimistic assumptions. There is still a\nchance that we'll decide that we need the list for programmer convenience, but this is something that we think we need real feedback and usage on. There are various\noptions for how such a list could be constructed: we could use the same syntax as we have for `union`s, or we could force all declarations to live in the same file or have\npartial parts in the same file. But we will start with no listing requirement and see what that looks like.\n\n#### Conclusion\n\nWe will be moving forward with closed hierarchies.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-10-13.md",
    "content": "# C# Language Design Meeting for October 13th, 2025\n\n## Agenda\n\n- [Collection expression safe-context bug fix](#collection-expression-safe-context-bug-fix)\n- [Immediately-enumerated collection expressions](#immediately-enumerated-collection-expressions)\n\n## Quote of the Day\n\n- '\"Bonafide Memory Safety Bug\" is a pretty good band name.'\n\n## Discussion\n\n### Collection expression safe-context bug fix\n\nIssue: https://github.com/dotnet/csharplang/issues/9750\n\nWe started today by examining a proposed bug fix for an issue around safe contexts and collection expressions. The current behavior is\na bug, but one that will cause new errors to be reported when it's fixed to reflect the specification as written. We do think that it's\na worthy change though, similar in nature to the breaking change around variable scoping in loops in C# 5. We also briefly considered\nwhether the compiler can be smarter and take the safe-context of the destination into account, but there are immediate and easy examples\nof where the assignment flows through multiple levels, making it hard for both the compiler and human readers to track. Given this, we\nwill update the compiler to follow the specification as written, and will revisit if this break causes too many follow-on issues.\n\n#### Conclusion\n\nBreak is accepted.\n\n### Immediately-enumerated collection expressions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9754  \nSpecification: https://github.com/dotnet/csharplang/blob/cb0652db1e5b7cbc1b3faae61b0df9ee175b9b90/proposals/immediately-enumerated-collection-expressions.md#use-of-special-language-level-collection-type-for-immediately-enumerated-collections\n\nNext up today, we looked at a proposal for allowing immediately enumerated collection expressions in the language. One thing that came up\nimmediately was that this is really 2 proposals in one; while the goal was originally just for non-observable collections to be enumerated\n(in spreads or `foreach`), the rules end up accomplishing more as they push type inference through more locations that aren't obvious\nfrom the title. We're concerned that there are effects beyond the examples in the specification that need to be thought through for this\ninference; for example, how should array creation expressions and lambda types be affected by the type inference rules? After some\nreflection, we're comfortable breaking this into two separate parts; the first is as in the title of the proposal, immediately-enumerated\ncollection expressions. This change would allow `foreach` over a collection expression, but by itself wouldn't permit spreading a ternary\nof collection expressions. The rules for type inference can then be fleshed out further and the corners explored, and brought back as a\nseparate proposal that enables its own abilities (such as `M(b ? [1, 2] : [3, 4])`).\n\nWe also looked at the \"type\" that we want to use for these immediately-enumerated scenarios. We feel that we want to start restrictive,\nand later relax restrictions, in order to protect future work in natural types. For example, if we were to say that the type of an\nimmediately-enumerated expression is an array, then that would permit pointer types. If we were to then choose `List<T>` as the natural\ntype of a collection expression, that would then create inconsistency on what you can `foreach` vs what you can assign to a `var` local.\nAnother interesting aspect is `ref foreach`. We think there's some thorny questions on what an interpretation of this code would be:\n\n```cs\nint x = 1;\n// Does this create a copy of `x`, and `y` is a ref to that copy, or is `y` a ref to `x`?\nforeach (ref int y in [x])\n{\n    y = 2;\n}\nConsole.Write(x);\n```\n\nEither interpretation is potentially confusing, so we think it's best to simply avoid the question and disallow `ref foreach` in this\narea. After some debate, we landed on `IEnumerable<T>` as the type to use in `foreach`. It should preserve our ability to make changes in\nthe future without ending up in an inconsistent space, while also still allowing the implementation to do whatever efficient form it\nchooses.\n\nFinally, we looked at whether we could apply similar optimizations for `foreach (var x in new[] { 1, 2, 3 })`. We ultimately don't think\nthis is the purview of the language. There are a few types like array and `List<T>` that we could special case, but we can't do this in\ngeneral. The runtime has been working on escape analysis to avoid heap allocations for this type of scenario, and will continue to do so.\nWe think that's the appropriate place for this work to go.\n\n#### Conclusion\n\nProposal is split up into immediately-enumerated collection expressions and type inference improvements for collection expressions. The\nformer is approved. The type of the immediately-enumerated expression will be `IEnumerable<T>`. We will not pursue optimizing other\ntypes of immediately-enumerated collection creation.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-10-29.md",
    "content": "# C# Language Design Meeting for October 29th, 2025\n\n## Agenda\n\n- [Unsafe evolution](#unsafe-evolution)\n\n## Quote of the Day\n\nI did not record any particularly amusing quotes today, sorry\n\n## Discussion\n\n### Unsafe evolution\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9704  \nSpecification: https://github.com/333fred/csharplang/blob/1b22088adb4e42323a3906c4e26105d001c79761/proposals/unsafe-evolution.md  \nRelated: https://github.com/dotnet/designs/blob/2b9e1b311d16ea142b4047d6eddeef15979ba6de/proposed/caller-unsafe.md\n\nToday, we started reviewing the initial specification for evolving `unsafe` at the C# level. We spent most of the session simply\ngetting clarity on what is being proposed, the impacts to code, and the limits of what can be detected by the compiler. Of\nparticular interest was the boundary between safe and unsafe code: can we strengthen guarantees about what must be in an `unsafe`\nblock? We considered this hypothetical bug:\n\n```cs\nint* ptr = stackalloc int[] { 1, 2, };\nint addr = 0;\nAddOne(ref addr);\nunsafe\n{\n    Console.WriteLine(ptr[addr]);\n}\n\nvoid AddOne(ref int i)\n{\n    i++;\n    i++; // Oops, someone accidentally duplicated a line\n}\n```\n\nIf that bug were checked in, the memory unsafety occurs in the `unsafe` section, but the true bug that _caused_ the unsafety\noccurred in C# that has no reason to be marked as `unsafe`, and no part of the calculation that was in error is required to be\ninside the `unsafe` block. Could there perhaps be an expanding rule, such that any inputs to an `unsafe` operation must also be\nin an `unsafe` block? We ultimately don't think this expansion is worth it; in general, we do not expect that it will be possible\nto detect every single input that is ultimately unsafe. A counterexample is something like:\n\n```cs\nvoid ReadFromArrayWithOffset(int[] array, int addr)\n{\n    if (addr + 1 >= array.Length)\n    {\n        throw new ArgumentOutOfRangeException();\n    }\n    AddOne(ref addr);\n    fixed (int* ptr = array)\n    {\n        unsafe\n        {\n            Console.WriteLine(ptr[addr]);\n        }\n    }\n}\n```\n\nHow would the compiler be able to detect that, in fact, `addr` (up until the `AddOne` call) was actually perfectly safe and valid?\nIt is an input to the unsafe operation, so virality would likely demand that `ReadFromArrayWithOffset` be declared as `unsafe`.\nAliasing rules further complicate this. The goal of the `unsafe` feature is to better call out what parts of the code need more\nmanual scrutiny, but they ultimately don't _replace_ that scrutiny. We think it is the job of the reviewers looking at this code\nto understand what is really involved in the calculations and enforce `unsafe` boundaries appropriately here.\n\nWe made no conclusions today, but have a better understanding of where the boundaries of the feature are and what the principles\nwe will be using to make further decisions are. We will come back next week to continue work here.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-11-05.md",
    "content": "# C# Language Design Meeting for November 5th, 2025\n\n## Agenda\n\n- [Unsafe evolution](#unsafe-evolution)\n\n## Quote of the Day\n\n- \"Do COM interfaces need to be unsafe?\" \"[with a look of visible pain] Well that's a \\*\\*\\*\\* question\"\n\n## Discussion\n\n### Unsafe evolution\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9704  \nSpecification: https://github.com/dotnet/csharplang/blob/ff88c654e26def239d2f7bcab52fe4e4d016dfba/proposals/unsafe-evolution.md  \nRelated: https://github.com/dotnet/designs/blob/2b9e1b311d16ea142b4047d6eddeef15979ba6de/proposed/caller-unsafe.md\n\nPicking up from [last time](LDM-2025-10-29.md#unsafe-evolution), we continue to discuss how we want to evolve `unsafe` in C#. From the last time, the proposal was\nrevised to include a few more open questions, as well as to reduce the level of breaking change it was proposing. Today, we were able to discuss 2 main topics:\n\n1. Do we accept the core kernel of the proposal, moving `unsafe` from meaning \"there exists a pointer type\" to \"there exists memory unsafety, as defined by the\n   [caller unsafe](https://github.com/dotnet/designs/blob/2b9e1b311d16ea142b4047d6eddeef15979ba6de/proposed/caller-unsafe.md) document being proposed for the platform?\n2. Will the new rules be warnings, errors, or some form of suppressible error between?\n\nFor the first question, we agreed that yes, this moving `unsafe` into this newer world is acceptable. That left the majority of the meeting for discussion on warning vs\nerror, which also bridges into areas of \"how would the state be controllable?\". The repeated analogy here is to the nullable reference types feature, and we discussed\nnearly every way in which nullable allows configuration. However, while the analogy works quite well, we think there are two major differences from the nullable feature:\n\n* We expect the amount of code in the average project that will need to change to adopt new memory safety rules is quite low. The majority of projects shouldn't even\n  be impacted. This is extremely different to nullable, where every single line of executable code, and most lines of definitions, were impacted. We expect that this\n  should reduce the number of configuration options needed.\n* Ignoring nullable warnings can cause bugs, and potentially even vulnerabilities in the form of DOS attacks, but memory safety issues are much more severe. Reading\n  an unintentional `null` can crash an app, but reading uninitialized or unmanaged memory incorrectly can expose the app's data or users to attack. We therefore feel\n  much more strongly about getting memory safety properly annotated across the ecosystem.\n\nGiven both the expected smaller blast radius and the higher importance of addressing issues, we believe that we want to start with stricter versions of the rules. We\nwill therefore start with memory safety diagnostics being errors, with no dedicated suppression mechanism. Wrapping new errors in `unsafe` with todo comments attached\nwill be the main form of \"suppress for now and come back later\" available to authors.\n\nThis does pose some adoption problems for users who depend on source generators, as there will be no special affordance given to source generators. This can mean that\nif a generator is not updated, and is emitting code that has new memory safety errors in it, the consumer of the generated code will be blocked from enabling the new\nrules. While this is harsh, we expect that the majority of the generators that use `unsafe` code are either first-party, or are from highly-engaged community members\nwho will be quick to jump on the new rules. If these rules prove too onerous and block widespread adoption of the feature, we can revisit, but we want to start at the\nmore secure end of the spectrum. We also don't expect that source generators need to be concerned by \"unexpected\" `unsafe`. Either the generator was written with the\nintent of using `unsafe` code in mind, or it is an error on the consumption side to provide the generator an `unsafe` member to interact with if it wasn't expecting it.\n\nNext up, we will be discussing how members are marked `unsafe`, and what `unsafe` on a type means.\n\n#### Conclusion\n\nThe core principle of the `unsafe` evolution feature is accepted. `unsafe` diagnostics will be errors by default, and no affordance for source generated code will be\ngiven.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-11-12.md",
    "content": "# C# Language Design Meeting for November 12th, 2025\n\n## Agenda\n\n- [Unsafe evolution](#unsafe-evolution)\n\n## Quote of the Day\n\n- \"Did you just say Romulan?\" \"No, I said cromulent.\"\n\n## Discussion\n\n### Unsafe evolution\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9704  \nSpecification: https://github.com/dotnet/csharplang/blob/4c6bee6ceaa48dc64a42f25d6a50155e1def2930/proposals/unsafe-evolution.md  \nRelated: https://github.com/dotnet/designs/blob/2b9e1b311d16ea142b4047d6eddeef15979ba6de/proposed/caller-unsafe.md\n\nToday, we [continued](./LDM-2025-11-05.md#unsafe-evolution) talking about the future of `unsafe` in C#. Our main focus today was on how members\nare declared as requiring an `unsafe` context: do we repurpose the `unsafe` keyword on members to mean this? Or do we do something new, such as\na new keyword or having an attribute to indicate this? After some discussion, we do believe that `unsafe` conveys what we want here. Much like\nnullable reference types, the future we want to get to isn't with the `unsafe` keyword as this odd vestigial thing, we want the feature to feel\nunified. Given that we feel pretty confident that we want to repurpose `unsafe` on members, even if that means increasing the scope of the\nbreaking change in the language.\n\nNext, we considered the broader application of `unsafe` on types. The new rules are very explicit that types cannot be considered `unsafe` by\nnature: it is only specific types of memory accesses that are `unsafe`. We therefore have a few options for what to do:\n\n1. Automatically mark all members inside an `unsafe` type as `unsafe`. This is the current proposal.\n2. Keep the historical meaning of `unsafe`: the body of the type is in an `unsafe` context, but members will still need a separate `unsafe`\n   modifier to be considered `unsafe` to call.\n3. Disallow `unsafe` on types.\n4. Allow `unsafe` as a modifier on types, but remove all meaning. Produce a warning that it is vestigial.\n\nAll of these are fairly large changes in one way or another; a simple search across GitHub indicates at least 150K results for `unsafe class`\nor `unsafe struct`, excluding forked projects. A decent number of spot checks of these have shown that they're not actually `unsafe`; the\ndeveloper simply marked the type as `unsafe` even though no pointers or `unsafe` memory accesses occurred in the type. There are plenty of real\n`unsafe` spots, though, so unless we were to adopt option 2, it would be a large breaking change.\n\nLooking more at options 1 and 2 though, we're not actually convinced that these truly help bring down the magnitude of the breaking change. In\neither case, developers really do still need to adjust their members. Option 1 will bleed `unsafe` out into the rest of the code, and both\noptions 1 and 2 make the scope of the `unsafe` blocks far too broad. In both cases, we don't actually _want_ users to put `unsafe` on their types.\nIt implies that a type can be `unsafe`, which is not how the feature works. We are then left with options 3 and 4, where 4 is just 3 but without\na hard error. There's definitely appetite for fully prohibiting `unsafe` on types altogether, but we're hesitant to fully commit at this time.\nWe'll proceed with option 4 for now, and come back to the question of 3 vs 4 in a few weeks after we've had some time to think more about it.\n\nAnother area we considered is whether or not `unsafe` as a modifier on a member should make the entire body of that member an `unsafe` context.\nRust did this originally, and has since moved to requiring an explicit `unsafe` block, even for a member marked as `unsafe`. This helps call out\nthe specific unsafety, rather than saying \"this entire 100 line method is unsafe, good luck finding the actual bit of concern\". We don't have\nconclusions on this today, but will add it to our list of questions to resolve.\n\n#### Conclusion\n\nWe will use `unsafe` on members as the way to denote that calling a member must be performed in an `unsafe` context. `unsafe` on a type will have\nno meaning, and we will revisit the question of whether to outright disallow it, or just add a warning.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-12-10.md",
    "content": "# C# Language Design Meeting for December 10th, 2025\n\n## Agenda\n\n- [Collection expression arguments](#collection-expression-arguments)\n\n## Quote of the Day\n\n- \"It's almost like it's been a few weeks and we're a bit rusty.\" \"We're not Rusty, we're C#y\"\n\n## Discussion\n\n### Collection expression arguments\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8887  \nSpec: https://github.com/dotnet/csharplang/blob/34a80fa9cfef3bfe3bcb66c412928c4d6bd735b4/proposals/collection-expression-arguments.md  \nDiff: https://github.com/dotnet/csharplang/commit/2afe544f5facf319b3d76a044bf58d07349ce5b9\n\nToday, we wanted to validate an assumption made during implementation, that the specific constructors we expose\nfor `IList<T>` and `ICollection<T>` are constructors from `List<T>`. After some discussion, we think that this is ok to do, and will\nextend to `IDictionary<TKey, TValue>` as well for dictionary expressions. The main thing we want to update is that the spec itself won't\ncare about the name of the parameter. If some version of the BCL decides to name `capacity` differently, then it is free to do so; users\nof that BCL would have to specify that different name instead of `capacity`.\n\n#### Conclusion\n\nThe candidate signatures for `IList<T>` and `ICollection<T>` bind to the constructors with the corresponding signatures in `List<T>`\nwhen constructing the value. The spec will not say the names of these parameters, it will only specify the parameter type.\n"
  },
  {
    "path": "meetings/2025/LDM-2025-12-17.md",
    "content": "# C# Language Design Meeting for December 17th, 2025\n\n## Agenda\n\n- [Collection expression arguments parsing question](#collection-expression-arguments-parsing-question)\n- [Null-conditionals evaluating to a pointer type](#null-conditionals-evaluating-to-a-pointer-type)\n- [Triage](#triage)\n    - [Top-Level Members](#top-level-members)\n    - [Using local declaration improvements](#using-local-declaration-improvements)\n\n## Quote of the Day\n\n- \"We can't do advent of triage? Just one more?\"\n\n## Discussion\n\n### Collection expression arguments parsing question\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8887  \nSpec: https://github.com/dotnet/csharplang/blob/01e436bf45790b7118c116100c27a8172148c58d/proposals/collection-expression-arguments.md#finalizing-an-open-concern-from-httpsgithubcomdotnetcsharplangblobmainmeetings2025ldm-2025-03-17mdconclusion  \n\nWe started today by revisiting an earlier temporary decision; when we were considering whether `with` would be a breaking change at the\ntop level for collection expressions, we initially decided that we would take the breaking change for preview, but since we hadn't yet\nfinalized our syntax and were planning on previewing it for .NET 10, we didn't want to potentially break users for syntax we weren't certain\nof. Since then, we've had our debates, settled on `with` as the syntax, and now we want to revisit the breaking change downlevel. Our\ndefault approach to parsing changes is to always parse with new language features, and issue errors when users don't have the appropriate\nlanguage version enabled. Searching through GitHub we are unable to find examples of code that will actually break in this, so we are\ncomfortable following our usual approach; the .NET 11 SDK/C# 15 compiler will always parse `with` as collection expression arguments,\nregardless of the language version of the project.\n\nWe also wanted to talk about the formal definition of the feature, and in particular, how the grammar rules actually will work. Do we want\nto have a rule where the `with` has to be the top-level expression in the collection expression element, or do we want a rule where, if we\nencounter `with(` to start a collection expression element, that element is a `with` element, regardless of following content? Concretely,\nthe question is how do we want something like this to parse: `[with() + with()]`. With the top-level rule, this would just be a binary \noperator `+` with method calls to methods named `with` in either arm. With the \"first token\" rule, it would be a `with` element, followed by a\nbinary operator `+` whose left operand is missing, and the right operand is a method invocation named `with`. After some debate, we decided\nthat it is simpler to go with the \"first token\" rule, and matches our precedent with `spread` elements, where a `..` always starts a spread,\nnever a range. This makes the parsing simple, and parentheses can easily disambiguate for scenarios where the user really wants to call a method,\njust like it works for range.\n\n#### Conclusion\n\nWe will not take language version into account when parsing, and will always parse `with` elements as `with` elements. If a collection expression\nelement starts with `with(`, that means it is a `with` element, following the `..` spread precedent.\n\n### Null-conditionals evaluating to a pointer type\n\nIssue: https://github.com/dotnet/roslyn/issues/7502  \nSpec: https://github.com/dotnet/csharpstandard/blob/41694caebb0fb759b75ef66b9d11d37006aab000/standard/expressions.md#12813-null-conditional-element-access\n\nNext up, we discussed a potential compiler bug/specification bug. This has been open for a long time, but was recently resurfaced and we wanted to\ninvestigate to clarify our definitions. The question hinges on what the definition of what a non-nullable value type is. If a pointer is a non-nullable\nvalue type, then the rules as written state that the type would have to be `Nullable<int*>`, which is indeed illegal. But if pointers are not\nnon-nullable value types, then the cases would fall through to the last bullet of the spec and it should just work, as the specified transformation\nwould be legal for a pointer. Certainly on the surface, pointer types are nullable: `int* i = null;` is legal, as is comparing them with `null`. Given\nthat, and the definitions in [§8.2.1](https://github.com/dotnet/csharpstandard/blob/41694caebb0fb759b75ef66b9d11d37006aab000/standard/types.md#821-general),\nwe are comfortable treating this as a compiler bug, and will fix it to work. We will also leave the decision on clarifying the specification further\nto the ECMA 334 committee.\n\n#### Conclusion\n\nNull-conditional expressions that produce a pointer type not being allowed is a compiler bug and will be fixed as such.\n\n### Triage\n\nFinally today, we did some triage on newly-championed issues over the past few months.\n\n#### Top-Level Members\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9803  \nSpec: https://github.com/dotnet/csharplang/blob/e878e7860d9b6420112fd7b99b910a79c7103132/proposals/top-level-members.md\n\nThere are some strong feelings on this one in the LDM; nothing that we think would hold us from doing a deep design dive on it, but by no means\nis there agreement on the feature at this point. We'll put it into the working set to have that debate.\n\n#### Using local declaration improvements\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8606  \nSpec: https://github.com/dotnet/csharplang/blob/afad49721a7b9923efbbc36ae6c455d85b994543/proposals/using-with-a-discard.md\n\nFinally, we looked at a proposal for creating `using` local declarations without actually having to declare a local, marrying the implicit scope\nbenefits of `using` locals with the lack of variable pollution available from `using` statements. We are interested, but want to rename the proposal\nfrom the current state to better reflect that goal, rather than a specific implementation of achieving that goal.\n"
  },
  {
    "path": "meetings/2025/README.md",
    "content": "## C# Language Design Notes for 2025\n\n### Wed December 17, 2025\n\n[C# Language Design Meeting for December 17th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-12-17.md)\n\n- Collection expression arguments parsing question\n- Null-conditionals evaluating to a pointer type\n- Triage\n    - Top-Level Members\n    - Using local declaration improvements\n\n### Wed Dec 10, 2025\n\n[C# Language Design Meeting for December 10th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-12-10.md)\n\n- Collection expression arguments\n\n### Wed Nov 12, 2025\n\n[C# Language Design Meeting for November 12th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-11-12.md)\n\n- Unsafe evolution\n\n### Wed Nov 5, 2025\n\n[C# Language Design Meeting for November 5th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-11-05.md)\n\n- Unsafe evolution\n\n### Wed Oct 29, 2025\n\n[C# Language Design Meeting for October 29th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-10-29.md)\n\n- Unsafe evolution\n\n### Mon Oct 13, 2025\n\n[C# Language Design Meeting for October 13th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-10-13.md)\n\n- Collection expression safe-context bug fix\n- Immediately-enumerated collection expressions\n\n### Wed Oct 1, 2025\n\n[C# Language Design Meeting for October 1st, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-10-01.md)\n\n- Closed enums\n- Closed Hierarchies\n\n### Mon Sep 29, 2025\n\n[C# Language Design Meeting for September 29th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-09-29.md)\n\n- Union Syntax Thunderdome Part 2\n- Enums vs Unions\n\n### Wed Sep 24, 2025\n\n[C# Language Design Meeting for September 24th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-09-24.md)\n\n- Union Syntax Thunderdome Part 1\n\n### Wed Sep 17, 2025\n\n[C# Language Design Meeting for September 17th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-09-17.md)\n\n- Unsafe evolution\n\n### Wed Sep 10, 2025\n\n[C# Language Design Meeting for September 10th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-09-10.md)\n\n- Unions overview\n\n### Wed Aug 27, 2025\n\n[C# Language Design Meeting for August 27th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-08-27.md)\n\n- Type inference in patterns\n- Type value conversion\n- Union syntax\n\n### Wed Aug 20, 2025\n\n[C# Language Design Meeting for August 20th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-08-20.md)\n\n- Union interfaces\n- Target-type inference improvements\n\n### Mon Aug 18, 2025\n\n[C# Language Design Meeting for August 18th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-08-18.md)\n\n- C# 15 Kickoff and Themes\n    - Unions\n    - Extensions\n    - Dictionary expressions\n    - Type inference\n    - Continuing the null monad\n    - Object initialization\n    - Top-level methods\n    - Caller type name\n    - Switch statement/expression improvements\n\n### Wed Aug 13, 2025\n\n[C# Language Design Meeting for August 13th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-08-13.md)\n\n- Unions\n\n### Wed Jul 30, 2025\n\n[C# Language Design Meeting for July 30th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-07-30.md)\n\n- '/main' and top-level statements\n- Union proposals overview\n- Add type parameter restriction to closed hierarchies\n- Standard unions\n- Union interfaces\n- Custom unions\n- Non-boxing access pattern\n\n### Mon Jun 30, 2025\n\n[C# Language Design Meeting for June 30th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-06-30.md)\n\n- Type parameter inference from constraints\n- Target-typed static member lookup\n\n### Wed Jun 25, 2025\n\n[C# Language Design Meeting for June 25th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-06-25.md)\n\n- Unions\n    - Stand-alone issues\n    - Mutually exclusive issues\n\n### Mon Jun 23, 2025\n\n[C# Language Design Meeting for June 23rd, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-06-23.md)\n\n- Extensions\n    - Use of extension operators in LINQ expression trees\n    - `ref` encoding and conflict checks\n    - Extern support\n    - Lookup\n\n### Wed Jun 18, 2025\n\n[C# Language Design Meeting for June 18th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-06-18.md)\n\n- Iterators in lambdas\n- Extensions\n\n### Wed Jun 11, 2025\n\n[C# Language Design Meeting for June 11th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-06-11.md)\n\n- Extensions\n    - Dynamic resolution of operator `true`/`false`\n    - Extension operators in LINQ expression trees\n    - Built-in operator protection rules\n    - Extension module initializers\n    - Extension methods as entry points\n    - Langversion behavior for new extensions\n    - `nameof`\n\n### Mon Jun 9, 2025\n\n[C# Language Design Meeting for June 9th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-06-09.md)\n\n- Extensions - crefs\n\n### Wed Jun 4, 2025\n\n[C# Language Design Meeting for June 4th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-06-04.md)\n\n- Extensions\n    - Should extension operators on nullable of extended type be disallowed\n    - Applicability of bitwise operators during evaluation of user-defined conditional logical operators\n    - Extension user-defined conditional logical operators\n    - Extension compound assignment operators\n    - Delegate returning properties\n    - Extension declaration validation\n    - Cref references\n\n### Wed May 28, 2025\n\n[C# Language Design Meeting for May 28th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-05-28.md)\n\n- Nominal type unions\n\n### Mon May 12, 2025\n\n[C# Language Design Meeting for May 12th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-05-12.md)\n\n- Collection expression arguments\n    - Empty argument lists\n    - Constructor binding behavior\n    - Syntax\n- Dictionary expressions\n\n### Wed May 7, 2025\n\n[C# Language Design Meeting for May 7th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-05-07.md)\n\n- Collection Expression Arguments\n    - Interface target type\n    - Constructor binding behavior\n    - Syntax\n\n### Mon May 5, 2025\n\n[C# Language Design Meeting for May 5th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-05-05.md)\n\n- Extensions\n    - XML Docs\n    - Participation in pattern-based constructs\n    - Skeleton type metadata\n    - Single-phase consequences\n\n### Wed, Apr 23, 2025\n\n[C# Language Design Meeting for April 23rd, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-04-23.md)\n\n- Extensions\n    - Extension operators\n    - Overload resolution priority\n- Dictionary Expressions\n\n### Wed Apr 16, 2025\n\n[C# Language Design Meeting for April 16th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-04-16.md)\n\n- Extensions\n\n### Mon Apr 14, 2025\n\n[C# Language Design Meeting for April 14th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-04-14.md)\n\n- Dictionary expressions\n- Collection expression arguments\n\n### Wed Apr 9, 2025\n\n[C# Language Design Meeting for April 9th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-04-09.md)\n\n- Dictionary expressions\n- Collection expression arguments\n\n### Mon Apr 7, 2025 \n\n[C# Language Design Meeting for April 7th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-04-07.md)\n\n- Breaking change discussion: making partial members in interfaces virtual and/or public\n- Interpolated string handler argument values\n\n### April 2, 2025\n\n[C# Language Design Meeting for April 2nd, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-04-02.md)\n\n- User Defined Compound Assignment Operators\n    - Should readonly modifier be allowed in structures?\n    - Should shadowing be allowed\n    - Should we have any consistency enforcement between declared += and + operators?\n- Readonly setters\n    - Expansions\n\n### Mon Mar 24, 2025\n\n[C# Language Design Meeting for March 24th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-03-24.md)\n\n- Dictionary Expressions\n    - Support dictionary types as `params` type\n    - Type inference for `KeyValuePair<K, V>` collections\n    - Overload resolution for `KeyValuePair<K, V>` collections\n- Extensions\n    - Signature conflict rules\n    - `extension` vs `extensions`\n\n### Wed Mar 19, 2025\n\n[C# Language Design Meeting for March 19th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-03-19.md)\n\n- Readonly setters on non-variables\n\n### Mon Mar 17, 2025\n\n[C# Language Design Meeting for March 17th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-03-17.md)\n\n- Collection expression arguments\n    - `with` breaking change\n    - Collection expression arguments and conversions\n- Dictionary expressions\n- Extensions\n    - Accessibility\n    - Static factory scenarios\n\n### Mon Mar 12, 2025\n\n[C# Language Design Meeting for March 12th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-03-12.md)\n\n- Optional and named parameters in expression trees\n- Collection builder method parameter order\n- Ignored directives\n\n### Mon Mar 10, 2025\n\n[C# Language Design Meeting for March 10th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-03-10.md)\n\n- Extensions\n    - Property method calling\n    - Scoping and Shadowing\n    - Type parameter inferrability\n    - Accessibility\n\n### Wed Mar 5, 2025\n\n[C# Language Design Meeting for March 5th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-03-05.md)\n\n- Dictionary expressions\n- Target-typed static member lookup\n\n### Mon Mar 3, 2025\n\n[C# Language Design Meeting for March 3rd, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-03-03.md)\n\n- Extensions\n\n### Wed Feb 26, 2025\n\n[C# Language Design Meeting for February 26th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-02-26.md)\n\n- Extensions\n\n### Mon Feb 24, 2025\n\n[C# Language Design Meeting for February 24th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-02-24.md)\n\n- Extensions\n- Interpolated string handler method names\n\n### Wed Feb 19, 2025\n\n[C# Language Design Meeting for February 19th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-02-19.md)\n\n- Extensions\n\n### Wed Feb 12, 2025\n\n[C# Language Design Meeting for February 12th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-02-12.md)\n\n- User-defined instance-based operators\n- Left-right join in query expressions\n\n### Wed Jan 22, 2025\n\n[C# Language Design Meeting for January 22nd, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-01-22.md)\n\n- Partial events and constructors\n- Collection expression arguments\n- Extensions disambiguation syntax\n\n### Wed Jan 15, 2025\n\n[C# Language Design Meeting for January 15th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-01-15.md)\n\n- `fieldof`\n- Simple lambda parameters\n- Interpolated string handler method names\n\n### Mon Jan 13th, 2025\n\n[C# Language Design Meeting for January 13th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-01-13.md)\n\n- Discriminated Unions\n\n### Mon Jan 6, 2025\n\n[C# Language Design Meeting for January 6th, 2025](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-01-06.md)\n\n- Ignoring `ref struct`s in `Expression`s\n- Extensions\n"
  },
  {
    "path": "meetings/2026/LDM-2026-01-12.md",
    "content": "# C# Language Design Meeting for January 12th, 2026\n\n## Agenda\n\n- [Triage](#triage)\n    - [Relaxed ordering for `partial` and `ref` modifiers](#relaxed-ordering-for-partial-and-ref-modifiers)\n    - [Deconstruction in lambda parameters](#deconstruction-in-lambda-parameters)\n    - [Unsigned sizeof](#unsigned-sizeof)\n    - [Labeled `break` and `continue` Statements](#labeled-break-and-continue-statements)\n    - [Extra accessor in property override](#extra-accessor-in-property-override)\n    - [Immediately Enumerated Collection Expressions](#immediately-enumerated-collection-expressions)\n    - [Allow arrays as CollectionBuilder Create parameter type](#allow-arrays-as-collectionbuilder-create-parameter-type)\n\n## Quote(s) of the Day\n\n- \"Wouldn't an imaginary array return a length of `i`?\"\n- \"I think I just saw a thread abort in real time as you were talking.\"\n\n## Discussion\n\n### Triage\n\n#### Relaxed ordering for `partial` and `ref` modifiers\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9804  \nSpec: https://github.com/dotnet/csharplang/blob/c4ec6fb60c2e174b1abb6c019f22bb15b9b13f6c/proposals/relaxed-partial-ref-ordering.md\n\nWe are in favor of this. Historical reasons for this restriction were both implementation driven and a more conservative\napproach to breaking changes. We want to move forward, into the working set.\n\n#### Deconstruction in lambda parameters\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9848  \nSpec: https://github.com/dotnet/csharplang/blob/c4ec6fb60c2e174b1abb6c019f22bb15b9b13f6c/proposals/deconstruction-in-lambda-parameters.md\n\nMore skepticism on this one. There are some concerns about the readability of the syntax, particularly in single-parameter cases, and\nan overall question as to whether this piece of syntactical sugar is worth it, particularly since several members think that it would\nnever be able to apply to non-lambdas (given that parameter names matter more there). We'll put it in the working set to take a\ncloser look though, and make a more comprehensive determination.\n\n#### Unsigned sizeof\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9633  \nSpec: https://github.com/dotnet/csharplang/blob/c4ec6fb60c2e174b1abb6c019f22bb15b9b13f6c/proposals/unsigned-sizeof.md\n\nWe think that this proposal is probably too much work for the benefits that it would bring; adding any new conversion comes with\nconsidering breaking changes, and we're not sure it's worth that level of effort for just `sizeof`. However, we do think that there\ncould be an interesting expansion that would potentially pay for itself in a broader \"non-negative integer\" feature, that could apply\nnot just to `sizeof`, but also collection count/length. We already special case these a bit in pattern matching, where the pattern\n`arr switch { [_, ..] or { Length: 0 } => \"\" }` is considered exhaustive, even though `Length: < 0` is not matched on. If we can square\nthat with `sizeof`, and expand it to the broader language, then we may be more amenable to that. For now, though, this will go into\nthe backlog.\n\n#### Labeled `break` and `continue` Statements\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9875  \nSpec: https://github.com/dotnet/csharplang/blob/c4ec6fb60c2e174b1abb6c019f22bb15b9b13f6c/proposals/labeled-break-continue.md\n\nThe LDM is unsure overall here, but wants to delve deeper in a full session to hash it out. We'll put it in the working set for now.\n\n#### Extra accessor in property override\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9921  \nSpec: https://github.com/dotnet/csharplang/pull/9920\n\nWe like it. Into the working set.\n\n#### Immediately Enumerated Collection Expressions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9754  \nSpec: https://github.com/dotnet/csharplang/blob/c4ec6fb60c2e174b1abb6c019f22bb15b9b13f6c/proposals/immediately-enumerated-collection-expressions.md\n\nThis was delayed so we could assess feedback from collection expressions on where natural types are desired. The areas that we've\nheard are addressed by this proposal, so we're ready to move forward and we'll put it into the working set. This proposal also\nsubsumes https://github.com/dotnet/csharplang/issues/9739, so that will be closed as a duplicate.\n\n#### Allow arrays as CollectionBuilder Create parameter type\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9923  \nSpec: https://github.com/dotnet/csharplang/pull/9922\n\nOne big question is how this behaves in the face of spread cases. The goal of the proposal is to avoid extra copies, but that copy\nseems like it may be inevitable in such cases, since the compiler can't know how big of an array to allocate the likelihood that it\nwill guess correctly is low. After some discussion, we've settled on a different goal: make `ReadOnlyMemory<T>` work with collection\nexpressions. We'll investigate approaches for doing so, and if other types can come along for the ride, all the better, but we won't\nhave it as the overriding goal unless we can see good evidence that the type is widely used and supported. This issue will go on the\nbacklog until that happens.\n"
  },
  {
    "path": "meetings/2026/LDM-2026-01-21.md",
    "content": "# C# Language Design Meeting for January 21st, 2026\n\n## Agenda\n\n- [Unsafe evolution](#unsafe-evolution)\n\n## Quote of the Day\n\n- \"To be more meaningfully unsafe\"\n\n## Discussion\n\n### Unsafe evolution\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9704  \nSpec: https://github.com/dotnet/csharplang/blob/37a912407b377f8a3fd5f7396549977e1207e759/proposals/unsafe-evolution.md  \nProposal: https://github.com/dotnet/csharplang/blob/37a912407b377f8a3fd5f7396549977e1207e759/meetings/working-groups/unsafe-evolution/unsafe-alternative-syntax.md\n\nToday we took another look at the syntax around the `unsafe` proposal. So far, our discussions have leaned heavily into the breaking changes aspect,\ntaking a fairly maximally-breaking approach. However, we wanted to fully explore our options for non-breaking versions of the change as well. To\nhelp guide discussion, there are two types of break we talk about in this area:\n\n* A _syntax_ breaking change. This is taking existing syntax, and changing the meaning of it. This is the type of change where, given a method\n  definition, a reader cannot know what it means without knowing the flags passed to the compiler. Namely, does `public unsafe void M() {}` mean\n  that the caller must be in an `unsafe` context, or not?\n* An ecosystem breaking change. This is where, upon upgrading to a new version of .NET and turning on the feature, what is unsafe and what is not\n  changes interpretation, because the user is consuming a BCL and set of dependencies that have added safety information to their APIs. This break\n  is not under debate today; it will happen, but it can happen independently of the syntax break.\n\nThere is a tension in our design between wanting a simple set of rules, without needing to know about new attributes or keywords, and ensuring that\nusers can actually adopt the changes and drive a safer .NET ecosystem. We feel that, given a brand new language, we would likely have `unsafe`\non the method body mean the caller must be in an `unsafe` context, which would then likely drive other decisions such as `unsafe` on the method\nsignature not automatically marking the body as an `unsafe` context. However, this is truly the largest syntax breaking change we would have ever\ndone in C#. Even though we hope it will only hit a small segment of our users, it will likely hit those users heavily, and those are the users we\nwant to adopt the change to ensure safety for the rest of the ecosystem. This was a shorter session, so we didn't arrive to any kind of final\nconclusion today. The LDM is generally leaning in favor of trying to avoid the syntax break, but how exactly (i.e., attribute vs a new keyword) is not\nsomething we were able to drill into today. Further, several members of the LDM are still interested in the original proposal, syntax break and all.\nTherefore, we want to continue exploring this topic, in particular drilling into the attribute vs new keyword discussion, and we'll come back to this\nnext week.\n"
  },
  {
    "path": "meetings/2026/LDM-2026-01-26.md",
    "content": "# C# Language Design Meeting for January 26th, 2026\n\n## Agenda\n\n- [Alternative syntax for caller-unsafe](#alternative-syntax-for-caller-unsafe)\n\n## Quote(s) of the Day\n\n- \"[redacted], you are the most punctual person ever. You joined exactly when the clock hit [meeting start time]. Are you using some kind of auto-meeting joiner?\" \"No, I was just watching the clock.\"\n- \"ų̷n̷s̷a̷f̷e̷\"\n- \"That wasn't a particularly bad dad joke, was it? It wasn't quote of the day material.\" \"Well that was\"\n\n## Discussion\n\n### Alternative syntax for caller-unsafe\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9704  \nSpec: https://github.com/dotnet/csharplang/blob/61f06216967ed264a8f83c71bff482f3eb6ac113/proposals/unsafe-evolution.md  \nWorking group notes: https://github.com/dotnet/csharplang/blob/61f06216967ed264a8f83c71bff482f3eb6ac113/meetings/working-groups/unsafe-evolution/unsafe-alternative-syntax.md\n\nContinuing from [last week's discussion](./LDM-2026-01-21.md), the LDM had a strong lean toward not repurposing the\nexisting `unsafe` keyword for caller-unsafe semantics. Today we explored the remaining design space: should we use an\nattribute like `[RequiresUnsafe]`, or a new keyword other than `unsafe`?\n\nSeveral arguments were raised in favor of an attribute approach. An attribute is a safer incremental choice; we could\nship an attribute, learn from user feedback during the .NET 11 preview cycle, and add a keyword later if needed. We\ncannot remove a keyword once introduced. Attributes also provide more flexibility for distinguishing between existing\nmembers that became caller-unsafe (where consumers may need an escape hatch during migration) versus new members that\nare caller-unsafe from the start (where there's no conceptual reason to allow opting out).\n\nOn the other hand, strong arguments were made for a dedicated keyword. A keyword conveys the seriousness with which C#\nis treating memory safety and makes it a first-class language concept. If caller-unsafe were just an attribute, it\nwould be effectively the same as shipping an analyzer; it wouldn't feel like part of the language. The signal value\nmatters: as the industry increasingly demands memory-safe languages, C# needs to demonstrate that safety is built into\nthe language itself, not bolted on as an afterthought.\n\nThe discussion also touched on audit ergonomics. The guidance that the libraries team is working on is to keep `unsafe`\nblocks as small as possible, drawing the eye to precisely where unsafety occurs. This has implications for the syntax\ndesign: having both `unsafe` at the method level and `[RequiresUnsafe]` on the same member is effectively incorrect,\nyou probably never want both. When `unsafe` is at the method level, it suppresses all warnings internally, making it\nimpossible to audit which specific operations are unsafe. This means that when users enable the feature, they cannot\neasily audit their existing code; they would need to go through every usage of `unsafe` line by line. Or, we have to\nmake the breaking change even larger, and change `unsafe` on a member to not create an `unsafe` block inside the member\nat all. This is currently an active question in the proposal, but if we proceed with `unsafe` as the keyword, then we\nwould need to answer that question.\n\nWe then brainstormed extensively on possible syntaxes:\n\n1. `[RequiresUnsafe]`\n2. `[CallerUnsafe]`\n3. `[Requires(\"unsafe\")]`, `[Requires(\"experimental\")]`\n4. `callerunsafe`\n5. `requiresunsafe`\n6. `unsafe(caller)`\n7. `requires(unsafe)`\n8. `requires unsafe`\n9. `unsafe required`\n10. `#require unsafe`\n11. `requires-unsafe`\n12. `unsafe-caller`\n13. `modifier(unsafe)`\n14. `unprotected`\n15. `dangerous`\n16. `access unsafe`\n17. `[RequiresUnsafeContext]`\n18. `propagate unsafe`\n19. `unsafe(propagate)`\n20. `[UnsafeOnly]`\n21. `leakunsafe`\n22. `exportunsafe`\n\nAfter an initial round of voting, the options were narrowed down to `[RequiresUnsafe]`, `[CallerUnsafe]`,\n`requiresunsafe`, `unsafe(caller)`, `requires unsafe`, and `unsafe required`. A second round of voting further narrowed\nthe field to `[RequiresUnsafe]`, `[CallerUnsafe]`, `[UnsafeOnly]`, `requires unsafe`, `unsafe(caller)`, and\n`requiresunsafe`. None of the keyword options were liked by a majority of the LDM, with most preferring the attribute\napproach, with `[RequiresUnsafe]` being the preferred option. We then compared this against the original proposal:\nrepurposing `unsafe` itself. `[RequiresUnsafe]` is preferred over repurposing the `unsafe` keyword, so we will proceed\nwith the alternative syntax proposal.\n\n#### Conclusion\n\nWe will use an attribute, `[RequiresUnsafe]`, for communicating when the caller of a method or user of a field/property\nmust be in an `unsafe` context.\n"
  },
  {
    "path": "meetings/2026/LDM-2026-02-02.md",
    "content": "# C# Language Design Meeting for February 2nd, 2026\n\n## Agenda\n\n- [Extension indexers](#extension-indexers)\n    - [Open question: params on indexer setters](#open-question-params-on-indexer-setters)\n    - [Open question: should extension Length/Count properties make a type countable?](#open-question-should-extension-lengthcount-properties-make-a-type-countable)\n    - [Open question: extension indexer access ordering](#open-question-extension-indexer-access-ordering)\n\n## Quote of the Day\n\n- \"Does Count count?\" \"Only after a Lengthy discussion\"\n\n## Discussion\n\n### Extension indexers\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9856  \nSpec: https://github.com/dotnet/csharplang/blob/7a58785d96afc903219cb33f45360744211c3c4c/proposals/extension-indexers.md\n\nThe LDM reviewed the extension indexers proposal and had no comments on the overview.\n\n#### Open question: params on indexer setters\n\nOpen question: https://github.com/dotnet/csharplang/blob/7a58785d96afc903219cb33f45360744211c3c4c/proposals/extension-indexers.md#dealing-with-params\n\nWhen an extension indexer has a `params` parameter, the setter's implementation method ends up with `params` in a\nnon-final position (the value parameter comes after it). The question was whether to disallow this scenario or simply\nemit the `params` attribute as-is.\n\nThis isn't actually an extension-specific problem: regular instance indexers with `params` already emit setters with the\n`params` attribute in the middle. The difference is that for regular indexers, users can't directly invoke the accessor\nmethods, so they never observed this signature (though there is a possibility it can be observed through C# consuming a\nVB non-default indexed property). With extension indexers, the implementation methods are invokable via the disambiguation\nsyntax, so it can be more directly observed.\n\nBoth the C# and VB compilers are designed to ignore `params` attributes on any parameter other than the last. While\nwe should verify that tooling (like IDE signature help) doesn't display `params` in confusing locations, the consensus\nwas that we should simply let things fall out naturally without special-casing this scenario.\n\n##### Conclusion\n\nEmit the `params` attribute on the setter implementation method even though it appears on a non-final parameter.\nCompilers will ignore it in that position, maintaining consistency with how regular indexers already behave. We will\nensure that the IDE behaves well in these scenarios.\n\n#### Open question: should extension Length/Count properties make a type countable?\n\nOpen question: https://github.com/dotnet/csharplang/blob/7a58785d96afc903219cb33f45360744211c3c4c/proposals/extension-indexers.md#should-extension-lengthcount-properties-make-a-type-countable\n\nIn C# 14, extension properties were explicitly excluded from contributing to implicit indexers (the pattern-based\nindexing that uses `Length`/`Count` with an `int` indexer or `Slice` method). This was because extension methods also\ndidn't contribute to that pattern.\n\nHowever, now that we're adding extension indexers that can directly take `System.Index` or `System.Range`, a question\narises: if you define an extension indexer taking `Index` and an extension `Length` property, should list patterns work\non that type?\n\n```cs\nclass C { }\n\nstatic class E\n{\n    extension(C c)\n    {\n        object this[System.Index] => ...;\n        C this[System.Range] => ...;\n        int Length => ...;\n    }\n}\n\n// Should this work?\nif (c is [.., var y]) { }\n```\n\nThere was strong sentiment in the LDM for a \"maximalist\" approach: extension members should participate in language\npatterns wherever possible. This mostly matches our past approaches, and how we've loosened similar restrictions on\nother language features recently.\n\nWe considered whether to require that all members contributing to a pattern come from the \"same origin\" (same extension\nblock or all from the instance type). The rationale was to prevent confusing situations where unrelated extensions from\ndifferent libraries combine unexpectedly. However, counter-arguments noted that this would force users to redeclare\nmembers that already exist (like `Length`), potentially causing ambiguity errors when both namespaces are imported. Those\nextensions may not even be ever usable, if the issue was that the underlying type did not provide a `Length`, for example,\nthen an extension being forced to provide a `Length` when it can never be invoked as an extension would be odd.\n\nThe LDM concluded that enforcing same-origin rules would add more complexity than it prevents. If the type already has a\n`Length` property that wasn't intended to participate in patterns, that's unfortunate, but preventing extensions from\nfilling in the rest of the pattern only works if the member happens to be named `Length`; otherwise an extension could\nadd it anyway. Analyzer rules could flag suspicious combinations if this becomes a real problem in practice.\n\nA follow-up question was whether extension members should also contribute to *implicit* indexers (the fallback that\nuses `Length` + `int` indexer instead of direct `Index`/`Range` indexers). The same maximalist reasoning applied: if\nyou add an extension `int` indexer, you shouldn't need to also add an `Index` indexer just to use `c[^1]`.\n\n##### Conclusion\n\nWe will allow permissive extension applicability. Extension members can contribute to pattern-based indexer matching\nfrom multiple sources.\n\n#### Open question: extension indexer access ordering\n\nOpen question: https://github.com/dotnet/csharplang/blob/7a58785d96afc903219cb33f45360744211c3c4c/proposals/extension-indexers.md#confirm-whether-extension-indexer-access-comes-before-or-after-implicit-indexers\n\nThe final open question concerned lookup ordering. When binding an element access, the current order is:\n\n1. Instance indexer (`Index`/`Range` signature)\n2. Instance implicit indexer (`Length` + `int`/`Slice`)\n3. Extension indexer\n\nThe previous decision to allow extensions to contribute to implicit indexers opened a can of worms about priority. What\nhappens when an inner extension scope defines `Length`, an outer scope defines an `int` indexer, and an even outer scope\ndefines an `Index` indexer? Different orderings lead to different behavior.\n\nSeveral approaches were discussed:\n\n1. Process instance members fully (both direct and implicit indexers) before any extensions\n2. At each extension scope, try direct indexers then implicit indexers, then move to the next scope\n3. Prioritize direct `Index`/`Range` indexers everywhere, then fall back to implicit patterns\n\nThere was agreement that instance members should be fully exhausted before looking at extensions, but the exact ordering\nwhen multiple extension scopes are involved remained unclear. We think this requires more investigation with concrete\nexamples to understand all the consequences. Depending on how we do searches, and for what piece of the language, there\ncould be very odd priority inversions and member selections that are not obvious to readers. For example, if there are 3\nscopes in order from `Length`, `Index`-based indexer, and `int`-based indexer, what is the expectation on what is being\ncalled for `underlying[^1]`?\n\n##### Conclusion\n\nWe need to revisit this question with a proposal that works through the combinations systematically. The extensions\nworking group will investigate and bring back a more concrete recommendation.\n"
  },
  {
    "path": "meetings/2026/LDM-2026-02-04.md",
    "content": "# C# Language Design Meeting for February 4th, 2026\n\n## Agenda\n\n- [Discriminated unions patterns](#discriminated-unions-patterns)\n    - [Null ambiguity in constructor selection](#null-ambiguity-in-constructor-selection)\n    - [Marking unions with an attribute instead of IUnion interface](#marking-unions-with-an-attribute-instead-of-iunion-interface)\n    - [Factory method support](#factory-method-support)\n    - [Union member providers](#union-member-providers)\n\n## Quote of the Day\n\n- \"The distant past. You know, late summer or early fall.\"\n\n## Discussion\n\n### Discriminated unions patterns\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9662  \nSpec: https://github.com/dotnet/csharplang/blob/d614288f7dab369f763520ba48b12623c34d8542/proposals/unions.md#union-declarations  \nWorking group notes: https://github.com/dotnet/csharplang/blob/d614288f7dab369f763520ba48b12623c34d8542/meetings/working-groups/discriminated-unions/union-patterns-update.md\n\nToday, we went over a few open questions in unions.\n\n#### Null ambiguity in constructor selection\n\nWhen a union has multiple reference type case types, passing `null` creates ambiguity about which constructor to\nuse. For example, with `Pet(Dog)` and `Pet(Bird?)` constructors, `null` could apply to either.\n\nCurrently, the compiler picks an arbitrary applicable constructor when there is ambiguity, based on the assumption\nthat well-formed unions have constructors that behave identically for the same input. However, this can lead to\nsurprising behavior: if the compiler picks the `Dog` constructor but `Bird?` is the one intended to accept `null`,\na nullability warning will be issued even though the union author intended `null` to be valid.\n\nWe discussed several approaches:\n1. Using standard overload resolution betterness rules to select among applicable constructors\n2. Requiring the user to be explicit when multiple cases could apply (warning or error on ambiguity)\n3. Ensuring nullability annotations factor into the decision\n\nWe liked options 1 and 2 here. Option 3 is not how the compiler works today, and doesn't solve the scenario in nullable\ndisabled locations. There are also scenarios where null isn't involved, such as a union of two interfaces and a type\nthat implements both. We also brought up operator conversions, as union conversions are very similar to user-defined\noperators. We like that analogy, and want to apply similar rules where applicable.\n\n##### Conclusion\n\nThe working group will consider requiring explicit disambiguation when ambiguity cannot be resolved through standard\nbetterness rules, similar to how conversion operators are resolved.\n\n#### Marking unions with an attribute instead of IUnion interface\n\nThe current design uses the `IUnion` interface to indicate that a type should be treated as a union. This causes\nproblems:\n- A type cannot implement `IUnion` without becoming a union (it might just want runtime participation)\n- Derived types of a union type automatically become unions themselves, which may not be intended and raises\n  awkward questions about what their case types should be\n- It conflates the runtime interface (useful for generic code that handles unions) with the compiler recognition\n  mechanism\n\nThe proposal is to use a `[Union]` attribute instead, with the compiler looking for members by shape rather than\nthrough the interface. The `IUnion` and `IUnion<TUnion>` interfaces would still exist for runtime scenarios (such\nas generic code that queries whether something is a union or accesses its value), but they would be optional and\nnot required for compiler recognition.\n\n##### Conclusion\n\nApproved. The design will change from requiring `IUnion` interface implementation to using a `[Union]` attribute\nfor compiler recognition. Members will be looked up by shape (constructors with case type parameters, a `Value`\nproperty).\n\n#### Factory method support\n\nConstructors have limitations: they cannot be defined on a type other than the one they construct, and they cannot\nbe inherited or delegated. Static factory methods provide more flexibility for scenarios involving type hierarchies,\nobject pooling, or delegating union member definitions to a separate type.\n\nThe proposal is to allow `public static Create` methods as an alternative to constructors for defining case types.\nWhen factory methods are present, they take precedence over constructors.\n\nThere was significant concern about implicit recognition of factory methods based on shape alone. A method like\n`Parse(string)` returning the union type could be unintentionally picked up as defining a `string` case type. Even\nif we restrict to just a single name (`Create`), we don't have enthusiasm for the magic shape recognition among\ndifferent overloads here.\n\nThe LDM expressed strong support for requiring explicit markers rather than relying on implicit shape matching.\nThe proposal of a `[UnionCase]` attribute was well-received: authors would mark constructors, factory methods, or\neven user-defined implicit conversion operators that should contribute to the union's case types.\n\nA follow-up question arose: should the `[UnionCase]` attribute be required on everything, including constructors,\nor should there be a simple default mode where constructors work implicitly? Two positions emerged:\n\n1. Attributes on everything: Any member used by the compiler for union behavior must be marked with `[UnionCase]`.\n\n2. Default behavior for constructors: If a union type has only constructors (no factory methods or conversion\n   operators), they work implicitly without attributes. Once you want any customization (factory methods, conversion\n   operators, or selective inclusion of constructors), you must use `[UnionCase]` on all participating members.\n\nA read-of-the-room vote showed preference for the second approach: allow the simple constructor-only case to work\nwithout attributes, while requiring explicit marking for any advanced scenarios. However, we want the working group\nto take a look at the implications and come back with a concrete proposal and recommendations.\n\n##### Conclusion\n\nMove forward with the `[UnionCase]` attribute approach. The working group will produce a concrete proposal with\nspecific rules. There is no requirement for a specific factory method name when the attribute is used.\n\n#### Union member providers\n\nThis proposal addresses scenarios where the union's desired behavior conflicts with its public surface area. Two\ncases were identified:\n1. The type has members that would be incorrectly recognized as union members\n2. The type needs union members but does not want them in its public API\n\nThe idea was to allow delegating union member lookup to a separate \"provider\" type (e.g., a nested interface).\n\nGiven the decision to use explicit `[UnionCase]` attributes, the first scenario is largely addressed: members won't\nbe picked up unless explicitly marked. For the second scenario, user-defined implicit conversion operators (if\nsupported) could address types like `Result<T>` that expose conversions but not constructors. However, we don't have\ngood examples of what could actually need this ability. Given that, we will simply table this addition for now, and\ncome back when we have concrete scenarios to address.\n\n##### Conclusion\n\nThis feature will be saved for later. The explicit attribute approach addresses the primary motivating scenarios.\nIf compelling use cases emerge that require full delegation to a provider type, the design space remains open.\n\n### General principle established\n\nThroughout the discussion, a general principle emerged: the LDM is comfortable with some implicit behavior for\nwell-known members (like recognizing a property named `Value`), but prefers explicit marking for case type\ndefinitions due to the inherent variability and potential for false positives. It's possible further consideration\nof real use cases may cause us to want to go even further into the explicit territory (explicitly marking `Value` or\nthe `TryValue` methods, for example), but the working group will explore this space.\n"
  },
  {
    "path": "meetings/2026/LDM-2026-02-09.md",
    "content": "# C# Language Design Meeting for February 9th, 2026\n\n## Agenda\n\n- [Closed hierarchies open questions](#closed-hierarchies-open-questions)\n    - [Confirming API shape](#confirming-api-shape)\n    - [Blocking subtyping from other languages](#blocking-subtyping-from-other-languages)\n    - [Multiple `CompilerFeatureRequired` attributes](#multiple-compilerfeaturerequired-attributes)\n    - [Same module restriction](#same-module-restriction)\n    - [Permit explicit use of `abstract` modifier](#permit-explicit-use-of-abstract-modifier)\n    - [Subtype metadata](#subtype-metadata)\n\n## Quote(s) of the Day\n\n- \"I will always call `unions`, `onions`.\"\n- \"This class, despite its name, is not `closed`\"\n\n## Discussion\n\n### Closed hierarchies open questions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9499  \nSpec: https://github.com/dotnet/csharplang/blob/fab1ad040df56d5cfcca0b271b02a20f30e389a6/proposals/closed-hierarchies.md\n\nToday we went through the open questions in the closed hierarchies spec.\n\n#### Confirming API shape\n\nSpec section: https://github.com/dotnet/csharplang/blob/fab1ad040df56d5cfcca0b271b02a20f30e389a6/proposals/closed-hierarchies.md#closedattribute\n\nWe started by confirming the shape of the API. We may add `interface`s as a supported target in the future, but for now limiting this simplifies the\nspecification. Otherwise, we like the shape, modulo getting it approved by the libraries API review.\n\n##### Conclusion\n\nAPI approved.\n\n#### Blocking subtyping from other languages\n\nSpec section: https://github.com/dotnet/csharplang/blob/fab1ad040df56d5cfcca0b271b02a20f30e389a6/proposals/closed-hierarchies.md#blocking-subtyping-from-other-languagescompilers\n\nThe spec proposes applying `[CompilerFeatureRequired(\"ClosedClasses\")]` to all constructors of closed classes. Since closed classes are abstract,\ntheir constructors can only be invoked from constructor initializers in derived types. Compilers that do not understand the feature will see the\n`CompilerFeatureRequired` attribute and block derivation, effectively preventing unauthorized subtyping from older C# compilers or other .NET\nlanguages. The `[Obsolete]` attribute that was used alongside `CompilerFeatureRequired` for `required` members is no longer considered necessary,\nsince `CompilerFeatureRequired` has been around long enough that compilers are expected to understand it.\n\nThe LDM approved this approach. There was also a suggestion about whether constructors of closed types should be required to have\n`private protected` accessibility, to further express the intent that these constructors are only for use by known subtypes. However, this was\nconsidered more trouble than it is worth: `private protected` is a niche accessibility, primary constructors pick up the accessibility of their\ncontaining type, and synthesized constructors would need special handling. Requiring more restrictive accessibility would add complexity without\nmeaningful benefit, since `CompilerFeatureRequired` already blocks unauthorized use. The LDM decided to proceed without constructor accessibility\nrestrictions and keep an eye on it going forward.\n\n##### Conclusion\n\nThe `CompilerFeatureRequired` approach on constructors is approved. No additional constructor accessibility restrictions will be required.\n\n#### Multiple `CompilerFeatureRequired` attributes\n\nSpec section: https://github.com/dotnet/csharplang/blob/fab1ad040df56d5cfcca0b271b02a20f30e389a6/proposals/closed-hierarchies.md#use-of-multiple-compilerfeaturerequired-attributes\n\nWhen a closed class also has required members, both `[CompilerFeatureRequired(\"RequiredMembers\")]` and\n`[CompilerFeatureRequired(\"ClosedClasses\")]` end up on the constructors. The question was whether to emit only the most recent attribute, on\nthe theory that a compiler supporting closed classes must already support required members.\n\nThe LDM concluded that all attributes should be emitted. Each part of the compiler that checks for a given feature can remain independent,\nwithout needing to know about other features. It is also a valid scenario for a language or compiler to support one feature but not another; for\nexample, a language might support closed hierarchies but not required members. Users also get better diagnostics when all relevant attributes are\npresent, rather than receiving confusing errors about only one of the features. While the number of attributes could grow over time, that concern\ncan be revisited if it ever actually becomes a problem.\n\n##### Conclusion\n\nEmit a `[CompilerFeatureRequired]` attribute for each feature independently.\n\n#### Same module restriction\n\nSpec section: https://github.com/dotnet/csharplang/blob/fab1ad040df56d5cfcca0b271b02a20f30e389a6/proposals/closed-hierarchies.md#same-module-restriction\n\nThe proposal strengthens the \"same assembly\" restriction to \"same module,\" since the compiler supports loading dependencies with multiple modules in\na single assembly. The reasoning is the same as for cross-assembly subtyping: the original module needs to know the complete set of subtypes for\nexhaustiveness checking, and allowing subtypes from another module would break that.\n\nIn practice, this distinction is largely academic since modern .NET no longer supports multi-module assemblies. The restriction effectively\nchanges nothing for real-world users, but it is the correct formulation from the language specification perspective, which generally talks about\nprograms in terms of modules.\n\n##### Conclusion\n\nApproved. The spec will use \"same module\" language instead of \"same assembly.\"\n\n#### Permit explicit use of `abstract` modifier\n\nSpec section: https://github.com/dotnet/csharplang/blob/fab1ad040df56d5cfcca0b271b02a20f30e389a6/proposals/closed-hierarchies.md#permit-explicit-use-of-abstract-modifier\n\nA `closed` class is implicitly abstract. Should the language also permit writing `closed abstract class`?\n\nArguments for allowing it centered on consistency with how the language handles default accessibility: when there is a default, C# typically\nallows you to state it explicitly for clarity. Partial declarations were raised as a scenario where one part of a type might have `closed` and\nanother might have `abstract`, and requiring the `abstract` to be removed would be unnecessary friction. Additionally, unlike `abstract` on\ninterfaces (which is truly meaningless), `abstract` on a closed class does have a concrete meaning: it is part of the definition of `closed`.\n\nArguments for blocking it drew an analogy to `static` classes, which are emitted as abstract sealed types but do not allow either `abstract` or\n`sealed` as explicit modifiers. The key difference from the default accessibility case is that there is no alternative here: you cannot make a\nclosed class non-abstract, so stating `abstract` is purely redundant rather than picking from multiple options. Blocking the combination also\nensures that every closed class declaration looks the same, which reduces cognitive overhead. A point was also raised about modern coding agent\nworkflows: languages that define a single uniform way to write things tend to produce better agent experiences, as agents are more likely to\nproduce consistent output when there is exactly one way to express something.\n\nAfter heavy discussion, we have decided to move forward with blocking for now. Starting restrictive is the prudent approach: if a compelling\nscenario arises where allowing `abstract` alongside `closed` is important, the restriction can always be relaxed later.\n\n##### Conclusion\n\n`closed abstract class` will not be allowed. The `closed` modifier implies `abstract`, and specifying both is an error.\n\n#### Subtype metadata\n\nSpec section: https://github.com/dotnet/csharplang/blob/fab1ad040df56d5cfcca0b271b02a20f30e389a6/proposals/closed-hierarchies.md#todo-should-subtypes-be-marked-in-metadata\n\nThe spec raised whether the compiler should emit an attribute on the closed type listing all of its direct subtypes (e.g.,\n`[ClosedSubtype(typeof(Subtype1), typeof(Subtype2), ...)]`), so that consuming tools do not have to scan the assembly to discover them. From the\ncompiler's perspective, this is not needed: the typedef table in the assembly metadata has an \"extends\" column, and scanning it for subtypes of a\ngiven type is fast. Even for large assemblies like `Microsoft.CodeAnalysis.CSharp`, the typedef table only has around 1,400 entries.\n\nHowever, concerns were raised about scenarios beyond the compiler. Runtime discovery via reflection would be significantly more expensive and is\nalso incompatible with trimming and AOT, since scanning an assembly for subtypes could return different results depending on what types the\ntrimmer kept. Without breadcrumbs in metadata, closed hierarchies would be effectively a compiler-only feature with no affordable way for\nruntime tools to discover the hierarchy.\n\nThe LDM concluded that this is not a language-level concern. The compiler does not need it, and there are no pending requests from runtime,\nreflection, or serialization teams. If such requests arise, the compiler can emit additional metadata without changing language-level semantics.\nFor now, subtypes will be discovered by scanning the assembly metadata tables.\n\n##### Conclusion\n\nNo subtype listing attribute will be emitted at this time. The compiler team will respond to requests from runtime or tooling teams if they need\ncheaper runtime discovery.\n"
  },
  {
    "path": "meetings/2026/LDM-2026-02-11.md",
    "content": "# C# Language Design Meeting for February 11th, 2026\n\n## Agenda\n\n- [Union patterns update](#union-patterns-update)\n\n## Quote of the Day\n\n- \"My Result type is a GC hole.\" \"I'd put that on a t-shirt.\"\n\n## Discussion\n\n### Union patterns update\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9662  \nSpec: https://github.com/dotnet/csharplang/blob/0e3a99401b0fb0fbde2ad976e63332c4d603e6d5/proposals/unions.md  \nWorking group notes: https://github.com/dotnet/csharplang/blob/0e3a99401b0fb0fbde2ad976e63332c4d603e6d5/meetings/working-groups/discriminated-unions/union-patterns-update.md\n\nThe discriminated unions working group returned to LDM with an updated proposal for union member patterns on custom union\ntypes. In the [previous discussion](./LDM-2026-02-04.md#union-patterns-update), the LDM had expressed a preference for\nexplicit marking of case types via a `UnionCase` attribute, rather than having them be implicitly recognized. The working\ngroup took that feedback and explored the attribute approach further, but found that attributes still lead to significant\ncomplexity in certain real-world scenarios.\n\nThe core problem is that existing types that want to become union types may already have members that would be recognized\nas union members, but that serve a different purpose. In some cases, these members even clash with what the union feature\nneeds, so an attribute cannot resolve the conflict. A common real-world example is a `Result`-like union type that has a\n`Value` property meaning something different from what the union pattern expects.\n\nInstead of attributes, the working group proposed a delegation approach: a union type can optionally delegate all of its\nunion members to a nested interface called `IUnionMembers` that the union type implements. Since constructors cannot\nappear in interfaces, factory methods named `Create` are used instead. The interface can include an abstract `Value`\nproperty that is explicitly implemented on the union type, keeping it off the public surface area. The compiler can then\nuse constrained calls to avoid the overhead of interface dispatch.\n\nThe walkthrough included several real-world union-like types to demonstrate how the approach works in practice:\n\n- **`SumType`** (from Roslyn/LSP): This type already happens to expose exactly the union pattern. It has constructors\n  for each case type and an `object?`-returning `Value` property. It can simply be marked with the `[Union]` attribute\n  and everything works. It was noted that this type also has `TryGet` methods but they use different names, so they do\n  not accidentally match the non-boxing access pattern, which is appropriate since the type stores values in a boxed\n  form anyway.\n\n- **`OneOf`** (a popular third-party library): This type has a `Value` property of the right shape but does not expose\n  constructors. This is a case where delegation is needed: a nested `IUnionMembers` interface can be added with `Create`\n  factory methods for each case type, plus a `Value` property. The type would then implement the interface, and since the\n  existing `Value` property already satisfies the interface member, no additional implementation is needed.\n\n- **`Results`** (from ASP.NET Minimal APIs): This type has a property that serves the same purpose as `Value` but has\n  a different name and a more specific return type (`IResult` rather than `object?`). This is another case where\n  delegation is needed. This example also raised a question about whether the `Value` property should be allowed to\n  have a more specific return type in general, which could enable better nullability analysis and more efficient code.\n  That question was noted but deferred to a separate discussion.\n\nIt was observed that all three real-world types already implement their own implicit conversion operators, which would\nshadow the compiler-generated union conversion in all cases. This means the `Create` factory methods on the\n`IUnionMembers` interface would primarily serve to inform the compiler about the case types, rather than being called\nat runtime. This prompted a brief discussion about \"consume-only\" unions, where the type does not want to expose the\nability for users to create union values directly. A possible future solution was sketched out involving a separate\nmethod name (e.g., `CaseTypeOf`) that returns `void` and only lists the case types, but this is not proposed for now.\n\nA question was raised about whether the non-boxing access pattern (`TryGetValue` methods) could actually be harmful if\napplied to types that already store values in a boxed form. The LDM agreed that guidance will be needed to explain when\nit is appropriate to expose the non-boxing pattern, but the specifics of the compiler heuristics for choosing between\n`Value` and `TryGetValue` are not yet fully worked out.\n\nRegarding the `IUnionMembers` interface, it was confirmed that this interface must be defined as a nested type directly\nwithin the union type, not inherited from a base type. An inherited `IUnionMembers` interface would have the wrong type\nparameters in its factory methods and would not be useful. Even though the language generally picks up members from base\ntypes in lookup, this particular interface is scoped to only the declaring type.\n\nThere was a question about whether static non-DIM (default interface method) members in interfaces are supported on\nolder runtimes. The C# compiler currently blocks static members in interfaces when the target runtime does not support\nDIMs, even though non-virtual static members in interfaces have always been supported by the runtime independently of\nDIM support. The working group followed up and confirmed that static non-virtual interface members have been properly\nexercised on the Desktop CLR: C++/CLI has offered them at the language level all along, and F# has also been targeting\nthem for some time. So this is not a concern.\n\nA concern was raised about metadata bloat from the additional interface type. The working group noted that they had\nconsidered an even simpler approach where every union, including those from the `union` keyword, always delegates to an\ninterface, but rejected it because generating two types for every union declaration felt excessive. The working group\nfollowed up on this concern as well, and confirmed that the nested-interface approach is not concerning from a metadata\nbloat perspective, given how uncommon the delegation scenario is expected to be.\n\n#### Conclusion\n\nThe LDM is in favor of the `IUnionMembers` delegation approach as proposed by the working group. We will move forward\nwith the proposal as written.\n"
  },
  {
    "path": "meetings/2026/LDM-2026-03-09.md",
    "content": "# C# Language Design Meeting for March 9th, 2026\n\n## Agenda\n\n- [Extension indexers](#extension-indexers)\n    - [Ordering for implicit indexers and list patterns](#ordering-for-implicit-indexers-and-list-patterns)\n    - [Slice extensions for range access](#slice-extensions-for-range-access)\n    - [Spread optimization in collection expressions](#spread-optimization-in-collection-expressions)\n\n## Quote(s) of the Day\n\n- \"Ordering or orering?\" \"I'm writing ordering, sorry if that confuses you\"\n\n## Discussion\n\n### Extension indexers\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9856  \nSpec: https://github.com/dotnet/csharplang/blob/ee06dd0eaaff1ddb16d0f6680107a1a00aecee92/proposals/extension-indexers.md\n\nWe continued discussion of the remaining open questions around extension indexers and their interactions with list patterns. The\ncore tension is that multiple lookup principles all seem desirable in isolation: instance members should continue to beat extensions\nfor compatibility, inner extension scopes should generally beat outer scopes, and real `this[Index]`/`this[Range]` members are\nusually preferable to implicit indexers assembled from `Length` or `Count` together with `this[int]` or `Slice`. Unfortunately,\nthese preferences conflict once extension members are allowed to contribute to indexing.\n\n#### Ordering for implicit indexers and list patterns\n\nThe hardest question was how to order extension lookup once implicit indexers are involved. We compared two broad\napproaches. One would continue to prioritize inner extension scopes over outer scopes, even when that meant selecting an\nimplicit indexer assembled from closer members instead of a real indexer found farther out. The other would keep the strong\npreference that instance members always beat extensions, but once extension lookup was required it would give a weak priority\nto real indexers over implicit ones, even if the real indexer came from an outer extension scope.\n\nWe chose the second ordering. We feel that a real indexer remains a more coherent single declaration than an implicit indexer\nassembled from multiple members, and that this weak preference was worth preserving once the search had already moved beyond\ninstance members. This does make extension lookup somewhat irregular, because the language will no longer uniformly prefer the\nclosest extension-provided solution in every case, but the LDM preferred that irregularity over a rule that would make real\nextension indexers lose to extension-based implicit combinations more often.\n\nList patterns were discussed alongside ordinary indexer access. We do not want list patterns to use one `Length` or\n`Count` member for shape checking and then silently use a different one when resolving indexing behavior. Instead, list pattern\nsupport should be described in terms of independently resolving the members needed for the operation, using the same overall\nordering principles as indexer access.\n\nWe workshopped the following specese during the meeting, which will need to be refined before inclusion in the speclet:\n\n> 1. List patterns are resolved as if we look for Length/Count, Index indexer and Range indexer individually\n> 2. For Index and Range indexers, proceed as follows:\n>     a. With instance lookup only, find the \"real\" index if possible\n>     b. With instance lookup only, find the parts of the implicit indexer if possible\n>     c. With full lookup (instance+extension), find the \"real\" index if possible\n>     d. With full lookup (instance+extension), find the parts of the implicit indexer if possible (each in individual lookups)\n\n##### Conclusion\n\nWhen resolving extension-based indexing behavior, instance lookup remains strictly better than extension lookup. After that,\nthe language will give a weak preference to real `Index` and `Range` indexers over implicit indexers, even when that means an\nouter extension scope can beat an implicit solution formed from a closer scope. List patterns will resolve the required\nmembers using the same overall ordering model rather than treating implicit indexers in extensions as unsupported.\n\n#### Slice extensions for range access\n\nWe next looked at the `Slice` portion of implicit range support. The question was whether, once extension members are\nallowed to contribute, only extension-block `Slice` members should count, or whether classic extension methods named `Slice`\nshould count as well. Historically, neither form contributed here, so enabling extension participation would cause some code\nto start compiling where it previously produced an error.\n\nWe see no good reason to distinguish the two forms. The extensions feature has consistently tried to make classic\nextension members and extension-block members interchangeable from the user's point of view, and this scenario should follow\nthat same principle. Moving from an error to a successful binding was also considered acceptable here, because it does not\nbreak previously-working code and is a natural consequence of allowing extensions to participate in range access.\n\n##### Conclusion\n\nBoth classic extension `Slice` methods and extension-block `Slice` members will contribute to implicit range access under the\nnew rules.\n\n#### Spread optimization in collection expressions\n\nFinally, we considered whether extension `Length` or `Count` properties should participate in the optimization for spread\nelements in collection expressions. That optimization exists to avoid unnecessary reallocations by pre-sizing the destination\nwhen the compiler can cheaply determine the number of elements that will be produced.\n\nThe concern was that an extension `Length` or `Count` member is much less likely to represent cheap, intrinsic knowledge about\nthe underlying type. In many cases, such an extension would have to enumerate the source to discover the count, which would\ndefeat the purpose of the optimization by adding an extra traversal before the actual spread occurs. We therefore\nprefer to keep the optimization tied to information directly exposed by the source type itself. If compelling scenarios\nemerge later, or if there is a better hook for efficient optional counts, the language can revisit this decision.\n\n##### Conclusion\n\nExtension `Length` and `Count` members will not participate in spread optimization for collection expressions.\n"
  },
  {
    "path": "meetings/2026/README.md",
    "content": "# Upcoming meetings for 2026\n\nAll schedule items must have a public issue or checked-in proposal that can be linked from the notes.\n\n## Schedule ASAP\n\n\n## Schedule when convenient\n\n- [Anonymous using declarations](https://github.com/dotnet/csharplang/blob/665a9392e172e6f4f16347c502d9f80220a6e7a4/proposals/anonymous-using-declarations.md) (jnm2, 333fred, CyrusNajmabadi)\n- Triage (working set)\n\n## Recurring topics\n\n- *Triage championed features and milestones*\n- *Design review*\n\n## Schedule\n\n### Wed Apr 29, 2026\n\n### Mon Apr 27, 2026\n\n### Wed Apr 22, 2026\n\n- [Final initializers](https://github.com/dotnet/csharplang/blob/5055b97eee8c10d12f822f6d4db9464329615947/proposals/final-initializers.md)\n  - [LDM in 2020](https://github.com/dotnet/csharplang/blob/main/meetings/2020/LDM-2020-04-27.md#primary-constructor-bodies-and-validators) approved the syntax. Next is discussing semantics.\n\n### Mon Apr 20, 2026\n\n### Wed Apr 15, 2026\n\n- [Deconstruction in lambda parameters](https://github.com/dotnet/csharplang/blob/c4ec6fb60c2e174b1abb6c019f22bb15b9b13f6c/proposals/deconstruction-in-lambda-parameters.md) (CyrusNajmabadi, jnm2)\n  - [Last conclusion](https://github.com/dotnet/csharplang/blob/main/meetings/2026/LDM-2026-01-12.md#deconstruction-in-lambda-parameters): take a closer look in LDM.\n\n### Mon Apr 13, 2026\n\n### Wed Apr 8, 2026\n\n- [Target-typed static member access](https://github.com/dotnet/csharplang/blob/c2465a0605180e9624ee5ea9d6e0eab7e93a7c5b/proposals/target-typed-static-member-access.md) (jnm2, CyrusNajmabadi)\n  - Continue discussing scope and open questions\n- [Labeled `break` and `continue` Statements](https://github.com/dotnet/csharplang/blob/c4ec6fb60c2e174b1abb6c019f22bb15b9b13f6c/proposals/labeled-break-continue.md) (CyrusNajmabadi)\n  - [Last conclusion](https://github.com/dotnet/csharplang/blob/main/meetings/2026/LDM-2026-01-12.md#labeled-break-and-continue-statements): delve deeper in a full session.\n\n### Mon Apr 6, 2026\n\n### Wed Apr 1, 2026\n\n### Mon Mar 30, 2026\n\n(One hour only)\n\n- MVP Summit feedback (Mads)\n\n### Wed Mar 11, 2026\n\n- [Target-typed static member access](https://github.com/dotnet/csharplang/blob/c2465a0605180e9624ee5ea9d6e0eab7e93a7c5b/proposals/target-typed-static-member-access.md) (jnm2, CyrusNajmabadi)\n\n\n## C# Language Design Notes for 2026\n\n### Mon Mar 9, 2026\n\n[C# Language Design Meeting for March 9th, 2026](https://github.com/dotnet/csharplang/blob/main/meetings/2026/LDM-2026-03-09.md)\n\n- Extension indexers\n    - Ordering for implicit indexers and list patterns\n    - Slice extensions for range access\n    - Spread optimization in collection expressions\n\n### Wed Feb 11, 2026\n\n[C# Language Design Meeting for February 11th, 2026](https://github.com/dotnet/csharplang/blob/main/meetings/2026/LDM-2026-02-11.md)\n\n- Union patterns update\n\n### Mon Feb 9, 2026\n\n[C# Language Design Meeting for February 9th, 2026](https://github.com/dotnet/csharplang/blob/main/meetings/2026/LDM-2026-02-09.md)\n\n- Closed hierarchies open questions\n    - Confirming API shape\n    - Blocking subtyping from other languages\n    - Multiple `CompilerFeatureRequired` attributes\n    - Same module restriction\n    - Permit explicit use of `abstract` modifier\n    - Subtype metadata\n\n### Wed Feb 4, 2026\n\n[C# Language Design Meeting for February 4th, 2026](https://github.com/dotnet/csharplang/blob/main/meetings/2026/LDM-2026-02-04.md)\n\n- Discriminated unions patterns\n    - Null ambiguity in constructor selection\n    - Marking unions with an attribute instead of IUnion interface\n    - Factory method support\n    - Union member providers\n\n### Mon Feb 2, 2026\n\n[C# Language Design Meeting for February 2nd, 2026](https://github.com/dotnet/csharplang/blob/main/meetings/2026/LDM-2026-02-02.md)\n\n- Extension indexers\n\n### Mon Jan 26, 2026\n\n[C# Language Design Meeting for January 26th, 2026](https://github.com/dotnet/csharplang/blob/main/meetings/2026/LDM-2026-01-26.md)\n\n- Alternative syntax for caller-unsafe\n\n### Wed Jan 21, 2026\n\n[C# Language Design Meeting for January 21st, 2026](https://github.com/dotnet/csharplang/blob/main/meetings/2026/LDM-2026-01-21.md)\n\n- Unsafe evolution\n\n### Mon Jan 12, 2026\n\n[C# Language Design Meeting for January 12, 2026](https://github.com/dotnet/csharplang/blob/main/meetings/2026/LDM-2026-01-12.md)\n\n- Triage\n    - Relaxed ordering for `partial` and `ref` modifiers\n    - Deconstruction in lambda parameters\n    - Unsigned sizeof\n    - Labeled `break` and `continue` Statements\n    - Extra accessor in property override\n    - Immediately Enumerated Collection Expressions\n    - Allow arrays as CollectionBuilder Create parameter type\n"
  },
  {
    "path": "meetings/README.md",
    "content": "# C# Language Design Meetings\n\nC# Language Design Meetings (LDM for short) are meetings by the C# Language Design Team and invited guests to investigate, design and ultimately decide on features to enter the C# language. It is a creative meeting, where active design work happens, not just a decision body. \n\nEach C# language design meeting is represented by a meeting notes file in this folder.\n\n## Purpose of the meetings notes\n\nMeeting notes serve the triple purposes of\n\n- recording decisions so they can be acted upon\n- communicating our design thinking to the community so we can get feedback on them\n- recording rationale so we can return later and see why we did things the way we did\n\nAll have proven extremely useful over time.\n\n## Life cycle of meeting notes\n\n- If upcoming design meetings have a specific agenda, for instance to suit the schedule of visitors, there may be a meeting notes file with that agenda even before the meeting happens.\n- Otherwise the meeting agendas are determined just-in-time based on urgency, arrival of new information or ideas, challenges found in design and implementation, and so on.\n- After the meeting, notes will be saved directly here. \n- Usually they will be raw notes in need of subsequent cleaning up. If that's the case, they will be clearly marked as such, and a [Meeting notes](https://github.com/dotnet/csharplang/labels/Meeting%20notes) work item will track the task of cleaning up the notes.\n- When the notes are finalized, a notification is posted as a [discussion issue](https://github.com/dotnet/csharplang/labels/Discussion) to encourage discussion of the decisions made. While quick comments are welcome directly on that issue, it is recommended to open a separate issue for deeper or more topic-specific discussions.\n- If the notes impact current proposals, [proposal](https://github.com/dotnet/csharplang/labels/Proposal) work items will track updating those proposals, assigned to their [champions](https://github.com/dotnet/csharplang/labels/Proposal%20champion).\n- When updated, the proposals link back to the meetings where the proposal was discussed.\n\n## Style of design notes\n\nThe notes serve as the collective voice of the LDM. They cover not just the decisions but the discussion, options and rationale, so that others can follow along in the discussion and provide input to it, and so that we don't forget them for later.\n\nHowever, *the notes are not minutes*! They *never* state who said what in the meeting. They will occasionally mention people by name if they are visiting, provided input, should be collaborated with, etc. But the notes aim to represent the shared thinking of the room. If there's disagreement, they will report that, but they won't focus on who wants what.\n\nThis approach is intended to reinforce that the LDMs are a safe space, and a collaborative, creative effort. It is not a negotiation between representatives of different interests. It is not a voting body, and it is not a venue for posturing. Everybody cooperates towards the same end: creating the best language for today's and tomorrow's C# developers.\n\nWhen there are external inputs to the notes (such as open questions, presentations, supplemental documents, etc), they will be committed to this repository and linked to from the notes, with a specific commit, to ensure that any future reorganization will keep the notes working.\n\n## Working groups\n\nWorking groups who choose to do so will keep meeting notes in a subfolder of the [working-groups](working-groups/) folder belonging to that group. These notes will be anonymized, like LDM notes, but are likely to be much rougher than dedicated LDM notes. We will not create dedicated discussions when posting these working group notes. Users that want to comment on them can either comment on the issue for the group or create a discussion, as they choose. Working groups will each have a leader, and that leader will be responsible for coordinating with the broader LDM on when things need to be brought back to the full group.\n"
  },
  {
    "path": "meetings/working-groups/collection-literals/CL-2022-10-06.md",
    "content": "# Collection literals working group meeting for October 6th, 2022\n\nThis is the first meeting of the collection literals working group. The proposal is currently located at <https://github.com/dotnet/csharplang/issues/5354>.\n\n## Agenda\n\n- Overview of the current proposal and its goals\n- Discovering an initial consensus on open questions from which to make recommendations\n- Fleshing out a design for dictionary literals\n\n### Collection literals discussion\n\n#### Natural types\n\nThere was consensus that there should be a natural type and that it should be `List<T>`. It’s not uncommon today for there to be more modifications following a collection initializer. The kicking-the-tires scenario was important to us; the experiences of trying both `var x = [a];` and subsequently `x.Add(...);` are things we think will be formative first impressions of the feature, and we don’t want them to feel confusing or broken.\n\nWe think that `List<T>` will only be an additional allocation beyond `T[]` or `ImmutableArray<T>`. `List<T>` can expose an `init void Init(T[])` method which takes ownership of the array. As a consequence, the list capacity would be initialized to exactly match the item count.\n\nIn a similar vein, we think *unknown-length* collection literals such as `[..enumerable]` should work with fixed-length collections such as `ImmutableArray<T>`. This is a reasonable scenario, and it will make the feature feel confusing or broken if the compiler doesn't allow it. We will look for a codegen strategy to enable this.\n\n#### Eager or lazy enumeration when the target type is `IEnumerable<T>`\n\nCollection literals create an instance of the concrete target type, whether that's `ImmutableArray<T>` or `HashSet<T>`. If the target type is `IEnumerable<T>`, we could imagine the expectation that a lazily-enumerating generator will be produced so that `[..a, ..b]` behaves exactly like `a.Concat(b)`. However, we think it's clear and explicit enough that the *collection* literal `[`...`]` always creates a new collection. This proposal is not about list comprehensions.\n\n#### Other observations\n\n1. We think collection literal syntax should be on par with or better than the runtime performance of the current methods of initializing collections. For example, we need to compare the codegen for `(ImmutableArray<T>)[..enumerableOfT]` to `ImmutableArray.CreateRange<T>`.\n\n1. We think `[..a]` will be a common way to do a shallow clone from one collection type to another.\n\n1. The repetition in `init void Init(...)` looks strange. `init void Construct(...)` was suggested as an alternative name for the compiler to bind to. This would parallel `Deconstruct`.\n\n1. If the language added `let`, we could consider making the natural type of `let x = [a];` be ImmutableArray similar to Swift.\n\n1. The `Init(...)` method could more naturally be static and return the constructed instance, rather than an instance method, except that it would not be possible to write extension methods to extend a fixed-length collection type so that collection literals can be used with it. This is a concession to the language's current lack of static extension methods.\n\n### Dictionary literals discussion\n\nWe liked the dictionary literal having the natural type `Dictionary<TKey, TValue>`, assuming `List<T>` as the natural type of a collection literal. It should feel parallel, so if the collection literal natural type was `ImmutableArray<T>`, it would be `ImmutableDictionary<TKey, TValue>`. We noted that there are not many framework types to choose between, unlike with collection literals.\n\n#### Syntactic options\n\nWe considered the following syntaxes for dictionary literals:\n\n```cs\nvar dict1 = { \"key1\": \"value1\", \"key2\": \"value2\" };\n\nvar dict2 = [ \"key1\": \"value1\", \"key2\": \"value2\" ];\n\nvar dict3 = [ [\"key1\"] = \"value1\", [\"key2\"] = \"value2\" ];\n\nvar dict4 = [ \"key1\" => \"value1\", \"key2\" => \"value2\" ];\n```\n\nOf the square bracket syntaxes, we agreed on the `dict2` style as being minimalist and the most familiar coming from other languages.\n\n- Curly braces are too overloaded. We don’t this to be visually confusing with block expressions or impede that space.\n- `[ [\"a\"] =`... starts out visually similar to a collection literal containing another collection literal.\n- Fat arrows could make it confusing to disambiguate lists of lambdas.\n\nLike with collection literals, we like the idea of making pattern matching resemble construction:\n\n```cs\nvar dict2 = [ \"key1\": \"value1\", \"key2\": \"value2\" ];\n\nif (dict5 is [ \"key1\": var value ])\n{\n```\n\nThere’s an existing community proposal for indexer patterns which would combine indexer access with property patterns: <https://github.com/dotnet/csharplang/discussions/4889>. This would be more general than dictionaries but would include dictionaries. The community proposal has the syntax `{ [a]: b }` and would enable patterns such as `{ a.b: c, [d].e: f }`, and so on. This would suggest yet another syntax permutation:\n\n```cs\nvar dict5 = { [\"key1\"] = \"value1\", [\"key2\"] = \"value2\" };\n\nif (dict5 is { [\"key1\"]: var value })\n{\n```\n\nOpen question: which way do we resolve our favored construction syntax with indexer pattern matching syntax?\n\nThe two existing dictionary initialization syntaxes have different behaviors for duplicate keys. One calls `Add`, which typically throws if the key already exists: `{ { a, b }, { a, c } }` The other calls the indexer setter, which typically overwrites if the key already exists: `{ [a] = b, [a] = c }`. This raises the question of whether dictionary literals should replace or throw. We leaned towards replacing rather than throwing. The throw behavior could annoyingly block a valid and intended scenario. Also, dictionary spread can be seen as a cousin of `with` expressions: `obj with { prop = a }` is a lot like `[..dict, prop: a]`.\n\nSwift has `[:]` to denote an empty dictionary. It would be rare to find this useful for C# dictionary literals: `[]` would also denote an empty dictionary when the target type is a dictionary type rather than a collection type, and neither `[]` nor `[:]` could be used when there is no target type, e.g. `var x = [];`. One place where `[:]` could be useful is to disambiguate between overloads when there is a collection type in one overload and a dictionary type in another overload. We doubt this motivates the syntax; there are other ways to disambiguate.\n\n#### Dictionary literal implementation strategy\n\nWhile planning dictionary literals, we need to propose a strategy for how they will initialize dictionaries. Extrapolating from the approach in the collection literals strategy provided a starting point:\n\n```cs\n// Or ReadOnlySpan<>, just like with collection literals\ninit void Init(KeyValuePair<TKey, TValue>[] values)\n```\n\nEven without a new `Init(...)` method, a similar extrapolation could work for mutable dictionaries by calling the `Add` method.\n\nLike with collection literals, we should make sure the runtime performance of dictionary literals is on par with existing methods of construction.\n\n## Future agenda\n\nThe next meeting is currently planned for October 14th, 2022.\n\n- Continuing on dictionary literals\n- Implementation strategies\n  - Initializing fixed-length collections from unknown-length collection literals\n  - Unresolved question 2 from the proposal:\n    > Stack allocations for huge collections might blow the stack. Should the compiler have a heuristic for placing this data on the heap? Should the language be unspecified to allow for this flexibility? We should follow what the spec/impl does for params `Span<T>`.\n- If there is time, exploring other open questions from the proposal\n"
  },
  {
    "path": "meetings/working-groups/collection-literals/CL-2022-10-14.md",
    "content": "# Collection literals working group meeting for October 14th, 2022\n\nThis is the second meeting of the collection literals working group. The proposal is currently located at <https://github.com/dotnet/csharplang/issues/5354>.\n\n## Agenda\n\n- `List<>`/`Dictionary<,>`/`KeyValuePair<,>` being first-class concepts\n- Use of `Enumerable.TryGetNonEnumeratedCount`\n- Known-length and unknown-length spreads not affecting what the user sees\n- Calling `.Count` along with each spread element evaluation or in a later phase\n- `k: v` dictionary element equivalent to KeyValuePair expression element\n- Natural typing with empty literals\n- Unsupported cases\n- Allowing target-typing to interfaces\n- Implementation strategy for dictionary spreads\n- Type parameters of the natural type for dictionary literals\n\n### Dictionaries\n\nPositive reception for tying `k: v` syntax to KeyValuePair and allowing dictionary elements alongside expression elements. If there's a typo and a colon is accidentally added or removed, we think the compiler can create a helpful diagnostic.\n\nWhat should we do if someone tries to use dictionary elements to call collection indexers?\n\n```cs\nList<string> list = [0: \"first\", 1: \"second\"];\n```\n\nWe could identify if the indexer being called is mapped to a list interface indexer and not a dictionary interface indexer. We should think about this more because we'd want to consider graph-like collections.\n\nTo determine the type parameters for the `Dictionary<,>` natural type, we definitely need both expressions (from the dictionary elements) and types (from the expression elements and spread elements) as inputs to the best common type algorithm.\n\nWe want `[..dict1, ..dict2]` to produce a dictionary, so the target type will be a dictionary when the expression elements and spread elements bring in only KeyValuePair instances even if there is no dictionary element `k: v`.\n\nWe agreed that there should be no natural type for `[k: v, someObject]`. If there is a dictionary element and don't get a dictionary, that's very confusing. If you want a list, you can explicitly type as `List<object>` which will then contain the KeyValuePair created by `k: v`.\n\n## Codegen efficiency\n\nWe like using `Enumerable.TryGetNonEnumeratedCount` in the codegen when available. We aren't sure where to draw the line in specifying improvements like this in the spec instead of leaving it up to the compiler, which the spec already invites to take initiative in improving codegen for runtime performance.\n\nWe think it will be imperative for span users that codegen uses stackalloc when target-typing `Span<T>`. Is it acceptable for there to be resizes (`TryGetNonEnumeratedCount` returns false)? We want input from experts in these areas about how to make good use of stack and heap memory for these use cases, and whether to allow spreads of known or unknown length when target-typing to spans. If we disallow spreads when target-typing to spans, users can create an array using `(T[])[...]` to obtain a heap-allocated span.\n\nPositive reception for the general concept that users won't get errors that force them to understand known-length versus unknown-length spreads when the target type is fixed-length and doesn't have a `Construct` method. We can always generate code to make this work.\n\nHesitation around not being visible enough when unknown-length spreads are resulting in resize reallocations. However, analyzers can show when this happens, either any spread or ones that don't have a known length. It feels important to be able to spread unknown-length enumerables into arrays or immutable collections. Roslyn code does this commonly and it would be unfortunate not to be able to use collection literals for this.\n\nCollection literals should be thing that gets you the best performance rather than everyone figuring it out by hand. Roslyn wouldn't want to give up its ArrayBuilder helper, but maybe the compiler can implement private pools in its codegen for collection literals. This would require a robust codegen strategy, but but we like that. The codegen strategy could improve over time. The yearly .NET performance blog post could say, \"Are you using collection literals? Now your code is faster!\"\n\n## Other discussion\n\nWe don't want users to be surprised at later spread elements having been evaluated if calling `.Count` on an earlier spread element throws an exception. However, this is necessarily the case anyway if an exception is thrown during enumeration. We decided to table this for now.\n\n`[]` should have a special type, similar to how the null literal has a null type, which allows it to participate in things such as conditional expressions or lists of lists. We'll work on speccing this. We'd like to see if we can make `var list = cond ? [str] : [obj];` work too.\n\nLet's reoutline the spec so nuggets of reasoning aren't buried. We want to invest in realistic examples before presenting at the LDM too.\n\n## Future agenda\n\nThe next meeting is currently planned for October 21st, 2022. We will discuss remaining unresolved questions from the spec:\n\n- Immediate indexing into a collection literal\n- Use of AddRange or CopyTo when available\n- Use of `Add(KeyValuePair<K, V>)` when the collection is a dictionary\n- Allowing spreads when target-typing to spans and which kinds (requiring intermediate resizes or not)\n- Stackalloc and spans\n"
  },
  {
    "path": "meetings/working-groups/collection-literals/CL-2022-10-21.md",
    "content": "# Collection literals working group meeting for October 21st, 2022\n\nThis is the third meeting of the collection literals working group. The proposal is currently located at [#5354](https://github.com/dotnet/csharplang/issues/5354).\n\n## Agenda\n\n* `Span<T>` and stack allocation\n* Preliminary review of collection literal speclet\n\n---\n\nSupporting `Span<T>` (and `ReadOnlySpan<T>`) is considered very important for completeness for the feature.  Stack allocation of data (using `stackalloc`) is also considered highly desirable for the ability to avoid incurring a GC cost, including avoiding overhead when the literal itself isn't observed but only its elements are.\n\nHowever, stack allocation is very dangerous as well.  It can trivially cause stack explosions when not used carefully.\n\nIt turns out this space is being heavily examined in the [`params span`](https://github.com/dotnet/csharplang/blob/main/proposals/params-span.md) proposal.  We strongly believe that we would want the following to be equivalent:\n\n```c#\nvoid M(params ReadOnlySpan<int> values);\nM(1, 2, 3, 4);   // as params span\nM([1, 2, 3, 4]); // as direct span\n```\n\nAs such, our position is to align with whatever the `params span` working group comes up with for using spans and `stackalloc`.  Currently, that spec says that the span:\n\n> will result in an array T[] created on the stack if the params array is within limits (if any) set by the compiler. Otherwise the array will be allocated on the heap.\n\nFollowing the same approach for collection literals would then always allow a literal to construct a `Span<T>`, albeit sometimes using stack allocation, and sometimes heap allocation.  We know that there will be some users and some use cases where this is unpalatable.  For example, code which wishes to use a `Span<T>` knowing that it will *only* stack-allocate.  To that end, we expect the compiler to issue *hidden* diagnostics (a capability already supported today) when such a collection literal might initialize a span using a heap allocation.  Concerned users would then enable a warning or error for that diagnostic, and could block any cases which the compiler doesn't guarantee will be on the stack.\n\nImportantly, we do not anticipate that stack allocating means a *direct translation* of a *collection literal expression* to `stackalloc`.  For example, given:\n\n```c#\nforeach (...)\n{\n   Span<T> values = [GetA(), GetB(), GetC()];\n   // do things with values\n}\n```\n\na simplistic translation to:\n\n```c#\nforeach (...)\n{\n   Span<T> values = stackalloc T[3];\n```\n\nwould be undesirable.  This would grow the stack on each iteration of the loop, easily leading to a blowup at runtime.  The compiler is allowed to translate that using `stackalloc` however it wants, as long as the `Span` meaning stays the same and [`span-safety`](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-7.2/span-safety.md) is maintained.  For example, it can translate the above to:\n\n```c#\nSpan<int> __buffer = stackalloc int[3];\nforeach (...)\n{\n    __buffer[0] = GetA();\n    __buffer[1] = GetB();\n    __buffer[2] = GetC();\n    Span<int> values = __buffer;\n    // do things with span.  It would likely be appropriate to clear __buffer when the scope ends.\n}\n```\n\nThis approach ensures that the stack does not grow in an unbounded fashion, though it may not be possible in all collection-literal cases.  This would incur a cost even if the loop was never taken.  But it feels absolutely more desirable than incurring growing for the much more common cases where the loop iterates multiple times.\n\nIf the compiler decides to allocate on the heap, the translation for `Span<T>` is simply:\n\n```c#\nT[] __array = [...]; // using existing rules\nSpan<T> __result = __array;\n```\n\n---\n\nA preliminary review of the spec was performed with another LDM member.  The purpose of the review was to get an early read on how the spec is shaping up, and how the decisions of the working group feel against the backdrop of the philosophy and history of C#.  Reviews around the intuitions behind constructibility, convertibility, the type system, etc. were performed, including whether the concepts matched C# so far and whether the descriptions so far could easily translate into the actual rules needed for the specification.  The review was highly positive, with understanding and approval of the decisions of the working group so far, and of what collection literals both aim to support and not support.\n\nAn entire topic was discovered that we have not considered so far: how collection literals operate with generic type inference.  Specifically, the feature does not currently support:\n\n```c#\nvoid M<T>(T[] values);\nM([1, 2, 3]);\n```\n\nHowever, there was strong agreement that this should work and that `T` should be inferrable to `int` here.  We believe the rules to support this should not be too difficult, but it certainly gets interesting with more complex cases like the following:\n\n```c#\nvoid M<T>(ImmutableArray<T> values);\nM([1, 2, 3]);\n```\n\nFor inference, we would likely need to see that `ImmutableArray<T>` was *constructible* through the `init void Construct(T[] values)` method.  Inference would then have to continue with `T[]` and `[1, 2, 3]`.  That *base case* of inference would find that `T` was `int` which would flow out all the way to the top level inference.\n\nThis topic has been added to the agenda for the working group to work through.\n"
  },
  {
    "path": "meetings/working-groups/collection-literals/CL-2023-04-05.md",
    "content": "# Collection literals working group meeting for April 4, 2023\n\n## Agenda\n\n* Allow efficient construction of collections that are typically represented as arrays, particularly `ImmutableArray<T>`.\n\n## Discussion\n\nWe discussed possible _construction method_ patterns that would allow the compiler to write directly to the underlying storage for collections such as `ImmutableArray<T>` and `List<T>`, and avoid extra allocations or copying in cases where the collection has a _known length_.\n\nThere were two promising approaches that provide equivalent capability, with the difference of whether the underlying storage is allocated by the caller or by the collection.\n\n### Pass ownership of array\nOne possible approach is a _construction method_ that takes an array as an argument and uses that array directly as the underlying storage of the collection, with the caller passing ownership of the array to the collection instance.\n\nFor instance, given the following method for creating an `ImmutableArray<T>`:\n```csharp\n// Create ImmutableArray<T> using the array as the underlying storage.\npublic static ImmutableArray<T> AsImmutableArray<T>(T[] array)\n{\n    // ...\n}\n```\n\nThe compiler could translate `ImmutableArray<T> result = [x, ..e, y];` to:\n```csharp\nT[] __array = new T[e.Count + 2];\n\nint __i = 0;\n__array[__i++] = x;\nforeach (T __t in e)\n    __array[__i++] = __t;\n__array[__i++] = y;\n\nImmutableArray<T> result = AsImmutableArray(__array);\n```\n\n### Write directly to storage span\nAn alternative is a _construction method_ that creates a collection of a given size and returns the collection _and_ a span that refers to the underlying storage, and the caller populates the collection using the span.\n\nFor instance, given the following method for creating a `ImmutableArray<T>`:\n```csharp\n// Create ImmutableArray<T> and return a span to the underlying storage.\npublic static ImmutableArray<T> CreateImmutableArray<T>(int size, out Span<T> span)\n{\n    // ...\n}\n```\n\nThe compiler could translate `ImmutableArray<T> result = [x, ..e, y];` to:\n```csharp\nSpan<T> __span;\nImmutableArray<T> result = CreateImmutableArray(e.Count + 2, out __span);\n\nint __i = 0;\n__span[__i++] = x;\nforeach (T __t in e)\n    __span[__i++] = __t;\n__span[__i++] = y;\n```\n\n### Runtime libraries\n\nThe BCL could provide _construction methods_ for `ImmutableArray<T>` and `List<T>`, and perhaps a few additional collection types where the underlying storage can be represented as a span.\n\nThe methods could be implemented in `System.Runtime.InteropServices` or `System.Runtime.CompilerServices` to indicate the intended use is from compilers or interop.\n\n### Compiler use\nThe compiler will use a _construction method_ for the corresponding collection type when creating a collection of _known length_.\n\nWhen creating collections of _unknown length_, using a _construction method_ may not provide an advantage over existing alternatives since either approach may require resizing and reallocating during construction.\n\n_What if the collection literal has a known length but the resulting collection instance is mutable? Is there an advantage to providing an initial length?_\n\n_Construction methods_ could be registered with attributes on the _collection type_.\n\nFor instance, an attribute could identify the construction method by containing type and method name.\n```csharp\n[CollectionLiteralConstruction(typeof(ImmutableCollections), \"AsImmutableArray\")]\npublic struct ImmutableArray<T>\n{\n    // ...\n}\n\npublic static class ImmutableCollections\n{\n    public static ImmutableArray<T> AsImmutableArray<T>(T[] array)\n    {\n        // ...\n    }\n}\n```\n\nA collection type should have at most one _construction method_. Most collection types will have none.\n"
  },
  {
    "path": "meetings/working-groups/collection-literals/CL-2023-04-28.md",
    "content": "# Collection literals working group meeting for April 28, 2023\n\n## Agenda\n\n* Should a collection literal have a *natural type*? If so, what type?\n* Infer the collection type from spread elements?\n* Should dictionaries use overwrite or add semantics?\n\n## Discussion\n\n### Should a collection literal have a natural type? If so, what type?\n[natural-type]: #natural-type\n\nWithout a *natural type*, a collection literal can only be used when *target typed* to a *constructible collection type*.\n\nGiven the *best common type* `T` of the elements, the choices for *natural type* include:\n* `T[]`\n* `List<T>`\n* `Span<T>`\n* `ReadOnlySpan<T>`\n* `ImmutableArray<T>`\n\nWe ruled out `Span<T>` and `ReadOnlySpan<T>` because `ref struct` types cannot be used in `async` contexts.\nAlso, `ref struct` types cannot implement interfaces, so spans cannot be used as `IEnumerable<T>`.\n\nOf the remaining types, `List<T>` is perhaps the most flexible and may satisfy more scenarios than `T[]` or `ImmutableArray<T>`.\n\nAlso, we speculate that `List<T>` is commonly used today in method bodies, so having `List<T>` as the *natural type* would be familiar and would align with existing code.\n\nAnother consideration is consistency between the *natural types* for non-dictionary and dictionary collection literals. The most obvious choice for dictionaries is `Dictionary<TKey, TValue>` which is consistent with `List<T>`.\n\nHowever, different collection types are appropriate for different scenarios.\n\nIf `List<T>` is used as the *natural type* for a particular variable, but `Span<T>` or `T[]` could have been used explicitly instead, the choice of `List<T>` may be more expensive.\n\n`List<T>` is mutable, even though it may be uncommon to mutate a collection that was created with an explicit initializer. That means consumers that want immutability will need to use an explicit type or wrap the instance.\n\nThe alternative is *no natural type*.\n\nCollection literals are not a simple replacement for existing collection construction.\nPreviously, constructing and populating a collection required handling details of capacity, allocations, indexing vs `Add()` vs `AddRange()`, etc., and using `List<T>` may have been simpler or more familiar than alternative collection types.\nCollection literals address that by providing a common syntax that can be used for a range of collection types.\nConsumers can now choose the optimal collection type for each scenario, and requiring the developer to specify the collection type explicitly helps that.\n\nSome other alternatives:\n* Add support for *natural type* later.\n* Support *natural type* behind a *feature flag*.\n* Support *natural type* now and also include an analyzer that warns for `var` with collection literals for performance reasons.\n* Support `var` element types, as suggested in a recent LDM: `List<var>`, `var[]`, `Dictionary<var, var>`, etc.\n\n#### Conclusion\nNo conclusion, although the most likely options for *natural type* may be `List<T>` or *no natural type*.\n\n### Infer the collection type from spread elements?\n[infer-from-spread]: #infer-from-spread\n\nShould the collection type of a collection literal be inferred from the collection types of any spread elements?\n```csharp\nImmutableArray<int> a = [1, 2, 3];\nvar b = [..a, 4]; // ImmutableArray<int> b\n```\n\nWhat if spread elements have distinct types, such as `HashSet<object>` and `HashSet<string>`, or distinct comparers?\n\nWhat if the spread element type is an interface, such as `IEnumerable<T>` or `IReadOnlyDictionary<TKey, TValue>`, or not a *constructible collection type*?\n\nThere is the potential for breaking changes to `var` collections when the types of spread elements change:\n* between an interface and a concrete collection type, or\n* between a constructible and non-constructible collection, by adding or removing a public constructor.\n\n#### Conclusion\nRequires further discussion.\n\n### Should dictionaries use overwrite or add semantics?\n[overwrite-or-add]: #overwrite-or-add\n\nShould construction of a dictionary from a collection with duplicates use overwrite or add (and throw) semantics?\n\nThere are valid scenarios for both.\nThe concern is when combining collections where the collection types use distinct semantics.\n\nThere is a similar issue around comparers.\nConsider the non-dictionary case when combining two `HashSet<T>` instances that use different comparers. There is potential for data loss in the resulting collection.\n\n#### Conclusion\nRequires further discussion."
  },
  {
    "path": "meetings/working-groups/collection-literals/CL-2023-05-10.md",
    "content": "# Collection literals working group meeting for May 10, 2023\n\n## Agenda\n\n* Discuss new options for natural typing of collection literals\n\n## Discussion\n\nComing out of the previous full LDM on collection literals ([notes](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-05-03.md#collection-literal-natural-type)), we wanted to explore more options for attaining both flexible usage and ideal performance with a natural type. Two alternatives were presented which had been fleshed out with potential designs.\n\n### Option 1: anonymous/unspeakable 'collection builder' type\n\nThis approach gives the natural type _builder_ semantics with a set of APIs such as `Add` and `AddRange`:\n\n```cs\nvar collection = [1, 2, 3];\ncollection.Remove(2);\nTakesImmutableArray(collection);\n```\n\nThe natural type would be anonymous. The compiler would realize the collection by directly initializing an `ImmutableArray<T>` in the example above, skipping any intermediate bookkeeping that is statically possible to skip, so that the best performance is achieved.\n\nThe extra builder concept changes how users would think about naturally-typed collection literals. This could make the mental model more complex. An explicit 'build' called out somehow in syntax might even be preferable over passing the variable implicitly as the targeted collection type.\n\nWe briefly considered whether there would be merits to making the type speakable, a new framework collection builder type that could be passed around. It would be yet another collection/builder type to teach people about. If the new builder type was itself capable of doing the building on the stack, it wouldn't be able to be captured or used across awaits. It would also be an advanced type which we wouldn't want normal users to be working with every time they use a naturally-typed collection literal.\n\n#### Conclusion\n\nThe working group had some hesitations with this approach.\n\n### Option 2: optimize away `List<T>`\n\nUnder this option, the natural type of collection literals would be `List<T>` as previously proposed. A `List<T>` instance would not actually be created if a different backing storage performs better and the difference is not observable by the code.\n\nThese performance benefits would extend to all existing code that creates a new `List<T>` instance using syntax. No `List<T>` would be created in code such as the following; instead, this would be lowered to `stackalloc` or similar:\n\n```cs\nList<int> list = new List<int> { 1, 2 };\nforeach (var item in list) // Only usage of 'list'\n{\n}\n```\n\nTuples are one example of prior art, where the compiler assumes implementations of System.ValueTuple to be well-behaved and skips creating them altogether in some cases when tuple syntax is used.\n\n#### Conclusion\n\nThe working group was interested in pursuing this approach.\n\nOne hesitation is that it might be hard to reason about when the optimizations are happening, and when you're actually getting a `List<T>` at runtime. Are hidden diagnostics and analyzers enough? We will think about this further.\n\n### Forward inference of the element type\n\nWe considered whether it would be advantageous to match the builder pattern seen in other languages without explicitly typing the collection variable:\n\n```cs\n// Infers the element type to be 'int' by looking forward\n// to the Add call.\nvar collection = [];\ncollection.Add(1);\n```\n\nBuilding a collection by starting without items is common, and this would enable users to use `var` instead of `List<int>` or creating some other builder.\n\nChoosing the element type by examining calls and usages of the collection itself could result in errors which are hard for users to figure out. It would be similar to lambda return type inference. Lambda return type inference usually works well, but inference errors while editing can sometimes create really confusing diagnostics far away. Would we be making this poor kind of experience more common?\n\n#### Conclusion\n\nThe working group was reluctant to embrace forward inference of element types unless forward inference became available for variables in a more general way, either by inferring generic type arguments as in `Service<_> s = ...` or even embracing forward inference completely by allowing `var s;`.\n\n### Conversions from `List<T>` to other collections\n\nOne of the things that the builder option would have done is allow a naturally-typed collection to be passed as a specific collection type later. If we go with option 2 instead, would we want to retain this ability by allowing `List<T>` to implicitly or maybe explicitly convert to any other collection type?\n\n```cs\nvar collection = [1, 2];\nTakesImmutableArray(collection); // Or Span\n```\n\n#### Conclusion\n\nThe working group leaned toward doing nothing special for implicit or explicit conversions from `List<T>`, and having the above code fail to compile.\n\n## Next steps\n\nWe will delve into option 2.\n"
  },
  {
    "path": "meetings/working-groups/collection-literals/CL-2023-05-26.md",
    "content": "# Collection literals working group meeting for May 26, 2023\n\n## Agenda\n\n* Codegen patterns and APIs for efficient construction\n* Open questions on dictionary literals\n* Cut line for C# 12\n\n## Discussion\n\n### Capacity of constructed collections\n\nIf an exact length is able to be calculated for the constructed collection, the capacity could be set ahead of time to avoid resizing the backing storage of the collection. But if the constructed collection escapes outside the method body, adding a single item to the collection after that would trigger a resize to double the backing storage size.\n\nPeople will be able to write better code by hand than the compiler can generate if they have outside knowledge of the eventual state of the collection during its life past the construction of the collection literal. This would be a caveat to a statement about the collection literals feature generating optimal code. This is fine; the compiler can strike a good balance, and people can drop down to manual construction of the collection if they need more control over the initial capacity.\n\nWhen an exact count is known for a collection literal but the compiler can't prove that it is not potentially resized later, or when only a minimum count is known for a collection literal, the compiler could for example set the initial capacity to the best-fitting power of two. This would skip some early resizes while also amortizing resizes that could happen if the collection is modified after the collection literal is created.\n\n### AddRange and boxing\n\nWhen a struct-typed collection is spread, codegen could call `AddRange(IEnumerable<T>)` on the collection being constructed. This would cause the collection being spread to be boxed. To avoid boxing, codegen could loop over the spread collection and call `Add(T)` repeatedly on the collection being constructed.\n\nThis would work fine when the constructed collection has a writeable Capacity property because codegen could set the capacity before calling `Add(T)` in a loop. However, if there's no writeable Capacity property, we're better off calling `AddRange` and boxing, because the `AddRange` implementation is the only way to intelligently avoid intermediate resizes. (In this situation, the thing being spread has a known length but the collection literal as a whole has an unknown length due to an earlier spread.)\n\n#### Conclusion (AddRange and boxing)\n\nStick with building using Add and AddRange. This is good enough for 95% of customers. Allow the compiler to special-case codegen for widely-used collections to improve performance.\n\nThe compiler should prefer calling `AddRange(ReadOnlySpan<T>)` if such a method exists and the thing being spread is a span or exposes a span.\n\n### Construction API pattern\n\nThe ideal API for constructing collections with contiguous backing storage is to pass the capacity and receive a span to the backing storage. The collection could be passed back using an `out` parameter to enable overloading on collection type.\n\nThe type parameter to use when calling the creation method could be the iteration type of the collection being constructed.\n\n```cs\n[CollectionLiteralBuilder(\n    typeof(CollectionsMarshal),\n    nameof(CollectionsMarshal.CreateUnsafe))]\npublic class MyCollection<T> : IEnumerable<T> { }\n\npublic static class CollectionsMarshal\n{\n    public static void CreateUnsafe<T>(\n        int capacity,\n        out MyCollection<T> collection,\n        out Span<T> storage);\n\n    public static void CreateUnsafe<T>(\n        int capacity,\n        out List<T> collection,\n        out Span<T> storage);\n}\n```\n\nThe reverse API pattern (passing a span to the collection rather than receiving one) would enable the construction of collections that have noncontiguous backing storage and do not have mutating Add/AddRange methods, such as ImmutableDictionary.\n\nThis would allow the use of existing Create methods in the BCL:\n\n```cs\n[CollectionLiteralBuilder(\n    typeof(MyCollection),\n    nameof(MyCollection.Create))]\npublic class MyCollection<T> : IEnumerable<T> { }\n\npublic static class MyCollection\n{\n    public static MyCollection<T> Create<T>(ReadOnlySpan<T> elements);\n}\n```\n\n#### Conclusion (construction API pattern)\n\nUse an attribute to point to a creation method similar to the code samples above. If this attribute is present, prefer it over generating Add/AddRange calls.\n\nThis will need to go through API review. If we don't ship this general facility in C# 12, special-case access to the backing spans of List and ImmutableArray anyway for the sake of performance.\n\n### Dictionary sigils\n\nIn a previous full LDM, some folks didn't like the idea that `[..dict1, ..dict2]` would create a dictionary (unless the target type is a dictionary type). A merged dictionary could change the count and enumerated order of the key-value pairs. Similar concerns apply to `[kvp1, kvp2, kvp3]`.\n\nThe working group doesn't expect these syntaxes to be commonly desired for producing dictionaries. We expect at least one `k: v` element to be present in literals where the user wants a dictionary and the target type is not already a dictionary type. Merging two dictionaries to create a new dictionary, and doing nothing further, is not a scenario we think comes up that often.\n\nSo, is there a place for a sigil to override this, where syntax similar to `[:, ..dict1, ..dict2]` or `[:, kvp1, kvp2]` causes a dictionary to be created instead of a list of key-value pairs?\n\nAn existing way to override this would be `[..dict1, ..dict2].ToDictionary()`. This is something which users may do anyway to override the natural type in other situations, such as `var x = [a, b].ToImmutableArray();`.\n\nThere's an open question about whether the natural type is influenced by the collection types of spread collections. Depending on the resolution, `[..dict1, ..dict2]` may create a dictionary while `[..listOfKvps1, ..listOfKvps2]` does not. A dictionary sigil would then be addressing a rarer set of scenarios.\n\n#### Conclusion (dictionary sigils)\n\nThe working group doesn't find the sigil use cases compelling, and it can be added later.\n\n### Cut line for C# 12\n\nThe working group feels good about shipping these features in C# 12:\n\n* Target-typing to core collections and collections which support classic collection initializers\n* An opt-in API construction pattern to enable 1️⃣ target-typing to other collections and 2️⃣ improving performance over classic collection initializers\n* Spreads\n* Dictionary literals\n\nWe'd like this in C# 12, but we'd rather let this slip to C# 13 than anything in the previous list:\n\n* Natural type for non-empty literals\n  * We think performance concerns about `List<T>` have a great resolution after input from the runtime on the \"optimize away `List<T>`\" strategy.\n  * Design discussion is still needed. For example, does the collection type of a spread collection affect the natural type of the collection literal?\n\nNot interested in pursuing for C# 12:\n\n* Natural type for empty literals\n  * This requires forward-looking type inference.\n\n## Next steps\n\nWe will present takeaways of recent working group meetings in a full language design meeting and get feedback on those and on some open questions.\n"
  },
  {
    "path": "meetings/working-groups/collection-literals/CL-2023-06-12.md",
    "content": "# Collection literals working group meeting for June 12, 2023\n\n## Agenda\n\n* API shape for BCL collections to opt-into collection literals support.\n\n## Discussion\n\nLDM and Runtime members met and discussed the shapes we think we'll want in the runtime to allow a type to either opt into collection-literals support entirely, or to opt into an extremely efficient approach to constructing an instance of itself.\n\nNote: for the following discussion, the code shown is a rough approximation of what we think is needed.  Exact naming, order of arguments, `return` vs `out` discussion will happen later.\n\nAll the approaches require the following attribute to be defined:\n\n```c#\n[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Struct))\npublic sealed class CollectionBuilderAttribute(Type factoryType, string methodName) : System.Attribute\n{\n    public readonly Type FactoryType;\n    public readonly string MethodName;\n}\n```\n\nWhen present on a type `T`, this identifies a static factory method `MethodName` found on type `FactoryType` which can be used to construct an instance of `T`. Several factory shapes will be supported.  Note: The type `T` and the `FactoryType` are allowed to be the same type.  These shapes may also be expanded upon in the future if motivating scenarios exist for them.\n\n### Shape 1: `ReadOnlySpan<T>` as input\n\nThe first shape we support is the following:\n\n```c#\n[CollectionBuilder(typeof(ImmutableHashSet), \"Create\")]\npublic class ImmutableHashSet<T> { /*...*/ }\n\npublic static class ImmutableHashSet\n{\n    public static ImmutableHashSet<T> Create<T>(ReadOnlySpan<T> values);\n}\n```\n\nHere, the factory method takes a `ReadOnlySpan` of values and returns an instance of the final collection.  The compiler would then translate in the following fashion:\n\n```c#\nImmutableHashSet<int> values = [1, 2, 3];\n\n// translates to:\nReadOnlySpan<int> __values = [1, 2, 3];\nImmutableHashSet<int> values = ImmutableHashSet.Create<int>(__values);\n```\n\nThis pattern will allow pointing at methods that already exist for this purpose, as well as allowing the runtime to add new methods to existing types to allow them to be created from spans.  A similar shape that we want to support is practically the same as the above, except that the factory method can be a constructor of the type.  Continuing the example above, that would be:\n\n```c#\n[CollectionBuilder(typeof(ImmutableHashSet<>), \".ctor\")]\npublic class ImmutableHashSet<T>\n{\n    public ImmutableHashSet(ReadOnlySpan<T> values);\n}\n\n// code:\nImmutableHashSet<int> values = [1, 2, 3];\n\n// translates to:\nReadOnlySpan<int> __values = [1, 2, 3];\nImmutableHashSet<int> values = new ImmutableHashSet<int>(__values);\n```\n\n#### Shape 1 consequences\n\nThe above approach is desired by the runtime so they can add overloads to their existing construction methods that allow the more efficient use of spans over more expensive collection types (arrays, IEnumerables, etc.).  However, this raises a problem given that these types normally have existing construction methods that take an `IEnumerable<T>`.  Consider, for example:\n\n```c#\npublic class HashSet<T>\n{\n    // existing constructor\n    public HashSet(IEnumerable<T> values);\n\n    // newly added\n    public HashSet(ReadOnlySpan<T> values);\n}\n\n// code:\nnew HashSet<int>(new int[] { 1, 2, 3 });\n```\n\nWith the rules of the language today, the above is ambiguous.  This is unfortunate as a prime reason to create Span overloads of methods is to allow for efficient options for callers that do not need to use the heap.  We believe this should be fixed, and the WG will present a proposal to the LDM to add overload resolution rules that consider Spans better than items in the inheritance chain for arrays.\n\n### Shape 2: Writable `Span<T>` or `T[]` storage.\n\nWhile the above pattern is good for collection types that own their own storage arrangement, it still involves producing the sequence one end, and then processing it to produce the final result within the factory method.  This is unnecessary overhead for a couple of very important, widely used, collections in the .NET BCL.  Specifically, `List<T>` and `ImmutableArray<T>`.  Both of these types are thin wrappers around a backing array, and it is highly desirable to just be able to write directly into that array without any overhead at all.  To that end, the above attribute can be used to point to a factory method with the following shape:\n\n```c#\n[CollectionBuilder(typeof(CollectionsMarshall), \"Create\")]\npublic struct ImmutableArray<T> { /*...*/ }\n\n// In System.Runtime.CompilerServices\npublic static class CollectionsMarshall\n{\n    public static Span<T> Create<T>(int capacity, out ImmutableArray<T> result); // or:\n    public static void Create<T>(int capacity, out ImmutableArray<T> result, out Span<T> storage);\n}\n\n// code:\nImmutableArray<string> values = [\"a\", \"b\", \"c\"];\n\n// translation:\nSpan<string> __storage = CollectionsMarshal.Create<string>(capacity: 3, out ImmutableArray<string> values);\n__storage[0] = \"a\";\n__storage[1] = \"b\";\n__storage[2] = \"c\";\n```\n\nDepending on how the compiler encodes constant information, this could also be a case where the data is stored in the read-only section of the dll and memcpy'ed to the destination.\n\nNote: the runtime already has methods that expose this data for high performance scenarios.  So this does not introduce any new safety concerns.  The methods are intentionally kept out of the way in the `CompilerServices` namespace to help indicate they are not for normal use, and should be treated very carefully.\n\n#### Shape 2 consequences\n\nThe above pattern will not work as efficiently in the case where the Span cannot be kept on the stack while evaluating the elements of the collection literal (for example, if there are `await` calls in the literal.  An alternative/complimentary approach that could be offered would be to have the following:\n\n```c#\npublic static class CollectionsMarshall\n{\n    public static void Create<T>(int capacity, out ImmutableArray<T> result, out Span<T> storage); // or:\n    public static void Create<T>(int capacity, out ImmutableArray<T> result, out T[] storage);\n}\n\n// code:\nImmutableArray<string> values = [await a, await b, await c];\n\n// translation:\nCollectionsMarshal.Create<string>(capacity: 3, out ImmutableArray<string> values, out string[] __storage);\n__storage[0] = await a;\n__storage[1] = await b;\n__storage[2] = await c;\n```\n\nDuring discussion, there was mixed feeling on this.  Sentiment indicated that it somehow felt worse to be handing out the array directly, where any consumer could then hold onto it forever.  While exposing the Span still gave access to all the data, it felt slightly more palatable as the Span was limited to the stack.  \n\nHowever, not having the array option means the compiler would have to translate like so:\n\n```c#\n// code:\nImmutableArray<string> values = [await a, await b, await c];\n\n// translation:\nstring[] __temp = new string[] { await a, await b, await c };\n\nCollectionsMarshal.Create<string>(capacity: 3, out ImmutableArray<string> values, out Span<string> __storage);\n__temp.CopyTo(__storage);\n```\n\nThis array seems wasteful, and could occur reasonably often in normal coding patterns.\n\n### Builders\n\nWG discussed if we should support a more flexible 'builder' pattern.  Both WG and Runtime felt this was unnecessary.  As per earlier decisions, it can also come in the future if there is a compelling case where they are needed.\n\n## Next steps\n\n1. LDM and Runtime to continue to drive the final shape for these APIs, and the work to get them into the runtime.\n2. WG to go back to LDM to request overload resolution tweaks for `ReadOnlySpan<T>` and `IEnumerable<T>`.\n"
  },
  {
    "path": "meetings/working-groups/collection-literals/CL-2023-06-26.md",
    "content": "# Collection literals working group meeting for June 26, 2023\n\n## Agenda\n\n* Collection expression lifetimes\n* BCL apis\n* Breaking changes\n* Extension method lookup\n* Syntactic disambiguation\n\n## Discussion\n\n### Collection expression lifetimes\n\nRelevant link: https://gist.github.com/jaredpar/a784f8963ce73613a0a696ef89a00d9a\n\nDiscussed the rules about spans produced by collection literals, and whether those are 'safe to return' from the 'current method'.\n\nConclusion.  We will accept the rules in the provided link. Specifically, spans from collection literals are *not* \"Safe to return from current method\". This has the benefit of allowing the compiler to potentially stackalloc these spans for very high efficiency code (including cases like `G([1, 2, 3])`).\n\nWhile the compiler is free to use stackallocs for these spans, it is not required to do so.  However, as some consumers *may* only want to allow collection literals when they will be stackalloc'ed we will ensure that the compiler emits a hidden-diagnostic if it heap allocs.  These consumers can set that diagnostic to be an error, blocking unwanted span heap allocations.  In those cases, they can manually stackalloc.\n\nUsers who want to be able to return those spans can do so by explicit conversion to an array.  e.g. `Span<int> s = (int[])[1, 2, 3];`. \n\n### BCL Apis\n\nBCL gave a status update on the work they have done.  Specifically: https://github.com/dotnet/runtime/pull/87945\n\nThis (merged) PR adds the pattern of an immutable collection type `C<T>` having a factory method `public static C<T> C.Create<T>(ReadOnlySpan<T> values);` to create the collection.  A soon to be added attribute (`CollectionBuilderAttribute`) will be added that will allow the language/compiler to find this factory method from a given collection type.\n\nWe do not plan any more BCL apis beyond this.  However, there are two key changes we will make in the compiler in terms of emit, to get even better codegen than what those above methods allow.  Specifically:\n\n1. while there is an `public static ImmutableArray<T> ImmutableArray.Create<T>(ReadOnlySpan<T> values);` method, the compiler will not call it.  Instead, it will sidestep it and use `ImmutableArray<T> ImmutableCollectionsMarshal.ToImmutableArray<T>(T[] values);` method.  This method passes ownership of the array *directly* to `ImmutableArray<T>` ensuring no overhead (no excess allocations *or* copying).\n\n2. while `List<T>` will already work with collection literals (due to it supporting collection-initializers) the compiler will emit new collection literal `List<T>'s` as:\n\n```c#\nList<int> list = [a, b, c]; // translates to:\n\nList<int> list = new List(capacity: 3);\nCollectionsMarshal.SetCount(list, 3);\nSpan<int> __storage = CollectionsMarshal.AsSpan(list);\n__storage[0] = a;\n__storage[1] = b;\n__storage[2] = c;\n```\n\nRule '1' will always apply for immutable arrays.  Rule '2' can apply depending on how complex it is for the compiler.  For example, if the code were `List<int> list] = [await a, await b, await c];` the compiler might choose to just emit this equivalently to `new List<int> { await a, await b, await c }` (i.e. equivalently to a collection initializer expression).\n\n### Breaking changes\n\nWe would like to update the language so that `(A)[B]` is *always* a cast of a collection literal, not an indexing expression of a trivial identifier expression.  This would apply to `(A)[B]` (trivial identifier), or `(A.B.C)[D]` (dotted identifier).  In both of these cases, if the user wanted indexing, it would be far more idiomatic to write this out as `A[B]` or `A.B.C[D]` (the parentheses are superfluous).\n\nTHe compelling case to want to make this a cast of a collection literal is:\n\n```c#\nusing CrazyArray = ImmutableArray<List<HashSet<int>>>; // i.e. some complex collection type\n\n// ...\nvar v1 = (CrazyArray)[a, b, c]; // really don't want to have to spell out the type in each location\nvar v2 = (CrazyArray)[x, y, z];\n```\n\nCurrently the prototype impl makes no breaks here and keeps parsing as it exists prior to this feature.\n\nAs this is a breaking change, we might want to combine it with the work on \"safe breaking changes\" being looked into.  However, we also think the chance of this impacting someone would be super small (though investigations would be necessary).  We want to get a read from LDM on if we should explore this fruther.\n\n### Extension method lookup\n\nWG believes it would be valuble for customers to be able to write:\n\n```c#\nstatic class Extensions\n{\n    public static ImmutableArray<T> AsImmutableArray<T>(this ImmutableArray<T> array) => array;\n}\n\nvoid M()\n{\n    var v = [complex, type, examples].AsImmutableArray();\n}\n```\n\nThis is because the alternative would be to have to write something like:\n\n```c#\n(ImmutableArray<Complex<Type<Examples[]>>)[complex, type, examples];\n```\n\nIn other words, the extension method approach would allow for type inference to make this much simpler and cleaner than having to fully specify all the types.  Working group believes (but needs to verify) that a simple extension (no pun intended) to 'extension method lookup' would make this work.  Specifically, while the collection type has no natural type currently (like `null`, a `lambda` or a `method group`) it could still trivially participate in extension method lookup and would work in cases like this.\n\nWe do, however, believe the value here is diminished if, say, the language adopts features like \"postfix cast\" and \"partial generic type inference\".  If those features make progress, you could write the above as:  ```[complex, type, examples].(ImmutableArray<_>)```.  This would be simple and clear.  \n\nWG also thinks that if we did add extension method support for the above, that we could consider doing the same for lambdas and method-groups.\n\n### Syntactic disambiguation update\n\nThe feature has some small syntactic ambiguities with both existing features, and features coming around at the same time.  Specifically:\n\nCase 1:\n```c#\na ? [b] ...   // is that:\n\n(a?[b])       // a conditional access expression, or:\na ? [b] : ... // a conditional expression\n```\n\nConclusion: we will preserve existing parsing for these.  So if it is a case where it would successfully parse as a conditional-access-expression, it will remain that way.  *However*, if trying that approach would end up failing, we will try again as a conditional-expression and accept that if it succeeds.  This means the following will work:\n\n```c#\nvar v1 = a ? [b] : c;\nvar v2 = [a ? [b] : c];\n```\n\nWhile this involves complex lookahead, we only need to apply it when parsing fails *and* we can see that there was a `?[` involved.  So costs should be minimal for mainline cases.  A PR for this is here: https://github.com/dotnet/roslyn/pull/68756\n\nCase2: \nThe collection literals feature *also* introduces its own ambiguity with: `[a ? [b] : c]` is that `[(a?[b]): c]` (a dictionary literal?), or `[a ? ([b]) : (c)]` a collection literal with a conditional-access in it.\n\nUnlike the above case, there is no back compat issue here as none of this code was legal before.  In this case, we choose an interpretation that prefers list-literals first, then dictionary literals.  So the above is a list-literal containing a conditional-access-expression.  If a dictionary-literal is preferred, the initial expression must be parenthesized.\n\nCase3:\nIn `[range1, ..x, range2]`, `..x` could be a spread-element or a range-expression.\n\nWG affirms this is always a spread-element.  This should be an extremely unlikely event.  And, if the user wants a range-expression they can write `0..x` or `(..x)`. \n"
  },
  {
    "path": "meetings/working-groups/collection-literals/CL-2023-07-26.md",
    "content": "# Collection literals working group meeting for July 26, 2023\n\n## Agenda\n\n* `[CollectionBuilder]` Create methods returning a derived/implementing type\n* Considering extension `GetEnumerator()` when determining element type\n* Inline array sizes to synthesize\n\n## Discussion\n\n### `[CollectionBuilder]` Create methods returning a derived/implementing type\n\nFor the BCL, this mainly concerns the `IImmutableXyz<T>` interfaces. The compiler will have its own rules for which concrete types to use when a collection expression targets certain interfaces such as `IReadOnlyList<T>`. If we don't allow `[CollectionBuilder]` to be placed on the `IImmutableXyz<T>` interfaces, they won't be able to be targeted by collection expressions.\n\nWe're lukewarm on the importance of the `IImmutableXyz<T>` interfaces themselves, but we don't feel great about blocking people from making their own interface type constructible using `[CollectionBuilder]`. It feels like a toe-stubbing situation, and the cost to the compiler to allow this is very low.\n\nThen if we do allow `[CollectionBuilder]` to be placed interface types, the runtime would go ahead with adding `[CollectionBuilder]` to the `IImmutableXyz<T>` interfaces so long as it would be valid for the attribute to point to the existing Create methods that return concrete types. For instance, `[CollectionBuilder]` on `IImmutableList<T>` would point to the Create method whose return type is the concrete `ImmutableList<T>` rather than the interface type. We would thus want to do both things together: allow `[CollectionBuilder]` on interface types, and allow the Create method to return a type which derives from or implements the attributed type.\n\n**Conclusion:** Ask at a language design meeting whether to allow `[CollectionBuilder]` on interface types. If the answer is yes, the runtime is only willing to make use of this if the attribute can point to Create methods whose return types are concrete implementing types rather than interface types.\n\n### Considering extension `GetEnumerator()` when determining element type\n\nThe spec currently says that the element type of a collection literal is the iteration type of the collection type. However, there's a downside to considering extension `GetEnumerator` methods: you can no longer tell whether the collection type is a valid target for a collection expression by looking at the collection type declaration itself. The iteration type of that collection type is dependent on the `using` directives where the collection expression is written because the `using` directives may or may not bring in a `GetEnumerator` extension method.\n\nThis makes it impossible for the compiler to provide a diagnostic for an obvious mistake where `[CollectionBuilder]` is applied to a type that declares no `GetEnumerator` method of its own. After all, a usage site could just happen to import an extension method which makes collection expressions compile when targeted to this collection type. If we rule this out by disallowing extension `GetEnumerator`, the situation becomes unequivocally invalid, and all diagnostics can be provided on the collection type declaration rather than the usages of collection expressions with that collection type.\n\n**Conclusion:** Do not consider extension `GetEnumerator` methods when determining the element type of a collection expression. Provide an error diagnostic if `[CollectionBuilder]` is applied to a type that doesn't declare its own `GetEnumerator` method.\n\n### Inline array sizes to synthesize\n\nThe current plan is to use [inline arrays](https://github.com/dotnet/csharplang/blob/main/proposals/inline-arrays.md) in the compiler-generated code. (`stackalloc` complicates codegen because the operation should be hoisted outside of loops. It also only works for unmanaged element types.)\n\nAn inline array requires a different type to be declared for each array length. If the BCL declares some well-known inline array types for certain array lengths, the compiler can use those, but array lengths not declared by the BCL require the compiler to generate types in the private implementation details of the assembly being compiled. A lot of inline array types could end up being generated per assembly which uses collection expressions.\n\nDo we want to try to cut down on the number of inline array types, for instance by only generating in powers of two and overallocating on the stack but slicing to the needed size? Also, should there be a cutoff where above a certain size, the heap is always used?\n\nThe performance downside of overallocating (using oversized inline arrays) is time spent zeroing memory. We don't want to leave performance on the table. The number of types being generated is not a concern. The compiler already generates large numbers of types of various fixed sizes for other features. If there are too many after all, the BCL will declare some of these.\n\nWe're not going to get it right on the first release. We can start simple, react to performance feedback from C# 12, and change the strategy as needed.\n\n**Conclusion:** When the element count is known at compile time, always use an exactly-sized inline array and never use the heap. When the element count can vary at runtime, always allocate on the heap.\n"
  },
  {
    "path": "meetings/working-groups/collection-literals/CL-2023-08-03.md",
    "content": "# Collection literals working group meeting for August 3, 2023\n\n## Agenda\n\n* Collection expression escape scope for ref-structs (like `ReadOnlySpan<T>`).\n* Confirm behavior of collection expressions and `ReadOnlySpan`s of blittable data.\n\n## Discussion\n\nThe purpose of the meeting was to discuss what semantics we would have in the language for a collection expression target-typed to a ref-struct.\n\nFirst, for simplicity and to aid by giving examples, we'll use `ReadOnlySpan<T>` to demonstrate the general problem space, the varying options, and the pros/cons of each option.  Second, all these cases deal with collection expression elements of *non-blittable-constant data* (e.g. `[a, b, c]` vs `[1, 2, 3]`).  Rules around the latter are covered at the end.\n\n\nToday, a user can write code like so:\n\n```c#\nReadOnlySpan<int> x1 = stackalloc int[] { a, b, c }; // stack allocated, local scope.\nReadOnlySpan<int> x2 = new int[] { a, b, c };        // heap allocated, global scope.\n```\n\nBased on how the variable is initialized, the language then dictates rules about how it can be used.  For example, with the above code it would be illegal to `return x1;` from the method (since it has local scope), while it would be fine to `return x2;`.  Variables without an initializer are assumed to have global scope.  So the following, for example, would be illegal:\n\n```c#\nReadOnlySpan<int> x3;              // global scope\nx3 = stackalloc int[] { a, b, c }; // illegal.  global scope now points at local data.\n```\n\nUnlike existing constructs, which clearly delineate whether they are on the stack or heap, a decision needs to be made as to what the following means:\n\n```c#\nReadOnlySpan<int> x4 = [a, b, c];\n```\n\nThe working group considered several options.\n\n### Option 1.  Stack-alloc'ed only if target has local-scope.\n\nThe first option considered was that a collection expression used with a `ReadOnlySpan<T>` would itself only be stack-alloc'ed if the span itself was known to be local scoped based on its declaration.   In other words, the following:\n\n```c#\nReadOnlySpan<int> x1 = [a, b, c];        // heap allocated, global scope.\nscoped ReadonlySpan<int> x2 = [a, b, c]; // stack allocated, local scope.\n\n// Less likely, but shown for completeness:\nReadOnlySpan<int> x3 = stackalloc int[] { d, e, f }; // stack allocated, local scope.\nx3 = [g, h, i];                                      // stack allocated.\n```\n\nThis has the positive that both heap and local allocations are possible, and choosing between them is as simple as adding `scoped` or not.  Unfortunately it has several major negatives the working group was quite dissatisfied with:\n\n1. We believe the *common* case for using spans with collection expressions will be for people wanting stack allocated data.  Having the default (non-`scoped`) syntax basically flips that and makes the common case more cluttered and less pleasant to work with.\n2. We believe the standard intuition for nearly all users (including experts in the low-level space) would be that the first line produces stack-allocated data.  After all, that's the most common reason to create locals of span types. Their belief would be that if they initialize with a collection expression, it will do the right thing.\n3. We believe that the first line would actually be a *large* \"pit of fail\" for users.  It would be very easy and attractive for customers to just take existing code, hear about collection expressions (including that it works for spans) and translate `stackalloc` code over to just using the collection expression, resulting in allocations that didn't exist before.\n4. We believe if we had this behavior, we would have to have a diagnostic (likely on by default) that warned the user of the heap allocation on 'x1' and to either:\n    1. suppress the diagnostic if they really wanted that, or\n    2. put an explicit cast (e.g. `(int[])[a, b, c]`) to indicate that they indeed did want this behavior, or\n    3. add the `scoped` modifier.\n\nAll in all, while this allowed for both cases to easily be distinguished with a simple modifier, everything about the defaults and behavior was flipped from where we wanted it to be.  This then led us to option 2:\n\n### Option 2. Determine what scoping a target has based on usage.\n\nA discussion has been going on about allowing the user to just write:\n\n```c#\nReadOnlySpan<int> x1 = [a, b, c]; // Could be local or global scoped\nscoped ReadOnlySpan<int> x2 = [a, b, c]; // Always local scoped.\n```\n\nand then determining the scoping based on how the variable is used.  For example, if 'x1' does not escape, then it could be stack allocated.  If it does end up escaping though (for example with `return x1;`), the collection expression would be heap allocated.  'x2' would always be local scoped of course and would be prevented from escaping.\n\nThe benefit of this approach would be allowing the user to always write the simple form with a collection expression, and then get the semantics they needed to make the code legal.  \n\nThis was attractive because of the simplicity of the user technically writing simple code, and then not having any stumbling blocks.  However, we felt this was actually a net negative.   A significant problem we foresee with this approach is that users will have code that is fast and nicely stack-allocating as they expect, and then some innocuous looking change ends up causing the compiler to conservatively think it may escape, causing the collection to now be heap allocated.  This could happen silently, easily tanking program performance.  Or, it could come with a warning.  But in the latter case, users would then have to suppress or introduce explicit casts.\n\nSimilar to option 1, it felt very strange for us to introduce behavior where the compiler would heap allocate for the user only to warn, since in the majority of times it was believed users would not want that.  After all, in the case of heap allocating, one might as well just choose a heap allocated type *to begin with*.\n\nThese concerns led us to our final option:\n\n### Option 3. Always stack-alloc for ref-struct target type.\n\nWe then moved to a discussion around our belief that when using ref-structs, and collection expressions, users would expect that data to be put on the stack.  Exploring this led to the following semantics:\n\n```c#\nReadOnlySpan<int> x1 = [a, b, c];        // stack allocated, local scope.\nscoped ReadonlySpan<int> x2 = [a, b, c]; // stack allocated, local scope.\n```\n\nIn other words, the above two have the same meaning.  With the latter just being explicit about the local scoping.  Returning either of those from a method would be illegal.  This has the benefit that the simple form matches the intuition nearly all users will want this to have, and will provide the best performance by default.  This heavily aligns with the stated goal of collection expressions (which we will continue to evangelize it with) that it makes the right default choices and by using it you should always (*ideally*) be getting the best performance results.  \n\nThis does have some downsides though.\n\nFirst, if the user did want to return the ref struct, they would now be blocked.  The workaround for this would be to instead be explicit that you wanted heap allocation for this span (e.g. `ReadOnlySpan<int> x1 = (int[])[1, 2, 3];`).  However, we see this explicitness as a *good* thing.  When working with spans and collection-expressions, we feel that having code be explicit when it is on the heap is actually a desirable documentary property for it to have.  And, while the cast syntax is not attractive, we could consider a simpler way of expressing that in the future (e.g. `new [1, 2, 3]`), where the syntax was light, but clear about intent.\n\nSecond, the aforementioned redundancy if you actually include `scoped`.  We could consider warning or blocking that to prevent confusion and to help convey that the data is always scoped.  That said, we already have this redundancy with `scoped ReadOnlySpan<int> x = stackalloc int[] { ... };` and we give no warning.  So we likely can just do the same here.\n\nThis approach also has the benefit that no diagnostic need ever be created for a span-targeted collection expression actually being heap allocated.  As we will always stack-allocate that simply is never a concern.\n\n## Decision:\n\nWorking group goes with option 3.  Collection expressions targeted to ref-struct types are always stack allocated.  Note that this covers more than just `Span<T>/ReadOnlySpan<T>`.  For example, if one had the following:\n\n```c#\n[CollectionBuilder(FrugalListBuilder)]\nref struct FrugalList<T>\n{\n}\n\nstatic class FrugalListBuilder\n{\n    public static FrugalList<T> Create(ReadOnlySpan<T> values);\n}\n\n// ...\nFrugalList<int> f = [a, b, c]; // Stack-allocated, local scope.\n```\n\nWe believe that this is the semantics ref-struct-collections will want.  And, similar to spans, the semantics users would expect to get *without* having to annotate with `scoped` on the local variable.\n\n## Blittable Data\n\nThe above discussion applied to collection expressions, target typed to ref-structs, *without* constant, blittable data in it.  Blittable data is effectively defined as C# builtin of 1-8 bytes in size.  Intuitively, the primitive integers, floating points, and characters.  \n\nToday, the language already allows optimizing the following:\n\n```c#\nprivate static ReadOnlySpan<char> s_chars = new char[] { 'a', 'b', 'c' };\n```\n\nDespite this explicitly having a `new` in the code, and explicitly referencing the `char[]` type, the above will be compiled without any allocations or array types.  Instead, the data will be embedded directly into the data segment of the compiled assembly, and the span will be created pointing directly at that raw data. \n\nWe will have those rules apply when using a collection expression as well.  This means that the following will be legal and will have the same behavior at runtime:\n\n```c#\nprivate static ReadOnlySpan<char> s_chars = ['a', 'b', 'c'];\n```\n\nIn other words, if a collection literal has nothing but constant blittable data, and it is target typed to a `ReadOnlySpan<BlittableType>` *only*, then it will actually be considered to have `global` not `local` scope.  This means that the following would be allowed:\n\n```c#\nReadOnlySpan<int> x = [1, 2, 3]; // pointer to data segment, global scope.\nreturn x;\n```\n\nNo decisions were needed on this.  Working group just affirmed these are the desired semantics and these rules and optimizations will be maintained with collection expressions.\n"
  },
  {
    "path": "meetings/working-groups/collection-literals/CL-2023-08-10.md",
    "content": "# Collection literals working group meeting for August 10, 2023\n\n## Agenda\n\n* Determine behavior when target runtime does not support Inline-Arrays.\n\n## Discussion\n\nThe purpose of the meeting was to go over the decisions made in the last WG meeting (https://github.com/dotnet/csharplang/blob/main/meetings/working-groups/collection-literals/CL-2023-08-03.md) and consider their impact in the context of users targeting runtimes which do not support inline-arrays.\n\nAs a reminder, the final conclusion from that meeting was:\n\n> Working group goes with option 3. Collection expressions targeted to ref-struct types are always stack allocated.\n\nCurrently, the approach we are intending to take for targeting something like `Span<T>/ReadOnlySpan<T>` is to use the [inline-arrays](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/inline-arrays.md) feature to synthesize an inline-array to place the data to, and then obtain a span from it.  However, inline-arrays are only available on Net8.0 and up.\n\nFurther discussion on this topic raised concerns from several participants that this approach was too onerous in practice.  Specifically, that a core use case in modern .NET is for users to multi-target their code.  This multi-targeting appears in practice with users targeting frameworks like netstandard2.0 and netX.0, or just multiple versions of netX.0 (like net6.0/net7.0/net8.0/etc.). This raises a dilemma where users who are multi-targeting are then shut out from being able to use collection expressions with spans.\n\nStack allocating, though, is not a mandatory requirement. It is possible for the compiler to still generate code in these cases.  Specifically, by allocating an array (on the heap) and storing it in the span.  Note: this would not change the local-versus-global scope aspect of the span.  Whether the span has local or global scope would use the same rules decided from the last working group meeting.  It would just be the case that a local-scoped span would be stack-allocated on targets that supported inline-arrays, but heap allocated on targets that did not.  This is necessary so that a user moving from a prior runtime (without inline-array support) to a current runtime would not find their scopes become more restrictive, certainly breaking user code that had come to depend on the global scope from before.\n\nVigorous debate about this followed, with concerns both about shutting people out from being able to use collection expressions in these real-world cases, while also not wanting usage of collection expressions to silently cause users to go over invisible performance cliffs.  Ultimately, we concluded that shutting people off from using collection literals in multi-targeting scenarios was not acceptable. Rather, users should be in control and should be able to make an informed choice about what best strategy to take in these circumstances.  To that end though, we felt strongly that users not run into a silent performance cliff.  As such, our final determination was:\n\n1. No change in global/local scoping rules for spans and collection expresssions\n1. No change in rules around blittable collections assigned to `ReadOnlySpan<T>`` (they remain global scoped, and will be read from the data segment of a dll)\n1. On target frameworks that support inline-arrays, we will use them and target the stack as the location where the data is actually stored.\n1. On target frameworks that do not support inline-arrays, we will *fall back* to allocating an array on the heap and having the span point at that array.  We will *also* issue a warning in this case to make the user aware of the allocation.\n\nThe final two rules apply to the spans created as temporary storage for the `collection builder` pattern as well.\n\nExamples:\n\n```c#\nReadOnlySpan<int> A()\n{\n    ReadOnlySpan<int> x = [GetInt(), GetInt(), GetInt()];\n\n    // Always illegal on any framework.  'x' has local scope.\n    return x;\n}\n\nReadOnlySpan<int> B()\n{\n    ReadOnlySpan<int> x = [1, 2, 3];\n\n    // Always legal.  'x' has global scope due to being a ReadOnlySpan of constant blittable data.\n    return x;\n}\n\nvoid C()\n{\n    // Stack allocated (using Inline-Array on Net8 and up)\n    //\n    // Heap allocated (using an int[] on Net7 and below).  Will warn in that event.\n    ReadOnlySpan<X> x = [Get(), Get(), Get()];\n}\n\nvoid D()\n{\n    // Temporary ReadOnlySpan<int> is stack allocated (using Inline-Array on Net8 and up)\n    //\n    // Temporary ReadOnlySpan<int> is heap allocated (using an int[] on Net7 and below).  Will warn in that event.\n    ImmutableList<X> x = [Get(), Get(), Get()];\n}\n```\n"
  },
  {
    "path": "meetings/working-groups/collection-literals/CL-2023-08-11.md",
    "content": "# Collection literals working group meeting for August 11, 2023\n\n## Agenda\n\n* Implementations used when targeting interface types\n\n## Discussion\n\nFollowing up from the Aug 8th language design meeting, the working group considered specific concrete implementations to use for each interface that collection expressions can target. We reviewed the [Compiler-synthesized types](https://github.com/dotnet/csharplang/blob/main/meetings/working-groups/collection-literals/Compiler-synthesized-types.md) proposal in preparation for upcoming language design meetings which will get into more of the details of the collection expressions feature.\n\nThe language design meeting on Aug 8th concluded that we can later change the concrete type created for interfaces even after people start using the feature. For now, we'll decide on a starting point to recommend which we feel comfortable with.\n\n### Targeting mutable interfaces\n\nWhen a collection expression targets `IList<T>` or `ICollection<T>`, we'll construct a `List<T>`. Even if people start depending on it, we could still change it in the future, similar to how .NET Core changed the concrete type returned from `Enumerable.Empty<T>()`.\n\n### Targeting readonly interfaces\n\nThese are `IEnumerable<T>`, `IReadOnlyCollection<T>`, and `IReadOnlyList<T>`. Empty collections will get whatever instance the framework returns from `Array.Empty<T>()`. For non-empty collections targeting readonly interfaces, we considered three alternatives:\n\nA: Synthesized type with a field of type `IList<T>` or `List<T>`  \nB: Just use the BCL's `ReadOnlyCollection<T>` type  \nC: Use `List<T>` for unknown-length construction and `T[]` for known-length.  \n\nAlternative C is great for performance but loses the safety that is a selling point to a significant part of our audience. Alternative B adds in the possibility for folks to cast and depend on the exact type (even though we do reserve the right to change the concrete type anyway), but it also doesn't have some of the benefits of alternative A; there are things we could do better in private implementations such as sealing it and wrapping a `List<T>` field rather than `IList<T>`, gaining better codegen with devirtualization and inlining.\n\nWith the extra indirection, indexing through a readonly wrapper is measurably worse than on an unwrapped array, twice as slow in a benchmark. On the other hand, wrappers add no cost to enumeration via `foreach` and `IEnumerable<T>` over the wrapped collection because the wrapped collection's enumerator can be returned directly through the wrapper.\n\nFor known-length collections, it may be worthwhile to construct and wrap a `T[]` rather than a `List<T>`, or even synthesize interface implementations with hardcoded counts and hardcoded fields for elements for certain sizes. `T[]` wouldn't be great for unknown-length collections since arrays must be exactly sized, often requiring a final copy from a larger-sized buffer that was used to hold the items while the length wasn't yet known. We could wrap an `IList<T>` field to handle both, or we could generate different wrappers to contain a `List<T>` field or a `T[]` field for the two situations as needed.\n\nEven if the target type is only `IEnumerable<T>`, the synthesized types should implement `IReadOnlyList<T>`, `IList<T>`, and nongeneric `IList`. This is in case of subsequent usage against runtime checks, such as data binding or LINQ optimizations. It could result in bigger generated code size that isn't trimmable. Method bodies could be shared though, since most of the `IList<T>` and nongeneric `IList` members are mutating members which contractually should just throw `NotSupportedException`.\n\n## Conclusion\n\nFor `ICollection<T>` or `IList<T>`, we will build a new `List<T>`.\n\nFor (non-empty) `IEnumerable<T>`, `IReadOnlyCollection<T>`, or `IReadOnlyList<T>`, initially we will synthesize a private type within the assembly which is similar to the framework's `System.Collections.ObjectModel.ReadOnlyCollection<T>`. This is a straightforward starting point which prevents casting to the framework class. The design space is open and the compiler can create specialized classes later in a data-driven fashion.\n\nIn C# 13 when we get to dictionaries, `IDictionary<T>` will be a new `Dictionary<T>`, and `IReadOnlyDictionary<T>` will follow a strategy consistent with the strategy for `IReadOnlyList<T>`, such as synthesizing a private type similar to `System.Collections.ObjectModel.ReadOnlyDictionary<TKey, TValue>`.\n"
  },
  {
    "path": "meetings/working-groups/collection-literals/CL-2024-01-23.md",
    "content": "# Collection expressions: design restart meeting 01/23/24\n\nThe collection expressions group met again for the first time after shipping C# 12 and going through the holidays.  The agenda was to discuss and outline all the interesting areas we want to consider in C# 13 (along with a loose prioritization).\n\n## C# 13 Collection expression design areas (loosely prioritized)\n\n### Dictionary expressions\n\nBroadly speaking, we consider dictionary expressions (tentatively `[k1:v1, k2:v2]`) to be the most important design space for us to front load.  Specifically, because it both seems like the area of collections most commonly used in the BCL and in APIs, but which has no support today with collection expressions.  We also believe that the decisions made here will impact any decisions we make in the [Natural Type](#natural-type) space.\n\nBroken down, we see important design needing to be made in the following areas:\n\n1. Pattern correspondence.\n\n    Collection literals started with a strong emphasis on the construction side needing to have parity with the pattern-matching side.  e.g. `x = [a, b, .. c]` and `x is [var x, var b, .. var c]`.  We strongly think that this should be kept in mind when it comes to dictionary-expressions as well.  That said, dictionary-patterns will be quite interesting in their own right and have several design challenges for them.  For example:\n\n    - We have to cognizant that we likely should only offer patterns that have a sensible translation.  For example: `x is [var key: 0, ..]` is not likely something that could be implemented (as it would need a linear walk of most dictionaries to find all the elements).\n    - Similarly, `x is [key1: 0, .. var rest]` would likely be extremely expensive, as it would require somehow cloning everything, and removing elements that matched.\n    - Similarly, certain types of constructs would likely not make sense, like `x is [key1: 0, .., key2: 1]`.  Specifically, as dictionaries are not ordered, allowing `slice` patterns in the middle is somewhat nonsensical as there is no before/after concept.\n    \n    All of the above  likely means that the pattern form that dictionaries should support would be limited to: `[(constant-pattern: pattern)+, (..)?]`.  In other words, some amount of key/value patterns, where the keys are all constants, and the values associated with those keys are then matched against a pattern, followed by an optional spread, to indicate if the dictionary can have more elements or not beyond those which are matched.\n\n2. The overlap/duality between lists and dictionaries, and what should `k:v` mean in that world.\n\n    For example, we could consider things in the following ways:\n\n    - `k:v` is simply a shorthand for `KeyValuePair<TKey,TValue>`.  And as such, the following would be legal: `List<KeyValuePair<string, int>> nameToAgeList = [\"mads\": 21]`. This allows for the possibility that `((Collection)[k:v])[k]` may not yield `v`.\n    - `k:v` represents a key-value *association*, and thus should only be usable with dictionary-esque (tbd) types, not sequence-esque types. This enforces the intuition that `((Collection)[k:v])[k]` yields `v`.\n\n    As part of this, we want to figure out what expressions elements can mix/match with what target types.  For example (as shown above) can a `k:v` element be used with a sequence-type?  Can a normal expression element be used with a dictionary type (e.g. `Dictionary<string, int> x = [kvp1, kvp2]`)?\n\n3. The semantics of dictionary expressions wrt 'adding' vs 'overwriting' key/value associations.\n\n    We could go with the simple approach of adding each association one at a time, left to right.  This would align both with how collection-expressions work today for sequence collections, as well as how dictionary-initializers work (e.g. `new D<string, int> { { \"mads\": 21 }, { \"cyrus\": 22 } }`).  However, there is a definite feeling that this approach is limiting and cuts out certain valuable scenarios, all specifically around `spread` elements.  For example:\n\n    ```\n    // Making a copy, but overwriting some elements\n    Dictionary<string, int> dest = [.. source, \"mads\": 21];\n    \n    // Having some default values, but allowing them to be supplanted.\n    Dictionary<string, int> dest = [\"mads\": 21, .. source];\n\n    // Merging two dictionaries, with the later ones winning.\n    Dictionary<string, int> dest = [.. source1, .. source2];\n    ```\n\n    Design group feels that they've run into all these situations, and they're generally useful.  Having 'Add+Throw' semantics here would be painfully limiting.\n    \n    If we do decide on 'overwrite' semantics, we could consider having the compiler warn though in the case of multiple `k:v` elements, with the same constant value for `k`.\n\n4. Adopting `JSON` syntax here.\n\n    Specifically, allowing `{ \"key\": value }` to work as legal dictionary-expression syntax.  Working group leans no, but we definitely want to run by LDM for thoughts.\n\n    - Pros: Great parity with a very popular data format.  This would allow users to also instantiate Newtonsoft J-Etcs or System.Text.JXXX types just with real JSON literals.  Copy/pasting to/from C# becomes very nice.\n\n    - Cons:\n        - Moves us away from `[...]` being the lingua franca for all collection types.\n        - Adds a lot of parsing/ambiguity complexity around `{...}`.  \n        - Impacts our future design space around `{...}` (for example, expression blocks).\n        - Is very difficult to have pattern-parity.  `{ k: ... }` is already legal as a property pattern.  Needing that to work as a dictionary-pattern is non-trivial (and potentially very confusing for users).\n\n5. Mechanisms to specify a `comparer` or `capacity` for a dictionary.\n\n    Discussions with the community have already indicated a strong desire to be able to specify these values (esp. the `comparer`). We think this is common enough to want to be able to have support, ideally in a way that doesn't feel like one is taking a big step back wrt brevity and simplicity of the dictionary-expression.  Importantly, it would be a shame if the collection-expression form weren't better than a user just using a dictionary-initializer today (e.g. `new(myComparer) { { \"mads\": 21 } }`).\n\n    Strawman proposals include:\n    \n    - `[comparer: ..., \"mads\": 21]` (where `comparer` was now a keyword in this context, and would be stylized as such by the ide).  If a user actually wanted to reference a variable called `comparer` they'd then do `@comparer`, like how we normally separate out keywords vs identifiers.\n\n    - `[new: (comparer, capacity), \"mads\": 21]`.  A special construct allowing one to state what arguments to pass to the constructor.  Note: this would likely be beneficial for normal sequence-collections as well.  As `new` is already a keyword and `new:` is not legal in the language today, this would have no concerns around ambiguity.\n\n6. Targeting interfaces.\n\n    Like with sequence-expressions, we believe that dictionary-expressions should be able to at least target the well known type `IDictionary<TKey, TValue>` as well as `IReadOnlyDictionary<TKey, TValue>`. We expect to take a similar approach to what we did with sequence-expressions, where we choose `Dictionary<TKey, TValue>` for the former, and allow the compiler to synthesize a read-only type for the latter.\n\n7. Immutable collections.\n\n    Like with sequence-expressions, we believe that dictionary-expressions should be able to target types like `ImmutableDictionary<TKey, TValue>`.  Our hope is that `CollectionBuilderAttribute` can be used for this purpose, likely pointing at signatures like: `ImmutableDictionary.CreateRange<TKey, TValue>(ReadOnlySpan<KeyValuePair<TKey, TValue>> items)`.\n\n    This will tie into the decisions on '5' though wrt to how to pass items like the comparers along.\n\n### Natural type\n\nWe consider natural types the next biggest area we would want to tackle.  Specifically, we think it would be so influenced by the decisions on dictionary-expressions that it would not be sensible to design this first without seeing how dictionaries play out.  For example, in the absence of dictionaries, we might consider the natural type of a sequence expression to be `ReadOnlySpan<SomeT>`.  However, would such a decision have a sensible glow-up story to tackle natural types for dictionary expressions?  Having a sensible story for both will very likely influence our decisions here.\n\nFor natural types, we see two broad areas we would like to examine:\n\n1. The natural type of a collection expression in the absence of *any* *element-target-typing* whatsoever. This would apply when a collection expression was targeted to something like `object` or `var`, where all information about the final type would have to come from the collection expression itself.  e.g. `object o = [1, 2, 3]`.  \n\n2. The natural type of a collection expression with some contextual *element-target-typing*.  This would apply to cases like so:\n\n    - `foreach (byte b in [1, 2, 3])`.  Here, we believe that the `byte` type should help influence the collection type being created (so that this case is legal).\n\n    - `List<Predicate> list = [a, b, .. c ? [_ => true] : []]`.  Similarly, the use of `Predicate` here in the target should help influence the type of `[_ => true]` such that this code succeeds.\n\nOverall though, this space is enormous and will need a lot of future design.  Open areas include, but are not limited to:\n\n1. Could we envision a world where `var v = [];` is ever allowed?  This would involve flow analysis to determine the element type based on how `v` was used.\n\n2. Should we align on a well known type for the natural type, or should we consider it just a special language type (like anonymous-types) that the compiler makes its own determinations about.  For example, we could pick a well known type like `List<T>` or we could consider the language having a special ``builtin-list<T>`` type with special properties.\n\n3. Should we try to mandate a very efficient type (like Span/InlineArrays) for perf?  How would that work with async/await?\n\n4. Would it be possible to pick an inefficient type (like `List<T>`) but then give the compiler broad leeway to optimize in the common case where it would not be observable (for example, actually emitting on the stack when safe).\n\n### Extension methods\n\nWe are still interesting in enabling `[a, b, c].ExtensionMethod()`. However, we think this is not something that should be limited to collection expressions.  Broadly speaking, the language is very limited wrt to the interaction of extension methods and target-typed constructs.  For example, you cannot do this `(x => true).ExtensionOnStringPredicate()`.  The language requires the item being invoked have a type *prior* to lookup of the extension method.  To make cases like this work, we'd need to allow them to not have a type, and then say that lookup should still find the extensions, which are then tested for applicability in the rewritten form (e.g. `ExtensionMethod([a, b, c])`).\n\nAs we are investing heavily in extensions in C# 13, we may want to roll the exploration of this area into that work.\n\n### Addressing existing types that should work with collection expressions, but don't.\n\nThere are several types we've found that annoying don't work with collection expressions.  For example:\n\n- `ArraySegment<T>`\n- `ReadOnlyMemory<T>`.  Commonly used as the analog of `ReadOnlySpan<T>` when you're working with async methods.\n- InlineArray\n\nWe want to continue collecting these types to see what would be a good approach to expanding out support in the future.  Specifically, if the set of types is very small, it might be acceptable to just hardcode support for them.  However, if the set grows large, we may need to identify patterns to allow them to participate.  For example, we might say that if a type has a `public static implicit operator ThisType(T[] array)` conversion operator, that it would then be constructible with a collection expression.\n\nIt's worth noting that making any type now be collection expression constructible would always be a potential breaking change with overload resolution, unless we made these always have a lower priority than the core rules we shipped with.\n\n### Supporting non-generic interfaces\n\nThere is an open question on what the (currently illegal) semantics should be for `IEnumerable x = [1, 2, 3];`\n\nThere are a few paths we could conceivably take here.\n\n- Have no special behavior for this, and allow 'natural type' to take care of it.  If, for example, the natural type of `[1, 2, 3]` was `List<int>` then this would be equivalent to: `IEnumerable x = (List<int>)[1, 2, 3];`.  Note that this would then be making a mutable collection under the covers, strongly typed to 'int'.\n\n- Treat the non-generic interfaces as the generic versions with 'object'.  In this case, that would mean the above would be equivalent to: `IEnumerable x = (IEnumerable<object>)[1, 2, 3];`.  This would then mean the compiler would synthesize the read-only collection, but also that every element would be boxed as object.\n\n- A hybrid approach where the element type might be picked using whatever natural-type system we had, but the collection type itself was the generic interface.  In this case, that would mean the above would be equivalent to: `IEnumerable x = (IEnumerable<int>)[1, 2, 3];`, This would then mean the compiler would synthesize the read-only collection, and also that every element would be non-boxed in the underlying storage.\n\nRegardless of what we decide, we have to keep this in mind when doing the [Natural type](#natural-type) work.  This will start working (with the first version above) once we have natural types.  If we do not like the code that would happen there, we would have to either block or come up with an alternate set of semantics when we do natural types.\n\n### Relaxing restrictions.\n\nRecent feedback has presented real-world examples where our restrictions around api shapes can be annoying.  As an example, the Roslyn team themselves have identified a case of a type that they'd like to be collection-expression constructible, which they cannot use.  Specifically, while they can add a CollectionBuilderAttribute to it, the type itself is not `IEnumerable<T>`, and so it fails that restriction we have.  This restriction seems onerous, especially as the user is stating explicitly that they think their type is a collection through the user of that attribute.\n\nSimilarly, we have recently added a restriction that a collection-initializer type used with a collection-expression must have an instance `Add` method that works with the iteration type of the collection.  This is more restrictive than what collection-initializers themselves require (simply that they can find a suitable 'Add' method (including extensions)).  We may want to relax this if we see worthwhile examples provided.\n"
  },
  {
    "path": "meetings/working-groups/collection-literals/CL-LDM-2023-05-31.md",
    "content": "# C# LDM Collection Literals Agenda\n\nCore spec: https://github.com/dotnet/csharplang/blob/main/proposals/collection-literals.md\n\n## Core set of features for C# 12\n\n1. We are not discussing any 'natural typing' scenarios today.  We're continuing to make progress in that space and would like to have a dedicated meeting on that topic.\n2. This is the set of features we believe has a very intuitive and solid design around them, and would hit a good 'sweet spot' of capabilities and user satisfaction for the initial release.\n3. We intend to have future meetings that go through the spec *in detail* to ensure LDM satisfaction with the exact changes being proposed (Chuck to drive).\n\n### Grammar:\n\n```diff\nprimary_no_array_creation_expression\n  ...\n+ | collection_literal_expression\n  ;\n\n+ collection_literal_expression\n  : '[' ']'\n  | '[' collection_literal_element ( ',' collection_literal_element )* ']'\n  ;\n\n+ collection_literal_element\n  : expression_element\n  | dictionary_element\n  | spread_element\n  ;\n\n+ expression_element\n  : expression\n  ;\n\n+ dictionary_element\n  : expression ':' expression\n  ;\n\n+ spread_element\n  : '..' expression\n  ;\n```\n\nCommon examples:\n\n```c#\nint[] a = [1, 2, 3];\nList<object> list = [start, .. middle, end];\nIDictionary<string, int> d = [k1:v1, k2:v2, k3:v3];\n```\n\n### Target-typing to core collections and collections with classic collection initializers\n\nThe following are constructible collection types that can be used to construct collection literals. These are the valid target types for collection literals.\n\nThe list is in priority order. If a collection type belongs in multiple categories, the first is used.\n\n\n1. Single dimensional arrays (e.g. `T[]`)\n\n```c#\nint[] a = [1, 2, 3]; // equivalent to:\nint[] a = new int[] { 1, 2, 3 };\n```\n\n2. Span types (`Span<T>` and `ReadOnlySpan<T>`)\n\n```c#\nSpan<int> values = [1, 2, 3]; // equivalent to either:\n\nSpan<int> values = new int[] { 1, 2, 3 }; // or\nSpan<int> values = stackalloc int[] { 1, 2, 3 };\n```\n\nWhich one is picked depends on compiler heuristics around stack space (and is part of the 'params span' WG outcomes), and the ref-safety rules around `values`.\n\n3. Types with a suitable `Construct` method.  This will be discussed below, but relates heavily to immutable collections, and how to efficiently construct them.  It will also be the preferred way to create a `List<T>` as it is the most efficient form with lowest overhead.\n\n4. Concrete collection types that implement `System.Collections.IDictionary`\n\n```c#\nDictionary<string, int> nameToAge = [ \"Dustin\": 42, \"Cyrus\": 43 ]; // possibly equivalent to:\n\nDictionary<string, int> nameToAge = new Dictionary<string, int> { { \"Dustin\", 42 }, { \"Cyrus\", 43 } }; \n\n// Open question below about update vs throw semantics for duplicate keys.  Will cover when we discuss dictionaries.\n```\n\n5. Interface types `I<TKey, TValue>` implemented by `System.Collections.Generic.Dictionary<TKey, TValue>` (e.g. `IDictionary<TKey, TValue>`, `IReadOnlyDictionary<TKey, TValue>`)\n\n```c#\nIReadOnlyDictionary<string, int> nameToAge = [ \"Dustin\": 42, \"Cyrus\": 43 ]; // possibly equivalent to:\nIReadOnlyDictionary<string, int> nameToAge = new Dictionary<string, int> { { \"Dustin\", 42 }, { \"Cyrus\", 43 } }; \n\n// Open questions on if there is a guarantee about concrete type instantiated.\n```\n\n6. Types that implement `System.Collections.IEnumerable`. e.g. normal C# 3.0 collection initializer types\n\n```c#\nHashSet<int> set = [1, 2, 3]; // equivalent to:\n\nHashSet<int> set = new HashSet { 1, 2, 3 };\n\n// We pass the capacity to the constructor if it takes one.\n```\n\n7. Interface types `I<T>` implemented by `System.Collections.Generic.List<T>` (e.g. `IEnumerable<T>`, `IList<T>`, `IReadOnlyList<T>`, etc.)\n\n```c#\nIEnumerable<int> values = [1, 2, 3]; // could be:\n\nIEnumerable<int> values = new List<int> { 1, 2, 3 }; // or could be:\nIEnumerable<int> valuies = new <>UnspeakableName { 1, 2, 3 };\n\n// Open question below about this.\n```\n\n\nOpen Questions:\n1. Does LDM agree with the priority order and totality of the support constructible collection types?  Of note: this means that any type that is not in that list, and is not being updated (e.g. netfx 4.7.2 types) might not work with collection literals.  Should we have some way (e.g. an extension-method pathway) to be able to opt those legacy types in?\n2. What is the behavior when users attempt to initialize an `IEnumerable` (or any interface type)? Do you get a `List<T>` or an undefined type?\n\n\n### Target-typing with BCL attribute Create method\n\nMain examples:\n    \n```c#\nList<int> list = [1, 2, 3]; // equivalent to:\nCollectionsMarshal.Create<int>(capacity: 3, out List<int> list, out Span<T> __storage);\n__storage[0] = 1;\n__storage[1] = 2;\n__storage[2] = 3;\n    \n// Works identically for ImmutableArray<T>.\n\n// However, some types cannot give you the storage to write sequentially into.  For those, the pattern is:\nImmutableDictionary<string, int> namesToAge = [ \"Dustin\": 42, \"Cyrus\": 43 ]; // equivalent to:\n    \n// Storage is initialized (ideally on stack when safe), and passed to type to own creating its internal structure\nReadOnlySpan<KeyValuePair<string, int>> storage = [ new(\"Dustin\", 42), new(\"Cyrus\", 43) ]; // could be heap or stack.\nCollectionsMarshal.Create<string, int>(out ImmutableDictionary<string, int> namesToAge, storage);\n```\n    \nThe pattern is:\n    \n```cs\n// Attribute placed on collection target type, stating where to find the factory method.\n// Specifies the type where it is found, and the factory method name.  Up to BCL to include.\n    \n[CollectionLiteralBuilder(\n    typeof(CollectionsMarshal),\n    nameof(CollectionsMarshal.Create))]\npublic class List<T> : IEnumerable<T> { } // or\n\n[CollectionLiteralBuilder(\n    typeof(CollectionsMarshal),\n    nameof(CollectionsMarshal.CreateRange))] \npublic sealed class ImmutableDictionary<TKey, TValue> : IDictionary<TKey, TValue> { }\n    \n// Factory method shape:\npublic static class CollectionsMarshal\n{\n    // For cases where the instance can share out its storage as a sequential buffer for caller to place the values in.\n    // Storage span is passed out for caller to populate with no overhead.\n    public static void Create<T>(\n        int capacity,\n        out List<T> collection,\n        out Span<T> storage);\n    \n    public static void Create<T>(\n        int capacity,\n        out ImmutableArray<T> collection,\n        out Span<T> storage);\n    \n    // For cases where the final instance has to manage non-sequential structure.  Storage is passed in and copied over to\n    // internal structure.\n    public static void CreateRange<T>(\n        out ImmutableHashSet<T> collection,\n        ReadOnlySpan<T> storage);\n    \n    // Example of the shape for things like dictionaries.\n    public static void CreateRange<TKey, TValue>(\n        out ImmutableDictionary<TKey, TValue> dictionary,\n        ReadOnlySpan<KeyValuePair<TKey, TValue>> storage);\n}\n```\n\nOpen Questions:\n1. Does LDM agree with introducing a new pattern for collection construction?\n1. If this API can't come in time, is it OK for the compiler to temporarily special case `List<T>` (and potentially `ImmutableArray<T>`)?  \n\n### Dictionaries\n    \nCreated as a natural syntactic extension on collection literals:\n    \n```c#\nList<int> list = [1, 2, 3];\nDictionary<string, int> nameToAge = [\"Dustin\": 42, \"Cyrus\": 43];\n```\n    \nSyntax picked for two reasons:\n1. Very brief.  A core goal of this feature is to prevent excessive syntax for simple ideas.\n2. Very familiar to many languages that use colon here (JS, Python, Swift, Dart, Go, etc.).  Want to put best foot forward.\n    \nDownsides:\n3. Does introduce syntactic ambiguity\n    \n```csharp\nDictionary<K, V> d = [a ? [b] : c]; // [a ? ([b]) : c)] or [(a ? [b]) : c]?\n```\nWG feeling is that this ambiguity though would be extremely rare to hit.  Picking 'expression' here (not k:v) seems totally fine.  If you do want K:V, parenthesize the key.\n    \nSpreading is also supported for dictionaries, allowing for nice things like:\n    \n```c#\nDictionary<string, int> nameToAge = [\"Dustin\": 42, \"Cyrus\": 43];\nDictionary<string, int> newNameToAge = [.. nameToAge, \"Mads\": 25];\n```\n    \nDictionaries (without 'Construct' methods) are rewritten as:   \n\n```cs\nDictionary<string, int> nameToAge = [\"Dustin\": 42, \"Cyrus\": 43]; // rewritten as:\n\nDictionary<string, int> nameToAge = new Dictionary<string, int>(capacity: 2);\nnameToAge[\"Dustin\"] = 42;\nnameToAge[\"Cyrus\"] = 43;\n    \n// But it could have been (throw vs update semantics):\nnameToAge.Add(\"Dustin\", 42);\nnameToAge.Add(\"Cyrus\", 43);\n```\n    \nOpen Questions:\n1. Does LDM agree with supporting dictionary literals for C#12?\n2. When target-typed to interface, do we guarantee a particular concrete type?\n3. Does dictionary creation use _update_ or _add_ semantics? (Are duplicate keys allowed?)\n\nConsider the `CollectionsMarshal.CreateRange<TKey, TValue>()` factory method above. The BCL already has similar construction methods for dictionaries, either as constructors or static helpers, that take an `IEnumerable<KeyValuePair<K, V>>`. Those existing methods typically don't allow duplicated keys with distinct values, and this method will probably need to work similarly. In short, the construct method may have _add (and throw)_ semantics.\n\n4. Allow `k:v` expression inside a non-dictionary collection literal?  e.g.:\n    \n```c#\nList<KeyValuePair<string, int>> pairs = [\"Dustin\": 42, \"Cyrus\": 43]; // Is this ok?  Or would we require you say:\n    \nList<KeyValuePair<string, int>> pairs = [new(\"Dustin\", 42), new(\"Cyrus\", 43)];\n```\n\nProposal: `dictionary_element` is supported for _non-dictionary_ collection literals if the _element type of the collection_ is some `KeyValuePair<,>`.\n    \n5. Allow `expression_element` and `spread_element` in dictionary?  This requires effectively that constructing dictionaries understands how to incorporate a KVP *value* from an external source.  For example:\n    \n```c#\nKeyValuePair<string, int> GetMads() => new(\"Mads\", 24);\n    \nDictionary<string, int> nameToAge = [\"Dustin\": 42, \"Cyrus\": 43, GetMads()]; // otherwise, you'd have to write:\n    \nvar mads = GetMads();\nDictionary<string, int> nameToAge = [\"Dustin\": 42, \"Cyrus\": 43, mads.Key: mads.Value]; \n```\n    \nNote: supporting spreads for dictionaries strongly implies that this should \"just work\".  But we want LDM to be ok here.\n\nProposal:\n- `expression_element` is supported in a dictionary if the _element type_ is some `KeyValuePair<,>` or `dynamic`.\n- `spread_element` is supported in a dictionary if the _enumerated element type_ is some `KeyValuePair<,>` or `dynamic`.\n\n6. Collection literal syntax does not allow for a custom comparer.\n\nIs it sufficient to rely on extension methods such as the following? Will type inference infer `TKey`, `TValue` from `k:v`?\n\n```C#\nd = [\"Alice\": 42, \"Bob\": 43].AsDictionary(comparer);\n\nstatic class Extensions\n{\n    public static Dictionary<TKey, TValue> AsDictionary<TKey, TValue>(\n        this List<KeyValuePair<TKey, TValue>> list,\n        IEqualityComparer<TKey> comparer = null);\n}\n```\n    \n7. Syntax ambiguity (shown above)\n\n### Spreads\n\nCorresponding 'construction' form of the 'slice' pattern. \n    \n```C#\nif (x is [var start, .. var middle, var end]) // pattern form:\n    \nList<string> values = [\"start\", .. middle, \"end\"]; // translates to potentially:\n    \nList<string> values = new List<string>(capacityIfKnown);\nvalues.Add(\"start\");\nvalues.AddRange(middle);\nvalues.Add(\"end\");\n    \n// or potentially:\n    \nList<string> values = new List<string>(capacityIfKnown);\nvalues.Add(start);\nforeach (var v in middle)\n    values.Add(v);\nvalues.Add(end);\n```\n    \n1. Should we use AddRange if available? What if it boxes? We could leave it underspecified and utilized compiler heuristics. Fits into the overall discussion of the presumption that \"construction\" semantics are well-behaved (like pattern matching semantics). \n    \nPros:\nThis will commonly be quite fast for many collections passed to AddRange.  AddRange often uses TryGetNonEnumeratedCount and CopyTo to update internal capacity, and then write directly into it.\n    \nCons:\nThere are definitely cases where this will allocate more than direct foreach (for example, if the AddRange impl cannot use CopyTo, and must instead create a heap allocated IEnumerator).\nThis will box in the case where 'middle' is a struct.  We could detect that and `foreach` in that case.\n    \n2. Should evaluation of spread elements be lazy? For instance:\n```C#\nstatic IEnumerable<int> GetIntegers()\n{\n    for (int i = 0; ; i++)\n        yield return i;\n}\n\nIEnumerable<int> e = [..GetIntegers()];\nint first = e.First();\n```\n"
  },
  {
    "path": "meetings/working-groups/collection-literals/CL-LDM-2023-08-14.md",
    "content": "# Collection expressions: LDM proposals 2023-08-14\n\n## Overload resolution\n\n*See proposal: [Overload resolution](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#overload-resolution)*\n\nCollection expressions can be implicitly converted to multiple target types, which increases the chance of overload resolution ambiguities.\n\nWe may not be able to choose between two arbitrary collection types when neither collection type is implicitly convertible to the other.\n\nFor performance though, we could consider choosing spans over arrays or interfaces.\nThe rule could apply to *collection expression arguments only*, to avoid a breaking change to existing code.\n\n```c#\nSpanAndArray([1, 2, 3]);  // (proposed) uses Span<T> overload\nSpanAndInterface([4, 5]); // (proposed) uses Span<T> overload\n\nstatic void SpanAndArray<T>(Span<T> args) { }\nstatic void SpanAndArray<T>(T[] args) { }\n    \nstatic void SpanAndInterface<T>(Span<T> args) { }\nstatic void SpanAndInterface<T>(IEnumerable<T> args) { }\n```\n\nFor instance, an additional rule could be added to [*better conversion from expression*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/expressions.md#11644-better-conversion-from-expression).\n\n> Given an implicit conversion `C₁` that converts from an expression `E` to a type `T₁`, and an implicit conversion `C₂` that converts from an expression `E` to a type `T₂`, `C₁` is a ***better conversion*** than `C₂` if one of the following holds:\n> \n> - ...\n> - `C₁` and `C₂` are collection expression conversions and the following hold:\n>   - `T₁` is a *span type* `Span<S>` or `ReadOnlySpan<S>`.\n>   - `T₂` is a single-dimensional *array type* `E[]` or an interface `IEnumerable<E>`, `IReadOnlyCollection<E>`, `IReadOnlyList<E>`, `ICollection<E>`, `IList<E>`.\n>   - `S` is implicitly convertible to `E`.\n\nIn practice though, pairs of overloads with spans and either arrays or interfaces may be uncommon, at least in the BCL, because overload resolution prefers the array and interface overloads when passing array arguments.\n\n```c#\nSpanAndArray(new[] { 1, 2, 3 });  // uses T[] overload\nSpanAndInterface(new[] { 4, 5 }); // uses IEnumerable<T> overload\n```\n\n*See also: [Prefer spans over interfaces in overload resolution](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-06-19.md#prefer-spans-over-interfaces-in-overload-resolution)*\n\n## Type inference\n\n*See proposal: [Type inference](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#type-inference)*\n\nMethod type inference involving collection expressions allows inferring the [*iteration type*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/statements.md#1295-the-foreach-statement) of a collection type. There is no support for inferring the containing *collection type*.\n\nThe *iteration type* is defined by `foreach` &mdash; it is the type of the `foreach`-able item. If a *collection initializer type* implements `IEnumerable` only and does not otherwise implement the `GetEnumerator()` pattern, the iteration type is `object`.\n\nInferences are made to the iteration type, independently for each element.\n\n```c#\nAsArray([null]);             // error: cannot infer T\nAsArray([1, 2, 3]);          // AsArray<int>(int[])\n\nstatic T[] AsArray<T>(T[] arg) => arg;\n```\n\n```c#\nbyte b = 1;\nint i = 2;\n\nArrayAndValue(new[] { b }, i); // error: cannot infer T\nArrayAndValue([b], i);         // ArrayAndValue<int>()\n\nstatic void ArrayAndValue<T>(T[] x, T y) { }\n```\n\nThe [*type inference*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/expressions.md#1163-type-inference) change is handled with two rules &mdash; one rule for *input type inference* and a matching rule for *output type inference*: see [proposal](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#type-inference).\n\n*Input type inference* is necessary for walking into the element expressions to infer from explicitly-typed lambda parameters, from tuple element types, or from nested collection expressions.\n```c#\nInputTypeInference([(int y) => { }]); // InputTypeInference<int>()\n\nstatic void InputTypeInference<T>(List<Action<T>> x) { }\n```\n\n*Output type inference* is necessary for inferring from the return type of lambdas and method groups in particular.\n```c#\nOutputTypeInference([() => 1]);       // OutputTypeInference<int>()\n\nstatic void OutputTypeInference<T>(List<Func<T>> x) { }\n```\n\n## Conversions\n\n*See proposal: [Conversions](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#conversions)*\n\nThere is a *collection expression conversion* from a collection expression to the following types. These represent the valid *target types* for a collection expression.\n\n* single-dimensional arrays\n* span types\n* types with a [*builder method*](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#create-methods)\n* generic interfaces implemented by `List<T>`\n* *collection initializer* types\n\n```c#\nint[]               a = [1]; // array\nReadOnlySpan<int>   b = [2]; // span\nImmutableArray<int> c = [3]; // builder\nIReadOnlyList<int>  d = [4]; // generic list interface\nList<int>           e = [5]; // collection initializer\n```\n\nFor all but collection initializer types, there must be an *implicit conversion* to the iteration type `T` for each *expression element* in the collection expression, and an *implicit conversion* to the`T` for the *iteration type* of each *spread element*.\n```c#\nstring[] a = [x, y, z];\nint[] b = [1, null];           // error: cannot convert 'null' to 'int'\nImmutableArray<int> c = [..a]; // error: cannot convert 'string' to 'int'\n```\n\nFor collection initializer types, there must be an applicable instance or extension `Add` method for each *expression element* in the collection expression, and an applicable `Add` method for an argument of the *iteration type* of each *spread element*.\n```c#\nMyCollection m = [1, \"2\", (object)3]; // error: no 'Add(object)' method found\n\nclass MyCollection : IEnumerable\n{\n    public void Add(int i) { ... }\n    public void Add(string s) { ... }\n    public IEnumerator GetEnumerator() { ... }\n}\n```\n\nCollection initializer types that implement `IEnumerable` only, are the one case of a target type without a strongly-typed *iteration type*.\n\nAdding target types is a *breaking change* for overload resolution and type inference.\n\n**Question**: Should \"generic interfaces implemented by `List<T>`\" be an explicit set instead?\n\n**Question**: Support conversions to `Memory<T>` and `ReadOnlyMemory<T>`?\n\n**Question**: Support conversions to *inline array* types? We'd need to validate the collection length at compile for *known length* collections.\n\n## Ref safety\n\n*See proposal: [Ref safety](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#ref-safety)*\n\nFor collection expressions of `ref struct` target types, the compiler *may* allocate the storage for the collection on the callstack when the following hold:\n* The collection expression has *local scope*\n* The collection has a *known length* and is not empty\n* The runtime supports *inline array* types\n\nAn empty collection requires no allocation for storage and has *global scope*.\n\nA `ReadOnlySpan<T>`, where `T` is one of several *primitive types*, and where the collection expression contains constant values only, is stored in the assembly data section and does not allocate at the use-site, and therefore has *global scope*.\n\nThe compiler will use heap allocation if the runtime *does not support* inline array types. The working group considered using `stackalloc` instead on older runtimes but managing `stackalloc` buffers would require unnecessary effort for what is otherwise an unsupported scenario.\n\n```c#\nPrint([]);               // empty collection, no allocation\nPrint([1, 2, 3]);        // primitive constants, assembly data, global scope\nPrint([x, y, z]);        // stack allocation, local scope\nPrint((int[])[1, 2, 3]); // heap allocation, global scope\n\nstatic void Print(ReadOnlySpan<object> values) { ... } // argument is implicitly scoped\n```\n\nThe span argument to a [*builder method*](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#create-methods) may be allocated on the callstack.\n```c#\nImmutableArray<int> ia = [x, y, z]; // stack allocate Create() argument\n\n[CollectionBuilder(typeof(ImmutableArray), \"Create\")]\npublic struct ImmutableArray<T> { ... }\n\npublic static class ImmutableArray\n{\n    public static ImmutableArray<T> Create(ReadOnlySpan<T> values) { ... }\n}\n```\n\nWhat about other uses of collection expressions as `ref struct` instances where the scope is not clear from the immediate context? Should those collection expressions be considered local or global scope?\n```c#\nstatic ReadOnlySpan<T> AsSpan2<T>(T x, T y)\n{\n    Span<int> s = [x, y]; // local scope or global?\n    return s;             // error if local scope\n}\n```\n\nFor that question, we considered three options - see [meeting notes](https://github.com/dotnet/csharplang/blob/main/meetings/working-groups/collection-literals/CL-2023-08-03.md):\n1. Use scope of target\n1. Determine scope of target based on usage\n1. Use local scope always\n\nOption 1 may go against user intuition that a collection expression represented as a span can be allocated on the stack, and as a result, it may be a *pit of failure*. To mitigate that, the compiler should report a diagnostic if heap allocation is required.\n\nOption 2 seems fragile since minor changes in the method (or external method signatures) may result in a collection expression being allocated on the heap. We'd need the diagnostic from option 1 to mitigate this. This option would also require the compiler to include flow analysis when checking ref safety.\n\nOption 3 ensures collection expressions that directly target spans can be allocated on the stack. However, this means such spans are not returnable unless the user explicitly converts to a heap-allocated type.\n```c#\nstatic ReadOnlySpan<T> Option3_AsSpan2<T>(T x, T y)\n{\n    return [x, y];    // error: span may refer to stack data\n}\n\nstatic ReadOnlySpan<T> Option3_AsSpan3<T>(T x, T y, T z)\n{\n    return (T[])[x, y, z]; // ok: span refers to T[] on heap\n}\n```\n\nThe working group recommendation is *option 3*: treat the collection expression as local scope, unless empty or cached in assembly data section.\n\n**Question**: When stack allocation cannot be used for a collection expression with span target type, should we fall back to a diagnostic and/or heap allocation?\n"
  },
  {
    "path": "meetings/working-groups/collection-literals/Compiler-synthesized-types.md",
    "content": "## Collection expressions - compiler synthesized types\n\nFollowup to https://github.com/dotnet/csharplang/blob/main/meetings/working-groups/collection-literals/Core-interface-target-type-proposal.md.\n\nwhen the user has one of the following types:\n\n1. `IEnumerable<T>`\n1. `IReadOnlyCollection<T>`\n1. `IReadOnlyList<T>`\n1. `ICollection<T>`\n1. `IList<T>`\n\nand they target that type with a collection-expression, we will choose a type on their behalf that satisfies the target interface.\n\n### Simple C# 12 approach\n\nSimplest solution for the short term (C# 12) would likely be:\n\n1. For `IList<T>` and `ICollection<T>` just use `List<T>`.\n\n    - Pros: The type is always available, tuned for the ecosystem and receives updates.  We likely could not do much better than it, and doing so would involve owning a large surface area of code to generate in the compiler.\n\n    - Cons: If we do this, it is likely some code out there will take a dependency on this.  As such, changing to another type in the future may risk breaks.  Those breaks would be around code doing undocumented and unsupported things, but would still likely happen and could cause customer ire.\n\n1. For `IEnumerable<T>`, `IReadOnlyCollection<T>` and `IReadOnlyList<T>`, synthesize a type for the user. The type should implement all those interfaces *and* `IList<T>` and `IList`.  These two interfaces help ensure the collections we produce are good citizens in the .Net ecosystem.  Lots of code checks for these two interfaces for varying reasons (perf optimizations, compat with winforms checks, etc.).  This also matches what the most common list-like BCL collections (`T[]`, `List<T>` and `ImmutableArray<T>`) do as well.  So this makes our type as usable as they are in practice.  Note: if the collection is empty, we can use just `Array.Empty<T>()`.\n\n    - Pros: We have broad power in the future to change our implementations, producing more specialized types, or deferring to potential future BCL apis.\n\n    - Cons: The BCL cannot specialize *as much* with an external synthesized type as they can with the types they know about.\n\n### Simple synthesized type for read-only interfaces\n\nFor C# 12, the simplest synthesized type we should likely go with when the user target-types to `IEnumerable<T>`, `IReadOnlyCollection<T>` or `IReadOnlyList<T>` is:\n\n```c#\n// TODO: Attributes?\n// [DebuggerDisplay(\"Count = {Count}\")]\n// [Serializable]\ninternal sealed class SimpleCompilerSynthesizedList<T> : IReadOnlyList<T>, IList<T>, IList\n{\n    private readonly T[] _values;\n\n    public CompilerSynthesizedList(T[] values)\n        => _values = values;\n\n    // IEnumerable/IEnumerable<T>\n\n    public IEnumerator<T> GetEnumerator() => ((IEnumerable<T>)_values).GetEnumerator();\n    IEnumerator IEnumerable.GetEnumerator() => _values.GetEnumerator();\n\n    // ICollection/ICollection<T>/IReadOnlyCollection<T>\n\n    public bool IsReadOnly => true;\n    public bool IsSynchronized => false;\n    public int Count => _values.Length;\n\n    public bool Contains(T item) => _values.Contains(item);\n    public void CopyTo(T[] array, int arrayIndex) => _values.CopyTo(array, arrayIndex);\n    public void CopyTo(Array array, int index) => _values.CopyTo(array, index);\n\n    public void Add(T item) => throw new NotSupportedException();\n    public void Clear() => throw new NotSupportedException();\n    public bool Remove(T item) => throw new NotSupportedException();\n\n    // Not sure what this should return:\n    public object SyncRoot => throw new NotSupportedException();\n\n    // IList/IList<T>/IReadOnlyList<T>\n\n    public bool IsFixedSize => true;\n\n    public T this[int index] { get => _values[index]; set => throw new NotSupportedException(); }\n    object? IList.this[int index] { get => _values[index]; set => throw new NotSupportedException(); }\n\n    public int IndexOf(T item) => ((IList<T>)_values).IndexOf(item);\n    public int IndexOf(object? value) => ((IList)_values).IndexOf(value);\n    public bool Contains(object? value) => ((IList)_values).Contains(value);\n\n    public int Add(object? value) => throw new NotSupportedException();\n    public void Insert(int index, T item) => throw new NotSupportedException();\n    public void Insert(int index, object? value) => throw new NotSupportedException();\n    public void Remove(object? value) => throw new NotSupportedException();\n    public void RemoveAt(int index) => throw new NotSupportedException();\n}\n```\n\nThis is just a wrapper around an array.  Non-mutating methods delegate directly to the array.  Mutating ones throw (as allowed by the documentation for these apis). `ICollection<T>.IsReadOnly` properly indicates the expected behavior here.\n\n### Future dictionary support\n\nWhen dictionary support is added to collection expressions, we will likely want to follow a complimentary path. Fortunately, dictionaries are likely simpler to support.  Namely:\n\nWhen when the user has one of the following types:\n\n1. `IReadOnlyDictionary<TKey, TValue>`\n1. `IDictionary<TKey, TValue>`\n\nand they target that type with a collection-expression, we will choose a type on their behalf that satisfies the target interface.\n\n1. For `IDictionary<TKey, TValue>` just use `Dictionary<TKey, TValue>`.  The pros/cons are the same as for using `List<T>` as the type chosed for `IList<T>/ICollection<T>`.\n\n1. For `IReadOnlyDictionary<T>` synthesize a type for the user.  Unlike the list-like collection space, there is no need for the synthesized type to implement anything beyond this surface area (as we are unaware of code that tries down-casting to `IDictionary<,>` to perform optimizations). The types generated here can be heavily optimized.  For example:\n\n    - We can synthesize specialized types for empty/small dictionaries (with no need for actual complex hashing strategies).\n\n    - The implementations could return themselves for `Keys`.  e.g. `IEnumerable<TKey> Keys => this;`\n\n### Future read-only list optimization ideas\n\n1. Optimize for small, or fixed, collection expression counts.  While we will already optimize the empty collection expression case, we can also optimize small counts like so:\n\n    ```c#\n    internal sealed class SmallCompilerSynthesizedList2<T> : IReadOnlyList<T>, IList<T>, IList\n    {\n        private readonly T _v1;\n        private readonly T _v2;\n\n        public SmallCompilerSynthesizedList2(T v1, T v2)\n            => (_v1 = v1, _v2 = v2);\n\n        public int Count => 2;\n\n        // remainder of methods optimized to just access fields directly.\n    }\n    ```\n\n    This would avoid the array indirection, as well as the extra space taken up by the array overhead itself.\n\n1. Optimize the synthesized collection for the common case where it is consumed only to be iterated one.  Specifically, for when the collection was passed *to* a consumer like:\n\n    ```C#\n    void DoWork(IEnumerable<int> values) { ... }\n\n    DoWork([a, b, c]);\n    ```\n    \n    In this case, we could synthesize the type like so:\n\n    ```c#\n    internal sealed class FastEnumerateCompilerSynthesizedList<T> : IReadOnlyList<T>, IList<T>, IList, /*new*/ IEnumerator<T>\n    {\n        private int _enumeratorIndex = -2;\n        private int _initialThreadId = Environment.CurrentManagedThreadId;\n\n        // actual underlying data, using whatever strategy we choose.\n\n        public IEnumerator<T> GetEnumerator()\n        {\n            if (_enumeratorIndex == -2 && _initialThreadId == Environment.CurrentManagedThreadId)\n            {\n                _enumeratorIndex = -1;\n                return this;\n            }\n\n            return new HeapAllocatedEnumerator(...);\n        }\n\n        public bool MoveNext()\n            => ++_enumeratorIndex < this.Count;\n\n        public T Current => this[_enumeratorIndex];\n    }\n    ```\n\n    This follows the same strategy we take when creating `IEnumerable<T>` instances with `yield` iterators.  There we also produce an `IEnumerable<T>` which is its own non-allocating `IEnumerator<T>` for the first consumer that tries to enumerate it on the same thread.\n\n    We would likely not do this for collections stored into a location (like into a field).  In that case, it seems more likely that the value might be enumerated many times.  So this would really only be beneficial for the collection-expressions passed to r-values.\n\n1. Optimize patterns found in arguments to produce collections that do not actually need storage for those values.  For example:\n\n    ```c#\n    IEnumerable<int> values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n\n    // Can be emitted as:\n    IEnumerable<int> values = Enumerable.Range(1, 10);\n\n    // Or with a specialized compiler synthesized impl that does the same.\n    ```\n\n    Similar types of optimizations may be possible depending on how deep we want to go with analysis of the argument values.\n\n1. Optimize collection expressions of blittable constants.  For example:\n\n    ```c#\n    IEnumerable<char> values = ['a', 'b', 'c', 'd', 'e', 'f'];\n\n    // Can be emitted as:\n\n    internal sealed class BlittableWrapperX : IReadOnlyList<T>, IList<T>, IList\n    {\n        // Has no-alloc optimization\n        private static ReadOnlySpan<char> __values => new char[] { 'a', 'b', 'c', 'd', 'e', 'f' };\n\n        public IEnumerator<char> GetEnumerator()\n        {\n            for (int i, n = 6; i < n> i++)\n                yield return __values[i];\n        }\n    }\n    ```\n"
  },
  {
    "path": "meetings/working-groups/collection-literals/Core-interface-target-type-proposal.md",
    "content": "## Collection expression conversion to specific interface types.\n\n### The problem we are trying to solve\n\nWhat does it mean when the user has one of the following five types (the types implemented by our core list-like-types like `T[]`, `List<T>`, `ImmutableArray<T>`):\n\n1. `IEnumerable<T>`\n2. `IReadOnlyCollection<T>`\n3. `IReadOnlyList<T>`\n4. `ICollection<T>`\n5. `IList<T>`\n\nand they try to convert a collection-expression to it.  For example:\n\n```c#\n// Passing to something that can only read data.\nvoid DoSomething(IEnumerable<int> values) { ... }\nDoSomething([1, 2, 3]);\n```\n\n// or:\n\n```c#\nclass Order\n{\n    // Intended to be mutated.\n    public IList<OrderId> ProductIds { get; } = [];\n}\n```\n\nBecause these are interfaces, unless the BCL chooses to put the `[CollectionBuilder]` attribute on them to bless a particular way of creating them, then the language itself needs to have understanding here to do the right thing.\n\nNote: these interfaces are already well known to the language.  '1' is well known because of the built-in support for creating iterators.  1-5 are well known as we understand and respect that any array instance is [implicitly convertible](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/conversions.md#1028-implicit-reference-conversions) to any of the above:\n\n> From a single-dimensional array type `S[]` to `IList<T>`, `IReadOnlyList<T>`, and their base interfaces, provided that there is an implicit identity or reference conversion from S to T.\n\n\n### Context\n\nCollection expressions aim to be a substantively 'complete' replacement for the myriad of ways people create collections today.  They are intended to be used for the *vast majority* of cases where people use collections, and default (as much as possible) to choices that fit the needs of the majority of the user base.  A strong desire here is to not add \"just another way to create a collection\" alongside everything else, but to provide a singular *replacement* that is then suitable to move almost all code wholesale to.  It aims to replace *all* of the following forms:\n\n1. `new T[] { ... }`\n1. `new[] { ... }`\n1. `stackalloc T[] { ... }`\n1. `stackalloc[] { ... }`\n1. `new CollectionType<Dictionary<(int x, int y), string[]>> { ... }`\n1. `new() { ... }`\n1. `ImmutableCollectionType.Create(...)`\n1. `ImmutableCollection.CreateBuilder(); builder.Add(...); ...; builder.ToImmutable()`.  (Wasteful, and doesn't work for base cases like a field initializer).\n1. And more... including things like: `ImmutableArray<T>.Empty.Add(x).AddRange(y).etc()`\n\nAn examination of the BCL and the top 20 NuGet packages (Newtonsoft, EF, Azure, Castle, AWS, AutoMapper, and more), all of which are >400m downloads, reveals very relevant data here.  Methods taking those interface collections account for roughly 28% of all methods taking some collection type (arrays, spans, other BCL collections), and `IEnumerable<T>` alone accounts for 25% of the collection-taking methods.  This is not surprising as our own practices, and general design guidance we give the community, are simply that:\n\n> Methods should be permissive in what they accept, and be precise in what they return.\n\n`IEnumerable<T>` (and our other collection interfaces) act as that permissive type that we and our ecosystem have broadly adopted. Indeed, if it were not for `(params) T[]` (a full 50% of all collection-taking methods), `IEnumerable<T>` would be the most commonly taken collection by far for the ecosystem.\n\nIdeally, we would ship with support for everything, but we've currently made judicious moves from C#12 to C#13 based on complexity, but also based on impact.  For example, `Dictionary expressions` were moved to C#13 to lighten our load, and because data indicates that APIs that consume those dictionary types are only <3% of all apis that take collections in the first place.  `Natural type` support has also been pushed out because the complexity is felt to be substantive enough to warrant more time.\n\nWith how important these interface types are though, we do not believe pushing out from C# 12 will allow us to ship a viable and coherent story to customers.  \n\n### What factors are at play?\n\nIn any interesting design, there are many factors that must be assessed and considered as a whole.  For collection expressions, these include but are not limited to:\n\n1. Simplicity. Ideally the feature works in a fashion that is both simple to explain and simple for users to understand. Using some of our modern terminology, we'd like to avoid 'decoder rings' when people use it.\n\n2. Universality.  This restates the background context. We want to meet the literal 97% case at launch, not the 69% which would be the case if interfaces can't be targeted.  This means needing good stories for arrays, spans, BCL concrete collections *and* BCL core interfaces.\n\n3. Brevity.  It is a strong goal of this feature that users be able to just write the simple, idiomatic, collection expression form without the need to do things like add coercive casts to commonly appease the compiler.  Specifically, for casts, once you add them (e.g. `(List<int>)[1, 2, 3]`) then the benefit of the feature as a whole is vastly diminished. In these cases, the new form isn't substantively better than the existing form (just 2 characters saved over `new List<int> {1, 2, 3}`).  Unlike other features, the cliff here is very steep, often fundamentally negating the idea that this is a valuable feature in the first place.  Many parts of the design (especially broad adoption of target-typing) have been entirely around ensuring users can just write the simple expression form and almost never have to do things to appease the language.\n\n4. Performance. A core pillar of collection expressions that we are both evangelizing it by, and which we are seeing customers resonate with, is the idea of\n\n    > Absent external information unavailable to the compiler, the compiler should almost always do as well or better than the user could.  Often much more so.  And almost certainly with clearer code for the user to write.\n    \n    Because the user can write a simple `[a, b, c, d, e]` expression, without having to explicitly state what is going on, and because we can provide so much smart understanding to each situation, we can heavily optimize.  For example:\n\n    - If the above 5-element collection were converted to an `ImmutableArray<T>`, our emitted code could would practically always be better than users using normal construction patterns.  We can also greatly leverage extremely fast and efficient systems under the covers (like synthesizing `Inline-Arrays` types) that would generally be extremely ugly and painful for users to do themselves.\n\n    - What we emit can adopt ecosystem best practices around performance.  For instance, `[]` can emit as efficient singletons, not causing undesirable allocations.\n\n    While many customers will not care about performance to this level, we still want customers that do to have confidence in this feature (and we definitely do not want to see the feature immediately banned).\n\n    It would also be highly unfortunate if we shipped and our own analyzers immediately flagged the usage as being a problem.\n\n    Finally, part of performance means being a good .NET citizen.  So the collections we produce should be able to pick up the optimizations the BCL has today for collection types.\n\n5. Safety.  Specifically, keeping data safe from undesirable mutation. We broadly think of users as being in two categories.  The first category generally doesn't consider it to be a safety concern to return mutable instances via read-only interfaces, and thus would suffice with any solution on our part.  However, the second group (which is likely smaller, but present, vocal, and influential) absolutely wants a roadblock at runtime to keep their exposed data safe from mutation.  Similar to the perf concerns, we believe we need a solution for this group that fits their expectations, puts them at ease, and isn't immediately banned (or flagged by analyzers) for doing unsafe things.\n\n## Options\n\nBased on feedback from LDM and the working group meetings, we tried to whittle a large number of options down to a reasonable few that we feel warrant discussion and comparison.\n\n### Option 1: Disallow target typing to these interface types.\n\nThis is the simplest and cheapest option we have at our disposal.  We could just say that these assignments would be an error, and force the user to specify the type they want to generate.  However, we believe this produces a negative result for every factor at play above.\n\nSpecifically:\n\n```c#\nvoid DoSomething(IEnumerable<int> values) { ... }\n\n// Not allowed.\nDoSomething([1, 2, 3]);\n\n// Write this instead:\nDoSomething((List<int>)[1, 2, 3]);\n```\n\nand\n\n```c#\nclass Order : ITaggable\n{\n    // Not allowed:\n    public IReadOnlyList<OrderTag> Tags { get; } = [];\n\n    // Write this instead:\n    public IReadOnlyList<OrderTag> Tags { get; } = (ImmutableArray<OrderTag>)[];\n\n    // Which is worse than just:\n    public IReadOnlyList<OrderTag> Tags { get; } = Array.Empty<OrderTag>();\n}\n```\n\nFirst, this immediately fails the simplicity and universality concerns. From our own experience, and the data about the ecosystem, we know that users will need to interface with, well, interfaces :).  This will be an immediate hurdle that will deeply undercut the value of this feature space, potentially even deeply tainting it for the future.  This also undercuts the core design principle we give to people of \"be permissive in what you accept\".  It would now be:\n\n> Be permissive in what you accept, but also accept a concrete type so that it can be called using collection expressions\n\nSecond, collection expressions would not provide any sort of actual useful syntax or brevity for users in this case.  Because an explicit type would have to be provided, users would be left with syntax with nearly the same complexity and verbosity as what they would have to write today.  Users seeing this would rightfully ask:\n\n> Why would I pick this new form, that is really just the same as the old form, just with some tokens tweaked?\n\nPerformance and safety though would be mostly neutral here.  Users who did not care about either would likely just use `List<T>`, and users who did would pick something appropriate for their domain.  However, this would still be a small tick in the 'negative' category as our claims about us making the \"right, smart, best choices\" for users would be undercut by then forcing the user to have to make those choices themselves.\n\n### Option 2: Specify explicit concrete types to use for the possible interface targets.\n\nThe idea here is to pick either a single concrete type, or potentially a few distinct types, to support constructing any of the above interfaces.  Examples of types that could work would be:\n\n1. `List<T>`\n2. `T[]`\n3. `ImmutableArray<T>`\n\nFor the purposes of discussion, we'll use `List<T>` as the example of the type to pick.  If we were to go this route, it would likely need to be at least the choice picked for `ICollection<T>/IList<T>` as otherwise you could create those mutable-types, and then find yourself unable to mutate them.\n\nIn practice this would look like:\n\n```c#\nvoid DoSomething(IEnumerable<int> values) { ... }\n\n// Legal. Is equivalent to `DoSomething(new List<int> { 1, 2, 3 })`\nDoSomething([1, 2, 3]);\n```\n\nand\n\n```c#\nclass Order : ITaggable\n{\n    // Legal. Is equivalent to: `Tags { get; } = new List<OrderTag>();\n    public IReadOnlyList<OrderTag> Tags { get; } = [];\n}\n```\n\nThis option *nails* the \"simplicity\", \"universality, and \"brevity\" aspects we are trying to solve.  Explaining to users what happens in these cases is trivial:\n\n> It makes a `List<T>`.  The part-and-parcel type of .NET that you've known about and have used for nearly 20 years now.\n\nSimilarly, it can be used for *all* these APIs that take in one of these interfaces.  Finally, it always allows the nice short syntactic form that really sells people on why collection expressions are a superior choice to use over practically every other collection creation construct they can use today.\n\nHowever, this also falls short in both the 'performance' and 'safety' domains.  Indeed, it does so so egregiously, that our own analyzers will flag this as inappropriate and push both the users who run these analyzers, and the users who just care about these facets of development, away from feeling they can trust this feature to live up to its recommendation as making the \"right, smart, best choices\" for them.   It will also likely lead to negative-evangelization, where voices in the community steer people away from the feature as a whole, proclaiming it as harmful.\n\n#### Option 2 - Performance\n\nFor \"performance\", `List<T>` has particular issues: \n\n1. It *already* comes with two allocations for itself.\n2. Getting an iterator for it (through the `IEnumerable<T>.GetEnumerator` path) will produce another allocation.\n3. It has excess overhead internally to support both being able to grow, and has overhead internally to ensure it is not mutated while it is being iterated.\n4. It allocates for the incredibly common case of an empty collection.\n\nWhile `List<T>` is a great type when you need flexibility and permissiveness, it is not a good choice when you know precisely what you are producing, and you have no need to access the flexible, mutation-oriented, capabilities it provides.\n\n#### Option 2 - Safety\n\nFor \"safety\" `List<T>` is also an unacceptable choice for many (and our own analyzers will push you away from it).  Users who expose data safely today through the readonly interfaces `IEnumerable<T>/IReadOnlyCollection<T>/IReadOnlyList<T>` today will find that they cannot effectively move to collection expressions.  They will have to keep the highly verbose and clunky code they have today, to use types like `ImmutableArray`, or things like `new List<int> { a, b, c }>.AsReadOnly()`.  This will make collection-expressions feel half-baked for these users, again undercutting the story that this new feature makes the  \"right, smart, best choices\" for the user.  It will also force them to lose the brevity and consistency of being able to use collection-expressions with confidence everywhere.\n\nNote: we could potentially choose *different* types depending in the end interface we were assigning to.  For example, `List<T>` for the mutable ones, and `ImmutableArray<T>` for the non-mutable ones.  However, this would certainly now start getting less simple, with the need for a 'decoder ring' rising.  It also likely would not play nicely with when we get to dictionaries.  While `Dictionary<K,V>` would be a natural analog to `List<T>`, with great familiarity to the ecosystem, `ImmutableDictionary<K,V>` would be a disaster in a great number of cases as the read-only dictionary analog.\n\n### Option 3: Do *not* specify concrete types to use for the possible interface targets.\n\nDeep discussion around the problems with Option 2 led the WG and partners to come up with a variant of '2', leveraging the parts it does well at, while curtailing its drawbacks.\n\nFirst, it's important to look at the surface area of the read-only interfaces `IEnumerable<T>/IReadOnlyCollection<T>/IReadOnlyList<T>` and see that it is only the following *three* members:\n\n```c#\n{\n    public IEnumerator<T> GetEnumerator(); // and the non-generic equivalent.\n    public int Count { get; }\n    public T this[int index] { get; }\n}\n```\n\nBasically, exactly the same as `IEnuemrable<T>` with *just* enough to think of it as an indexable sequence. With that in mind the rules for target-typing an interface would be as follows:\n\n1. We take a page from what we do today *already* for `IEnumerable<T>` and `yield` iterators, and we say that if you have a target-type of `IEnumerable<T>/IReadOnlyCollection<T>/IReadOnlyList<T>`, the language will state that you have no guarantee on any particular type being used at all.  But you will get an instance that efficiently implements the API surface area requested.  For example, the type that is used could be:\n\n    - An unnameable, compiler synthesized type.  This could be something like what we do with arrays today (and Inline-Arrays for collection-expressions) where a specific type is generated for each specific size (including using Inline-Array tricks where available), producing values with practically no size overhead.  Or it could potentially be a generalized unnameable type that has contiguous storage (like an array) for the elements, but wraps it safely.\n\n    - An unknown type provided by the runtime.  For example, through a method like `IEnumerable<T> Create(ReadOnlySpan<T> values)` (i.e. the builder-pattern applied to these interfaces).  This would allow the runtime itself to choose the most optimal internal representation for the data, and would also allow for it to do things like implement internal APIs it can query for specialized scenarios, or directly cast to the underlying type to do things like grab the contiguous data directly as a span.\n\n    - Importantly, both of the above are possible, and we could even do one, then migrate to the other over different releases.  Because all that user could could ever know about is the target-interface type, there would be no source, binary, or runtime breaking changes here.  This means that in C# 12 we could use a compiler-synthesized type.  But also then migrate over to a BCL api if the BCL would like to own a canonical API for this purpose.\n\n    - Also, we have enormous flexibility here in terms of what does happen.  For example, if the compiler synthesizes types, it could choose a handful to make extremely efficient (for example, for collections expression of less then eight elements), and then fallback to a single type that handled the rest of the cases.  These approaches could change over time based on data (similar to how we've adapted how we emit switch statements/expressions, and hashing). \n\n2. For a target-type of `ICollection<T>/IList<T>`, we would state the same thing.  That no type was guaranteed, but you would be certain to get an good implementation that supported mutation.  In practice though, we would be *highly* likely to just default this to `List<T>` as it would satisfy these requirements, while being an excellent implementation that is already heavily optimized for the flexible cases these interfaces would need.  This would also lower the burden on the compiler side in terms of codegen and complexity.\n\nEffectively, this *intentionally* bifurcates the interfaces into two important categories.  The 'read only' interfaces, which support no mutation, and the 'mutable interfaces' which do.  Our feeling is that for the latter, there is no real better choice than `List<T>`.  It is the 'bread and butter' type the BCL has for this purpose that the entire ecosystem understands and feels comfortable with.  For the domain of mutable-sequences, it is extremely good and does its job well.\n\n\nSpecifically:\n\n```c#\nvoid DoSomething(IEnumerable<int> values) { ... }\n\n// Allowed, an efficient type is used here, but you will not know what it is, or be able\n// to take a dependency on it.\nDoSomething([1, 2, 3]);\n```\n\nand\n\n```c#\nclass Order : ITaggable\n{\n    // Legal. An efficient 'empty', read-only singleton will be used.\n    public IReadOnlyList<OrderTag> Tags { get; } = [];\n\n    // Legal. Equivalent to: `{ get; } = new List<int>()`, \n    // though we technically would not guarantee `List<T>`\n    public IList<int> ProductIds { get; } = [];\n}\n```\n\nWith respect to the factors we care about, here's how the above falls out:\n\nFor 'brevity/universality', this still strongly satisfies our goals.  Users will be able to use the succinct collection-expression form for all these APIs with ease. However, compared to option 2, we now see wins in both safety and performance. \n\n#### Option 3 - Safety\n\nStarting with safety, we now have a good option for everyone exposing data through any of those three read-only interfaces.  Data is safe by default, which is good for the users that care, and non-harmful for the users that do not care.  Users who care are then satisfied that they can trust this feature and that it lives up to the stated goal that it will make the smart choices they can depend on and they do not have to ban this feature, or recommend others steer away from it.  Importantly, analyzers do not trigger, preventing our own tooling from pushing people away from using our cohesive story here.\n\nThis approach also naturally extends out to when we do dictionary-literals.  There, it will also be the case that for `IReadOnlyDictionary<TKey, Value>` we will not want to expose a mutable type (like `Dictionary<TKey, TValue>`) for safety reasons.\n\n#### Option 3 - Performance\n\nWhile the wins now with 'safety' are definitely welcome, the largest benefits come in the \"performance\" category.\n\nSpecifically, not having to name a particular type for the read-only interfaces opens up many areas of optimization that would simply be unavailable when having to pick an existing generalized type. This would also live up to the promise that we will do an excellent job with perf, and that it would be *very* hard for a user to do the same, and practically impossible for them to do so with simple syntax.  Specifically, all of the following are available as things we could do to heavily optimize here when target-typing `IEnumerable<T>/IReadOnlyCollection<T>/IReadOnlyList<T>`.\n\n1. Empty collection expressions can always be collapsed down to a single empty singleton (per `T` element type) across the entire program.\n\n1. We can use features like inline-arrays to generate instances that inline all their elements and are no larger than space for the elements themselves.  A count would not even need to be stored as it could just be hard-coded as the value returned by `int Count { get; }`.  While this might generate many types in the assembly (one type per unique count), it's worth noting that this is what we *already* do for arrays *today*, and what we will be doing for the inline-array types we generate for spans/params-spans.\n\n1. We can borrow a trick from `yield iterators` where the iterator returned from `IEnumerator<T> GetEnumerator()` *reuses* the `this` instance to be its own iterator *if* it has never been iterated yet and the calling thread is the same one that generated the `IEnumerable<T>`.  This means that if you have:\n\n    ```c#\n    DoSomething([1, 2, 3]);\n    ```\n\n    Then this may be a *single* allocation, *including* for when it is immediately iterated.\n\n1. We do not need any code anywhere that sits in service of supporting variable sizes, or supporting mutation.  This means no overheads of checks, or invalidation of iterators, etc.\n\n1. Collections full of constants, with well-known patterns, could potentially be implemented without allocating contiguous storage for them.  For example `[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]` could be generated as `Enumerable.Range(1, 10)`, and so on.\n\n    Overall, by not specifying explicit types, we actually open up a wealth of optimizations that both our own compiler or the BCL can choose to do.  While synthesizing types may initially seem concerning, we do already do it for many cases today, including when we already generate `IEnumerables` with `yield`, and also for every array creation that has an initializer (like `new int[] { 1, 2, 3 }`).  The surface area here is also exceptionally small.  There are only three extremely basic operations to support (`GetEnumerator(),Count,this[]`).  So the burden on the compiler to generate types for this feels completely acceptable, especially for the large wins we can achieve.  \n\n    There are still benefits though with the BCL taking this over.  Specifically, if they do so, they can then implement internal interfaces they may query for.  Or they can use their knowledge of the exact internal types they use to get to the underlying data in even more efficient ways (including potentially being able to grab spans to it).  That said, if there was such an API to grab a span from an collection type, it would be good for that to be public so that the compiler could just implement that itself.\n\n    This approach also naturally extends out to when we do dictionary-literals.  There, it will also be the case that for `IReadOnlyDictionary<TKey, Value>` we (and the BCL) could likely heavily optimize.  For example, it will often be the case that read-only dictionaries may be small (or empty).  Having specialized implementations that eschew complex wasted-space strategies for contiguous linear lookup may be highly beneficial.  Reserving that read-only implementations may be unknown, specialized, types allows for these sorts of wins to happen automatically.\n\n    Ultimately, by being an internal implementation detail, we also have the flexibility to pick and choose any of these optimizations we feel worthwhile at any point.  We can, for example, leave these (or more) to C# 13, 14 and beyond.  And data can be used to help identify potential optimizations and indicate how worthwhile they would be.\n\n#### Option 3 - Simplicity\n\nFinally, we come to the one area where the above proposal ticks downward: \"simplicity\".  It is certainly the case that \"Use `List<T>` for everything\" approach is much simpler to explain.  However, we believe the above to be *acceptably* complex to explain, with enough benefits to point at to convince users that this was the right choice for them.  Specifically, we believe the best way to explain it is:\n\n1. Are you using one of the mutation-supporting interfaces (`ICollection<T>/IList<T>`)?  If so, you'll get something great.  A high quality mutable type that supports that API and will work great with the rest of the ecosystem.\n2. Are you using the read-only interfaces (`IEnumerable<T>/IReadOnlyCollection<T>/IReadOnlyList<T>`)?  If so, you get a *safe*, *high performance* impl that supports the API shape needed.  This is right in line with what we already do for you today when you use `IEnumerable<T>` with `yield`.\n\n    Your instance will be safe, with no concern about data changing out from you unexpectedly.\n    \n    And, by switching to collection-expressions you will just get performance wins *for free*.  In other words, compared to virtually any other approach you're taking today (outside of hand-writing custom types for everything, and initializing them all with exceptionally ugly code), this system will work better.  And, if you are the user that was hand-writing everything before, this system is also so much better because now you get the same perf, with exceptional clarity and brevity.\n\nWe feel there is nothing particularly strange or difficult to explain here to users. C# and .Net is replete with APIs and patterns that do not let you know the specific type being constructed. For example, from C# 3 onwards, `Linq` very much put forth the idea of:\n\n> You will just get an `IEnumerable<T>`, but you won't know what the actual concrete type is. This abstraction also allows the underlying system to heavily optimize.  `Linq` itself uses this to great effect, using many different specialized implementations under the covers to provide better performance.\n\nSimilarly, with several of our latest releases, we've started more heavily pushing the idea that the language has smart semantics that will do what you ask it to do, very efficiently, without overspecifying exactly how that must be done.  Patterns in general, and List-patterns (the analog to list-construction) heavily push this idea, stating explicitly that assumptions about well-behavedness will be made and that the compiler will pick the best way to do things.\n\nSo we feel that collection-expressions fit well into both the historical, and modern, way that C# and .Net works.  Where you can declaratively tell us what you want (like with `Linq`), and the systems coordinate to produce great results by default.\n\n## Conclusion\n\nBased on all of this, the working group strongly thinks that we should go with option 3 and that we should do so in C#12.  The other options come with enormously painful caveats that heavily undercut the core messaging of this feature entirely.  Missing C# 12 on this also dramatically limits the usefulness of this feature space, and will immediately cause customer confusion and frustration that such a core scenario feels unaddressed by us in the initial release.\n"
  },
  {
    "path": "meetings/working-groups/collection-literals/LDM-questions-2023-08-15.md",
    "content": "## Collection expression working group questions and suggestions\n\n### Ref safety\n\nDiscussion and examples do not apply to ReadOnlySpan of constant, blittable data.  That always has global-scope.\n\nQ: What should the ref-safety scope be for:\n\n```c#\nSpan<int> s = [x, y, z];\n```\n\nThere are two primary directions we can go here:\n\n1. Analyze how the variable is use that to inform the scenario. Specifically, we could use flow analysis to determine what scope a variable should have.  For example:\n\n    ```c#\n    void M()\n    {\n        // Local scoped, s does not escape.\n        Span<int> s = [x, y, z];\n        foreach (var v in s)\n            Console.WriteLine(v);\n    }\n    ```\n\n    ```c#\n    ReadOnlySpan<int> M()\n    {\n        // Global scoped, since 's' escapes out of 'M'.\n        Span<int> s = [x, y, z];\n        UseSpan(s);\n        return s;\n    }\n    ```\n\n    Pros: Users can write spans + collection-expressions in a very simple fashion, and have the code \"just work\".\n\n    Cons: Unclear about what's actually happening.  Minor changes could lead to very different outcomes. Analysis is likely also very non trivial (on the order of major flow analysis work).  Scoping constraints would have to flow backwards from escape points back to the origination point.  For example:\n\n    ```c#\n    ReadOnlySpan<int> M()\n    {\n        Span<int> s1 = [x, y, z];\n        Span<int> s2 = X(s1);\n        return s2;\n    }\n\n    Span<T> X<T>(Span<T> s) => s;\n    ```\n\n    Here, 's2' must have global scope in order to escape 'M'.  But that then must flow that constraint into the invocation of 'X'.  This will then have to flow the constraint into 's1' to finally choose that s1 is globally scoped.  Complexity rises greatly with all flow-analysis constructs. \n\n2. Decide on the scope directly from the declaration, instead of depending on how it is used.\n\n    - Option A: Ref-struct local has global scope by default.  To have local-scope, add the `scoped` keyword:\n\n        ```c#\n        void M()\n        {\n            // 's' has 'global scope' but does not escape.  Will allocate.  If they want stack-allocation, add `scoped`\n            Span<int> s = [x, y, z];\n            foreach (var v in s)\n                Console.WriteLine(v);\n        }\n        ```\n\n        Ideally compiler tells the user to make these variables `scoped` when it can be.\n\n        Pros: User gets the scoping they explicitly request.  When scope can be narrower, they are informed.\n\n        Cons: Analysis is similarly complex due to requisite reverse flow analysis.  Also, WG believes the default position of users is to want a span + collection-expression to have local scope and be stack allocated.  However, to get that, users will have to write:\n\n        ```c#\n        void M()\n        {\n            // 's' has 'local scope'\n            scoped Span<int> s = [x, y, z];\n            foreach (var v in s)\n                Console.WriteLine(v);\n        }\n        ```\n\n        This feels punishing to the common/default case that users will want.  Importantly, it means that if a user wants to switch off from `stackalloc` to collection-expressions they get less pleasant code. \n\n    - Option B: Collection expressions of `ref struct` type have local scope.\n\n        ```c#\n        void M()\n        {\n            // 's' has 'local scope'.  Will get stack allocated.\n            Span<int> s = [x, y, z];\n            foreach (var v in s)\n                Console.WriteLine(v);\n        }\n        ```\n\n        Pros: A very simple and easy rule to explain to users.\n\n        Default, simple, syntax gives best performance.\n\n        No need for any sort of complex flow analysis.  Existing analysis \"just works\" and lets the user know if there are any problems.\n\n        When code needs to allocate on the heap it is clear in the code that this is happening.\n\n        Cons: if the user *does* want the span to have global scope, then they have to be explicit about that:\n\n        ```c#\n        Span<int> M()\n        {\n            // Either:\n            Span<int> s1 = (int[])[x, y, z];\n            Span<int> s1 = new[] { x, y, z };\n            \n            return x ? s1 : s2;\n        }\n        ```\n\n        However, WG believe this is a good thing.  This will be the rare case, and having *it* be slightly more verbose is unlikely to be a burden.  In other words, we want the common, fast, case to sing with collection-expressions, while the less common, slower, case is ok to pay a small price.\n\nWorking group suggestion:\n\nOption 2B. Collection expressions of `ref struct` type have local scope.\n\n### Overload resolution priority\n\nWe know we want a `Span<T>` overload to be preferred over a `T[]` overload or an interface overload ( `IEnumerable<T>/IReadOnlyCollection<T>/IReadOnlyList<T>/ICollection<T>/IList<T>`).\n\nHowever, we have options on how to specify things to get the above outcome.\n\n1. Option A: Span/ReadOnlySpan is preferred over arrays and those specific interfaces when the iteration type of the span is implicitly convertible to the iteration type of the array or interface.\n\n    The general intuition here is Spans/Arrays/Interfaces have a natural ordering we can make an airtight case around.  Specifically:\n\n    Spans are better than arrays as they're the fast form that can subsume arrays and also be on the stack.\n\n    Arrays are better than all those interfaces because it's a more specific type that implements the interface.\n\n    Spans are better than interfaces both because they're already better than arrays, and because they can be thought of as morally implementing those interfaces (which may also be literally true in the future).\n\n    However, this has oddities:\n\n    ```c#\n    void M(List<int> list);\n    void M(ReadOnlySpan<int> list);\n\n    M([1, 2, 3]); // Ambiguous.\n    ```\n\n    This seems odd.  If there are collection overloads, and one is concrete, and one is a span, we would say it was ambiguous, when it seems clear that one exists for perf and should be preferred.\n\n1. Option B: Same as option A, except that it applies to all ref-structs, not just Span/ReadOnlySpan.\n\n    The general intuition is that anything in the ref-struct realm should be considered fast/span-like and then fit into this bucket.  \n\n    With this approach the following would also hold:\n\n    ```c#\n    ref struct ValueList<T> { ... }\n\n    void M(int[] list);\n    void M(ValueList<int> list);\n\n    M([1, 2, 3]); // calls the ValueList version.\n    ```\n\n    However, like Option A, this would become ambiguous with other concrete overloads:\n\n    ```c#\n    ref struct ValueList<T> { ... }\n\n    void M(List<int> list);\n    void M(ValueList<int> list);\n\n    M([1, 2, 3]); // Ambiguous.\n    ```\n\n1. Option C: `ref struct` collection types are preferred over non-`ref struct` collection types when there is an implicit conversion from the iteration type of the `ref struct` type to the iteration type of the non-`ref struct` type.\n\n    The general intuition here is that if the user provides a ref-struct overload that that is the 'fast' option, and thus would be preferred over other types.  This seems like the 'more likely than not' case that extends beyond just Span/ReadOnlySpan. Also seems to align with things like interpolated string handlers over System.String.\n\n    For example:\n\n    ```c#\n    ref struct ValueSet<T> { ... }\n\n    void M(ValueSet<int> list);\n    void M(HashSet<int> list);\n\n    M([x, y, z]); // calls the ValueList version.\n    ```\n\n    The general intuition here is that if the user provides a ref-struct overload that that is the 'fast' option, and thus would be preferred over other types.  This seems like the 'more likely than not' case that extends beyond just Span/ReadOnlySpan.\n\nWG opinion: Leaning towards Option C, prefer ref-structs over all other types.\n\n### Add support for `Memory<T>`\n\nShould we add support for `Memory<T>` in C# 12.  For example:\n\n```c#\nMemory<int> m = [1, 2, 3];\n```\n\nBased on last LDM meeting, we are deciding \"We will do if we have time, but it is low pri and can be cut if we do not have the time/resources\"\n\n1. We made a similar decision for inline-array types.  These types are not in the core majority of apis/use-cases, and can come later.\n\n1. Adding support for a new type *is* a breaking change.  However, this is unavoidable in this space as any type can become a collection type in the future (through usage of the `[CollectionBuilder]` attribute).  As such, we do not think it critical to front load support to avoid this problem.\n\n1. In practice `Memory<T>` is for async versions of `Span<T>` methods.  These are not generally overloads as one method is `Foo(Span<T>)` while the other is `FooAsync`.  So the concern about overload ambiguity in the future is low.\n\nIf we do support this in C# 12 we will do so through special-casing this exact type.  However, in the future we will likely add support for `CollectionBuilderAttribute` to point at the existing construction member like so:\n\n```c#\n[CollectionBuilder(typeof(Memory<>, \"op_Implicit\"))]\npublic readonly struct Memory<T>\n{\n    public static implicit operator Memory<T>(T[]? array) { ... } \n}\n```\n\nWe would then define the Collection-Builder pattern as doing array-ownership-transfer (where the compiler would create the array and then give it to the final collection to own).  This would also likely apply to `ImmutableArray<T>` in the future as well, as it would point to `ImmutableCollectionMarshal.AsImmutable(T[])`\n"
  },
  {
    "path": "meetings/working-groups/collection-literals/collection-expressions-inferred-type.md",
    "content": "# Collection expressions: inferred type\n\n## Summary\n\nInferring an element type for collection expressions based on the elements in the collection, and choosing a containing collection type, would allow using collection expressions in locations that are implicitly-typed.\n\n## Motivation\n\nInferring an element type would allow collection expressions to be used in `foreach` and in spread elements.\nIn these cases, the inferred *element type* is observable, but the containing *collection type* is not observable.\n\n```csharp\nforeach (var i in [x, y, z]) { }\n\nint[] items = [x, y, .. b ? [z] : []];\n```\n\nIf the compiler chooses a specific containing *collection type*, collection expressions could be used in other implicitly-typed locations where the collection type is observable.\n\n```csharp\nvar a = [x, y];                       // var\nvar b = [x, y].Where(e => e != null); // extension methods\nvar c = Identity([x, y]);             // type inference: T Identity<T>(T)\n```\n\n## Inferred element type\n\nThe *element type* `E` inferred for a collection expressions is the [*best common type*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/expressions.md#116315-finding-the-best-common-type-of-a-set-of-expressions) of the elements, where for each element `Eᵢ`:\n* If `Eᵢ` is an *expression element*, the contribution is the *type* of `Eᵢ`. If `Eᵢ` does not have a type, there is no contribution.\n* If `Eᵢ` is a *spread element* `..Sᵢ`, the contribution is the [*iteration type*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/statements.md#1295-the-foreach-statement) of `Sᵢ`. If `Sᵢ` does not have a type, there is no contribution.\n\nIf there is no *best common type*, the collection expression has no type.\n\nInferring the element type is sufficient for scenarios such as `foreach` and spreads where the *collection type* is *not observable*. For those cases, the compiler may use any conforming representation for the collection, including eliding the collection instance altogether.\n\n```csharp\nforeach (var i in [1, .. b ? [2, 3] : []]) { } // ok: collection of int\nforeach (var i in []) { }                      // error: cannot determine element type\nforeach (var i in [1, null]) { }               // error: no common type for int, <null>\n```\n\n## Natural collection type\n\nFor implicitly-typed scenarios where the *collection type* is observable, the compiler needs to choose a specific collection type in addition to inferring the element type.\n\nThe choice of collection type has a few implications:\n- **Mutability**: Can the collection instance or the elements be modified?\n- **Allocations**: How many allocations are required to create the instance?\n- **`IEnumerable<T>`**: Is the collection instance implicitly convertible to `IEnumerable<T>`, and perhaps other collection interfaces?\n- **Non-type arguments**: Does the collection type support elements that are not valid as type arguments, such as pointers or `ref struct`?\n- **Async code**: Can the collection be used in `async` code or an iterator?\n\nThe table below includes some possible collection types, and implications for each type.\n\n|Collection type|Mutable|Allocs|`IEnumerable<T>`|Non-type args|Async|Details|\n|:---:|:---:|:---:|:---:|:---:|:---:|:---:|\n|`T[]`|elements only|1|Yes|pointers|Yes| |\n|`List<T>`|Yes|2|Yes|No|Yes| |\n|`ReadOnlySpan<T>`|No|0/1|No|No|No|stack/heap allocated buffer|\n|`ReadOnlyMemory<T>`|No|1|Yes|No|Yes|heap allocated buffer|\n|`IEnumerable<T>`|No|1+|Yes|No|Yes|context-dependent implementation|\n|*Anonymous type*|?|1+|Yes|Yes|Yes|compiler-generated type|\n\n## Breaking changes\n\nPreviously, collection expressions [*conversions*](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#conversions) relied on *conversion from expression* to a target type.\nAnd previously, collection expression [*type inference*](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#type-inference) relied on input and output type inference for the elements.\nFor scenarios where the natural type of the collection could be used instead, there is a potential breaking change.\n\nIf the natural type is `IEnumerable<T>`, the following is a breaking change due to the **conversion** from `List<int>` to `IEnumerable<int>`\n\n```csharp\nbool b = true;\nList<int> x = [1, 2, 3];\nvar y = b ? x : [4]; // y: previously List<int>, now IEnumerable<int>\n```\n\nThe following is a breaking change in overload resolution due to **type inference** from the natural type to `T`:\n\n```csharp\nLog([1, 2, 3]); // previously Log<T>(IEnumerable<T>), now ambiguous\n\nvoid Log<T>(T item) { ... }\nvoid Log<T>(IEnumerable<T> items) { ... }\n```\n\n## Open questions\n\n### Support `foreach` and spread over typeless collection expressions?\n\nShould we support collection expressions in `foreach` expressions and in spread elements, even if we decide not to support a natural *collection type* in general?\n\nWhat are the set of locations where the collection type is not observable that should be supported?\n\n### Collection type?\n\nIf we do support a natural *collection type*, which collection type should we use? See the table above for some considerations.\n\n### Conversions from type?\n\nIs the natural type considered for *conversion from type*?\n\nFor instance, can a collection expression with natural type be assigned to `object`?\n\n```csharp\nobject obj = [1, 2, 3]; // convert col<int> to object?\n\n[Value([1, 2, 3])]      // convert col<int> to object?\nstatic void F() { }\n\nclass ValueAttribute : Attribute\n{\n    public ValueAttribute(object value) { }\n}\n```\n\n### Target-type `foreach` collection?\n\nShould the collection expression be target-typed when used in `foreach` with an *explicitly typed iteration variable*?\n\nIn short, if the iteration variable type is explicitly typed as `E`, should we use `col<E>` as the target type of the `foreach` expression?\n\n```csharp\nforeach (bool? b in [false, true, null]) { } // target type: col<bool?>?\nforeach (byte b in [1, 2, 3]) { }            // target type: col<byte>?\n```\n\n### Target-type spread collection?\n\nIf a spread element is contained in a *target-typed* collection expression, should the spread element expression be target-typed?\n\nIn short, if the containing collection expression has a target type with *element type* `E`, should we use `col<E>` as the target type for any spread element expressions?\n\n```csharp\nint[] x = [1, ..[]];           // spread target type: col<int>?\nobject[] y = [2, ..[default]]; // spread target type: col<object>?\n```\n"
  },
  {
    "path": "meetings/working-groups/collection-literals/collection-expressions-next.md",
    "content": "# Collection expressions - next\n\n## Summary\n[summary]: #summary\n\nAdditions to [*collection expressions*](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md).\n\n## Motivation\n[motivation]: #motivation\n\nA form for dictionary-like collections is also supported where the elements of the literal are written as `k: v` like `[k1: v1, ..d1]`.  A future pattern form that has a corresponding syntax (like `x is [k1: var v1]`) would be desirable.\n\n## Detailed design\n[design]: #detailed-design\n\n```diff\ncollection_literal_element\n  : expression_element\n+ | dictionary_element\n  | spread_element\n  ;\n\n+ dictionary_element\n  : expression ':' expression\n  ;\n```\n\n### Spec clarifications\n[spec-clarifications]: #spec-clarifications\n\n* `dictionary_element` instances will commonly be referred to as `k1: v1`, `k_n: v_n`, etc.\n\n* While a collection literal has a *natural type* of `List<T>`, it is permissible to avoid such an allocation if the result would not be observable.  For example, `foreach (var toggle in [true, false])`.  Because the elements are all that the user's code can refer to, the above could be optimized away into a direct stack allocation.\n\n## Conversions\n[conversions]: #conversions\n\nThe following implicit *collection literal conversions* exist from a collection literal expression:\n\n* ...\n\n* To a *type* that implements `System.Collections.IDictionary` where:\n  * The *type* contains an applicable instance constructor that can be invoked with no arguments or invoked with a single argument for the 0-th parameter where the parameter has type `System.Int32` and name `capacity`.\n  * For each *expression element* `Ei`:\n    * the type of `Ei` is `dynamic` and there is an [applicable](https://github.com/dotnet/csharpstandard/blob/draft-v7/standard/expressions.md#1265-compile-time-checking-of-dynamic-member-invocation) indexer setter that can be invoked with two `dynamic` arguments, or\n    * the type of `Ei` is a type `System.Collections.Generic.KeyValuePair<Ki, Vi>` and there is an applicable indexer setter that can be invoked with two arguments of types `Ki` and `Vi`.\n  * For each *dictionary element* `Ki:Vi`, there is an applicable indexer setter that can be invoked with two arguments of types `Ki` and `Vi`.\n  * For each *spread element* `Si`:\n    * the *iteration type* of `Si` is `dynamic` and there is an [applicable](https://github.com/dotnet/csharpstandard/blob/draft-v7/standard/expressions.md#1265-compile-time-checking-of-dynamic-member-invocation) indexer setter that can be invoked with two `dynamic` arguments, or\n    * the *iteration type* is `System.Collections.Generic.KeyValuePair<Ki, Vi>` and there is an applicable indexer setter that can be invoked with two arguments of types `Ki` and `Vi`.\n\n* To an *interface type* `I<K, V>` where `System.Collections.Generic.Dictionary<TKey, TValue>` implements `I<TKey, TValue>` and where:\n  * For each *expression element* `Ei`, the type of `Ei` is `dynamic`, or the type of `Ei` is a type `System.Collections.Generic.KeyValuePair<Ki, Vi>` and there is an implicit conversion from `Ki` to `K` and from `Vi` to `V`.\n  * For each *dictionary element* `Ki:Vi` there is an implicit conversion from `Ki` to `K` and from `Vi` to `V`.\n  * For each *spread element* `Si`, the *iteration type* of `Si` is `dynamic`, or the *iteration type* is `System.Collections.Generic.KeyValuePair<Ki, Vi>` and there is an implicit conversion from `Ki` to `K` and from `Vi` to `V`.\n\n## Natural type\n[natural-type]: #natural-type\n\nIn the absence of a *constructible collection target type*, a non-empty literal can have a *natural type*.\n\nThe *natural type* is determined from the [*natural element type*](#natural-element-type).\nIf the *natural element type* `T` cannot be determined, the literal has no *natural type*. If `T` can be determined, the *natural type* of the collection is `List<T>`.\n\nThe choice of `List<T>` rather than `T[]` or `ImmutableArray<T>` is to allow mutation of `var` locals after initialization. `List<T>` is preferred over `Span<T>` because `Span<T>` cannot be used in `async` methods.\n\n```c#\nvar values = [1, 2, 3];\nvalues.Add(4); // ok\n```\n\nThe *natural element type* may be inferred from `spread_element` enumerated element type.\n\n```c#\nvar c = [..[1, 2, 3]]; // List<int>\n```\n\nShould `IEnumerable` contribute an *iteration type* of `object` or no contribution?\n\n```c#\nIEnumerable e1 = [1, 2, 3];\nvar e2 = [..e1];           // List<object> or error?\nList<string> e3 = [..e1];  // error?\n```\n\nThe *natural type* should not prevent conversions to other collection types in *best common type* or *type inference* scenarios.\n```c#\nvar x = new[] { new int[0], [1, 2, 3] }; // ok: int[][]\nvar y = First(new int[0], [1, 2, 3]);    // ok: int[]\n\nstatic T First<T>(T x, T y) => x;\n```\n\n---\n\n* For example, given:\n\n    ```c#\n    string s = ...;\n    object[] objects = ...;\n    var x = [s, ..objects]; // List<object>\n    ```\n\n    The *natural type* of `x` is `List<T>` where `T` is the *best common type* of `s` and the *iteration type* of `objects`.  Respectively, that would be the *best common type* between `string` and `object`, which would be `object`.  As such, the type of `x` would be `List<object>`.\n\n* Given:\n\n    ```c#\n    var values = x ? [1, 2, 3] : []; // List<int>\n    ```\n\n    The *best common type* between `[1, 2, 3]` and `[]` causes `[]` to take on the type `[1, 2, 3]`, which is `List<int>` as per the existing *natural type* rules. As this is a constructible collection type, `[]` is treated as target-typed to that collection type.\n\n## Natural element type\n[natural-element-type]: #natural-element-type\n\nComputing the *natural element type* starts with three sets of types and expressions called *dictionary key set*, *dictionary value set*, and *remainder set*.\n\nThe *dictionary key/value sets* will either both be empty or both be non-empty.\n\nEach element of the literal is examined in the following fashion:\n\n* An element `e_n` has its *type* determined.  If that type is some `KeyValuePair<TKey, TValue>`, then `TKey` is added to *dictionary key set* and `TValue` is added to *dictionary value set*.  Otherwise, the `e_n` *expression* is added to *remainder set*.\n\n* An element `..s_n` has its *iteration type* determined.  If that type is some `KeyValuePair<TKey, TValue>`, then `TKey` is added to *dictionary key set* and `TValue` is added to *dictionary value set*. Otherwise, the *iteration type* is added to *remainder set*.\n\n* An element `k_n: v_n` adds the `k_n` and `v_n` *expressions* to *dictionary key set* and *dictionary value set* respectively.\n\n* If the *dictionary key/value sets* are empty, then there were definitely no `k_n: v_n` elements. In that case, the *fallback case* runs below.\n\n* If *dictionary key/value sets* are non-empty, then a first round of the *best common type* algorithm in performed on those sets to determine `BCT_Key` and `BCT_Value` respectively.\n\n    * If the first round fails for either set, the *fallback case* runs below.\n\n    * If the first round succeeds for both sets, there is a `KeyValuePair<BCT_Key, BCT_Value>` type produced.  This type is added to *remainder set*.  A second round of the *best common type* algorithm is performed on *remainder set* set to determine `BCT_Final`.\n\n        * If the second round fails, the *fallback* case runs below.\n        * Otherwise `BCT_Final` is the *natural element type* and the algorithm ends.\n\n* The *fallback case*:\n\n    * All `e_n` *expressions* are added to *remainder set*\n    * All `..s_n` *iteration types* are added to *remainder set*\n    * The *natural element type* is the *best common type* of the *remainder set* and the algorithm ends.\n\n---\n\n* Given:\n\n    ```c#\n    Dictionary<string, object> d1 = ...;\n    Dictionary<object, string> d2 = ...;\n    var d3 = [..d1, ..d2];\n    ```\n\n    The *natural type* of `d3` is `Dictionary<object, object>`.  This is because the `..d1` will have a *iteration type* of `KeyValuePair<string, object>` and `..d2` will have a *iteration type* of `KeyValuePair<object, string>`. These will contribute `{string, object}` to the determination of the `TKey` type and `{object, string}` to the determination of the `TValue` type.  In both cases, the *best common type* of each of these sets is `object`.\n\n* Given:\n\n    ```c#\n    var d = [null: null, \"a\": \"b\"];\n    ```\n\n    The *natural type* of `d` is `Dictionary<string, string>`.  This is because the `k_n: v_n` elements will construct the set `{null, \"a\"}` for the determination of the `TKey` type and `{null, \"b\"}` to the determination of the `TValue` type.  In both cases, the *best common type* of each of these sets is `string`.\n\n* Given:\n\n    ```c#\n    string s1, s2;\n    object o1, o2;\n    var d = [s1: o1, o2: s2];\n    ```\n\n    The *natural type* of `d3` is `Dictionary<object, object>`.  This is because the `k_n: v_n` elements will construct the set `{s1, o1}` for the determination of the `TKey` type and `{o2, s2}` to the determination of the `TValue` type.  In both cases, the *best common type* of each of these sets is `object`.\n\n* Given:\n\n    ```c#\n    string s1, s2;\n    object o1, o2;\n    var d = [KeyValuePair.Create(s1, o1), KeyValuePair.Create(o2, s2)];\n    ```\n\n    The *natural type* of `d3` is `Dictionary<object, object>`.  This is because the `e_n` elements are `KeyValuePair<string, object>` and `KeyValuePair<object, string>` respectively.  These will construct the set `{string, object}`for the determination of the `TKey` type and `{object, string}` to the determination of the `TValue` type.  In both cases, the *best common type* of each of these sets is `object`.\n\n### Interface translation\n[interface-translation]: #interface-translation\n\nGiven a target type `T` for a literal:\n\n* If `T` is some interface `I<TKey, TValue>` where that interface is implemented by `Dictionary<TKey, TValue>`, then the literal is translated as:\n\n    ```c#\n    Dictionary<TKey, TValue> __temp = [...]; /* standard translation */\n    I<TKey, TValue> __result = __temp;\n    ```\n\n* If `T` is a dictionary collection initializer with key `K1` and value `V1`, the literal is translated as:\n\n    ```c#\n    T __result = new T(capacity: __len);\n\n    __result[__e1.Key] = __e1.Value;\n    __result[__k1] = __v1;\n    foreach (var __t in __s1)\n        __result[__t.Key] = __t.Value;\n\n    // further additions of the remaining elements\n    ```\n\n    * In this translation, `expression_element` is only supported if the element type is some `KeyValuePair<,>` or `dynamic`, and `spread_element` is only supported if the enumerated element type is some `KeyValuePair<,>` or `dynamic`.\n\n## Syntax ambiguities\n[syntax-ambiguities]: #syntax-ambiguities\n\n* `dictionary_element` can be ambiguous with a [`conditional_expression`](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/expressions.md#1115-conditional-operator).  For example:\n\n    ```c#\n    var v = [ a ? [b] : c ];\n    ```\n\n    This could be interpreted as `expression_element` where the `expression` is a `conditional_expression` (e.g. `[ (a ? [b] : c) ]`).  Or it could be interpreted as a `dictionary_element` `\"k: v\"` where `a?[b]` is `k`, and `c` is `v`.\n\n## Resolved questions\n[resolved]: #resolved-questions\n\n* Should a `collection_literal_expression` have a *natural type*?  In other words, should it be legal to write the following:\n\n    ```c#\n    var x = [1, 2, 3];\n    ```\n\n    Resolution: Yes, the *natural type* will be an appropriate instantiation of `List<T>`. The following text exists to record the original discussion of this topic.\n\n    <details>\n\n    It is virtually certain that users will want to do this.  However, there is much less certainty both on what users would want this mean and if there is even any sort of broad majority on some default.  There are numerous types we could pick, all of which have varying pros and cons.  Specifically, our options are *at least* any of the following:\n\n    * Array types\n    * Span types\n    * `ImmutableArray<T>`\n    * `List<T>`\n    * [`ValueArray<T, N>`](https://github.com/dotnet/roslyn/pull/57286)\n\n    Each of those options has varying benefits with respect to the following questions:\n\n    * Will the literal cause a heap allocation (and, if so, how many), or can it live on the stack?\n    * Are the values of the literal mutable after creation or are they fixed?\n    * Is the resultant value itself mutable (e.g. can it be cleared, or can new elements be added to it)?\n    * Can the value be used in all contexts (for example, async/non-async)?\n    * Can be used for *all* literal forms (for example, a `spread_element` of an *unknown length*)?\n\n    Note: for whatever type we pick as a *natural type*, the user can always target-type to the type they want with a simple cast, though that won't be pleasant.\n\n    With all of that, we have a matrix like so:\n\n    | type | heap allocs | mutable elements | mutable collection | async | all literal forms |\n    |-|-|-|-|-|-|\n    | `T[]` | 1 | Yes | No | Yes | No* |\n    | `Span<T>` | 0 | Yes | No | No | No* |\n    | `ReadOnlySpan<T>` | 0 | No | No | No | No* |\n    | `List<T>` | 2 | Yes | Yes | Yes | Yes |\n    | `ImmutableArray<T>` | 1 | No | No | Yes | No* |\n    | `ValueArray<T, N>` | ? | ? | ? | ? | ? |\n\n    \\* `T[]`, `Span<T>` and `ImmutableArray<T>` might potentially work for 'all literal forms' if we extend this spec greatly with some sort of builder mechanism that allows us to tell it about all the pieces, with a final `T[]` or `Span<T>` obtained from the builder which can also then be passed to the `Construct` method used by *known length* translation in order to support `ImmutableArray<T>` and any other collection.\n\n    Only `List<T>` gives us a `Yes` for all columns. However, getting `Yes` for everything is not necessarily what we desire.  For example, if we believe the future is one where immutable is the most desirable, the types like `T[]`, `Span<T>`, or `List<T>` may not complement that well.  Similarly if we believe that people will want to use these without paying for allocations, then `Span<T>` and `ReadOnlySpan<T>` seem the most viable.\n\n    However, the likely crux of this is the following:\n\n    * Mutation is part and parcel of .NET\n    * `List<T>` is already heavily the lingua franca of lists.\n    * `List<T>` is a viable final form for any potential list literal (including those with spreads of *unknown length*)\n    * Span types and ValueArray are too esoteric, and the inability to use ref structs within async-contexts is likely a deal breaker for broad acceptance.\n\n    As such, while it unfortunate that it has two allocations, `List<T>` seems be the most broadly applicable. This is likely what we would want from the *natural type*.\n\n    I believe the only other reasonable alternative would be `ImmutableArray<T>`, but either with the caveat that that it cannot support `spread_elements` of *unknown length*, or that we will have to add a fair amount of complexity to this specification to allow for some API pattern to allow it to participate.  That said, we should strongly consider adding that complexity if we believe this will be the recommended collection type that we and the BCL will be encouraging people to use.\n\n    Finally, we could consider having different *natural types* in different contexts (like in an async context, pick a type that isn't a ref struct), but that seems rather confusing and distasteful.\n\n    </details>\n"
  },
  {
    "path": "meetings/working-groups/discriminated-unions/Case Classes.md",
    "content": "This proposal has moved to: https://github.com/dotnet/csharplang/blob/main/proposals/case-declarations.md"
  },
  {
    "path": "meetings/working-groups/discriminated-unions/Closed Enums.md",
    "content": "This proposal has moved to: https://github.com/dotnet/csharplang/blob/main/proposals/closed-enums.md"
  },
  {
    "path": "meetings/working-groups/discriminated-unions/Closed Hierarchies.md",
    "content": "This proposal has moved to: https://github.com/dotnet/csharplang/blob/main/proposals/closed-hierarchies.md"
  },
  {
    "path": "meetings/working-groups/discriminated-unions/DU-2022-10-19.md",
    "content": "## Notes for October 19th, 2022\n\nThe theme of our first meeting was collecting scenarios that we think can be improved by discriminated unions, so we have an idea of what problems we're trying\nto solve.\n\n### PageState\n\n```cs\npublic enum PageState\n{\n    NotLoaded,\n    Loading,\n    Loaded,\n    Errored\n}\n\npublic class Page {\n    PageState state;\n    \n    // used when state is Loaded\n    PageData data;\n    \n    // used when state is Errored\n    string errorMessage;\n    \n    \n    public View Render() {\n        switch (this.state)\n        {\n            case PageState.NotLoaded:\n                return ShowLoadButton();\n            case PageState.Loading:\n                return ShowLoadingSpinner();\n            case PageState.Loaded:\n                return ShowData(this.data!);\n            case PageState.Errored:\n                return ShowErrorMessage(this.errorMessage);\n            default:\n                throw Unreachable;\n        }\n    }\n}\n\nclass PageData { }\n\nclass View { }\n```\n\n* UI App scenario\n* Different page states - state machine transition\n* Has some state fields that are only applicable when in a particular state\n    * Could be represented as a type hierarchy as well\n* Should be able to remove `throw Unreachable;`\n* Would you be able to define a `PageState.Show()`?\n    * This is the OO fashion, we're really talking more functional.\n\n### Web APIs\n\n```cs\n[HttpGet(Name = \"GetWeatherForecast\")]\npublic IActionResult Get(int id)\n{\n    return id % 2 == 0\n        ? Ok(Enumerable.Range(1, 5).Select(index => new WeatherForecast\n        {\n            Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),\n            TemperatureC = Random.Shared.Next(-20, 55),\n            Summary = Summaries[Random.Shared.Next(Summaries.Length)]\n        }).ToArray())\n        : NotFound();\n}\n\napp.MapGet(\"/minimal-dus/{id}\", Results<Ok<string>, ProblemHttpResult> (int id) => {\n    return id % 2 == 0\n        ? TypedResults.Ok(\"Valid ID\")\n        : TypedResults.Problem(\"Invalid Id\");\n});\n```\n\n* `IActionResult` is very common in MVC\n    * Worked around in minimal APIs by using `Results<TypeA, TypeB, ... TypeN>` (lots of versions of this, like ValueTuple)\n        * All Results are `IResult`s\n    * Does it matter if it's anonymous in some fashion or explicitly declared by the user?\n    * What about subsets of the full union?\n        * Just Ok or NotFound?\n* Error recovery: `Optional` or `Result<TOk, TErr>`\n\n### IDE APIs\n\n* IDE: message passing where something could be a subset of a larger group of possibilities\n    * Heterogeneous data - not a subset of a larger type hierarchy.\n    * Painful and not checked today: can only be one of the tuple elements, but we have to pass around and check these in a non-straightforward fashion\n\n### Optional\n\n* Could we have semantics such that we can have a `Optional<T>` in the BCL\n* Maybe an syntactic shortcut for this?\n* Result type would be useful for type metadata decoding: currently we throw exceptions.\n* Some sort of syntax help for short-circuiting these would be nice, a-la `?` in Rust.\n    * Would hopefully be able to apply not just to Ok/Result monads, but other kinds as well.\n\n### Type Hierarchy subsets\n\nhttps://github.com/dotnet/roslyn/blob/7b6fc9baa013ceb935973144543bcc422b8234d2/src/Compilers/CSharp/Portable/Binder/LockOrUsingBinder.cs#L44-L45\n\n* More of an anonymous scenario\n* Subset of a larger union - homogenous data\n* Large DUs, such as SyntaxNode or BoundNode, are almost never useful as those large subsets. Smaller subsets, often defined ad-hoc, are usually what we want to work with.\n* Large unions might be hard to add to existing projects without large refactorings. Some projects might be able to do this, but many won't. The BCL won't for their public APIs.\n\n### Generalized semantics\n\n* Are there advantages to targeting existing scenarios, and then having syntax that can make it easier to do?\n    * Likely yes: will have wide compatibility with existing code.\n\n### Next meeting\n\nFor next time, we will look at the commonalities in these scenarios and start looking at strategies for representing them.\n"
  },
  {
    "path": "meetings/working-groups/discriminated-unions/DU-2022-10-24.md",
    "content": "## Notes for October 24th, 2022\n\nThis meeting distilled the previous use case discussions to a few broad concepts of unions, and we talked about some basic features and tenets that we want to see in unions.\n\n### Concepts\n\n* `Result<TResult, TError>`/`Option<T>`\n    * Very interested in syntactic shortcuts here.\n    * Monads over the `T` inside\n    * Forces users handle errors up front\n    * Is short declaration of these types of unions necessary?\n        * Maybe not? Maybe if the BCL ships Result/Option itself, people may not actually need to declare many of their own versions of these.\n* Internal State with associated data\n    * UI States\n    * `BoundNode`\n    * Subsets of these are often useful: State machines only transitioning from X -> Y, not Z -> Y, or only accepting certain types of expressions.\n        * Anonymous definition of these might be useful. `(BoundLiteral | BoundMethodGroup)` inline, for example\n    * Simplifies handling of state and state transitions, potentially enforces explicit handling of cases.\n* `OneOf<T1, ..., Tn>`\n    * Passing heterogeneous data around\n    * Anonymous definition might also be useful\n        * How would this reconcile with a homogeneous subset?\n    * Potentially easier to integrate into existing codebases\n\n### Union versioning and compat\n\n* What's our compat strategy for public APIs with this type of union in them?\n* Matters particularly in the same areas as variance: what happens when public apis start returning a new result?\n* Or stop accepting a result variant?\n    * Maybe this one doesn't matter as much?\n* Source compatibility in an return position is not guaranteed when revving a union type\n* Binary compatibility in a input position?\n    * Historically, we've cared about this\n    * If my public function accepts a new case, all existing code should still work\n    * On the other hand, if I add a new input to some interface a consumer is implementing, they may get a case they weren't expecting\n* In general, we're not worried about maintaining binary compatibility. We just want to make sure that API authors can be intentional about when they\n  want to make a breaking change and make it obvious that they did.\n* Do we want to _ensure_ that binary breaks happen when users encounter new cases?\n    * No. If it falls out then it falls out, similar to required members.\n\n### Opaque unions\n\n* F# has these:\n  ```fs\n  type C =\n      private // or internal\n      | Case1 of int\n  ```\n\n  These create an interchange type that appears as a union to the file or assembly that created them, but is opaque to consumers. Do we need this?\n    * We think this is probably just existing base types/interfaces in C#\n\n### Exhaustiveness\n\n* List all valid subtypes in the base type?\n    * Compiler error when adding a new type?\n    * This is Java's approach in JEP 409 - Sealed Classes\n* For sufficiently large hierarchies, maybe exhaustiveness isn't always as useful as hoped?\n    * May often be working on subsets, and forcing handling of all unexpected values might erode desired errors when adding new expected cases.\n\n### Conclusions\n\n* Subsets of larger unions keep coming up in our discussions, though we need to make sure we're not being overly colored by roslyn.\n    * Subsets of unions may call for an anonymous union syntax.\n    * Having different implementation details for sets of homogeneous data and sets of heterogeneous data would likely be confusing for users. A singular lowering\n      for subsets is likely needed.\n* Compatibility with existing forms is important. Users should not have to perform large refactorings to take advantage of any improvements we come up with here.\n    * Importantly, we're not looking to deprecate existing forms of creating hierarchies.\n* Experiencing source breaks when adding or removing new cases to unions is likely both unavoidable and desirable. We're ok with binary breaks as well, but won't\n  be attempting to _ensure_ that they occur.\n"
  },
  {
    "path": "meetings/working-groups/discriminated-unions/DU-2022-10-31.md",
    "content": "## Notes for October 31st, 2022\n\n### Pseudo-syntax\n\nThis meeting starting by defining a pseudo-syntax to help us understand what everyone refers to when talking\nabout examples. This syntax is:\n\n```cs\nunion [Name] { A, B, C }      // tagged, internal (members declared within type)\nunion [Name] ( A | B | C )    // untagged, external (members declared outside type)\nunion [Name] { A(int x), B }  // tagged with values (mixed)\nunion [Name] { A = 10 }       // tagged with values\nunion [Name] { 10 | 20 }      // untagged, external, with values\nunion [Name] { ..Base }       // all known derived types of Base (splatting). Covered by `union Name { Base }` \n```\n\nWe arrived at these from looking at a matrix of all the different possible dimensions of union types:\n\n* Named vs unnamed union type\n* Tagged vs untagged cases\n* Values vs no values\n* Internal vs external members\n\nThe `[Name]` sections are optional, which deals with the first bullet. The rest of the bullets are explicitly covered,\nwith some exceptions for scenarios we didn't think were realistic (such as internal untagged value unions).\n\n### Equivalence\n\nWe next turned our thoughts to untagged external unions and equivalence: should `union (A | B) == union (B | A)`, ignoring\nimplementation details as much as we can. We considered multiple levels of this type of conversion:\n\n* No conversion\n* Implicit (non-identity conversion)\n* Identity conversion\n\nImplementation details keep rearing their heads here, though we tried to avoid talking about them. We generally said we wanted\nsome amount of conversion here, and which conversion can impact scenarios such as:\n\n```cs\n// Overloading\nvoid M(union (A|B) x);\nvoid M(union (B|A) x);\n\n// Type unification between ternary branches\nstatic (T | U) F<T, U>(bool b, T t, U u) => b ? t : u;\nvar x = true ? F(cond1, 1, \"hello\") : F(cond2, \"world\", 2); // type of var? union (int | string) or union(string | int)\n```\n\nAnother way of wording this is, do people think that ordering matters when they type something like this? After some debate,\nwe settled on thinking that it doesn't matter. Adding order effectively implies adding a tag, and we're specifically looking\nat untagged, anonymous unions of external types in this case.\n\nWe also looked at equivalence in unions in switching:\n\n```cs\nunion (A | B) u = ...;\nswitch ((object)u)\n{\n    case union(B | A):\n        Console.WriteLine(\"Union matched\"); // Should this work?\n        break;\n}\n```\n\nWe feel like this should work, which raises the question of whether the runtime needs to be involved in the scenario: if we\nwent with a `OneOf<T1, T2>` implementation, then the conversion would likely need to unbox to just `A` or `B`. We then need\nto consider whether we even want a union type to be allowed as a type pattern or not. Generics make all of this more difficult;\nthe unboxing is entirely implementable by the compiler when we know about the types ahead of time, but in generic methods the\nprecise types won't be known until runtime.\n\nWe need to think more about this, so we'll revisit these rules again in a later meeting.\n"
  },
  {
    "path": "meetings/working-groups/discriminated-unions/DU-2022-11-07.md",
    "content": "## Notes for November 7th, 2022\n\nAs a reminder, we use [this syntax](DU-2022-10-31.md#pseudo-syntax) for describing unions forms.\n\n### Conversions\n\nPickup up from last week, we talked about equivalency again. This time, we started by focusing on the differences between `union (A | B)` (an anonymous union of types) and\n`union NamedAOrB (A | B)` (a named union of types). We do generally think that `union (A | B)` and `union (B | A)` should at least be implicitly convertible, if not identical,\nand that has implications on the grow up story. Much like with tuples, we don't think anonymous union types belong in public APIs, except in cases like `Zip` where the\nimplementation detail of the tuple is the _purpose_ of the API (in other words, when the likelihood of adding or removing a new element is nonexistent). Tuples that need to\nbe in public API generally want to grow up to be positional records, and we might need something similar here for untagged named unions. In thinking about it more, though,\nwe're not certain of the need for exporting this type of union. It would have limitations, such as the inability to have two different cases with the same type (a string result\nor string error, for example, couldn't be represented without a separate tag), so it's possible that the roles proposal is enough for us here. Something like\n`role NamedAOrB : (A | B);` would give a name to the case, give us equivalency with the underlying type, and maintain discouragement of putting untagged unions in public\ntype hierarchies.\n\n### Switching on unions\n\nWe considered a few different ways that users might want to pattern match against anonymous unions of types:\n\n```cs\nvoid M((int|string) x) \n{\n    object o = x;\n    _ = o switch\n    {\n        (int|string) => 0,\n        _ => 0\n    };\n    _ = o switch\n    {\n        int or string => 1,\n        _ => 1\n    };\n    _ = o switch\n    {\n        int => 2,\n        string => 2,\n        _ => 2,\n    };\n\n    // Switch on x\n    _ = x switch\n    {\n        int => 2, // Could use x.IsTypeOf<int>\n        string => 2,\n        _ => 2,\n    };\n}\n```\n\nThere are a few ways this could work:\n\n1. Erase the union, and have it be object. Type tests are emitted as today.\n2. Check for an IsOneOf marker interface. Would have to always check, behavior change on recompile.\n3. When switching on the union itself, call an `IsType<T>` method.\n4. Have the runtime participate in boxing, throwing away a wrapper type.\n\nWe don't have any decisions yet, we're still exploring the space. We'll keep exploring further.\n"
  },
  {
    "path": "meetings/working-groups/discriminated-unions/Nominal Type Unions.md",
    "content": "This proposal has moved to: https://github.com/dotnet/csharplang/blob/main/proposals/case-declarations.md"
  },
  {
    "path": "meetings/working-groups/discriminated-unions/Runtime Type Unions.md",
    "content": "# Runtime Type Unions\n\n## Summary\n\nRuntime type unions are C# type unions built on top of support for type unions in the runtime. Each union has a closed \"list\" of case types.\n\nThey can be used without declaration via an anonymous type expression syntax:\n\n```csharp\n(int or string) x = 10;\n```\n\nOr declared with a name:\n\n```csharp\nunion IntOrString(int, string);\n```\n\nUnion specific case types can be succinctly declared if we adopt the \"Case Classes\" proposal:\n\n```csharp\nunion Pet\n{\n    case Cat(...);\n    case Dog(...);\n}\n```\n\nCase types can be implicitly converted to the union type:\n\n```csharp\n(int or string) value = 10;\nPet pet = new Dog(...);\n```\n\nOr explicitly converted:\n\n```csharp\nPet pet = (Pet)obj;  // convert from unknown to union\nDog dog = (Dog)pet;  // convert from union to case type\n```\n\nPatterns apply to the contents of a union. Switches on all cases types are exhaustive:\n\n```csharp\nvar name = pet switch\n{\n    Cat cat => ...,\n    Dog dog => ...\n}\n```\n\nWhile there is no inheritance relationship between unions and case types, \nmatching to a runtime union type succeeds when the value on the left\nmatches any of the case types.\n\n```csharp\n_ = obj is Pet;  // True if obj is Cat or Dog\n```\n\n## Motivation\nTo provide a canonical type union in C# that is also fully supported in the runtime and reflection,\nso it works automatically in all contexts.\n\n## Runtime Support\nThe runtime is aware of a special union type that is used only descriptively in metadata to describe the union, but is actually represented at runtime as a simple object reference. Certain IL operations are handled specially for values with this encoding to help guarantee that those values are compatible with one of the case types of the union.\n\n### The Union Type\n```csharp\nSystem.Union<T1, T2>\n```\nThe runtime is aware of a special abstract generic class `System.Union<T1, T2>`. \nThis type can never be allocated, but it can be used in signatures, fields and local variables as a way to provide more information for a value that is ultimately just an object reference.\n\nThis type has two generic type parameters, both of which can either describe a case type or another union type when constructed.\n\nFor example, \n```csharp\nUnion<int, string>                  // int or string\nUnion<int, Union<string, double>>   // int or string or double\nUnion<Union<int, float>, Union<string, double>>  // int or float or string or double\n```\n\nIn a sense, the runtime unravels the constructed union type to determine its set of case types. It uses this knowledge of the case types to implement specific IL instructions.\n\n### Type Non-Equivalence\nUnion types constructed differently are different types.\n\n```csharp\nUnion<int, string>  =/=   Union<string, int>\n```\n However, there may be a conversion relationship between them.\n\n### Type Conversion\nWhen a union type is used as the target type of an `ISINST` or `CASTCLASS` IL instruction, these instructions succeed when the source runtime type would succeed on any one of the target union's case types, and fail when no case type would succeed.\n\nWhen a union type is used as the static source type of an `ISINST` or `CASTCLASS` IL instruction, the union type is ignored and the runtime type is used always. (This is already how the runtime functions.)\n\nThe runtime is free to optimize away the actual type checks of the conversion when it knows that the source and target static types are compatible.\n\n*Note: CASTCLASS succeeds when the source is a null value and target is a reference type or Nullable<T> type.*\n\n### Named Sub Types\nThe union type `Union<T1, T2>` is allowed to have sub-types. \n\n```csharp\npublic sealed abstract class MyUnion : Union<int, string>;\n```\n\nThese types must be abstract classes that declare no members, except for nested type declarations, and no type my derived from them (sealed abstract?).\n\nThese sub-types serve only as a means to give a union a name and to set it apart from other union types so they will be considered unique in signatures. However, the same assignment and conversion rules still apply.\n\n#### Type Parameter Constraints\nA type union type can be used in a type parameter constraint. However, it does not mean anything other than a constraint on normal sub typing. If you constrain a type parameter to a union type `Union<x,y>` then the type parameter must be that type or a sub-type of that type.\n\n```csharp\n    public abstract class IntOrString : Union<int, string>;\n\n    public void M<T>() where T : Union<int, string> {...}\n\n    M<Union<int, string>>();\n    M<IntOrString>();\n    M<int>(); // Error!\n    M<string>(); // Error!\n    M<(string, int)>(); // Error!\n```\n\n### Reflection\nReflection API assigning values to a field or parameter that is a union type will allow case types to be assigned (with runtime checks), as there is no way to actually have an instance of a union type.\n\n```csharp\n    void M(Union<int, string> value) {...};\n    ...\n\n    MethodInfo methodM = ...;\n    method.Invoke(instance, new object []{ 10 });  // boxed int assignable to union\n```\n\nThe methods `Type.IsAssignableFrom` and `Type.IsAssignableTo` will return true if a value of the source type is assignable to any of a target union's case types. If both source and target types are union types, the methods will return true if all the source union's case types are assignable to one of the target union's case types.\n\nThe runtime `Type` class will add the following members to help tools and libraries using reflection understand when a type is actually a union.\n\n```csharp\n    public class Type \n    {\n        public bool IsUnion { get; }\n        public Type[] GetUnionCaseTypes();\n    }\n```\n\n## Language Support\n\n### Anonymous Type Unions\nA type expression exists to refer to a runtime union type without specifying a name. These anonymous unions unify across assemblies since they are all translated to the same generic system type.\n\n#### Grammar\n```csharp\nanonymousUnionType := '(' <type> ('or' <type>)* ')';\n```\n\n#### Lowering\nAn anonymous type union is a synonym for an equivalent System.Union<T1,T2>.\n\n|Union Syntax|Lowered Type|\n|------|-------|\n|`(A or B)` |`Union<A, B>` |\n|`(A or B or C)` |`Union<A, Union<B, C>>` |\n|`(A or B or C or D)` |`Union<A, Union<B, Union<C, D>>>`|\n\n### Nominal Type Unions\nA nominal type union exists to give a type union a name, since repeatedly writing anonymous union expressions for unions with multiple cases gets tedious after about three.\n\nYou declare one minimally using the `union` keyword, a name and a list of type references.\n\n```csharp\nunion Pet (Cat, Dog, Bird, Fish, Turtle, Rabbit);\n```\n\nThe nominal type union has no members other than those inherited from object, yet it may declared nested types.\nBecause of this, a nominal type union can declared its case types as part of the overall declaration. \n\n```csharp\nunion Pet(Cat, Dog)\n{\n    public record Cat(...);\n    public record Dog(...);\n    ...\n}\n```\n\nIf using the [Case Classes](#) proposal, there is no need to also specify the nested type in the type reference list, allowing the declaration to become simpler:\n\n```csharp\nunion Pet\n{\n    case Cat(...);\n    case Dog(...);\n    ...\n}\n```\n\n#### Grammar\n```csharp\nnominalUnionType :=   \n    <attribute>* <accessibility>? 'union' <name> \n    (<type-parameter-list>)? \n    (<type-reference-list>)? \n    (<type-constraints>)* \n    ('{' <nested-type-declarations> '}' | ';')\n```\n\n#### Lowering\nNominal type unions are lowered to a declaration of a sub-type of the `System.Union<T1, T2>` type.\n\n```csharp\npublic union Result<TValue, TError>(Success<TValue>, Failure<TError>);\n```\nis lowered to:\n```csharp\npublic sealed abstract class Result<TValue, TError> : System.Union<Success<TValue>, Failure<TError>>;\n```\n\n#### Assignment\nWhen the target of an assignment is a type union, and the source is assignable to one of the case types, the assignment can be made without an explicit conversion (cast).\n\nWhen the source of an assignment is also a type union, and each of the source's case types can be assigned to any one of the target's case types, the assignment can be made without an explicit conversion.\n\n```csharp\n(int or string) x = 10;\n(int or string or double) y = x;\nint z = x; // error!\n(int or double) = x; // error!\n```\n\nRegardless, the assignment is encoded as a conversion generating a `CASTCLASS` instruction, unless the [Runtime Assignable Conversion](#runtime-assignable-conversions) feature is implemented.\n\n#### Conversion\nC# is aware of type unions. Casts and pattern matching allow union types in both the source and target position, and all are handled by the same runtime IL as used today.\n\nHowever, normally the C# compiler will report an error when the source of a cast or pattern match will never match the target type. This rule is modified for type unions.\n\nWhen a union is the source of a cast or pattern match, no error is given if the target type is compatible with at least one of the source's case types.\n\n```csharp\n(int or string) x = ...;\nvar r = x switch \n{\n    int value => ...,\n    string value => ...,\n    double value => ... // error! this will never match\n}\n```\n\nWhen a union is the target of a cast or pattern match, no error is given if the source type is compatible with at least one of the target's case types.\n\n```csharp\nint x = ...;\nvar r = x switch \n{\n    int value => ...,\n    (int or string) => ...,\n    (string or double) => ...  // error! this will never match\n}\n```\n\nWhen both the source and target types are union types, no error is given if the target and source case types have at least on compatible combination.\n\n```csharp\n(int or string) x = ...;\nvar r = x switch \n{\n    (string or int) => ...,\n    (int or string or double) => ...,\n    (string or double) => ...,\n    (double or float) => ...  // error! will never match\n}\n```\n\n#### Exhaustiveness\nA `switch` with a source value that statically has a type union type is exhausted if all case types are handled in the switch. If the switch is exhausted, no default case need be specified.\n\n```csharp\n(int or string or double) x = ...\nvar r = x switch\n{\n    int value => ...,\n    string value => ...,\n    double value => ...\n}\n```\n\n#### Nullability\nWhen one of a type union's case types is a type that can be null, a nullable reference type or nullable value, the type union is considered nullable or may be null by the null type checker and may be assigned a null value.\n\n```csharp\n(int or string?) x = null;  // legal\n```\n\nIn addition, a type union without a nullable case type may still be considered nullable if the type is referred to using the question-mark syntax or is inferred to be possibly null using the existing null type checker rules.\n\n```csharp\n(int or string)? x = null;  // legal\n```\n\nSpecifying both is unnecessary, but also allowed.\n\n```csharp\n(int or string?)? x = null; // legal\n```\n\nHowever, even when a case type is declared as nullable, you cannot use a nullable type in a type pattern match. Yet, as with any reference type, when a type union is nullable it may be matched with a null pattern match. \n\n```csharp\n(int or string)? x = ...;\nif (x is null) {...}\n```\n\nA switch with a nullable type union must include a null pattern match in order to be considered exhausted.\n\n```csharp\n(int or string?) x = ...;\nvar r = switch\n{\n    int value => ...,\n    string value => ...,\n    null => ...\n}\n```\n\n**Question:** Can you assign a value of a nullable variation of a case type to a nullable type union when the case type itself is not nullable?\n\n```csharp\n    int? v = ...;\n    (int or string?) x = v; // Error?\n```\nHow about now?\n```csharp\n    int? v = ...;\n    (int or string)? x = v; // Error?\n```\n\nThere is no actual violation of the type system. A value with this type may be null or not. However, the intuition may be that this is not possible for one or both.\n\nCould maybe the first case be a warning, since you went out of your way to describe the case types and either being nullable or not? But the second sort of implies that any value could be nullable.\n\n```csharp\n    (int or string)?  <===>  (int? or string?)\n```\n\n**Question:** If type parameters are used as case types, without constraints that would imply nullability of the case type, should the type union be considered nullable?\n\n```csharp\n    void Method<T1, T2>()\n    {\n        (T1, T2) x = null; // allowed?\n\n        var r = x switch \n        {\n            T1 value => ...,\n            T2 value => ...,\n            null => ...   // necessary?\n        }\n    }\n```\n\n## Drawbacks\n\n- No back-compat: Only works in newer runtimes and cannot be reasonably used via older language versions.\n- Delay: Getting these features into a new runtime may take a long time.\n- Boxing: No non-boxing solution.\n\n## Optional Features\nOptional features are stretch goals.\n\n### Runtime Assignable Conversions\n\nThe runtime IL type checker is enhanced to understand the assignment rules without requiring a `CASTCLASS` instruction to convert between different (though compatible) union types.\n\n1. A source value can be to a target with a union type if the source value's static type is assignable to at least one of the target union's case types.\n2. A source value with a union type is assignable to a target with a different union type if each of the source's case types are assignable to at least one of the target's cast types.\n\n### Type Parameter Union Constraints\nTo have a more meaningful constraint for type unions, a new kind of constraint must exist that constrains against the union case membership. This needs to be represented specially in metadata and would require different syntax in C#.\n\nA new constraint operator exists C# that means union subtype. Instead of `:`, we use the `in` keyword.\nThe type parameter `T` matches if it has a `:` relationship with any one of the constraint's case types, or if it is a union itself then each case type must have a `:` relationship with one of the constraint's case types. If the constraint's type is not a union, then the `in` operator has the same meaning as the `:` operator.\n\n```csharp\n    record Animal;\n    record Dog : Animal;\n    class AnimalOrInt : Union<Animal, int>;\n\n    void Method<T>() where T in (int or Animal) {...}\n    \n    Method<int>(); // okay\n    Method<Animal>(); // okay\n    Method<Dog>(); // okay\n    Method<double>(); // Error!\n    Method<Union<int, Animal>>(); // okay\n    Method<Union<Animal, int>>(); // okay\n    Method<Union<int, Dog>>(); // okay\n    Method<AnimalOrInt>(); // okay\n    Method<Union<int, double>>(); // Error!\n```\n\nThis means T is constrained to be either an int or Animal.\n\nIf a generic type parameter is used as part of generic constraint of another type parameter, and that type parameter is constructed with a union type, the constraint checker sees that it is a union and applies the same rule (at whatever point this normally happens, loading, jit, e tc).\n\n```csharp\n    void Method<T, U>() where T in U {...}\n    \n    Method<int, (int or Animal)>(); // okay\n    Method<Animal, (int or Animal)>(); // okay\n    Method<Dog, (int or Animal)>(); // okay\n    Method<double, (int or Animal)>(); // Error!\n    Method<(int or Animal), (int or Animal)>(); // okay\n    Method<(Animal or int), (int or Animal)>(); // okay\n    Method<(int or Dog), (int or Animal)>(); // okay\n    Method<AnimalOrInt, (int or Animal)>(); // okay\n    Method<(int or double), (int or Animal)>(); // Error!\n\n    Method<int, AnimalOrInt>(); // okay\n    Method<(int or Animal), AnimalOrInt>(); // okay\n```\n"
  },
  {
    "path": "meetings/working-groups/discriminated-unions/Trade Off Matrix.md",
    "content": "# Union Trade Offs\n\n## Solution Space\n\nThere are only three possible ways to represent a type that behaves like a discriminated union or type union in C# without a large runtime overhaul.\n\n1) As a class Hierarchy\n```csharp\n    // example: a record hierarchy\n    public abstract record MyUnion\n    {\n        public record Case1(...) : MyUnion;\n        public record Case2(...) : MyUnion;\n        public record Case3(...) : MyUnion;\n    }\n\n    MyUnion union = new MyUnion.Case1(...);\n```\n\n2) As an object reference\n```csharp\n    object union; // only assign Case1, Case2 or Case3 here please.\n    ...\n    union = new Case1(...);\n```\n\n3) As a wrapper type\n```csharp\n    // example: a struct wrapper with constructors and a value property\n    public struct MyUnion\n    {\n        public MyUnion(Case1 value) {...}\n        public MyUnion(Case2 value) {...}\n        public MyUnion(Case3 value) {...}\n        public object Value { get; }\n    }\n\n    MyUnion union = new MyUnion(new Case1(...));\n```\n\nThese are exactly what developers use when defining the equivalent of discriminated unions and type unions in C# code today.\n\nHowever, none of these user defined solutions allow for exhaustiveness in pattern matching, because they are either too open ended or not understood as being closed by the runtime and language.\n\nThe following proposals offer solutions for exhaustiveness and more, with a matrix of trade-offs between them.\n\n- The `Closed Hierarchies` proposal offers an easy way to make class hierarchies closed.\n- The `Runtime Type Unions` proposal offers a special kind of object reference that is understood by the runtime.\n- The `Nominal Type Unions` proposal offers a wrapper type solution understood by the language.\n\n## Trade Off Matrix\n\n| Feature                               |  Runtime Type Unions | Nominal Type Unions | Closed Hierarchies |\n|---------------------------------------|----------------------|---------------------|--------------------|\n| Declared Cases                        | **Yes**              | **Yes**             | **Yes**            |\n| Singleton Cases                       | **Yes**              | **Yes**      \t     | **Yes**            |\n| Existing Cases                       \t| **Yes**              | **Yes**             |                    |\n| Anonymous Syntax                      | **Yes**              |                     |                    |\n| Pattern Matching                      | **Yes**              | **Yes**             | **Yes**            |\n| Dynamic Pattern Matching              | **Yes**\t\t       |                     | **Yes**            |\n| Subtype Relationship                  |                      |                     | **Yes**            |\n| Conversion Relationship               | **Yes**              |                     | **Yes**            |\n| Back-Compat       \t\t\t        |                      | **Yes**\t\t     | **Yes**            |\n| Non-ABI Breaking                      | *named only*         | **Yes**             | **Yes**            |\n| Non-Allocating/Boxing\t\t\t        |                      | *future*            |                    |\n| Custom Unions \t                    |                      | *future*            |                    |\n| Any Time Soon                         |\t                   | **Yes**             | **Yes**            |\n\n- *Declared Cases* - Case types can be declared as part of the union type declaration.\n- *Singleton Cases* - Singleton cases can be declared and used without additional allocations.\n- *Existing Cases* - Existing types can be used as cases w/o declaring and allocating case type wrappers.\n- *Anonymous Syntax* - A type expression syntax exists to refer to a union without declaring a named typed.\n- *Pattern Matching* - Pattern matching works directly on union instance.\n- *Dynamic Pattern Matching* - Pattern matching works when union types are not statically known.\n- *Subtype Relationship* - A subtype relationship exists between Union and Case types.\n- *Conversion Relationship* - A conversion relationship exists between Union and Case types. \n- *Back-Compat* - Union types can be used with older runtimes and older language versions.\n- *Non-ABI Breaking* - Adding or reordering cases does not cause binary breaks.\n- *Non-Allocating/Boxing* - Union and case values can be used without any kind of allocation or boxing.\n- *Custom Unions* - Possible to declare a type that behaves like a union type in the language but has a custom implementation.\n- *Any Time Soon* - Could appear in next few C# releases.\n\n\n\n"
  },
  {
    "path": "meetings/working-groups/discriminated-unions/TypeUnions.md",
    "content": "# Type Unions for C#\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/8928>\n\n## Summary\n[summary]: #summary\n\nA proposal for type unions (aka discriminated unions) in C#.\n\n## Motivation\n\nWhen developing software you may encounter situations where the values that you want to store in a variable are not always the same kind each time through. While you are usually not concerned about storing strings and numbers in the same spot, you may need to store one of a few related types depending on what that data is meant to represent at that moment.\n\nFor example, your application may have both a customer and a supplier definition that share only some of the same properties and you may need to perform a similar operation on both in a fashion that depends on the differences. \n\nTypically, this is where you might choose to distribute those specialized implementations into the types themselves and expose them through common abstract methods or interfaces. However, this is only good practice when those types exist primarily for the purpose of the operation or it makes sense for the operation to appear as an intrinsic part of the type. If the types have a broader purpose, polluting them with methods like this can be undesirable. \n\nThe alternative is to make the same logic handle both types, and if you do this, at some point you will need to declare a parameter or variable that can contain either.  \n\nYou might think you can still solve this through inheritance, by defining both `Customer` and `Supplier` as classes in a hierarchy with a common base type like `Contact`. However, if you are not able to define such a relationship, because either you don't own the definition of these types, or you have too many similar situations and can only solve one of them through inheritance or you choose to not leak the requirements of the specific operation into the definition of the data, the only easy choice you have is to declare the variable as object and let it be just anything.\n\nWhile this may work, it leaves you policing your code through documentation and comments. If you are brave, you can devise such things as special-case hierarchies of wrapper types to put around your values, or custom aggregate types that act as guardians around all the kinds of values you want to possibly store in the variable,\nwhich is time consuming and cumbersome, especially if you have many similar situations but they all involve different sets of types.\n\nIt would be better if C# gave you a way to declare a type that allows you to store one of a limited number of other types in the same place, and let it do all the hard work guarding the variables for you.\n\nMany other languages already do this. They typically call these special types discriminated unions, tagged unions, sum types or type unions.\nAll of them solve the problem of allowing a single variable to hold values of one or more limited forms.\n\nIt is time C# had a feature that did this too.\n\n### Solutions\n\nYou might imagine that the most appropriate implementation for union types in C# is as a hierarchy of classes with an abstract base representing the union itself and all the specific cases of the union as derived classes, just like you or I might make to solve the problem on our own, because it fits really well with the concepts already in the language. This usually works well when you have a specific use case in mind as you design a specific set of classes to solve that specific problem. However, there are some drawbacks to implementing unions as class hierarchies.\n\nOne is the inability to constrain the hierarchy, as object-oriented languages are usually open for inheritance.\n\n> I know there are only three possible subtypes, why does the compiler require me to have a default in my switch expression?\n\nAnother is the inability to represent unions of unrelated types that exist outside a single hierarchy or even to restrict values to a subset of types from within the same hierarchy.\n\n> I want this parameter to be restricted to only Cats and Dogs, not all Animals.\n\nBecause of the class hierarchy implementation, the only way to include a value from a type that already exists is to use a class that is part of the union hierarchy to wrap the value.\n\n> I either have to type these fields as object and trust myself and my team to always do the right thing, or wrap my values in new class instances each time I want to store them in the variable.\n\nAnd lastly, classes in C# require allocation to represent and cannot contain values such as ref types, which may be requirements for specific scenarios.\n\n> I wish I could use unions in my graphics pipeline, but they cause too much gen 0.\n\nFor these reasons, it may be necessary to have more than one kind of union,\nas it may not be possible to satisfy some use cases without compromising others, and if there are multiple kinds it is best to strive to make them appear to look and work the same as as much as possible.\n\nThis proposal attempts to provide solutions to all use cases by declaring four categories for them to fall into, listing some examples for each.\n\n- [Standard](#standard---union-classes) - Use cases where the union and its members can be defined together, because they have a predominant reason to belong together and you intend to use the members as classes on their own. Allocation is not a problem because you would have been allocating the classes regardless.\n    - Protocols, serialization and data transfer types\n    - UI data models (XAML)\n    - Syntax trees\n    - Infrequently changed state machine states\n    - Other polymorphic data models\n    - Values that last a while in union form (fields/properties)\n\n- [Specialized](#specialized---union-structs) - Use cases that need to avoid allocations or require use of special types and are willing to accept some limitations to achieve it.\n    - Allocated in contiguous arrays\n    - Mapped over blocks of memory (interop)\n    - Frequently changed state machine states\n    - Values that last briefly in union form (arguments/return values)\n    - Library types with potentially specialized uses\n    \n- [Ad Hoc](#ad-hoc---ad-hoc-unions) - Use cases that require unions to be formed from existing, possibly unrelated, types and where similarly declared unions with the same member types are interchangeable with one another.\n    - Same examples as standard.\n\n- [Custom](#custom-unions) - Use cases that do not fit well with the other categories.\n    - Already existing types and hierarchies that cannot easily be redefined.\n    - Custom storage layouts.\n    - Custom API shapes and behaviors.\n\n*Note: Pre-declared unions like Option and Result are proposed in the [Common Unions](#common-unions) section.*\n\n*Note: Many of the examples are written in a shorthand syntax made possible by related proposals\nbriefly described in the [Related Proposals](#related-proposals) section.*\n\n----\n\n## Standard - Union Classes\n\nA union class is a named type union that declares all its member types in a single self-contained declaration.\n\n### Declaration\nA union class is declared similar to an enum, \nexcept each member is a type that itself can hold state in one or more state variables.\n\n    union U \n    {\n        A(int x, string y);\n        B(int z);\n        C;\n    }\n\nFor each member, only the name and the list of state variables may be specified.\n\n### Construction\n\nUnion classes are constructed via allocation of the member type.\n\n    U u = new A(10, \"ten\");\n\nThe type of the constructed member is the member type `A`.\nIt is converted to type `U` when assigned to variable `u`.\n\n### Deconstruction\n\nUnion classes are deconstructed by type tests and pattern matching.\n\n    if (u is A a) { ... }\n\n    if (u is A(var x, var y)) { ... }\n\n    if (u is A { y: var y }) { ... }\n\n\n### Exhaustiveness\n\nUnion classes are considered exhaustive.\nIf all member types are accounted for in a switch expression or statement, no default case is needed.\n\n    var x = u switch { \n        A a => a.x,\n        B b => b.z,\n        C c => 0\n        };\n\n### Nullability\n\nNulls can be included in a union class variable using the standard nullability notation.\n\n    U? u = null;\n\n### Implementation\n\nA union class is implemented as an abstract record class with the member types as nested derived record classes.\n\n    [Closed]\n    abstract record U \n    {\n        public record A(int x, string y) : U;\n        public record B(int z) : U;\n        public record C : U { public static C Singleton = new C(); };\n    }\n\n*Note: The `Closed` attribute allows the language to understand that the type hierarchy is closed to sub-types declared outside the base type's module.\nSee the following section [Related Proposals](#related-proposals).*\n\n*Note: Nested member types may be referred to without qualification using related proposal.*\n\n----\n\n## Specialized - Union Structs\n\nSimilar to a union class, a union struct is also a named type union that declares all its member types in a single self-contained declaration, except the union and the member types are all structs and are able to be used without heap allocation.\n\n### Declaration\nA union struct is declared similarly to a union class, with the addition of the `struct` keyword.\n\n    union struct U \n    {\n        A(int x, string y);\n        B(int z);\n        C;\n    }\n\nFor each member, only the name and the list of state variables may be specified.\n\n### Construction\n\nUnion structs are constructed via allocation of the member type.\n\n    U u = new A(10, \"ten\");\n\nThe type of the constructed member is the member type `A`.\nIt is converted to type `U` when assigned to variable `u`.\n\n### Deconstruction\n\nUnion structs are deconstructed by type tests and pattern matching.\n\n    if (u is A a) { ... }\n\n    if (u is A(var x, var y)) { ... }\n\n    if (u is A { y: var y }) { ... }\n\n### Exhaustiveness\n\nUnion structs are considered exhaustive.\nIf all member types are accounted for in a switch expression or statement, no default case is needed.\n\n    var x = u switch { \n        A a => a.x,\n        B b => b.z,\n        C c => 0\n        };\n\n### Nullability\n\nNulls can be included in a union struct variable using the standard nullability notation.\n\n    U? u = null;\n\n### Default\n\nUnion structs can be in an undefined state due to being unassigned or assigned default. This state will not correspond to any declared member type, \nleading to a runtime exception in a switch that relies on exhaustiveness.\n\n    U u = default;  \n\n    // switch throws, since not A, B or C\n    var x = u switch \n    {\n        A a => a.x,\n        B b => b.z,\n        C c => 0\n    }\n\nTo help avoid this, the compiler will produce a warning when a struct union is assigned default.\n\n    // warning: default not a valid state\n    U u = default;  \n\nYou may also avoid the warning by declaring a default state for the union struct, \nassociating a member type as the default.\n\n    union struct U\n    {\n        A(int x, string y);\n        B(int z);\n        C = default;\n    }\n\n\n### Implementation\n\nA union struct is implemented as a struct with nested record structs as member types and an API that converts the member types to and from the aggregate union struct. The interior layout of the union struct is chosen to allow for efficient storage of the data found within the different possible member types with tradeoffs between speed and size chosen by the compiler. \n\n    [Union]\n    struct U \n    {\n        public record struct A(int x, string y);\n        public record struct B(int z);\n        public record struct C { public static C Singleton = default; };\n\n        public static implicit operator U(A value) {...};\n        public static implicit operator U(B value) {...};\n        public static implicit operator U(C value) {...};\n\n        public static explicit operator A(U union) {...};\n        public static explicit operator B(U union) {...};\n        public static explicit operator C(U union) {...};\n\n        public bool TryGetA(out A value) {...};\n        public bool TryGetB(out B value) {...};\n        public bool TryGetC(out C value) {...};\n\n        public enum UnionKind { A = 1, B = 2, C = 3 };\n        public UnionKind Kind => {...};\n    }\n\n*Note: The `Union` attribute identifies this type as a union struct type.*\n\n*Note: A union struct with a default state has its corresponding `UnionKind` declared as 0.*\n\n*Note: this full generated API of the union struct is not shown.*\n\n### Type Tests\nWhenever a type test is made against a known union struct, the union structs API is invoked to determine the outcome instead of \ntesting the union struct's type itself.\n\nFor example, the expression:\n\n    u is A a\n\nis translated to:\n\n    u.TryGetA(out var a)\n\nAnd the switch expression:\n\n    u switch {\n        A a => a.x,\n        B b => b.z,\n        C c => 0\n    }\n\ntranslates to:\n\n    u.Kind switch {\n       U.UnionKind.A when u.TryGetA(out var a) => a.x,\n       U.UnionKind.B when u.TryGetB(out var b) => b.z,\n       U.UnionKind.C when u.TryGetC(out var c) => 0,\n       _ => throw ...;\n    }\n\n### Boxed Unions\n\nA union struct that is boxed is a boxed union struct, not the boxed value of one of its member types. You may never need to be concerned about this since the primary use case for a union struct is to avoid boxing. However, it may be necessary on occasion to box a union struct.\n\nNormally, type tests for two unrelated structs would never succeed when the boxed value is one type and the test is for the other. However, union struct types and their members are related to each other and so it is possible to type test and unbox a boxed union struct into one of its member types.\n\n    U u = ...;\n    object value = u;\n\n    // will succeed since A is known to be a member type of U\n    if (value is A a) {...}\n\nTranslates to:\n\n    if (value is A a || (value is U u && u.TryGetA(out a))) {...}\n    \nLikewise, a boxed member type can be tested and unboxed into a union struct.\n\n    A a = ...;\n    object value = a;\n\n    // will succeed since U is known to have member type A\n    if (value is U u) {...}\n\nTranslates to:\n\n    if (value is U u || U.TryCreate(value, out u)) { ... }\n\nHowever, when neither type in the test is statically known to be related to a union struct, the type test will fail.\n\n    bool IsType<T>(object value) => value is T;\n\n    U u = new A(...);\n\n    // always fails\n    if (IsType<A>(u)) {...}\n\nThis is because the language will not special case the type test when no union struct members are involved, since its not clear which type to check for. Checks for a common union interface could be made to work, but that would unduly impact the vast majority of type tests that do not involve union structs.\n\n### Reflection \n\nYou may be required to interact with union structs when using reflection. \n\nFor example, you may need to pass a union struct to a method, but you have a boxed instance of the member type `A` and not the union struct type `U`. You will need to convert the boxed `A` value to a boxed `U` value.\n\nThe struct union feature provides utility methods to help convert between boxed union structs and boxed member types at runtime.\n\n    public static class TypeUnion\n    {\n        public bool TryConvert(Type unionType, object value, out object? boxedUnion);\n        public bool TryConvert<TUnion>(object value, out TUnion union);\n        public object? GetValue(object? boxedUnion);\n    }\n\n*Note: Union classes and ad hoc unions do not require conversion since they are already in the correct form for reflection use.*\n\n### Ref Union Structs\n\nA union struct with the `ref` modifier may contain state variables that are refs or ref structs.\n\n    ref union struct U\n    {\n        A(ref int x);\n        B(ReadOnlySpan<char> y);\n        C;\n    }\n\nIn this case, both the implementation of the union and the member types with ref struct values \nare translated to ref structs.\n\n    ref struct U\n    {\n        public ref struct A { public ref int x; public A(ref int x) {...}; }\n        public ref struct B { public ReadOnlySpan<char> y; public B(ReadOnlySpan<char> y) {...} }\n        public record struct C { public static C Singleton = default; }\n        ...\n    }\n\n*Note: The impacted member types may be able to continue to be record structs if a ref record struct type is added to C#.*\n\n\n----\n\n## Ad Hoc - Ad Hoc Unions\n\nAd hoc unions are anonymous unions of types declared elsewhere.\n\n### Syntax\n\nYou refer to an ad hoc union using the `or` pattern syntax with parentheses.\n\n    (A or B or C)\n\n### Naming\n\nYou may desire to refer to an ad hoc union using a common name.\nTo do this, use a file or global using alias.\n\n    global using U = (A or B or C);\n\n### Construction\n\nAd hoc unions are constructed by assigning an instance of one of the union's member types to a variable of the ad hoc union type.\n\n    record A(int x, string y);\n    record B(int z);\n    record C() { public static C Singleton = new C(); };\n\n    (A or B or C) u = new A(10, \"ten\");\n\nThe type of the constructed member is the member type `A`.\nIt is converted to type `(A or B or C)` when assigned to variable `u`.\n\n### Deconstruction\n\nAd hoc unions are deconstructed using type tests and pattern matching.\n\n    if (u is A a) {...}\n\n    if (u is A(var x, var y)) { ... }\n\n### Exhaustiveness\n\nAd hoc unions are considered exhaustive.\nIf all member types are accounted for in a switch expression or statement, no default case is needed.\n\n    var x = u switch { \n        A a => a.x,\n        B b => b.z,\n        C c => 0\n        };\n\n### Nullability\n\nNulls can be included in an ad hoc union using the standard nullability notation.\n\n    (A or B)? x = null;\n\n### Equivalence\n\nAd hoc unions with the same member types (regardless of order) are understood by the compiler to be the same type.\n\n    (A or B) x = new A(10, \"ten\");\n    (B or A) y = x;\n\n### Assignability\n\n#### Super and subset assignability \n\nAd hoc unions with the same or a subset of member types are assignable to ad hoc unions with a super set, without runtime checks.\n\n    (A or B) x = new A(10, \"ten\");\n    (A or B or C) y = x;\n\nAd hoc unions with a superset of member types are assignable to ad hoc unions with a subset, with explicit coercions and runtime checks.\n\n    (A or B or C) x = new A(10, \"ten\");\n    var y = (A or B)x;\n\n#### Subtyping assignability\n\nA value of one ad hoc union type can be implicitly coerced to a value of another ad hoc union type without runtime checks if all member types of the source union are the same type or a sub type of at least one of the target union's member types.\n\n    (Chihuahua or Siamese) pet = ...;\n    (Cat or Dog) animal = pet;\n\nOtherwise an explicit coercion can be made involving runtime checks if at least one member type of the source union is a sub type of one of the member types of the target union.\n\n    (Cat or Chihuahua) mostlyCats = ...;\n    (Dog or Siamese) mostlyDogs = (Dog or Siamese)mostlyCats;\n\nFor the purposes of assignability, you may consider a type that is not an ad hoc union to be an ad hoc union of a single type.\n\n    Siamese pet = ...;\n    (Cat or Chihuahua) mostlyCats = pet;\n    Dog dog = (Dog)mostlyCats;\n\n*Note: This works for implemented interfaces too.*\n\n#### Generalized Coercions\n\nA value of a type can be implicitly coerced to a union type if an implicit coercion from that type to one of the union's member types exists.\n\n    (string or double) value = 10;\n\nA value of an ad hoc union can be implicitly coerced to a type if all member type's of the union can be implicitly coerced to the type.\n\n    (int or short) value = 10;\n    double value2 = value;\n\nA value of an ad hoc union can be explicitly coerced to a type if one of the member types is coercible to the type.\n\n    (string or double) value = 10.0;\n    int value2 = (int)value;\n\nA value of an ad hoc union type can be implicitly coerced to another ad hoc union type if all member types of the source union type can be implicitly coerced to one of the member types of the target union type.\n\n    (int or short) value = 10;\n    (float or double) value2 = value;\n\nA value of an ad hoc union type can be explicitly coerced to another ad hoc union type if at least one member of the source union type can be explicitly coerced to one of the member types of the target union type.\n\n    (float or double) value = 10.0;\n    (int or short) value2 = (int or short)value;\n\n*Note: Need rule for which coercion if multiple are possible.*\n\n*Note: This assignability relationship is not intended to be a sub typing relationship. One ad hoc union is not a sub type of another ad hoc union.*\n\n### Interchangeability\n\nAd hoc unions with the same member types are interchangeable through generics and array elements.\n\nFor example, constructing an array of ad hoc unions of generic type parameters,\nwill return an array that is compatible with an array of ad hoc unions of concrete types.\n\n    (T1 or T2)[] F<T1, T2>(T1 v1, T2 v2) => new (T1 or T2)[] { v1, v2 };\n\n    (Dog or Cat)[] pets = F<Dog, Cat>(rufus, petunia);\n\nLikewise, \n\n    IReadOnlyList<(Cat or Dog)> pets = F<Dog, Cat>(rufus, petunia);\n\n### Covariance and Contravariance\n\nAd hoc union types used as with generic type arguments can be used with covariance and contra-variance, if all member types of the two ad hoc unions involved have sub type relationships with members of the other.\n\n I'd tell you the specific rules, but it hurts my head to think about it.\n\n    void Groom(IEnumerable<(Dog or Cat)> animals) => ...;\n\n    List<(Chihuahua or Siamese)> pets = ...;\n    Groom(pet);\n\n*Note: Have Mads write this part.*\n\n### Patterns\n\nAd hoc unions may be used in pattern matching and behave similarly to the `or` pattern, and may also have a variable declaration.\n\n    if (u is Dog or Cat) { ... }  // normal 'or' pattern\n\n    if (u is (Dog or Cat)) { ... }  // type test with ad hoc union\n    \n    if (u is (Dog or Cat) pet) {...}  // type test with ad hoc union and variable\n\n*Note: assigning into an ad hoc union variable may cause boxing of value types*\n\n### Inference\n\nAd hoc unions can be inferred from context when that inference would not otherwise have been possible.\n\nThe conditional and switch expressions can have result types inferred as ad hoc unions from the constituent expressions.\n\n    Dog rufus = ...;\n    Cat petunia = ...;\n    Bird polly = ...;\n\n    // u : (Dog or Cat or Bird)\n    var u = \n          x == 1 ? rufus\n        : x == 2 ? petunia\n        : polly;\n\nLikewise, the return type of a lambda expression can also be inferred using an ad hoc union of the return types of the lambda body.\n\n    T M<T>(F<int, T> f) => f(2);\n\n    (Dog or Cat or Bird) pet = \n        M(x => \n        {\n            if (x == 1)\n                return rufus;\n            else if (x == 2)\n                return petunia;\n            return polly;\n        });\n\n\n*Note: this may cause boxing of value types*\n\n### Implementation\n\nAd hoc unions are implemented through erasure and runtime checks.\n\n    (A or B) ab = new A(10, \"ten\");\n\ntranslates to:\n\n    object ab = new A(10, \"ten\");\n\n#### Runtime checks\n\nAssignments that are not statically known to be correct require runtime checks.\nThe compiler generates a custom method for each unique ad hoc union used in the module.\n\n    object value = ...;\n    var ab = (A or B)value;\n    \ntranslates to:\n\n    object value = ...;\n    object ab = <ValidateAB>(value);\n\n    object <ValidateAB>(object? value) =>\n        value is A or B ? value : throw ...;\n\n*note: Parameters are not checked at entry of a method.*\n\n#### Metadata encoding\n\nThe type of the ad hoc union is encoded in metadata using custom attributes.\n\n    void M((A or B) x);\n\ntranslates to:\n\n    void M([AdHocUnion([typeof(A), typeof(B)])] object x);\n\n*note: The details of this attribute are not yet specified.*\n\n#### Overloading\n\nSince all ad hoc unions erase to the same type, true runtime overloading of methods with ad hoc union parameters is not possible.\n\n    public void Wash((Cat or Dog) pet) { ... }\n    public void Wash((Compact or Sedan) car) { ... }\n\nThis is still an open area of discussion.\n\n----\n\n## Custom Unions\n\nIf you need to declare a union type that cannot be specified as a union class or a union struct,\ndue to specific behaviors that cannot be specified via the union syntax or for other reasons,\nyou may declare you own custom class or struct and have C# recognize it as a custom union type.\n\nFor example, if your union is specified as a class hierarchy, you can give it the same exhaustiveness behavior\nas union classes using the `Closed` attribute.  It will be functionally the same as a union class.\n\n    [Closed]\n    public class U { ... }\n    public class A(int x, string y) : U { ... }\n    public class B(int z) : U { ... }\n\nIf your union is implemented as a struct wrapper with specialized storage rules, you can annotate your struct with the `Union` attribute\nand as long as you provide API's following the union pattern, your struct will be functionally the same as a union struct.\n\n    [Union]\n    public struct U    \n    {\n        public record struct A(int x, string y);\n        public record struct B(int z);\n\n        public bool TryGetA(out var A a) { ... }\n        public bool TryGetB(out var B b) { ... }\n    }\n\nIf your union does not include member types or uses a different API pattern\nyou may provide the API the compiler is expecting via extensions.\n\n    [Union]\n    public struct U\n    {\n        public bool IsA { get; }\n        public void GetA(out int x, out string y);\n        public bool IsB { get; }\n        public void GetB(out int z);\n    }\n\n    public implicit extension UX for U \n    {\n        public record struct A(int x, int y);\n        public record struct B(int z);\n\n        public bool TryGetA(out A a) { ... }\n        public bool TryGetB(out B b) { ... }\n    }\n\n*Note: The full union struct API pattern is not yet specified.*\n\n*Note: You cannot customize the behavior of an ad hoc union, other than your ability to modify the behaviors of\nthe individual member types.*\n\n----\n\n## Common Unions\n\n### Option\n\nOption is a struct union, similar to the type of the same name or purpose found in other languages.\nIt is used to represent a value that may exist or not.\n\n    public union struct Option<TValue>\n    {\n        Some(TValue value);\n        None = default;\n    }\n\nusage:\n\n    Option<string> x = new Some(\"text\");\n    Option<string> y = None;\n\n    if (x is Some(var value)) {...}\n\n    var v = x is Some(var value) ? value : 0;\n\n*Note: Option type not fully specified.*\n\n### Result\n\nResult is a struct union, similar to the type of the same name or purpose found in other languages.\nIt is used to return either a successful result or an error from a function.\n\n    public union struct Result<TValue, TError>\n    {\n        Success(TValue value);\n        Failure(TError error);\n    }\n\nusage:\n\n    Result<string, string> x = Success(\"hurray!\");\n    Result<string, string> y = Failure(\"boo\");\n\n    switch (x)\n    {\n        case Success(var value): ...;\n        case Failure(var error): ...;\n    }\n\n*Note: Result type not fully specified.*\n\n----\n\n## Related Proposals\n\nThese are proposed (or yet to be proposed) features that are presumed to exist by this proposal.\n\n### Closed Hierarchies\n\nA `Closed` attribute applied to an abstract base type declares the closed set of sub-types to be all the \nsub-types in the declaring module.\n\nThe compiler errors when sub types are declared outside the declaring module.\n\nA closed hierarchy is treated as exhaustive by the compiler.\nIf all sub-types are accounted for in a switch expression or statement, no default case is needed.\n\n### Singleton values\n\nTypes that are singletons (with a static `Singleton` property) can be used as values in non-type contexts by implicitly accessing the property.\n\nInstead of:\n    \n    var x = U.C.Singleton;\n\nYou can write:\n\n    var x = U.C;\n\n### Nested Member Shorthand\n\nNames that are otherwise not bound, can be bound to static members or nested types of the target type.\n\nInstead of:\n\n    Color color = Color.Red;\n\nYou can write:\n\n    Color color = Red;\n\nInstead of:\n\n    U u = new U.A(10, \"ten\");\n\nYou can write:\n\n    U u = new A(10, \"ten\");\n\n----\n\n## Q & A\n\nQ: If I can easily declare my own nested hierarchy of records, are union classes needed?  \nA: No, not really. However, it is nice to have a concise syntax that is easy to transition to union structs when necessary with the addition of a single modifier.\n\nQ: If union structs can use more kinds of types with little or no allocation why do union classes and ad hoc unions exist?  \nA: While union structs are necessary in some scenarios, they do not work well in others.\n\n- They may not cause their own allocations but that does not mean they perform better.  \nUnion structs typically have a larger footprint on the stack that is normally copied when assigned, passed or returned.\n\n- Union structs do not work well as a solution for anonymous ad hoc unions, since they are not easily interchangeable.  \nFor example, a union of statically known generic type parameters is a different type at runtime that the same union with the statically known member types,\nand an array of one is not interchangeable with an array of the other.\n\n- Union structs have problems with type tests, casts and pattern matching when boxed or represented in code statically as a generic type parameter.\n\nQ: Why are there no tagged unions?  \nA: Union structs are both tagged unions and type unions. \nUnder the hood, a union struct is a tagged union, even exposing an enum property that is the tag to enable faster compiler generated code, but in the language it is presented as a type union to allow you to interact with it in familiar ways, like type tests, casts and pattern matching.\n\nQ: Can the compiler skip constructing a union struct's member type if I immediately assign it to union struct variable?  \nA: Yes, this is an expected optimization.\n\nQ: Can the compiler skip copying my union struct state variables into a member type if I deconstruct my union directly to variables?   \nA: Yes, this is an expected optimization.\n\nQ: Is the union struct, like the union class, the base type of its member types?  \nA: No, struct types do not allow for actual inheritance.\nLogically, the union struct acts as the base type such that there are automatic conversions between them,\nbut this illusion falls apart eventually as the relationship extends no further into the type system and runtime.\n\nQ: Can I declare ad hoc unions with names?  \nA: Not at this time. If you need a name to help describe or avoid repeating a lengthy union, use a global using alias.\n\nQ: Can I have an ad hoc union that does not box value types?  \nA: Ad hoc unions box value types. If you need to avoid boxing use a union struct.\n\nQ: Can I have an ad hoc union that includes ref types?  \nA: Ad hoc unions cannot include ref types. If you need to include ref types use a union struct.\n\nQ: If variables typed as object are bad, why are ad hoc unions erased to object?  \nA: Using `object` is the solution developers are most likely using today. \nThe ad hoc union feature is an improvement.\nRepresented as an object, the value is in the best form to be understood by the type system at runtime, it is only lacking static type safety at compile time.\nUsing a wrapper type to enforce safety interferes with simple operations like type tests and casts.\nThe Ad Hoc Union feature adds support for understanding ad hoc union types at compile time and generates validation checks to help keep your code correct at runtime.\n\nQ: Can I access common properties and methods of the ad hoc union without handling each type case?  \nA: No, you can only access the values of an individual type by first successfully converting the union to that type.\n\nQ: Why don't you just use the same kinds of unions that are in F#?  \nA: F# has union types that correspond to both the union classes and union structs definitions in this specification, with the difference of treating the members as types in the language instead of tag states with associated state variables.\nAd hoc unions are similar to the kind of type unions found in Typescript.\n\nQ: Why do I need the `Option` type if I can do the same thing with nulls and nullable reference types?  \nA: You many not need the `Option` type at all if you are comfortable with using nulls for the same purpose. Some developers prefer an option type as it has stronger enforcement than nullable types do in C#.\n\nQ: Will the `Option` and `Result` type also include the monadic behaviors that these types enable in F#?  \nA: No, C# will not include any monadic behaviors in the language for these types at this time.\n\nQ: Why do I need the `Result` type when I already have exception handling?  \nA: Many of the use cases for the `Result` type are solved using exception handling in C#. However, you may prefer to avoid exception handling and require the caller to deal with errors explicitly when errors are expected and occur commonly at runtime.\n\nQ: Types similar to the `Option` and `Result` types are already available in other 3rd party libraries. Why are you adding them to the runtime?  \nA: Many developers have asked us to include these types in the runtime to standardize them for interoperability between libraries.\n"
  },
  {
    "path": "meetings/working-groups/discriminated-unions/Union implementation challenges.md",
    "content": "# Union implementation challenges\n\nThis heavily references https://github.com/dotnet/csharplang/blob/main/proposals/TypeUnions.md.\n\n## Proposal: start with union classes\n\nThe four kinds of unions outlined in [TypeUnions.md](https://github.com/dotnet/csharplang/blob/main/proposals/TypeUnions.md) do not need to be viewed as alternatives - any or all of them could coexist nicely at the language level.\n\nHowever, some of them have significant challenges at the implementation level, which may need to some hard choices being made at the language level. Some of these challenges are outlined below. \n\nThe one approach that seems pretty straightforward from an implementation view point is [Union classes](https://github.com/dotnet/csharplang/blob/main/proposals/TypeUnions.md#standard---union-classes). We also estimate that it has high value on its own, addressing a large chunk of scenarios. We therefore propose that we double down on language design and implementation for this direction, with the likely outcome of it arriving in C# before the others.\n\nAlong the way we can still try to make progress on the others.\n\n## Challenges with union structs\n\n[Union structs](https://github.com/dotnet/csharplang/blob/main/proposals/TypeUnions.md#specialized---union-structs) are an alternative to class structs where the union value doesn't need to be allocated, which can be a performance benefit.\n\nHowever, the way class unions represent the different cases is through inheritance, and structs do not have that. The most straightforward way for a union struct to be able to represent all its different cases is for it to have a field for each of them, as well as a `Kind` field indicating which of the cases the current value belongs to.\n\nThis easily leads to large structs, with a lot of copying when values are passed around, and a lot of wasted memory, since all but one of the case fields is empty. There are ways of compacting the representation, e.g. by overlapping fields, but the more you do, the more time is spent packing and unpacking values. This starts to offset the benefits of avoiding allocation.\n\nIf compaction uses unsafe techniques, the runtime might get confused and turn off its own optimizations. Runtime work to address this directly would likely be costly.\n\nAny representation also needs to deal gracefully with evolution of unions. If a new member is added, and that causes the representation to change materially, will existing compiled code continue to work correctly? The public representation of a union struct needs to be stable against recompilation.\n\n## Challenges with ad-hoc unions\n\n[Ad-hoc unions](https://github.com/dotnet/csharplang/blob/main/proposals/TypeUnions.md#ad-hoc---ad-hoc-unions) are anonymous type expressions combining other types.\n\nThe most obvious way to implement ad-hoc unions is via erasure: the compiler simply replaces occurrences of any ad-hoc union with `object` (or perhaps a common base type of the constituent types), and adds some metadata to public signatures to describe what the types \"really\" are. This is the same approach we use for `dynamic`, tuple names and nullable annotations.\n\nThis mostly works! However, it isn't quite safe at runtime. The most confounding problem is when ad-hoc unions are used as type parameters. Imagine this type:\n\n``` c#\npublic class MyCollection<T>\n{\n    public bool TryAdd(object o)\n    {\n        if (o is T t)\n        {\n            // add t\n            return true;\n        }\n        else return false;\n    }\n    ...\n}\n```\n\nIf you use an ad-hoc union as the type argument, it will be erased to `object` and the type check in `TryAdd` will always succeed, violating the type safety of the collection!\n\nAn alternative is to not erase, and instead have implementation types such as `ValueUnion<T1, T2>` etc. However, this has semantic consequences: Now `(string or bool)` will not be the same type as `(bool or string)`! We've investigated runtime approaches to dealing with this, but they are imperfect and very expensive!\n"
  },
  {
    "path": "meetings/working-groups/discriminated-unions/allows.md",
    "content": "# `allows` syntax for union declarations\n\n## Summary\n\nAs compared to the current proposal, this proposal retains all aspects, but removes the parentheses in the declaration syntax:\n\n```cs\nunion Pet(Cat, Dog);\n```\n\nAnd replaces them with the `allows` keyword (first introduced in C# 13):\n\n```cs\nunion Pet allows Cat, Dog;\n```\n\nAll features of the syntax in the current proposal are retained. The following example exercises more of the syntax:\n\n```cs\n[Description(\"Example\")]\npublic partial union Pet<T> allows Cat<T>, Dog<T>\n    where T : allows ref struct\n{\n    // members\n}\n```\n\n## Motivation\n\nThe current syntax is a solid and workable syntax. While that is true, there are advantages that would be uniquely available with the `allows` syntax: syntactic feel and reception, and a path to coherence with closed hierarchies.\n\nOn syntactic feel, some LDM and community members have voiced concerns with commas-inside-parentheses for the syntax. Comma-separated items, especially within parens, convey a sense of carrying or passing _all_ of the items rather than just one of them. The syntax most closely resembles primary constructors based on its placement in the type declaration, but it gains nothing by this resemblence. `allows` communicates that this is a constraint, not a set of items which are all present together.\n\nClosed hierarchies are also expected to need to list the allowed subtypes at the base declaration. This is so that exhaustiveness can be evaluated for a given expression involving a closed hierarchy without having to first bind all type declarations in the entire compilation. Java uses the keyword `permits` for the same purpose (<https://openjdk.org/jeps/409>). Thus, closed hierarchies could also benefit from this same syntax. This syntax even works well alongside primary constructors:\n\n```cs\nclosed record Pet(int Feet) allows Cat, Dog;\n\nrecord Cat(int Feet, ...) : Pet(Feet);\nrecord Dog(int Feet, ...) : Pet(Feet);\n```\n\nIt would feel coherent to have the exact same syntax meaning the exact same thing between unions and closed non-unions.\n\n## Detailed design\n\nAll elements of the syntax retain the meaning they have under the current proposal, and can appear in all the same combinations. The only change is replacing the tokens `(`...`)` with the token `allows`.\n\n### Base types\n\nThinking to the future, if unions ever supported base types such as implementing interfaces, it might look like this:\n\n```cs\nunion Pet<T> allows Cat<T>, Dog<T>\n    : ISomeInterface\n    where T : allows ref struct\n{\n    // members\n}\n```\n\nPutting everything on one line shows a possible downside where the `:` may appear strongly related to the last allowed type:\n\n```cs\nunion Pet<T> allows Cat<T>, Dog<T> : ISomeInterface;\n```\n\nWhere the original design's parentheses would clearly show that the `:` applies to `Pet<T>` and not to `Dog<T>`:\n\n```cs\nunion Pet<T>(Cat<T>, Dog<T>) : ISomeInterface;\n```\n\nIf we do not expect base types to be a large percentage of the use cases for the syntax, it may be wise not to optimize heavily around them. Both the `allows` syntax and the parenthesized syntax have aspects which may be initially misleading. Perhaps it could hit a sweet spot to optimize the syntax that will be seen more often.\n\n## Specification\n\nThe grammar is updated to the following:\n\n```antlr\nunion_declaration\n    : attributes? struct_modifier* 'partial'? 'union' identifier type_parameter_list?\n      ('allows' type (',' type)*)? type_parameter_constraints_clause*\n      (`{` struct_member_declaration* `}` | ';')\n    ;\n```\n"
  },
  {
    "path": "meetings/working-groups/discriminated-unions/brace-syntax.md",
    "content": "# Braced Union Syntax\n\n## Summary\n\nNominal type unions are declared using a comma separated list of case members inside braces.\n\nSome unions declare fresh cases like an enum does.\n\n```csharp\nunion Gate\n{\n    Locked,             // declaration of Gate.Locked\n    Closed,\n    Open(float Percent) // declaration with a parameter list\n}\n```\n\nWhile others refer to existing types as cases.\n\n```csharp\nrecord Cat(...);\nrecord Dog(...);\n\nunion Pet\n{\n    Cat,                // reference to type Cat\n    Dog\n}\n```\n\nAnd some do both.\n\n```csharp\nunion Result<T>\n{\n    T,                      // reference to type T\n    Error(string Message)   // declaration of Result<T>.Error\n}\n```\n\nNotice, there is an ambiguity here since simple named members sometimes refer to existing types and other times refer to declarations of fresh ones. How this ambiguity is resolved is the crux of the issues surrounding syntax for unions.\n\n#### Disambiguating\n\nThe following is an explanation of how the proposal disambiguates without introducing additional syntax.\n\nIf a union member is a simple name that refers to a type in scope, it is a type reference.\n\n```csharp\nrecord Cat(...);\nrecord Dog(...);\n\nunion Pet\n{\n    Cat,        // reference to type Cat\n    Dog\n}\n```\n\nIf a union member is a simple name that does not refer to a type in scope, it is a declaration.\n\n```csharp\nunion Gate\n{\n    Locked,     // declaration of Gate.Locked\n    Closed,\n    Open(float Percent);\n}\n```\n\nIf a union member is a simple name with a parameter list, it is a declaration.\n\n```csharp\nunion Gate\n{\n    Locked,\n    Closed,\n    Open(float Percent);    // declaration of Gate.Open\n}\n```\n\nIf a union member is not a simple name, it is a type reference.\n\n```csharp\nunion SomeUnion\n{\n    System.Int32,           // dotted name can only be reference \n    Int32?,                 // nullable types can only be references\n    int,                    // keyword type can only be reference\n    Int32[],                // array can only be reference\n    IEnumerable<Int32>      // type arguments can only exist on references\n}\n```\n\nTo override a simple name to be a declaration instead of a type reference add an empty parameter list.\n\n```csharp\nusing Locked=Int32;\n\nunion Gate\n{\n    Locked(),                // declaration of Gate.Locked\n    Closed,\n    Open(float Percent)\n}\n```\n\n#### Other Declarations\n\nTo include additional kinds of declarations within the braces, use a semicolon at the end of the case member list.\n\n```csharp\nunion Pet\n{\n    Cat,\n    Dog,\n    Bird;\n\n    public bool HasPaws => this is Cat or Dog;\n}\n```\n\n*Note: The declaration or type reference list can be thought of as a single declaration in the body of the type. The semicolon is not acting as a separator between the two sections, it is a terminator for the case member declaration as with other declarations. However, it is optional if the case member list is the only declaration.*\n\n## Motivation\n\nTo have a nominal union syntax that works equally well for declaring unions of existing types and declaring unions of fresh types in a single list.\n\nHaving a union declaration syntax be similar to enum syntax is ideal, since it leans on the existing enum concept of a set of finite values or states. An enum-like syntax is one that appears as a list of simple names with the one addition that members may include declarations of associated values.\n\nThis proposal tries to find a compromise between type references and type declarations that maintains this connection.\n\n\n## Specification\n\nThis is a specification for an alternate syntax for nominal type unions. It otherwise depends on the existing nominal type union spec and case declarations spec, even though it eliminates the need for case declarations within union declarations.\n\n### Syntax\n\n```antlr\nunion_declaration: \n    attributes? struct_modifier* 'partial'? \n    'union' identifier type_parameter_list?\n    type_parameter_constraints_clause* \n    `{` union_body `}` \n    ;\n\nunion_body:\n    union_member_list\n    (';' struct_member_declaration*)?\n    ;\n\nunion_member_list: \n    union_member (',' union_member)*\n    ;\n\nunion_member: \n    type \n    | identifier parameter_list\n    ;\n```\n\n### Member Declarations\n\nUnion member declarations are translated to nested records with the same declaration. This is done using the same rules defined in case declarations feature, except members cannot declare type parameters, base types or bodies.\n\n```csharp\nunion Pet\n{\n    Cat(string Name, string Personality),\n    Dog(string Name, bool Friendly),\n    Bird(string Name, string Species),\n    None\n}\n```\n\nTranslates to:\n\n```csharp\nrecord struct Pet : IUnion\n{\n    public Pet(Cat value) { this.Value = value; }\n    public Pet(Dog value) { this.Value = value; }\n    public Pet(Bird value) { this.Value = value; }\n    public object? Value { get; }\n\n    public record Cat(string Name, string Personality);\n    public record Dog(string Name, bool Friendly);\n    public record Bird(string Name, string Species);\n    public record None;\n}\n```\n\nTo describe a more full featured case type, you must declare the case types separately. They may be nested types.\n\n```csharp\nunion Pet\n{\n    Cat,\n    Dog,\n    Bird,\n    None;\n\n    public record Cat(string Name, string Personality) : IHavePaws {...};\n    public record Dog(string Name, bool Friendly) : IHavePaws {...};\n    public record Bird(string Name, string Species) { ... };\n    public record None {...};\n}\n```\n\n### Type Reference Scope\n\nThe scope available for members to be type references is the body of the union itself, including any type parameters declared.\n\nUnions can refer to their own nested types.\n```csharp\nunion Shape\n{\n    Point,\n    Line,\n    Circle;\n\n    public class Point {...};\n    public class Line {...};\n    public class Circle {...};\n}\n```\n\nUnions can refer to types that are their own type parameters.\n\n```csharp\nunion Union<T1, T2> { T1, T2 };\n```\n\nOr combination thereof.\n\n```csharp\nunion OneOrMore<T> \n{ \n    T, \n    IEnumerable<T>,\n    Two;\n\n    public record Two(T First, T Second) : IEnumerable<T> {...};\n};\n```\n\nA union member can refer to another union member, but that would be an error to include the same member twice.\n\n```csharp\nunion Pet\n{\n    Cat(...),\n    Cat\n}\n```\n\n## Concerns\n\n* Simple name declarations can accidentally become references if same named types are introduced in scope.\n\n    > This may not be a big concern, since this kind of change will likely impact use sites and cause build breaks. And it can be avoided be using parentheses.\n\n    > Possible solution may be to add a warning when a simple name matches a type in scope and the union also has member declarations.\n\n    ```csharp\n    record Cat(...);\n\n    union Pet \n    {\n        Cat,        // warning - Identifier refers to external type in \n        Dog(...)    //           union with member declarations.\n    }\n    ```\n\n* Simple names type references can unexpectedly become declarations if/when the type is removed or no longer in scope.\n\n    > No solution yet for this one.    \n\n* There is no easy grow up story for declared members.  \n\n    > Having to declare the member fully as a nested type is not that much hardship when deviating from the common case.\n\n\n## Alternatives\n\nThe inability to be certain about the nature of simple names in the primary proposal leads to a desire to explore alternatives that are easier to digest.\n\n### Simple Names are Type References\n\nIn this alternative, all simple names are interpreted as type references. The only way to get one to mean a member declaration is to include an empty parameter list.\n\n```csharp\nunion Pet \n{ \n    Cat,                        // reference to existing type or error\n    Dog\n}\n\nunion Gate\n{\n    Locked(),                   // declaration of Gate.Locked\n    Closed(),\n    Open(float Percent)\n}\n```\n\n#### Variation\n\nA variation of this is to require additional syntax on all declarations.\n\n```csharp\nunion Pet \n{ \n    Cat,                        // reference to existing type or error\n    Dog\n}\n\nunion Gate\n{\n    case Locked,                // declaration of Gate.Locked\n    case Closed,\n    case Open(float Percent)\n}\n```\n\nThis eliminates the need to put parentheses at the end of member declarations, but it does require non-enum-like syntax for the main enum-like scenario.\n\nIt also may appear awkward when mixed.\n\n```csharp\nrecord Cat(...);\n\nunion Pet\n{\n    Cat,\n    case Dog(...);\n}\n```\n\nFor example, it's non-intuitive why the declaration is the only one denoted as a case, when they are all cases. Possibly a different keyword would work better.\n\n```csharp\nunion Pet\n{\n    Cat,\n    declare Dog(...);\n}\n```\n\nDownsides:\n\n* It is no longer enum-like. You cannot simply start with an enum and upgrade it to a union without adding parentheses to all members.\n\n\n### Simple Names Are Declarations\n\nIn this alternative, all simple names are considered to be declarations. Instead, type references require additional syntax. This makes union syntax be enum-like by default for declarations.\n\n```csharp\nunion Gate\n{\n    Locked,                     // declaration of Gate.Locked\n    Closed,\n    Open(float Percent)\n}\n```\n\nAdditional punctuation indicates it is a type reference.\n\n```csharp\nunion Pet\n{   \n    ~Cat,                       // reference to existing type or error\n    ~Dog\n}\n```\n\nOther single character punctuation options:\n\n```csharp\n^Cat,       \n`Cat,       // finally the back-tick\n:Cat,\n=Cat,       // maybe..\n>Cat,\n!Cat,\n?Cat,\n$Cat,\n&Cat,\n*Cat,\n/Cat,\n+Cat,\n-Cat,\n[Cat]\n(Cat)\n<Cat>\n```\n\n#### Variation: Keywords\n\nA keyword indicates the name is a type reference.\n\n```csharp\nunion Pet\n{\n    type Cat,                     // reference to existing type or error\n    type Dog\n}\n```\n*Note: An alternative to this alternative is to only require the extra syntax for simple names (identifiers). Unfortunately, simple name type references are the common case.*\n\nDownsides:\n* Type references end up requiring additional syntax making the union declaration feel biased toward being used with declarations when in fact the underlying union concept is the opposite.\n\n#### Variation: Conditional\n\nSimple names are declarations if other declarations also exist in the same union declaration, otherwise they are type references.\n\nThis alternative determines the meaning of simple names depending on the meaning of other members.  If any other member has a parameter list then simple names are member declarations too.\n\n```csharp\nunion Pet\n{\n    Cat,               // type reference since no members have parameter lists\n    Dog\n}\n\nunion Gate\n{\n    Locked,            // declaration of Gate.Locked\n    Closed,\n    Open(float Percent)\n}\n```\n\nThis alternative works well since the common case is that unions have case members that are either all references or all declarations, and those with declarations will have at least one with parameters.\n\nHowever, there would be no way to include a type that can only be specified as a simple name when there is also a declaration.\n\n```csharp\nunion Result<T>\n{\n    T,                      // oops, this is a now a declaration \n    Error(string message)\n}\n```\n\nA variant of this variation could, of course, introduce an optional syntax to specify references, but would have all the same issues as the other alternate syntaxes.\n\n```csharp\nunion Result<T>\n{\n    ~T,\n    Error(string message)\n}\n```\n\nDownsides:\n* The condition makes it cumbersome to understand the meaning of simple names.\n* It still needs additional syntax in some cases.\n\n### Separate Indicator\n\nIn this alternative some part of syntax outside the braces indicates the meaning of simple named members inside the braces.\n\nIn this example, the keyword `type` is added to the declaration to indicate that simple names inside the braces mean references to existing types, not declarations.\n\n```csharp\ntype union Pet\n{\n    Cat,        // reference to existing type or error\n    Dog,\n    Bird\n}\n```\n\nWithout the additional keyword, the default meaning is a fresh case member.\n```csharp\nunion Gate\n{\n    Locked,     // declaration of Gate.Locked\n    Closed,\n    Open(float Percent)\n}\n```\n\nTo have a mix of both simple named type references and declarations you must use empty parameter lists to get have a simple name declaration.\n\n```csharp\nrecord Unknown;\n\ntype union Gate\n{\n    Unknown,          // reference to external type\n    Locked(),         // reference to Gate.Locked\n    Closed(),\n    Open(float Percent)\n}\n```\n\nDownsides:\n* There now seems to be two different almost identical syntaxes and the reader must be aware which is in use to understand the meaning of a simple name.\n\n### Type References Outside\n\nIn this alternative all type references are specified somewhere outside the braces leaving the body to only specify declarations. This allows a declaration-only union to remain enum-like and takes advantage of the intuition that braces inside declarations contain other declarations.\n\nThe example includes a list of references to existing types inside parentheses, similar to the current plan-of-record proposal, except also including the enum-like syntax for fresh case member declarations.\n\n```csharp\nunion Pet (Cat, Dog, Bird);  // references to existing types\n\nunion Gate\n{\n    Locked,                 // declaration of Gate.Locked\n    Closed,\n    Open(float Percent)\n}\n```\n\n#### Variation: Brackets\n\nThis alternative changes the parentheses to square brackets to avoid similarity with primary constructors.\n\n```csharp\nunion Pet [Cat, Dog, Bird];  // clearly not a primary constructor or declarations\n\nunion Gate\n{\n    Locked,                 // declaration of Gate.Locked\n    Closed,\n    Open(float Percent)\n}\n```\n\nThis similarity of the square brackets to collection expressions helps reinforce that the members listed are not declarations.\n\n#### Variation: Keyword list\n\nThis alternative is similar to the 'allows' keyword proposal, but it retains the enum-like syntax for declarations inside the braces.\n\nA keyword initiated clause with list of type expressions appears somewhere in the syntax after the name and possible type parameters.\n\n```csharp\nunion Pet allows Cat, Dog, Bird;\n\nunion Gate\n{\n    Locked,\n    Closed,\n    Open(float Percent)\n}\n```\n\nOther example keywords:\n\n```csharp\nunion Pet includes Cat, Dog, Bird;\nunion Pet contains Cat, Dog, Bird;\nunion Pet has Cat, Dog, Bird;\nunion Pet with Cat, Dog, Bird;\nunion Pet of Cat, Dog, Bird;\n```\n\nDownsides:\n* The keyword implies meaning that may not correctly describe what is going on. \n* It makes the case members appear to be more of an addendum than the core of the declaration.\n\n## Extra Credit\n\n### Declarations Outside Braces\n\nThis alternative moves away from using braces as a means of listing case types. It allows both case member declarations and type references to be included in a single list but leave the brace syntax for other kinds of declarations.\n\n```csharp\nunion Pet(Cat, Dog, Bird);  // type references\n\nunion Gate(Locked(), Closed(), Open(float Percent));  // declarations\n\nunion Result<T>(T, Error(string Message)); // references and declarations.\n```\n\nIt has all the issues as the braces syntax, requiring the same kinds of solutions, but does not try to be enum-like.\n\n#### Variation: Leaving the Nest\n\nA variation of this proposal allows for declarations both inside and outside of the braces. Declarations inside the braces become nested, while declarations outside the braces become types in the same declaration scope as the union. Type references can appear in both, but simple names are considered type references outside the braces and declarations inside the braces. The is no syntax that inverts the meaning of simple names inside the braces.\n\n```csharp\nnamespace NS;\n\nunion Gate\n(\n    Locked(),  // declaration of NS.Locked\n    Closed(),\n    Open(float Percent)\n);\n\nunion Gate\n{\n    Locked,   // declaration of Gate.Locked\n    Closed,\n    Open(float Percent)\n}\n\nunion Result<T>\n(\n    T,                        // reference to type T\n    Error(string Message)     // declaration of NS.Error\n}\n\nunion Result<T>(T)            // reference to type T\n{\n    Error(string Message)     // declaration of Result<T>.Error\n}\n```\n"
  },
  {
    "path": "meetings/working-groups/discriminated-unions/enum-like-unions.md",
    "content": "# Enum-like unions\n\n## Summary\n\n**Enum-like unions** are \"enum-like\" in the same sense that field-like events are \"field-like\": They are introduced by the same keyword (`union`/`event`), and to the consumer they are the same kind of thing (unions/events), but their body uses an alternative, terser, syntax that is similar to another kind of declaration (enums/fields):\n\n```csharp\npublic union Gate { Locked, Closed, Open(float percent) }\n```\n\n## Motivation\n\nFor straightforward \"discriminated union\" scenarios, it is desirable to have a very terse syntax for declaring fresh case types, and it is helpful to lean into enum syntax (curly braces, simple names, commas) to manifest the analogy. Both these claims are borne out by other programming languages.\n\nHowever, to a consumer such unions aren't observably different from ones declared with type references, just like field-like events aren't observably different from other events. Sharing the `union` keyword makes the shared semantics clear. \n\nAt the same time, this lets us allow the same enum-like bodies in closed hierarchies if we want, creating symmetry between the two kinds of closed type declarations.\n\nFinally, while this proposal separates \"struct-like\" and \"enum-like\" declarations, it leaves open the possibility of unifying them.\n\n## Detailed design\n\n### Syntax\n\n```antlr\nunion_declaration\n    : attributes? struct_modifier* 'partial'? 'union' identifier type_parameter_list? union_declarator\n    ;\n\nunion_declarator\n    : struct_like_union_declarator\n    | enum_like_union_declarator\n    ;\n\nstruct_like_union_declarator\n    : '(' type (',' type)* ')' type_parameter_constraints_clause* \n      (`{` struct_member_declaration* `}` | ';')\n    ;\n    \nenum_like_union_declarator\n    : type_parameter_constraints_clause* `{` enum_like_union_member_list `}`\n    ;\n\nenum_like_union_member_list\n    : enum_like_union_member (',' enum_like_union_member)* (`,`)?\n    ;\n\nenum_like_union_member\n    : identifier (`(` parameter_list? `)`)?\n    ;\n```\n\nNote that the `struct_like_union_declarator` shown here just reflects the current plan of record, but could change as part of other decisions. Its exact shape is not part of this proposal.\n\n### Semantics\n\nEnum-like unions are translated into struct-like unions, where enum-like union members are translated into nested record declarations (with primary constructor parameter lists if they contain parameter lists `(...)`) and added to the resulting unions case type list. \n\nFor example:\n\n```csharp\npublic union Gate { Locked, Closed, Open(float percent) }\n```\n\nTranslates to:\n\n```csharp\npublic union Gate(Gate.Locked, Gate.Closed, Gate.Open)\n{\n    public record class Locked;\n    public record class Closed;\n    public record class Open(float percent);\n}\n```\n\n### Examples\n\n```csharp\npublic union Pet\n{\n    Cat(string Name, string Personality),\n    Dog(string Name, bool Friendly),\n    Bird(string Name, string Species),\n    None\n}\n\npublic union Option<T>\n{\n    None,\n    Some(T value),\n}\n```\n\n## Drawbacks\n\n- Is it too subtle that the presence or absence of a list of case type references determines whether the `{...}` body is enum-like or struct-like?\n\n- Does the `enum` keyword need to be present to stress the analogy to enums?\n\n- Like enums, enum-like unions cannot declare struct members such as function members or nested types. Their body is reserved for case members.\n\n- Types declared as enum-like union members cannot declare their own bodies. This represents quite a cliff, as doing so for even one member requires the whole union to be rewritten as a struct-like union.\n\n\n## Alternatives\n\n- Use other keywords or additional keywords to further differentiate an enum-like union declaration from a struct-like one.\n\n## Additions\n\n- Allow closed hierarchies to also have an enum-like body. That way, the author of a \"discriminated union\" can freely choose whether to implement it as a union or a closed class without paying a syntactic penalty either way:\n\n    ```csharp\n    public union Gate { Locked, Closed, Open(float percent) }\n    // or\n    public closed class Gate { Locked, Closed, Open(float percent) }\n    ```\n\n- Allow the `enum_like_union_member_list` to be followed by a `;` and a list of `struct_member_declaration`s so that enum-like unions also can have e.g. function members.\n\n    ```csharp\n    union Pet\n    {\n        Cat,\n        Dog,\n        Bird;\n    \n        public bool HasPaws => this is Cat or Dog;\n    }\n    ```    \n    \n    This could also be allowed in actual enum declarations, maintaining the analogy.\n\n    ```csharp\n    enum TrafficLight\n    {\n        Green,\n        Yellow,\n        Red,\n        \n        public bool Stop => this is not Green;\n    }\n    ```\n    \n    Additionally, if we continue to embrace the [Case declarations](https://github.com/dotnet/csharplang/blob/main/proposals/case-declarations.md) proposal, this could mitigate the cliff occurring when you want to add a member body to a case type: Simply put that case type as a case declaration:\n    \n    ```csharp\n    public closed record GateState\n    {\n        Closed, Locked; // Simple cases\n        case Open(float Percent)\n        {\n            public static Open Fully => new Open(100);\n        }\n    }\n    ```\n    \n- Fully unify struct-like and enum-like declarations by allowing both a list of case type references and a list of enum-like union members in the same union declaration. This would be a superset of the proposal, but would go against the current decision to keep the two kinds of union declarations separate. It is unclear how many scenarios would benefit from this, but it is also unclear who would benefit from forbidding it.\n\n    ```csharp\n    public record None;\n    public union Option<T>(None) { Some(T value) }\n    ```\n\n## Open questions\n\n- Does this coexist with [Case declarations](https://github.com/dotnet/csharplang/blob/main/proposals/case-declarations.md)?\n"
  },
  {
    "path": "meetings/working-groups/discriminated-unions/extended-enums.md",
    "content": "# Discriminated Unions and Enhanced Enums for C#\n\nThis proposal introduces enhanced enums as an elegant way to build discriminated unions in C#. Building on [type unions](https://raw.githubusercontent.com/dotnet/csharplang/refs/heads/main/proposals/unions.md), enhanced enums provide familiar, concise syntax for algebraic sum types where cases are known at declaration time.\n\nIt consolidates design feedback from many years of repository discussions, especially [#113](https://github.com/dotnet/csharplang/issues/113) and related issues.\n\n<details>\n  <summary>Key discussion threads...</summary>\n\n  - [#75](https://github.com/dotnet/csharplang/issues/75) - Early comprehensive discussion exploring DU syntax options including enum class\n  - [#2962](https://github.com/dotnet/csharplang/discussions/2962) - Major discussion on Andy Gocke's DU proposal, debating enum class vs enum struct\n  - [#7016](https://github.com/dotnet/csharplang/issues/7016) - Fast, efficient unions proposal focusing on struct-based implementations\n  - [#3760](https://github.com/dotnet/csharplang/discussions/3760) - Community \"shopping list\" of desired discriminated union features\n  - [#7544](https://github.com/dotnet/csharplang/issues/7544) - Simple encoding of unions exploring type unions vs tagged unions\n  - [#8804](https://github.com/dotnet/csharplang/discussions/8804) - String-based enums for cloud services with extensibility needs\n  - [#1860](https://github.com/dotnet/csharplang/issues/1860) - Long-running request for string enum support citing TypeScript/Java\n  - [#9010](https://github.com/dotnet/csharplang/discussions/9010) - \"Closed\" enum types that guarantee exhaustiveness\n  - [#6927](https://github.com/dotnet/csharplang/discussions/6927) - Constant enums discussion around strict value enforcement\n  - [#7854](https://github.com/dotnet/csharplang/issues/7854) - Exhaustiveness checking for ADT patterns using private constructors\n  - [#8942](https://github.com/dotnet/csharplang/discussions/8942) - Track subtype exhaustiveness for closed hierarchies\n  - [#8926](https://github.com/dotnet/csharplang/discussions/8926) - Extensive discussion on Option<T> as canonical DU use case\n  - [#7010](https://github.com/dotnet/csharplang/discussions/7010) - Union types discussion heavily featuring Option<T> and Result<T>\n  - [#274](https://github.com/dotnet/csharplang/discussions/274) - Java-style class-level enums with methods and constructors\n  - [#8987](https://github.com/dotnet/csharplang/discussions/8987) - Champion \"permit methods in enum declarations\"\n  - [#5937](https://github.com/dotnet/csharplang/discussions/5937) - Smart Enums In C# Like Java\" (extra state!)\n  - [#782](https://github.com/dotnet/csharplang/discussions/782) Sealed enums (completeness checking in switch statements)\n  - [#2669](https://github.com/dotnet/csharplang/discussions/2669) Feature request: Partial enums\n</details>\n\n## 1. Overview\n\nC# gains a layered approach to union types: type unions provide the foundation for combining types, while enhanced enums offer elegant syntax for discriminated unions where you define cases and their union together.\n\n```csharp\n// Type unions - combine existing types\nunion Result(string, ValidationError, NetworkException);\n\n// Shape enums - discriminated unions with integrated case definitions\nenum struct PaymentResult // or `enum class`\n{\n    Success(string transactionId),\n    Declined(string reason),\n    PartialRefund(string originalId, decimal amount)\n}\n```\n\n## 2. Motivation and Design Philosophy\n\n### From Type Unions to Discriminated Unions\n\nType unions solve the fundamental problem of representing \"one of several types\". A particularly important pattern is discriminated unions, where:\n\n- Cases are defined together as a logical unit\n- Each case may carry different data\n- The set of cases is typically closed and known at design time\n\nShape enums provide natural syntax for this pattern—expressing the entire discriminated union in a single declaration rather than manually defining and combining types.\n\n### Limitations of Current Enums\n\nToday's C# enums have significant limitations:\n\n1. **No associated data**: Cases are merely integral values\n2. **Not truly exhaustive**: Any integer can be cast to an enum type\n3. **Limited to integers**: Cannot use strings or doubles\n\nEnhanced enums address all these limitations while preserving conceptual simplicity.\n\n### Building on Familiar Concepts\n\nBy extending the existing `enum` keyword, enhanced enums provide a grow-up story. Simple enums remain simple, while advanced scenarios become possible without abandoning familiar patterns.\n\n## 3. Type Unions (Foundation)\n\nType unions are fully specified in the [unions proposal](https://raw.githubusercontent.com/dotnet/csharplang/refs/heads/main/proposals/unions.md#summary). They provide:\n\n- Implicit conversions from case types to the union type\n- Pattern matching that unwraps union contents\n- Exhaustiveness checking in switch expressions\n- Enhanced nullability tracking\n- Flexible storage strategies (boxing or non-boxing)\n\n## 4. Enhanced Enums\n\n### Design Principles\n\n- **Progressive enhancement**: Simple enums stay simple; complexity is opt-in\n- **Data carrying**: Each case can carry its own constituent data\n- **Familiar syntax**: Builds on existing enum and record concepts\n- **Union foundation**: Shape enums are discriminated unions\n\n### Syntax Extensions\n\nEnhanced enums extend traditional enum syntax in three orthogonal ways:\n\n#### Extended Base Types\n\nSupport any constant-bearing type:\n\n```csharp\nenum Traditional : int { A = 1, B = 2 }\nenum Priority : string { Low = \"low\", Medium = \"medium\", High = \"high\" }\nenum TranscendentalConstants : double { Pi = 3.14159, E = 2.71828 }\n```\n\n#### Shape Declarations\n\nCreate a shape enum (discriminated union) by:\n- Adding `class` or `struct` after `enum`\n\n```csharp\nenum class Result { Success, Failure }  // shape enum via 'class' keyword\nenum struct Result { Success, Failure } // shape enum via 'struct' keyword\n```\n\n#### Data-Carrying Cases\n\n```csharp\nenum class Result // or enum struct\n{\n    Success(string id),\n    Failure(int code, string message)\n}\n```\n\nEach case with a parameter list generates a nested record type. `enum class` generates `sealed record class` types; `enum struct` generates `readonly record struct` types. While these are the generated types, the union implementation may optimize internal storage.\n\nTODO: Should the structs be readonly?  Seems like that goes against normal structs (including `record struct`).  Seems like that could be opt in with `readonly enum struct X`.\n\n#### Combination Rules\n\n- **Constant enums**: Can use extended base types but NOT have parameter lists\n- **Shape enums**: Can have parameter lists but NOT specify a base type\n- **Mixing cases**: Cannot mix constant values and parameterized cases\n\n```csharp\n// ✓ Valid - constant enum with string base\nenum Status : string { Active = \"A\", Inactive = \"I\" }\n\n// ✓ Valid - shape enum with data\nenum class Result { Ok(int value), Error(string msg) }\n\n// ✗ Invalid - cannot mix constants and shapes\nenum class Bad { A = 1, B(string x) }\n\n// ✗ Invalid - shape enums cannot have base types\nenum struct Bad : int { A, B }\n\n// ✗ Invalid - Constant enums cannot have parameter lists\nenum Bad { A(), B() }\n```\n\nFor the complete formal grammar, see [Appendix A: Grammar Changes](#appendix-a-grammar-changes).\n\n### Constant Value Enums\n\nEnhanced constant enums support any primitive type with compile-time constants:\n\n```csharp\nenum Priority : string \n{\n    Low = \"low\",\n    Medium = \"medium\", \n    High = \"high\"\n}\n```\n\nThese compile to `System.Enum` subclasses with the appropriate `value__` backing field. Non-integral constant enums require explicit values for each member.\n\n### Shape Enums: Discriminated Unions Made Elegant\n\nShape enums combine type unions with convenient integrated syntax:\n\n```csharp\nenum class FileOperation // or enum struct\n{\n    Open(string path),\n    Close,\n    Read(byte[] buffer, int offset, int count),\n    Write(byte[] buffer)\n}\n```\n\n#### Reference Type and Value Type\n\n```csharp\nenum class WebResponse\n{\n    Success(string content),\n    Error(int statusCode, string message),\n    Timeout\n}\n\nenum struct Option<T>\n{\n    None,\n    Some(T value)\n}\n```\n\n**`enum class`** creates discriminated unions with reference type cases:\n- Cheap to pass around (pointer-sized)\n- No struct tearing risk\n- Natural null representation\n\n**`enum struct`** creates discriminated unions with optimized value-type storage:\n- No heap allocation\n- Better cache locality\n- Reduced GC pressure\n\n#### Members and Methods\n\nEnums can contain members just like unions:\n\n```csharp\nenum class Result<T>\n{\n    Success(T value),\n    Error(string message);\n    \n    public bool IsSuccess => this switch \n    {\n        Success(_) => true,\n        _ => false\n    };\n    \n    public T GetValueOrDefault(T defaultValue) => this switch\n    {\n        Success(var value) => value,\n        _ => defaultValue\n    };\n}\n```\n\nMembers are restricted to:\n- Instance methods, properties, indexers and events (no additional state)\n- Static members\n- Nested types\n\n## 5. Translation Strategy\n\nShape enums translate directly to unions—generating case types as nested types and creating a union that combines them.\n\n### `enum class` Translation\n\n```csharp\nenum class Result\n{\n    Success(string value),\n    Failure(int code)\n}\n\n// Translates to:\npublic union Result(Success, Failure)\n{    \n    public sealed record class Success(string value);\n    public sealed record class Failure(int code);\n}\n```\n\nSingleton cases generate types with shared instances:\n\n```csharp\nenum class State { Ready, Processing, Complete }\n\n// Translates to:\npublic union State(Ready, Processing, Complete)\n{    \n    public sealed class Ready \n    {\n        public static readonly Ready Instance = new();\n        private Ready() { }\n    }\n    // Similar for Processing and Complete\n}\n```\n\n### `enum struct` Translation\n\n```csharp\nenum struct Option<T>\n{\n    None,\n    Some(T value)\n}\n\n// Conceptually translates to:\npublic struct Option<T> : IUnion\n{\n    public readonly struct None { }\n    public readonly record struct Some(T value);\n\n    // Optimized layout: discriminator + space for largest case\n    private byte _discriminant;\n    private T _value;\n    \n    object? IUnion.Value => _discriminant switch\n    {\n        1 => new None(),\n        2 => new Some(_value),\n        _ => null\n    };\n    \n    // Non-boxing access pattern\n    public bool TryGetValue(out None value)\n    {\n        value = default;\n        return _discriminant == 1;\n    }\n\n    public bool TryGetValue(out Some value)\n    {\n        if (_discriminant == 2)\n        {\n            value = new Some(_value);\n            return true;\n        }\n        value = default!;\n        return false;\n    }\n    \n    // Constructors and factories\n    public Option(None _) => _discriminant = 1;\n    public Option(Some some) => (_discriminant, _value) = (2, some.value);\n    \n    public static Option<T> None => new Option<T>(new None());\n    public static Option<T> Some(T value) => new Option<T>(new Some(value));\n}\n```\n\n## 6. Pattern Matching and Behaviors\n\n### Unified Pattern Matching\n\nShape enums inherit all union pattern matching behavior:\n\n```csharp\nvar message = operation switch\n{\n    Open(var path) => $\"Opening {path}\",\n    Close => \"Closing file\",\n    Read(_, var offset, var count) => $\"Reading {count} bytes at {offset}\",\n    Write(var buffer) => $\"Writing {buffer.Length} bytes\"\n};\n```\n\n### Exhaustiveness\n\nThe compiler tracks all declared cases. Both constant and shape enums can be open or closed (see [Closed Enums proposal](https://github.com/dotnet/csharplang/blob/main/proposals/closed-enums.md)).\n\nOpen enums can be used to signal that the enum author may add new cases in future versions—consumers must handle unknown cases defensively (e.g., with a default branch). Closed enums signal that there is no need to handle unknown cases, such as when the case set is complete and will never change—the compiler ensures exhaustive matching without requiring a default case.\n\nFor constant enums, \"open\" also means values outside the declared set can be safely freely cast to the enum type.\n\n```csharp\nclosed enum Status { Active, Pending(DateTime since), Inactive }\n\n// Compiler knows this is exhaustive - no default needed\nvar description = status switch\n{\n    Active => \"Currently active\",\n    Pending(var date) => $\"Pending since {date}\",\n    Inactive => \"Not active\"\n};\n\nenum Priority : string { Low = \"low\", Medium = \"medium\", High = \"high\" }\n\n// Default case is needed, other string values may be converted to Priority, or new cases may be added in the future:\nvar value = priority switch\n{\n    Low => -1,\n    Medium => 0,\n    High => 1,\n    _ => /* fallback to low priority */ -1,\n}\n```\n\n### All Union Behaviors\n\nShape enums automatically get:\n- Implicit conversions from case values\n- Nullability tracking\n- Well-formedness guarantees\n\n## 7. Examples and Use Cases\n\n### Migrating Traditional Enums\n\n```csharp\n// Traditional enum\nenum OrderStatus { Pending = 1, Processing = 2, Shipped = 3, Delivered = 4 }\n\n// Enhanced with data\nenum struct OrderStatus\n{\n    Pending,\n    Processing(DateTime startedAt),\n    Shipped(string trackingNumber),\n    Delivered(DateTime deliveredAt);\n    \n    public bool IsComplete => this is Delivered;\n}\n```\n\n### Result and Option Types\n\n```csharp\nenum class Result<T, E>\n{\n    Ok(T value),\n    Error(E error);\n    \n    public Result<U, E> Map<U>(Func<T, U> mapper) => this switch\n    {\n        Ok(var value) => Result<U, E>.Ok(mapper(value)),\n        Error(var err) => Result<U, E>.Error(err)\n    };\n}\n\nenum struct Option<T>\n{\n    None,\n    Some(T value);\n    \n    public T GetOrDefault(T defaultValue) => this switch\n    {\n        Some(var value) => value,\n        None => defaultValue\n    };\n}\n```\n\n### State Machines\n\n```csharp\nenum class ConnectionState\n{\n    Disconnected,\n    Connecting(DateTime attemptStarted, int attemptNumber),\n    Connected(IPEndPoint endpoint, DateTime connectedAt),\n    Reconnecting(IPEndPoint lastEndpoint, int retryCount, DateTime nextRetryAt),\n    Failed(string reason, Exception exception);\n    \n    public ConnectionState HandleTimeout() => this switch\n    {\n        Connecting(var started, var attempts) when attempts < 3 => \n            ConnectionState.Reconnecting(null, attempts + 1, DateTime.Now.AddSeconds(Math.Pow(2, attempts))),\n        Connecting(_, _) => \n            ConnectionState.Failed(\"Connection timeout\", new TimeoutException()),\n        Connected(var endpoint, _) => \n            ConnectionState.Reconnecting(endpoint, 1, DateTime.Now.AddSeconds(1)),\n        _ => this\n    };\n}\n```\n\n## 8. Design Decisions and Trade-offs\n\n### Why Extend `enum`\n\n- **Familiarity**: Developers already understand enums conceptually\n- **Progressive disclosure**: Simple cases remain simple\n- **Cognitive load**: One concept instead of two\n- **Migration path**: Existing enums can be enhanced incrementally\n\n### Union Foundation\n\nShape enums are discriminated unions expressed through enum syntax. By building on union machinery:\n- All union optimizations automatically benefit shape enums\n- No risk of semantic divergence between features\n- Simple mental model: shape enums generate types and combine them with a union\n- Future union enhancements immediately apply\n\n### Storage Strategy Trade-offs\n\nThe distinction between `enum class` and `enum struct` allows developers to choose the right trade-off, similar to choosing between `record class` and `record struct`.\n\n## 9. Performance Characteristics\n\n### Memory Layout\n\n**`enum class`**:\n- Union contains single reference (8 bytes on 64-bit)\n- Case instances allocated on heap\n- Singleton pattern for parameter-less cases\n\n**`enum struct`**:\n- Size equals discriminator plus space for largest case\n- Inline storage, no heap allocation\n- Optimized layout per union's non-boxing pattern\n\n### Allocation Patterns\n\n```csharp\n// Allocation per construction\nenum class Result { Ok(int value), Error(string message) }\nvar r1 = Result.Ok(42);  // Heap allocation\n\n// No allocation\nenum struct Result { Ok(int value), Error(string message) }  \nvar r2 = Result.Ok(42);  // Stack only\n```\n\n### Optimization Opportunities\n\nShape enums benefit from all union optimizations:\n- Singleton cases to shared instances\n- Small structs fitting in registers\n- Pattern matching via optimized paths\n- Exhaustive switches avoiding default branches\n\n## 10. Open Questions\n\n1. **Nested type accessibility**: Should users reference generated case types directly?\n2. **Partial support**: Should enhanced enums support `partial` for source generators?\n3. **Default values**: What should `default(EnumType)` produce for shape enums?\n4. **Serialization**: How should enhanced enums interact with System.Text.Json?\n5. **Additional state**: Should shape enums allow instance fields outside case data?\n6. **Custom constructors**: Should enums allow custom constructors that delegate to cases?\n7. **Construction syntax**: `Result.Ok(42)` or `new Result.Ok(42)` or both?\n8. **Generic cases**: Should cases support independent generic parameters?\n9. **Interface implementation**: Should enhanced enums automatically implement `IEquatable<T>`?\n10. **Exact lowering**: Should the spec define exact names and shapes of generated types?\n\n## Appendix A: Grammar Changes\n\n```antlr\nenum_declaration\n    : attributes? enum_modifier* 'enum' ('class' | 'struct')? identifier enum_base? enum_body ';'?\n    ;\n\nenum_base\n    : ':' enum_underlying_type\n    ;\n\nenum_underlying_type\n    : simple_type // all integral types, fp-types, decimal, bool and char\n    | 'string'\n    | type_name  // Must resolve to one of the above\n    ;\n\nenum_body\n    : '{' enum_member_declarations? '}'\n    | '{' enum_member_declarations ';' class_member_declarations '}'\n    ;\n\nenum_member_declarations\n    : enum_member_declaration (',' enum_member_declaration)*\n    ;\n\nenum_member_declaration\n    : attributes? identifier enum_member_initializer?\n    ;\n\nenum_member_initializer\n    : '=' constant_expression\n    | parameter_list\n    ;\n```\n"
  },
  {
    "path": "meetings/working-groups/discriminated-unions/original-nominal-type-unions.md",
    "content": "# Nominal Type Unions for C#\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9411\n\n## Summary\n[summary]: #summary\n\nA type union is a type that can represent a single value from a closed and disjoint set of types declared separately. These types, known as *case types* in this proposal, are not required to be declared in a hierarchy or share a common base (other than object).\n\n```csharp\n    record Cat(...);   // the case types\n    record Dog(...);\n    record Bird(...);\n\n    union Pet(Cat, Dog, Bird);  // the type union\n```\n\nValues of a case type can be assigned directly to a variable of a type-union type. However, since type unions can represent values of unrelated types, having a variable of one is similar to having a variable typed as object. Interacting with a type union instance typically first involves testing and accessing its value in the form of one of its case types.\n\n```csharp\n    Pet pet = new Dog(...);\n    ...\n    if (pet is Dog d) {...}\n```\n\nThis proposal introduces a first class nominal type union to C# that is fundamentally a struct wrapper around a value. It is declared and used like any other type, yet, it is also treated specially in some situations to help create an illusion that it is the value and not the wrapper. \n\n```csharp\n    union Pet(Cat, Dog, Bird);\n```\nbecomes\n```csharp\n    readonly struct Pet \n    {\n        public Pet(Cat value) {...}\n        public Pet(Dog value) {...}\n        public Pet(Bird value) {...}\n        public object Value => ...;\n    }\n```\n\nTo treat it like its value, certain operations like casting and pattern matching are translated by the compiler to API calls on the type union instance. \n \n```csharp\n    if (pet is Dog dog) {...}   \n```\nbecomes\n```csharp\n    if (pet is { Value: Dog dog }) {...}\n```\n\nThe proposal is broken down into a core set of features needed to make nominal type union's viable and an additional assortment of optional features that may improve performance or capability and can be conditionally implemented over time.\n\n## Motivation\nC# has been adopting functional programming concepts for many years as the language continues to evolve to support popular paradigms as they become mainstream, like the monadic behaviors of nullable types and sequence operators in LINQ and more recently tuples and records that focus on data over behavior and help shift development to a more immutable style.\n\nWriting software using functional paradigms often utilizes coding practices that are opposite or inverted from object-oriented ones. Frequently data is not hidden in the way one might do with objects, where ideally only the contract of behavior is exposed via methods and polymorphism is handled by virtual dispatch. Instead, a fixed set of types are used to represent a well known and finite data model with elements that are themselves often polymorphic leading to the need to identify and handle cases explicitly in the code.\n\nYou see this happening in the real world in places where the veil of abstraction is lifted, such as when protocols and data models are defined for communicating and exchanging information between boundaries (like machines, processes and libraries) and beneath the veil where the stuff of algorithmic minutia takes place. In these situations behavior is not the contract, the data is.\n\nWhen you are operating on a data model in this way it becomes necessary to be confident that you are handling all cases when a property or collection can optionally contain more than one kind of data. Having the language help you enforce and know when this is true is extremely valuable. Both are usually solved in programming languages using the concepts of *type unions* and *discriminated unions*.\n\nType unions allow you to specify a variable as being able to hold a value from a set of otherwise unrelated types instead of just one type. Values of other types are not allowed and using the variable typically requires testing and converting it to one of its known case types. \n\nLikewise, discriminated unions allow you to have a variable that holds different kinds of values depending on its given named state and then depending on which state the variable is in you can get access to just those associated values. They are kind of like type unions without the types. Yet, in a language like C#, these named states with their values are better expressed as records allowing discriminated unions to be built out of type unions.\n\nThe only way currently to have a variable hold values of more than one type in C# is to either give the variable the object type or to use a base type that all the case types share. Yet, using object does not allow the language to restrict what the variable contains and a base type, while better, still does not constrain it because the type itself does not describe the set of possible sub types and additional sub types can easily be declared elsewhere outside the scope of the original design.\n\nC# needs type unions to enable a better style of programming when polymorphic data models are being operated on. It solves the problem of guaranteeing that a variable can hold a value from more than one type, but also from only a specific set of types, and helps inform you when all cases have been handled.\n\n### Everyday Unions\nType unions can also be used for less grand purposes. While you might not have any published protocols or data models to operate on, simply being able to return a value that can be one of many types and have that documented strongly in the method's signature is a huge benefit. Both consumers of a method like this and the compiler will know right away what types need to be handled in the result. \n\n```csharp\n    public union TestResult(double, string);\n\n    // Possible values are obvious\n    public TestResult RunTest(...) {...};\n```\n\nLikewise, a parameter using a type union can constrain the values passed in, that might otherwise require abundant overloading, or be used as a settable property that cannot even have an overload.\n\n```csharp\n    // otherwise would need N overloads to constrain input\n    public void RegisterVisit(Pet patient, DateTime time, string reason, string vet);\n\n    // cannot have overloads for properties\n    public Pet Patient { get; set; }\n```\n\nHaving a way to express this makes code easier to read and prove correct because there are less ways to provide invalid input and more ways to ensure that all cases are understood.\n\n### Beyond Class Hierarchies\nA shallow class hierarchy can sometimes be used as a substitute for a type union if there is a way for both the compiler and you to know the full set of sub-types being used as cases and you have the freedom to declare all these cases for just this purpose. A separate proposal known as *Closed Class Hierarchies* attempts to solve this. Yet, even when this is possible, nominal type unions are often a better solution.\n\nWhen to use *nominal type unions* over *class hierarchies*.\n\n- **To avoid allocations of the case types.**  \n\n   *This is important when the cases may be constructed and consumed frequently, like with the Option and Result types.*\n\n- **Some or all of the case types are declared elsewhere.**  \n\n   *For example, you want to constrain a field to only double and string values. You don't get to redeclare these types. You could declare a hierarchy with special sub-types that wrap these values but that would no longer be a type union of the desired types and those wrapper types would require allocations too.*\n\n- **The case types have other uses outside the union.**  \n\n  *While it might make sense to declare Animal and Vehicle in the same hierarchy of ThingsInAutoAccident, it may be awkward to have the Animal type as part of that hierarchy when also using it in your MeatsOnTheMenu model.*\n   \n- **The need to handle only a subset of cases.**  \n\n   *You have a hierarchy of animals but need to limit a variable to just pets. You might be able to introduce Pet as an additional abstract class wedged between Animal and the pet specific case types but sometimes a perfect taxonomy cannot be defined when multiple subsets are needed.*\n\n- **The need for multiple unions of similar cases.**  \n\n  *There is no multiple inheritance in C# and therefore no sharing of the same case types in different hierarchies. You would need to create multiple identical classes with different base classes instead with no easy way to convert between them.*\n\n\n## Principles\n\nSome foundational principles that guided this proposal.\n\n- **A nominal type union represents a single value.**  \n\n  *It holds a single value that can be one of its case types. Its not meant to have other instance fields or properties.*\n  \n- **A nominal type union is a distinct type from other type unions even when they share the same cases.**  \n\n  *They are not interchangeable or structural. However, conversion between similar type-union types should be possible.*\n\n- **A nominal type union instance behaves as if it were its value in some situations.**  \n\n  *Some operations applied to the union instance are instead applied to the value of the union, as far as its meaning is well understood and it is practical to do so.*\n\n- **A nominal type union is its own type.**  \n\n  *The type is not erased. An instance of one might behave as if it were the value it wraps in some situations, but it is also its own instance distinct from the value everywhere else.*\n\n- **A nominal type union is always meant to have a value of one of its case types.**  \n\n  *The reality, however, is that a default or uninitialized state does exist that we pretend does not, leading to the need to define what happens when this occurs.*\n\n- **A nominal type union's value is never meant to be null.**  \n\n  *The reality, however, is that null values can still sneak in which leads us to need to define what happens when this occurs.*\n\n- **A nominal type union's storage model is opaque.**  \n\n  *The field(s) storing the value are hidden behind constructors and properties/methods allowing the storage model to vary depending on the cases and potentially improve over time.*\n\n- **A nominal type union is exactly what you declare it to be.**  \n\n  *A type union that includes cases that are other type unions (not recommended but could happen due to type argument cases) is not flattened into a union of the leaf cases. The values held for these cases are type union instances not the values they indirectly contain.*\n\n\n## Declaration\n\nA nominal type union is declared using the `union` keyword and minimally a name and a list of case types that are each declared elsewhere. \n```csharp\n    union Pet(Cat, Dog, Bird);\n```\nThough rare, some nominal type unions may declare type parameters:\n```csharp\n    union Option<TValue>(Some<TValue>, None);\n```\n\nOr add additional members:\n```csharp\n    union Option<TValue>(Some<TValue>, None)\n    {\n        public bool HasValue => this is Some<TVale>;\n    }\n```\n\nThey may even declare their case types as nested declarations:\n```csharp\n    public union Option<TValue>(Some<TValue>, None)\n    {\n        public record struct Some(TValue Value);\n        public record struct None();\n    }\n```\n\nOthers may choose to declare and implement interfaces for special circumstances:\n\n ```csharp\n    public partial union Pet(Cat, Dog, Bird) : ICustomSerializable\n    {\n        void ICustomSerializable.SerializeTo(Stream stream) => ...;\n    }\n```\n\n*These interfaces are elements of the union type and not related to the case types or the value of the union. The might be needed for interop with libraries or frameworks that require them.*\n\n### Grammar\n```\ntype_union_declaration\n    : attributes? struct_modifier* 'partial'? 'union' identifier type_parameter_list?\n      case_type_list? struct_interfaces? type_parameter_constraints_clause* struct_body\n    ;\ncase_type_list\n    : '(' case_type (',' case_type)* ')'\ncase_type\n    : attributes? case_modifiers? type\ncase_modifiers\n    : ???\n```\n\n### Modifiers\nA nominal type union may have zero or more modifiers. However, only certain modifiers are allowed.\n- Any accessibility modifier: public, private, internal, etc\n- partial\n- file\n\n### Type Parameters\nThe nominal type union can have zero or more type parameters that can be used in member declarations, interface declarations and case type specifications.\n\n```csharp\n    union OneOrList<A>(A, IReadOnlyList<A>);\n```\n\n- Note: declaring case types that are just type parameters hides knowledge of the true types used at runtime from the compiler at compile time making it possible to end up with type unions at runtime that would typically be avoided like unions containing other type unions or unions with duplicate case types. It also reduces the ability of the compiler to optimize the storage layout of the data.\n\n### Case Types\nA nominal type union specifies a list of case types. These types determine the closed set of types that a value contained by the type union can have. They can be any type except for the ones that are excluded by producing errors.\n\nThe following conditions produce an error by the compiler:\n\n- A case type is a pointer or ref type.  \n  *These types cannot be boxed to object and accessed via Value property.*\n\n- A case type is the containing union's type.  \n  *Infinite storage recursion?*  \n\nThe following conditions produce a warning from the compiler. If found the author has likely made a mistake. The warning can be overridden with pragmas.\n\n- A case type is a type-union type.  \n  *The author likely intended to have the individual cases of this type listed instead.*\n\n- A case type is specified more than once.  \n  *This is a redundant case that will never be used in practice.*\n\n- A case type subsumes another case type.  \n  *The author probably does not realize the subsumption and redundancy of additional cases.*\n\n- A case type is the object type.  \n  *The object type not only subsumes all other cases, it does not constrain the values the union may have in any way, defeating the purpose of the union.*\n\n- A case type is a nullable struct or reference type.  \n  *Type Unions only have non-null values.*\n\n### Base Type\nA nominal type union cannot declare a base type, only interfaces.\n\nIf the intention of having a base type was to extend an existing type union with more cases, the way of doing this is to list the cases of the other union in this union's case type list. An optional [Combined Unions](#combined-unions) feature would make this easier.\n\n### Interfaces\nA nominal type union can declare any interfaces that it implements. These are interfaces of the union type and may have no relation to the interfaces implemented by the case types.\n\n### Body\nA nominal type union may declare additional members beyond the members generated by the compiler. These are member of the union type and may have no relation to the members of the case types.\n\n- Any member that introduces an instance field is disallowed and will produce an error at compile time. A type union only represents a single value.\n\n- Any constructor declared must defer to one of the compiler's generated constructors. These each behave like a record's generated primary constructor. *There may not be a reasonable use case for defining additional constructors.*\n\n### Partial Type Unions\nA nominal type union may have multiple partial declarations.\n\n```csharp\npublic partial union Pet(Cat, Dog, Bird);\n```\n```csharp\npublic partial union Pet\n{\n    public bool HasFourLegs => ...;\n}\n```\n\n- Each partial declaration follows the same rules as other types with respect to modifiers, type parameters and constraints.\n- One and only one partial declaration includes the list of case types. The order of the case types may be significant and a change in order may be a breaking change.\n\n## Basic Representation\nThe nominal type union is emitted as a read-only struct, with constructors corresponding to the case types and a property for accessing the contained value. All interfaces, members and attributes declared on the type union are included as part of the emitted struct type.\n\n```csharp\n    public union Pet(Cat, Dog, Bird);\n```\nBecomes\n```csharp\n    public readonly struct Pet\n    {\n        // constructors\n        public Pet(Cat value) {...}\n        public Pet(Dog value) {...}\n        public Pet(Bird value) {...}\n\n        // value access pattern\n        public object Value => ...;\n    }\n```\n\n### Construction\nA constructor exists for each case type, initializing the type union instance with the argument value. These constructors are the minimum API necessary to create type union instances from case type values using language idioms such as casting or implicit coercion.\nAn optional API, outlined in [conditional construction](#conditional-construction) may also exist to enable construction of type unions from values that are not known to be case types.\n\n#### Constructing with Nulls\n A nominal type union is not meant to have a null value. It would never match its case type in a type pattern match. The compiler warns when a type union is declared to include case types that can be null. However, it is still possible that a null value may be passed as an argument to a constructor by ignoring this warning or others. When this happens, the type union is initialized to the equivalent of its default state instead, indicating that it does not contain a value.\n\n The [Nullable Unions](#nullable-unions) section covers techniques for enabling null or non values in type unions.\n\n### Access Patterns\nA nominal type union exposes one or more methods or properties used to access the value contained by the union. These are referred to in this proposal as *access patterns*.\n\nA nominal type union always has the [Value Access Pattern](#value-access-pattern), a single weakly-typed property that returns the value used to construct the type union. This is the minimum API required to translate type tests, pattern matching and explicit coercion, but not always the best way to access the value. If supported, other optional access patterns may be preferred.\n\nPossible Access Patterns:  \n- [Value Access Pattern](#value-access-pattern)\n- [Discriminator Access Pattern](#discriminator-access-pattern)  \n- [TryGet Access Pattern](#tryget-access-pattern)  \n- [Generic TryGet Access Pattern](#generic-tryget-access-pattern)  \n\n### Storage Layouts\nBecause the truth of how the value is stored within the nominal type union is hidden behind the facade of the access patterns it is possible to store the value in one of many possible and reasonable ways. For example, there may be a strongly-typed field for each possible case type or there may only be one field typed as object, shared by all the cases, boxing any struct types.\n\n*Due to runtime limitations it is not possible to simply overlay the memory used by the different cases (like a C++ union would) so an alternative storage layout must be chosen that finds a balance between the footprint (the size of the type itself) and the potential use of heap allocation due to boxing.*\n\nThe compiler choses a layout that best suits the case types given a heuristic and possible hint by the author. In future versions of C#, the set of layouts known by the compiler may grow, the heuristic changed or the ability to specify preferences in the declaration may increase, meaning when the code is recompiled in the future the storage layout of the type may change.\n\nBy default, a nominal type unions uses the [Boxed Layout](#boxed-layout) which simply backs the `Value` property with a single field. If supported, other optional layouts may be preferred.\n\nPossible Layouts:\n- [Boxed Layout](#boxed-layout)\n- [Discriminated Boxed Layout](#discriminated-boxed-layout)\n- [Fat Layout](#fat-layout)\n- [Skim Layout](#skim-layout)\n- [Overlapped Layout](#overlapped-layout)\n- [Deconstructed Layout](#deconstructed-layout)\n- [Overlapped Deconstructed Layout](#overlapped-deconstructed-layout)\n- [Hybrid Layout](#hybrid-layout)\n\n*Storage fields are not accessible to user written logic in member declarations within the body of the union declaration. They can only be assigned via the constructors and accessed via the access patterns or the language operations that use them.*\n\n### Metadata Encoding\nThe emitted struct is annotated with a `TypeUnion` attribute to indicate in metadata that this type is a type union. Constructors corresponding to case types are annotated with the `TypeUnionCase` attribute, indicating that the parameter type of the constructor is one of the case types.\n\n```csharp\n    [TypeUnion]\n    public readonly struct Pet\n    {\n        [TypeUnionCase]\n        public Pet(Cat value) {...}\n        ...\n    }\n```\n\n>*Case types cannot be listed in the `TypeUnion` attribute since type parameters cannot be specified in an attribute literal so they must appear as part of a member signature.*\n\n## Language Integration\nWhen integrated into the language a type union instance behaves as if it were the value it contains for some operations when the instance is known to be a type union. While this is a gray area that may not be practical or reasonable to push to the extremes, it is a useful illusion to maintain as it simplifies code.\n\nTo implement the illusion some language operations are defined to instead operate on the value contained by the union. These operations are translated into interactions with the type union's API like how cast operations are translated to calls on user-defined operator methods.\n\nThis section details the minimum necessary integration points for type unions to be considered a part of the language.\n\n----\n### Implicit Conversion to Union\nTo make type-union types feel like they are the value they contain, assignment from a case type value to a type-union variable should happen automatically, without needing to manually construct one from the other, similar to how a value of any type can be assigned to an object variable.\n\nTo enable this, an implicit conversion is introduced for any value that would match the parameter type of a case constructor. This conversion is emitted as an invocation of the constructor.\n\n```csharp\n    Pet pet = dog;\n```\n\nTranslates to:\n\n```csharp\n    Pet pet = new Pet(dog);\n```\n\n*Note: This conversion cannot be specified using the user-defined conversion operators feature since case types may be interface types and user-defined conversion operators cannot be specified for interface types.*\n\n----\n### Conversion to Union from Default\nAssigning default to a type union variable or converting default to a type-union results in a compiler warning.\n\n```csharp\n    public union Pet(Cat, Dog, Bird);\n    Pet pet = default; // warning: cannot assign default to union\n```\n- It is still possible to have a type union in a default state. This rule just catches unintentional conversions similar to assigning null to a non-nullable reference type.\n- **Optional**: We allow use of the forgiveness operator `!` to silence this warning.\n\n----\n### Null Pattern Match\nA nominal type union's value is never null. When a null pattern match is made against a type union type, it always fails.\n\n```csharp\n    if (pet is null) {...}\n```\n\nWhile the `Value` property may return a null value when the struct wrapper is in the default state, this accessor is only used for a type pattern match and not a null pattern match.\n\nTo have a type union with a null value see the [Nullable Unions](#nullable-unions) section.\n\n----\n### Type Pattern Match from Union\nThe illusion of the union being its value means that accessing the value of the type union should feel like asking an object variable if it is one of the case-types via pattern matching. Type pattern matches on a statically known type-union type are translated to matches against the value contained in the type union.\n\n```csharp\n    pet is X\n```\nSome target types, however, might also apply to the type-union type itself. A target type of an interface that the type union is known to implement or that any case type might implement or just being a type parameter, means the match must be translated to a match on both the type union and the contained value.\n\n| Example                           | Translation                                  |\n|-----------------------------------|----------------------------------------------|\n| `pet is Dog`                      | `pet is { Value: Dog }`                      |\n| `pet is Dog dog`                  | `pet is { Value: Dog dog }`                  |\n| `pet is Dog { Name: \"Spot\" } dog` | `pet is { Value: Dog { Name: \"Spot\" } dog }` |\n| `pet is Corgi corgi`              | `pet is { Value: Corgi corgi }`              |\n| `pet is ICase value`              | `pet is { Value: ICase value }`              |\n| `pet is ISomething value`         | `pet is { Value: ISomething value }`         |\n| `pet is IUnion value`             | N/A - no translation                         |\n| `pet is TCase value`              | `pet is TCase value or { Value: TCase value }` |\n| `pet is T value`                  | `pet is T value or { Value: T value }`       |\n\n- Dog: A case type.\n- Corgi: A sub-type of Dog.\n- ISomething: an interface not implemented by the union but may be implemented by case types.\n- ICase: A case type that is an interface and not implemented by the type union itself.\n- IUnion: An interface that is implemented by the union.\n- TCase: A case type that is a type parameter\n- T: An arbitrary type parameter not known to be a case type.\n- N/A: Translation not supported, original interpretation of operation is used.\n\n----\n### Type Pattern Match to Union\nA value of a known case type can be converted to a type-union type via pattern matching.\n\n```csharp\n    dog is Pet pet\n```\nBeing similar to [implicit conversion](#implicit-conversion-to-union), the pattern match translates into an invocation of a corresponding constructor.\n\n```csharp   \n    {Pet pet = new Pet(value); true}\n```\n\n*Note: Pattern matching to a type-union type from values of types not known to be a case type are supported via the optional [Type Pattern Match Unknown to Union](#type-pattern-match-unknown-to-union) feature.*\n\n----\n### Explicit Conversion\nExplicit conversions involving a type-union type as either the source or target of the conversion where special rules for pattern matching would apply for the same source and target types are translated into an `is` operator applying those pattern matching rules, returning the value on success or throwing an exception on failure.\n\n```csharp\n    (Pet)dog;\n```\n\nTranslates to:\n\n```csharp\n    <<dog is Pet tmp>> ? tmp : throw new InvalidCastException(...);    \n```\n\nAnd the reverse:\n\n```csharp\n    (Dog)pet;\n```\n\nTranslates to:\n\n```csharp\n    <<pet is Dog tmp>> ? tmp : throw new InvalidCastException(...);\n```\n\n*Note: the << >> brackets denote where additional translation occurs.*\n\n----\n### As Operator\nAn `as` operator involving a type-union type as either the source or target of the conversion where special rules for pattern matching would apply for the same source and target types are translated into an `is` operator applying those pattern matching rules, returning the value of on success or the default of the target type on failure.\n```csharp\n    pet as Dog\n```\n\nTranslates to:\n```csharp\n    <<pet is Dog tmp>> ? tmp : default(Dog)\n```\n\n*Note: Normal rules apply for which types can be used on the right side of an `as` operator.*  \n*Note: the << >> brackets denote where additional translation occurs.*\n\n----\n### Switch Statement and Expression\nThe switch statement and expression employ the same translations for type pattern matching involving type-union types in switch cases as outlined above, with switch case using the preferred translation for its target type.\n\n```csharp\n    pet switch \n    {\n        Cat cat => ...,\n        Dog dog => ...,\n        Bird bird => ...\n        _ => ...\n    }\n```\n\nTranslate to:\n\n```csharp\n    pet switch\n    {\n        { Value: Cat cat } => ...,\n        { Value: Dog dog } => ...,\n        { Value: Bird bird } => ...,\n        _ => ...\n    }\n```\n\n#### Exhaustive Unions\nSince type unions are limited to a closed set of case types they are exhaustible in a switch. If all cases of a type union are handled in the switch cases, a default does not need to be specified. However, a default case will still be added to handle cases of invalid unions as is normally added to an exhaustive switch.\n\n----\n### Nullable Unions\nType unions are not allowed to have a null value. Nullable case types are warned against and null values are intercepted during construction placing the type union instance into a default state that does not have a case type value.\n\nTo represent the equivalent of null in a type union it is preferred to use an explicit case type to represent a non value. For example, an `Option` type union might have a `None` case type that represents not having a value.\n\nStill, you may have reasons why a null value makes sense to assign to your type union variable. If this is the case, you can easily declare the type as the nullable version of the union using the question mark syntax.\n\n```csharp\n    Pet? maybePet = null;\n```\n\nBecause the type union `Pet` is emitted as a `struct` type, this will mean references to `Pet?` are references to `Nullable<Pet>` at runtime. However, this may cause issues with the translation of some language operations which can be solved with some additional rules that are used when nullables are combined with type unions.\n\nWhen a nullable type union is used in a type pattern match, the match is translated to match on the non-nullable value of the nullable type union.\n\n```csharp\n    maybePet is Dog dog\n```\n```csharp\n    maybePet is Pet tmp && <<tmp is Dog dog>>\n```\n\nThe other operations, type conversion, etc, are translated likewise. A switch over a nullable union value can be optimized to only access the non-nullable value once.\n\n----\n### Unknown Unions\nThe special translations outlined in this document for nominal type unions only occur when a type union is known statically to be involved. If a type union value exists but is statically typed as object or a type parameter no special translations will occur and the normal meaning of the operation made against the union's struct wrapper type will remain in effect.\n\nCode that deals solely with generic types will not have recognized a type union being used and will not translate type tests or casts using these new rules. \n\nFor example, the `OfType<T>` method does a type test with generics only.\n```csharp\n    List<Pet> pets = [new Dog(...), new Cat(...)];\n    pets.OfType<Dog>()  // will never match\n```\n\nHowever, doing the equivalent manually in a context that sees the type union will succeed.\n```csharp\n    List<Pet> pets = [new Dog(...), new Cat(...)];\n    pets.Where(p => p is Dog).Select(p => (Dog)p);  // will match\n```\n*Note: It is possible that a future version of the runtime may become type union aware and allow type tests in generic-only contexts to succeed.*\n\n---\n### Union Constraints\n\nIt may seem to make sense to specify a type-union type in a generic type parameter constraint in order to constrain a type parameter to be one of the type union's case types.\n\n```csharp\n    TPet Feed<TPet>(TPet pet) where TPet : Pet {...}\n```\nFor example, the `Feed` method takes a pet as input, feeds it and returns a new fed pet instance on output. It uses the type parameter to guarantee the same type going in is the same type going out.\n\n```csharp\n    Dog fedDog = Feed(unfedDog);\n```\n\nHowever, since the type union is represented as a struct wrapper and struct's cannot be used in constraints like this, it is not possible to do so. The proposed feature of a type union is language only and does not exist in the runtime.\n\nThe best we can do to actually constrain to a type union is to use the type union as the parameter type, but this will not get you the desired return type.\n\n```csharp\n    Pet Feed(Pet pet) {...}\n```\n\nThis is an interesting area to consider perhaps adding a compile-time only constraint to C# or creating a new kind of runtime constraint that includes an *or* condition.\n\n```csharp\n    TPet Feed<TPet>(TPet pet) where TPet : Cat or Dog or Bird {...}\n```\n\n----\n----\n\n## Optional Features\nThe rest of the proposal includes optional features that may enhance capability or improve performance of nominal type unions.\n\n#### Features that improve the representation or access of the value\n  - Access Patterns\n    - [Discriminator Access Pattern](#discriminator-access-pattern)  \n    - [TryGet Access Pattern](#tryget-access-pattern)  \n    - [Generic TryGet Access Pattern](#generic-tryget-access-pattern)\n  - Storage Layouts\n    - [Discriminated Boxed Layout](#discriminated-boxed-layout)  \n    - [Fat Layout](#fat-layout)  \n    - [Skim Layout](#skim-layout)  \n    - [Overlapped Layout](#overlapped-layout)\n    - [Deconstructed Layout](#deconstructed-layout)  \n    - [Overlapped Deconstructed Layout](#overlapped-deconstructed-layout)  \n    - [Hybrid Layout](#hybrid-layout)  \n  \n#### Features that make the union behave more like the value in more places\n  - More Conversions\n    - [Conversion from unknown case to union](#type-pattern-match-unknown-to-union)  \n    - [Conversion from union to union](#type-pattern-match-from-union-to-union)  \n    - [Implicit conversion from union to union](#implicit-conversion-from-union-to-union)  \n  - Common Members \n    - [Common Member Proxies](#common-member-proxies)  \n    - [Common Member Access](#common-member-access)\n    - [Common Base Types](#common-base-types)  \n    - [Common Interface Implementation](#common-interface-implementation)  \n    - [ToString](#tostring)  \n    - [Equality](#equality)  \n  \n#### Features that help with interop or reflection\n  - [Common Helper Methods](#common-helper-methods)  \n  - [Common Interfaces](#common-interface)  \n\n#### Miscellaneous\n  - [Default Unions](#default-unions)\n  - [Combined Unions](#combined-unions)\n</br>\n\n----\n### Type Pattern Match Unknown to Union\nTo enable conversion of a value not statically known to be a case type to a union type, a special translation exists.\n\n```csharp\n    object value = ...;\n    if (value is Pet pet) {...}\n```\n\nTo do this translation the source is checked against all possible case types, calling the corresponding constructor when a match is found.\n\nIf the [TypeUnion.TryConvert](#typeuniontryconvert) feature is available, the pattern match is translated into a call on the `TryConvert` method that does these checks and more.\n\n```csharp\n    if (value is Pet Pet || TypeHelper.TryConvert(value, out tmp)) {...}\n```\n\nOtherwise, if the [Conditional Construction](#conditional-construction) feature is available, the pattern match is translated into a call on the `TryCreate` method that does exactly these checks.\n\n```csharp\n    if (value is Pet Pet || Pet.TryCreate(value, out tmp)) {...}\n```\n\nIf neither are available, the pattern match has no special translation, leaving just the original test for the type union type.\n\n```csharp\n    if (value is Pet pet) {...}\n```\n\n**Optional:** The compiler generates the checks against all case types inline, including all the same logic that would appear in the [Conditional Construction](#conditional-construction) implementation of the `TryCreate` method.\n\n```csharp\n    if (value is Pet pet || (value is Cat tmp1 && new Pet(tmp1) is Pet pet) || ...) {...}\n```\n\n**Optional:** The compiler generates a per-compilation-unit helper method with the same logic\n\n```csharp\n    public static class PrivateTypeUnionHelpers\n    {\n        public static bool TryCreate<T>(T value, out Pet pet) {...}\n    }\n    ...\n\n    if (value is Pet pet || PrivateTypeUnionHelpers.TryCreate(value, out pet)) {...}\n```\n\n----\n### Conditional Construction\nThe Type Union's generated struct includes a `TryCreate` method to help in conditionally constructing type unions.\n\n```csharp\n    public static bool TryCreate<TValue>(TValue value, out Pet pet);\n```\n\nThe method tests the input value against the known case types and constructs the union using the corresponding constructor.\n\nThe implementation would be similar to this:\n\n```csharp\n    public static bool TryCreate<TValue>(TValue value, out Pet union)\n    {\n        switch (value)\n        {\n            case Cat value1:\n                union = new Pet(value1);\n                return true;\n            case Dog value2:\n                union = new Pet(value2);\n                return true;\n            case Bird value3:\n                union = new Pet(value3);\n                return true;\n            default:\n                pet = default;\n                return false;\n        }\n    }\n```\n\nThis may be used by the [Type Pattern Match Unknown to Union](#type-pattern-match-unknown-to-union) feature, may be used by the [TypeUnion.TryConvert](#typeuniontryconvert) feature, may be an implementation detail of [Common Interface](#common-interface) feature, or may just be used manually by users to perform this construction/conversion.\n\n----\n### Type Pattern Match from Union to Union\nConverting between two union types will be a common operation when multiple union types exist that share some of the same case types, or similar case types such as some values from one union would be legal values of another.\n\nIf the [TypeUnion.TryConvert](#typeuniontryconvert) helper method is available, it is used to conditionally convert between the two type union types.\n\n```csharp\n    animal is Pet pet\n```\n```csharp\n    TypeHelper.TryConvert(animal, out Pet tmp);\n```\n\nOtherwise, if the [conditional construction](#conditional-construction) `TryCreate` method is available, it is used with the value of the source obtained via the [value access pattern](#value-access-pattern).\n\n```csharp\n    Pet.TryCreate(animal.Value, out var pet);\n```\n\n**Optional:** this is only exposed in the explicit conversion form and not a pattern match.\n\n```csharp\n    (Pet)animal\n```\n\n----\n### Implicit Conversion from Union to Union\nWhen one type union has at least all the same case types as another, a value of the other is assignable to a variable of the first without requiring an explicit cast.\n\nThis is translated the same as with [type pattern match from union to union](#type-pattern-match-from-union-to-union) and [explicit conversion](#explicit-conversion) rules.\n\n```csharp\n    Animal animal = pet;\n```\n```csharp\n    Animal animal = TypeHelper.TryConvert(pet, out Animal tmp) ? tmp : default;\n```\n\n----\n### Combined Unions\nThe case types of one type union can be included in another type union without manually listing them all using a spread-like operator in its declaration.\n\n```csharp\n    public union Pet(Cat, Dog, Bird);\n    public union Animal(..Pet, Alligator, Bison, Platypus);\n```\n\n- Should there be an operators to exclude types? Maybe: !, ~, -\n- What about including all but some cases?  ..Pet-Cat\n\n----\n### Default Unions\nA nominal type union always has a value. Yet, since it is implemented as a struct wrapper it may not actually have a value when the union is uninitialized or initialized to default. This is mostly dealt with by fact that type tests do not succeed when the union is in the default state. Yet, this can lead to runtime exceptions in an exhausted switch.\n\nYou may want to give a nominal type union a meaningful value when it is in the default state, especially when it has a case that corresponds to not having a value, like `None` used by the `Option` type.\n\nTo enable this, one case in the nominal type union's case type list can be designated as the default by assigning it to `default`, as long as that default is not null.\n\n```csharp\n    record None();\n    record Some<T>(T Value);\n\n    union Option<T>(None=default, Some<T>);\n```\n\nWhen the type union is in the default state, the union behaves like it has the specified value, with the `Value` property returning this value and the other accessor patterns acting likewise. \nIf the [Discriminated Access Pattern](#discriminator-access-pattern) is available, the discriminator property returns the value corresponding to this case.\n\n```csharp\n    readonly struct Option<T>\n    {\n        private readonly object _value;\n        ...\n        public object Value => _value ?? default(None);\n    }\n```\n\n**Optional:** a full initializer expression may be specified to allow the default to be any non-null value.\n\n```csharp\n    union Pet(Cat, Dog, Bird=new Bird(\"Polly\"));\n```\n```csharp\n    readonly struct Pet\n    {\n        private readonly object _value;\n        private static readonly Bird _default = new Bird(\"Polly\");\n        ...\n        public object Value => _value ?? _default;\n    }\n```\n\n**Conversion from Default**  \n\nA nominal type union with a default case can be converted to from default without warning as listed in [Conversion to Union from Default](#conversion-to-union-from-default).\n\n```csharp\n    union Number(long=default, double, string);\n    ...\n    Number n = default; // okay here\n```\n----\n### ToString\nThe type union provides an overload to the `ToString` method, dispatching to the method on the contained value.\n\n```csharp\n    public override string ToString()\n    {\n        return this switch\n        {\n            Cat v => v.ToString(),\n            Dog v => v.ToString(),\n            Bird v => v.ToString(),\n            _ => \"\"\n        }\n    }\n```\n\n----\n### Equality\nTo support comparing two type-union instances of the same type-union type, necessary to use the union type as a key in a dictionary for example, the compiler emits code that implements the standard equality interfaces and methods by deferring to the contained value when the unions both have the same cases.\n\n```csharp\n    public readonly struct Pet : IEquatable<Pet>\n    {\n        public bool Equals(Pet other) {...}\n        {\n            return (this, other) switch \n            {\n                (Cat tv, Cat ov) => EqualityComparer<Dog>.Default.Equals(tv, ov),\n                (Dog tv, Dog ov) => EqualityComparer<Cat>.Default.Equals(tv, ov),\n                (Bird tv, Bird ov) => EqualityComparer<Bird>.Default.Equals(tv, ov),\n                _ => false\n            }\n        }\n\n        public override Equals(object other) =>\n            return other is Pet typedOther && Equals(typedOther); \n\n        public static bool operator == (Pet other) => Equals(other);\n        public static bool operator != (Pet other) => !Equals(other);\n    }\n```\n\n- Optional: In addition, the weakly-type Equals overload supports comparing instances of different type-union types, or comparing type union instances to case type values.\n\nThis might be implemented using the [Common Helper Methods](#common-helper-methods) feature.\n```csharp\n    public override Equals(object other) =>\n        object.Equals(\n            TypeUnion.GetValueUnwrapped(this), \n            TypeUnion.TryGetValueUnwrapped(other, out object otherValue) ? otherValue : other\n            );\n```\n\n----\n### Common Member Proxies\nSometimes all cases of a type union share similar members. It would be convenient to be able to access those common members directly on the union type instance rather than need to first switch over all the cases and interact with each case separately. \n\nThis feature adds proxy versions of those members onto the type-union type automatically generated by the compiler for all methods and properties shared by all case types.\n\n```csharp\n    public record Cat(...) { public bool IsHairy => true; }\n    public record Dog(...) { public bool IsHairy => true; }\n    public record Bird(...) { public bool IsHairy => false; }\n\n    public union Pet(Cat, Dog, Bird);\n```\nBecomes\n```csharp\n    public readonly struct Pet\n    {\n        ...\n        public bool IsHairy =>\n            this switch \n            {\n                Cat value1 => value1.IsHairy,\n                Dog value2 => value2.IsHairy,\n                Bird value3 => value3.IsHairy\n            };\n    }\n```\nAnd now it is possible to use the common property directly.\n```csharp\n    Pet pet = ...;\n    if (pet.IsHairy) {...}\n```\n\n- Note: Works well with cases that are structs or don't otherwise share a base type.\n  \n----\n### Common Base Types\nSometimes all cases of a type union share a common base type. It would be convenient to be able to access the value as that type and also the members declared by it directly on the union type instance rather than need to first convert the union instance to that common type. \n\nThis is an alternative to the the [Common Member Proxies](#common-member-proxies) feature. But instead of generating proxy members on the type-union type, it would simply introduce additional translations so the members of the common base type would appear to be accessible from type union instance.\n\nIf all case types share a common base type, the union type takes advantage of this fact and uses that it the `Value` property instead of object. This common base type could either be inferred byt he compiler or declared using some additional syntax.\n\n```csharp\n    public record Animal { public virtual bool HasFourLegs { get; } }\n    public record Cat(...): Animal;\n    public record Dog(...): Animal;\n    public record Bird(...): Animal;\n\n    public union Pet(Cat, Dog, Bird);           // inferred?\n    public union Pet(Cat, Dog, Bird)[Animal];   // syntax?\n``` \nBecomes\n```csharp\n    public readonly struct Pet\n    {\n        public Animal Value { get; }\n    }\n```\n\n- Note: Works well with case types that share a base type and does not require proxy members, but does not work for fully disjoint case types.\n\n#### Translations\nWhen a common base type exists, member access operations against the type union instance that do not bind to the type-union instance itself are translated to apply to the value instead via the `Value` property. This helps maintain the illusion that the union type is its value.\n\n```csharp\n    if (pet.HasFourLegs)\n```    \nTranslates to:\n\n```csharp\n    if (pet.Value.HasFourLegs)\n```\n\nLikewise, conversions to the base type (or any of its base types or interfaces) translate into accesses directly on the `Value` property.\n\n```csharp \n    Animal animal = pet;\n```\nTranslates to:\n```csharp\n    Animal animal = pet.Value;\n```\n\n----\n### Common Member Access\nSometimes all cases of a type union share similar members. It would be convenient to be able to access those common members directly on the union type instance rather than need to first switch over all the cases and interact with each case separately. \n\nThis feature is an alternative to both the [Common Member Proxies](#common-member-proxies) and [Common Base Types](#common-base-types) features.\n\nInstead of generating proxies for members or requiring them to share a base type, this feature enables access of common members by translating accesses to members not found on the union into into access of the members on the value by generating a switch inline (at the use site) or in a generated helper method within the emitted module.\n\n```csharp\n    public record Cat(...) { public bool HasFourLegs => true; }\n    public record Dot(...) { public bool HasFourLegs => true; }\n    public record Bird(...) { public bool HasFourLegs => false; }\n    public union (Cat, Dog, Bird);\n```\n```csharp\n    if (pet.HasFourLegs) {...}\n```\nBecomes\n```csharp\n    if (pet switch {\n        Cat value => value.HasFourLegs,\n        Dog value => value.HasFourLegs,\n        Bird value => value.HasFourLegs\n        }) {...}\n```\n\n----\n### Common Interface Implementation\nWhile rare, it may be necessary to declare and implement an interface on a type union that is also declared and implemented by the case types. You may have an interface you need to be available even in a context that is not aware of the union, such as when the type union is represented boxed as an object or as a type parameter.\n\n```csharp\n    interface ICustomSerialize { void SerializeTo(Stream stream); }\n\n    record Cat(...): ICustomSerialize {...}\n    record Dog(...): ICustomSerialize {...}\n    record Bird(...): ICustomSerialize {...}\n\n    union Pet(Cat, Dog, Bird);\n\n    Pet pet = ...;\n    Serialize(pet);\n    \n    void Serialize<T>(T item) where T : ICustomSerialize\n    {\n        item.SerializeTo(...);\n    }\n```\n\nYou could declare the interface on the type union and implement it yourself to delegate to the union's value. It would be easier if you could avoid writing the boilerplate implementation and let the compiler generate it for you in a manner similar to the [Common Member Proxies](#common-member-proxies) feature.\n\n*When a type union declares an interface that all case types share, but does not implement a member of the interface, that member is auto-generated by the compiler on your behalf to delegate to the specific case type values.*\n\n```csharp\n    // declare without implementation\n    union Pet(Cat, Dog, Bird) : ICustomSerialize;\n```\n\n```csharp\n    // implementation generated private\n    public readonly struct Pet : ICustomSerialize\n    {\n        void ICustomSerializable.SerializeTo(Stream stream) =>\n            ((ICustomSerialize)this.Value)?.SerializeTo(stream);\n    }\n```\n\n----\n### Common Helper Methods\nSome code may need to interact with type unions when the unions or case type values are weakly-typed. For instance, a serialization tool may need to deserialize a value that is a case type and store it via reflection in a field that is a type-union type.\n\nTo enable this, the `TypeUnion` static class of helper methods exists with methods that help identify facts about type unions and converting values to and from unions and even conditionally converting unions to other kinds of unions.\n\n#### TypeUnion.IsTypeUnion\n```csharp\n    public static bool IsTypeUnion(Type type);\n```\nReturns true if the type is a type union.\n\n#### TypeUnion.GetCaseTypes\n```csharp\n    public static IReadOnlyList<Type> GetCaseTypes(Type type);\n```\nReturns a read only list of the case types of a type union. If the type is not a type union it returns an empty list.\n\n#### TypeUnion.GetValue\n```csharp\n    public static object? GetValue(object union);\n```\nThe `GetValue` method gets the current value of the union. \nIf the `union` parameter is not actually a type union it returns null.\n\n#### TypeUnion.GetUnwrappedValue\n```csharp\n    public static object? GetUnwrappedValue(object union);\n```\nThe `GetUnwrappedValue` method is similar to the `GetValue` method, except it continues to drill down through values that might also be type unions until a non-type-union value is reached.\n\n#### TypeUnion.TryConvert (boxed)\n```csharp\n    public static bool TryConvert(object source, Type targetType, out object target);\n```\nThe `TryConvert` method is used to conditionally convert a source value to a target union type, a source union's value to a target type or a source union to a target union type.\n\n#### TypeUnion.TryConvert\n```csharp\n    public static bool TryConvert<TSource, TTarget>(TSource source, [NotNullWhen(true)] out TTarget target);\n```\nThe `TryConvert` method is used to conditionally convert a source value to a target union type, a source union's unwrapped value to a target type or a source union to a target union type.\n\n*This method may be targeted by the compiler to offer additional language conversions of type unions.*\n\n----\n### Common Interface\nUsing [helper methods](#helper-methods) is a good way to write code that constructs, accesses and converts type unions. But those helper methods would be relying on reflection to function, which may require runtime dependencies that you would rather not have and extra performance costs you would rather avoid. Having an interface that type unions implement would solve this. The helper methods could then defer to the type union via its interface for all interactions.\n\n*The `ITypeUnion` interface (actually two interfaces) provides a common means to construct and access the value of arbitrary type unions. Type unions that implement these interfaces can be handled more efficiently.*\n\n```csharp\npublic interface ITypeUnion\n{\n    object Value { get; }\n    bool TryGetValue<TValue>([NotNullWhen(true)] out TValue value);\n}\n\npublic interface ITypeUnion<TSelf> : ITypeUnion\n{\n    static bool TryCreate<TValue>(TValue value, [NotNullWhen(true)] out TSelf union);\n}\n```\n\n- The `Value` property accesses the value of the type union weakly-typed. This may cause boxing of struct values not already boxed.\n- The `TryGetValue` method offers a way to conditionally access the value without boxing. \n- The `TryCreate` static method enables conditional construction of the type union without boxing the value.\n\n----\n### Discriminator Access Pattern\nThe discriminator access pattern offers an alternative to the [value access pattern](#value-access-pattern) that can be significantly more performant with storage layouts that use an underlying discriminator.\n\nThis pattern offers a discriminator property that returns a number corresponding to the case type of the value contained by the union and an accessor property for each case type to access the value without boxing.\n\n```csharp\n    public readonly struct Pet\n    {\n        // discriminator\n        public int Kind { get; }\n\n        // accessors\n        public Cat Value1 { get; }\n        public Dog Value2 { get; }\n        public Bird Value3 { get; }\n    }\n```\n\n- The discriminator property returns an integer value 1 through N, indicating which accessor property should be used to access the value. It returns 0 when the type union has not been formally initialized or has been assigned default, indicting that the type union is in an invalid state and none of the accessor properties should be used to access the value, unless the union has a case that is declared to be default and then the number corresponding to this default case is returned.\n\n- The accessor properties are named Value#N. The number N corresponds to the ordinal of the corresponding case type in the type union declaration.\n\n- The accessor properties are intended to only be accessed when they correspond to the current value of the discriminator. They always return a non-null value when they do correspond to the discriminator, and always return the default value of the corresponding case type when they do not.\n\n- The introduction of this access pattern will cause the order of the case types in the type union declaration to become significant. A change in the order will become a breaking change.\n\n\n#### Pattern Matching\nWhen used to translate a type pattern match the discriminator property is used to match the associated case and the corresponding accessor property is used to perform any additional type tests or matches. \n\n| Example                           | Translation                                  |\n|-----------------------------------|----------------------------------------------|\n| `pet is Dog`                      | `pet is { Kind: 2 }`                         |\n| `pet is Dog dog`                  | `pet is { Kind: 2, Value2: var dog }`        |\n| `pet is Dog { Name: \"Spot\" } dog` | `pet is { Kind: 2, Value2: { Name: \"Spot\" } dog }` |\n| `pet is Corgi corgi`              | `pet is { Kind: 2, Value2: Corgi corgi }`     |\n| `pet is ICase value`              | N/A |\n| `pet is ISomething value`         | N/A |\n| `pet is IUnion value`             | N/A |\n| `pet is TCase value`              | N/A |\n| `pet is T value`                  | N/A |\n\nWhile it is always safe to use the discriminator access pattern to access the value of the union, since it tells you which accessor to use to access the value, it is not always safe for the compiler to assume a single discriminator value comparison can be used to replace a type check. Target types that are interfaces or type parameters may match multiple cases. This is why the translation table is incomplete. Its not safe to use the discriminator access pattern in these cases.\n\nIn addition, the existence of any case type that is an interface potentially pollutes the use of the discriminator access pattern for any other case. If other case types might also implement the same interface it is not possible for the compiler to know that the other case types can be provably accessed via one and only one discriminated accessor.\n\n```csharp\n    public union Pet(IAnimal, Dog);\n    ...\n    Pet pet = (IAnimal)new Dog(...);\n    ...\n    if (pet is Dog dog) {...}  // comparing Kind to 2 (Dog) fails, it is encoded as 1 (IAnimal)\n```\n\nThe existence of any case types that are type parameters has similar issues. However, it is possible that an instantiated generic type union has replaced the type parameters with types that are now sufficiently disjoint such that the compiler can prove that a target type can be accessed from one and only one discriminated accessor. It all depends on what case types are known to exist in the context that the type union is being used.\n\n```csharp\n    public union OneOf<T1, T2>(T1, T2);\n    ...\n    OneOf<int, long> number = 1;\n    if (number is int n) {...} // succeeds because int can only occur when Kind==1\n    ...\n    OneOf<Tx, Ty> something = ...;\n    if (something is Tx x) {...} // may fail because cannot know which Kind is Tx is stored.\n```\n\nPros:\n- Does not box to test or access the value.\n- Significantly faster than a type test and can help optimize switch statements and expressions that match multiple cases.\n\nCons:\n- A change in the set or order of case types is a binary breaking change because it changes the meaning of the discriminator values and the naming of the accessor properties.\n- Some case types may not be sufficiently disjoint to correspond to a single discriminated accessor.\n\n----\n### TryGet Access Pattern\nThe TryGet access pattern is another alternative to the value access pattern, that like the [discriminator access pattern](#discriminator-access-pattern) can access the values strongly-typed, but may not be as favorable to optimization.\n\nThe TryGet access pattern has a `TryGetValue` method for each case type, that returns a bool indicating if the value is successfully accessed as that type and the value itself as a strongly-typed out parameter.\n\n```csharp\n    public readonly struct Pet\n    {\n        public bool TryGetValue(out Cat value);\n        public bool TryGetValue(out Dog value);\n        public bool TryGetValue(out Bird value);\n    }\n```\n- Each `TryGetValue` method tests and accesses the value in one call, with the semantics exactly the same as pattern matching using the [Value Access Pattern](#value-access-pattern), regardless of the storage model.\n\n#### Pattern Matching\nWhen a corresponding `TryGetValue` method is available, a type pattern match can be translated using this method.\n\n| Example                           | Translation                                  |\n|-----------------------------------|----------------------------------------------|\n| `pet is Dog`                      | `pet.TryGetValue(out Dog _)`                      |\n| `pet is Dog dog`                  | `pet.TryGetValue(out Dog dog)`                    |\n| `pet is Dog { Name: \"Spot\" } dog` | `pet.TryGetValue(out Dog tmp) && tmp is { Name: \"Spot\" } dog }` |\n| `pet is Corgi corgi`              | `pet.TryGetValue(out Dog tmp) && tmp is Corgi corgi`     |\n| `pet is ICase value`              | `pet.TryGetValue(out ICase value)`                |\n| `pet is ISomething value`         | N/A |\n| `pet is IUnion value`             | N/A |\n| `pet is TCase value`              | `pet.TryGetValue(out TCase value)`                |\n| `pet is T value`                  | N/A |\n\nSome examples cannot be translated. Only cases with `TryGetValue` overloads that correspond to the target type can be used.\n\nPros:\n- Does not box to test or access the value like the [Value Access Pattern](#value-access-pattern).\n- Does not have the drawback of the [Discriminated Access Pattern](#discriminator-access-pattern) with respect to target types can case types that are not sufficiently disjoint.\n- Faster than the [Generic TryGet Access Pattern](#generic-tryget-access-pattern).\n\nCons:\n- Cannot help optimize a switch statement or expression.\n\n----\n### Generic TryGet Access Pattern\nThe generic TryGet access pattern is similar to the [TryGet Access Pattern](#tryget-access-pattern) but only has a single generic `TryGetValue` method that can be used to test and access any value without boxing.\n\n```csharp\n    public readonly struct Pet \n    {\n        public bool TryGetValue<T>([NotNullWhen(true)] out T value);\n    }\n```\n\n#### Pattern Matching\nWhen this access pattern is available, all type pattern matches can be translated using the generic `TryGetValue` method.\n\n| Example                           | Translation                                  |\n|-----------------------------------|----------------------------------------------|\n| `pet is Dog`                      | `pet.TryGetValue(out Dog _)`                      |\n| `pet is Dog dog`                  | `pet.TryGetValue(out Dog dog)`                    |\n| `pet is Dog { Name: \"Spot\" } dog` | `pet.TryGetValue(out Dog tmp) && tmp is { Name: \"Spot\" } dog }` |\n| `pet is Corgi corgi`              | `pet.TryGetValue(out Dog tmp) && tmp is Corgi corgi`     |\n| `pet is ICase value`              | `pet.TryGetValue(out ICase value)`                |\n| `pet is ISomething value`         | `pet.TryGetValue(out ISomething value)`           |\n| `pet is IUnion value`             | N/A                                          |\n| `pet is TCase value`              | `pet is TCase value or pet.TryGetValue(out value)` |\n| `pet is T value`                  | `pet is T value or pet.TryGetValue(out value)` |\n\nPros:\n- Does not box to test or access the value like the [Value Access Pattern](#value-access-pattern).\n- Does not have the drawback of the [Discriminated Access Pattern](#discriminator-access-pattern) with respect to target types can case types that are not sufficiently disjoint.\n- Only requires one method, unlike the [TryGet Access Pattern](#tryget-access-pattern).\n\nCons:\n- Slower than the [TryGet Access Pattern](#tryget-access-pattern) due to generic method overhead.\n\n----\n### Value Access Pattern \nThe value access pattern is the default access pattern and is always generated for a type union by the compiler. It is listed here only for completeness.\n\n```csharp\n    public readonly struct Pet\n    {\n        // value access pattern\n        public object Value => ...;\n    }\n```\n\n- The `Value` property returns the same value used to construct the type union, even if the case type was another type union.\n\n#### Pattern Matching\nThe translation for the value access pattern is outlined in the [Type Pattern Matching From Union](#type-pattern-match-from-union) section.\n\n- Depending on the nature of the case types, this access pattern may not be best suited for use in translating language operations. Other optional access patterns, if included may be preferred.\n\n----\n### Access Pattern Heuristic\nThe compiler chooses the access pattern to use for a pattern match or conversion translation given the patterns available on the type union.\n\n1. If the [discriminated access pattern](#discriminator-access-pattern) is available and the target type of a type pattern match or conversion can be reduced to a single discriminated accessor, then this access pattern is used.\n2. If the non-generic [TryGet access pattern](#tryget-access-pattern) is available and the target type of a type pattern match or conversion has a corresponding `TryGet` method, then this access pattern is used.\n3. Either the [value access pattern](#value-access-pattern) or the generic [TryGet access pattern](#generic-tryget-access-pattern) is used. The choices are:\n   - The value access pattern is always used. (current plan)\n   - The generic TryGet access pattern is always used.\n   - If all cases are known to be reference types, the value access pattern is used.\n   - If all cases are known to be value types, the generic TryGet access pattern is used.\n\n----\n### Boxed Layout\nThe boxed layout includes a single field typed as object for all values. This is the default layout unless other layouts are available and chosen by the compiler.\n\n```csharp\n    public record Cat(...);\n    public record Dog(...);\n    public record Bird(...);\n\n    public union Pet(Cat, Dog, Bird);\n```\n```csharp\n    public readonly struct Pet\n    {\n        private readonly object _value;\n\n        private Pet(object value) \n        {\n            _value = value;\n        }\n\n        public Pet(Cat value): this(value) {}\n        public Dog(Dog value): this(value) {}\n        public Bird(Bird value): this(value) {}\n\n        public object Value => _value;\n    }\n```\n\n- The boxed layout is never combined with a [discriminated access pattern](#discriminator-access-pattern) because determining a discriminator value would defeat the performance advantage of using the pattern.\n\n----\n### Discriminated Boxed Layout\nThe discriminated boxed layout includes a field typed as object for all values and a discriminator field. \n\n```csharp\n    public record Cat(...);\n    public record Dog(...);\n    public record Bird(...);\n\n    public union Pet(Cat, Dog, Bird);\n```\n```csharp\n    public readonly struct Pet\n    {\n        private readonly int _kind;\n        private readonly object _value;\n\n        private Pet(int kind, object value) \n        {\n            _kind = kind;\n            _value = value;\n        }\n\n        public Pet(Cat value): this(1, value) {}\n        public Dog(Dog value): this(2, value) {}\n        public Bird(Bird value): this(3, value) {}\n\n        public object Value => _value;\n\n        // optional discriminator access pattern\n        public int Kind => _kind;\n        public Cat Value1 => _kind == 1 ? (Cat)_value : default!;\n        public Dog Value2 => _kind == 2 ? (Dog)_value : default!;\n        public Bird Value3 => _kind == 3 ? (Bird)_value : default!;\n    }\n```\n\n- This layout is practical only when the [discriminator access pattern](#discriminator-access-pattern) is being exposed.\n\n----\n### Fat Layout\nThe fat layout includes a strongly-typed field for each case type and a discriminator field typed as int.\n\n```csharp\n    public union Pet(Cat, Dog, Bird);\n```\n```csharp\n    public readonly struct Pet\n    {\n        private readonly int _kind;\n        private readonly Cat _value1;\n        private readonly Dog _value2;\n        private readonly Bird _value3;\n\n        public Pet(Cat value)\n        {\n            _kind = 1;\n            _value1 = value;\n        }\n\n        public Dog(Dog value)\n        {\n            _kind = 2;\n            _value2 = value;\n        }\n\n        public Bird(Bird value)\n        {\n            _kind = 3;\n            _value3 = value;\n        }\n\n        // value access pattern\n        public object Value =>\n            _kind switch \n            {\n                1 => _value1,\n                2 => _value2,\n                3 => _value3,\n                _ => null!\n            };\n\n        // optional discriminator access pattern\n        public int Kind => _kind;\n        public Cat Value1 => _value1;\n        public Dog Value2 => _value2;\n        public Bird Value3 => _value3;\n    }\n```\n- This layout never boxes a case type value since all cases have their own strongly-typed field.\n- Use of the [value access pattern](#value-access-pattern) may cause boxing.\n\n----\n### Skim Layout\nThe skim layout is similar to the [Fat Layout](#fat-layout) except when multiple case types are known to be reference types then those cases stored in a single shared object field and cast back to the case type on access.\n\n```csharp\n    public record Cat(...);\n    public record Dog(...);\n    public record struct Bird(...); \n\n    public union Pet(Cat, Dog, Bird);\n```\n```csharp\n    public readonly struct Pet\n    {\n        private readonly int _kind;\n        private readonly object _value;\n        private readonly Bird _value3;\n\n        public Pet(Cat value)\n        {\n            _kind = 1;\n            _value = value;\n        }\n\n        public Dog(Dog value)\n        {\n            _kind = 2;\n            _value = value;\n        }\n\n        public Bird(Bird value)\n        {\n            _kind = 3;\n            _value3 = value;\n        }\n\n        // value access pattern\n        public object Value =>\n            _kind switch \n            {\n                1 => _value,\n                2 => _value,\n                3 => _value3,\n                _ => null!\n            };\n\n        // optional discriminator access pattern\n        public int Kind => _kind;\n        public Cat Value1 => _kind == 1 ? (Cat)_value : default!;\n        public Dog Value2 => _kind == 2 ? (Dog)_value : default!;\n        public Bird Value3 => _kind == 3 ? _value3 : default!;\n    }   \n```\n\n- When all cases are known reference type this reduces to the same as the [discriminated boxed layout](#discriminated-boxed-layout).\n- When fewer than two cases are known to be reference types this layout reduces to the [fat layout](#fat-layout).\n\n----\n### Overlapped Layout\nThe overlapped layout is similar to the [Skim Layout](#skim-layout), except that it overlaps the values of case types that can be overlapped.\n\nIf two or more case types can be overlapped, a special `Overlap` struct type is generated using `StructLayout` and `FieldOffset` attributes to store the values of different cases in the same memory area. Those cases with types that can be overlapped have a field corresponding to them in the `Overlap` type instead of a field in type-union type. A single field of the `Overlap` type is then added to store and access these cases.\n\nTypes that are safe to overlap are:\n- primitive value-types\n- value-types from the runtime libraries that do not contain reference values\n- value-types from the current compilation unit that do not contain reference values\n\n*Other value types from outside the compilation unit cannot be proven to be free of reference values at compile time, since compile-time metadata may not show all private fields of a type.*\n\n```csharp\n    public union Number(long, double, decimal, string);\n```\n```csharp\n    public readonly struct Number\n    {\n        private readonly int _kind;\n        private readonly Overlap _overlap;\n        private readonly string _value4;\n\n        [StructLayout(LayoutKind.Explicit)]\n        file struct Overlap\n        {\n            [FieldOffset(0)]\n            public long value1;\n            [FieldOffset(0)]\n            public double value2;\n            [FieldOffset(0)]\n            public decimal value3;\n        }\n\n        public Number(long value)\n        {\n            _kind = 1;\n            _overlap.value1 = value;\n        }\n\n        public Number(double value)\n        {\n            _kind = 2;\n            _overlap.value2 = value;\n        }\n\n        public Number(decimal value)\n        {\n            _kind = 3;\n            _overlap.value3 = value;\n        }\n\n        public Number(string value)\n        {\n            _kind = 4;\n            _value4 = value;\n        }\n\n        // value access pattern\n        public object Value =>\n            _kind switch \n            {\n                1 => _overlap.value1,\n                2 => _overlap.value2,\n                3 => _overlap.value3,\n                4 => _value4,\n                _ => null!,\n            };\n\n        // optional discriminator access pattern\n        public int Kind => _kind;\n        public long Value1 => _kind == 1 ? _overlap.value1 : default!;\n        public double Value2 => _kind == 2 ? _overlap.value2 : default!;\n        public decimal Value3 => _kind == 3 ? _overlap.value3 : default!;\n        public string Value4 => _kind == 4 ? _value4 : default!;\n    }\n```\n\n----\n### Deconstructed Layout\nThis deconstructed layout is similar to the [Skim Layout](#skim-layout) except that it also deconstructs value tuples and record structs into their constituent parts, allocating storage for each element using rules to share fields with other cases when possible, and then reconstructing the values on access.\n\nType union cases under this technique end up having zero or more elements each stored in zero or more fields. If the case type cannot be deconstructed then it simply represents its own single element. If it can it is deconstructed into its elements, and then the same process is applied to each of these elements until a final set of elements that cannot be deconstructed is obtained.\n\nEach element of a case is assigned a storage location using the same pool of fields shared with all other cases. Multiple fields of the same type may be required to satisfy storage of all elements.\n\n- Elements of reference type are stored in a field with type object, unless a field of the reference type can satisfy all uses of the field across all cases.\n- Elements of value type (struct) are stored in a field of that type.\n- Case types that deconstruct into zero elements take up no additional storage.\n\n```csharp\n    public record struct Cat(string Name, int Lives);\n    public record struct Dog(string Name, bool Hunts);\n    public record struct Bird(string Name, bool WantsCracker);\n\n    public union Pet(Cat, Dog, Bird);\n```\n```csharp\n    public readonly struct Pet\n    {\n        private readonly int _kind;\n        private readonly string _element1;\n        private readonly int _element2;\n        private readonly bool _element3;\n\n        public Pet(Cat value)\n        {\n            _kind = 1;\n            (_element1, _element2) = value;\n        }\n\n        public Pet(Dog value)\n        {\n            _kind = 2;\n            (_element1, _element3) = value;\n        }\n\n        public Pet(Bird value)\n        {\n            _kind = 3;\n            (_element1, _element3) = value;\n        }\n\n        // value access pattern\n        public object Value =>\n            _kind switch \n            {\n                1 => new Cat(_element1, _element2),\n                2 => new Dog(_element1, _element3),\n                3 => new Bird(_element1, _element3)\n                _ => null!\n            };\n\n        // optional discriminator access pattern\n        public int Kind => _kind;\n        public Cat Value1 => _kind == 1 ? new Cat(_element1, _element2) : default!;\n        public Dot Value2 => _kind == 2 ? new Dog(_element1, _element3) : default!;\n        public Bird Value3 => _kind == 3 ? new Bird(_element1, _element3) : default;\n    }\n```\n\n----\n### Overlapped Deconstructed Layout\nThe [Overlapped Layout](#overlapped-layout) and the [Deconstructed Layout](#deconstructed-layout) can be combined. Deconstructed elements with types that can be overlapped are overlapped. \n\n```csharp\n    public record struct Cat(string Name, int Lives);\n    public record struct Dog(string Name, bool Hunts);\n    public record struct Bird(string Name, bool WantsCracker);\n\n    public union Pet(Cat, Dog, Bird);\n```\n```csharp\n    public readonly struct Pet\n    {\n        private readonly int _kind;\n        private readonly string _element1;\n        private readonly Overlap _overlap;\n\n        [StructLayout(LayoutKind.Explicit)]\n        file struct Overlap\n        {\n            [FieldOffset(0)]\n            public int element2;\n            [FieldOffset(0)]\n            public bool element3;\n        }\n\n        public Pet(Cat value)\n        {\n            _kind = 1;\n            (_element1, _overlap.element2) = value;\n        }\n\n        public Pet(Dog value)\n        {\n            _kind = 2;\n            (_element1, _overlap.element3) = value;\n        }\n\n        public Pet(Bird value)\n        {\n            _kind = 3;\n            (_element1, _overlap.element3) = value;\n        }\n\n        // value access pattern\n        public object Value =>\n            _kind switch \n            {\n                1 => new Cat(_element1, _overlap.element2),\n                2 => new Dog(_element1, _overlap.element3),\n                3 => new Bird(_element1, _overlap.element3)\n                _ => null!\n            };\n\n        // optional discriminator access pattern\n        public int Kind => _kind;\n        public Cat Value1 => _kind == 1 ? new Cat(_element1, _overlap.element2) : default!;\n        public Dot Value2 => _kind == 2 ? new Dog(_element1, _overlap.element3) : default!;\n        public Bird Value3 => _kind == 3 ? new Bird(_element1, _overlap.element3) : default;\n    }\n```\n\n- Each case that has at least one element that can be overlapped has a field corresponding to it in generated `Overlap` type. If a case has multiple elements that can be overlapped, those elements are grouped into a value-tuple.\n\n----\n### Hybrid Layout\nThis layout stores both the value (in all its cases) and discriminator in a special hybrid type that can store both reference and struct value types in a minimal representation without requiring custom code generation particular to the case types.\n\n```csharp\n    public union Pet(Cat, Dog, Bird);\n```    \n```csharp\n    public readonly struct Pet\n    {\n        private readonly HybridLayout _data;\n\n        private static HybridLayout.Encoding<Cat> _encoding1 = ...;\n        private static HybridLayout.Encoding<Dog> _encoding2 = ...;\n        private static HybridLayout.Encoding<Bird> _encoding3 = ...;\n\n        file Pet(HybridLayout data) \n        {\n            _data = data;\n        }\n\n        public Pet(Cat value): this(_encoding1.Create(value)) {}\n        public Pet(Dog value): this(_encoding2.Create(value)) {}\n        public Pet(Bird value): this(_encoding3.Create(value)) {}\n\n        // value access pattern\n        public object Value => _data.Value;\n\n        // discriminator access pattern\n        public int Kind => _data.Kind;\n        public Cat Value1 => _encoding1.Decode(_data);\n        public Dog Value2 => _encoding2.Decode(_data);\n        public Bird Value3 => _encoding3.Decode(_data);\n    }   \n```\n\n- This layout contains an object field for reference type values and 64 bits of extra memory for small structs that do not contain references. Large structs or structs with references are boxed and stored in the same field as reference type values.\n- Structs wrapping a single reference value are deconstructed and the reference value stored in the reference type field.\n- A discriminator value is also recorded using *tricks* not explained here.\n- This layout is a compromise that avoid boxing for some commonly used small value types, and boxing for larger value types.\n\n----\n### Layout Heuristic\nThe compiler chooses a layout that best suits the case types of the union. The following options are listed in order of preference, assuming the each layout is available to the compiler.\n\n1. If all case types are reference types, the [Boxed Layout](#boxed-layout) is used.\n2. The [Overlapped Deconstructed Layout](#overlapped-deconstructed-layout) is used.\n3. The [Deconstructed Layout](#deconstructed-layout) is used.\n4. The [Overlapped Layout](#overlapped-layout) is used.\n5. The [Skim Layout](#skim-layout) is used.\n6. The [Fat Layout](#fat-layout) is used.\n7. The [Hybrid Layout](#hybrid-layout) is used.\n8. The [Boxed Layout](#boxed-layout) is used.\n\n----\n### Layout Hints\nA hint can be given to the compiler to influence the heuristic into choosing a different layout.\n\nThe `UnionLayout` attribute can be specified to influence the layout used, by allowing you specify a value of the `UnionLayoutKind` enum.\n\nThe `UnionLayoutKind` contains the following values:\n\n- Boxed: The [Boxed Layout](#boxed-layout) is used.\n- Fat: The [Fat Layout](#fat-layout) is used.\n- Balanced: The Standard Heuristic is used.\n\nExample:\n```csharp\n    [UnionLayout(UnionLayoutKind.Fat)]\n    public union Pet(Cat, Dog, Bird)\n```\n\n----\n# END OF PROPOSAL\n"
  },
  {
    "path": "meetings/working-groups/discriminated-unions/pre-unification-proposals/custom-unions.md",
    "content": "# Custom Unions\n\n## Summary\n\n[Nominal Type Unions](https://github.com/dotnet/csharplang/blob/main/proposals/nominal-type-unions.md) allow the compiler to generate union types that have special behavior when consumed.\n\nThis proposal specifies a pattern that a class or struct declaration can follow in order to get the same special behavior when consumed.\n\n## Motivation\n\nThe declaration syntax for nominal unions is intended to cover most green-field situations where people want to specify a union. However, for some scenarios the generated outcome is not optimal or even usable:\n\n- There is already an existing widely consumed library type representing a \"union\", and the author wants to imbue it with \"union powers\" without breaking existing usage.\n- For e.g. performance, architectural or interop reasons, the contents of the union need to be stored differently than the default boxed object field used in compiler-generated unions.\n\n## Specification\n\nA type is considered a \"custom union type\" if it implements the [`IUnion` interface](https://github.com/dotnet/csharplang/blob/main/proposals/union-interfaces.md). Every constructor on the type that is at least as accessible as the type and takes exactly one parameter contributes the type of that parameter as a case type of the custom union type.\n\nThe consumption of such a type as a custom union type is enabled in the following ways:\n\n- **Implicit conversion**: There is an implicit union conversion from each case type to the custom union type. It is implemented by calling the corresponding constructor.\n- **Pattern matching**: Patterns applied to a value of the custom union type (other than always-succeeding patterns such as `_` and `var`) are instead applied to the `IUnion.Value` property.\n- **Exhaustiveness**: Switch expressions covering all the case types of the custom union type are considered exhaustive.\n\n## Example\n\nSay the following type already exists:\n\n```csharp\npublic sealed class Result<T>\n{\n    internal Result(object? outcome) => (Value, Error) = outcome switch\n    {\n        Exception error => (default!, error),\n        T value => (value, null),\n        null when default(T) is null => (default!, null);\n        _ => throw new InvalidOperationException(...);\n    };\n    \n    public Result(T value) => (Value, Error) = (value, null);\n    public Result(Exception error) => (Value, Error) = (default!, error);\n    \n    public T Value { get; }\n    public Exception? Error { get; }\n    public bool Succeeded => Error is null;\n}\n```\n\nIt can be made a union type simply by implementing the `IUnion` interface:\n\n```csharp\npublic sealed class Result<T> : IUnion\n{\n    object? IUnion.Value => Error ?? Value;\n    ... // Existing members\n}\n```\n\nNote that in this example the existing type already has a public `Value` property with a different meaning than the one on the `IUnion` interface, so `IUnion.Value` gets implemented explicitly, and that's the one the compiler will consume for pattern matching purposes.\n\nNote also that the type is only considered to have two case types, `T` and `Exception`, even though it has a third single-parameter constructor. That's because the `object?` constructor is less accessible than the type itself and doesn't count.\n\n## Drawbacks\n\nNot every existing type may be enhanced in a non-breaking way to become a custom union type using these rules. For instance, it may not be able to expose the right set of constructors to establish the desired set of case types - e.g. it relies on factory methods for creating values. It is possible that we need to refine or enhance the mechanism by which a type is interpreted as a custom union type."
  },
  {
    "path": "meetings/working-groups/discriminated-unions/pre-unification-proposals/nominal-type-unions.md",
    "content": "# Nominal Type Unions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9411  \nUnion overview issue: https://github.com/dotnet/csharplang/issues/8928\n\n## Summary\n\nNamed unions have a closed list of \"case types\":\n\n``` c#\npublic union IntOrString(int, string);\n```\n\nFresh case types can be succinctly declared if we adopt the \"Case Declarations\" proposal:\n\n``` c#\npublic union Pet\n{\n    case Cat(...);\n    case Dog(...);\n}\n```\n\nCase types convert implicitly to the union type:\n\n``` c#\nPet pet = dog;\n```\n\nPatterns apply to the *contents* of a union. Switches that handle all case types are exhaustive:\n\n``` c#\nvar name = pet switch\n{\n    Cat cat => ...,\n    Dog dog => ...,\n    // No warning about missing cases\n}\n```\n\nThere is no \"is-a\" relationship between a union type and its case types:\n\n``` c#\n_ = obj is Pet; // True only if 'obj' is an actual boxed 'Pet'\n```\n\n## Motivation\n\n- **Cost:** Forego runtime support and get 90% of the value for 10% of the cost.\n- **Performance:** Eliminate more allocations now and in the future.\n- **Simplicity:** Avoid introducing a new kind of runtime type relationship in e.g. generic code.\n- **Flexibility:** Embrace custom unions and low allocation layout options in the future.\n\n## Detailed design\n\n### Syntax\n\nA union declaration has a name and a list of case types.\n\n``` antlr\ntype_union_declaration\n    : attributes? struct_modifier* 'partial'? 'union' identifier type_parameter_list?\n      '(' type (',' type)* ')' type_parameter_constraints_clause* \n      (`{` type_declarations `}` | ';')\n    ;\n```\n\nCase types can be any type that converts to `object`, e.g., interfaces, type parameters, nullable types and other unions. It is fine for cases to overlap, and for unions to nest or be null.\n\n### Lowering\n\n``` c#\npublic union Pet(Cat, Dog){ ... }\n```\n\nIs lowered to:\n\n``` c#\n[Union]\npublic record struct Pet\n{\n    public object? Value { get; }\n    \n    public Pet(Cat value) => Value = value;\n    public Pet(Dog value) => Value = value;\n    \n    ...\n}\n```\n\n### Implicit conversion\n\nA \"union conversion\" implicitly converts from a case type to the union. It is sugar for calling the union's constructor:\n\n``` c#\nPet pet = dog;\n// becomes\nPet pet = new Pet(dog);\n```\n\nIf more than one constructor overload applies an ambiguity error occurs.\n\n### Pattern matching\n\nExcept for the unconditional `_` and `var` patterns, all patterns on a union value get implicitly applied to its `Value` property:\n\n``` c#\nvar name = pet switch\n{\n    Dog dog => dog.Name,   // applies to 'pet.Value'\n    var p => p.ToString(), // applies to 'pet'\n};\n```\n\nA pattern cannot _explicitly_ access a union's `Value` property. This is similar to `Nullable<T>`.\n\n### Exhaustiveness\n\nA `switch` expression is exhaustive if it handles all of a union's cases:\n\n``` c#\nvar name = pet switch\n{\n    Dog dog => ...,\n    Cat cat => ...,\n    // No warning about non-exhaustive switch\n};\n```\n\n### Nullability\n\nThe null state of a union's `Value` property is tracked normally, with these additions: \n- When none of the case types are nullable, the default state for `Value` is \"not null\" rather than \"maybe null\". \n- When a union constructor is called (explicitly or through a union conversion), the new union's `Value` gets the null state of the incoming value.\n\nSwitch exhaustiveness obeys normal nullability rules:\n\n``` c#\nPet pet = GetNullableDog(); // 'pet.Value' is \"maybe null\"\nvar value = pet switch\n{\n    Dog dog => ...,\n    Cat cat => ...,\n    // Warning: 'null' not handled\n}\n```\n\n### Nested unions\n\nUnions can recursively have unions as case types:\n\n``` c#\nunion Pet (Cat, Dog);\nunion Animal (Pet, Cow);\n```\n\nThere is no \"merging\" of nested unions - in patterns or elsewhere. An `Animal` is never directly a `Cat`, but it might be a `Pet` that is a `Cat`:\n\n``` c#\nif (animal is Pet p && p is Cat c) ...\n```\n\nOr simply\n\n```c#\nif (animal is Pet and Cat c) ...\n```\n\n## Drawbacks\n\n- *Merging:* Unlike runtime-supported unions, nested unions do not \"merge\". If the declaration is nested then so is the consuming code.\n- *Runtime type relationships:* Some functionality, e.g. testing whether a value belongs to a union, requires helper methods.\n- *Serialization:* Serialization frameworks may need to special case unions to roundtrip them correctly.\n- *Generic specialization:* Unions, like other structs, put pressure on generic specialization in the current runtime.\n\n## Optional features\n\n- *Custom union types:* Generalize to a compiler pattern so custom union types can be manually authored.\n- *Helper methods:* Generate helper methods to facilitate common union functionality such as testing union membership.\n- *Alternative layouts:* Let the user request a non-boxing union layout, e.g. with a `struct` keyword. \n"
  },
  {
    "path": "meetings/working-groups/discriminated-unions/pre-unification-proposals/non-boxing-access-pattern.md",
    "content": "# Non-boxing Access Pattern for Custom Unions\n\n## Summary\n\nA custom union can provide an alternative, non-boxing means to access its value by implementing a `TryGetValue` method overload for each case type, as well as a `HasValue` property to check for null.\n\n## Motivation\n\nA motivating scenario for manually implementing a [custom union type](https://github.com/dotnet/csharplang/blob/main/proposals/custom-unions.md) is to customize how the value is stored to hopefully either match an existing interop layout or to avoid allocations.\n\nHowever, this goal is hampered by the limitation of the compiler only understanding how to access the value via the `Value` property, resulting in struct values being boxed regardless of layout.\n\nThis proposal allows custom union types that support non-allocation scenarios, opening the way to possible future first-class syntax for non-allocating unions and to the development of special union types like `Option` and `Result` that would benefit from minimizing or eliminating extra allocations.\n\n## Specification\n\n### Pattern\n\nA custom union may offer non-boxing access to its value by implementing `TryGetValue` methods that accept each of its case types, plus a `HasValue` property to check for null:\n\n```csharp\npublic struct MyUnion : IUnion\n{\n    public bool HasValue => ...;\n    public bool TryGetValue(out Case1 value) {...}\n    public bool TryGetValue(out Case2 value) {...}\n    \n    object? IUnion.Value => ...;\n}\n```\n\n### Lowering\n\nWhen the compiler lowers a type pattern match, and the type involved corresponds to a `TryGetValue` overload, the compiler uses this overload instead of the `Value` property to implement the pattern match.\n\n```csharp\nif (u is Case1 c1) {...}\n```\n\nlowers to:\n\n```csharp\nif (u.TryGetValue(out Case1 c1)) {...}\n```\n\nIf multiple `TryGetValue` overloads apply, and overload resolution fails to pick a unique best overload, the compiler will pick one arbitrarily rather than yield an ambiguity error.\n\nWhen the compiler lowers a `null` constant pattern match, and a `HasValue` property is available, the compiler uses this property instead of the `Value` property to implement the pattern match:\n\n```csharp\nif (u is null) {...}\n```\n\nlowers to:\n\n```csharp\nif (!u.HasValue) {...}\n```\n\n### Well-formedness\n\nIt is up to the author of a custom union with non-boxing access to ensure that the behavior of the access methods is functionally equivalent to the behavior of using the `Value` property:\n\n- `u.HasValue` yields true if and only if `u.Value is not null` would yield true\n- `u.TryGetValue(out T value1)` yields true if and only if `u.Value is T value2` would yield true, and `value1` is equal to `value2`.\n\n## Example\n\nHere is an example of a custom union employing a strategy of using separate fields for each case, and an additional field acting as a discriminator.\n\n```csharp\npublic record struct Point(double X, double Y);\npublic record struct Rectangle(Point TopLeft, Point BottomRight);\n\npublic struct PointOrRectangle : IUnion\n{\n    private enum Kind { Null = 0, Point, Rectangle }\n\n    private readonly Kind _kind;\n    private readonly Point _value1;\n    private readonly Rectangle _value2;\n\n    public PointOrRectangle(Point value) =>\n        (_kind, _value1, _value2) = (Kind.Point, value, default);\n\n    public PointOrRectangle(Rectangle value) =>\n        (_kind, _value1, _value2) = (Kind.Rectangle, default, value);\n\n    object? IUnion.Value => \n        _kind switch \n        {\n            Kind.Point => _value1, // boxes\n            Kind.Rectangle => _value2, // boxes\n            _ => null\n        };\n\n    public bool HasValue => _kind != Null;\n        \n    public bool TryGetValue(out Point value)\n    {\n        if (_kind == Kind.Point)\n        {\n            value = _value1;\n            return true;\n        }\n        else \n        {\n            value = default;\n            return false;\n        }\n    }\n\n    public bool TryGetValue(out Rectangle value)\n    {\n        if (_kind == Kind.Rectangle)\n        {\n            value = _value2;\n            return true;\n        }\n        else \n        {\n            value = default;\n            return false;\n        }\n    }\n}\n```"
  },
  {
    "path": "meetings/working-groups/discriminated-unions/pre-unification-proposals/union-interfaces.md",
    "content": "# Union Interfaces\n\n## IUnion\n\n### Summary\n\nUnion types implement the interface `IUnion` that makes it easy to identify and interact with unions at runtime when a value that might be a union is weakly typed or represented as a type parameter.\n\n```csharp\nobject value = ...;\n\nif (value is IUnion union) \n{\n    // don't write union wrapper\n    Write(union.Value);\n}\nelse \n{\n    Write(value);\n}\n```\n\n### Motivation\n\nTo enable library or utility code that is unaware of application specific union types to become union aware and interact with union values without using reflection.\n\nTo provide a means for the compiler to identify union types and access the value of the union with certainty.\n\n### Detailed Design\n\n```csharp\npublic interface IUnion\n{\n    // The value of the union or null\n    object? Value { get; }\n}\n```\n\n* The `IUnion` interface is all that is necessary for a type to be considered a union by the language.  \n* The `Value` property of the interface is targeted by the compiler to implement pattern matching.\n* *Nominal Type Unions* generated by the compiler implement this interface.\n\n### Example\n\n```csharp\npublic struct MyUnion : IUnion\n{\n    public MyUnion(Case1 value) { this.Value = value; }\n    public MyUnion(Case2 value) { this.Value = value; }\n\n    // implements IUnion.Value\n    public object Value { get; }\n}\n```\n\n## IUnion&lt;TUnion&gt;\n\n### Summary\n\nUnions may also implement the `IUnion<TUnion>` to provides a means to construct union instances at runtime when the union type is a constrained type parameter.\n\n```csharp\nTUnion ReadUnion<TUnion>() where TUnion : IUnion<TUnion>\n{\n    object val = ReadValue();\n\n    // wrap the value in the union\n    if (TUnion.TryCreate(val, out var union)) \n        return union;\n\n    throw ...;\n}\n```\n\n### Motivation\n\nTo enable library or utility code that is unaware of application specific union types to become union aware and construct union instances from case values at runtime.\n\n### Detailed Design\n\n```csharp\npublic interface IUnion<TUnion> : IUnion\n    where TUnion : IUnion<TUnion>\n{\n    // Creates a union from a value\n    static abstract bool TryCreate(object? value, [NotNullWhen(true)] out TUnion union);\n}\n```\n* *Nominal Type Unions* generated by the compiler implement this interface.\n* Maybe named `IUnionTryCreate` instead?\n\n### Example\n\n```csharp\n// lowered MyUnion\npublic struct MyUnion : IUnion<MyUnion>\n{\n    public Union(Case1 value) { this.Value = value; }\n    public Union(Case2 value) { this.Value = value; }\n\n    // IUnion.Value\n    public object? Value { get; }\n\n    // IUnion<MyUnion>.TryCreate\n    public static bool TryCreate(object? value, [NotNullWhen(true)] out MyUnion union)\n    {\n        // handle all known case types and null\n        switch (value)\n        {   \n            case Case1 value1:\n                union = new MyUnion(case1);\n                return true;\n            case Case2 value2:\n                union = new MyUnion(value2);\n                return true;\n            case null when _canBeNull:                \n                union = default;\n                return true;\n            default:\n                union = default!;\n                return false;\n        }\n    }\n\n    // precompute if this union can be created with a null value.\n    private static readonly bool _canBeNull = \n        default(Case1) == null || default(Case2) == null;\n}\n```\n\n* *Note*: it is also valuable for a union type to provide a public means to construct another instance when the union type is fully understood, but the value is not.\n\n```csharp\nobject? value = ReadValue();\n\n// if not type-safe certain that value is a case type, use TryCreate.\nif (MyUnion.TryCreate(value, out MyUnion union))\n{\n    ...\n}\n```\n\n## Additional Interfaces (Not Approved)\n\n### Summary\n\nAdditional interfaces expose the remaining methods and properties that the compiler is designed to look for without requiring the union to adopt these specific signatures as its public API.\n\nFor example, the following union-like type is not compatible as is. It uses the term `Value` to refer to a case and it does not expose public constructors.\n\n```csharp\npublic record Error(int code);\n\npublic struct Result<T>\n{\n    public bool IsValue => ...;\n    public bool IsError => ...;\n    public T Value => ...;\n    public Error Error => ...;\n    public static Result<T> FromValue(T value) {...}\n    public static Result<T> FromError(Error error) {...}\n}\n\n...\nResult<int> result = ...;\nif (result is Value(var v)) {...}  // error: not a union\n\n```\n\nWithout completely redesigning the type and impacting all the current users, the type can be brought forward by implementing union interfaces explicitly.\n\n```csharp\npublic record Error(int code);\n\npublic struct Result<T> \n    : IUnion,\n      IUnionCreate<Result<T>, T>,\n      IUnionCreate<Result<T>, Error>,\n      IUnionGetValue<T>,\n      IUnionGetValue<Error>\n{\n    public bool IsValue => ...;\n    public bool IsError => ...;\n    public T Value => ...;\n    public Error Error => ...;\n    public static Result<T> FromValue(T value) {...}\n    public static Result<T> FromError(Error error) {...}\n\n    // incompatible with existing API\n    object? IUnion.Value => \n        IsValue ? this.Value \n        : IsError ? this.Error\n        : null;\n\n    // custom union pattern to avoid boxing \n    // would be confusing terminology given existing API\n    bool IUnionCreate<Result<T>, Value<T>>.Create(T value) => FromValue(value);\n    bool IUnionCreate<Result<T>, Error>.Create(Error value) => FromError(value);\n    bool IUnionHasValue.HasValue => IsValue || IsError;\n    bool IUnionTryGetValue<Value<T>>.TryGetValue([NotNullWhen(true)] out T value) => ...;\n    bool IUnionTryGetValue<Error>.TryGetValue([NotNullWhen(true)] out Error error) => ...;\n}\n\n...\nResult<int> result = ...;\nif (result is Value(var v)) {...}  // works!\n\n```\n\n### Motivation\n\nMany existing first and third party types already exist that are unions, but do not today conform to the patterns the compiler is looking for to identify and interact with them correctly.  It is already possible to create custom union types that implement the `IUnion` and `IUnion<T>` interfaces without exposing the interface methods on the union itself. The compiler can easily identify these types as union and call through to the interface methods directly (using constrained calls) to guarantee \n\n### Detailed Design\n\n```csharp\npublic interface IUnionCreate<TUnion, TCase> \n    where TUnion : IUnionCreate<TUnion, TCase>\n{\n    static abstract TUnion Create(TCase value);\n}\n\npublic interface IUnionHasValue\n{\n    bool HasValue { get; }\n}\n\npublic interface IUnionTryGetValue<TCase> : IUnionHasValue\n{\n    bool TryGetValue([NotNullWhen(true)] out TCase value);\n}\n```\n\n* The compiler will target the IUnionCreate's Create methods if available, when an appropriate accessible constructor is not. The compiler will also use the IUnionCreate implementations to identify the set of case types.\n* The compiler will translate null pattern tests to the IUnionHasValue.HasValue property.\n* The compiler will translate type pattern matches to the IUnionTryGetValue.TryGetValue method if available and applicable, instead of accessing via IUnion.Value property.\n* Note: it is not required to implement these interfaces if the union type's public API contains the equivalent signatures.\n\n\n### Known Issues\n\n* Multiple implementations of generic interfaces with type parameter arguments produce an error today. However, this kind of usage will not become more ambiguous than the type would already be if instantiated with multiple uses of the same type argument.\n\n    ```csharp\n    public struct FatUnion<T1, T2>\n    : IUnion,\n      IUnionTryGetValue<T1>,  // error, may become ambiguous at runtime\n      IUnionTryGetValue<T2>\n    {\n        private readonly int _kind;\n        private readonly T1 _value1;\n        private readonly T2 _value2;\n\n        public FatUnion(T1 value) { _kind = 1; _value1 = value; }\n        public FatUnion(T1 value) { _kind = 2; _value2 = value; }\n\n        bool IUnionHasValue.HasValue => _kind != 0;\n        bool IUnionTryGetValue<T1>.TryGetValue(out T1 value) {...}\n        bool IUnionTryGetValue<T2>.TryGetValue(out T2 value) {...}\n    }\n    ```\n### Alternatives\n\nInstead of requiring union types to implement multiple variations of the same generic interface,\na family of similar interfaces could exist for each arity of cases.\n\n```csharp\npublic interface IUnionCreate<TUnion, T1, T2>\n    where TUnion : IUnionCreate<TUnion, T1, T2>\n{\n    static abstract TUnion Create(T1 value);\n    static abstract TUnion Create(T2 value);\n}\n\npublic interface IUnionCreate<TUnion, T1, T2, T3>\n    where TUnion : IUnionCreate<TUnion, T1, T2, T3>\n{\n    static abstract TUnion Create(T1 value);\n    static abstract TUnion Create(T2 value);\n    static abstract TUnion Create(T3 value);\n}\n\npublic interface IUnionTryGetValue<T1, T2> : IUnionHasValue\n{\n    bool TryGetValue([NotNullWhen(true)] out T1 value);\n    bool TryGetValue([NotNullWhen(true)] out T2 value);\n}\n\npublic interface IUnionTryGetValue<T1, T2, T3> : IUnionHasValue\n{\n    bool TryGetValue([NotNullWhen(true)] out T1 value);\n    bool TryGetValue([NotNullWhen(true)] out T2 value);\n    bool TryGetValue([NotNullWhen(true)] out T3 value);\n}\n```\n\n* How many of these would be defined? What happens to custom unions that have a large number of cases?\n\n\n"
  },
  {
    "path": "meetings/working-groups/discriminated-unions/to-nest-or-not-to-nest.md",
    "content": "# Case types: To nest or not to nest?\n\nBoth [closed hierarchies](https://github.com/dotnet/csharplang/blob/main/proposals/closed-hierarchies.md) and [nominal type unions](https://github.com/dotnet/csharplang/blob/main/proposals/nominal-type-unions.md) allow the declaration of \"case types\" (derived types of closed classes or listed case types of unions) to be either nested or not - both approaches are perfectly valid for a programmer to choose.\n\nWith the [case declarations](https://github.com/dotnet/csharplang/blob/main/proposals/case-declarations.md) proposal in its current form we are implicitly encouraging a style where case types are nested within their closed class or union type. This is further supported by the [Target-typed static member access](https://github.com/dotnet/csharplang/blob/main/proposals/target-typed-static-member-lookup.md) proposal, which eliminates the drudgery of fishing such nested members out again, at least when a target type is present.\n\nBut is nesting case types the right thing to do - or at least to encourage? Is the answer different for closed hierarchies vs union types? Should we use nesting ourselves if we define e.g. `Option` and `Result` types in our libraries?\n\nLet's compare nested and non-nested approaches on different parameters. \n\n## Running example: Option types\n\n`Option<T>` is a canonical example of a \"union type\" representing that there may or may not be a value of type `T`. We can define `Option<T>` either as a closed class or a union, and with either nested or top-level case types:\n\n```csharp\n// Closed hierarchy, non-nested case types\npublic closed record Option<T>;\npublic record None<T>() : Option<T>;\npublic record Some<T>(T value) : Option<T>;\n\n// Closed hierarchy, nested case types\npublic closed record Option<T>\n{\n    public record None() : Option<T>;\n    public record Some(T value) : Option<T>;\n}\n\n// Union, non-nested case types\npublic record None();\npublic record Some<T>(T value);\npublic union Option<T>(None, Some<T>);\n\n// Union, nested case types\npublic union Option<T>(Option<T>.None, Option<T>.Some)\n{\n    public record None();\n    public record Some(T Value);\n}\n```\n\nWe'll refer back to these declarations in nearly every section below.\n\n## Existing types\n\nFor closed classes, the \"case types\" - the derived classes - are always declared in context of their base class. There are no \"existing case types\". You are always free to choose whether to nest them in the closed base class or declare them at the top level next to it.\n\nUnions, on the other hand, are designed to allow existing types as case types. This means that case types may be declared independently elsewhere, unaware that anyone is using them as a case type in a union:\n\n```csharp\npublic union Pet(Cat, Dog); // 'Cat' and 'Dog' are existing types\n```\n\nIn those situations, you don't have the option of nesting the case types in the union type. Anything we do in the language to improve the nested-case-types experience won't help existing-types scenarios.\n\n## Analogy with enums \n\nUnions/closed classes are somewhat analogous to enums, in that there's a list of possible contents. For enums that list is nested:\n\n```csharp\npublic enum Color\n{\n    Red,\n    Green, \n    Blue,\n}\n```\n\nThe analogy only goes so far: Enums list *values*, unions list *types*. And enums aren't actually listing *all* possible values, as by default they are not exhaustive (although [Closed Enums](https://github.com/dotnet/csharplang/blob/main/meetings/working-groups/discriminated-unions/Closed%20Enums.md) aim to help with that).\n\nThat said, leaning into a syntactic analogy with enums through nesting of case types may help developers better connect with the new concepts of closed hierarchies and unions.\n\n## Pollution of declaration space\n\nWhen nested, case types won't \"pollute\" the enclosing declaration space. This argument definitely has merit for enums, where \"cases\" are often many, and their naming is often somewhat contextual to the enclosing enum type.\n\nIt is not clear that this argument applies to the same degree to closed hierarchies and unions. Perhaps they will tend to have fewer cases with more self-explanatory names? \n\nIf we look to other languages, case types generally are *not* nested. F# for example puts the case names into the enclosing scope: You can (and do) directly use e.g. the `Some` name to create or match an `Option` value without any target typing. In TypeScript there is also no notion of nesting case types in union types. Both seem to do fine - insofar as we're looking to address similar scenarios with unions in C#, it seems unlikely that we would have different needs.\n\nIn general, in C# it is fairly rare for types to be nested in other types if their primary use is intended to be outside of those types. Is there reason to believe that this would be different for unions?\n\n## Avoiding explicit type parameters\n\nNested types implicitly have the same type parameters - if any - as the enclosing type. There's no need to repeat them. Looking at the nested `Option<T>` declarations above, the case types don't need explicit type parameters.\n\nBy contrast, top-level case types do need to explicitly take the type parameters they need and either pass them to a closed base class or instantiate them in a union case type list.\n\n## Avoiding repetition in the declaration\n\nThe [case declarations](https://github.com/dotnet/csharplang/blob/main/proposals/case-declarations.md) feature provides a much abbreviated way of declaring nested case types for both closed classes and unions:\n\n```csharp\n// Case declarations in a closed hierarchy\npublic closed class Option<T>\n{\n    case None();\n    case Some(T Value);\n}\n\n// Case declarations in a union\npublic union Option<T>\n{\n    case None();\n    case Some(T Value);\n}\n```\n\nCompared to the nested `Option<T>` declarations above, it uses the context of the outer declaration to fill in missing information that links the cases to the \"union\" type: For the closed class it fills in the base class of each of the case types, whereas for the union it fills in the list of case types. In both it avoids one explicit mention of `Option<T>` for each case type.\n\nWould it be possible to have similar abbreviations for top-level case types?\n\nFor closed hierarchies it is hard to see how. The \"linking information\" between derived and closed type is in the derived class, in the form of a base class specification. If you're not nested in the intended base class, how do you imply what *should* be the base class, short of saying it explicitly?\n\nFor unions, however, the \"linking\" information is in the union declaration itself, in the form of the case type list. It would be entirely possible to allow syntax in that list that causes the case types to be implicitly declared, e.g.:\n\n```csharp\npublic union Option<T>(case None(), case Some<T>(T Value));\n\n// or simply\n\npublic union Option<T>(None(), Some<T>(T Value));\n```\n\nWhere either the `case` keyword or the `(...)` parameter list itself is the syntactic signal that the case type doesn't refer to an existing type, but should be declared as a record of the given name.\n\nSuch a scheme may be great for simple situations like this, but may become unwieldy if you want to e.g. specify explicit bodies on the case types. It is possible that we can come up with better syntax.\n\n## Avoiding type arguments\n\nWhen referencing a case type from the \"outside\", you need to specify type arguments, regardless of whether it's nested or not. Which features could help with that?\n\nFirst a scenario without useful target types:\n\n```csharp\n// non-nested, no target type\nobject o = new Some<int>(5); \nif (o is Some<int>(var value)) ...;\n\n// nested, no target type\nobject o = new Option<int>.Some(5); \nif (o is Option<int>.Some(var value)) ...;\n```\n\nHere the only hope of doing a bit of type inference seems to be in the `new` expression. Long ago we discussed, but rejected, a [proposal](https://github.com/dotnet/roslyn/issues/2319) for allowing generic type inference in object creation expressions, similar to how it works in generic methods:\n\n```csharp\n// non-nested, no target type\nobject o = new Some(5); // '<int>' inferred from constructor argument\n\n// nested, no target type\nobject o = new Option.Some(5); // '<int>' inferred from constructor argument?\n```\n\nThe type inference for the non-nested example seems a straightforward application of existing type inference logic. For the nested case it gets more complicated; we'd essentially have to figure out how to allow type arguments for enclosing types to be inferred as well.\n\nTurning to scenarios with a potentially useful target type:\n\n```csharp\n// non-nested, target type\nOption<int> option = new Some<int>(5); \nif (option is Some<int>(var value)) ...;\n\n// nested, target type\nOption<int> option = new Option<int>.Some(5); \nif (option is Option<int>.Some(var value)) ...;\n```\n\nIn the nested case, [target-typed static member access](https://github.com/dotnet/csharplang/blob/main/proposals/target-typed-static-member-lookup.md) can abbreviate away not only the type argument but also the enclosing type:\n\n```csharp\n// nested\nOption<int> option = new .Some(5);   // 'Option<int>' inferred\nif (option is .Some(var value)) ...; // 'Option<int>' inferred\n```\n\nFor the non-nested case, there are now proposals to:\n\n- Allow target types to be taken into account in generic type inference: [Target-typed generic type inference](https://github.com/dotnet/csharplang/blob/main/proposals/target-typed-generic-type-inference.md).\n- Allow generic type inference in `new` expressions: [Inference for constructor calls](https://github.com/dotnet/csharplang/blob/main/proposals/inference-for-constructor-calls.md).\n- Allow generic type inference in type patterns, treating the incoming type (`Option<int>` in this case) as the \"target type\": [Inference for type patterns](https://github.com/dotnet/csharplang/blob/main/proposals/inference-for-type-patterns.md).\n\nBetween them, they would enable:\n\n```csharp\n// non-nested\nOption<int> option = new Some(5);   // '<int>' inferred\nif (option is Some(var value)) ...; // '<int>' inferred\n```\n\nIn summary, various auxiliary features have been proposed that would help avoid specifying type arguments when consuming the case types of closed classes or unions, both in nested and non-nested scenarios.\n\n### Too many type parameters\n\nWhen it comes to type parameters, there's a fundamental and significant difference in expressiveness between closed hierarchies and type unions. Looking back at the top-level versions of declarations in the running `Option<T>` example, the closed hierarchy version of `None` needs a type parameter of its own, whereas the union version does not:\n\n```csharp\npublic record None<T> : Option<T>(); // closed hierarchy\npublic record None();                // union\n```\n\nThe closed hierarchy `None<T>` has to be generic, even though it doesn't use `T` for anything! That's because the relationship between `None` and `Option` is expressed through inheritance,  the derived class needs to pass *some* `T` to its base class, and there is no other good option (no pun intended). As a result, each generic instantiation of `Option<T>` has its own `None` type. In a sense, every type parameter of the closed base class is forced upon all case types.\n\nBy contrast, in the union version, all generic instantiations of `Option<T>` share the same `None` type:\n\n```csharp\nvar none = new None();\nOption<string> stringOption = none; // Fine\nOption<int> intOption = none; // Also fine\n```\n\nThe upshot is that a generic union type, unlike a closed generic class, is free to have non-generic (or less-generic) case types that are shared between multiple generic instantiations of the union type.\n\nNesting changes this, however: Nested types in general are *also* forced to \"inherit\" all type parameters of the enclosing type - it happens implicitly in the language. So union types with nested case types are in the same situation as (nested or non-nested) closed hierarchies: They cannot have non-generic or less-generic case types. In the running example, there is no sharing of `None` values:\n\n```csharp\nvar none = new Option<int>.None();  // Why do I need to specify `T` when `None` doesn't use it?\nOption<string> stringOption = none; // Error: 'Option<int>.None' cannot be assigned to 'Option<string>.None'\n```\n\nThis loss of expressiveness for nested union types may not be that big of a problem for our `Option<T>` example: `None` values carry no data, so people probably won't be too upset that they can't reuse `None` values across different content types. But that changes if we look at another common union example, the `Result` type. Let's try a nested version first:\n\n```csharp\npublic union Result<TValue, TError>(Result<TValue, TError>.Success, Result<TValue, TError>.Failure)\n{\n    public record Success(TValue Value);\n    public record Failure(TError Error);\n}\n```\n\nResult types are often brought up in connection with \"pipelining\" architectures; where a function in a pipeline may look like this:\n\n```csharp\n// Produce a string from an incoming int, or propagate a failure\nResult<string, string> M<T>(Result<int, string> result)\n{\n    if (result is Result<TValue, TError>.Failure failure) return failure; // Error\n    ...\n}\n```\n\nEven though the incoming and outgoing `Result` both have `TError = string`, a `Failure` value cannot just be passed through because it embeds an implicit `TValue` type argument that doesn't match! Not being able to propagate a `Failure` directly without deconstructing and reconstructing at every step seems unreasonably cumbersome.\n\n(Of course the same issue applies the other way around: You cannot propagate a `Success` through a function that changes only the `TError` type).\n\nBy contrast, with top-level case type declarations:\n\n```csharp\npublic record Success<TValue>(TValue Value);\npublic record Failure<TError>(TError Error);\npublic union Result<TValue, TError>(Success<TValue>, Failure<TError>);\n\nResult<string, string> M<T>(Result<int, string> result)\n{\n    if (result is Failure<string> failure) return failure; // Fine! Both have 'Failure<string>' as a case.\n}\n```\n\nNon-nested failures don't have to lug around which kind of value they would have had if they'd succeeded, and non-nested successes don't have to be distinguished by what kind of error they would have had if they had failed.\n\nIn summary, if case types need only some of the type parameters of their union, nesting them adds significant generic complexity for consuming code.\n\n## Summary\n\n- *Existing types*: Not all case types *can* be nested in a closed class or union type. For that reason alone it's important to consider features that improve the experience with non-nested case types.\n- *Enum analogy*: Some union scenarios are probably closer to enum scenarios than others. Where applicable, the enum analogy can probably help users embrace closed classes and unions.\n- *Declaration space pollution*: Enums use nesting to protect the wider code from being \"polluted\" by all the enum value names. On the other hand, union features in e.g. F# and TypeScript do fine without such nesting.\n- *Repetition in declarations*: \"Case declarations\" propose a shorthand for declaring nested case types. Features could probably also be designed to abbreviate non-nested case types.\n- *Avoiding type arguments*: \"Target-typed static member access\" sidesteps having to provide type arguments *when* there's a target type *and* the case type declaration is nested. For other scenarios we can imagine various extensions to generic type inference.\n- *Too many type parameters*: Closed classes as well as nesting of case types force case types to have as many type parameters as the base type or union, even when they don't need them. Only unions with top-level case types escape this problem.\n\n## Questions\n\nThis write-up is not in and of itself a proposal. But it brings up questions the answers to which can help guide which future concrete proposals to consider, and how to think about them:\n\n- As we add convenience features to the language and concrete union types to the core libraries, should we adopt a bias for or against nesting of case types? Is one more important to support and encourage than the other?\n- As we start thinking about guidance around these new features, can we identify scenarios that lend themselves more to nested or to non-nested approaches?"
  },
  {
    "path": "meetings/working-groups/discriminated-unions/type-value-conversion.md",
    "content": "# Type Value Conversion\n\n## Summary\n\nA type expression specified in a value context can be converted to a value if the type supports a conversion to value.\n\n```csharp\nGateState value = GateState.Locked;\n```\n\n## Motivation\n\nA nominal type union can declare cases that contain no corresponding values. Unions that are similar to enums will often have many of these no-value cases.\n\n```csharp\npublic union GateState\n{\n    case Locked;\n    case Closed;\n    case Open(float amount);\n}\n```\n\nEven though only a few of the cases contain data, all cases are separate types. In this example, the types declared when using case declarations are records. \n\nHowever unfortunate, a case without data must still be allocated.\n\n```csharp\nGateState state = new GateState.Locked()\n```\n\nIt would be preferable if all uses of these non-value cases could share a single instance and avoid repeated allocation. A typical way of achieving this is to declare a static field or property on the type, using that member to access the same instance each time.\n\n```csharp\nrecord Locked { public static readonly Locked Instance = new Locked(); }\n```\n\nA case declaration could add this member implicitly, but a user would still need to refer to it explicitly. This may be unexpected at first and tedious always.\n\n```csharp\nGateState value = GateState.Locked.Instance;\n```\n\nIf the type expression could be converted directly to a value, then code is clearer because it is always just referring to the case, and not an implementation artifact.\n\n```csharp\nGateState value = GateState.Locked;\n```\n\n* *Note: It is not possible to have a nested type and a property of the same name in the same declaration scope.*\n\n### Other Uses\n\nSingleton classes are quite common in the wild and would benefit from a type to value conversion.\n\nFor example, most custom equality comparers take no outside arguments and rarely ever require more than one instance to exist.\n\n```csharp\npublic class MyEqualityComparer : IEqualityComparer<MyType>\n{\n    public bool Equals(MyType a, MyType b) => ...;\n    public int GetHashCode(MyType a) => ...;\n\n    public static readonly MyEqualityComparer Instance = new MyEqualityComparer();\n}\n```\n\n## Detailed Design\n\nThe type expression to value conversion is declared via a conversion operator on the type.\n\n```csharp\npublic record Locked\n{\n    public static readonly Locked Instance = new Locked();\n    public static implicit operator this => Instance;\n}\n```\n\n* The `this` operator converts a type expression to a value of that same type.\n* The author declaring a conversion operator expresses clear intent for the conversion to exist.\n\n## Alternative Designs\n\n### Conversion by Pattern\n\nA conversion exists between a type expression and a value when the type contains a static field or property with a recognized name that returns a value of the type's type.\n\n```csharp\npublic record Locked\n{\n    public static readonly Locked Instance = new Locked();\n}\n```\n\n* The pattern looks for a specific member name like `Instance`.\n\n### Conversion by Attribute\n\nA conversion exists between a type expression and a value when the type contains a static field or property decorated with the `Singleton` attribute.\n\n```csharp\npublic record Locked\n{\n    [Singleton]\n    public static readonly Locked Value = new Locked();\n}\n```\n\n* This alternative allows existing types with fields/properties returning singleton or default values to support this conversion even if the member does not have the pattern recognized name.\n\n### Conversion by Interface\n\nA conversion exists between a type expression and a value when the type implements an interface with a known static property.\n\n```csharp\npublic interface ISingleton<TSelf>\n    where TSelf : ISingleton<TSelf>\n{\n    TSelf Singleton { get; }\n}\n```\n\n```csharp\npublic record Locked : ISingleton<Locked>\n{\n    public static readonly Locked Instance = new Locked();\n    static Locked ISingleton<Locked>.Singleton => _instance;\n}\n```\n\n* The compiler uses the property from the interface.\n"
  },
  {
    "path": "meetings/working-groups/discriminated-unions/union-patterns-update.md",
    "content": "# Union patterns update\n\nUnion patterns matter for \"custom unions\", i.e., union types that are \"handwritten\" to get the language's [union behaviors](https://github.com/dotnet/csharplang/blob/main/proposals/unions.md#union-behaviors), rather than generated from [union declarations](https://github.com/dotnet/csharplang/blob/main/proposals/unions.md#union-declarations). \n\nWe anticipate custom unions to include existing \"union-like\" types that are augmented to be recognized as unions by the language, as well as new types for which different characteristics (e.g. in terms of storage or performance) are desired compared to what's generated from union declarations. We expect both kinds to be rare in comparison to use of union declarations, and for most users never having to declare custom union types.\n\nWe propose a few changes to the current patterns in order to better serve more scenarios:\n\n- Union types are marked with a `[Union]` attribute instead of the `IUnion` interface.\n- Union members are either found on the union type itself or delegated to an interface that the union type implements.\n\n\nIn addition there are some potential scenarios that we don't currently have proposals for, but that might come up later. We list those at the end.\n\n## Marking union types with an attribute\n\nThe current pattern of marking union types with the `IUnion` interface leads to a couple of problems, e.g.:\n\n- A type cannot implement the `IUnion` interface *without* being a union.\n- If a base class is a union then derived classes must also be unions.\n\nWe propose to use a `[Union]` attribute to mark types that are intended to have union behaviors:\n\n```csharp\n[Union] public record struct Pet\n{\n    public Pet(Dog value) => Value = value;\n    public Pet(Cat value) => Value = value;\n    public Pet(Bird? value) => Value = value;\n\n    public object? Value { get; }\n}\n```\n\nAs part of this change, the `Value` property used by the compiler is no longer `IUnion.Value`, but just the property found on the type. Union patterns no longer rely on specific interfaces or interface members.\n\nWe don't anticipate allowing `[Union]` on type parameters, which therefore cannot be considered union types by the compiler.\n\n## Union member providers\n\nThe current pattern looks for members on the union type itself. This has a few downsides:\n\n- Existing types may have members that would unintentionally be recognized as union members (e.g. copy constructor).\n- Such members may even clash in such a way that you couldn't have both, even if you had an attribute to distinguish them (e.g. `Value` property).\n- Types may not wish to expose additional union members as part of their public surface area.\n\nWe propose to allow a union type to optionally delegate all union members to a nested `IUnionMembers` interface that the union type implements. Since constructors for a type cannot occur on another type, the interface would instead use static factory methods called `Create`:\n\n```csharp\n[Union] public record struct Pet : Pet.IUnionMembers\n{\n    object? _value;\n\n    Pet(object? value) => _value = value;\n    \n    // Look for union members here, not in 'Pet' itself\n    public interface IUnionMembers\n    {\n        static Pet Create(Dog value) => new(value);\n        static Pet Create(Cat value) => new(value);\n        static Pet Create(Bird? value) => new(value);\n\n        object? Value { get; }\n    }\n\n    object? IUnionMembers.Value => _value;\n}\n```\n\nThe compiler can use constrained calls where applicable to avoid the overhead of interface invocation.\n\n### Alternatives\n\nInstead of delegating to another type, it has been proposed to mark union members in the union type itself with attributes. This could allow marking members with different names, or different kinds of members (e.g. factory methods or user-defined implicit conversions) so as to make use of any suitable members the type already has.\n\nOne downside is that attributes can never be used to hide members from the surface area. Thus it is strictly less expressive than delegation. In addition, the set of attributes and the rules for their usage might get quite complicated. By comparison, the delegation approach puts all union members in one place with well-defined, unambiguous names and signatures.\n\n## Other scenarios\n\nWe can imagine reasonable scenarios that are not expressible by the above changes. While we are not proposing solutions for those now, it is useful to imagine possible ways to address them in the future, if only to reassure ourselves that we are not accidentally blocking them by choices we make now.\n\n### \"Consume-only\" unions\n\nNot all union types may want to offer the ability for their users to create union values directly; perhaps instead they offer APIs that create them internally and hand them out.\n\nSuch unions wouldn't have creation members (constructors or factories), so they need another way of specifying their case types. We don't yet have specific proposals.\n\n### More specific shared base types\n\nIn some union types, case types share a more specific base type than `object?`. We could probably allow the `Value` property to expose such a more specific type, and have the compiler take advantage of the additional knowledge (e.g. non-nullability) in its implementation of union behaviors.\n\n### Non-object case types\n\nThe requirement for an `object`-returning `Value` property that gives access to the union's value no matter the case type, means that all case types have to be implicitly convertible to object.\n\nThat rules out e.g. ref structs and pointer types as case types of compiler-recognized unions.\n\nThere may be ways in which we can amend this, either by removing the requirement for a `Value` property to exist, or allowing certain case types not to be accessed through it. We don't yet have specific proposals.\n\n### Non-boxing access pattern\n\nThe original proposal includes an optional non-boxing access pattern, and this proposal preserves that. Additional `HasValue` and `TryGetValue` members can be used by the compiler as strongly typed alternatives to matching through the weakly typed `Value` property. This can be used for efficiency purposes, e.g. when a union type stores value types directly instead of boxing them.\n\nThe current non-boxing access pattern is definitely worth revisiting before we lock it in, but we don't yet have specific alternate proposals."
  },
  {
    "path": "meetings/working-groups/discriminated-unions/union-proposals-overview.md",
    "content": "# Union proposals overview\n\n**Umbrella issue**: https://github.com/dotnet/csharplang/issues/9662\n\n- [Union proposals overview](#union-proposals-overview)\n  - [Unions](#unions)\n  - [Standard type unions](#standard-type-unions)\n  - [Closed enums](#closed-enums)\n  - [Closed hierarchies](#closed-hierarchies)\n  - [Case declarations](#case-declarations)\n  - [Target-typed static member access](#target-typed-static-member-access)\n  - [Target-typed generic type inference](#target-typed-generic-type-inference)\n  - [Inference for constructor calls](#inference-for-constructor-calls)\n  - [Inference for type patterns](#inference-for-type-patterns)\n  - [Type value conversion](#type-value-conversion)\n\n``` mermaid\nflowchart LR\n\n%% Features\nUnions[Unions]:::approved\nStandard[Standard type unions]:::approved\nEnums[Closed enums]:::approved\nHierarchies[Closed hierarchies]:::approved\nCases[Case declarations]:::approved\nTargetAccess[Target-typed access]:::approved\nTargetInfer[Target-typed inference]:::approved\nInferNew[Inference for constructors]:::approved\nInferPattern[Inference for type patterns]:::consideration\nTypeValue[Type value conversion]:::consideration\n\n%% Dependencies\nUnions --> Standard\nUnions & Hierarchies --> Cases -.-> TargetAccess\nHierarchies <-.-> Enums\nTargetInfer --> InferNew & InferPattern\n\n%% Colors\nclassDef approved fill:#cfc,stroke:#333,stroke-width:1.5px;\nclassDef consideration fill:#ffd,stroke:#333,stroke-width:1.5px;\nclassDef unapproved fill:#ddd,stroke:#333,stroke-width:1.5px;\nclassDef rejected fill:#fdd,stroke:#333,stroke-width:1.5px;\n```\n\n## Unions\n\n- **Proposal**: [Unions](https://github.com/dotnet/csharplang/blob/main/proposals/unions.md)\n- **LDM**: Approved. \n- **Dependencies**: None.\n\nA set of interlinked features that combine to provide C# support for union types, including a declaration syntax and several useful behaviors.\n\n```csharp\npublic union Pet(Cat, Dog); // Declaration syntax\n\nPet pet = dog;              // Implicit conversion\n\n_ = pet switch\n{\n    Cat cat => ...,         // Implicit matching\n    Dog dog => ...,\n}                           // Exhaustive switching\n```\n\n## Standard type unions\n\n- **Proposal**: [Standard type unions](https://github.com/dotnet/csharplang/blob/main/proposals/standard-unions.md)\n- **LDM**: Approved. \n- **Dependencies**: [Nominal type unions](#nominal-type-unions). \n\nA family of nominal type unions in the `System` namespace:\n\n```csharp\npublic union Union<T1, T2>(T1, T2);\npublic union Union<T1, T2, T3>(T1, T2, T3);\npublic union Union<T1, T2, T3, T4>(T1, T2, T3, T4);\n...\n```\n\n## Closed enums\n\n- **Proposal**: [Closed enums](https://github.com/dotnet/csharplang/blob/main/proposals/closed-enums.md)\n- **LDM**: Approved. \n- **Dependencies**: None. Design together with [Closed hierarchies](#closed-hierarchies) to ensure coherence.\n\nAllow enums to be declared `closed`, preventing creation of values other than the explicitly declared enum members. A consuming switch expression can assume only those values can occur, avoiding exhaustiveness warnings.\n\n```csharp\npublic closed enum Color { Red, Green, Blue }\n\nvar infrared = Color.Red - 1; // Error, not a declared member\n\n_ = color switch\n{\n    Red => \"red\",\n    Green => \"green\",\n    Blue => \"blue\"\n    // No warning about missing cases\n};\n```\n\n## Closed hierarchies\n\n- **Proposal**: [Closed hierarchies](https://github.com/dotnet/csharplang/blob/main/proposals/closed-hierarchies.md)\n- **LDM**: Approved. \n- **Dependencies**: None. Design with [Closed enums](#closed-enums) to ensure coherence.\n\nAllow classes to be declared `closed`, preventing its use as a base class outside of the assembly. A consuming switch expression can assume only derived types from within that assembly can occur, avoiding exhaustiveness warnings.\n\n```csharp\n// Assembly 1\npublic closed class C { ... } \npublic class D : C { ... }     // Ok, same assembly\n\n// Assembly 2\npublic class E : C { ... }     // Error, 'C' is closed and in a different assembly\n\n_ = c switch\n{\n    D d => ...,\n    // No warning about missing cases\n}\n```\n\n## Case declarations\n\n- **Proposal**: [Case declarations](https://github.com/dotnet/csharplang/blob/main/proposals/case-declarations.md)\n- **LDM**: Approved. \n- **Dependencies**:  [Closed hierarchies](#closed-hierarchies) and [Nominal type unions](#nominal-type-unions).\n\nA shorthand for declaring nested case types of a closed type (closed class or union type).\n\n```csharp\npublic closed record GateState\n{\n    case Closed;\n    case Locked;\n    case Open(float Percent);\n}\n\npublic union Pet\n{\n    case Cat(...);\n    case Dog(...);\n}\n```\n\n## Target-typed static member access\n\n- **Proposal**: [Target-typed static member access](https://github.com/dotnet/csharplang/blob/main/proposals/target-typed-static-member-access.md)\n- **LDM**: Approved. \n- **Dependencies**: None. Informed by union scenarios.\n\nEnables a type name to be omitted from static member access when it is the same as the target type.\n\n``` c#\nreturn result switch\n{\n    .Success(var val) => val,\n    .Error => defaultVal,\n};\n```\n\n## Target-typed generic type inference\n\n- **Proposal**: [Target-typed generic type inference](https://github.com/dotnet/csharplang/blob/main/proposals/target-typed-generic-type-inference.md)\n- **LDM**: Approved. \n- **Dependencies**: None. Informed by union scenarios.\n\nGeneric type inference may take a target type into account.\n\n```csharp\nMyCollection<string> c = MyCollection.Create(); // 'T' = 'string' inferred from target type\n```\n\n## Inference for constructor calls\n\n- **Proposal**: [Inference for constructor calls](https://github.com/dotnet/csharplang/blob/main/proposals/inference-for-constructor-calls.md)\n- **LDM**: Approved. \n- **Dependencies**: [Target-typed generic type inference](#target-typed-generic-type-inference)\n\n'new' expressions may infer type arguments for the newly created class or struct, including [from a target type](target-typed-generic-type-inference) if present.\n\n```csharp\nOption<int> option = new Some(5); // Infer 'int' from argument and target type\n```\n\n## Inference for type patterns\n\n- **Proposal**: [Inference for type patterns](https://github.com/dotnet/csharplang/blob/main/proposals/inference-for-type-patterns.md)\n- **LDM**: Needs more work. \n- **Dependencies**: [Target-typed generic type inference](#target-typed-generic-type-inference)\n\nType patterns may omit a type argument list when it can be inferred from the pattern input value.\n\n```csharp\nvoid M(Option<int> option) => option switch\n{\n    Some(var i) => ..., // 'Some<int>' inferred\n    ...\n};\n```\n\n## Type value conversion\n\n- **Proposal**:[Type value conversion](https://github.com/dotnet/csharplang/blob/12e6f5b0d512d15d32c8e7ae95674bd070b2758f/meetings/working-groups/discriminated-unions/type-value-conversion.md)\n- **LDM**: Needs more work.\n- **Dependencies**: None.\n\nA type expression specified in a value context can be converted to a value if the type supports a conversion to value.\n\n```csharp\nGateState value = GateState.Locked;\n```\n"
  },
  {
    "path": "meetings/working-groups/expressions-statements/ES-2022-11-30.md",
    "content": "# Bridging expressions and statements working group meeting - Nov 30, 2022\n\nOur agenda was to review proposal issues and make an initial decision on whether or not we wanted to pursue the feature in the short term. We organized the discussion around feature areas and scenarios.\n\n## Making things that are currently statements exist as expressions\n\n- [#973](https://github.com/dotnet/csharplang/issues/973) - **Declaration expressions**\n  This would enable syntax like `(var x = 1).ToString()`.\n  > Resolution: We felt this is not a feature we will work on in the near term.\n- [#1340](https://github.com/dotnet/csharplang/issues/1340) - **Rethrow expressions**\n  This would allow `throw` in expression contexts, where we currently allow `throw ex`.\n  > We will work on this in the near term.\n- [#867](https://github.com/dotnet/csharplang/issues/867) - **Allow `break`, `return`, `continue` in an expression context**\n  This would allow `break`, `return`, or `continue` where we allow `throw ex` expressions today.\n  > We think `throw` was a special case. We think `return` may be a similar special case. There are identified scenarios where `??` and `null` checks might immediately return from a method. We're less sure about `break` and `continue`. We need to see scenarios where those would be compelling. Those may not be added now.\n- **Allow any statement to appear as an expression**\n  There isn't an issue for this. We added it to the discussion as a logical extension. We don't see a compelling scenario for investing in this at this time.\n\n## Modernizing older syntax\n\nThese centered on the different structures of the `switch` statement and `switch` expression.\n\nThere are two alternative for bringing the `switch` expression and statement syntax closer together:\n\n- [#3038](https://github.com/dotnet/csharplang/issues/3038) - **Revamping switch statements to reflect switch expression syntax**\n  This would allow switch statements to use some of the syntax for switch expressions.\n- [#2632](https://github.com/dotnet/csharplang/issues/2632) - **Allow a switch expression as a statement expression**\n  This can be thought of as the inverse of #3038. It would allow a switch expression to be a *statement-expression* (or a void returning statement).\n\n> We're interested in pursuing this in the near term. We're not sure if these are mutually exclusive, or which would be more useful.\n\n## Allowing sequences of operations in place of a single expression\n\nThese are are very similar, each being a different syntax with potentially different things allowed inside the syntax, but they're all similar in concept.\n\n- [#377](https://github.com/dotnet/csharplang/issues/377) - This is most similar to let bindings in Lisp. Most restrictive of the proposals, it doesn't allow things like foreach\n- [#3086](https://github.com/dotnet/csharplang/issues/3086) - More general than #377, allows any statement before the final expression.\n- [#3037](https://github.com/dotnet/csharplang/issues/3037) - A more specific version of #3086, it only expands the syntax for switch expressions\n\n> Of these, the only one we're interested in pursuing in the near term is #3037\n\nOverall, of this set, we are interested in these three items:\n\n1. Allowing switch expressions to be statement expressions\n1. Coalescing switch expression and switch statement syntax\n1. Allowing multi-line arms in a switch expression.\n"
  },
  {
    "path": "meetings/working-groups/extensions/Compatibility through coexistence between extension types and extension methods.md",
    "content": "# Compatibility through coexistence between extension types and extension methods\n\nThis proposal approaches compatibility between classic extension methods and new extension types by emphasizing smooth coexistence and avoiding arbitrary behavior differences.\n\n* **Goal:** Bring _expressiveness_ of new extension methods close enough to that of old ones that new code won't need to use classic extension method syntax\n* **Goal:** Avoid arbitrary _behavior differences_ that may be jarring or surprising\n* **Goal:** Allow smooth _coexistence_ between new and old extension methods for the same underlying type\n* **Non-goal:** Allow all existing extension methods to be faithfully ported to the new paradigm\n* **Non-goal:** Allow reliance on details of lowered format for new extension members\n\nThe dual purpose of extension types is to allow other member kinds and also raise the level of abstraction. The two are linked: other member kinds are possible - and pleasant - because the declaration syntax is detached from the generated format. We should protect that by not exposing the lowered shape of declarations at the language level.\n\nThe basis of this proposal is the [extension proposal](https://github.com/dotnet/csharplang/blob/main/proposals/extensions.md) resulting from [separating extensions from roles](https://github.com/dotnet/csharplang/blob/1e8255a438517bc3ad067c726c28cfa20cb60f1e/meetings/working-groups/extensions/rename-to-roles-and-extensions.md) and [dropping their ability to act as instance types](https://github.com/dotnet/csharplang/blob/1e8255a438517bc3ad067c726c28cfa20cb60f1e/meetings/working-groups/extensions/extensions-as-static-types.md).\n\nWe'll address the three goals in turn. At the end is a brief summary of the features proposed throughout.\n\n## Expressiveness\n\nIn classic extension methods, the fact that the receiver is expressed as a parameter enables a lot of variation in how it is specified, some of which is useful, much of which isn't.\n\nIn extension types, the receiver is specified as a shared underlying type for all the members. This proposal takes the viewpoint that where variations allowed by old extension methods are useful, the new syntax should enable them to be specified at the member level. This way they won't be split between multiple extension types.\n\nNot all the variations are worth carrying forward. In the following, some are kept, and some are discarded based on perceived prevalence and usefulness.\n\n### Attributes\n\nOnly about .7% of extension methods have attributes on the receiver, and an overwhelming fraction (95%) of those are nullability-related. However, the next section on nullability may add to that.\n\nWe could add a new attribute target `this`, so that such attributes can be placed on the member declaration:\n\n``` c#\n[this:NotNullWhen(false)] public bool IsNullOrEmpty() { ... }\n```\n\n### Nullability\n\nAbout 1.5% of extension methods have a nullable receiver type. Some fraction of those are nullable value types. Nullable reference types are useful in this position for extension methods like `IsNullOrEmpty` that are explicitly null-safe.\n\nThis feels like a useful scenario, and some core infrastructural extension methods rely on it. However, it is also quite rare and probably doesn't warrant dedicated language syntax. Instead, we can use attributes in conjunction with the `this` attribute target proposed above:\n\n``` c#\n[this:AllowNull][this:NotNullWhen(false)] public bool IsNullOrEmpty() { ... }\n```\n\nUsing attributes to refine the nullability profile of members is already quite common, and this doesn't seem out of place.\n\n### Ref and readonly\n\nExtension method receivers are usually value parameters, but if the receiver type is a value type they can also be declared as `ref`, `in` or `ref readonly` parameters. The latter was eventually allowed in C# so that value types can be mutated by extension methods as well as passed to them more efficiently.\n\nExtension types in their current design take a different approach: Reference type receivers are _always_ passed by value and value type receivers are _always_ passed by reference. (If the receiver type is an unconstrained type parameter, the decision is made at runtime!) This closely emulates the behavior of `this` inside instance member declarations, which extension members syntactically imitate, leading to the least surprising semantics of `this`.\n\nThe new design does not allow for passing the reference receivers by reference or value receivers by value. Classic extension methods do not allow reference types to be passed by reference either, so that is no loss of expressiveness. There hasn't been a user ask for this.\n\nPassing value receivers by value, however, is common in classic extension methods. It's what happens by default, and passing by reference wasn't even allowed in C# for several versions. Any extension method that doesn't actively need to mutate the receiver is likely to take its receiver by value, and only about 1% of extension methods in fact take the receiver by reference.\n\nThe main benefit of choosing to pass a value receiver by value is that it protects the original from being mutated. The proposal here is to instead satisfy that desire in a different way: Members of extension types for value types can be declared `readonly`, just as members of a struct can be declared `readonly`. \n\n``` c#\npublic extension TupleExtensions for (int x, int y)\n{\n    public readonly int Sum() => x + y; // `this` is readonly and cannot me mutated\n}\n```\n\nJust as in struct declarations, the extension type itself could be declared `readonly` as a shorthand for declaring `readonly` on all members.\n\nA `readonly` annotated member will have its receiver passed as `ref readonly`, which protects it from mutation. It differs semantically from pass-by-value only in subtle ways that aren't likely to be important in usage scenarios. However, unlike pass-by-value, it prevents mutation of `this`, avoiding undetected bugs where mutation is accidentally applied to a copy and changes are lost.\n\n### Disambiguation\n\nClassic extension methods allow disambiguation simply by calling them as a static method. Extension types do not allow this, because from a user perspective there *are* no static methods.\n\nWhen extensions were still intended to be usable as instance types, disambiguation could happen simply by casting the receiver to the extension type. This option is no longer open - or at least it would need special context-specific semantics.\n\nDisambiguation for certain static extension members such as methods and properties is likely to be simple: Just dot off the extension type instead of the underlying type:\n\n``` c#\nMyStringExtensions.Format(...); // Instead of string.Format(...)\n```\n\nFor instance members and e.g. operators it is still possible to disambiguate through other means, but they are not elegant, and the LDM has agreed that we should work towards a good disambiguation solution.\n\n### Grouping\n\nClassic extension methods can - and often do - co-inhabit the same static class even when they have different receiver types. Extension types do not offer the same possibility, since the receiver type is tied to the extension type.\n\nWhile this is a difference to get used to, it does not seem to be a limit to expressiveness. It may lead to more type declarations, but probably not excessively so. This proposal does not attempt to address it.\n\n## Behavior differences\n\n### Overload resolution and type inference\n\nThe current proposal for extension types does overload resolution in two stages: First, suitable extension types are found, inferring any type arguments to the extension type in the process. Then, type inference and overload resolution is performed on eligible candidate members in those extensions. This two-stage approach seems intuitively right: the first stage identifies the receivers, and once determined, the second stage works exactly the same as would an instance method call.\n\nHowever, this differs from how overload resolution and type inference work on classic extensions methods, where all type parameters are already on the method, and the receiver participates in one big round of type inference alongside other arguments to the underlying static method.\n\nMost behavioral differences currently stem from using a weaker inference approach in the first phase of extension type resolution. At minimum this should be replaced with full type inference. \n\nThis still leaves scenarios where, with classic extension methods, non-receiver arguments can impact type inference for type parameters that occur in the receiver type. However, those situations are likely to be exceedingly rare in practice.\n\nThere's a proposal for how to do the one-phase approach with extension types. Embracing that would allow overload resolution to mix old and new extension methods in the same candidate sets, something which we rely upon in the Coexistence section below. At the same time, with behavior differences to the more intuitive two-phase approach being so rare, it is unlikely to lead to user confusion.\n\n### Refness\n\nAs already mentioned, extension types pass the receiver using the same semantics - by-value, `ref` or `ref readonly` - as the `this` parameter in corresponding instance members. This is a deliberate behavior deviation from that of extension methods, intended to minimize behavioral differences from the instance members that extension members are syntactically imitating.\n\n## Coexistence\n\nThis proposal specifically does not attempt to preserve semantics from old to new syntax. This means that library authors concerned with compatibility may need to keep their classic extension methods around for a while, possibly forever. In recognition of this, we should strive to make coexistence of new and old extensions friction-free.\n\nThere are several points on the dial that a library author may aim for; possibly going through them from one to the next over time in a deprecation process. Staying at any one of these stages forever is a fully supported and encouraged choice, depending on the library author's priorities.\n\n1. *Keep old extension methods, add new extension members:* You should not ever need to write another classic extension method, and if you already have some, that should not hamper the ability to seamlessly add new ones in the new style. This should give library users full source and binary compatibility.\n\n2. *Migrate old extension methods, keep most back compat:* Most old extension methods should be able to migrate to new ones in ways that are fully source compatible - or very close to it - as long as they are used *as* extension methods. If the old static methods are kept *without* the `this` modifier and made to redirect to the new ones, then binary compatibility is achieved, and invocations *as* static methods stay source compatible as well. \n\n3. *Deprecate old extension methods:* The old static methods - formerly extension methods - could be deprecated. This would drive users to switch to new disambiguation syntax, while still maintaining binary compatibility.\n\n4. *Remove old extension methods:* This would force recompilation of code that was compiled against the old extension methods.\n\nLet's look at what it takes to allow this.\n\n### Precedence\n\nIf either kind of extension method - old or new - is given precedence in overload resolution then it would allow old and new versions of the same extension method to coexist without giving rise to ambiguity. However, this could lead to surprising results where less suitable members of the preferred kind are chosen.\n\nAllowing two simultaneous versions of the same extension method is not a goal. While it could ensure slightly higher source compatibility in rare cases, the interactions are confusing, and there's a risk of the two versions drifting apart.\n\nThe proposal here is to have new and old extension methods share the same precedence. For that to work, we need to use the one-phase type inference and overload resolution approach described earlier.\n\n### Type names\n\nStatic classes with extension methods often already have the \"good\" names. It would be great if new non-generic extension types could optionally use the same type name. The easiest way is for the two to just *be* the same type. There are some different ways you could imagine allowing this in syntax; the simplest and most readable would probably be to allow both to be declared, and then implicitly merge them as if they were declared `partial`.\n\n## Summary of proposed decisions\n\n1. New `this:` target for attributes\n2. Nullable reference receivers expressed with `[this:AllowNull]` attribute\n3. Allow `readonly` modifier on extension members and extension types with a value-type underlying type\n4. Disambiguation mechanism still to be designed\n5. Use one-phase approach to type inference and overload resolution of extension type members\n6. Share overload resolution precedence between old and new extension methods\n7. Allow non-generic top-level extension type and static class of the same name to implicitly merge\n"
  },
  {
    "path": "meetings/working-groups/extensions/Extension-API-docs.md",
    "content": "# Extensions and API reference\n\nExtensions introduce new requirements for our API reference pipeline. The addition of new extension member types, and the representation of extension containers require changes to the pipeline for a good customer experience:\n\n- The docs term is \"Extension Methods\". That term currently means \"extension methods with an instance receiver\". Now, extensions can be properties, indexers, or operators. These extension members can be accessed as either an instance member on the extended type, or as a static member on the extended type.\n- Readers need to know if the receiver is an instance of a type, or the type itself.\n- Readers occasionally need to know the class name of holding the extension, typically for disambiguation.\n- The extension block is emitted as a nested class with skeleton members and XML doc comments. The nested class is given an unspeakable name.\n\nThe new extensions experience should be built on the framework used for the existing extension methods. In fact, when a new extension member is a method whose receiver is an instance, both forms are binary compatible. The document describes the new experience as a set of enhancements to the existing extension method documentation.\n\n## Existing Extension methods\n\nThe prototype for an extension method communicates many of the key concepts that consumers need to use these methods in their application. Consider this prototype:\n\n```csharp\npublic static class SomeExtensionsAndStuff\n{\n    public static bool IsEmpty<T>(this IEnumerable<T> source) => source.Any() == false;\n}\n```\n\nThe prototype and the class declaration communicate important information to readers.\n\n- The first parameter, noted with the `this` modifier indicates two important keys:\n  - The method is an extension method.\n  - The receiver is an instance of an `IEnumerable<T>`.\n- The class name `SomeExtensionsAndStuff` indicates how it can be called as a static method, if multiple extension methods have signatures that create an ambiguity.\n\nFor example, users can call extension methods in two ways:\n\n- As though it were an instance of a receiver:\n  ```csharp\n  bool empty = sequence.IsEmpty();\n  ```\n- As a static method call using the declaring type as the receiver:\n  ```csharp\n  bool empty = SomeExtensionsAndStuff.IsEmpty(sequence);\n  ```\n\nThe presentation and navigation elements used for the docs site help users find these methods and recognize that these methods are *extension methods*. For the following notes the links are to the docs for `System.Linq.Enumerable` and the extensions on `System.Collections.Generic.IEnumerable<T>` as they exist today:\n\n- The Table of Contents (TOC) nodes for the extended type, such as [`IEnumerable<T>`](https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1), list only the members defined on the interface. In other words, none of the extension methods are listed in the TOC (left navigation pane) under the extended type.\n- The API docs build system generates a section on the type page for the extended type, such as `IEnumerable<T>`, that lists all [extension methods](https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1#extension-methods). This section uses the following format:\n  - The prototypes show the `this` modifier, indicating that they are extension methods.\n  - Each overload has a separate entry in the section.\n  - The signatures indicate if the method is a specialization (`Sum(this IEnumerable<int>)`) or generic (`Where<T>(this IEnumerable<T> source, Func<T, bool> predicate)`).\n  - The section lists all extensions, from all extending types. They are grouped by type, then sorted alphabetically. **We would like this to change, and have the extension methods sorted alphabetically, without regard to the containing class.**\n    - **Alternative: This should change so that the API pages always group extension methods by their containing class and receiver type, including generic specialization.**\n  - The signature does not show any indication of the extending type.\n  - The docs pipeline generates this section on the extended type from the descriptions of the extension methods. The `///` comments on the extended type (for example, `System.Collections.Generic.IEnumerable<T>`) doesn't need to include all extension methods in the entire library.\n\nIn source, the existing `///` elements on the extending type and the extension method declarations enable this presentation.\n\n## Docs presentation for C# 14 extension members\n\nThe presentation for C# 14 extensions needs to account for several new types of extension members:\n\n- Extension methods (new, instance or static)\n- Extension properties (instance or static)\n- Extension indexers.\n- Extension operators.\n\nThis proposal currently assumes no changes to the presentation for existing extension methods.\n\n> Alternative:  We could experiment with displaying all extension members using this updated format. Readers can give feedback on whether they prefer a unified presentation, or want to know if a method follows the new or old format. There is no reason a consumer needs to know which format was used to declare an extension. The declarations are binary compatible.\n\n### Extension member prototypes\n\nWhen an extension member prototype is shown, the format should show the extension container:\n\n```csharp\nextension<T>(IEnumerable<T> source)\n{\n    public bool IsEmpty { get; }\n}\n```\n\nThe `source` parameter is referred to as the *receiver parameter*, or *receiver*. The *receiver parameter* may be an instance, as shown above, or it may be a type, as in the following:\n\n```csharp\nextension<T>(IEnumerable<T>)\n{\n    public static IEnumerable<T> Create(int size, Func<int, T> factory);\n}\n```\n\n> Alternatives: The prototypes above show a single extension member in an extension container. In source, multiple members share the same receiver and are declared in the same extension container. An alternative for the prototypes would be as follows:\n>\n> ```csharp\n> extension<T>(IEnumerable<T> source)\n> {\n>     public bool IsEmpty { get; }\n>     public int Length { get; }\n>     public IEnumerable<T> Sample(int sampleInterval);\n> }\n> ```\n>\n> It could save screen space to collect members by receiver declaration and remove the duplication. That would only apply on pages where multiple prototypes are shown together. Another negative is that it could conflict with the current lists in the TOC that have all overloads collected together. We should specify the URL for the docs page for a single `extension` declaration.\n\nThe *receiver parameter* includes a parameter name when the receiver is an instance. The *receiver parameter* doesn't include a parameter name when the receiver is a type.\n\nThis presentation enables the following:\n\n- Readers see the new extension syntax when consuming new extensions, driving awareness and adoption.\n- Readers can quickly distinguish a new-style extension (noted by the receiver parameter), and existing extension methods (noted by the `this` modifier on the first parameter).\n- The `extension` container indicates that the member is an extension member.\n- The parameter on the `extension` node indicates the type extended, and provides a key to know if the member is intended to extend an instance or extend the type.\n- The prototype only includes the `static` modifier if it would be present in source, as in an operator declaration:\n  ```csharp\n  extension<T>(IEnumerable<T>)\n  {\n      public static IEnumerable<T> operator + (IEnumerable<T> left, IEnumerable<T> right);\n  }\n  ```\n\n### Extension members in the extended type's page\n\nThe API docs build system generates the section on the type page for the extended type that lists all extension members. This section should have sub-sections for *extension methods*, *extension properties*, and *extension operators*. Extension indexers should follow the format for indexers, and be listed as an `Item[]` property. There isn't a `this` modifier on the first parameter. In fact, the receiver is declared on the extension, not the member. The prototypes in this section should expand to show the `extension` container, as follows:\n\n- The prototypes are displayed as described in the previous section.\n- Otherwise, the format is consistent with the current format:\n  - Each overload has a separate entry in the section.\n  - The signatures indicate if the method is a specialization (`extension(IEnumerable<int> source) { ... }`) or generic (`extension<T>(IEnumerable<T> source) { ... }`).\n  - The section lists all extensions, from all extending types. They are sorted alphabetically, as proposed for current extension methods.\n    - **Alternative: All extension members are grouped by containing class and receiver type, including generic specialization.**\n\n### Extension class page\n\nThe page for the class containing extensions will need only minimal updates in how extension members are displayed. The `static` classes that contain extension methods are classes, and could already define static properties, indexers, and operators. The additional work involves understanding the [unspeakable extension type](#unspeakable-extension-type) that contains new extension members.\n\n- The TOC node for the class will typically have additional nodes for **Properties** (including indexers), and **operators**. Classes already support this, so it should already work. Note that the node for methods displays *method groups*, not *individual overloads*. That should remain.\n- The page should also have sections for **Properties**, and **operators**.\n- The prototypes for extensions should be displayed as shown [above](#extension-member-prototypes). Note alternative for grouping extensions by receiver declaration.\n\n### Extension member page\n\nThere should be a new style for extension members. This should be modeled after the existing member template, with the following changes:\n\n- The receiver type should be shown in the title and the header block.\n- The receiver parameter should have its own block. It should precede the other parameter block.\n- The prototype for the member should follow the format shown [above](#extension-member-prototypes). The receiver parameter is named for extensions whose receiver is an instance. The name is not included for extensions where the receiver is a type.\n\nThe emphasis on the receiver parameter reinforces the new syntax, and is necessary for readers to see the extended type on the new extension member.\n\n### Unspeakable extension skeletons\n\nThe compiler generates a public skeleton class that defines prototypes for extension members. The skeleton class has an unspeakable name and contains the following prototypes:\n\n- A private static unspeakable method declaration starting with `<Extension>`. This private static method includes one parameter that represents the receiver for the extension members declared in the skeleton.\n- Prototypes for all extension members defined for the receiver. These prototypes show the declarations as though declared on the receiver type.\n\nThe unspeakable skeleton provides the prototypes for the extension members and the receiver type. The nodes of the skeleton provide a location for the XML output from the `///` comments on the extension members and the receiver parameter. The `///` comments on the extension declaration are written as XML on the node for the unspeakable member declaring the receiver. The `///` comments on each extension member are written as XML on the node for the embedded member of the unspeakable containing class.\n\nSee the following code and XML for an example of extension members and the resulting XML output.\n\n```csharp\n/// <summary>Summary for E</summary>\nstatic class E\n{\n    /// <summary>Summary for extension block</summary>\n    /// <typeparam name=\"T\">Description for T</typeparam>\n    /// <param name=\"t\">Description for t</param>\n    extension<T>(T t)\n    {\n        /// <summary>Summary for M</summary>\n        /// <typeparam name=\"U\">Description for U</typeparam>\n        /// <param name=\"u\">Description for u</param>\n        public void M<U>(U u) => throw null!;\n\n        /// <summary>Summary for P</summary>\n        public int P => 0;\n    }\n}\n```\n\nproduces the following XML output:\n\n```xml\n<?xml version=\"1.0\"?>\n<doc>\n    <assembly>\n        <name>Test</name>\n    </assembly>\n    <members>\n        <member name=\"T:E\">\n            <summary>Summary for E</summary>\n        </member>\n        <member name=\"T:E.<>E__0`1\">\n            <summary>Summary for extension block</summary>\n            <typeparam name=\"T\">Description for T</typeparam>\n            <param name=\"t\">Description for t</param>\n        </member>\n        <member name=\"M:E.<>E__0`1.M``1(``0)\">\n            <summary>Summary for M</summary>\n            <typeparam name=\"U\">Description for U</typeparam>\n            <param name=\"u\">Description for u</param>\n        </member>\n        <member name=\"P:E.<>E__0`1.P\">\n            <summary>Summary for P</summary>\n        </member>\n        <member name=\"M:E.M``2(``0,``1)\">\n            <inheritdoc cref=\"M:E.<>E__0`1.M``1(``0)\"/>\n        </member>\n        <member name=\"M:E.get_P``1(``0)\">\n            <inheritdoc cref=\"P:E.<>E__0`1.P\"/>\n        </member>\n    </members>\n</doc>\n```\n\n### XML Output for `///` comments\n\nThe compiler uses the skeleton declarations to produce the XML output for all `///` comments on the extension node and the embedded extension members:\n\n- Comments from the `extension` block are applied to the embedded receiver field in the unspeakable nested class. This can include type parameter information and parameter information for the receiver.\n- Comments from extension members are output to the skeleton prototypes embedded in the unspeakable nested class.\n- Any extension member declaration that includes `typeparamref` or `paramref` nodes in the extension block resolve to the corresponding `typeparam` and `param` nodes on the extension block.\n- The implementation nodes for the extension members use the `<inheritdoc cref=\"skeleton-member\" />` node to point to the generated XML output from the skeleton member.\n\nThe nodes on the receiver and each member must be merged by the tools that consume the XML (for example, Visual Studio IntelliSense, or the MS Learn build process).\n\n## Disambiguation and API docs\n\nA disambiguation syntax is required when more than one `class` declares extension members with the same signature. Consumers must use a static syntax to specify which method should be called. We believe this is the less common case. However, it is common enough that our docs presentation should clearly display the class where an extension member is declared.\n\nThe C# LDM hasn't finalized the [disambiguation syntax](https://github.com/dotnet/csharplang/blob/main/meetings/working-groups/extensions/disambiguation-syntax-examples.md). The final disambiguation syntax shouldn't impact the API generation pipeline. We will demonstrate it in docs.\n"
  },
  {
    "path": "meetings/working-groups/extensions/anonymous-extension-declarations.md",
    "content": "# Anonymous extension declarations\n\n## Summary\n\nThis design draws on many recent proposals, and is derived based on a set of assumptions about the kind of feature that would be successful with developers. It places extension member declarations within anonymous extension declarations that specify underlying type and accompanying type parameters, and which are in turn nested within non-generic static classes.\n\n``` c#\npublic static class Enumerable\n{\n    // Extension members for IEnumerable\n    extension(IEnumerable)\n    {\n        // 'this' refers to underlying value\n        public bool IsEmpty => !this.GetEnumerator().MoveNext();\n    }\n    // Extension members for IEnumerable<T>\n    extension<T>(IEnumerable<T>)\n    {\n        public IEnumerable<T> Where(Func<T, bool> predicate) { ... }\n        public IEnumerable<TResult> Select<TResult>(Func<T, TResult> selector) { ... }\n        public static IEnumerable<T> operator +(IEnumerable<T> e1, IEnumerable<T> e2) { ... }\n    }\n    \n    // Classic extension method\n    public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source) { ... }\n    \n    // Non-extension member\n    public static IEnumerable<int> Range(int start, int count) { ... } \n\n}\n```\n\n## Motivation\n\nThis design starts from a set of assumptions about what matters more or less to users of the feature, deriving a design that meets them. Those assumptions, though gathered from the criticisms of both \"type-based\" and \"member-based\" proposals, are certainly debatable and won't all be agreed upon. They represent the beliefs and opinions of the author. Let's go through them below, along with a sneak peek at how they drive the design.\n\n### Type names and grouping\n\n* Developers want to be able to group a collection of related extension members under just one type name, even if they span multiple different underlying types. People would resent having to come up with multiple separate type names for different underlying types, and having to navigate those many names for disambiguation, `using static` inclusion etc.\n* Separate type names for different receiver types won't be necessary for disambiguation - they aren't today.\n\nThis implies an overarching grouping entity that carries no inherent information beyond simply a type name. The proposed design reuses top-level non-generic static classes for this purpose.\n\n### Relationship to classic extension methods\n\n* People would like to be able to place their new extension members together with their existing extension methods.\n* People do appreciate being able to declare non-extension static members next to extension declarations.\n* People are better off leaving their classic extension methods as static method declarations so that the static invocation signature is obvious, and to avoid churn and risk.\n* People will, however, expect lookup to work very closely similar between old and new extension methods.\n\nBecause the proposed design keeps using non-generic static classes as the overarching grouping entity, new extension declarations can sit side by side with old extension methods and non-extension static members. However, new extension methods do not work exactly the same as old ones. (Although do see the \"Alternatives\" section).\n\n### Type parameters and underlying types\n\n* Underlying types belong together with their type parameter declarations, and it would be confusing to separate them.\n* People will resent the verbosity of having to repeat underlying types and accompanying type parameters for each member.\n* Sometimes there's a need to specify different parameter details (ref-ness, nullability, ...) for the same underlying type.\n\nThe design uses anonymous extension declarations within static classes. These anonymous extension declarations specify type parameters, underlying type and any parameter details for the extension member declarations they contain.\n\n### Member declarations\n\n* Extension member declarations should look identical to corresponding member declarations in classes and structs.\n* Parameter names for underlying values aren't important and people will resent the forced verbosity of having to specify them.\n\nThe design keeps extension members with the same syntax as their class and struct counterparts, including using `this` to refer to the underlying value.\n\n### Regularity\n\n* Rules and syntax should be consistent across all different member kinds, generic arities etc.\n* Implementation limitations or compatibility constraints shouldn't be materially felt in the user level feature experience.\n* There should be just one right way to declare a given extension member.\n\nThe design has exactly one syntactic location for each of the extension type name, underlying types with accompanying type parameters, additional parameter info and the extension members themselves.\n\n### Efficiency\n\n* Extension declarations shouldn't result in an unnecessarily large number of types being generated.\n* Extension member invocations should not incur hidden penalties, allocations or copying.\n\nThe design represents anonymous extension declaration as nested static classes which are merged as much as generic arity and constraints allow. Extension members are represented as static members with an extra parameter for the underlying value, using any additional parameter info in that parameter's declaration. Extension member invocation is just invocation of those static members.\n\n## Detailed design\n\n### Declaration\nExtensions are declared inside top-level non-generic static classes, just like extension methods today, and can thus coexist with classic extension methods and non-extension static members:\n\n``` c#\npublic static class Enumerable\n{\n    // New extension declaration\n    extension(IEnumerable) { ... }\n    \n    // Classic extension method\n    public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source) { ... }\n    \n    // Non-extension member\n    public static IEnumerable<int> Range(int start, int count) { ... } \n}\n```\n\nAn extension declaration is anonymous, and provides a specification of an underlying type with any associated type parameters and ref kinds, followed by a set of extension member declarations:\n\n``` c#\npublic static class Enumerable\n{\n    extension(IEnumerable) // extension members for IEnumerable\n    {\n        public bool IsEmpty { get { ... } }\n    }\n    extension<T>(IEnumerable<T>) // extension members for IEnumerable<T>\n    {\n        public IEnumerable<T> Where(Func<T, bool> predicate) { ... }\n        public IEnumerable<TResult> Select<TResult>(Func<T, TResult> selector) { ... }\n        public static IEnumerable<T> operator +(IEnumerable<T> e1, IEnumerable<T> e2) { ... }\n    }\n}\n```\n\nThe extension member declarations are syntactically identical to corresponding instance and static members in class and struct declarations. Instance members refer to the underlying value with the keyword `this`:\n\n``` c#\npublic static class Enumerable\n{\n    extension(IEnumerable)\n    {\n        // 'this' refers to underlying value\n        public bool IsEmpty => !this.GetEnumerator().MoveNext();\n    }\n}\n```\n\nAs in instance members, the reference to `this` can be implicit:\n\n``` c#\npublic static class Enumerable\n{\n    extension(IEnumerable)\n    {\n        // implicit 'this.GetEnumerator()'\n        public bool IsEmpty => !GetEnumerator().MoveNext();\n    }\n}\n```\n\nBy default, the underlying value is passed to instance extension members by value, but an extension declaration can explicitly specify a different ref kind, as long as the underlying type is known to be a value type:\n\n``` c#\npublic static class Bits\n{\n    extension(ref ulong) // underlying value is passed by ref\n    {\n        public bool this[int index]\n        {\n            get => (this & Mask(index)) != 0;\n            set => this = value ? this | Mask(index) : this & ~Mask(index); // mutates underlying value\n        }\n    }\n    static ulong Mask(int index) => 1ul << index;\n}\n```\n\nUnderlying types in extension declarations can be or contain nullable reference types. If underlying types vary by nullability, separate extension declarations are needed.\n\nIndividual extension members can place attributes on the implicit `this` parameter by using the `param` target in an attribute placed on the member itself. `param` is not currently allowed in this position, but is already used elsewhere in C# to refer to implicit parameters:\n\n``` c#\npublic static class NullableExtensions\n{\n    extension(string?)\n    {\n        public string AsNotNull => this is null ? \"\" : this;\n        [param:NotNullWhen(false)] public bool IsNullOrEmpty => this is null or [];\n    }\n    extension<T> (T) where T : class?\n    {\n        [param:NotNull] public void ThrowIfNull() => ArgumentNullException.ThrowIfNull(this);\n    }\n}\n```\n\n### Lowering\n\nExtension declarations give rise to static classes nested within the enclosing static class. These inner static classes are generated with unspeakable names and do not pollute the namespace of the enclosing static class. \n\nWithin a given enclosing static class, extension declarations with the same number of type parameters and equivalent constraints are merged into a single static class even if they differ on underlying type, ref-kind or type parameter names. Thus the minimum number of nested classes are generated to represent the combinations of type parameters and constraints present across all the extension declarations within the enclosing static class:\n\n``` c#\npublic static class MyExtensions\n{\n    extension<TSource>(Span<TSource>) where TSource : class?\n    {\n        ...\n    }\n    extension<TElement>(Span<TElement?>) where TElement : class\n    {\n        ...\n    }\n}\n```\n\nBecause the signatures are sufficiently equivalent, this is lowered to just one class:\n\n``` c#\npublic static class MyExtensions\n{\n    public static class __E1<__T1> where __T1 : class\n    {\n        ...\n    }\n}\n```\n\nThe requirement is not unlike that between the two parts of a partial method in today's C#.\n\nThe members themselves are generated as static members. For instance members, insofar as it is possible to represent in IL, the same kind of member is generated, but with an extra first parameter for the underlying value. Where not possible, the body is represented as one or two (for accessors) static methods, and attributes are emitted to record their original member kind.\n\nThe generated first parameter includes any ref kind specified in the extension declaration, and any attributes on the member which have the `param` target specifier:\n\n``` c#\npublic static class NullableExtensions\n{\n    extension<T> (T) where T : class?\n    {\n        [param:NotNull] public void ThrowIfNull() => ArgumentNullException.ThrowIfNull(this);\n    }\n}\n```\n\nGenerates:\n\n``` c#\npublic static class NullableExtensions\n{\n    public static class __E1<__T1> where T1__ : class\n    {\n        public static void ThrowIfNull([NotNull] __this) => ArgumentNullException.ThrowIfNull(__this);\n    }\n}\n```\n\n### Checking\n\n__Inferrability:__ The underlying type of an extension declaration must make use of all the type parameters of that extension declaration, so that it is always possible to infer the type arguments when applied to the underlying type.\n\n__Uniqueness:__ Within a given enclosing static class, the set of extension member declarations with the same underlying type (modulo identity conversion and type parameter name substitution) are treated as a single declaration space similar to the members within a class or struct declaration, and are subject to the same [rules about uniqueness](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/classes.md#153-class-members).\n\nThe uniqueness rule also applies across classic extension methods within the same static class, where any type parameter list is used unchanged, the `this` parameter is used to determine the underlying type, and the remaining parameters are used for the method signature.\n\n``` c#\npublic static class MyExtensions\n{\n    extension<T1>(IEnumerable<int>) // Error! T1 not inferrable\n    {\n        ...\n    }\n    extension<T2>(IEnumerable<T2>)\n    {\n        public bool IsEmpty { get ... }\n    }\n    extension<T3>(IEnumerable<T3>?)\n    {\n        public bool IsEmpty { get ... } // Error! Duplicate declaration\n    }\n}\n```\n\n### Lookup and disambiguation\n\nWhen an extension member lookup is attempted, all extension declarations within static classes that are `using`-imported contribute their members as candidates, regardless of underlying type. Only as part of resolution are candidates with incompatible underlying types discarded. A full generic type inference is attempted between the type of a receiver and any type parameters in the underlying type.\n\nThe inferrability and uniqueness rules mean that the name of the enclosing static type is sufficient to disambiguate between extension members on a given underlying type. As a strawman, consider `E @ T` as a disambiguation syntax meaning on a given expression `E` begin member lookup for an immediately enclosing expression in type `T`. For instance:\n\n``` c#\nstring[] strings = ...;\nvar query  = (strings @ Enumerable).Where(s => s.Length > 10);\n \npublic static class Enumerable\n{\n    extension<T>(IEnumerable<T>)\n    {\n        public IEnumerable<T> Where(Func<T, bool> predicate) { ... }\n    }\n}\n```\n\nMeans lookup `Where` in the type `Enumerable` with `strings` as its underlying value. A type argument for `T` can now be inferred from the type of `strings` using standard generic type inference.\n\nA similar approach also works for types: `T1 @ T2` means on a given type `T1` begin static member lookup for an immediately enclosing expression in type `T2`.\n\nThis disambiguation approach should work not only for new extension members but also for classic extension methods.\n\nNote that this is not a proposal for a specific disambiguation syntax; it is only meant to illustrate how the inferrability and uniqueness rules enable disambiguation without having to explicitly specify type arguments for an extension declaration's type parameters.\n\n## Drawbacks\n\n## Alternatives\n\n### Avoiding nesting for simple cases\n\nThe proposed design avoids a lot of repetition, but does end up with extension members being nested two-deep in a static class _and_ and extension declaration.\n\nTwo kinds of short-hand syntax are possible:\n\n__Merge static class and extension declarations:__ When a static class contains only a singe extension declaration and nothing else, allow it to be abbreviated to a top-level extension declaration _with_ a name:\n\n``` c#\npublic extension(IEnumerable) Enumerable\n{\n    public bool IsEmpty => !GetEnumerator().MoveNext();\n}\n```\n\nThis ends up looking more like what we've been calling a \"type-based\" approach, where the container for extension members is itself named. However, the nesting would still be applied in the generated output.\n\n__Merge extension declaration and extension member:__ When an extension declaration contains only one member, allow the `{ ... }` curlies to be omitted around that member:\n\n``` c#\npublic static class Bits\n{\n    extension(ref ulong) public bool this[int index]\n    {\n        get => (this & Mask(index)) != 0;\n        set => this = value ? this | Mask(index) : this & ~Mask(index); // mutates underlying value\n    }\n    static ulong Mask(int index) => 1ul << index;\n}\n```\n``` c#\npublic static class Enumerable\n{\n    extension<T>(IEnumerable<T>) public IEnumerable<T> Where(Func<T, bool> predicate) { ... }\n}\n```\n\nThis ends up looking more like what we've been calling a \"member-based\" approach, where each extension member contains its own details about the underlying type. However, in the generated output the type parameter and underlying type would still be applied to a generated nested class, not the member itself.\n\n### Embracing compatibility\n\nAllowing full compatibility for existing extension methods to be ported to new syntax was an explicit non-goal for this proposal, but in the end it does come quite close to being able to embrace such compatibility. an instance extension method in this syntax has everything it needs to generate an equivalent classic extension method - except a parameter name for the `this` parameter. Why is this necessary? Because existing callers of the extension method as a static method may pass the `this` argument by name! \n\n``` c#\npublic static class Enumerable\n{\n    extension<T>(IEnumerable<T>)\n    {\n        [GenerateStaticMethod(\"source\")]\n        public IEnumerable<T> Where(Func<T, bool> predicate) \n        { \n            foreach (var e in this){ ... }\n        }\n        [GenerateStaticMethod(\"source\")]\n        public IEnumerable<T> Select<TResult>(Func<T, TResult> selector) \n        { \n            foreach (var e in this){ ... }\n        }\n    }\n}\n```\n\nType parameters from the extension declaration and the method declaration would be concatenated. In principle there are some classic extension methods that couldn't be expressed like this: ones where the type parameters used in the underlying type aren't first in the type parameter list:\n\n``` c#\npublic static IEnumerable<TResult> WeirdSelect<TResult, TSource>(\n    this IEnumerable<TSource> source,\n    Func<TSource, TResult> selector) \n{ ... }\n```\n\nI don't think I've ever seen an extension method like that! But any such method would have to stay in the classic syntax.\n\n### Member-based lowering strategy\n\nThe proposed lowering strategy merges extension declarations into anonymous static classes under the hood. This helps reduce the amount of transformation that needs to happen on individual members - properties can stay properties, and so on.\n\nHowever, it does lead to challenges:\n- How do we generate stable names for these anonymous classes?\n- This would be the first time we generate \"unspeakable\" public types. How does the ecosystem manage that - other languages, documentation, etc.?\n\nAs an alternative, we could generate extension members as static methods directly on the enclosing static class. Any member from a generic extension declaration would need to be turned into one or two generic methods with mangled names, and metadata would need to be generated to track how it all belongs together in extension declarations. All in all, members would be much more heavily transformed, but we would avoid the extra layer of anonymous static classes.\n\n## Unresolved questions\n\n- How stable can we make the generated names of merged static classes, and how much does it matter?\n"
  },
  {
    "path": "meetings/working-groups/extensions/compat-mode-in-extensions.md",
    "content": "# Compat mode in extensions\n\n_This document is very much work in progress!_\n\nThere are several ways in which the new extension members design causes potential compat breaks, in the sense that a classic extension method being upgraded to the new syntax might break existing callers. The \"compat mode\" is an attempt at addressing these.\n\n## Syntax\n\nCompat mode is activated by using the `this` modifier on a receiver parameter:\n\n``` c#\npublic static class Enumerable\n{\n    extension<TSource>(this IEnumerable<TSource> source) // `this` means compat mode\n    {\n        ...\n    }\n}\n```\n\n## Objective\n\nA design goal of compat mode is that any instance extension method within the extension declaration either a) behaves in a fully compatible way with the corresponding classic extension method, or b) yields a compile time error if that is not possible.\n\nThus, if an existing classic extension method is ported to the new syntax with compat mode on, it will either be disallowed or guaranteed to continue to work as before.\n\n## Semantics in compat mode\n\nThe following are areas where classic and new extension methods are known to differ. Compat mode addresses each of those differences. More may be added as we discover them. There are currently no examples of giving errors.\n\n### Static methods\n\nClassic extension methods are static methods on the enclosing static class, and they may be invoked as such. In compat mode, a static method is generated by the compiler, using:\n\n- the attributes, accessibility, return type, name and body of the declared instance extension method,\n- a type parameter list concatenated from the type parameters of the extension declaration and the extension method, in that order,\n- a parameter list concatenated from the receiver parameter of the extension declaration and the parameter list of the extension method, in that order.\n\n``` c#\npublic static class Enumerable\n{\n    extension<TSource>(this IEnumerable<TSource> source) // Generate compatible extension methods\n    {\n        public IEnumerable<TSource> Where(Func<TSource, bool> predicate) { ... }\n        public IEnumerable<TSource> Select<TResult>(Func<TSource, TResult> selector)  { ... }\n    }\n}\n```\n\nGenerates\n\n``` c#\npublic static class Enumerable\n{\n    public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { ... }\n    public static IEnumerable<TSource> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)  { ... }\n}\n```\n\n### Type arguments\n\nWhen type arguments are explicitly given to a classic extension method, they must correspond to all type parameters, including those that are used in the receiver type. By contrast, with new extensions any type parameters on the extension declaration are inferred from the receiver, and type arguments on invocation correspond only to those declared on the extension method itself.\n\nIn compat mode, type argument lists are first matched against the full type parameter list generated in the corresponding static method. Only if no applicable such methods are found is an attempt made using only the type parameter list from the extension method itself.\n\nGiven:\n``` c#\npublic static class Enumerable\n{\n    extension<TSource>(this IEnumerable<TSource> source)\n    {\n        public IEnumerable<TSource> Select<TResult>(Func<TSource, TResult> selector)  { ... }\n    }\n\n```\n\nThe call `myList.Select<int, string>(...)` would provide type arguments for `TSource` and `TResult`, foregoing the separate inference of `TSource` from the type of `myList`.\n\nThe call `myList.Select<string>(...)` would still be allowed, and if it isn't resolved to another extension method in the first round, would provide a type argument for `TResult` in the above `Select` method, with `TSource` being inferred from the type of `myList`.\n\n### Type inference\n\nWhen type arguments are inferred for a given classic extension method, any argument may impact the inference of any type parameter. By contrast, with new extensions type arguments for the extension declaration type parameters are inferred from the receiver, whereas arguments to the extension method may only impact type arguments for the extension method's own type parameters.\n\nIn compat mode, type arguments are inferred using the generated static method signature, passing the receiver as the first argument.\n\n``` c#\nvoid M(I<string> i, out object o)\n{\n    i.M1(out o); // infers E.M1<object>\n    i.M2(out o); // error CS1503: Argument 1: cannot convert from 'out object' to 'out string'\n    i.M3(out o); // infers E.M3<object>\n}\n\npublic static class E\n{\n   public static void M1<T>(this I<T> i, out T t) { ... }\n   extension<T>(I<T> i)\n   {\n      public void M2(out T t) { ... }\n   }\n   extension<T>(this I<T> i) // Compat mode\n   {\n      public void M3(out T t) { ... }\n   }\n}\npublic interface I<out T> { }\n```\n\n### Inferrability\n\nNew extension declarations have an inferrability requirement which dictates that any type parameter on the extension declaration occurs at least once in the receiver type. This allows type arguments for those type parameters to be inferred solely from the type of the receiver. However, this prevents certain classic extension methods from being ported to the new syntax, if their type parameters are not in the right order to have those that occur in the receiver type come first in the type parameter list.\n\nIn compat mode, the inferrability requirement is waived. This means that type parameters can occur on the extension declaration itself without occurring in the receiver type. For any classic extension method there is therefore the option of porting it to an extension declaration that contains all its type parameters (or as many as needed), instead of leaving them on the extension method declaration.\n\nMaking use of this option to have uninferrable type arguments on the extension declaration does introduce other limitations:\n\n- Only instance extension methods can be declared in the the extension declaration\n- Explicit type arguments will only be matched to the full argument list of the generated static method, not subsequently to only those declared in the extension method\n\n``` c#\npublic static class E\n{\n    public static IEnumerable<TResult> Select1<TResult, TSource>(this IEnumerable<TSource> source, Func<TSource, TResult> selector) { ... }\n    extension<TResult, TSource>(this IEnumerable<TSource> source) // TResult not used\n    {\n        public static IEnumerable<TResult> Select2(Func<TSource, TResult> selector) { ... }\n    }\n}\n```\n\n## Alternatives\n\n### No explicit compat mode\nSome of the above effects of compat mode might be acceptable for all extension declarations, as they would have little negative effect on the user experience as seen from the perspective of the new extension feature. Perhaps a decent compromise and simplification would be to not have an explicit compat mode, adopt some of its behaviors for all extension members and live with the hopefully small breaking changes caused by abandoning the rest of those behaviors.\n\nBased on currently known scenarios, the two first features - calling extension methods as static methods and passing all type arguments to extension methods - seem likely to be common. Both seem reasonable to support for all new extension methods, as long as the ability to pass only the method's own type arguments is also preserved. \n\nAllowing extension method arguments to influence inference of extension declaration level type arguments seems like a much more contrived scenario. From a user perspective it seems reasonable that we could quietly support it, although the implementation cost - or the degree of complification to the spec - may not be so reasonable. However, even if we give the advice to keep the extension method in classic form, we then have to make two different type inference approaches - the old and the new - coexist side by side and figure out how to make them work together.\n\nHaving type parameters \"out of order\" so that ones that are not used in the `this`-parameter precede ones that are also seems vanishingly rare. We can probably live with not having those be portable to the new syntax."
  },
  {
    "path": "meetings/working-groups/extensions/compromise-design-for-extensions.md",
    "content": "# Compromise design for extensions\n\n## Summary\n[summary]: #summary\n\nThis proposal mixes the type- and member-based approaches to extension declarations: It combines a type-based approach for all member kinds with a member-based syntax for member-specific annotations and backwards-compatible extension method declarations.\n\n## Motivation\n[motivation]: #motivation\n\nWe're currently facing the conundrum that the type-based approach to extensions does not provide a compatible way for existing extension methods to move forward into new syntax, whereas the member-based approach imposes a high syntactic burden on new extension members (both methods and others) that do not need such compatibility.\n\nThis proposal tries to bring the best of the two approaches together without creating too many different ways of doing the same thing. At its core it uses the type-based approach, where type parameters and a parameter-like \"for-clause\" with the receiver type are specified on the extension type declaration. Non-method extension members cannot declare type parameters. Extension members _can_ specify for-clauses of their own, but, with one exception, only to add additional annotations such as attributes and ref-ness modifiers that are specific to how this particular member interacts with the receiver.\n\nThe one exception is \"compatible extension methods\". These are extension methods that _do_ override the for-clause of the extension declaration. Such extension methods generate static methods that are guaranteed to be fully source and binary compatible with corresponding classic extension methods.\n\nWhile the proposal encompasses core tenets of both type-based and member-based proposals, it also loses some expressiveness from both. Compared to pure member-based proposals, it doesn't allow the general grouping of extension members with different receiver types into the same extension declaration. There isn't a proposal on the table that achieves that without raising the as-yet unaddressed issue of type parameters and type arguments for member kinds other than members.\n\nOn the type-based side the proposal loses the proposed implicit \"this-style\" parameter passing mode, which automatically treats the receiver as a value parameter when it is of a reference type, and as a reference parameter when it is of a value type. While some explicit version of this may be possible to add, doing it implicitly likely introduces too much of an arbitrary behavior difference with classic extension methods.\n\n## Detailed design\n[design]: #detailed-design\n\nThere are many variations on what a merged syntax could look like. This is one attempt, but pretty much anything is debatable!\n\n``` antlr\nextension_declaration\n    : attributes? extension_modifier* 'partial'? 'extension' identifier\n        type_parameter_list? for_clause? type_parameter_constraints_clause*\n        extension_body ';'?\n    ;\n    \nextension_modifier\n    : 'new'\n    | 'public'\n    | 'protected'\n    | 'internal'\n    | 'private'\n    | 'sealed'\n    | 'static'\n    | unsafe_modifier   // unsafe code support\n    ;\n    \nfor_clause\n    : 'for' attributes? extension_mode_modifier? type\n    ;\n    \nextension_mode_modifier:\n    | 'ref'\n    | 'ref readonly'\n    | 'in'\n    ;\n\nextension_body\n    : '{' extension_member_declaration* '}'\n    ;\n    \nextension_member_declaration\n    : constant_declaration\n    | field_declaration\n    | extension_method_declaration\n    | extension_property_declaration\n    | extension_event_declaration\n    | extension_indexer_declaration\n    | operator_declaration\n    | constructor_declaration\n    | static_constructor_declaration\n    | type_declaration\n    ;\n    \nextension_method_declaration\n    : attributes? method_modifiers return_type extension_method_header method_body\n    | attributes? ref_method_modifiers ref_kind ref_return_type extension_method_header\n      ref_method_body\n    ;\n    \nextension_method_header\n    : member_name '(' formal_parameter_list? ')' method_for_clause?\n    | member_name type_parameter_list '(' formal_parameter_list? ')' method_for_clause?\n      type_parameter_constraints_clause*\n    ;\n\nmethod_for_clause\n    : for_clause identifier?\n    ;\n    \nextension_property_declaration\n    : attributes? property_modifier* type member_name for_clause? property_body\n    | attributes? property_modifier* ref_kind type member_name for_clause? ref_property_body\n    ;    \n\nextension_event_declaration\n    : attributes? event_modifier* 'event' type member_name for_clause?\n        '{' event_accessor_declarations '}'\n    ;\n\nextension_indexer_declaration\n    : attributes? indexer_modifier* indexer_declarator for_clause? indexer_body\n    | attributes? indexer_modifier* ref_kind indexer_declarator for_clause? ref_indexer_body\n    ;\n```\n\nAn `extension_method_declaration` with a `for_clause` that includes an `identifier` is called a \"_compatible extension method_.\"\n\nThe following syntactic restrictions apply to `extension_declaration`s:\n\n- `field_declaration`s must be `static`.\n- `extension_member_declaration`s may not have a `new`, `protected`, `virtual`, `sealed`, `override` or `abstract` modifier.\n- `extension_member_declaration`s with a `static` modifier may not have a `for_clause`.\n- Compatible extension methods may not occur within a generic `extension_declaration`.\n- An `extension_declaration` may omit its `for_clause` only if all its member declarations are compatible extension methods.\n- An accessor body of a non-static `extension_property_declaration` may not be `;` and may not use `field` keyword.\n\nThe `for_clause` of any `extension_member_declaration` other than a compatible extension method must specify a `type` that is identity-convertible to that of the enclosing extension declaration's `for_clause`.\n\nThe `identifier` of a compatible extension method's `method_for_clause` may not be referenced within the method body, but is added to the local variable declaration space of the method body to prevent other declarations from using it.\n\nWithin the bodies of all non-static `extension_member_declaration`s, the receiver is referred to by the keyword `this`. \n\nCompatible extension method declarations implicitly generate a static method with the same signature, except that the `method_for_clause` is used as an additional first parameter. Within the body of the generated method, implicit and explicit occurrences of `this` are replaced with the identifier from the `method_for_clause`.\n\nOther extension member declarations do not implicitly generate additional members that are visible at the language level. Their lowering is an implementation detail, and does not affect language level semantics.\n\nThe `extension_mode_modifier` is interpreted the same way as a `parameter_mode_modifier`, and determines the parameter passing mode of `this` in the body of non-static extension members. There is no proposed way to specify the \"mixed\" parameter passing mode that applies to `this` within instance members in classes (by value) and structs (by ref).\n\nThis proposal is for declaration syntax and its meaning. It does not take a stance on lookup, type inference and overload resolution, but can likely accommodate most variations under discussion.\n\n\n## Examples\n\n``` c#\n// Different kinds of extension members\npublic extension E for C\n{\n    // Instance members - assume f is an accessible instance field on C\n    public string P { get => f; set => f = value.Trim(); }         // Property\n    public T M<T>() where T : IParsable<T> => T.Parse(f, default); // Method\n    public char this[int index] => f[index];                       // Indexer\n    public C(string f) => this.f = f;                              // Constructor\n\n    // Static members\n    public static int ff = 0;                                // Static field\n    public static int PP { get; set => field = Abs(value); } // Static property\n    public static C MM(string s) => new C(s);                // Static method\n    public static C operator +(C c1, C c2) => c1.f + c2.f;   // Operator\n    public static implicit operator C(string s) => new C(s); // UD conversion\n}\n\n// Type- and member-level for-clauses for attributes, nullability and ref-ness\npublic extension NullableStringExtensions for string?\n{\n    public bool IsNullOrEmpty for [NotNullWhen(false)] string? \n        => this is null or [];\n    public string AsNotNull => this is null ? \"\" : this;\n    public void MakeNotNull for [NotNull] ref string? => this ??= \"\";\n}\n\n// Core LINQ methods as a non-compatible generic extension\npublic extension Enumerable<T> for IEnumerable<T>\n{\n    public IEnumerable<T> Where(Func<bool> predicate) { ... }\n    public IEnumerable<TResult> Select<TResult>(Func<T, TResult> selector) { ... }\n}\n\n// Core LINQ methods as compatible extension methods\npublic extension Enumerable\n{\n    public IEnumerable<TResult> Select<TSource, TResult>(Func<TSource, TResult> selector) for IEnumerable<TSource> source { ... }\n    public IEnumerable<TSource> Where<TSource>(Func<TSource, bool> predicate) for IEnumerable<TSource> source { ... }\n}\n```\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\n- As a compromise, this proposal may be less principled and conceptually clear to users.\n- The proposal does not allow grouping of extension members with different receiver types (except for compatible extension methods). The same is true for any proposal that puts type parameters on the extension declaration itself.\n- The proposal takes a parameter-like view of the underlying type, and therefore does not allow - let alone default to - a \"this-style\" mixed parameter passing modes for the receiver that depends on whether the receiver is a reference or a value type. \n\n## Alternatives\n[alternatives]: #alternatives\n\nThere are many possible variations on the details of the proposed syntax, restrictions and semantics. Here are a few:\n\n- For-clauses are syntactically identical between the type and the member levels. This underscores their \"parameter-ness\" and supports the notion that member-level clauses just override type-level ones. Another approach would be to let the type-level for-clause only specify a type, and leave any other detail to member-level ones.\n- Compatible extension methods have a subtle syntactic marker in the form of an identifier - a parameter name - on their for-clause. This attempts to strike a balance of making them blend in with the new syntax, while still giving the user a way to express their intent. One could argue for removing this distinction, e.g. by allowing parameter names on all for-clauses. Determining whether a method is compatible would then depend on syntactic and semantic context. At the other end, the distinction could be made more pronounced, e.g. by putting parentheses around the for-clause elements of a compatible extension method.\n- Non-static extension member bodies refer to the receiver with the keyword `this`. We could make receivers even more parameter-like by letting them have a parameter name as part of the for-clause, and then using that name in the bodies. This would be more verbose of course, both because of the added parameter names, and because bodies cannot make use of implicit `this.` to refer to fellow members with simple names.\n- Even compatible extension methods, which do have parameter names in this proposal, use `this` in the body. That choice was made for greater syntactic uniformity, but one could argue that compatible extension methods should be more like classic extension methods in this regard.\n- The proposal disallows member-level specification of the receiver type (except to modify a type-level one for nullability etc.) for non-method members on the grounds that, since those member kinds can't have type parameters, they can't specify open generic types as receiver types in their for-clauses, and then it's cleaner that they can't specify receiver types at all. That line could be drawn more leniently to allow closed types. About 25% of current extension methods are on open generic types.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\nThis proposal is only about declaration syntax and its meaning. There are many decisions, especially around lookup, type inference and overload resolution, that lie ahead. Since those felt largely orthogonal - or at least secondary - to the syntax, they've been left for later.\n"
  },
  {
    "path": "meetings/working-groups/extensions/content-based-naming.md",
    "content": "# Content Based Naming\n\n## Terminology\n\nAn extension member in source will result in two members in metadata:\n\n1. The implementation member: this is the method generated into the type which contains the extension block declaration and used at runtime.\n2. The declaration member: this is the method generated for the purposes of the compiler to support build and design time capabilities of extension members.\n\nThe declaration type is the type that contains the declaration members.\n\nThe marker method is the method in a declaration type which is used to recover the original C# declaration semantics of the extension block parameter.\n\n## Summary\n\nThe current metadata strategy for declaration members relies on ordinals to create declaration types from extension blocks. The use of ordinals causes friction in a few parts of the C# ecosystem:\n\n- Edit and Continue: any use of ordinals tied to source ordering means that adding or removing elements can create unnecessary, and possibly unresolvable, conflicts during ENC operations. Natural operations like adding a new extension block in the middle of two others can lead to renaming of existing blocks which is difficult to reconcile.\n- Public API Tracking: the declaration methods are necessarily generated as `public` and there are many tools in the .NET ecosystem that track `public` method usage. The current design means moving extension blocks around in source can observably change the set of `public` API in an assembly. Shipping with this design would mean this ecosystem of tools would need to change to treat this `public` API as _special_ in some way.\n- CREF generate an observable reference to declaration methods via `inheritdoc`. This means source reordering can break any place CREFs are treated as a durable item.\n\nThis proposal wants to revamp our approach to declaration type and method metadata such that the following goals are achieved:\n\n1. The declaration type and set of declaration and marker that will be generated for a given extension member can be determined by looking at solely that extension member. There is no need to consider other members in the same extension block, `partial` declarations in the containing type, etc ...\n2. Declaration types and methods are treated like `public`. This proposal accepts that declaration types and members will be observable by design and build time processes. This means they need to have, as much as possible, the same characteristics as other `public` API. Specifically the following types of actions should **not** break runtime binary compatibility for `public` members in a declaration type:\n    1. Reordering extension blocks or members in source code\n    2. Changing C# specific aspects of the type like adding / removing nullable annotations, changing tuple names, etc ...\n3. The C# compiler should be able to fully rehydrate the original extension paramater from metadata. This means for each declaration member the compiler can recreate the _exact_ type name, ref-ness, type parameter names, parameter name, etc... that was written in source.\n\nThis will be achieved by moving to a content based naming scheme for declaration types and members.\n\n## Detailed Design\n\nThis proposal relies heavily on using content based naming for declaration types and members.  The proposal is going to focus on what items are included in the content name, it will not discuss the actual name produced. That is because the specific hashing algorithm used will be an implementation detail of the compiler.\n\nFor an extension block the content name of the declaration type will be determined by using the following parts of the extension block declaration:\n\n- The fully qualified CLR name of the type. This will include namespaces, type constraints, named constraints (like `new`).\n    - Type parameter names will be normalized to `T0`, `T1`, etc ... based on the order they appear in the type declaration. This means an extension block with a type parameter `Dictionary<TKey, TValue>` will result in the fully qualified name being `System.Collections.Generic.Dictionary<T0, T1>`.\n    - The fully qualified name will not include the containing assembly. It is common for types to be moved between assemblies and that should not break the public API.\n- Constraints will included and sorted such that reordering them in source code does not change the name. Specifically:\n    - Type parameter constraints will be listed in declaration order. The constraints for the Nth type parameter will occur before the Nth+1 type parameter.\n    - Base type and interface constraints will be sorted by comparing the full names ordinally\n    - Non-type constraints will be sorted by comparing the C# text ordinally\n- This will not include any C# isms like tuple names, nullability, etc ...\n\nThis will achieve the goal that the name of declaration types will only change when the underlying CLR type of an extension block parameter changes. Any change to C# parts of the type such as adding nullable annotations or tuple names will impact the declaration type name.\n\nThe marker method for an extension block will be a `private` method in the declaration type. This method will have a single parameter which mirrors the extension block `this` parameter. Specifically it will have the same attributes, ref declaration, parameter name and C# type. The name of this marker method will be a content name that is determined by using the following parts of the extension block parameter declaration:\n\n- The fully qualified C# name of the type. This will include items like nullable annotations, tuple names, etc ... The constraints will have the same ordering as CLR types for the marker type name.\n- The name of the extension `this` parameter\n- The ref-ness of the extension `this` parameter\n- The fully qualified name + attribute arguments for any attributes applied to the extension `this` parameter.\n\nFor every member in an extension block, the generated declaration member will have an attribute which contains the name of the marker method that represents the original extension `this` parameter. This allows the compiler to fully rehydrate the C# extension `this` parameter for any declaration member.\n\nHere is an example of how this approach would look in real code:\n\n```cs\nclass E\n{\n    extension<T>(IEnumerable<T> source)\n    {\n        public bool IsEmpty => !source.Any();\n        public int Count => sourec.Count();\n    }\n\n    extension<T>(ref IEnumerable<T?> p)\n    {\n        public bool AnyNull => p.Any(x => x == null);\n        public bool NullToEmpty() => this ??= [];\n    }\n\n    extension<T>(IEnumerable<U> source)\n        where T : IEquatable<U>\n    {\n        public bool IsPresent(U value) => source.Any(x => x.Equals(value));\n    }\n}\n```\n\nThis would generate the following:\n\n```cs\nclass E\n{\n    public class <>ContentName_For_IEnumerable_T<T>\n    {\n        private void <>ContentName1(IEnumerable<T> source) { }\n\n        private void <>ContentName2(ref IEnumerable<T?> p) { }\n\n        [MarkerMethodName(\"ContentName1\")]\n        public bool IsEmpty => throw null!;\n\n        [MarkerMethodName(\"ContentName1\")]\n        public int Count => throw null!;\n    \n        [MarkerMethodName(\"ContentName2\")]\n        public bool AnyNull => throw null!;\n    \n        [MarkerMethodName(\"ContentName2\")]\n        public bool NullToEmpty() => throw null!;\n    }\n  \n    public class <>ContentName_For_IEnumerable_T_With_Constraint<U>\n       where U : IEquatable<U>\n    {\n        private void <>ContentName3(IEnumerable<U> source) { }\n\n        [MarkerMethodName(\"ContentName3\")]\n        public static bool IsPresent(U value) => throw null!;\n    }\n}\n```\n\nThis approach will result in stable names for our declaration types and members that will make it much more consumable for the existing C# ecosystem.\n\nThe content hash algorithm will be left as an implementation detail to the compiler. The _recommendation_ is picking a hash that has the following properties:\n\n1. Resilient to collisions from common elements in C# type names.\n2. Has a bounded length on generated names as unbounded names at scale could negatively contribute to metadata limitations on names.\n\nThe only _requirement_ of the hash is that it cannot be a cryptographic hash. Because this is a non-cryptographic hash the compiler will be responsible for doing collision detection. Specifically:\n\n- When the extension block parameter type for two extension blocks have different CLR types but produce the same declaration type name an error must be produced.\n- When the extension block parameter type for two extension blocks have different C# types but produce the same marker method name an error must be produced.\n\nThis design will result in the following restrictions for extension blocks:\n\n- All extension blocks that map to the same declaration type must have type parameters with the same name. This mirrors the existing restrictions that we have for `partial` types.\n- All extension blocks which generate a declaration type name X must refer to the same CLR type. Essentially there cannot be two extension blocks in the same container which map to the same declaration type but different CLR types for the extension parameter. This is not resolvable with `extern alias`. Instead such extension block declarations must be put into different containing types.\n- Changing constraints on an extension block will result in breaking changes for existing CREF in the ecosystem\n\n## Alternatives\n\n### Reduce scope of constraint breaking changes to non-methods\n\nThe biggest challenge with constraints and breaking changes is that for member types like properties the only place constraints can exist is on the type. That means changing constraints means that constraints on the containing type must change. That, combined with other requirements of the design, force the name of the marker type to change as constraints change.\n\nThis problem does not _inherently_ exist for methods. Those can declare their own type parameters and hence be independent of the type parameter / constraints on the containing type.\n\nThis means that we could do the following to make constraint changes for extension methods only non-breaking. Extension blocks would generate into two marker types:\n\n1. A declaration type which contained all extension members that were methods. This declaration type would be non-generic. Type parameters on the original extension type would be copied to each declaration method.\n2. A declaration type which contained all extension members that were not methods. This declaration type would be as previously described in this document.\n\nThis design has a few downsides:\n\n- Significantly increases the complexity of the compiler implementation.\n- Yes it does reduce scope of breaking changes but at the expense of creating a decoder ring for understanding the subtleties of what does / doesn't break.\n\nThe working group does not feel the extra complexity is justified by the limited relief of CREF breaking changes.\n\n### Emit everything as methods in the declaration types\n\nAs mentioned above when dealing with methods it's easier to avoid breaking changes around constraints. One strategy could be to simply emit everything in an extension block as a method and move all the type parameters to these methods.\n\nFor example: when emitting the declaration member for a property named `Example` declared in an extension block we could find a strategy where:\n\n1. Pick a naming scheme that identifies it as property like prefix with `<>Property_Example`\n2. Emit the accessors with a naming scheme like `<>Property_Example_get`\n\nThe exact details would be involved but we could identify a naming scheme that let us map back and forth to the original property name. It would increase the complexity of the compiler implementation but it seems reasonable we could create a name mapping scheme here.\n\nThis design though would require us to generate _invalid_ metadata. For example we'd need to map attributes from the property declaration to the generated method. In the case these were marked as `AttributeTargets.Property` that would be invalid. This is a case where the binary would execute as the CLR does not verify attribute targets are correct but it is likely that it would cause friction in the ecosystem for tools that assume such target are correct.\n\nThat is the biggest issue with this approach. There are several aspects like this where there is no clean mapping. Also there a lot of items like this were are likely missing. We'd need to go through every aspect of metadata and language, find every part that is specific to properties and rationalize them with this approach. This is why the working group discarded this idea (previously and in the context of this specific discussion).\n\n### Remove the matching type parameter name restriction\n\nThe design could be altered such that the restriction on all extension blocks that map to the same marker type must have type parameters with the same name is removed. This would roughly mean that the code generation would do the following:\n\n1. Type parameter names would be normalized to `T0`, `T1`, etc ... in the marker type name.\n2. Type parameter names would be part of the source type marker method content hash.\n3. An attribute would be generated on the source type method that contains the original type parameter names.\n\nThis would allow us to remove this restriction but at the extra cost to the compiler code generation strategy.\n\n## Miscellaneous\n\n### Why not use a Cryptographic Hash?\n\nThe generated names must be the same through the lifetime of this feature in C#. This is not compatible with any use of cryptography which must be agile. Specifically the compiler must assume there is a future where SHA-256, the current defacto crypto algorithm, will be broken and banned in applications. That would leave the compiler in a place where it's using a banned cryptographic algorithm. This is just not compatible with our current security posture.\n\nThe only downside to using a non-cryptographic hashing algorithm is that the compiler cannot take uniqueness for granted. It instead must be verified during compilation time to ensure there are no accidental collisions which is straight forward to implement in the compiler.\n\n## Open Questions\n\n### Type Parameter Names\n\nThis design normalizes type parameter names to `T0`, `T1`, etc ... The original names are encoded in an attribute on the source type method. Need to validate from the compiler team if this is a workable solution for rehydrating the original type parameter names. If this is not viable then we will need to consider adding the following restriction:\n\n- All extension blocks that map to the same declaration type must have type parameters with the same name.\n\nAt a glance this may seem like an unreasonable restriction but there is precedence as this is what we require for `partial` types today.\n\n### Categorizing the breaking change\n\nChanges to the source code that result in only changes to the declaration types are a new kind of breaking change.  Let's consider concretely a case where a constraint on a type parameter is removed.\n\n```cs\n// Before\nclass E\n{\n    extension<T>(C<T> source)\n        where T : IDisposable\n    {\n        public void M() { }\n    }\n}\n\n// After\nclass E\n{\n    extension<T>(C<T> source)\n    {\n        public void M() { }\n    }\n}\n```\n\nThis source change will only result in a change to the declaration types. That means it is **not** a runtime binary breaking change as that would bind against the implementation methods. This change to the declaration type is also not a source breaking change (yes modifying constraints can break source but there is nothing about the declaration types / methods itself that are used in source).\n\nThis is a breaking change for the following items:\n\n- CREF: changing the declaration type / method can break generated CREF in the wild. These would be fixed upon recompilation against the new assembly.\n- Design Time: the Roslyn API can be used to observe the declaration types, CREF being one case.\n\nTime should be taken to better outline and categorize these type of breaks so teams like .NET libraries can make informed decisions about changing aspects of declaration types between releases.\n\n### The MarkerMethodName name\n\nThis proposal uses `[MarkerMethodName]` as the attribute to map between the declaration method and its marker method. This name is a place holder and likely a better name should be considered.\n"
  },
  {
    "path": "meetings/working-groups/extensions/disambiguation-syntax-examples.md",
    "content": "## Declarations\n\n``` c#\npublic static class MyExtensions\n{\n    extension<T>(IEnumerable<T> source)\n    {\n        public bool IsEmpty => !source.Any();\n        public IEnumerable<T> Where(Func<T, bool> predicate) => ...;\n        public T this[int index] => source.ElementAt(index);\n\n        public static IEnumerable<T> Empty => [];\n        public static implicit operator ReadOnlySpan<T>(IEnumerable<T> sequence)\n            => sequence.ToArray().AsSpan();\n    }\n    extension(IEnumerable<int> source)\n    {\n        public IEnumerable(int element, int count) \n            => Enumerable.Repeat(element, count);\n\n        public static IEnumerable<int> Range(int start, int count) \n            => Enumerable.Range(start, count);\n        public static IEnumerable<int> operator +(IEnumerable<int> sequence, int value)\n            => sequence.Select(i => i + value);\n    }\n}\n```\n\n## Example code\n\n``` c#\n// Static extension members\nvar range = IEnumerable<int>.Range(0, 10);\nvar empty = IEnumerable<int>.Empty;\nrange += 5;\nReadOnlySpan<int> span = range;\n\n// Instance extension members\nvar query = range.Where(i => i < 10);\nvar isEmpty = query.IsEmpty;\nvar first = query[0];\nvar repetition = new IEnumerable<int>(first, 10);\n```\n\n## Qualified members\n\n``` c#\n// Static extension members\nvar range = IEnumerable<int>.(MyExtensions.Range)(0, 10);\nvar empty = IEnumerable<int>.(MyExtensions.Empty);\nrange (MyExtensions.+=) 5; /* or */ (MyExtensions.+)(range, 5);\nReadOnlySpan<int> span = (MyExtensions.implicit)(range);\n\n// Instance extension members\nvar query = range.(MyExtensions.Where)(i => i < 10);\nvar isEmpty = query.(MyExtensions.IsEmpty);\nvar first = query.(MyExtensions.this)[0];\nvar repetition = (MyExtensions.new) IEnumerable<int>(first, 10);\n```\n\n- Hard to come up with consistent approach to qualifying different members\n\n## Cast-operator\n\n``` c#\n// Static extension members\nvar range = ((MyExtensions)IEnumerable<int>).Range(0, 10);\nvar empty = ((MyExtensions)IEnumerable<int>).Empty;\n(MyExtensions)range += 5;\nReadOnlySpan<int> span = (MyExtensions)range;\n\n// Instance extension members\nvar query = ((MyExtensions)range).Where(i => i < 10);\nvar isEmpty = ((MyExtensions)query).IsEmpty;\nvar first = ((MyExtensions)query)[0];\nvar repetition = new ((MyExtensions)IEnumerable<int>)(first, 10);\n```\n\n- Casting a type\n- Casting to a non-type\n- Casting LHS of compound assignment\n\n## Invocation syntax\n\n``` c#\n// Static extension members\nvar range = MyExtensions(IEnumerable<int>).Range(0, 10);\nvar empty = MyExtensions(IEnumerable<int>).Empty;\nMyExtensions(range) += 5;\nReadOnlySpan<int> span = MyExtensions(range);\n\n// Instance extension members\nvar query = MyExtensions(range).Where(i => i < 10);\nvar isEmpty = MyExtensions(query).IsEmpty;\nvar first = MyExtensions(query)[0];\nvar repetition = new MyExtensions(IEnumerable<int>)(first, 10);\n```\n\n- Matches the parameter syntax for receiver types\n- Invoking a type\n\n## Indexing syntax\n\n``` c#\n// Static extension members\nvar range = MyExtensions[IEnumerable<int>].Range(0, 10);\nvar empty = MyExtensions[IEnumerable<int>].Empty;\nMyExtensions[range] += 5;\nReadOnlySpan<int> span = MyExtensions[range];\n\n// Instance extension members\nvar query = MyExtensions[range].Where(i => i < 10);\nvar isEmpty = MyExtensions[query].IsEmpty;\nvar first = MyExtensions[query][0];\nvar repetition = new MyExtensions[IEnumerable<int>](first, 10);\n```\n\n- Indexing a type\n\n## As-operator\n\n``` c#\n// Static extension members\nvar range = (IEnumerable<int> as MyExtensions).Range(0, 10);\nvar empty = (IEnumerable<int> as MyExtensions).Empty;\n(range as MyExtensions) += 5;\nReadOnlySpan<int> span = range as MyExtensions;\n\n// Instance extension members\nvar query = (range as MyExtensions).Where(i => i < 10);\nvar isEmpty = (query as MyExtensions).IsEmpty;\nvar first = (query as MyExtensions)[0];\nvar repetition = new (IEnumerable<int> as MyExtensions)(first, 10);\n```\n\n- `as` on a type\n- `as` a non-type\n- `as` on LHS of compound assignment\n\n## At-operator\n\n``` c#\n// Static extension members\nvar range = (IEnumerable<int> at MyExtensions).Range(0, 10);\nvar empty = (IEnumerable<int> at MyExtensions).Empty;\n(range at MyExtensions) += 5;\nReadOnlySpan<int> span = range at MyExtensions;\n\n// Instance extension members\nvar query = (range at MyExtensions).Where(i => i < 10);\nvar isEmpty = (query at MyExtensions).IsEmpty;\nvar first = (query at MyExtensions)[0];\nvar repetition = new (IEnumerable<int> at MyExtensions)(first, 10);\n```\n\n## @-operator\n\n``` c#\n// Static extension members\nvar range = (IEnumerable<int> @ MyExtensions).Range(0, 10);\nvar empty = (IEnumerable<int> @ MyExtensions).Empty;\nrange @ MyExtensions += 5;\nReadOnlySpan<int> span = range @ MyExtensions;\n\n// Instance extension members\nvar query = (range @ MyExtensions).Where(i => i < 10);\nvar isEmpty = (query @ MyExtensions).IsEmpty;\nvar first = (query @ MyExtensions)[0];\nvar repetition = new (IEnumerable<int> @ MyExtensions)(first, 10);\n```\n\n## In-operator\n\n``` c#\n// Static extension members\nvar range = (IEnumerable<int> in MyExtensions).Range(0, 10);\nvar empty = (IEnumerable<int> in MyExtensions).Empty;\n(range in MyExtensions) += 5;\nReadOnlySpan<int> span = range in MyExtensions;\n\n// Instance extension members\nvar query = (range in MyExtensions).Where(i => i < 10);\nvar isEmpty = (query in MyExtensions).IsEmpty;\nvar first = (query in MyExtensions)[0];\nvar repetition = new (IEnumerable<int> in MyExtensions)(first, 10);\n```\n\n## Using-operator\n\n``` c#\n// Static extension members\nvar range = (IEnumerable<int> using MyExtensions).Range(0, 10);\nvar empty = (IEnumerable<int> using MyExtensions).Empty;\n(range using MyExtensions) += 5;\nReadOnlySpan<int> span = range using MyExtensions;\n\n// Instance extension members\nvar query = (range using MyExtensions).Where(i => i < 10);\nvar isEmpty = (query using MyExtensions).IsEmpty;\nvar first = (query using MyExtensions)[0];\nvar repetition = new (IEnumerable<int> using MyExtensions)(first, 10);\n```\n\n## Speakable lowering\n\n``` c#\n// Static extension members\nvar range = MyExtensions.Range(0, 10);\nvar empty = MyExtensions.Empty;\nrange = MyExtensions.op_addition(range, 5);\nReadOnlySpan<int> span = MyExtensions.op_implicit(range); // Need target typing?\n\n// Instance extension members\nvar query = MyExtensions.Where(range, i => i < 10);\nvar isEmpty = MyExtensions.get_IsEmpty(query);\nvar first = MyExtensions.get_Item(query, 0);\nvar repetition = MyExtensions.__ctor_IEnumerable<int>(first, 10);\n```\n\n## Using clauses as statements\n\n``` c#\nusing static MyExtensions \n{\n    // Static extension members\n    var range = IEnumerable<int>.Range(0, 10);\n    var empty = IEnumerable<int>.Empty;\n    range += 5;\n    ReadOnlySpan<int> span = range;\n\n    // Instance extension members\n    var query = range.Where(i => i < 10);\n    var isEmpty = query.IsEmpty;\n    var first = query[0];\n    var repetition = new IEnumerable<int>(first, 10);\n}\n```\n\n- Doesn't address bypassing instance member\n\n\n``` c#\n// Static extension members\nvar range = MyExtensions.(IEnumerable<int>).Range(0, 10);\nvar empty = MyExtensions.(IEnumerable<int>).Empty;\nMyExtensions.(range) += 5;\nReadOnlySpan<int> span = MyExtensions.(range);\n\n// Instance extension members\nvar query = MyExtensions.(range).Where(i => i < 10);\nvar isEmpty = MyExtensions.(query).IsEmpty;\nvar first = MyExtensions.(query)[0];\nvar repetition = new MyExtensions.(IEnumerable<int>)(first, 10);\n```\n\n\n``` c#\n// Static extension members\nvar range = IEnumerable<int>.(MyExtensions).Range(0, 10);\nvar empty = IEnumerable<int>.(MyExtensions).Empty;\nrange.(MyExtensions) += 5;\nReadOnlySpan<int> span = range.(MyExtensions);\n\n// Instance extension members\nvar query = range.(MyExtensions).Where(i => i < 10);\nvar isEmpty = query.(MyExtensions).IsEmpty;\nvar first = query.(MyExtensions)[0];\nvar repetition = new IEnumerable<int>.(MyExtensions)(first, 10);\n```\n\n\n``` c#\n// Static extension members\nvar range = IEnumerable<int>.as(MyExtensions).Range(0, 10);\nvar empty = IEnumerable<int>.as(MyExtensions).Empty;\nrange.as(MyExtensions) += 5;\nReadOnlySpan<int> span = range.as(MyExtensions);\n\n// Instance extension members\nvar query = range.as(MyExtensions).Where(i => i < 10);\nvar isEmpty = query.as(MyExtensions).IsEmpty;\nvar first = query.as(MyExtensions)[0];\nvar repetition = new IEnumerable<int>.as(MyExtensions)(first, 10);\n```\n\n\n``` c#\n// Static extension members\nvar range = IEnumerable<int>.MyExtensions.Range(0, 10);\nvar empty = IEnumerable<int>.MyExtensions.Empty;\nrange.MyExtensions += 5;\nReadOnlySpan<int> span = range.MyExtensions;\n\n// Instance extension members\nvar query = range.MyExtensions.Where(i => i < 10);\nvar isEmpty = query.MyExtensions.IsEmpty;\nvar first = query.MyExtensions[0];\nvar repetition = new IEnumerable<int>.MyExtensions(first, 10);\n```\n- Doesn't allow giving the full name of `MyExtensions`\n\n\n``` c#\n// Static extension members\nvar range = IEnumerable<int>.in(MyExtensions).Range(0, 10);\nvar empty = IEnumerable<int>.in(MyExtensions).Empty;\nrange.in(MyExtensions) += 5;\nReadOnlySpan<int> span = range.in(MyExtensions);\n\n// Instance extension members\nvar query = range.in(MyExtensions).Where(i => i < 10);\nvar isEmpty = query.in(MyExtensions).IsEmpty;\nvar first = query.in(MyExtensions)[0];\nvar repetition = new IEnumerable<int>.in(MyExtensions)(first, 10);\n```\n\n\n\n``` c#\n// Static extension members\nvar range = IEnumerable<int>.at(MyExtensions).Range(0, 10);\nvar empty = IEnumerable<int>.at(MyExtensions).Empty;\nrange.at(MyExtensions) += 5;\nReadOnlySpan<int> span = range.at(MyExtensions);\n\n// Instance extension members\nvar query = range.at(MyExtensions).Where(i => i < 10);\nvar isEmpty = query.at(MyExtensions).IsEmpty;\nvar first = query.at(MyExtensions)[0];\nvar repetition = new IEnumerable<int>.at(MyExtensions)(first, 10);\n```\n\n"
  },
  {
    "path": "meetings/working-groups/extensions/extending-extensions-a-guide-to-relaxation.md",
    "content": "# Extending Extensions: A Guide to Relaxation\n\n## Summary\n\nThis proposal aims to describe a series of possible relaxations to the design presented by\n[anonymous extension declarations](https://github.com/dotnet/csharplang/blob/ac07118129334241b6a1dfa53a7e8c715b9ec0b1/meetings/working-groups/extensions/anonymous-extension-declarations.md).\nBecause that document lays out key design principles that this proposal builds upon, it should be considered required\nreading for this one.\n\n## Motivation\n\nThe anonymous extension declarations proposal provides an excellent solution to many of the challenges described in\n[the design space for extensions](https://github.com/dotnet/csharplang/blob/ac07118129334241b6a1dfa53a7e8c715b9ec0b1/meetings/working-groups/extensions/the-design-space-for-extensions.md).\nBy introducing the concept of an \"extension declaration\" declared anonymously within a static class to serve as a\ngrouping for extension members, it elegantly avoids the \"type explosion\" problem that has plagued other designs. This\nnew design ensures that extension members can be declared with a simple, familiar syntax while removing any rough edges\nthat would complicate consumption.\n\nThe design is based on a set of assumptions that are not necessarily agreed upon, but impose restrictions that bring\nclarity and simplicity to the design space. It is the belief of this author that some of these assumptions will not be\ntrue for all and the feature will feel restrictive in its current form.\n\nGenerally, the restrictions will be felt by those declaring extension members, not those consuming extension members.\nClassic extension methods offer a tremendous amount of flexibility with regard to the declaration and organization of\nmethods. In contrast, anonymous extension declarations design imposes limits that may serve as speed bumps to existing\nextension method authors. It is the goal of this proposal to identify opportunities to relax some of those restrictions\nwith the goal of providing a similar level of flexibility for anonymous extension declarations that classic extension\nmethods already enjoy.\n\nThis is approach is not unlike C# records. Positional records provide a simple and straightforward syntax that offer\ntype authors a broad set of functionality. However, during the design of records, it was realized that type authors\nneeded ways to customize records in various ways. And so, many features were introduced for type authors to serve as\n\"knobs\" when declaring records, such as init-only properties, Deconstruct methods, value-based equality customization,\nrequired properties, mutable and immutable struct-based records, etc.\n\n## Detailed design\n\n### Optional parameter name on an extension declaration\n\nThe anonymous extension declarations proposal makes the following assumption:\n\n> - Parameter names for underlying values aren't important and people will resent the forced verbosity of having to specify them.\n\nWhile this leads to a clear design, that assertion will not be true for all. Parameter names provide important value\nto a member’s signature and the code within.\n\n- Parameter names are an important form of self-documentation when the type system isn’t expressive enough to clearly\n  state the author's intent. For example, it is helpful when a parameter of type `Person` has the parameter name\n  `teacher`. This is a clear indicator to the caller what sort of `Person` to pass and helps make the code within the\n  member more readable.\n- Parameter names can synergize semantically with other parameter names. For example, the parameter name `source` might\n  be linked semantically to another parameter named `destination`.\n- Parameter names can be used to disambiguate overloads by applying a named argument.\n- Parameter names are important for XML documentation. Our own API documentation for the classic extension methods\n  defined on [`System.Linq.Enumerable`](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable) often have\n  different documentation for the `source` parameter. In addition, parameters are referenced by name via the\n  `<paramref name=\"name\"/>` XML doc comment tag.\n\nBy disallowing parameter names for an extension member’s \"receiver parameter\", programmers must use `this` to refer to\nthe underlying value. However, in some cases, that may result in code that uses `this` in ways that are less natural to\nmost users’ mental model of `this`. Consider the example taken from the anonymous extension declarations proposal below.\n\n``` c#\npublic static class Bits\n{\n    extension(ref ulong) // underlying value is passed by ref\n    {\n        public bool this[int index]\n        {\n            get => (this & Mask(index)) != 0;\n            set => this = value ? this | Mask(index) : this & ~Mask(index); // mutates underlying value\n        }\n    }\n    static ulong Mask(int index) => 1ul << index;\n}\n```\n\nThe code above uses `this` in a way that will be unfamiliar to most users. Most users aren’t aware that that `this` can\nbe assigned within a mutable struct, and users who *are* aware largely view it as a bad practice.\n\nTo relax this, consider an optional parameter name on the anonymous extension declaration.\n\n``` c#\npublic static class Bits\n{\n    extension(ref ulong number) // underlying value is passed by ref and called \"number\"\n    {\n        public bool this[int index]\n        {\n            get => (number & Mask(index)) != 0;\n            set => number = value ? number | Mask(index) : number & ~Mask(index); // mutates underlying value\n        }\n    }\n    static ulong Mask(int index) => 1ul << index;\n}\n```\n\nThe underlying type on the anonymous extension declaration corresponds strongly with a primary constructor, so it\nshould be clear to the programmer that the parameter name is accessible with the extension members.\n\nImportantly, adding a parameter name would disable the ability to use `this` within an extension member body. Instead,\nthe programmer must use the parameter name with all member bodies in the declaration. In addition, because `this` is no\nlonger available, it won't be possible to reference `this` implicitly either.\n\n``` c#\npublic static class Enumerable\n{\n    extension(IEnumerable source)\n    {\n        // Must use the parameter name to access the underlying value.\n        public bool IsEmpty => !source.GetEnumerator().MoveNext();\n\n        // Removing the parameter name would make it possible to use this, implicitly and explicitly.\n        // public bool IsEmpty => !this.GetEnumerator().MoveNext();\n        // public bool IsEmpty => !GetEnumerator().MoveNext();\n    }\n}\n```\n\nThis proposed relaxation does not imply that attributes targeting the underlying value parameter would be moved to the\nextension declaration. Instead, they would continue to be declared on the parameter using the\n`param` attribute specifier just as they are in the base design.\n\nUnfortunately, adding an optional parameter name at the top of the extension declaration means there’s another axis\nthat might force an extension author to need another declaration. If the author wants the `this` parameter name to\nchange between extension members within the same underlying type, they’ll need a declaration for each variation of the\nparameter name.\n\nThis can be solved with another relaxation.\n\n### Mixing underlying types within an extension declaration\n\nWhile the anonymous extension declaration proposal protects the consumer from the \"type explosion\" problem, that\nproblem is still very much alive for the extension author. The base proposal makes the following assumptions:\n\n> - Underlying types belong together with their type parameter declarations, and it would be confusing to separate them.\n> - People will resent the verbosity of having to repeat underlying types and accompanying type parameters for each member.\n\nThese assumptions drive a design in which all members within an extension declaration must share the same underlying\ntype for their `this` parameter, including nullable reference types. While it is possible that both of these\nassumptions may true, they will not be true for all.\n\nIt _may_ be confusing to separate underlying types from the their type parameter declarations. However, that depends\nlargely on the mental model a programmer develops for extensions. If they see extensions as a special form of type\ninheritance, it would indeed by confusing to separate type parameters from the type itself! However, if they view\nextensions as a new way to extension methods that allow for other members with a simpler syntax, they might not be so\nconfused.\n\nIt’s also true that people may resent having to repeat underlying types and accompanying type parameters for each\nmember. However, if the first assumption above is relaxed to allow the underlying type to be separated from their type\nparameters, the second assumption becomes much more palatable. And, classic extension methods require that the\nunderlying type be repeated for each method, and it is a massively popular feature.\n\nConsider the following classic extension methods from Roslyn’s public API:\n\n```c#\npublic static class CSharpExtensions\n{\n    public static bool IsKind(this SyntaxToken token, SyntaxKind kind) => ...;\n    public static bool IsKind(this SyntaxTrivia trivia, SyntaxKind kind) => ...;\n    public static bool IsKind([NotNullWhen(true)] this SyntaxNode? node, SyntaxKind kind) => ...;\n    public static bool IsKind(this SyntaxNodeOrToken nodeOrToken, SyntaxKind kind) => ...;\n    public static bool ContainsDirective(this SyntaxNode node, SyntaxKind kind) => ...;\n}\n```\n\nIf these were written using the base design, they would need to be declared across four extension declarations:\n\n```c#\npublic static class CSharpExtensions\n{\n    extension(SyntaxToken)\n    {\n        public bool IsKind(SyntaxKind kind) => ...;\n    }\n    \n    extension(SyntaxTrivia)\n    {\n        public bool IsKind(SyntaxKind kind) => ...;\n    }\n    \n    extension(SyntaxNode?)\n    {\n        [param: NotNullWhen(true)]\n        public bool IsKind(SyntaxKind kind) => ...;\n    }\n    \n    extension(SyntaxNodeOrToken)\n    {\n        public bool IsKind(SyntaxKind kind) => ...;\n    }\n    \n    extension(SyntaxNode)\n    {\n        public bool ContainsDirective(SyntaxKind kind) => ...;\n    }\n}\n```\n\nIt is this author’s belief that programmers will resent being forced to separate extension declarations by underlying\ntype. This resentment might even deepen for programmers who realize that all of the extension declarations above would\nlower to the same nested static class. A common question might be, if the compiler generates extension declarations to\nthe same type, why must they be declared in separate declarations?\n\nTo relax this restriction, consider allowing the parenthesized underlying types to be moved to the member declarations.\nMaking a correspondence with the reduced form of an extension method, the underlying types would be declared before the\nmember names with a `.` token.\n\n```c#\npublic static class CSharpExtensions\n{\n    extension\n    {\n        public bool (SyntaxToken).IsKind(SyntaxKind kind) => ...;\n        public bool (SyntaxTrivia).IsKind(SyntaxKind kind) => ...;\n        [param: NotNullWhen(true)]\n        public bool (SyntaxNode?).IsKind(SyntaxKind kind) => ...;\n        public bool (SyntaxNodeOrToken).IsKind(SyntaxKind kind) => ...;\n        public bool (SyntaxNode).ContainsDirective(SyntaxKind kind) => ...;\n    }\n}\n```\n\nThis expansion to the base design provides a similar level of grouping flexibility that programmers enjoy with\nclassic extension methods. In addition, the position chosen for a member-level underlying type works for all other\nextension member kinds, as well.\n\n```c#\npublic static class Extensions\n{\n    extension\n    {\n        // instance extension property\n        public bool (Digit).IsPrime => ...;\n\n        // instance extension indexer\n        public bool (Digit).this[int bit] => ...;\n\n        // instance extension event\n        public event EventHandler (Digit).BitFlipped\n        {\n            add => ...;\n            remove => ...;\n        }\n\n        // static extension method\n        public static int (int).FromBits(ReadOnlySpan<bool> bits) => ...;\n\n        // static extension property\n        public static Utf8StringComparer (StringComparer).OrdinalUtf8 => ...;\n\n        // static extension event\n        public static event EventHandler SystemEvents.NetworkConnected\n        {\n            add => ...;\n            remove => ...;\n        }\n\n        // operator overloads\n        public static Digit operator +(Digit d) => ...;\n        public static Digit operator +(Digit d1, Digit d2) => ...;\n        \n        // User-defined conversions\n        public static implicit operator byte(Digit d) => ...;\n        public static explicit operator Digit(byte b) => ...;\n    }\n}\n```\n\nInterestingly, there’s no need to provide declare the underlying type for an operator overload or user-defined\nconversion. It should be implicit from the signature.\n\nIt would still be possible to declare non-method extension members that use type parameters and constraints. However,\nsuch type parameters and constraints would go on the extension declaration. In addition, members within an extension\ndeclaration must use all type parameters on the declaration in order to be callable as an extension.\n\n```c#\npublic static class Extensions\n{\n    extension<T>\n    {\n        public bool (List<T>).IsEmpty => this.Count == 0;\n    }\n}\n```\n\nFinally, if an instance extension member is declared with its underlying type, the programmer can include a parameter\nname.\n\n```c#\npublic static class Extensions\n{\n    extension<T>\n    {\n        public bool (List<T> list).IsEmpty => list.Count == 0;\n    }\n}\n```\n\n## Unresolved Questions\n\n- It seems that an extension member that declares its own own underlying type and doesn’t depend on an external type\nparameter could be declared directly in the body of a static class. Is this useful, or would it be confusing?\n- The base design uses a model that is arguably closer to extension members rather than extension types. After all, the\n\"types\" are fully anonymous and transparent. Given that, would it be helpful to rename the \"extension\" keyword to\n\"extensions\"? Does it matter?\n- The base design lowers all extension declarations to a nested static class, even if a declaration doesn’t declare any\ntype parameters. If extension declarations are relaxed to allow the underlying type and parameter to be declared per\nmember, it seems that binary compatibility with classic extension methods could be achieved if non-generic extension\ndeclarations lowered to generic members in the static class body.\n- If a programmer declares an underlying type on one member, this proposal implies that means that _all_ members within\nan extension declaration must declare their underlying type. Is it possible to allow both the extension declaration and\nmembers declare an underlying type? In this case, the member would win and \"override\" the extension declaration’s\n\"default\" underlying type. This might help avoid the \"cliff\" of switching the underlying type from the extension\ndeclaration to it’s members. Or would this be too confusing for authors?\n- Is there a way that an extension author could declare a parameter name per member without moving the underlying type?"
  },
  {
    "path": "meetings/working-groups/extensions/extension-member-disambiguation.md",
    "content": "# Extension member disambiguation\n\nIt's possible for separate extensions to add identical extension members to the same underlying type. In those cases it's fairly tricky to pick one over the other. We've resolved to add a syntax to help with this, but we haven't decided what that syntax should be.\n\nHere are some requirements for a disambiguation syntax:\n\n- Usable with all kinds of extension members, not just those that use member access (`a.b`)\n- Specifies the static class where the desired extension member is declared\n\nThe easiest type of syntax to imagine is one where a receiver or operand expression is augmented with a \"start lookup here\" annotation of some sort.\n\nAn extension disambiguation syntax will also provide a way to target extension members that are otherwise hidden, e.g. by regular members or by other extension members that are \"closer\".\n\n### Scope\n\nExtension members are not the only place in the language where it would be helpful to be able to specify where to begin lookup. For instance, interface members cannot be directly invoked on values of classes and structs that implement the interface, and, especially for structs, casting the receiver has impact on both semantics (copying) and performance (allocation). Again, workarounds are tedious.\n\nWe should keep these broader scenarios in mind when selecting a syntax, even if we do not implement them yet beyond extensions.\n\n### Existing or new\n\nSome features today, such as casts or `as`, come pretty close to addressing the problem. Could we just bend them to this new scenario? Risks when using an existing syntax include breaking changes and user confusion. But new syntax is a steeper price to pay.\n\n## Candidates\n\nShown here with extension property and extension operator examples.\n\n- **Cast**: `((MyExtensions)e).Prop`, `((MyExtensions)e1) + e2`. Existing syntax, may clash with existing uses or cause breaks. May seem odd since `MyExtensions` isn't really a type. \n- **As-operator**: `(e as MyExtensions).Prop`, `(e1 as MyExtensions) + e2`. Existing syntax, may clash with existing uses or cause breaks. May seem odd since `MyExtensions` isn't really a type. \n- **Invocation syntax**: `MyExtensions(e).Prop`, `MyExtensions(e1) + e2`. Existing syntax, but less likely to break. May clash with proposed feature of implicit `new` in object construction. May be a confusing syntax overload. But very short and can have high precedence (primary expression) minimizing extraneous parentheses.\n- **At-operator**: `(e at MyExtensions).Prop`, `(e1 at MyExtensions) + e2`. New syntax, analogous to `as`. Possibly slightly breaking in corner cases.\n- **@-operator**: `(e @ MyExtensions).Prop`, `(e1 @ MyExtensions) + e2`. New syntax, glyph version of `at`. Possibly slightly breaking in corner cases.\n- **In-operator**: `(e in MyExtensions).Prop`, `(e1 in MyExtensions) + e2`. New syntax, Existing token. Possibly slightly breaking in corner cases.\n- **Using operator**: `(e using MyExtensions).Prop`, `(e1 using MyExtensions) + e2`. New syntax, existing token. Bring using-clauses to mind, but may clash conceptually with using statements. Possibly slightly breaking in corner cases.\n- **Qualified member**: `e.(MyExtensions.Prop)`, `e1 (MyExtensions.+) e2`. Needs a syntax for denoting every single kind of (extension) member. What does that look like for e.g. indexers, constructors and conversion operators?\n- ...\n\nLet's get more proposals on the table and discuss pros and cons.\n"
  },
  {
    "path": "meetings/working-groups/extensions/extension-members-unified-proposal.md",
    "content": "# Extension members\n\n## What's changed\n\nThis proposal is an update on [Anonymous extension declarations](https://github.com/dotnet/csharplang/blob/main/meetings/working-groups/extensions/anonymous-extension-declarations.md) in the following ways:\n\n- It leans into a parameter-style syntax for specifying the receiver.\n- It includes syntax for generating compatible extension methods.\n- It clarifies the goals of lowering, while leaving more details to implementation.\n\n### Receiver specification: `this` vs parameter\n\n The strongest sentiment I've heard is that whichever approach we take should be done *consistently*. Of the two there's a lean towards the parameter approach. This proposal leans into the parameter-based approach as strongly as it can.\n\n### Compatibility with classic extension methods\n\nThere is a clear desire to be able to move classic extension methods forward into new syntax without breaking existing callers. This proposal lets extension methods be marked for compatibility, which will cause them to generate visible static methods in the pattern of classic extension methods.\n\n### Lowering\n\nThe proposal takes the stance that the declarations generated from lowering - static methods and/or types - should be hidden from the language level, making extension members a \"real\" abstraction. The implementation strategy needs to establish metadata and rules that can be followed and consumed by other compilers, and that ensure stability and compatibility for consuming code as APIs evolve.\n\n## Declaration\n\n### Static classes as extension containers\n\nExtensions are declared inside top-level non-generic static classes, just like extension methods today, and can thus coexist with classic extension methods and non-extension static members:\n\n``` c#\npublic static class Enumerable\n{\n    // New extension declaration\n    extension(IEnumerable source) { ... }\n    \n    // Classic extension method\n    public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source) { ... }\n    \n    // Non-extension member\n    public static IEnumerable<int> Range(int start, int count) { ... } \n}\n```\n\n### Extension declarations\n\nAn extension declaration is anonymous, and provides a _receiver specification_ with any associated type parameters and constraints, followed by a set of extension member declarations. The receiver specification may be in the form of a parameter, or - if only static extension members are declared - a type:\n\n``` c#\npublic static class Enumerable\n{\n    extension(IEnumerable source) // extension members for IEnumerable\n    {\n        public bool IsEmpty { get { ... } }\n    }\n    extension<TSource>(IEnumerable<TSource> source) // extension members for IEnumerable<TSource>\n    {\n        public IEnumerable<T> Where(Func<TSource, bool> predicate) { ... }\n        public IEnumerable<TResult> Select<TResult>(Func<TSource, TResult> selector) { ... }\n    }\n    extension<TElement>(IEnumerable<TElement>) // static extension members for IEnumerable<TElement>\n        where TElement : INumber<TElement>\n    {\n        public static IEnumerable<TElement> operator +(IEnumerable<TElement> first, IEnumerable<TElement> second) { ... }\n    }\n}\n```\n\nThe type in the receiver specification is referred to as the _receiver type_ and the parameter name, if present, is referred to as the _receiver parameter_.\n\n### Extension members\n\nExtension member declarations are syntactically identical to corresponding instance and static members in class and struct declarations (with the exception of constructors). Instance members refer to the receiver with the receiver parameter name:\n\n``` c#\npublic static class Enumerable\n{\n    extension(IEnumerable source)\n    {\n        // 'source' refers to receiver\n        public bool IsEmpty => !source.GetEnumerator().MoveNext();\n    }\n}\n```\n\nIt is an error to specify an instance extension member (method, property, indexer or event) if the enclosing extension declaration does not specify a receiver parameter:\n\n``` c#\npublic static class Enumerable\n{\n    extension(IEnumerable) // No parameter name\n    {\n        public bool IsEmpty => true; // Error: instance extension member not allowed\n    }\n}\n```\n\n### Refness\n\nBy default the receiver is passed to instance extension members by value, just like other parameters. However, an extension declaration receiver in parameter form can specify `ref`, `ref readonly` and `in`, as long as the receiver type is known to be a value type. \n\nIf `ref` is specified, an instance member or one of its accessors can be declared `readonly`, which prevents it from mutating the receiver:\n\n``` c#\npublic static class Bits\n{\n    extension(ref ulong bits) // receiver is passed by ref\n    {\n        public bool this[int index]\n        {\n            set => bits = value ? bits | Mask(index) : bits & ~Mask(index); // mutates receiver\n            readonly get => (bits & Mask(index)) != 0;                // cannot mutate receiver\n        }\n    }\n    static ulong Mask(int index) => 1ul << index;\n}\n```\n\n### Nullability and attributes\n\nReceiver types can be or contain nullable reference types, and receiver specifications that are in the form of parameters can specify attributes:\n\n``` c#\npublic static class NullableExtensions\n{\n    extension(string? text)\n    {\n        public string AsNotNull => text is null ? \"\" : text;\n    }\n    extension([NotNullWhen(false)] string? text)\n    {\n        public bool IsNullOrEmpty => text is null or [];\n    }\n    extension<T> ([NotNull] T t) where T : class?\n    {\n        public void ThrowIfNull() => ArgumentNullException.ThrowIfNull(t);\n    }\n}\n```\n\n### Compatible extension methods\n\nBy default, extension members are lowered in such a way that the generated artifacts are not visible at the language level. However, if the receiver specification is in the form of a parameter and specifies the `this` modifier, then any extension instance methods in that extension declaration will generate visible classic extension methods.\n\nSpecifically the generated static method has the attributes, modifiers and name of the declared extension method, as well as type parameter list, parameter list and constraints list concatenated from the extension declaration and the method declaration in that order:\n\n``` c#\npublic static class Enumerable\n{\n    extension<TSource>(this IEnumerable<TSource> source) // Generate compatible extension methods\n    {\n        public IEnumerable<TSource> Where(Func<TSource, bool> predicate) { ... }\n        public IEnumerable<TSource> Select<TResult>(Func<TSource, TResult> selector)  { ... }\n    }\n}\n```\n\nGenerates:\n\n``` c#\npublic static class Enumerable\n{\n    public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { ... }\n    public static IEnumerable<TSource> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)  { ... }\n}\n```\n\nThis does not change anything else about how the declared extension method works. However, adding the `this` modifier may lead to a binary break for consumers because the generated artifact may change.\n\n### Constructors\n\nConstructors are generally described as an instance member in C#, since their body has access to the newly created value through the `this` keyword. This does not work well for the parameter-based approach to instance extension members, though, since there is no prior value to pass in as a parameter.\n\nInstead, extension constructors work more like static factory methods. They are considered static members in the sense that they don't depend on a receiver parameter name. Their bodies need to explicitly create and return the construction result. The member itself is still declared with constructor syntax, but cannot have `this` or `base` initializers and does not rely on the receiver type having accessible constructors.\n\nThis also means that extension constructors can be declared for types that have no constructors of their own, such as interfaces and enum types:\n\n``` c#\npublic static class Enumerable\n{\n    extension(IEnumerable<int>)\n    {\n        public static IEnumerable(int start, int count) => Range(start, count);\n    }\n    public static IEnumerable<int> Range(int start, int count) { ... } \n}\n```\n\nAllows:\n\n```\nvar range = new IEnumerable<int>(1, 100);\n```\n\n### Operators\n\nAlthough extension operators have explicit operand types, they still need to be declared within an extension declaration:\n\n``` c#\npublic static class Enumerable\n{\n    extension<TElement>(IEnumerable<TElement>) where TElement : INumber<TElement>\n    {\n        public static IEnumerable<TElement> operator *(IEnumerable<TElement> vector, TElement scalar) { ... }\n        public static IEnumerable<TElement> operator *(TElement scalar, IEnumerable<TElement> vector) { ... }\n    }\n}\n```\n\nThis allows type parameters to be declared and inferred, and is analogous to how a regular user-defined operator must be declared within one of its operand types.\n\n## Checking\n\n__Inferrability:__ All the type parameters of an extension declaration must be used in the receiver type. This makes it always possible to infer the type arguments when applied to a receiver of the given receiver type.\n\n__Uniqueness:__ Within a given enclosing static class, the set of extension member declarations with the same receiver type (modulo identity conversion and type parameter name substitution) are treated as a single declaration space similar to the members within a class or struct declaration, and are subject to the same [rules about uniqueness](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/classes.md#153-class-members).\n\n``` c#\npublic static class MyExtensions\n{\n    extension<T1>(IEnumerable<int>) // Error! T1 not inferrable\n    {\n        ...\n    }\n    extension<T2>(IEnumerable<T2>)\n    {\n        public bool IsEmpty { get ... }\n    }\n    extension<T3>(IEnumerable<T3>?)\n    {\n        public bool IsEmpty { get ... } // Error! Duplicate declaration\n    }\n}\n```\n\nThe application of this uniqueness rule includes classic extension methods within the same static class. For the purposes of comparison with methods within extension declarations, the `this` parameter is treated as a receiver specification along with any type parameters mentioned in that receiver type, and the remaining type parameters and method parameters are used for the method signature:\n\n``` c#\npublic static class Enumerable\n{\n    public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source) { ... }\n    \n    extension(IEnumerable source) \n    {\n        IEnumerable<TResult> Cast<TResult>() { ... } // Error! Duplicate declaration\n    }\n}\n```\n\n## Consumption\n\nWhen an extension member lookup is attempted, all extension declarations within static classes that are `using`-imported contribute their members as candidates, regardless of receiver type. Only as part of resolution are candidates with incompatible receiver types discarded. A full generic type inference is attempted between the type of the actual receiver and any type parameters in the declared receiver type.\n\nThe inferrability and uniqueness rules mean that the name of the enclosing static type is sufficient to disambiguate between extension members on a given receiver type. As a strawman, consider `E @ T` as a disambiguation syntax meaning on a given expression `E` begin member lookup for an immediately enclosing expression in type `T`. For instance:\n\n``` c#\nstring[] strings = ...;\nvar query  = (strings @ Enumerable).Where(s => s.Length > 10);\n \npublic static class Enumerable\n{\n    extension<T>(IEnumerable<T>)\n    {\n        public IEnumerable<T> Where(Func<T, bool> predicate) { ... }\n    }\n}\n```\n\nMeans lookup `Where` in the type `Enumerable` with `strings` as its receiver. A type argument `string` can now be inferred for `T` from the type of `strings` using standard generic type inference.\n\nA similar approach also works for types: `T1 @ T2` means on a given type `T1` begin static member lookup for an immediately enclosing expression in type `T2`.\n\nThis disambiguation approach should work not only for new extension members but also for classic extension methods.\n\nNote that this is not a proposal for a specific disambiguation syntax; it is only meant to illustrate how the inferrability and uniqueness rules enable disambiguation without having to explicitly specify type arguments for an extension declaration's type parameters.\n\n## Lowering\n\nThe lowering strategy for extension declarations is not a language level decision. However, beyond implementing the language semantics it must satisfy certain requirements:\n\n- The format of generated types, members and metadata should be clearly specified in all cases so that other compilers can consume and generate it.\n- The generated artifacts should be hidden from the language level not just of the new C# compiler but of any existing compiler that respects CLI rules (e.g. modreq's).\n- The generated artifacts should be stable, in the sense that reasonable later modifications should not break consumers who compiled against earlier versions.\n\nThese requirements need more refinement as implementation progresses, and may need to be compromised in corner cases in order to allow for a reasonable implementation approach.\n\n## Order of implementation\n\nWe do not need to implement all of this design at once, but can approach it one or a few member kinds at a time. Based on known scenarios in our core libraries, we should work in the following order:\n\n1. Properties and methods (instance and static)\n2. Operators\n3. Indexers (instance and static, may be done opportunistically at an earlier point)\n4. Anything else\n\n## Future work\n\n### Disambiguation\n\nWe still need to settle on a disambiguation syntax. Per the above it needs to be able to take a receiver expression or type, as well as the name of a static class from which to begin member lookup. However, the feature does not have to be extension-specific. There are several cases in C# where it's awkward to get to the right member of a given receiver. Casting often works, but can lead to boxing that may be too expensive or lead to mutations being lost.\n\nIt would probably be unfortunate to ship extension members without a disambiguation syntax, so this has high priority.\n\n### Shorter forms\n\nThe proposed design avoids per-member repetition of receiver specifications, but does end up with extension members being nested two-deep in a static class _and_ and extension declaration. It will likely be common for static classes to contain only one extension declaration or for extension declarations to contain only one member, and it seems plausible for us to allow syntactic abbreviation of those cases.\n\n__Merge static class and extension declarations:__\n\n``` c#\npublic static class EmptyExtensions : extension(IEnumerable source)\n{\n    public bool IsEmpty => !source.GetEnumerator().MoveNext();\n}\n```\n\nThis ends up looking more like what we've been calling a \"type-based\" approach, where the container for extension members is itself named.\n\n__Merge extension declaration and extension member:__ \n\n``` c#\npublic static class Bits\n{\n    extension(ref ulong bits) public bool this[int index]\n    {\n        get => (bits & Mask(index)) != 0;\n        set => bits = value ? bits | Mask(index) : bits & ~Mask(index);\n    }\n    static ulong Mask(int index) => 1ul << index;\n}\n \npublic static class Enumerable\n{\n    extension<TSource>(IEnumerable<TSource> source) public IEnumerable<TSource> Where(Func<TSource, bool> predicate) { ... }\n}\n```\n\nThis ends up looking more like what we've been calling a \"member-based\" approach, where each extension member contains its own receiver specification. \n\n"
  },
  {
    "path": "meetings/working-groups/extensions/extensions-an-evolution-of-extension-methods.md",
    "content": "# Extensions: An Evolution of Extension Methods\n\n* [x] Proposed\n* [ ] Prototype\n* [ ] Implementation\n* [ ] Specification\n\n## Summary\n[summary]: #summary\n\nThis proposal presents a design for \"extension everything\" as an evolution of classic extension methods and allows for\nfuture expansion.\n\n### Goals\n- Describe a new syntax for extension members that scales to member kinds beyond just instance methods.\n- Provide support for all functionality available to classic extension methods.\n- Guarantee binary and source compatibility for classic extension method scenarios in the new syntax.\n- Design support for the highest value extension member kinds that have the best chance of being implemented in the\n  C# 14 timeframe.\n- Lay the design groundwork for further extension member kinds, if or when the scenarios are compelling enough\n  to pursue.\n\n### Non-Goals\n- Do not consider syntax for a possible future “roles” or \"explicit extensions\" feature. This proposal assumes that\n  “extensions” and “roles” have no dependency on one another. However, it allows for future synergy through additional\n  language features.\n- Do not consider syntax to allow type parameters on member kinds that do not support them today. Although, this could\n  be supported by future work.\n\n## Motivation\n[motivation]: #motivation\n\n[Extension methods](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods)\nare wildly popular! They first appeared in C# 3 as a smallish feature intended to support the syntactic rewrites of\nLINQ’s query expression syntax[^1]. However, over the past 15+ years, extension methods have cemented themselves as a\ncrucial part of the C# developer toolkit.\n\nA key reason for extension methods' popularity is the their inherent discoverability. Once a set of extension methods\nare brought into scope, they can be discovered in IntelliSense simply by typing `.` after an expression. This\ndiscoverability makes extension methods a powerful way to define important helpers within a code base or provide public\nAPI surface for a library. Extension methods have been used to simplify interface implementation[^2], as a tool to\nlayer public API surface area[^3], and even to implement domain-specific languages (DSLs)[^4].\n\nIn the ten(!) C# releases since their introduction, extension methods have received some small improvements. For\nexample, C# 6 added the `static` modifier for using directives, allowing a type’s static members to be brought into\nscope, including extension methods. C# 7.2 introduced support for `this ref` on extension methods targeting value\ntypes. However, in all that time, there haven’t been any new extension members kinds added to C#, though there has\ncertainly been a consistent stream of requests for them.\n\nOver the years, the C# language design team has received many requests for *extension properties*. Initially, extension\nproperties might seem straightforward but they present several challenges. The most glaring issue is that properties\ndon’t have a parameter list, so there isn’t an obvious place to declare a `this` parameter. However, even if that were\nsolved, C# properties cannot declare generic type parameters. Without a way to define a generic type parameter on an\nextension property, it would be impossible to declare an `IsEmpty` property for `IEnumerable<T>`. And of course, once\nthose issues are addressed (along with generic property type inference and the inevitable overload resolution work),\nwhy would we stop at extension properties? The next step would clearly be to add instance and static generic\nproperties. Given that, extension properties trigger a bit of an avalanche of design issues that lead to a much larger\nC# feature that feels a bit niche and only saves the programmer a pair of empty parentheses. This has never seemed\nworth the investment.\n\nIn addition, there a long-standing request from the .NET libraries team for *static extension methods*. Extension\nmethods that are accessible through member access on a type open up new API composition scenarios. Imagine how powerful\nit would be to add a package reference to a .NET project and have new static methods accessible from `string` related\nto that package's domain! Unfortunately, a natural syntax to declare a static extension method that derives from\nclassic extension method syntax has proven elusive. After all, extension methods are already declared as static\nmethods. Would a static extension method be `static static` or maybe require an extra attribute? Also, the `this`\nparameter wouldn’t make sense, since a static extension method wouldn’t be passed an instance of the type. Then where\nwould the target type go? Clearly, a new syntax is needed to support static extension methods but what happens to\nclassic extension methods? Are there two radically different syntaxes?\n\nThis proposal aims to solve these issues and more through a new declaration syntax specially tailored for extension\nmembers.\n\n## Detailed design\n[design]: #detailed-design\n\n### The Extension Container\n\nExtension members are declared in a new type declaration called an *extension container*.\n\n```antlr\nextension_container_declaration\n    : attributes? extension_container_modifier* 'partial'? 'extensions' identifier type_parameter_list? for_clause? type_parameter_constraints_clause* extension_container_body ';'?\n    ;\n\nextension_container_modifier\n    : 'public'\n    | 'internal'\n    | unsafe_modifier   // unsafe code support\n    ;\n    \nfor_clause\n    : 'for' type\n    ;\n\nextension_container_body\n    : '{' extension-container-member* '}'\n    ;\n\nextension-container-member\n    : extension_member_declaration\n    | class_member_declaration\n    ;\n\nextension_member_declaration\n    : extension_method_declaration\n    | extension_property_declaration\n    ;\n```\n\nBelow are a few examples of extension containers:\n\n```C#\nextensions E\n{\n}\n\nextensions E<T>\n{\n}\n\nextensions E for string\n{\n}\n\nextensions E<T> for T where T : IEquatable<T>\n{\n}\n```\n\nAn extension container compiles to a type that is similar to a [static class](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/classes#15224-static-classes),\nwhich is necessary for binary compatibility. It can't inherit from a base type, implement interfaces, and can only be\nreferenced in the same ways that a static class can. Using the plural `extensions` as a keyword is an important\ndistinction from other proposals that prefer `extension`. The `extensions` keyword makes it clear that this is a\ncontainer for members and not an entity that a programmer generally needs to be concerned with, except for situations\nwhere disambiguation is required[^5].\n\nWithin an extension container body, there can be both extension members and regular static members (the same set that\nare supported by static classes). There is no restriction on the type that an extension member can target (i.e. the\n\"receiver type\") unless the programmer provides an optional _for-clause_. A _for-clause_ specifies a type that applies\nto all extension members declared within the container. If a _for-clause_ type references a type parameter (e.g.\n`IEnumerable<T>`), that type parameter must be declared on the extension container[^6].\n\n### Instance Extension Methods\n\nThe syntax used to declare a classic extension method starts with a static method on a static class and adds a `this`\nkeyword to the first parameter that anoints it as the receiver type. From a conceptual point of view, the programmer\nsees an extension method for what it really is: a static method that can be reduced syntactically when invoked to\nappears as if it were an instance method.\n\nHere's an example of a set of classic extension methods from Roslyn:\n\n```C#\npublic static partial class Extensions\n{\n    public static SourceTextContainer AsTextContainer(this ITextBuffer buffer)\n        => TextBufferContainer.From(buffer);\n\n    internal static TextLine AsTextLine(this ITextSnapshotLine line)\n        => line.Snapshot.AsText().Lines[line.LineNumber];\n}\n```\n\nThe syntax for instance extension methods within an extension container take the opposite approach. They are declared\nas instance methods, but the receiver parameter is moved *before* the method name and no longer requires the `this`\nmodifier. In this way, the receiver parameter is given more importance and the syntax looks similar to how it is\nexpected to be invoked.\n\n```C#\npublic partial extensions Extensions\n{\n    public SourceTextContainer (ITextBuffer buffer).AsTextContainer()\n        => TextBufferContainer.From(buffer);\n\n    internal TextLine (ITextSnapshotLine line).AsTextLine()\n        => line.Snapshot.AsText().Lines[line.LineNumber];\n}\n```\n\nWhen a _for-clause_ is included on the extension container, an instance extension method does not need to restate the\ntype from the _for-clause_. And, if there aren't any attributes or modifiers, the parentheses aren't needed, making a\nsyntactic connection to the single parameter form of a lambda expression.\n\n```C#\ninternal partial extensions ProjectExtensions for Project\n{\n    public Document project.GetRequiredDocument(DocumentId documentId)\n        => project.GetDocument(documentId) ?? throw new ...;\n\n    public Document project.GetRequiredDocument(SyntaxTree tree)\n        => project.GetDocument(tree) ?? throw new ...;\n\n    public TextDocument project.GetRequiredAdditionalDocument(DocumentId documentId)\n        => project.GetAdditionalDocument(documentId) ?? throw new ...;\n}\n```\n\nFor compatibility, all of the examples above compile to the same metadata as their equivalent classic extension method\nsyntax.\n\n> [!NOTE]\n> This proposal suggests a succinct syntax that allows just the receiver parameter name followed by `.`. There are\n> other possibilities called out [below](#unresolved-questions).\n\nThe following grammar describes the syntax for an instance extension method declared in an extension container.\n\n```antlr\nextension_method_declaration\n    : attributes? method_modifiers return_type extension_method_header method_body\n    | attributes? ref_method_modifiers ref_kind ref_return_type extension_method_header ref_method_body\n    ;\n\nextension_method_header\n    : receiver_parameter '.' member_name '(' parameter_list? ')'\n    | receiver_parameter '.' member_name type_parameter_list '(' parameter_list? ')' type_parameter_constraints_clause*\n    ;\n\nreceiver_parameter\n    : '(' attributes? receiver_mode_modifier? type? identifier ')'\n    | identifier\n    | type\n    ;\n\nreceiver_mode_modifier\n    | 'ref'\n    | 'ref readonly'\n    | 'in'\n```\n\n### Static Extension Methods\n\nThe ability to declare a static extension method for a type is a long-standing ask from the .NET libraries team. This\nprovides new API layering possibilities and could provide new avenues for offering APIs down-level. Consider the \n[`string.Create(...)` method](https://learn.microsoft.com/en-us/dotnet/api/system.string.create?view=net-8.0#system-string-create-1(system-int32-0-system-buffers-spanaction((system-char-0))))\nthat was added in .NET Core 2.1.\n\n```C#\npublic sealed partial class String\n{\n    public static string Create<TState>(int length, TState state, SpanAction<char, TState> action)\n    {\n    }\n}\n```\n\nIf static extension methods had been available, it would have been possible to define this method in a .NET package\nthat included down-level support[^7] like so.\n\n```C#\npublic partial extensions Extensions\n{\n    public static string string.Create<TState>(int length, TState state, SpanAction<char, TState> action)\n    {\n    }\n}\n```\n\nLike an instance extension method's receiver parameter, it is necessary to state the target type of the static\nextension method before the method name[^8]. This allows the declaration syntax to align with the calling syntax. A\ndownside is that the type must be restated even if an optional _for-clause_ is defined, but this seems a small price to\nallow regular static members alongside static extension methods.\n\n### Extension Properties\n\nThe design for instance and static extension properties largely fall out of the design framework described used for\nextension methods above.\n\n```antlr\nextension_property_declaration\n    : attributes? property_modifier* type extension_property_header property_body\n    | attributes? property_modifier* ref_kind type extension_property_header ref_property_body\n    ;\n    \nextension_property_header\n    : receiver_parameter '.' name\n    ;\n```\n\nHere are a couple of examples selecting from existing Roslyn extension methods that could be declared as extension\nproperties.\n\n```C#\ninternal extensions IComparerExtensions<T> for IComparer<T>\n{\n    public IComparer<T> comparer.Inverse => new InverseComparer<T>(comparer)\n}\n\ninternal extensions ISymbolExtensions for ISymbol\n{\n    public bool ([NotNullWhen(true)] ISymbol? symbol).IsImplicitValueParameter\n        => ...;\n}\n\ninternal extensions CompilationExtensions for Compilation\n{\n    public INamedTypeSymbol? compilation.AttributeType\n        => compilation.GetTypeByMetadataName(typeof(Attribute).FullName!);\n\n    public INamedTypeSymbol? compilation.ExceptionType\n        => compilation.GetTypeByMetadataName(typeof(Exception).FullName!);\n\n    public INamedTypeSymbol? compilation.EqualityComparerOfTType\n        => compilation.GetTypeByMetadataName(typeof(EqualityComparer<>).FullName!);\n\n    public INamedTypeSymbol? compilation.ActionType\n        => compilation.GetTypeByMetadataName(typeof(Action).FullName!);\n}\n```\n\nStatic extension properties may prove to be less common as static properties are less common in general. However, there\nare still interesting cases! Consider the following extension method defined by the\n[Fluent Assertions library](https://fluentassertions.com/typesandmethods/).\n\n```C#\npublic static class AssertionExtensions\n{\n    public static TypeAssertions Should(this Type subject)\n    {\n        return new TypeAssertions(subject);\n    }\n}\n```\n\nThat extension method is intended to be called like so:\n\n``` C#\ntypeof(MyBaseClass).Should().BeAbstract();\n```\n\nIf static extension properties were available when this library were defined, the Fluent Assertions DSL could have been\ndesigned to require less ceremony.\n\n```C#\npublic static class AssertionExtensions<T> for T\n{\n    public static TypeAssertions T.Should\n    {\n        return new TypeAssertions(typeof(T));\n    }\n}\n\n// Usage:\nMyBaseClass.Should.BeAbstract;\n```\n\n### Inference\n\nFor scenarios where the extension container doesn't declare a type parameter, existing type inference for extension\nmethods should be sufficient. If the extension container does declare a type parameter, an additional inference step\nwill be required to determine what extension containers apply for a given receiver. Consider the following code.\n\n```C#\nvar numbers = new List<int>();\n\nforeach (var text in numbers.ToFormattedStrings(\"x8\"))\n{\n    Console.WriteLine(text);\n}\n\nextensions EnumerableExtensions<T> for IEnumerable<T> where T : IFormattable\n{\n    public IEnumerable<string> source.ToFormattedStrings(string format)\n        => source.Select(x => x.ToString(format, formatProvider: null));\n}\n```\n\nIn this example, the compiler would need to first determine that `EnumerableExtensions<T>` is an appliable extension\ntype for `List<int>`. Then, applicable extension methods could be chosen and normal overload resolution would\ncontinue.[^9]\n\n### Disambiguation\n\nFor static extension methods and properties, disambiguation falls out. The programmer can simply call the member on the\nextension container directly. For instance extension methods, it is possible to disambiguate by using the same static\ninvocation syntax as classic extension methods. However, it will be necessary to add a general unifying disambiguation\nsyntax at the call site to account for other scenarios. Below are a few strawman proposals:\n\n#### Cast-style syntax\n\nBecause an extension container is really a type, it seems reasonable to allow it to be used with a _cast-expression_ to\ndisambiguate:\n\n```C#\n((Extensions)instance).Prop = 42;\nConsole.WriteLine(((Extensions)instance).Prop);\n```\n\n#### Invocation-style syntax\n\nSince an extension container cannot have instance constructors, it seems reasonable to consider a syntax based on a\nnormal invocation.\n\n```C#\nExtensions(instance).Prop = 42;\nConsole.WriteLine(Extensions(instance).Prop);\n```\n\nThis _might_ have some problems to sort out, but it seems possible.\n\n#### Alias-qualified syntax\n\nAn underused C# why to qualify C# types is the `::` operator. Currently, this can be used whenever the left-hand side\nis a namespace alias, extern alias, or the `global` alias. We could consider allowing the left-hand side to also be an\nextension container.\n\n```C#\nExtensions::instance.Prop = 42;\nConsole.WriteLine(Extensions::instance.Prop);\n```\n\nCurrently, the left-hand side can identifier. To support this, that operator would need to allow a fully-qualified\ngeneric type name, which might also be alias-qualified. However, perhaps this idea might lead to others?\n\n## Future Work\n\n### More Member Kinds!\n\nThe goal of this proposal was to cover instance and static methods and properties, providing a design framework that\ncould be used to add other member kinds if the scenarios requiring them are important. Using a similar approach, it\nshould not be too difficult to provide syntax for other member kinds. For example:\n\n``` C#\nextensions E for int\n{\n    public bool number.this[int bit] => ...;\n\n    public event Action number.NonsenseEvent\n    {\n        add => ...;\n        remove => ...;\n    }\n\n    public static event Action int.NonsenseEvent\n    {\n        add => ...;\n        remove => ...;\n    }\n\n    public static operator +(int x, string y) => ...;\n\n    public static implicit operator int(string x) => ...;\n}\n```\n\nInstance indexers are straightforward and would likely be useful. Events are possible, but similar to extension\nproperties, they would require `add` and `remove` accessors to avoid creating state that wouldn't flow with the\nreceiver.\n\nNote that operators overloads and user-defined conversions are declared using the same syntax as always. It is not\nlegal to write an operator overload for an extension type, so the syntax is open to be used. However, one of operands\nmust match the type in the _for-clause_.\n\n### Roles and Interfaces!\n\nAn alternate proposal for extensions explores a type-based approach in two related flavors: implicit and explicit\nextensions. Recently, these have been re-renamed back to \"extensions\" (implicit extensions) and \"roles\" (explicit\nextensions) to avoid confusion and might their conceptual differences clearer. This proposal provides a new design for\n\"extensions\" as an evolution of classic extension methods that is fully disconnected from \"roles\". However, it's still\npossible to bring some synergy back in the future if roles do become part of C#.\n\nIf roles manifest as light weight wrappers around an instance of an underlying type and eventually allow interface\nimplementation, it's possible that an extension container could leverage roles to provide a future \"extension\ninterface\". This is bit hand-wavey it's unclear what shape roles will ultimately take, but there is at least a\n_possible_ universe where something like the following code could be made to work, possibly by generating an anonymous\nrole under-the hood.\n\n``` C#\npublic extensions E for string : IDisposable\n{\n    public void s.Dispose()\n    {\n       \n    }\n}\n```\n\nThe purpose here is not to promise anything or solve all of the potential issues (like ambiguity with explicit\ninterface implementation). The intention is to show that there can still be a path to synergy between extensions, as\npresented by this proposal, and roles, if and when they become a part of the C# language.\n\n## FAQ\n\n### What about allowing `this` for member access?\n\nOther proposals allow the programmer to use `this` within an instance extension member body to refer to the receiver\ntype. Additionally, unqualified member accesses implicitly binds to `this` to create the illusion that the user is\nreally typing in an instance method inside of a type. Unfortunately, that approach is incongruent with classic\nextension methods and loses important semantic detail that might be provided by a name. For example, it's useful to\nknow that the `string` being operated on is actually `articleText` and not just any `string`.\n\nIn this proposal, it is assumed that extension methods are well-understood by C# programmers as fancy static methods.\nSo unqualified member access in an extension member should has static access within the extension container, allowing\naccess to all other static members and extension members. In addition, the programmer can always access the receiver\nparameter in an instance extension method by name.\n\n### Can non-method extension members declare generic type members?\n\nNo! As mentioned in the non-goals section, this proposal does not attempt to allow type parameters to be added to\nextension members that can't already support them. A key reason for this is that doing the work to support type\nparameters on, say, extension properties would be strange if weren't adding them for normal instance and static\nproperties as well. And, doing that is well-beyond the scope of extensions. If we ever allow type parameters to be\ndeclared on regular properties, we should also allow them for extension properties.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\n<!-- Why should we *not* do this? -->\n\n## Alternatives\n[alternatives]: #alternatives\n\n<!-- What other designs have been considered? What is the impact of not doing this? -->\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n<!-- What parts of the design are still undecided? -->\n\n- **Should the receiver parameter _always_ be parenthesized rather than allowing `<identifier>.`**?\n\n  This is definitely something to consider. It seems reasonable to parenthesize the receiver parameter and remove\n  the '.' for instance extension members.\n  \n  ```C#\n  extensions StringExtensions for string\n  {\n      public bool ([NotNullWhen(false)] string? s) IsNullOrEmpty => ...;\n      \n      public int (text) CountWord(string word) => ...;\n  }\n  ```\n\n- **Should the receiver parameter _always_ be required to state the type**?\n\n  This is related to the question above. To some, it might seem too irregular in a method declaration to declare a\n  parameter with just the name and no type. To be more regular with other top-level declarations,  the `.` for instance\n  extension members as well. Merging that with the syntax above would look something like this:\n  \n  ```C#\n  extensions StringExtensions for string\n  {\n      public bool ([NotNullWhen(false)] string? s) IsNullOrEmpty => ...;\n      \n      public int (string text) CountWord(string word) => ...;\n  }\n  ```\n\n- **What syntax should be used for disambigation?**\n\n  As shown [above](#Disambiguation), there are many syntactic possibilities for disambiguating an extension and this\n  proposal only suggests a few. Conceptually, it feels like the invocation-style syntax aligns best for instance\n  extensions by embracing the importance this design places on the receiver parameter. However, this is yet undecided.\n  \n- **Can an extension container declare generic type parameters without a _for-clause_**?\n  \n  This should be feasible but would need a restriction that all extension members use all of the type parameters\n  somewhere in their receiver parameter or remaining parameter list. Otherwise, it will not be possible to infer the\n  type arguments for the extension container from the call site, making an extension member uncallable in reduced form. \n  It seems reasonble to issue a warning if an instance extension member could would not be callable with instance\n  syntax.\n  \n  ```C#\n  extensions E<T>\n  {\n      public void (IComparable<T> obj) M1(); // Firne\n      public int (string s) M2(IEnumerable<T> items); // Fine\n      \n      public T M3(); // Works with disambiguation, but issue a warning.\n  }\n  ```\n\n## Design meetings\n\n<!-- Link to design notes that affect this proposal, and describe in one sentence for each what changes they led to. -->\n\n[^1]: For example, the query expression, `from x in Enumerable.Range(1, 10) select x * x` is rewritten syntactically at\ncompile-time as `Enumerable.Range(1, 10).Select(x => x * x)`. The `Enumerable.Select(...)` extension method ensure that\nthis rewrite compiles.\n[^2]: Consider the [`ILogger`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.logging.ilogger)\ninterface, which only has three interface members that need to be implemented. A much larger API surface is available\nfor an `ILogger` implementation by the 29 (as of this writing) extension methods defined by [`LoggerExtensions`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.logging.loggerextensions)\nin the same `Microsoft.Extensions.Logging` namespace.\n[^3]: Roslyn's public API uses extension methods to provide separate API sets for C# and Visual Basic across a common\nset of types.\n[^4]: For an example of a domain-specific language implemented almost entirely with extensions, consider\n[Fluent Assertions](https://fluentassertions.com/).\n[^5]: One possible expansion of this proposal would be to allow for nameless extension containers, though such\nextension containers would have no means of disambiguation.\n[^6]: Taking a cue from classic extension methods, this proposal assumes that an extension container can't be nested\nwithin another type. If that restriction is loosened, it would be possible for a _for-clause_ to reference a type\nparameter from an enclosing type.\n[^7]: Adding `string.Create(...)` as a static extension method might not have been advisable when it was introduced.\nThe point made by this proposal is that it would have been _possible_.\n[^8]: This is syntactic similarity to explicitly-implemented interface members. However, since an extension container\ncannot implement interfaces, this approach does not introduce an ambiguity.\n[^9]: I'm pretty sure this is a *gross* oversimplification. `#notacsharpcompilerengineer`"
  },
  {
    "path": "meetings/working-groups/extensions/extensions-as-static-types.md",
    "content": "\n# Extensions as static types\n\n* [x] Proposed\n* [ ] Prototype: Not Started\n* [ ] Implementation: Not Started\n* [ ] Specification: Not Started\n\n## Summary\n[summary]: #summary\n\nDisallow use of an extension as an instance type. Just like static classes this means that it cannot be the type of a value or variable, and cannot be a type parameter.\n\n## Motivation\n[motivation]: #motivation\n\nA large part of the complexity of the roles and extensions pair of features comes from allowing them as types of values. For roles, that is the core of the feature; an indispensable part of the design. For extensions, however, their \"typeness\" is a more peripheral aspect, mainly to do with disambiguation. If we can live without those aspects of the extension feature, we can ship it faster and with less implementation complexity and risk. This does not prevent us from adding roles later, and in the process \"upgrading\" extensions to also be instance types. It allows us to further stratify the work across multiple waves of effort.\n\n## Detailed design\n[design]: #detailed-design\n\nSeparate out the design for extensions from that for roles. Disallow the use of extension types as the type of values and variables, including in variable and member declarations, cast expressions, and as type arguments.\n\nInside extension declarations, change the type of `this` to be the underlying type rather than the extension type. Other members of the extension can still be accessed on (implicit or explicit) `this`, as they show up as extension members on the underlying type.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\n### The type of `this` in extension declarations\n\nIn the current design, the type of `this` in an extension declaration is the extension type itself. This enables inheritance-like lookup behavior, where the members of the extension take precedence over the members of the underlying type. With `this` having the underlying type, that would no longer be the case - members of the underlying type would win over extension members, even ones from the enclosing declaration.\n\nThis does not seem like a big loss in practice. Why would an extension declare a member that the underlying type would hide? Such an extension member would be effectively unusable, given the other restrictions of this proposal. In fact, such a declaration might warrant a warning:\n\n``` c#\npublic extension StringExtensions for string\n{\n    public string Length => ...; // Useless - warning?\n    public bool IsUtf8 => ... Length ...; // Would bind to string.Length\n}\n```\n\nIt is still the case that the extension's members would compete on equal terms with other extensions and could clash with them. This is a special case of the more general ambiguity issue, that we will address next. \n\nIn this particular case, ambiguities would be quite rare. If the other extension is imported with a `using` it would lose due to existing \"closeness\" rules. If it is defined on a base type, it would lose due to existing overload resolution rules.\n\nIf we still think it is a problem, we could consider an additional closeness rule that an extension is closer than others inside its own declaration.\n\n``` c#\npublic extension E1 for string\n{\n    public void M() => ...;\n}\nextension E2 for string\n{\n    public void M() => ...;\n    public void P => ... M() ...; // Ambiguity? Closeness rule?\n}\n```\n\nIt would likely be a breaking change if at a later point (when extensions were allowed as instance types) we changed the type of `this` to the extension type. \n\n### Disambiguation\n\nThe other place where the type-ness of extensions plays a part in the current design is in disambiguation between members of two imported extensions.\n\n``` c#\nusing E1; // Brings in void M() on string;\nusing E2; // Also brings in void M() on string;\n\n\"Hello\".M(); // Ambiguous\n((E1)\"Hello\").M(); // No longer allowed\n```\n\nGiven current rules, ambiguities like this would have to be handled by playing tricks with using clauses. E.g. putting `using` inside vs outside of the namespace (the one inside is nearer). Or defining a helper extension member in a separate file that only imports one of the extensions, and simply redirects to it:\n\n``` c#\n// OtherFile.cs\nusing E1;\n\nextension HelperExtensions for string\n{\n    public void E1_M() => M();\n}\n```\n\nWe know from extension methods that ambiguities are rare, but do occur. If the above is not satisfactory, we could recognize very specific patterns in code (such as `((E1)\"Hello\").M()`) or consider new syntax for disambiguation.\n\n## Alternatives\n[alternatives]: #alternatives\n\nThese possible supplementary mitigating features were mentioned in the Drawbacks section:\n\n- A warning when an extension declares a member that would be hidden by a member of the underlying type\n- An additional closeness rule preferring members of a given extension within the declaration of that extension\n- Syntax or special rules to help with disambiguation between extension members\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n## Design meetings\n\n"
  },
  {
    "path": "meetings/working-groups/extensions/extensions-lookup.md",
    "content": "There are two parts to this proposal:\n1. adjust how we find compatible substituted extension containers\n2. align with current implementation of extension methods\n\n# Finding a compatible substituted extension container\n\nThe proposal here is to look at `extension<extensionTypeParameters>(receiverParameter)` like a method signature, \nand apply current [type inference](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1263-type-inference) \nand [receiver applicability](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#128103-extension-method-invocations) rules to it, given the type of a receiver.\n\nThe type inference step infers the extension type parameters (if possible).  \nThe applicability step tells us whether the extension works with the given receiver, \nusing the applicability rules of `this` parameters.\n\nThis can be applied both when the receiver is an instance or when it is a type.\n\nRe-using the existing type inference and conversion algorithm solves the variance problem we'd discussed in LDM.  \nIt makes this scenario work as desired:\n```cs\nIEnumerable<string>.M();\n\nstatic class E\n{\n  extension(IEnumerable<object>)\n  {\n    public static void M() { }\n  }\n}\n```\n\nNote: this change was made in the new extensions feature branch.\n\n# Aligning with implementation of classic extension methods\n\nDecision: we're resolving new instance extension members exactly like classic extension methods.\n\nThe above should bring the behavior of new extensions very close to classic extensions.  \nBut there is still a small gap with the current implementation of classic extension methods, \nwhen arguments beyond the receiver are required for type inference of the type parameters\non the extension container.  \n\nThe spec for classic extension methods specifies 2 phases (find candidates compatible with the receiver, then complete the overload resolution), \nbut the implementation only has 1 phase (find all candidates and do overload resolution with all the arguments including one for the receiver value).\n\nExample we had [discussed](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-10-02.md#extensions):\n```cs\npublic class C\n{\n    public void M(I<string> i, out object o)\n    {\n        i.M(out o); // infers E.M<object>\n        i.M2(out o); // error CS1503: Argument 1: cannot convert from 'out object' to 'out string'\n    }\n}\npublic static class E\n{\n   public static void M<T>(this I<T> i, out T t) { t = default; }\n   extension<T>(I<T> i)\n   {\n      public void M2(out T t) { t = default; }\n   }\n}\npublic interface I<out T> { }\n```\n\nWe have a few options:\n1. Bend the implementation of new extension member lookup to work the same way as classic extensions (1-phase for invocation scenarios, 2-phases for others)\n   We can either update the spec for classic extension methods, or document a spec deviation for both classic and new extension methods. \n2. Introduce a subtle difference in behavior between new and old extension methods (and figure out how we then resolve when both kinds are candidates)\n   This means that migrating from a classic extension method to a new extension method is not quite 100% compatible.\n3. Make new and old extension methods both work the new way, thus breaking existing uses of existing extension methods\n\nNote: depending on this choice, still need to solve how to mix classic and new extension methods in invocation and function type scenarios.\n\n## Details on option 1 (1 phase design to match implementation of classic extension methods)\n\nIf we choose to do 1-phase lookup for invocation scenarios, we would:\n1. we collect all the candidate methods (both classic extension methods and new ones, without excluding any extension containers)\n2. we combine all the type parameters and the parameters into a single signature\n3. we apply overload resolution to the resulting set\n\nThe transformation at step 2 would take a method like the following:\n```cs\nstatic class E\n{\n  extension<extensionTypeParameters>(receiverParameter)\n  {\n    void M<methodTypeParameters>(methodParameters);  \n  }\n}\n```\nand produce a signature like this:\n```\nstatic void M<extensionTypeParameters, methodTypeParameters>(this receiverParameter, methodParameters);\n```\n\nNote: for static scenarios, we would play the same trick as in the above section, where we take a type/static receiver and use it as an argument.\n\nNote: This approach solve the mixing question.\n\n# Overload resolution for extension methods\n\nDecision: we're going for maximum compatibility between new instance extension methods and classic extension methods.\n\nWe previously concluded that we should prefer more specific extensions members.  \nBut classic extension methods don't follow that.\nInstead they use betterness rules ([better function member](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12643-better-function-member)).\n\nWe remove less specific applicable candidates of instance methods (type-like behavior)\n```\nnew Derived().M(new Derived()); // Derived.M\n\npublic class Base \n{\n    public void M(Derived d) { }\n}\n\npublic class Derived : Base \n{\n    public void M(Base b) { }\n}\n```\n[sharplab](https://sharplab.io/#v2:C4LglgNgPgdgpgdwAQBE4CcwDc4BMAUAlAHQCy+8yamOBhhA3EgPTOobZ5kCwAUHwAEAzEgEAmJACEAhgGc4SPgG8+SNaJECALEnLVOuJLkJIlSAL59L/XsNET9tJCClyFy1ervbd+GfKQAIxMza3MgA)\n\nBut we rely on betterness for classic extension methods (parameter-like behavior)\n```\n\"\".M(); // E.M(string)\n\npublic static class E \n{\n    public static void M(this object o) { }\n    public static void M(this string s) { }\n}\n```\n[sharplab](https://sharplab.io/#v2:C4LglgNgPgRDB0BZAFASgNwAID03MFElkABARgAZUBYAKFuIGZMyA2ZgJgM1oG9bMBzJq2YAWTCmAALMAGdMAewBGAKwCmAY2CLUmHpgC+/QY2ak2xcZJnyy5TLN36jNA0A=)\n\n```\n\"\".M(\"\"); // ambiguous\n\npublic static class E \n{\n    public static void M(this object o, string s) { }\n    public static void M(this string s, object o) { }\n}\n```\n\n[sharplab](https://sharplab.io/#v2:C4LglgNgPgRDB0BZAFHAlAbgAQHodYEMBbAIzAHMBXAe0oGcBYAKGYAEBmLVgRgDYuATFgCiWZgG9mWaV049+rACxYUwABZg6WaiQBWAUwDGwbQBou3AAxY6aLOKwBfKTI4WFy1Rq09rdczoGxtp2Ds5M4UA)\n\nWhich should we do for new extension methods?\n\nWe have competing goals:\n1. we want to align extension methods with classic extension methods (portability/compat, parameter-like behaviors) and with instance methods (type-like behaviors)\n2. we want to align other extension members (properties) with extension methods\n3. we want to align instance and static scenarios\n\nOptions for methods:\n1. maximum compatibility with classic extension methods\n2. maximum alignment with instance methods\n\n## Extension methods proposal\n\nGather candidates (no applicability involved)\nPruning more candidates:\n1. by type inference (including the type parameters on the extension declaration)  \n2. by applicability to arguments (including the extension parameter)  \n3. Remove based on inaccessible type arguments (apply, see RemoveInaccessibleTypeArguments)\n4. Remove less specific or hidden applicable candidates (doesn't apply, see RemoveLessDerivedMembers and RemoveHiddenMembers)\n5. Remove static-instance mismatches (apply)  \n6. Remove candidates with constraints violations (apply)  \nFigure out best candidate: \n1. Remove lower priority/ORPA members (apply)  \n2. Remove worse members (better function member) (including the receiver parameter)  \n\nNote: the other pruning steps in overload resolution not sdon't apply to extension receiver parameter scenarios (RemoveDelegateConversionsWithWrongReturnType, RemoveCallingConventionMismatches, RemoveMethodsNotDeclaredStatic)\n\n# Resolution for static methods\n\nDecision: match what we do for instance methods\n\nDo we want the same semantics for static extension methods (ie. we pretend like we have a receiver/value of the given type) or do we want some new semantics?  \nI assume that we want the old semantics.  \nThis also makes it clear what to expect in a \"Color Color\" scenario, where we don't know whether the receiver is an instance or static.\n\n# Resolution for properties\n\nDecision: match what we do for instance/static methods as long as it makes sense. In particular, the \"prefer more specific\" step won't apply to properties either. We'll want to revisit the details of betterness we want for properties. We're okay keeping the betterness step after the member kind determination, for now.\n\nWe have similar questions for extension properties.  \nWe're going to cover three questions:\n- what kind of pruning should be applied?\n- what kind of betterness should be applied?\n- how should properties be resolved together with methods?\n\n## Pruning candidates\n\n### Prefer more specific\n\nYes, we'd previously agree that we want to prefer more specific members.\n\n```csharp\n_ = \"\".P; // should pick E(string).P\n\npublic static class E\n{\n    extension(object o)\n    {\n        public int P => throw null; \n    }\n    extension(string s) // more specific parameter type\n    {\n        public int P => 0;\n    }\n}\n```\n\n### Static/instance mismatch\n\nIf we try to follow the behavior of regular instance or static methods, then the resolution of extension properties should prune based on static/instance mismatch:\n```csharp\n_ = 42.P;\n\nstatic class E1\n{\n    extension(int i)\n    {\n        public int P => 0;\n    }\n}\nstatic class E2\n{\n    extension(int)\n    {\n        public static int P => throw null;\n    }\n}\n```\n```csharp\n_ = int.P;\n\nstatic class E1\n{\n    extension(int i)\n    {\n        public int P => throw null;\n    }\n}\nstatic class E2\n{\n    extension(int)\n    {\n        public static int P => 0;\n    }\n}\n```\n\n## Betterness\n\n### Better conversion from expression\n\n```csharp\nIEnumerable<C2> iEnumerableOfC2 = null;\n_ = iEnumerableOfC2.P; // should we prefer IEnumerable<C1> because it is a better conversion? (parameter-like behavior)\n\npublic static class E\n{\n    extension(IEnumerable<C1> i)\n    {\n       int P => 0;\n    }\n    extension(IEnumerable<object> i)\n    {\n       int P => throw null;\n    }\n}\npublic class C1 { }\npublic class C2 : C1 { }\n```\n```csharp\n_ = IEnumerable<C2>.P; // should we prefer IEnumerable<C1> because it is a better conversion? (parameter-like behavior)\n\npublic static class E\n{\n    extension(IEnumerable<C1>)\n    {\n      static int P => 0;\n    }\n    extension(IEnumerable<object>)\n    {\n      static int P => throw null;\n    }\n}\n```\n[classic extension analog](https://sharplab.io/#v2:C4LglgNgPgAgDAAhgRgCwG4CwAoFBmAHgGEAmAPgTAQF4EA7AVwgi2xzADoBZACgEp0CAPRCEAUW498xZGT44cMPEmQA2JCXE4A3jgT6kylOpioEvYAAswAZxWEishAA8+CbQgC+eg0pUmzC2s7aQB7ACMAKwBTAGNgCld3LxxvXCNNR2S0vxhMzRAELI9PIA===)\n\nShould both extensions be applicable both when the receiver is an instance or a type?  \nIf yes, should we have some preference between those two?  \n\n### Prefer non-generic over generic\n\nIf we follow the parameter-like behavior of classic extension methods, then we'd probably want more better member rules:\n```csharp\n_ = 42.P;\n\npublic static class E\n{\n    extension<T>(T t)\n    {\n        public int P => throw null; \n    }\n    extension(int i) // non-generic, so better function member\n    {\n        public int P => 0;\n    }\n}\n```\n\n### Prefer by-value parameter\n\n```csharp\n_ = 42.P;\n\npublic static class E\n{\n    extension(in int i)\n    {\n        public int P => throw null; \n    }\n    extension(int i) // better parameter-passing mode\n    {\n        public int P => 0;\n    }\n}\n```\n\n### Issue with betterness in static scenarios\n\nBut those betterness rules don't necessarily feel right when it comes to static extension methods:\n```csharp\nint.M2();\npublic static class E1\n{\n    extension(in int i)\n    {\n       public static void M() { }\n    }\n}\n\npublic static class E2\n{\n    extension(int)\n    {\n        public static void M() { }\n    }\n}\n```\n\n## Resolving properties and methods together\n\nFollowing last LDM's decision to use old semantics for new extension methods, we have to find a new way to resolve properties and methods together.  \n\nPreviously, we would only gather candidates from compatible extensions, then we would decide the winning member kind and proceed with resolving (either overload resolution for methods, or picking the single property).  \nNow that we're gathering all candidates (without regards to compatibility of extensions), we're thinking to delay the determination of the member kind.\n\nThe process that we've brainstormed:\n1. gather candidates\n2. prune candidates by type inference and applicability to arguments\n3. prune candidates by other rules (static/instance mismatch, prefer more specific, ...)\n4. determine member kind\n\nIf all the remaining candidates are methods, the member kind is method and we resolve to the best method.  \nIf the only remaining candidate is a property, the member kind is property and we resolve to that property.  \nOtherwise we have an ambiguity.  \n\nNote: I don't think there's a scenario for removing lower priority members based on ORPA here. \n\n### Remove static/instance mismatches\n\nThe following example illustrates the relevance of step 3 above, when we have a method and a property, but one has a static/instance mismatch.\n\n```csharp\nobject.M();\n\nstatic class E1\n{\n    extension(object)\n    {\n        public static string M() => throw null;\n    }\n}\n\nstatic class E2\n{\n    extension(object o)\n    {\n        public string M() => throw null;\n    }\n}\n```\n\n### Prefer more specific\n\nThe following example illustrates the relevance of step 3 above, when we have a method and a property, but one is more specific.  \nThe problem is that we've decided not to apply the \"more specific\" pruning step to extension methods, for compatibility with classic extension methods.  \n\n```csharp\nstring.M();\n\nstatic class E1\n{\n    extension(string)\n    {\n        public static string M() => throw null;\n    }\n}\n\nstatic class E2\n{\n    extension(object)\n    {\n        public static System.Action M => throw null;\n    }\n}\n```\n\n\n## Function types\n\nNote: the determination of function types starts with the applicable candidates, with candidates pruned, but some of the pruning rules weren't applicable (static/instance mismatch).  \nI assume we'll want all possible applicable pruning steps to apply:\n\n```csharp\nvar x = C.M; // binds to static method\n\npublic class C { }\npublic static class E1\n{\n    extension(object)\n    {\n        public static void M() { }\n    }\n    extension(object o)\n    {\n        public void M(int i) { }\n    }\n}\n```\n"
  },
  {
    "path": "meetings/working-groups/extensions/extensions_v2.md",
    "content": "# Modern Extensions\n\n* [x] Proposed\n* [ ] Prototype: Not Started\n* [ ] Implementation: Not Started\n* [ ] Specification: Not Started\n\nMany thanks to those who helped with this proposal.  Esp. @jnm2!\n\n## Summary\n[summary]: #summary\n\nModern Extensions introduce a new syntax to produce \"extension members\", greatly expanding on the set of supported members including properties, static methods, operators and constructors (and more), in a clean and cohesive fashion.\n\nThis new form subsumes C# 3's \"classic extension methods\", allowing migration to the new modern form in a semantically *identical* fashion (both at a source and ABI level).\n\nNote: this proposal is broken into two parts.  A core kernel needed to initially ship with perfect forward and backwards compatibility with classic extension methods, and then potential enhancements on top of this kernel to make certain common designs more succinct and pleasant.  This does not preclude the feature shipping with any or all of these enhancements at launch.  It simply allows the design to be broken into separable concerns, with a clearer ordering of dependencies.\n\nA rough strawman of the syntax is as follows.  In all cases, the extended type is shown to be generic, to indicate handling that complex case:\n\nNote: the strawman is not intended to be final form.  That said, it is useful to see any proposed form with all members to ensure that it's generally comprehensible.  For example, a form that is only good for properties, but not for other members, it likely not appropriate.\n\n```c#\nextension E\n{\n    // Instance method form, replaces `public static int M<X>(this SomeType<X> val, ...) { } \n    public int M<X>(...) for SomeType<X> val { }\n\n    // Property form:\n    // Auto-properties, or usage of 'field' not allowed as extensions do not have instance state.\n    public int Count<X> for SomeType<X> val { get { ... } }\n\n    // Event form:\n    // Note: would have to be the add/remove form.\n    // field-backed events would not be possible as extensions do not have instance state.\n    public event Action E<X> for SomeType<X> val { add { } remove { } }\n\n    // Indexer form:\n    public int this<T>[int index] for SomeType<X> val { get { ... } }\n\n    // Operator form:\n    // note: no SomeType<X> val, an operator is static, so it is not passed an instance value.\n    public static SomeTypeX<X> operator+ <X>(SomeType<X> s1, SomeType<X> s2) for SomeType<X> { ... }\n    \n    // Conversion form:\n    // note: no SomeType<X> val, an operator is static, so it is not passed an instance value.\n    public static implicit operator SomeTypeX<X>(int i) for SomeType<X> { ... }\n\n    // Constructor form:\n    // note: no SomeType<X> val, an operator is static, so it is not passed an instance value.\n    public SomeType<X>() for SomeType<X> { }\n\n    // *Static* extension method (not possible today).  Called as `Assert.Boo(\"\", \"\")`\n    // note: no `Assert val`, a static method is not passed an instance value.\n    public static bool Boo(string s1, string s2) for Assert { }\n\n    // Static extensions properties, indexers and events are all conceptually supportable.\n    // Though we can decide which are sensible to have or not.\n    // Static extensions can having backing static fields. Static extension properties can use `field`.\n    \n    // Nested types must be supported to maintain compatibility with existing static classes with extension members in them.\n}\n```\n\nWithout specifying the full grammar changes, the intuition is that we are making the following changes:\n\n```g4\nfor-clause\n    | 'for' parameter\n    ;\n\nparameter (no change)\n    | attributes? modifiers? type identifier ...\n    ;\n\nextension\n    | attributes? modifiers? 'extension' identifier { member_declaration* }\n    ;\n\n// For method/property/indexer/operator/constructor/event declarations\n// we are augmenting its syntax to allow type-parameters\n// (if not already allowed) and a for-clause. For example:\nproperty-declaration\n    | attributes? modifiers identifier type-parameters for-clause property-body\n    ;\n    \ncompilation-unit-member\n    | ...\n    | extension\n    ;\n \nnamespace-declaration-member\n    | ...\n    | extension\n    ;\n```\n\nThe use of `parameter` means all of the following are legal, with the same semantics that that classic extension methods have today:\n\n```c#\nfor ref Span<T> span\nfor ref readonly Span<T> span\nfor in Span<T> span\nfor scoped ref Span<T> span\nfor scoped Span<T> span\n```\n\nModern extensions continue to not allow adding fields or destructors to a type.\n\nNot all of these *new* extension member forms need be supported.  For example, we may decide that a `static extension indexer` or `static extension event` is just too esoteric, and can be cut.  The proposal shows them all though to demonstrate completeness of the idea.  All *classic* forms must be supported of course.\n\n\n## Migration and compatibility\n\nGiven an existing static class with extensions, a straightforward *semantically identical* (both at the source and binary level) translation to modern extensions is done in the following fashion.\n\n```c#\n// Existing style\nstatic class E\n{\n    static TField field;\n    static int Property => ...\n    static void NonExtensionHelperMethod() { }\n\n    static int ExtensionMethod(this string x, ...) { }\n    static T GenericExtensionMethod<T, U>(this U u, ...) { }\n}\n\n// New style\nextension E\n{\n    // Non extensions stay exactly the same.\n    static TField field;\n    static int Property => ...\n\n    // Note the lack of a 'for-clause'.  This is a normal static method.\n    // An *modern static extension method* will have a 'for-clause' on it\n    static void NonExtensionHelperMethod() { }\n\n    // Migrated *instance* extension members\n    int ExtensionMethod(...) for string x { }\n    T GenericExtensionMethod<T, U>(...) for U u { }\n}\n```\n\nIn other words, all existing extension methods drop `static` from their signature, and move their first parameter to a `for-clause` placed within the method header (currently strawmanned as after the parameter list).  The strawman chooses this location as it already cleanly supports clauses, being where the type parameter constraint clauses already go.\n\nNote: the syntax of a `for-clause` is `'for' parameter`, allowing things like a parameter name to be specified.  `parameter` is critical in this design to ensure the classic extension method `this` parameter can always cleanly move. \n\nThe extension itself (E) will get emitted exactly as a static class would be that contains extension methods (allowing usage from older compilers and other languages without any updates post this mechanical translation).\n\nNew extension members (beyond instance members) will need to have their metadata form decided on.  Consumption from older compilers and different languages of these new members will be specified at a later point in time.\n\nA full example of this translation with a real world complex signature would be:\n\n```c#\nstatic class Enumerable\n{\n    public static TResult Sum<TSource, TResult, TAccumulator>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)\n        where TResult : struct, INumber<TResult>\n        where TAccumulator : struct, INumber<TAccumulator>\n    {\n        // Original body\n    }\n}\n\nextension Enumerable\n{\n    public TResult Sum<TSource, TResult, TAccumulator>(Func<TSource, TResult> selector)\n        for IEnumerable<TSource> source\n        where TResult : struct, INumber<TResult>\n        where TAccumulator : struct, INumber<TAccumulator>\n    {\n        // Exactly the same code as original body.\n    }\n}\n```\n\nThis form supports *non* extension static methods.  For example `Enumerable.Range` would migrate like so:\n\n```c#\nstatic class Enumerable\n{\n    public static IEnumerable<int> Range(int start, int count) { ... }\n}\n\n\nextension Enumerable\n{\n    // Exact same signature.  No 'for-clause'.\n    public static IEnumerable<int> Range(int start, int count) { ... }\n}\n```\n\nPerfect source and binary compatibility are goals here.  That means any other features that work with static classes and extensions are expected to migrate over to extensions without change.  This includes, but it not limited to other features like 'attributes'.  For example, all attributes that might be present on a `static class` should migrate unchanged to an `extension`.  Other features not mentioned here should not be inferred to not be part of this design.  By default all features should continue being compatible, and only explicitly specified deviations should be allowed.\n\n## Disambiguation\n\nClassic extension methods today can be disambiguated by falling back to static-invocation syntax.  For example, if `x.Count()` is ambiguous, it is possible to switch to some form of `StaticClass.Count(x)` to call the desired method.  A similar facility is needed for modern extension members.  While the existing method-invocation-translation approach works fine for methods (where the receiver can be remapped to the first argument of the static extension method call), it is ungainly for these other extension forms.\n\nAs an initial strawman this proposal suggests reusing `cast expression` syntax for disambiguation purposes.  For example:\n\n```c#\nvar v1 = ((Extension)receiver).ExtensionMethod(); // instead of Extension.ExtensionMethod(receiver)\nvar v2 = ((Extension)receiver).ExtensionProperty;\nvar v3 = ((Extension)receiver)[indexerArg];\nvar v4 = (Extension)receiver1 + receiver2;\n```\n\nConstructors and static methods would not need any special syntax as the extension can cleanly be referenced as a type where needed.\n\n```c#\nvar v3 = new Extension(...); // Makes instance of the actual extended type.\nvar v4 = Extension.StaticExtensionMethod(...);\n```\n\nNote 1: while the cast syntax traditionally casts or converts a value, that would not be the case for its use here.  It would only be used as a lookup mechanism to indicate which extension gets priority.  Importantly, even with this syntax, extensions themselves are not types.  For example:\n\n```c#\nExtension e1;                   // Not legal.  Extension is not a type.\nExtension[] e2;                 // Not legal.  Extension is not a type.\nList<Extension> e3;             // Not legal.  Extension is not a type.\nvar v1 = (Extension)receiver;   // Not legal.  Can't can't have a value of extension type.\n```\n\nThis is exactly the same as the restrictions on static-types *except* with the carve out that you can use the extension in a cast-syntax or new-expression *only* for lookup purposes, or where a static-class could be used, and nothing else.  Usage in places like `nameof(Extension)` or `typeof(Extension)` would still be fine, as those are places where a static type is allowed.\n\nNote 2. If cast syntax is not desirable here (especially if confuses the idea if extensions are types), we can come up with a new syntactic form.  We are not beholden to the above syntax.\n\n# Future expansion\n\nThe above initial strawman solves several major goals for we want for the extensions space:\n\n1. Supporting a much broader set of extension member types.\n2. Having a clean syntax for extension members that matches the regular syntax form (in other words, an extension proeprty still looks like a property).\n3. Ensuring teams can move safely to modern extensions *especially* in environments where source *and* binary compatibility is non-negotiable.\n\nHowever, there are parts of its core design that are not ideal in the long term which we would like to ensure we can expand on.  These expansions could be released with extensions if time and other resources permit.  Or they could come later and cleanly sit on top of the feature to improve the experience.\n\nThese areas are:\n\n## Expansion 1: Syntactic clumsiness and repetition\n\nThe initial extension form considers source and binary compatibility as core requirements that must be present to ensure easy migration, allowing codebases to avoid both:\n1. bifurcation; where some codebases adopt modern extensions and some do not.\n2. internal inconsistency; where some codebases must keep around old extensions and new extensions, with confusion about the semantics of how each interacts with the other.\n\nBecause classic extension methods have very few restrictions, modern extension methods need to be flexible enough to support all the scenarios which they support.\n\nHowever, many codebases do not need all the flexibility that classic extension methods afforded.  For example, classic extension methods allow disparate extension methods in a single static class to target multiple different types.  For use cases where that isn't required, we forsee a natural extension (pun intended) where one can translate a modern extension like so:\n\n```c#\nextension E\n{\n    // All extension members extend the same thing:\n\n    public void M() for SomeType str { ... }\n    public int P for SomeType str { get { ... } }\n    public static operator+(...) for SomeType str { ... }\n    // etc\n}\n\n// Can be translated to:\n\nextension E for SomeType str\n{\n    public void M() { ... }\n    public int P { get { ... } }\n    public static operator+(...) { ... }\n}\n\nTODO: Do an ecosystem check on what percentage of existing extensions could use this simpler form.\n\nTODO: It's possible someone might have an extension where almost all extensions extend a single type, and a small handful do something slightly different (perhaps extending by `this ref`).  Would it be beneficial here to *still* allow the extension members to provide a `for-clause` to override that default for that specific member.  For example:\n\n```c#\nextension StringExtensions for string str\n{\n    // Lots of normal extension methods on string ...\n\n    // Override here to extend `string?`\n    public bool MyIsNullOrEmpty() for [NotNullWhen(false)] string? str\n    {\n    }\n}\n```\n\nIt seems like this would be nice to support with little drawback.\n\n## Expansion 2: Optional syntactic components\n\nAs above, we want modern extensions to completely subsume classic extension methods.  As such, a modern extension  method must be able to support everything a classic extension method supported.  For example:\n\n```c#\nstatic class Extensions\n{\n    // Yes, this is legal\n    public static void MakeNonNull([Attr] this ref int? value)\n    {\n        if (value is null)\n            value = 0;\n    }\n}\n```\n\nFor this reason, the strawman syntax is:\n\n```g4\nfor-clause\n    | 'for' parameter`\n    ;\n\nparameter (unchanged)\n    | attributes? modifiers? type identifier\n    | attributes? modifiers? type identifier '=' expression\n    ;\n```\n\nFortunately, extension methods today don't support a default value for the `this` parameter, so we don't have to support migrating the second `= value` form forward, and we would consider writing a default value in a `for-clause` to be an error.\n\nHowever, for many extensions no name is really required.  All non-static extension members (instance methods, properties, indexers and events) are conceptually a way to extend `this` with new functionality.  This is so much so the case that we even designed classic extension methods to use the `this` keyword as their designator.  As such, we forsee potentially making the name optional, allowing one to write an extension like so:\n\n```c#\nextension Enumerable\n{\n    public TResult Sum<TSource, TResult, TAccumulator>(Func<TSource, TResult> selector)\n        for IEnumerable<TSource> // no name\n        where TResult : struct, INumber<TResult>\n        where TAccumulator : struct, INumber<TAccumulator>\n    {\n        // Use 'this' in here to represent the value being extended\n    }\n}\n```\n\nThis would have to come with some default name chosen by the language for the parameter in metadata.  But that never be needed by anyone calling it from a modern compiler.\n\n## Expansion 3: Generic extensions.\n\nThe initial design allows for extending generic types through the use of generic extension members.  For example:\n\n```c#\nextension IListExtensions\n{\n    public void ForEach<T>(Action<T> act) for IList<T> list\n    {\n        foreach (var value in list)\n            act(list);\n    }\n\n    public long LongCount<T> for IList<T> list\n    {\n        get\n        {\n            long count = 0;\n            foreach (var value in list)\n                count++;\n\n            return count;\n        }\n    }\n}\n```\n\nIdeally with the optional first expansion we could 'lift' `List<T>` up to `extension IListExtensions`.  However, this doesn't work as we need to define the type parameter it references.  This naturally leads to the following idea:\n\n```c#\nextension IListExtensions<T> for IList<T> list\n{\n    public void ForEach(Action<T> act) { ... }\n    public long LongCount { ... }\n}\n```\n\nThis has a few new, but solvable, design challenges.  For example, say one has the code:\n\n```c#\nList<int> ints = ...;\nvar v = ints.ForEach(i => Console.WriteLine(i));\n```\n\nThis naturally raises the question of how does this extension get picked for this particular receiver, and how does its type parameter get instantiated to the `int` type.\n\nConceptually (and trying to keep somewhat in line with classic extension methods), we really want to think of the 'receiver' as an 'argument' to some method where normal type inference occurs.  Morally, we could think of there being a `IListExtension<T> Infer<T>(IList<T> list)` function whose shape is determined by the extension and its type-parameters and the extended receiver parameter.\n\nThen, when trying to determine if an extension applies to a receiver, it would be akin to calling that function with the receiver and seeing if inference works.  In the above example that would mean performing type inference on `Infer(ints)` seeing that `T` then bound to `int`, which then gives you back `IListExtensions<int>`.  At that point, lookup would then find and perform overload resolution on `ForEach(Action<int>)` with the lambda parameter.\n\nThis approach does fundamentally expand on the initial extension-members approach, as now, calling extensions is done in two phases.  An initial phase to determine and infer extension type parameters based on the receiver, and a second phase to determine and perform overload resolution on the member.\n\nWe believe this is very powerful and beneficial.  But there are deep design questions here which may cause this to be scheduled after the core extension members work happens.\n\n## Expansion 4: Extensions as actual types\n\nWe are very undecided on if we actually want this.  Currently, our view is that it feels like 'roles' fits this goal much better, especially if roles have the ability to be 'implicit' or 'explicit'.  Extensions exist very much in the space where they are erased and really are just delicious delicious sugar over calling effectively static helpers to augment a type or value.\n\nRoles, on the other hand, seem more fitted to the type space where they are truly part of the type system, intended to appear in signatures, generics, and the like, potentially with strong enforcement about values moving into or out of the role.\n\nThis warrants deep discussion about the path taken here and the future we are envisioning, to ensure we're happy with any paths this current approach may close off or make more difficult.\n\n## Detailed design\n[design]: #detailed-design\n"
  },
  {
    "path": "meetings/working-groups/extensions/implicit-compatibility-for-ported-extension-methods.md",
    "content": "# Implicit compatibility for ported extension methods\n\nThe new extension syntax introduces a separation between the receiver specification and the member declaration itself. The natural semantics accompanying this leads to several differences from how classic extension methods behave; places where the fact that classic extension methods are really just static methods bleeds through to their behavior.\n\nIf we don't address this discrepancy, many classic extension methods will not be compatibly portable to the new syntax, and there will be an observable behavior misalignment between those that aren't ported and extension methods in the new syntax.\n\nThere are two strategies for addressing this: Explicit and implicit compat. \n\nWith *explicit* compat, a syntactic marker signals that a given extension method in the new syntax should remain compatible with its corresponding classic declaration, and behavior is suitably adjusted to achieve that.\n\nWith *implicit* compat, all extension methods in the new syntax have behavior that makes all (or nearly all) existing consumption code continue to work the same way, even as new behavior is also embraced.\n\nThis document pursues **implicit compat**. It looks at each of the behavior discrepancies we know of, and suggests ways to address them.\n\n## Static methods\n\nClassic extension methods are static methods on the enclosing static class, and they may be invoked as such. To achieve implicit compat, a new extension instance method generates a static method that mimics the corresponding classic extension method. It uses:\n\n- the attributes, accessibility, return type, name and body of the declared instance extension method,\n- a type parameter list concatenated from the type parameters of the extension declaration and the extension method, in that order, and\n- a parameter list concatenated from the receiver parameter of the extension declaration and the parameter list of the extension method, in that order.\n\n``` c#\npublic static class Enumerable\n{\n    extension<TSource>(IEnumerable<TSource> source)\n    {\n        public IEnumerable<TSource> Where(Func<TSource, bool> predicate) { ... }\n        public IEnumerable<TSource> Select<TResult>(Func<TSource, TResult> selector)  { ... }\n    }\n}\n```\n\nGenerates\n\n``` c#\npublic static class Enumerable\n{\n    public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { ... }\n    public static IEnumerable<TSource> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)  { ... }\n}\n```\n\n## Type arguments\n\nWhen type arguments are explicitly given to a classic extension method, they must correspond to all the method's type parameters, including those that are used in the receiver type. This may make sense when the classic extension method is invoked as a static method, but it is not a great experience when it is called as an extension method. By contrast, with new extensions any type parameters on the extension declaration are inferred from the receiver, and type arguments on invocation correspond only to those declared on the extension method itself.\n\nIt is not uncommon for classic extension methods to have type parameters both for use in the receiver parameter and in subsequent parameters or return types. An example is `System.Linq.Enumerable.Select` where a rewrite to new syntax would put `TSource` on the extension declaration, and `TResult` on the method declaration.\n\nIt is also not that uncommon for explicit type arguments to be given. A rough GitHub code search suggests that 1.3% of `Select` calls do pass type arguments explicitly. So this is a significant existing scenario.\n\nWith implicit compat, both \"versions\" of the type argument list are allowed. \n\nThis could introduce ambiguities if there are overloads of the extension method with different number of type parameters. That situation is not uncommon in e.g. `System.Linq.Enumerable` (e.g. `SelectMany`) or `System.MemoryExtensions` (e.g. `Contains`). However, those overloads do seem to be distinguishable by parameter list. This is not surprising, since they would have been authored to not clash in the common case where type arguments are inferred. Thus, the scenario for true ambiguity seems very limited in practice.\n\nWe need to make a determination as to whether we believe significant code exists that currently relies on generic arity to disambiguate extension methods. Based on that we can choose to either take a breaking change or introduce some sort of preference system, where the \"classic\" arities win over the new \"method-only\" ones.\n\nGiven:\n``` c#\npublic static class Enumerable\n{\n    extension<TSource>(IEnumerable<TSource> source)\n    {\n        public IEnumerable<TSource> Select<TResult>(Func<TSource, TResult> selector)  { ... }\n    }\n\n```\n\nThe call `myList.Select<int, string>(...)` would provide type arguments for `TSource` and `TResult`, foregoing the separate inference of `TSource` from the type of `myList`.\n\nThe call `myList.Select<string>(...)` would provide a type argument for `TResult` in the above `Select` method, with `TSource` being inferred from the type of `myList`.\n\nGiven that it is non-breaking (enough), we could \"backport\" this behavior to existing extension methods as well.\n\n## Overload resolution\n\nClassic extension methods get excluded from consideration if there isn't an identity, reference or boxing conversion from the receiver to the this-parameter. However, after that point, the receiver gets treated as just yet another argument in determining which method overload wins. This can lead to ambiguities such as this:\n\n``` c#\n\"Hello\".M(\"World!\"); // Ambiguous!\n\npublic static class MyExtensions\n{\n    public static void M(this object o, string s) { ... }\n    public static void M(this string s, object o) { ... }\n}\n```\n\nFor new extension methods, it seems much more in line with expectations that applicable methods \"on\" more specific types shadow (and thus eliminate) applicable methods \"on\" base types. After all, that's how lookup works in type hierarchies: As soon as we find an applicable method, we look no further up the chain.\n\nIt seems such elimination would lead to _fewer_ ambiguities, without causing different results when overload resolution does succeed. Thus it wouldn't be breaking behavior for ported classic extension methods. This claim needs to be investigated for counterexamples of course.\n\n``` c#\n\"Hello\".M(\"World!\"); // Picks string.M(object) because receiver is more specific\n\npublic static class MyExtensions\n{\n    extension(object o)\n    {\n        publicvoid M(string s) { ... }\n    }\n    extension(string s)\n    {\n        public void M(object o) { ... }\n    }\n}\n```\n\nGiven that it is non-breaking, we could \"backport\" this behavior to existing extension methods as well.\n\n## Type inference\n\nWhen type arguments are inferred for a given classic extension method, any argument may impact the inference of any type parameter. By contrast, with new extensions, type arguments for the extension declaration type parameters are inferred from the receiver, whereas arguments to the extension method may only impact type arguments for the extension method's own type parameters.\n\nWhile we can construct examples where this makes a difference, we have not yet encountered such examples in the wild. If we find this to be very rare, we may choose not to do anything to mitigate it.\n\nIf we _do_ choose to address it, we would continue to use classic inference for extension methods, lumping in the type parameters and method parameters from both the extension declaration and extension method. For modern usage, this would be unlikely to produce observably different results; only slightly fewer errors. However, it would allow any occurrences of this pattern to continue to compile as well.\n\n``` c#\nvoid M(I<string> i, out object o)\n{\n    i.M1(out o); // infers E.M1<object>\n    i.M2(out o); // infers E.M2<object>\n}\n\npublic static class E\n{\n   public static void M1<T>(this I<T> i, out T t) { ... }\n   extension<T>(I<T> i)\n   {\n      public void M2(out T t) { ... }\n   }\n}\npublic interface I<out T> { }\n```\n\n## Other differences\n\nThere are some more special discrepancies between instance methods and classic extension methods, which warrant explicit design decisions for the new extension syntax.\n\n### Out-of-order type parameters\n\nClassic extension methods can have type parameters that do not occur in the receiver type precede ones that do in the type parameter list. There is no direct way to port such an extension method compatibly to the new syntax. We do not know of examples of this in the wild, and the best way forward is probably to accept that such methods, should they exist, will have to stay in classic syntax in order to remain fully compatible.\n\n### InterpolatedStringHandlerArgumentAttribute\n\nIn instance methods this attribute can use the empty string to denote the name of the receiver. This doesn't currently work for classic extension methods. Should it work for new extension methods? Should it also be made to work for old ones? In both cases the receiver already has a name, as it is expressed as a parameter.\n\n### CallerArgumentExpressionAttribute\n\nThis attribute cannot be used to refer to the receiver in instance methods. However, in classic extension methods it can, because the receiver is expressed as a parameter. For implicit compat it should remain able to do so in the new extension method syntax.\n\n## Next steps\n\nThere are several open questions, assumptions about existing code and lacking details in this proposal. If LDM approves of the direction, we need to drill down on the details through spec and implementation, and validate our assumptions about potential for breaks."
  },
  {
    "path": "meetings/working-groups/extensions/metadata-names.md",
    "content": "The structure for docID for extension blocks is `E.GroupingName.MarkerName` and that for extension members is `E.GroupingName.Member`.  \nBut there is an issue when it comes to dealing with arity on the grouping name.\n\nThe convention for metadata names is to add an arity suffix to the type name. For `List<T>`, the name is \"List\" and the name in metadata is \"List\\`1\".  \nThis allows for overloading on arity while avoiding name conflicts. You can have \"List\" (with arity zero) and \"List\\`1\" (with arity one).  \nFor extension grouping types, the name is unique enough that we use it directly as the metadata name, without adding an arity suffix.  \nBut this is causing some issues.\n\nThe way we produce docIDs for types is to take the name and append the arity suffix.  \nFor extensions, we added special handling to use the grouping and marker names. \n\nLet's consider this example:\n```csharp\nstatic class E\n{\n  extension<T>(T t)\n  {\n    public void M() { }\n  }\n}\n```\nwith corresponding metadata:\n```\n.class E\n{\n  .class '<G>$8048A6C8BE30A622530249B904B537EB'<T0> // grouping type\n  {  \n    .class '<M>$65CB762EDFDF72BBC048551FDEA778ED'<T> // marker type\n    {\n      .. marker method ..\n    }\n    public void M() => throw; // extension member without implementation\n  }\n\n  public static void M<T>(this int i) { } // implementation method\n}\n```\n\n**If we do include an arity suffix** when producing docIDs for extensions, then:\n- the docIDs don't match the metadata names.\n- if someone makes metadata for an extension type using some other tool, and they do include the arity suffix in the metadata names of grouping types, then docIDs won't match metadata names again.\n\nTo illustrate the first bullet, the docIDs for the example would differ from the names in metadata:\n- extension block: \"E.<G>$8048A6C8BE30A622530249B904B537EB\\`1.<M>$65CB762EDFDF72BBC048551FDEA778ED\"\n- extension member: \"E.<G>$8048A6C8BE30A622530249B904B537EB\\`1.M\"\n\nTo illustrate the second bullet, if some other tool cooks up extension metadata including arity suffixes like this:\n```\n.class E\n{\n  .class 'GroupingType`1'<T0> // grouping type\n  {  \n    .class 'MarkerType'<T> // marker type\n    {\n      .. marker method ..\n    }\n    public void M() => throw; // extension member without implementation\n  }\n\n  public static void M<T>(this int i) { } // implementation method\n}\n```\n\nThen the docIDs would not match the metadata names:\n- extension block: \"E.GroupingName\\`1\\`1.MarkerName\"\n- extension member: \"E.GroupingName\\`1\\`1.M\"\n\nAnd when producing docIDs for constructed symbols, we'd end up with both type arguments and arity suffixes:\n- extension block: \"E.GroupingName\\`1{System.Int32}.MarkerName\"\n- extension member: \"E.GroupingName\\`1{System.Int32}.M\"\n\n\n**If we don't include an arity suffix**, then:\n- docIDs produced from VB symbols on extension metadata will diverge from those produced from C# symbols. VB doesn't have the concept of extension, so will have regular handling for types (which include an arity suffix)\n\nTo illustrate that issue, the docIDs from C# source or metadata for the example would be:\n- extension block: \"E.<G>$8048A6C8BE30A622530249B904B537EB.<M>$65CB762EDFDF72BBC048551FDEA778ED\"\n- extension member: \"E.<G>$8048A6C8BE30A622530249B904B537EB.M\"\n\nBut the docIDs from VB metadata would differ from those from C#:\n- extension grouping type: \"E.<G>$8048A6C8BE30A622530249B904B537EB\\`1\"\n- extension marker type: \"E.<G>$8048A6C8BE30A622530249B904B537EB\\`1.<M>$65CB762EDFDF72BBC048551FDEA778ED\"\n- extension member: \"E.<G>$8048A6C8BE30A622530249B904B537EB\\`1.M\"\n\n\n# Proposal \n\nWe're proposing to compose the metadata name for grouping types by appending an arity suffix to `ExtensionGroupingName`.  \n`ExtensionGroupingName` should reflect names of the emitted grouping types from language perspective, not its emitted names. \nThat would be more conventional.  \nNo change to `ExtensionMarkerName` (name and metadata names match).  \nThen we'd produce the docIDs as described above, by appending an arity suffix to `ExtensionGroupingName` in a way consistent to the current handling of regular generic types.\n\nFor the above example, the compiler would produce:\n```\n.class E\n{\n  .class '<G>$8048A6C8BE30A622530249B904B537EB`1'<T0> // grouping type with arity suffix\n  {  \n    .class '<M>$65CB762EDFDF72BBC048551FDEA778ED'<T> // marker type\n    {\n      .. marker method ..\n    }\n    public void M() => throw; // extension member without implementation\n  }\n\n  public static void M<T>(this int i) { } // implementation method\n}\n```\nThe `ExtensionGroupingName` would remain \"<G>$8048A6C8BE30A622530249B904B537EB\" (both for source and metadata symbols).\nThe `ExtensionMarkerName` would remain \"<M>$65CB762EDFDF72BBC048551FDEA778ED\" (both for source and metadata symbols).\n\nThen the docIDs for C# symbols would be:\n- extension block: \"E.<G>$8048A6C8BE30A622530249B904B537EB\\`1.<M>$65CB762EDFDF72BBC048551FDEA778ED\"\n- extension member: \"E.<G>$8048A6C8BE30A622530249B904B537EB\\`1.M\"\n\nAnd the docIDs for VB metadata symbols would be:\n- extension grouping type: \"E.<G>$8048A6C8BE30A622530249B904B537EB\\`1\"\n- extension marker type: \"E.<G>$8048A6C8BE30A622530249B904B537EB\\`1.<M>$65CB762EDFDF72BBC048551FDEA778ED\"\n- extension member: \"E.<G>$8048A6C8BE30A622530249B904B537EB\\`1.M\"\n\nEverything aligns.\n\nAnd if some other tool cooks up extension metadata without arity suffix like this:\n```\n.class E\n{\n  .class 'GroupingType'<T0> // grouping type (without arity suffix)\n  {  \n    .class 'MarkerType'<T> // marker\n    {\n      .. marker method ..\n    }\n    public void M() => throw; // extension member without implementation\n  }\n\n  public static void M<T>(this int i) { } // implementation method\n}\n```\nthen the docIDs would be:\n- extension block: \"E.GroupingType\\`1.MarkerType\"\n- extension member: \"E.GroupingType\\`1.M\"\n\nThose docIDs are not ideal (they differ from metadata names), but that's not a new problem.\n\n# Practical considerations\n\nIf we're going to make this change, we have about 1 week to get this into the RC2 compiler.  \nBut the RC2 SDK/BCL will be compiled using the RC1 compiler, so the change would only be visible in the GA SDK/BCL assemblies.  \nThe new compiler will still be able to consume extensions produced by the RC1 compiler: when loading metadata symbols, the unmangling is optional (if there is no arity suffix in the metadata name, we just use the whole metadata name as the name).  \nGiven that only the compiler and docIDs make use of grouping types, there would be no binary breaking change. Only implementation methods are referenced in IL, and those are unaffected by the change.  \n\n# Alternative proposals\n\nWe also brainstormed a design where docIDs for extensions would be produced by taking `ExtensionGroupingName`, would strip any arity suffix (to deal with metadata from another tool), then would proceed as usual (add an arity suffix).\n\n# References\nSome pointers to roslyn codebase for reference:\n\n## Producing docIDs\nAll implementations use `Name` from the symbol (as opposed to `MetadataName`) and append a suffix for generics (either an arity suffix for docIds or type arguments for reference Ids on constructed symbols)\n\n1. `ISymbol.GetDocumentationCommentId()` (implemented as part of C# and VB symbols)\nThis API also produces the docIDs emitted in xml output (see `DocumentationCommentCompiler.WriteDocumentationCommentXml` and `GenerateDocumentationComments`)\nUses `Name`, either appends an arity suffix (for definitions) or type arguments (for constructed symbols). (see `DocumentationCommentIDVisitor.PartVisitor.VisitNamedType`)\n\n2. `DocumentationCommentId.CreateDeclarationId(ISymbol)` (implemented in core compiler layer)\nUses `Name`, appends an arity suffix (see `DocumentationCommentId.PrefixAndDeclarationGenerator.DeclarationGenerator.VisitNamedType`)\n\n3. `DocumentationCommentId.CreateReferenceId()` (implemented in core compiler layer)\nUses Name (see `BuildDottedName`), either appends an arity suffix or type arguments (see `DocumentationCommentId.ReferenceGenerator`)\n\n## Reading docIDs\n1. `DocumentationCommentId.GetSymbolsForDeclarationId(string id, Compilation compilation)`\n`DocumentationCommentId.Parser.ParseDeclaredId`  \nSplits identifier into name and arity, then searches symbols with matching Name and Arity (exact).\n\n2. CREF binding\n`BindNameMemberCref`, `ComputeSortedCrefMembers`  \nTakes a name followed by type argument list (which provides arity), looks up by name and arity (exact, for types), then constructs with type arguments\n\n\n## Metadata names and metadata loading\nThe C# and VB compilers generally appends the arity suffix for generic types, to make the metadata name for a named type. There's some exceptions (notably EE named type symbols).\n\nWhen loading types from metadata, the C# and VB compilers remove the arity suffix when it matches the arity found in metadata (see `MetadataHelpers.UnmangleMetadataNameForArity`).\n\nThis means that we can load a type whose name doesn't include a suffix.\n\n"
  },
  {
    "path": "meetings/working-groups/extensions/rename-to-roles-and-extensions.md",
    "content": "# Re-rename to Roles and Extensions\n\n* [x] Proposed\n* [ ] Prototype: Not Started\n* [ ] Implementation: Not Started\n* [ ] Specification: Not Started\n\n## Summary\n[summary]: #summary\n\nRename `explicit extension` back to `role` and `implicit extension` back to simply `extension`.\n\n## Motivation\n[motivation]: #motivation\n\nThe proposed [Extensions](https://github.com/dotnet/csharplang/blob/main/proposals/extensions.md) feature design eliminates the previously proposed distinction between \"roles\" and \"extensions\", in recognition that they are in fact two flavors of the same feature. Instead it introduces modifiers `explicit` and `implicit` onto the shared declaration keyword `extension`.\n\nThis makes sense from a language designer economy-of-concepts point of view. However, the intended mainline *use* of the two kinds of extension differs considerably: One is explicitly used _as_ a type, whereas the other implicitly adds members to an _existing_ type. The overlap in intended usage is small, boiling down to using an implicit extension explicitly as a type for disambiguation purposes. \n\nWe've now had some time to get experience with the design. In practice, anyone but a language designer or implementer rarely has to discuss the overall feature as a whole. Any given declaration is either an \"explicit extension\" or an \"implicit extension\", and the intended mode of use follows from that. The terms are not only long but deceptively similar, causing confusion as well as verbosity. \n\nWe should go back to clear, separate nouns for the two features. The previously used nouns \"role\" and \"extension\" are great candidates, though the choice of terms is less important than the choice of having two of them. This will help people understand them separately, in a manner specific to their main usage patterns. It allows developers to adopt them one at a time, and not worry much about the connections between them.\n\nGoing back to a narrower use of the term \"extension\" also keeps it better aligned with the meaning developers are already used to from extension methods. There have been demands for \"extension members\" and \"extension everything\" ever since extension methods were added, and this use of the term matches the intuition reflected in these asks.\n\nThis is not a proposal to turn roles and extensions into completely separate features. With the rename an extension will still *also* be a role. The two features benefit hugely from having a shared core. The syntax of declarations, the type of `this` inside them, the conversions to and from the underlying type, the code generation strategies, etc., etc., all entirely overlap. Additionally, envisioned future feature evolution such as inheritance and interface implementation apply to and have compelling scenarios for both features.\n\nIt is conceivable that this step opens up opportunities where more differences between roles and extensions would be possible and beneficial. That is totally fine but is not implied here.\n\n## Detailed design\n[design]: #detailed-design\n\nIn the [proposal grammar](https://github.com/dotnet/csharplang/blob/main/proposals/extensions.md#design) change the `extension_declaration` production as follows:\n\n``` antlr\nrole_declaration\n    : role_modifier* ('role' | 'extension') identifier type_parameter_list? ('for' type)? type_parameter_constraints_clause* role_body\n    ;\n```\n\nRename all productions named `extension_NNN` to `role_NNN`. Throughout the proposal, update code snippets accordingly.\n\nIn prose, change \"implicit extension\" to \"extension\" and unqualified \"extension\" to \"role\". There are only two occurrences of \"explicit extension\" in prose; they can easily be rewritten (to e.g. \"non-extension role\"), and \"role\" can safely be used as the overarching term. It turns out that it is rare for the specification to have to talk about explicit extensions *only*, since everything that applies to them applies to implicit extensions also. \n\nIn the [Implementation Details](https://github.com/dotnet/csharplang/blob/main/proposals/extensions.md#implementation-details) section we will want to adjust the naming of emitted attributes and members, and there are probably a few other places that would benefit from a rewording after this change.\n\n### Examples\n\n``` c#\n// Roles intended to be used directly as types\npublic role Order for JsonElement\n{\n    public string Description => GetProperty(\"description\").GetString()!;\n}\n\npublic role Customer for JsonElement\n{\n    public string Name => GetProperty(\"name\").GetString()!;\n    public IEnumerable<Order> Orders => GetProperty(\"orders\").EnumerateArray();\n}\n\n// Extensions intended to provide new function members to existing types\npublic extension JsonString for string\n{\n    private static readonly JsonSerializerOptions s_indentedOptions = new() { WriteIndented = true };\n\n    public JsonElement ParseAsJson() => JsonDocument.Parse(this).RootElement;\n\n    public static string CreateIndented(JsonElement element)\n        => element.ValueKind != JsonValueKind.Undefined\n            ? JsonSerializer.Serialize(element, s_indentedOptions)\n            : string.Empty;\n}\n```\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nIt becomes less directly clear from syntax that extensions are just roles with more behavior.\n\n## Alternatives\n[alternatives]: #alternatives\n\n### Alternative nouns\nWhile \"extension\" is very likely the right term for \"implicit extensions\" because of the connection to the existing extension methods, there is more room for debate about \"role\". While that term does occur in literature, it is not particularly established among developers. We can essentially pick whichever term we like, and many others have been proposed.\n\n### Allowing `extension role`\n\nIf we want the language to more directly reflect that every extension is a role, we could make the declaration syntax for extensions allow an optional `role` keyword to occur in the declaration:\n\n``` c#\npublic extension role JsonString for string { ... }\n\n// equivalent to\n\npublic extension JsonString for string { ... }\n```\n\nThis would be somewhat similar to `record class` which is allowed to be abbreviated to `record`. However, for records the use of `record class` might be motivated by wanting to highlight that it is not a `record struct`. For `extension role` on the other hand there is no `extension something-else` to distinguish it from.  \n\nWe don't have great scenarios at the moment (outside disambiguation) where an extension is *also* intended to be used as a role (i.e. an explicit type), but such scenarios may come up. In those cases, it might be useful to stress this intent by explicitly putting the word `role` in the declaration, even if it doesn't have semantic impact.\n\nThis is something that could be added anytime. We could ship the feature without it, and add the ability to say `extension role` as a long form of `extension` add any future point if it seems warranted. By analogy we also shipped `record` first and then retcon'ed it to be an abbreviation of `record class` in a subsequent release when `record struct` was added.\n\n### Implementing extensions before roles\n\nUsing separate nouns as proposed here, it may become an option to ship extensions first and roles later. While `this`-access and disambiguation for extensions use them as a named type, that is only going to be needed locally in a function body. By contrast, roles are likely to be used in signatures, and so require quite an elaborate metadata scheme for implementation.\n\nPerhaps there's a stage where we leave out role declarations, as well as disallow extension types from occurring in signatures. The latter restriction would be similar to the one that applies to anonymous types in today's C#.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n## Design meetings\n\nhttps://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-09-18.md#extensions-naming\n"
  },
  {
    "path": "meetings/working-groups/extensions/the-design-space-for-extensions.md",
    "content": "# The design space for extensions\n\nLet's put the current proposals for extensions in a broader context, and compare their pros and cons.\n\n## Background: How we got here\n\nThe competing approaches and philosophies around how to express the declaration of extension members trace their roots all the way back to when extension methods were first designed. \n\n### C# 3: The start of extension methods\n\nC# 3 shipped with the extension methods we know today. But their design was not a given: An alternative proposal was on the table which organized extension methods in type-like declarations, each for one specific extended (underlying) type. In this model, extension method declarations would look like instance method declarations, and future addition of other member kinds - even interfaces - would be syntactically straightforward. I cannot find direct references to this first type-based proposal,  but here is a slightly later version from 2009 that was inspired by it:\n\n``` c#\npublic extension Complex : Point\n{\n    public Point Scale(double s) { return new Point(X * s, Y * s); }\n    public double Size { get { return Math.Sqrt(X*X + Y*Y); } }\n    public static Point operator +(Point p1, Point p2) { return new Point(p1.X + p2.X, p1.Y + p2.Y); }\n}\n```\n\nUltimately the current design was chosen for several reasons. Importantly it was much simpler: a syntactic hack on top of static methods. C# 3 was already brimming with heavy-duty features - lambdas, expression trees, query expressions, advanced type inference, etc. - so the appetite to go big on extension methods was limited. Moreover, the static method approach came with its own disambiguation mechanism - just call as a static method! - and allowed convenient grouping of extension methods within one static class declaration. The extension methods of `System.Linq.Enumerable` would have needed to be spread across about 15 extension type declarations if they had been split by underlying type.\n\nBut perhaps most significantly, we didn't know extension methods were going to be such a hit. There was a lot of skepticism in the community, especially around the risks of someone else being able to add members to your type. The full usefulness of the paradigm was not obvious even to us at the time; mostly we needed them for the query scenario to come together elegantly. So betting on them as a full-fledged new feature direction felt like a risky choice. Better to keep them a cheap hack to start with.\n\n### C# 4: Foundered attempts at extension members\n\nOf course extension methods _were_ a huge success in their own right, and the community was immediately asking for more; especially extension properties and extension interfaces. The LDM went to work on trying to generalize to all member kinds, but felt captive to the choices made in C# 3. We felt extension members would have to be a continuation, not just philosophically but _syntactically_, of the extension methods we'd shipped. For instance, extension properties would have to either use property syntax and take an extra `this` parameter somehow, or we'd need to operate at the lowered level of `set` and `get` methods representing the accessors of properties. Here is an example from 2008:\n\n``` c#\npublic extension E\n{\n    public static string Name<T>(this Foo<T> myself){ get { … } set { … } }\n    public static V this<K,V>(this Dict<K,V> dict)[K index] { get { … } }\n    public static event Handler<MyArgs> OnExplode<T>(this Foo<T> it) { \n    \tadd { … }\n    \tremove { … }\n    }\n    public static operator + (BigInteger i, Complex c) { … }\n    public static implicit operator Complex(BigInteger i) { … }\n}\n```\n\nThese explorations led to proposals of unbearable complexity, and after much design and implementation effort they were abandoned. At the time we were not ready to consider rebooting extensions with an alternative syntax, one that would leave the popular classic extension methods behind as a sort of legacy syntax.\n\n### The return of type-based extensions\n\nThe Haskell programming language has _type classes_, which describe the relationships within groups of types and functions, and which, crucially, can be applied after the fact, without those types and functions participating. A proposal from Microsoft Research in Cambridge for adding type classes to C# triggered a string of proposals that eventually led back to extension interfaces: If extension members could somehow help a type implement an interface without the involvement of that type, this would facilitate similar adaptation capabilities to what type classes provide in Haskell, and would greatly aid software composition.\n\nExtension interfaces fit well with the old alternative idea that extensions were a form of type declaration, so much so that we ended up with a grand plan where extensions were types, and where such types would even be a first class feature of their own - separate from the automatic extension of underlying types - in the form of _roles_.\n\nThis approach ran into several consecutive setbacks: We couldn't find a reasonable way to represent interface-implementing extensions in the runtime. Then the implementation of the \"typeness\" of extensions proved prohibitively expensive. In the end, the proposal had to be pared back to something much like the old alternative design from above: extensions as type declarations, but with no \"typeness\" and no roles. Here's a recent 2024 example:\n\n``` c#\nextension E for C\n{\n    // Instance members\n    public string P { get => f; set => f = value.Trim(); }         // Property\n    public T M<T>() where T : IParsable<T> => T.Parse(f, default); // Method\n    public char this[int index] => f[index];                       // Indexer\n    public C(string f) => this.f = f;                              // Constructor\n\n    // Static members\n    public static int ff = 0;                                // Static field\n    public static int PP { get; set => field = Abs(value); } // Static property\n    public static C MM(string s) => new C(s);                // Static method\n    public static C operator +(C c1, C c2) => c1.f + c2.f;   // Operator\n    public static implicit operator C(string s) => new C(s); // UD conversion\n\n}\n```\n\nWe will refer to the resulting flavor of design as \"_type-based extensions_\", because the underlying type of the extension is specified on the extension type itself, and the members are just \"normal\" instance and static member declarations, including providing access to the underlying value with the `this` keyword rather than a parameter.\n\n### The return of member-based extensions\n\nNow that the bigger story of extensions as types with interfaces has been put on hold with its future prospects in question, it is worth asking: Are we still on the right syntactic and philosophical path? Perhaps we should instead do something that is more of a continuation of classic extension methods, and is capable of bringing those along in a compatible way.\n\nThis has led to several proposals that we will collectively refer to as \"_member-based extensions_\". Unlike most of the abandoned C# 4 designs of yore, these designs do break with classic extension methods _syntactically_. Like the type-based approach they embrace an extension member declaration syntax that is based on the corresponding instance member declaration syntax from classes and structs. However, unlike type-based extensions, the underlying type is expressed at the member level, using new syntax that retains more characteristics of a parameter.\n\nHere are a few examples from [this recent proposal](https://github.com/dotnet/csharplang/pull/8525):\n\n``` c#\npublic partial extensions Extensions\n{\n    public SourceTextContainer (ITextBuffer buffer).AsTextContainer()\n        => TextBufferContainer.From(buffer);\n\n    internal TextLine (ITextSnapshotLine line).AsTextLine()\n        => line.Snapshot.AsText().Lines[line.LineNumber];\n}\ninternal extensions IComparerExtensions<T> for IComparer<T>\n{\n    public IComparer<T> comparer.Inverse => new InverseComparer<T>(comparer)\n}\n```\n\nThe motivation is not just a closer philosophical relationship with classic extension methods: It is an explicit goal that existing classic extension methods can be ported to the new syntax in such a way that they remain source and binary compatible. This includes allowing them to be called as static methods, when their declarations follow a certain pattern.\n\nWe've had much less time to explore this approach. There are many possible syntactic directions, and we are just now beginning to tease out which properties are inherent to the approach, and which are the result of specific syntax choices. Which leads us to the following section, trying to compare and contrast the two approaches.\n\n## Comparing type-based and member-based proposals\n\nBoth approaches agree on a number of important points, even as the underlying philosophy differs in what currently feels like fundamental ways:\n\n- __Member syntax:__ In both approaches the member declaration syntax is based on the corresponding instance member declaration syntax. They may be adorned or modified in different ways, but neither attempts to use the naked static method syntax of classic extension methods, or otherwise embrace the lowered form in declaration syntax.\n- __Type syntax:__ Both also introduce a new form of type declaration (with the keyword `extension` or `extensions`) to hold extension member declarations. Neither approach keeps extension members in static classes.\n- __Abstraction:__ Both generally hide the low-level representation of the declaration from language-level use (with one exception in the member-based approach for compatibility purposes). This means that both have the same need for a disambiguation mechanism to replace classic extension methods' ability to be called directly as static methods.\n- __Lookup:__ Both are amenable to pretty much the same range of design options regarding extension member lookup, inference of type arguments, and overload resolution.\n\nAnd of course both approaches share the same overarching goal: to be able to facilitate extension members of nearly every member kind, not just instance methods. Either now or in the future this may include instance and static methods, properties, indexers, events, operators, constructors, user-defined conversions, and even static fields. The only exception is members that add instance state, such as instance fields, auto-properties and field-like events.\n\nThe similarities make it tempting to search for a middle ground, but we haven't found satisfactory compromise proposals (though [not for lack of trying](./compromise-design-for-extensions.md)). Most likely this is because the differences are pretty fundamental. So let's look at what divides the two approaches.\n\n### Relationship to classic extension methods\n\nThe core differentiating factor between the two approaches is how they relate to classic extension methods.\n\nIn the member-based approach, it is a key goal that existing classic extension methods be able to migrate to the new syntax with 100% source and binary compatibility. This includes being able to continue to call them directly as static methods, even though they are no longer directly declared as such. A lot of design choices for the feature flow from there: The underlying type is specified in the style of a parameter, including parameter name and potential ref-kinds. The body refers to the underlying value through the parameter name.\n\nOnly instance extension methods declared within a non-generic `extensions` declaration are compatible and can be called as static methods, and the signature of that static method is no longer self-evident in the declaration syntax.\n\nThe type-based approach also aims for comparable expressiveness to classic extension methods, but without the goal of bringing them forward compatibly. Instead it has a different key objective, which is to declare extension members with the same syntax as the instance and static members they \"pretend\" to be, leaving the specification of the underlying type to the enclosing type declaration. This \"thicker\" abstraction cannot compatibly represent existing classic extension methods. People who want their existing extension methods to stay fully compatible can instead leave them as they are, and they will play well with new extension members.\n\nWhile the type-based approach looks like any other class or struct declaration, this may be deceptive and lead to surprises when things don't work the same way.\n\nThe member-based approach is arguably more contiguous with classic extension methods, whereas the type-based approach is arguably simpler. Which has more weight?\n\n### Handling type parameters\n\nAn area where the member-based approach runs into complexity is when the underlying type is an open generic type. We know from existing extension methods that this is quite frequent, not least in the core .NET libraries where about 30% of extension methods have an open generic underlying type. This includes nearly all extension methods in `System.Linq.Enumerable` and `System.MemoryExtensions`.\n\nClassic extension methods facilitate this through one or (occasionally) more type parameters on the static method that occur in the `this` parameter's type:\n\n``` c#\npublic static class MemoryExtensions\n{\n    public static Span<T> AsSpan<T>(this T[]? array);\n}\n```\n\nThe same approach can be used to - compatibly - declare such a method with the member-based approach:\n\n``` c#\npublic extensions MemoryExtensions\n{\n    public Span<T> (T[]? array).AsSpan<T>();\n}\n```\n\nWe should assume that open generic underlying types would be similarly frequent for other extension member kinds, such as properties and operators. However, those kinds of member declarations don't come with the ability to declare type parameters. If we were to declare `AsSpan` as a property, where to declare the `T`?\n\nThis is a non-issue for the type-based approach, which always has type parameters and underlying type on the enclosing `extension` type declaration.\n\nFor the member-based approach there seem to be two options:\n\n1. Allow non-method extension members to also have type parameters.\n2. Allow the type parameter and the specification of the underlying type on the enclosing type.\n\nBoth lead to significant complication:\n\n#### Type parameters on non-method extension members\n\nSyntactically we can probably find a place to put type parameters on each kind of member. But other questions abound: Should these be allowed on non-extension members too? If so, how does that work, and if not, why not? How are type arguments explicitly passed to each member kind when they can't be inferred - or are they always inferred?\n\n``` c#\npublic extensions MemoryExtensions \n{\n    public Span<T> (T[]? array).AsSpan<T> { get; }\n}\n```\nThis seems like a big language extension to bite off, especially since type parameters on other members isn't really a goal, and current proposals don't go there.\n\n#### Allow type parameters and underlying type to be specified on the enclosing type declaration\n\nIf the enclosing `extensions` type declaration can specify type parameters and underlying type, that would give members such as properties a place to put an open generic underlying type without themselves having type parameters:\n\n``` c#\npublic extensions MemoryExtensions<T> for T[]?\n{\n    public Span<T> (array).AsSpan { get; }\n}\n```\n\nThis is indeed how current member-based proposals address the situation. However, this raises its own set of complexities:\n\n1. Classic extension methods are purely method-based, and the enclosing static class is just a plain container contributing nothing but its name. Here, though, the enclosing `extensions` declaration starts carrying crucial information for at least some scenarios.\n2. There are now two distinct ways of providing the underlying type for an extension member, and figuring out which to use becomes a bit of a decoder-ring situation:\n    - For a compatible port of a classic extension method, the underlying type and any type parameters must be on the _member_.\n    - For non-method extension members with an open generic underlying type, the underlying type and the type parameters must be on the enclosing  _type_.\n    - For extension methods that do not need to be compatible and have an open generic underlying type, the underlying type and the type parameters can be specified _either_ on the method or the type, but the generated code will be incompatible between the two.\n    - For extension members with a closed underlying type, the underlying type can be defined _either_ on the method or the type, and the two are interchangeable.\n3. Once an `extensions` declaration specifies an underlying type, it can no longer be shared between extension members with different underlying types. The grouping of extension members with different underlying types that is one of the benefits of the member-based approach doesn't actually work when non-method extension members with open generic underlying types are involved: You need separate `extensions` declarations with separate type-level underlying types just as in the type-based approach!\n\n``` c#\npublic extensions ArrayMemoryExtensions<T> for T[]?\n{\n    public Span<T> (array).AsSpan { get; }\n}\npublic extensions ArraySegmentMemoryExtensions<T> for ArraySegment<T>?\n{\n    public Span<T> (segment).AsSpan { get; }\n}\n```\n\nIn summary, classic extension methods rely critically on static methods being able to specify both parameters and type parameters. A member-based approach must either extend that capability fully to other member kinds, or it must partially embrace a type-based approach.\n\n### Tweaking parameter semantics\n\nAn area where the type-based approach runs into complexity is when the default behavior for how the underlying value is referenced does not suffice, and the syntax suffers from not having the expressiveness of \"parameter syntax\" for the underlying value.\n\nThis is a non-issue for the member-based approach, which allows all this detail to be specified on each member.\n\nThere are several kinds of information one might want to specify on the underlying value:\n\n#### By-ref or by_value for underlying value types\n\nIn classic extension methods, the fact that the `this` parameter _is_ a parameter can be used to specify details about it that real instance methods don't get to specify about how `this` works in their body. By default, `this` parameters, like all parameters, are passed by value. However, if the underlying type is a value type they can also be specified as `ref`, `ref readonly` and `in`. The benefit is to avoid copying of large structs and - in the case of `ref` - to enable mutation of the receiver itself rather than a copy.\n\nThe use of this varies wildly, but is sometimes very high. Measuring across a few different libraries, the percentage of existing extension methods on value types that take the underlying value by reference ranges from 2% to 78%!\n\nThe type-based approach abstracts away the parameter passing semantics of the underlying value - extension instance members just reference it using `this`, in analogy with instance members in classes and structs. But classes and structs have different \"parameter passing\" semantics for `this`! In classes `this` is by-value, and in structs `this` is by `ref` - or `ref readonly` when the member or struct is declared `readonly`.\n\nThere are two reasonable designs for what the default should be for extension members:\n\n1. Follow classes and structs: When the underlying type is a reference type, pass `this` by value, and when it is a value type pass `this` by `ref` (or perhaps `ref readonly` when the member is `readonly`). In the rare case (<2%) that the underlying type is an unconstrained type parameter, decide at runtime.\n2. Follow classic extension methods: Always pass `this` by value.\n\nEither way, the default will be wrong for some significant number of extension members on value types! Passing by value prevents mutation. Passing by reference is unnecessarily expensive for small value types.\n\nIn order to get to reasonable expressiveness on this, the type-based approach would need to break the abstraction and get a little more \"parameter-like\" with the underlying type. For instance, the `for` clause might optionally specify `ref` or `in`:\n\n``` c#\npublic extension TupleExtensions for ref (int x, int y)\n{\n    public void Swap() => (x, y) = (y, x); // `this` is by ref and can be mutated\n    public readonly int Sum => x + y; // `this` is ref readonly and cannot me mutated\n}\n```\n\n#### Attributes\n\nThis-parameters can have attributes. It is quite rare (< 1%), and the vast majority are nullability-related. Of course, extension members can have attributes, but they would need a way to specify that an attribute goes on the implicit `this` parameter! \n\nOne way is to introduce an additional attribute target, say `this`, which can be put on instance extension members:\n\n``` c#\n[this:NotNullWhen(false)] public bool IsNullOrEmpty => this is null or [];\n```\n\n#### Nullable reference types\n\nA classic extension method can specify the underlying type as a nullable reference type. It is fairly rare (< 2%) but allows for useful scenarios, since, unlike instance members, extension members can actually have useful behavior when invoked on null. Anotating the receiver as nullable allows the extension method to be called without warning on a value that may be null, in exchange for its body dealing with the possibility that the parameter may be null.\n\nA type-based approach could certainly allow the `for` clause to specify a nullable reference type as the underlying type. However, not all extension members on that type might want it to be nullable, and forcing them to be split across two `extension` declarations seems to break with the ideal that nullability shouldn't have semantic impact:\n\n``` c#\npublic extension NullableStringExtension for string?\n{\n    [this:NotNullWhen(false)] public bool IsNullOrEmpty => this is null or [];\n}\npublic extension StringExtension for string\n{\n    public string Reverse() => ...;\n}\n```\n\nIt would be better if nullability could be specified at the member level. But how? Adding new syntax to members seems to be exactly what the type-based approach is trying to avoid! The best bet may be using an attribute with the `this` target as introduced above:\n\n``` c#\npublic extension StringExtension for string\n{\n    [this:AllowNull][this:NotNullWhen(false)] public bool IsNullOrEmpty => this is null or [];\n    public string Reverse() => ...;\n}\n```\n\nThis would allow extension members on nullable and nonnullable versions of the same underlying reference type to be grouped together.\n\n### Grouping\n\nClassic extension methods can be grouped together in static classes without regard to their underlying types. This is not the case with the type-based approach, which requires an `extension` declaration for each underlying type. Unfortunately it is also only partially the case for the member-based approach, as we saw above. Adding e.g. extension properties to `MemoryExtensions`, which has a lot of open generic underlying types, would lead to it having to be broken up into several `extensions` declarations.\n\nThis is an important quality of classic extension methods that unfortunately neither approach is able to fully bring forward.\n\n### Non-extension members\n\nCurrent static classes can of course have non-extension static members, and it is somewhat common for those to co-exist with extension methods.\n\nIn the member-based approach a similar thing should be easy to allow. Since the extension members have special syntactic elements, ordinary static members wouldn't conflict.\n\nIn the type-based approach, ordinary member syntax introduces extension members! So if we want _non_-extension members that would have to be accommodated specially somehow.\n\n### Interface implementation\n\nThe type-based syntax lends itself to a future where extensions implement interfaces on behalf of underlying types.\n\nFor the member-based syntax that would require more design.\n\n## Summary\n\nAll in all, both approaches have some challenges. The member-based approach struggles with open generic underlying types, which are fairly common. They can be addressed in two different ways, both of which add significant syntax and complexity. \n\nThe type-based approach abstracts away parameter details that are occasionally useful or even critical, and would need to be augmented with ways to \"open the lid\" to bring that expressiveness forward from classic extension methods when needed.\n\n"
  },
  {
    "path": "meetings/working-groups/field-keyword/FK-2024-06-26.md",
    "content": "# `field` keyword working group notes for June 26, 2024\n\nWorking group met today at the request of the LDM to look into potential options on how to mesh the `field` keyword and [Nullable Reference Types](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-9.0/nullable-reference-types-specification.md) in a complimentary fashion.\n\nThrough our own investigations and discussions with the community we've identified many areas where we would like the `field` keyword to be available where arguments can be made that the backing field's type should be nullable, even if the property's type is not.  A non-exhaustive list of these cases is at: https://gist.github.com/jnm2/df690bc7278371d735c546c57e787b6e\n\nIn particular, we would like users to take idiomatic code cases that already use a field+property, and move those over to using `field`, ideally with no extra effort.  In other words, we'd like them to be able to remove their field, and replace references to that field in the property with `field` without any extra cruft or mess.\n\nThere are several approaches we can consider, with varying user experience outcomes depending on the approach and the specific example we are looking at.  These working group notes will outline the 5 potential paths we believe have merit, along with some small examinations of interesting outcomes.  A followup document will go into these in depth, showing the outcome of each path against every use case we're aware of.\n\n## Clarifications\n\nAll of the examples deal with a property signature of the form:\n\n```C#\nT Prop { ...field... } // or\nT Prop => ...field...;\n```\n\nWhere `T` is not known to be a value type.  For example, a reference type like `string`, or an unconstrained type parameter.  Importantly, none of this document applies to when `T` is a value type (like `int`).  In that case, the backing field's type is exactly the same as the property type.  We do not want the runtime representation of the two member's types to be different.\n\nFor all followup examples, we'll just use the `T Prop { ...field... }` form as `T Prop => ...field...;` is already equivalent to `T Prop { get { return ...field...; } }`\n\nSimilarly, the examples will often use `_field` when translating the above form to an actual field+property pair.  This does not mean that the field's name is actually `_field`.  It is just a convenient way to indicate it without clutter.\n\n## Approach A. Backing field has the same type as the property type.\n\n### Approach A1. Ship as is with no new rules/understanding of this case.\n\nWith this approach:\n\n```c#\nT Prop { ...field... }\n\n// Would be the same as\nT _field;\nT Prop { ..._field... }\n```\n\nThis is, by far, the simplest approach we can take.  It is also safe to do in C#13, as we can relax this approach in a post launch if we want.  This approach is also likely one of the easiest to explain to users, and how users may immediately think about this feature space from the start.\n\nHowever, there are repercussions for how certain use cases will work here.  For example, if you had:\n\n```c#\nstring Prop { get => field ?? \"\"; private set; } // or\nstring Prop { get => field ??= ComputeInitialValue(); }\n```\n\nYou would get a warning in each constructor that the backing field `_field` was not initialized through all code paths.  This would then require the user to have to suppress the warning, or write something like the following:\n\n```c#\nstring Prop { get => field ??= ComputeInitialValue(); } = null!; // or\n\n// in constructor:\nthis.Prop = null!;\n```\n\nSo, while simple, migrating a trivial, idiomatic case like:\n\n```c#\nstring? _prop;\nstring Prop { get => _prop ??= ComputeInitialValue(); }\n```\n\nwould involve a non-trivial transformation, with potentially annoying suppressions.\n\n### Approach A2. Control backing field warnings with attributes.\n\nWith this approach:\n\n```c#\n[field: MaybeNull] string Prop { ...field... }\n\n// Would be the same as\n[MaybeNull] string _field;\nstring Prop { ..._field... }\n```\n\nThis has the benefit of now both suppressing any warnings about the field being `null` in any constructor, while also providing appropriate warnings if `field` was not used safely.  For example:\n\n```c#\n[field: MaybeNull] string Prop { get => field; } // will appropriately warn\n[field: MaybeNull] string Prop { get => field ??= ComputeValue(); } // will appropriately not warn.\n```\n\nNote: the above approach would also allow for the case where the setter wanted to reset the value back to `null` by using `AllowNull`.  Specifically:\n\n```c#\n// will appropriately not warn.\n[field: MaybeNull, AllowNull] string Prop { get => field ??= ComputeValue(); set => field = value is \"\" ? null : value.Trim(); } \n```\n\nLike with `A1` though, this whole approach comes with the annoying nuisance of having to annotate the field in this fashion to avoid warnings in the constructor. Even if it seems like something the language/compiler could understand.\n\n\n## Approach B.  Backing field has the nullable version of the property type.\n\n### Approach B1. Use existing rules about initializing an auto-prop from a constructor.\n\nWith this approach:\n\n```c#\nstring Prop { ...field... }\n\n// Would be the same as the following for the purpose of analyzing the accessors\nstring? _field;\nstring Prop { ..._field... }\n```\n\nHowever, like with auto-properties today, one would still be required to initialize the property in the constructor, even if not necessary.  So:\n\n```c#\npublic C()\n{\n    // would warn, the auto-prop is not considered initialized\n    Console.WriteLine(this.Prop);\n}\n```\n\nWhereas:\n\n```c#\npublic C()\n{\n    this.Prop = \"\";\n    // would no longer warn, the auto-prop is considered initialized\n    Console.WriteLine(this.Prop);\n}\n```\n\nNote that this analysis is not accurate.  Consider a setter that resets the backing field back to null:\n\n```c#\nstring Prop { get; set => field = value is \"\" ? null : value }\n\npublic C()\n{\n    this.Prop = \"\";\n    // would not warn, even though you could get null. \n    Console.WriteLine(this.Prop);\n}\n```\n\nThe benefit of this approach is the simplicity.  But false negatives might unfortunately emerge for some of these cases.\n\n### Approach B2. Perform flow analysis between constructors and accessors.\n\nThis approach is the most extensive, and would prove to have the most precise understanding of nullable flow between a constructor and the auto-prop accessor.\n\nThe general idea would be perform *nullable analysis* of:\n\n```c#\nT Prop { get => ...field...; set => ...field... } = optional_initializer;\n\npublic C()\n{\n    // ... constructor statements ...\n}\n```\n\nas if it had been written like so:\n\n```c#\npublic C()\n{\n    T? _field = default;\n    _field = optional_initializer; // if present\n\n    // ... constructor statements ...\n    // ... any calls to this.Prop become calls to Prop_get and Prop_set ...\n\n    while (true)\n    {\n        if (rand())\n            Prop_get();\n        else\n            Prop_set(...non-null-value...)\n    }\n\n    T Prop_get() { ...getter body... }\n    void Prop_set(T value) { ...setter body... }\n}\n```\n\nThis looks a bit daunting at first, but comes with a simple general intuition:\n\n1. The language/compiler already support precise NRT flow analysis of locals and local functions within a method.\n1. The backing field is rethought of as just a nullable local field.\n1. If initialized at the property declaration site, there is an upfront assignment to that backing field solely for the purpose of updating the initial flow state.\n1. The normal constructor statements are analyzed, with any calls to the auto-props in the type now being calls to the local functions corresponding to the accessors.  This ensures precise NRT analysis at every call site.\n1. After the constructor statements finish, the property is analyzed again in a fashion that simulates how the getter/setter can be called randomly in any order after the constructor concludes.\n\nWith this formalization, precise NRT analysis just \"falls out\". For example, if the user had:\n\n```c#\nstring Prop { get => field ?? \"\"; private set; } // or\nstring Prop { get => field ??= ComputeInitialValue(); }\n```\n\nthen they would have to do nothing else (no need for any updating of the constructor).  Similarly, the following would be known to be safe without warnings:\n\n```c#\nstring Prop { get => field; set => field = value.Trim(); }\n\npublic C()\n{\n    this.Prop = \"\";\n}\n```\n\nHowever, this would properly report a warning:\n\n```c#\n// warning that `field` in the getter might be null.\nstring Prop { get => field; set => field = value is \"\" ? null : value.Trim(); }\n\npublic C()\n{\n    this.Prop = \"\";\n}\n```\n\nEverything is precise here because we are performing real NRT analysis across the constructor statements, and for after the constructor finishes up.\n\nThe downside here though is complexity of implementation and potential computational costs having to perform this analysis for each constructor in the type.  It would also be critical for diagnostic messages to clearly state both where a null-ref issue might exist, and from what constructor or post-constructor path was potentially causing it.\n\n## Approach C. Backing field's type may or may not be the nullable version of the property's type.\n\nThe final approach we are exploring is one where the backing field is *conditionally* nullable.  The intuition here is to *first* do an initial analysis pass of the get-accessor starting with the assumption that the backing field *is* nullable.  If the conclusion of that analysis is that no exit points of the accessor return a maybe-null expression, then the backing field will be considered nullable.  Otherwise, it will be considered non-nullable, and the existing language rules will take effect.\n\nWith this formalization, the following cases work without the need to do anything in the constructor:\n\n```c#\nstring Prop { get => field ?? \"\"; private set; } // or\nstring Prop { get => field ??= ComputeInitialValue(); }\n```\n\nWith both properties, the initial analysis is done with the backing field being `string?`.  The analysis proves that the get accessor never returns a maybe-null expression.  As such, it's \"safe\" to have a nullable backing field.  And because it is safe, we don't need a constructor initializer.\n\nHowever, if you had:\n\n```c#\n// this will appropriate warn if the constructor or initializer\n// does not assign to the property as the backing field is `string`\n// and thus must be assigned before the constructors exit.\nstring Prop { get => field; set => field = value.Trim(); }\n```\n\nThis seems like a very simple, and limited, form of flow analysis that can make many cases work nicely without difficulty.  \n\n## Next Steps\n\n1. Compiler to give rough estimates on the above approaches.\n1. Rough specs for these options.\n1. Take every example we have and check the experience of each option against them.\n"
  },
  {
    "path": "meetings/working-groups/field-keyword/FK-2024-08-07 Nullability analysis with the `field` keyword.md",
    "content": "# Nullability analysis with the `field` keyword\n\nTable of contents:\n\n- [Motivation](#motivation)\n- [Introduction](#introduction)\n- [Constructor initialization](#constructor-initialization)\n- [Field-targeted nullability attributes](#field-targeted-nullability-attributes)\n- [Property-targeted nullability attributes](#property-targeted-nullability-attributes)\n- [Null-resilient getters](#null-resilient-getters)\n- [Alternatives](#alternatives)\n\n## Motivation\n\nSome vastly common patterns which are served by the `field` feature are lazy initialization, and defaulting. When a field-backed property is non-nullable, it's required to be initialized during construction. This flies in the face of these kinds of properties. They are well-formed. Warnings requiring constructor initialization would be noisy and unwelcome in these properties and in many similar forms.\n\n```cs\npublic List<int> LazyProp => field ??= new();\n\npublic string DefaultingProp { get => field ?? GetDefault(); private set; }\n```\n\nThese are not speculative use cases. They've been highly requested by the community and have been a core part of the design from the beginning. People have been expecting these scenarios to work. It would be a bitter pill to swallow if the scenarios were onerous to use.\n\nFirst, we'll walk through enabling the user to provide existing nullability attributes explicitly for the backing field just as for manually declared fields, such as `[field: MaybeNull]`. Then, we'll walk through how the compiler builds on this capability to apply these attributes automatically in a simple and intuitive fashion.\n\n## Introduction\n\nThis proposal brings together a few building blocks:\n\n1. Properties can be considered initialized to non-null in the constructor by calling the setter, just as with `required` and normal flow analysis today.\n\n1. `field`-targeted nullability attributes work just as with manually declared fields. (E.g. `[field: MaybeNull]`)\n\n1. Null-resilient getters, a simple concept that allows maintaining a property's contract of not returning null, while flexibly allowing idiomatic patterns that use a nullable backing field. \n\nThe following sections will walk through how these concepts play out.\n\n## Constructor initialization\n\nIn C# today, a non-nullable auto property which has no property initializer and is not marked `required` is forced to be initialized in the constructor. We will preserve this enforcement for all field-backed properties. This enforcement is in the form of the existing warning \"CS8618: Non-nullable property 'Prop' must contain a non-null value when exiting constructor.\"\n\nInitializing the property this way, by calling the setter in the constructor, will appease the requirement. This is the case even though a manually implemented setter of a field-backed property does not guarantee that the backing field is actually initialized:\n\n```cs\nclass C\n{\n    public C() { Prop = \"...\"; }\n\n    public string Prop\n    {\n        get;\n        set { if (condition) field = value; }\n    }\n}\n```\n\nWhile this introduces a possibility for null to end up being returned with no warnings, this level of trust in the setter's implementation is consistent with how C# 8 analyzes property assignments of non-null values:\n\n```cs\nobj.NullableProp.ToString(); // Warning\nobj.NullableProp = \"...\";    // This could be calling `set { }`\nobj.NullableProp.ToString(); // No warning\n```\n\nThis is also the same level of trust that is necessary when the burden of initializing is moved via `required`, from the constructor to the caller of the constructor:\n\n```cs\nnew C() { Prop = \"...\" };\n\nclass C\n{\n    public required string Prop\n    {\n        get;\n        set { if (condition) field = value; }\n    }\n}\n```\n\nSee [Constructor initialization alternatives](#constructor-initialization-alternatives) for alternatives that were considered.\n\n## Field-targeted nullability attributes\n\nThe nullability attributes which are applicable to regular fields may be applied to the backing field of a property using the existing `field:` attribute target. These are the preconditions `AllowNull` and `DisallowNull` and the postconditions `MaybeNull` and `NotNull`.\n\nWhen applied, they affect the nullability analysis of the `field` keyword within the accessors just as they would affect a manually declared field. In cases where the manually-declared field would be required to be assigned in constructors, the field-backed property will be required to be assigned in constructors.\n\n### Postconditions (MaybeNull, NotNull)\n\nWhen `[field: MaybeNull]` is applied on a non-nullable field-backed property, the property will not be required to be initialized in all construction paths. This is consistent with how a manually declared non-nullable field would no longer be required to be initialized when this attribute is applied to it.\n\nThe reverse is true for `[field: NotNull]` on a *nullable* property. Just like how this would cause warnings requiring a manually declared field to be initialized in all construction paths, applying `[field: NotNull]` to a field-backed property will cause the property to be required to be initialized in all construction paths.\n\n#### Examples \n\nThis will give \"CS8603: Possible null reference return\" on `field` just as with a manually declared field:\n\n```cs\n// CS8603: Possible null reference return\n[field: MaybeNull]\npublic string Prop { get => field; set => field = value; }\n                            ~~~~~\n```\n\nThe same warning will be shown here on 'get', since `get;` expands to `get => field;`:\n\n```cs\n// CS8603: Possible null reference return\n[field: MaybeNull]\npublic string Prop { get; set => field = value; }\n                     ~~~\n```\n\nThe next example is not real code we expect people to write, but for consistency its behavior will change. In C# 12, the attribute is ignored. In C# 13, applying this attribute to an auto-property will show the same warning as in the previous example, instead of showing \"CS8618: Non-nullable property 'Prop' must contain a non-null value when exiting constructor.\"\n\n```cs\n// CS8603: Possible null reference return\n[field: MaybeNull]\npublic string Prop { get; set; }\n                     ~~~\n```\n\n### Preconditions (AllowNull, DisallowNull)\n\nWhen `[field: AllowNull]` is applied on a non-nullable field-backed property, the property will be able to assign maybe-null values to the field without a warning. Here's an example:\n\n```cs\n[field: AllowNull]\npublic string ResetIfSetToDefault\n{\n    get => field ?? GetDefault();\n    set => field = (value == GetDefault() ? null : value);\n}\n```\n\nAutomatic `field` nullability is covered by the [null-resilient getter proposal](#null-resilient-getters) below. `[field: AllowNull, MaybeNull]` will be automatically applied due to the `?? GetDefault();` in the example above, and will not be applied if the `?? Default();` is removed.\n\nThis is safer than manually declaring `[field: AllowNull]` because there is an existing hole in C#'s nullability analysis that allows null to be returned from the property with no warning:\n\n```cs\n// C# 12. No warning to initialize 'field' and no warning in the getter.\n[AllowNull]\nprivate string field;\n\npublic string ResetIfSetToDefault\n{\n    get => field; // Returns null! `?? GetDefault()` is missing\n    set => field = value == GetDefault() ? null : value;\n}\n```\n\nNo use cases are known for `[field: DisallowNull]`, but it would be part of the automatic set of behaviors inherited from how manually-declared fields work.\n\n```cs\n// CS8601 Possible null reference assignment\n[field: DisallowNull]\npublic string? Prop { get; set => field = value; }\n                                          ~~~~~\n\n// CS8601 Possible null reference assignment\n[field: DisallowNull]\npublic string? Prop { get => field; set; }\n                                    ~~~\n\n// With C# 13, same warning as the previous example.\n// With C# 12, the attribute is ignored.\n[field: DisallowNull]\npublic string? Prop { get; set; }\n                           ~~~\n```\n\nHowever, if the property also has `DisallowNull` applied, then there is no warning:\n\n```cs\n[DisallowNull]\n[field: DisallowNull]\npublic string? Prop { get; set => field = value; } // No warning\n```\n\n## Property-targeted nullability attributes\n\nNullability attributes applied to the property itself will not be automatically inherited by the backing field. The intended scenario for applying `[AllowNull]` to a property is where the property setter sanitizes nulls to other values before storing in the field.\n\n```cs\n[AllowNull]\npublic string Prop { get; set => field = value ?? \"\"; }\n```\n\nIf the user actually wants to store `null` in the field, the user can either rely on the automatic `field` nullability granted by the [null-resilient getter proposal](#null-resilient-getters) below:\n\n```cs\n[AllowNull]\npublic string Prop { get => field ?? GetDefault(); set; }\n```\n\nOr if that version is not taken, the user will have to add `[field: AllowNull]` as well:\n\n```cs\n[AllowNull]\n[field: AllowNull]\npublic string Prop { get => field ?? GetDefault(); set; }\n```\n\n## Null-resilient getters\n\nA central scenario for the `field` keyword is lazily-initialized properties. Without automatic nullability, users would have to manually place `[field: MaybeNull]` on every lazily-initialized property in order for the compiler to stop telling the user that the _lazily_-initialized property should be initialized in the _constructor_!\n\n```cs\n// This is ungainly.\n[field: MaybeNull]\npublic List<int> Prop => field ??= new();\n```\n\nA null-resilient getter is a getter which continues to fulfill the property's contract of not returning a `null` value, even when `field` is maybe-null at the start of the getter. For properties with a null-resilient getter, the backing field does not need to be initialized, and it may be assigned a maybe-null value at any point, all without risk of returning `null` from a non-nullable property.\n\nNull resilience is further extended to mean that there are no nullability warnings when `field` is maybe-null. This is inclusive of checking that no exit point returns a maybe-null expression. We would determine null resilience by analyzing the getter with a pass that starts `field` out as maybe-null and checks to see that there are no nullability warnings. (A less inclusive alternative is considered in [Definition of null resilience](#definition-of-null-resilience).)\n\nThese getters are null-resilient because there are no nullability warnings when `field` is maybe-null:\n\n```cs\nget => field ?? \"\";\nget => field ??= new();\nget => LazyInitializer.EnsureInitialized(ref field, ...);\nget => field ?? throw new InvalidOperationException(...);\nget => throw new NotImplementedException();\nget => field!;\n```\n\nThese getters are not null-resilient because there are nullability warnings when `field` is maybe-null:\n\n```cs\nget;\nget => field;\nget => field ?? SomethingNullable;\nget => (T[]?)field?.Clone();\nget => (T[])field.Clone();\nget\n{\n    string unrelated = null; // Warning\n    return field ?? \"\";\n}\n```\n\nOn field-backed properties with a null-resilient getter, if the property type is non-nullable and not a value type, and no field-targeted nullability attributes are manually specified, `[field: AllowNull, MaybeNull]` will be automatically applied. Or, equivalently the field type may become nullable.\n\nAlternatively, AllowNull could be left off, which is considered in [Full or half nullability](#full-or-half-nullability).\n\nIn terms of explaining this feature to users, users are more used to thinking in terms of `string?` more than working with attributes.\n\n### Open question: unrelated nullability warnings\n\nShould two passes be done, so that the getter's null-resilience is only impacted by warnings that relate to the flow state of `field`?\n\n```cs\nget\n{\n    string unrelated = null; // Warning\n    return field ?? \"\";\n}\n```\n\n### Open question: interaction with manually-applied attributes\n\nIf the user directly applies `[field: MaybeNull]` or `[field: NotNull]`, the getter is not checked for null resilience because the user has already stated the outcome they intend.\n\nHowever, if the user directly applies only the _precondition_ `[field: AllowNull]` or `[field: DisallowNull]` and not the _postcondition_ `[field: MaybeNull]` or `[field: NotNull]`, should the postcondition still be automatically determined based on the null resilience of the getter? Or, between the reading non-nullable property type and the modification of `[field: AllowNull]`, should the ommission of `[field: MaybeNull]` be taken to mean the same as if `[field: NotNull]` had explicitly been stated?\n\nIn other words, in the following example, does the user intend `[field: AllowNull, NotNull]`, or merely `[field: AllowNull]` with `MaybeNull` automatically applied as long as it is safe due to the getter being null-resilient?\n```cs\n[field: AllowNull] // Manually specified, though it could also be inferred due to null-resilience\npublic string Prop { get => field ?? GetDefault(); set; }\n```\n\n## Alternatives\n\n### Constructor initialization alternatives\n\nAs proposed, a property assignment in the constructor will appease \"CS8618: Non-nullable property 'Prop' must contain a non-null value when exiting constructor,\" even if the setter does not initialize the backing field. A more conservative alternative to this would be cross-body nullability analysis, analyzing each constructor body as though the setter bodies were inlined into the constructor bodies in order to establish whether initialization is statically guaranteed.\n\nThis would bring extra safety, but also extra noise. There would be cases where the user would have to suppress initialization warnings on valid code, such as the following:\n```cs\nclass C\n{\n    // With cross-body analysis, this still warns!\n    // CS8618: Non-nullable property 'Prop' must contain a non-null value when exiting constructor\n    public C() { Prop = \"...\"; }\n\n    public string Prop\n    {\n        get;\n        set { if (condition) field = value; }\n    }\n}\n```\n\nThe warning is due to the cross-body analysis seeing this inlined form, which does not assign on all construction paths:\n```cs\n    public C() { if (condition) <Prop>k__BackingField = \"...\"; }\n```\n\nThis requires a suppression, such as `= null!` which initializes the field directly. After adding such a suppression, the user is in a scenario where even totally removing the constructor assignment does not cause a warning.\n```cs\n    public string Prop\n    {\n        get;\n        set { if (condition) field = value; }\n    } = null!;\n```\n\nThe cross-body analysis approach is complex both for implementation and for users understanding how to react to warnings. The working group recommends not pursuing cross-body analysis.\n\nA different alternative could be to ignore assignments to manually implemented setters. This would require users to generally add pragmas or `= null!` property initializers even when assigning the property in the constructor, which seems punishing and noisy.\n\n### Definition of null resilience\n\nAlternatively, null resilience could be defined more directly around what it means to uphold a non-nullable contract, namely that a null value is never returned. Instead of collecting _all_ nullability warnings during the analysis pass where `field` is initially maybe-null, we would only examine exit points and ensure that every exit point is still returning a not-null expression in spite of `field` being maybe-null.\n\nHere's an example of where the difference would show. This would change from not being null-resilient, to being considered null-resilient. This is technically fulfilling the aspect of the property contract that a null value is never returned, even while it implicitly throws NullReferenceException.\n\nIn the alternative where this getter is considered null-resilient, the user will immediately get a warning in the code which will be confusing. Furthermore, there's no good way to respond to the warning; even when the property is initialized, the getter will be considered null-resilient and thus will allow `field` to hold nulls:\n```cs\nclass C<T>\n{\n    public C(T[] prop) { Prop = prop; }\n\n    // CS8602: Dereference of a possibly null reference.\n    public T[] Prop { get => (T[])field.Clone(); private set; }\n                                  ~~~~~\n}\n```\n\nNot taking the alternative, and not considering this getter to be null-resilient, the warning is exchanged for a construction warning. This warning is desirable because it points the way to properly addressing it by making sure the property is initialized during construction, at which point the warning disappears.\n```cs\nclass C<T>\n{\n    // CS8618: Non-nullable property 'Prop' must contain a non-null value when exiting constructor.\n    public T[] Prop { get => (T[])field.Clone(); private set; }\n               ~~~~\n}\n```\n\n### Full or half nullability\n\nNull resilience means that the backing field may always hold `null` at the start of the getter. The simplest way for the user to think of this is for the field type to be nullable. The field type being nullable could also be thought of as applying `[field: MaybeNull, AllowNull]`, which is what the user would have to manually specify in the absence of automatic `field` nullability.\n\nAlternatively, instead of `[field: MaybeNull, AllowNull]`, the automatic nullability could be weakened to `[field: MaybeNull]`. This would retain the benefits of not requiring constructor initialization, but it would require the user to manually add `[field: AllowNull]` in scenarios where the user wants to take full advantage of the null-resilience of the property and assign maybe-null values to the backing field:\n\n```cs\n[field: AllowNull] // Required if we only go halfway.\npublic string ResetIfSetToDefault\n{\n    get => field ?? GetDefault();\n    set => field = value == GetDefault() ? null : value;\n}\n```\n\nThe presence of `[field: AllowNull]` also opens up an existing kind of safety hole. Once it's specified, if you remove `?? GetDefault()`, there will be no nullability warnings in spite of the whole which this leaves. This can be shown in the language today:\n\n```cs\nclass C\n{\n    [AllowNull]\n    private string resetIfSetToDefault;\n\n    public string ResetIfSetToDefault\n    {\n        // Removed `?? GetDefault()` without warnings!\n        get => resetIfSetToDefault; \n        set => resetIfSetToDefault = value == GetDefault() ? null : value;\n    }\n}\n```\n"
  },
  {
    "path": "meetings/working-groups/field-keyword/FK-2024-08-07.md",
    "content": "# `field` keyword working group notes for August 7, 2024\n\nThe working group met to review the [Nullability analysis with the `field` keyword](FK-2024-08-07%20Nullability%20analysis%20with%20the%20`field`%20keyword.md) proposal to discuss the direction and come away ready to start on spec updates to present to the LDM.\n\n## Takeaways\n\nThere was agreement on the changes laid out in the document. This included taking the proposed version of null-resilient getters, instead of the alternatives:\n\n- We like the version of null-resilient getters that takes all nullability warnings into consideration, not just ensuring that exit points return non-null expressions. This should be very cheap to implement.\n\n- We see no reason to stop halfway and apply only `[field: MaybeNull]` without `[field: AllowNull]`. The latter would just be harder to explain to users.\n\n### Motivation takeaway\n\nFor the motivation to apply nullability automatically, we felt the motivation was much stronger than simply that it is too much code to write to manually specify `[field: MaybeNull]` in a common scenario. Rather, we feel that these nullability attributes are hard for users to understand and get right. It's much greater of a conceptual hurdle than we want for how commonplace it will be to write simple lazy or defaulting scenarios.\n\n```cs\n[field: MaybeNull]\npublic string Prop => field ?? GetDefault();\n\n[field: MaybeNull]\npublic List<int> Prop => field ??= new();\n\n[field: MaybeNull]\npublic SomeComponent Prop => LazyInitializer.EnsureInitialized(ref field);\n```\n\n### Additional NRT checking for setters\n\nThe [constructor initialization](FK-2024-08-07%20Nullability%20analysis%20with%20the%20`field`%20keyword.md#constructor-initialization) section proposes that \"CS8618: Non-nullable property 'Prop' must contain a non-null value when exiting constructor\" will be appeased by calling the property setter in the constructor, trusting that the property getter will return a non-null value after that call. This has precedent in C#.\n\nThis was accepted, but a suggestion was made to check the other half of this initialization scenario. The setter could be analyzed as though it had a `MemberNotNull` attribute guaranteeing that the backing field is not null by the time it exits.\n\nApplying MemberNotNull-style analysis to the setter would provide useful warnings for two kinds of issues. One, where the field was null during the initial call to the property setter:\n\n```cs\nclass C\n{\n    public C() { Prop = \"...\" };\n\n    public string Prop\n    {\n        get;\n        set\n        {\n            // CS8602 Dereference of a possibly null reference.\n            Console.WriteLine(field.Length);\n                              ~~~~~\n            field = value;\n        }\n    }\n}\n```\n\nAnd two, where the property setter can return without initializing the backing field:\n\n```cs\nclass C\n{\n    public C() { Prop = \"...\" };\n\n    public string Prop\n    {\n        get;\n        set\n        {\n            if (condition) field = value;\n        //  CS8774 Member 'field' must have a non-null value when exiting.\n        }\n        ~\n    }\n}\n```\n\n### Nullable backing field\n\nWe preferred the idea of making the backing field nullable rather than keeping it matching the property type while applying `[field: AllowNull, MaybeNull]`. Users are by far more familiar with using nullable types than working with the attributes. The null-resilient getter concept is stronger when its usage and explanation is simpler for users. Making the field nullable at the symbolic level is a difference that would be visible through the IDE, where the user would see a question mark after the type when hovering over the `field` keyword.\n\n### `[AllowNull]` nullability hole\n\nThe proposal mentions that there is an existing nullability hole in the language when `[AllowNull]` is applied to a field, and that this hole will be inherited by `[field: AllowNull]`:\n\n```cs\n// C# 12\nclass C\n{\n    [AllowNull]\n    private string resetIfSetToDefault;\n\n    public string ResetIfSetToDefault\n    {\n        // Removed `?? GetDefault()` without warnings!\n        get => resetIfSetToDefault;\n        set => resetIfSetToDefault = value == GetDefault() ? null : value;\n    }\n}\n```\n\nThe point was raised that when it comes to `[field: AllowNull]`, we might have an opportunity to close that gap in warnings because the backing field is scoped to the property. For instance, perhaps we could simply create a nullability warning if `[field: AllowNull]` is used without `[field: MaybeNull]`.\n\nAs mentioned elsewhere, `[field: AllowNull]` is likely only going to be specified in advanced scenarios where automatic backing field nullability (somewhat equivalent to AllowNull and MaybeNull together) isn't what the user wants.\n\n### Open question: unrelated nullability warnings\n\nWe considered whether unrelated nullability warnings should affect the nullability of the backing field:\n\n```cs\n// Is this a null-resilient getter?\nget\n{\n    string unrelated = null; // Warning\n    return field ?? \"\";\n}\n```\n\nDetecting the relatedness of a warning would likely be based on doing two nullability analysis passes, and considering the getter to be null-resilient if there are no _new_ warnings present in a maybe-null-field pass which were not present in a non-null-field pass. This diff would likely not be expensive to do. Any additional expense would also only kick in with new code, and even in new code, we expect complex getters to be quite rare. And in the event that a user needs an escape hatch to skip the null resilience evaluation, the user can apply nullability attributes manually.\n\nThere could be occasional scenarios with inferred generic type arguments where there is a different error in each pass; however, what would fall out in that case would be a \"not null-resilient\" detection, which is a safe place to land, still closer to the mark than doing only a single pass. Finally, it might be harder to explain and understand \"are there new warnings caused by `field` becoming nullable\" compared to understanding \"are there any warnings when `field` is nullable.\"\n\nWe decided to implement only one pass for now and see how it does in practice during implementation. We can revisit this if it seems that the single pass is leaving something to be desired.\n\n### Open question: interaction with manually-applied attributes\n\nWe decided that if any nullability attribute is applied using a `field:` target, including the preconditions AllowNull and DisallowNull, then null resilience will not be considered. The user has already entered the space of taking control over the nullability of the backing field. Someone specifying a nullability attribute is likely using it as an escape hatch because the null resilience check wasn't what they wanted.\n\n## Next steps\n\nWe would like to bring three options to LDM:\n1. No specific nullability support at all.  Users would be forced to initialize all non-nullable properties, regardless of their bodies.\n2. Only support field-targeted attributes.  Users could suppress initialization warnings, through explicit addition of particular attributes for particular property bodies.\n3. Support field-targeted attributes as well as null-resilient getters.  Users would normally not get initialization warnings and would not need to add attributes for safe coding patterns.\n\nTo get ready to present these options to LDM, a compiler team member will write the nullability spec changes and optionally do some implementation investigations.\n"
  },
  {
    "path": "meetings/working-groups/interceptors/IC-2023-03-20.md",
    "content": "# Interceptors working group notes for 20th March 2023\n\nWe explored the extension shadowing concept and compared with interceptors to determine where to invest to meet our short and long term goals.\n\n## Extension shadowing\n\nhttps://github.com/dotnet/csharplang/issues/7061\n\nThe working group had several observations to make about this approach:\n\n### Constant propagation\n\nWhile generalized compile-time constant propagation is intractible, there are ways to scope it down and make the \"dispatch blocks\" proposed in this approach work well. For example, we can mark specific methods or parameters to indicate that the AOT compiler should do some interprocedural analysis, e.g. `void M([ConstantExpected] string param)`. The AOT compiler already takes hints on whether to do interprocedural analysis based on knowledge of Roslyn compiler-generated symbols, and `[ConstantExpected]` actually already exists.\n\nThe suggestion in this case would be not to inline these \"dispatch block\" methods, but instead to trim as though the arguments coming in are constant, eliminating any dead branches within the block.\n\nRoslyn has fairly sophisticated emit behavior when switching on strings which complicates the AOT compiler's ability to optimize in cases like these. We might want to give some hints to downstream compilers to make it easier for them. It helps that these extensions will usually be used in the same assembly they are declared in.\n\nWe also gave some consideration to whether Roslyn could adjust its codegen based on presence of these attributes. For example, Roslyn hasn't really done method inlining to date, but we might introduce it in order to handle scenarios like these.\n\n```cs\n// ASP.NET library\nimplicit extension RouteBuilderExtension for IEndpointRouteBuilder\n{\n    public void MapGet(\n        string route,\n        Delegate handler) { }\n}\n\n// Generated.cs\nimplicit extension SpecializedRouteBuilder : RouteBuilderExtension\n{\n    // produced by the source generator:\n    public void MapGet(\n        string route,\n        Delegate handler,\n        [ConstantExpected] [CallerFilePath] string? filePath = null,\n        [CallerLineNumber] int lineNumber = -1,\n        [CallerCharacterNumber] int characterNumber = -1) // https://github.com/dotnet/csharplang/issues/3992\n    {\n        switch (filePath, lineNumber, characterNumber)\n        {\n            case (\"User.main.cs\", 5, 11): MapProducts(handler);\n            case (\"User.main.cs\", 6, 11): MapUsers(handler);\n            // imagine there are many many more cases than these...\n            default: throw new Exception(\"unknown route\");\n        }\n    }\n    \n    // roughly what the AOT compiler ends up generating:\n    public void MapGet(\n        string route,\n        Delegate handler,\n        [ConstantExpected] [CallerFilePath] string? filePath = null,\n        [CallerLineNumber] int lineNumber = -1,\n        [CallerCharacterNumber] int characterNumber = -1) // https://github.com/dotnet/csharplang/issues/3992\n    {\n        switch (filePath, lineNumber, characterNumber)\n        {\n            // The path which adds a handler for 'Products' is unreachable, so it is elided here.\n            case (\"User.main.cs\", 6, 11): MapUsers(handler);\n            // imagine there are many many more cases than these...\n            default: throw new Exception(\"unknown route\");\n        }\n    }\n}\n```\n\n### Denoting shadowing, and shadowing non-extensions\n\nIf we went with this approach, we would need extensions to be able to shadow non-extension methods. This feels fairly risky.\n\nIt isn't clear whether a \"shadowable\" modifier on base members is needed or not, or if some new usage of the \"new\" modifier in extensions is needed or not. It feels like requiring too much opt-in will be burdensome, but not enough opt-in might confuse users.\n\nAdditionally, the actual lookup rules could be quite difficult to get right. Extensions will be able to be declared in complex hierarchies, with members varying in signature and potential \"betterness\". It's possible new overload resolution rules would be needed in order to make things work here, and it may be very difficult to formulate the right rule, build it and test it.\n\nWe believe that extension shadowing would be more work across more teams than interceptors would be.\n\n## Interceptors\n\nThere are some toolability concerns for InterceptsLocationAttribute.\n\nIt may be problematic if locations aren't normalized. Directory separators, etc. differ across platforms. This means that cross-platform projects would basically only work if their interceptors are created exclusively by source generators during the build. Of course, the \"brittleness\" problem with locations affects that as well.\n\nWe're not certain to what extent to invest in IDE support. One particular concern we have is just how many editor features would need to be updated to indicate new information about the meaning of a call. Also, the possibility of interception may make things like incrementally analyzing method edits more expensive. This is what pushed us toward including a syntactic marker like `#Interceptable()` in earlier passes on the feature.\n\nHowever, in terms of program behavior and perf characteristics, we think this is easier to get right for the scenarios we care about than extension shadowing. The concerns about inlining and trimmability are removed.\n\n## Conclusion\n\nWe think that interceptors are the better of the two approaches to address key scenarios for .NET 8.\n\nWe will treat interceptors as an *experimental compiler feature* for .NET 8. The feature will have diagnostics for misuse, but it will have a limited amount of design-time traceability. The feature may have breaking changes or be removed in a future release.\n"
  },
  {
    "path": "meetings/working-groups/interceptors/IC-2023-04-04.md",
    "content": "# Interceptors working group notes for 4th April 2023\n\nThe working group reviewed the design doc for the [interceptors compiler feature](https://github.com/dotnet/roslyn/blob/c16a87d4c58a8f6e64f5f6fbb7b885201c7c8dc0/docs/features/interceptors.md), and addressed some of the open questions.\n\n**Are the `[InterceptsLocation]` attributes dropped when emitting the methods to metadata?**\n\nNo. Other attributes which are specially recognized by the compiler (which also are not pseudo-custom attributes) aren't dropped in this way. We don't think it's problematic to do the same here.\n\n**Should we permit interceptors declared in file types to refer to other files?**\n\nYes. We think it's fine for the compiler to intercept with a call to an \"effectively file-local\" interceptor, even if the call is not in the same file as the interceptor.\n\nOne concern that could come up here is: what if the runtime wanted to add a *reified* concept of `file` accessibility? Then, assuming the compiler adopted it, using file-local types in this way it might actually fail at runtime. However, we don't think adding such runtime enforcement is especially compelling, and feel comfortable blocking the ability to add it in the future.\n\n**What kind of user opt-in step should be required to use interceptors?**\n\nInterceptors are in an unusual spot compared to preview features we've shipped in the past.\n- We want to use them in *stable/supported* scenarios, including a stable `<LangVersion>`. We think referring to the feature as *preview* isn't quite right, as preview features aren't used as components of *stable* features. This is part of why the label *experimental* was chosen.\n- We want them to be an implementation detail of certain source generators. If any opt-in step is necessary, we want generators to essentially be able to do it on behalf of users.\n- We want to be able to change them based on what we learn from their usage in .NET 8. In order to get a significant enough amount of usage, we want them to be used in the mainline \"ASP.NET Minimal API with NativeAOT\" scenario, without the user having to set an extra property in their project, for example.\n\nWhen discussing what kind of opt-in step to build, we also ended up discussing the entire conception of the feature as \"experimental\", and the associated set of risks.\n\nOne problematic scenario we considered is: what happens when someone installs a .NET 9 SDK someday and uses `<TargetFramework>net8.0</TargetFramework>`. We might be in a situation where interceptor-based source generators from the .NET 8 targeting pack get used, while .NET 9 has removed or changed support for them.\n\nTo keep things from failing in that case, we would need to either maintain support in the compiler for as long as .NET 8 is supported, or the generator author (basically, the runtime) would need to service the targeting pack. We think this wouldn't be a problem for generators which ship in the SDK, which are more naturally \"synchronized\" with the compiler version in use.\n\nIt was suggested that it's not extremely problematic for this feature to stay around for the .NET 8 support cycle, or even stay around indefinitely, just because a feature is introduced later that handles the scenarios better.\n\n**Conclusion**\n\nThere will be no opt-in step needed to use interceptors.\n\nWe think that an opt-in step which is only performed by generators doesn't add enough *safety value* to be justified. Instead, we want to convey in documentation that early adoption of interceptors is risky. We will not *publicize* the feature (in blog posts, etc..) as something third-party generator authors should onboard to at this time.\n"
  },
  {
    "path": "meetings/working-groups/interceptors/interceptors-issues-2024-01.md",
    "content": "# Open issues for interceptors\n\nThe following issues were identified during the interceptors preview, and should be addressed before the feature is transitioned to stable.\n\nFurther down there is a \"Future\" section containing issues which do not block the move to stable, but could be addressed in the longer term.\n\n## Checksums instead of file paths\n\nWe identified a number of issues with using file paths to identify the location of a call.\n\n- Absolute paths, while simple and accurate, break portability (the ability to generate code in one environment and compile it in another).\n- Relative paths require generator authors to consume contextual information about \"where the generated file will be written to\" on disk. This complicates the public API design and feels arbitrary.\n- We considered also introducing \"project-relative\" paths for use in InterceptsLocationAttribute, which would reduce the amount of public API bloat. However, this effectively introduces a new requirement on compilations created through the public APIs: they need to have the path resolvers in compilation options properly configured to indicate where the \"project root\" is. Otherwise, the Roslyn APIs can't correctly interpret the meaning of source code in the compilation.\n\nWe finally arrived at checksums as a more satisfactory way of identifying the file containing the intercepted call. This essentially does away with the portability and complexity concerns around paths.\n\nIt also pushes us toward an opaque representation of \"interceptable locations\". In the design we have now, it's expected that InterceptsLocation attribute arguments are produced solely by calling the public APIs. We don't expect users to create or to interpret the arguments to InterceptsLocationAttribute.\n\nSee https://github.com/dotnet/roslyn/issues/72133 for further details on the public API design.\nhttps://github.com/RikkiGibson/roslyn/blob/interceptablelocation/docs/features/interceptors.md includes more precise details on the location format.\n\n**Resolution**: The described design was approved by LDM on [2024-04-15](https://github.com/dotnet/csharplang/blob/d5bab90e846f9b3e9a7a4e552249643148f0194d/meetings/2024/LDM-2024-04-15.md#interceptors).\n\n## Need for interceptor semantic info in IDE\n\nWe added public API which allows determining if a call in a compilation is being intercepted, and if so, which method declaration is decorated with the InterceptsLocationAttribute referencing the call.\n\nSee https://github.com/dotnet/roslyn/issues/72093 for further details.\n\n**Resolution**: No LDM decision here, this was informational to help LDM understand the larger context which the design sits in.\n\n### `<InterceptorsNamespaces>` property\n\nWe introduced an MSBuild property `<InterceptorsPreviewNamespaces>` as part of the experimental release of the interceptors feature. A compilation error occurs if an interceptor is declared outside of one of the namespaces listed in this property. We suggest keeping this property under the name `<InterceptorsNamespaces>`, eventually phasing out the original name. This will help us get a better level of performance with the `GetInterceptorMethod` public API, by reducing the set of declarations which need to be searched for possible `[InterceptsLocation]` attributes.\n\n**Not yet resolved.** As of 2024-05-13 the property is still present in the implementation as `<InterceptorsPreviewNamespaces>`. We'll seek confirmation with LDM whether to proceed with the suggested requirement that generators and/or users specify `<InterceptorsNamespaces>` (perhaps phasing out the use of the original property name).\n\n## Future (possibly post-C# 13)\n\n### Intercepting properties\nCurrently the interceptors feature only supports intercepting ordinary methods. Much like with partial methods and the upcoming partial properties, users want to be able to intercept usages of more kinds of members, such as properties and constructors.\n\n  - UnsafeAccessor does not support properties directly. Instead, a given usage of UnsafeAccessor decorates a method which calls through to a single property accessor.\n  - Consider: What happens when we want to intercept `obj.Prop += a`? We can't choose a single method to replace usage of `Prop`.\n  - Conclusion: We should probably favor intercepting a property with an extension property. We are likely blocked here until we ship extensions.\n\n### Intercepting constructors and other member kinds\n\nFor all the member kinds we want to support, we will need to decide how usages of each member kind are denoted syntactically. In terms of signature matching requirements, we should try to be consistent with [UnsafeAccessorAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.unsafeaccessorattribute?view=net-8.0), which also works by referencing members in attribute arguments.\n\nFor method invocations like `receiver.M(args)`, we use the location of the `M` token to intercept the call. Perhaps for property accesses like `receiver.P` we can use location of the `P` token. For constructors should use the location of the `new` token.\n\nFor member usages such as user-defined implicit conversions which do not have any specific corresponding syntax, we expect that interception will never be possible.\n\n### Interceptor signature variance and advanced generics cases\n\nIn the experimental release of interceptors, we've used a fairly stringent [signature matching](https://github.com/dotnet/roslyn/blob/main/docs/features/interceptors.md#signature-matching) requirement which does not permit variance of the parameter or return types between the interceptor and original methods.\n\nWe also have limited support for [generics](https://github.com/dotnet/roslyn/blob/main/docs/features/interceptors.md#arity). Essentially, an interceptor needs to either have the same arity as the original method, or it needs to not be generic at all.\n\nASP.NET has a [use case](https://github.com/dotnet/aspnetcore/issues/47338), which in order to address, we would need to make adjustments in both the above areas.\n\n```cs\nclass Original<TCaptured>\n{\n    public void M1()\n    {\n        API.M2(() => this);\n    }\n}\n\nclass API\n{\n    public static void M2(Delegate del) { }\n}\n\nclass Interceptors\n{\n    [InterceptsLocation(/* API.M2(() => this) */)]\n    public static void M3<T>(Func<T> func) { }\n}\n```\n\nIn `M3<T>`, the generator author wants to be able to use the the type parameter `TCaptured` within the return value `=> this`. This means that we would need to permit a parameter type difference between interceptor and original methods where an implicit reference conversion exists from the interceptor parameter type (`Func<T>`) to the original method parameter type (`Delegate`). We would need to start reporting errors when the argument of an intercepted call is not convertible to the interceptor parameter type.\n\nAny change we make in this vein, we should be careful has no possibility for \"ripple effects\", e.g. use of an interceptor changing the type of an expression, then changing the overload resolution of another call, changing the type of a `var`, and so on.\n\nWe would also need to define how the type arguments to the `M3<T>` call are determined. This might require doing a type argument inference on the intercepted \"version\" of the call.\n\nThere are more specifics which need to be investigated here before we can be sure how to move forward. ASP.NET has indicated this can wait till later in the .NET 9 cycle, so we'd like to push this question out until we've addressed the more urgent aspects of the feature design.\n\n### Design meetings\n\n- https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-04-15.md#interceptors\n\n"
  },
  {
    "path": "meetings/working-groups/nullability-improvements/NI-2022-10-24.md",
    "content": "# Nullability improvements working group meeting for October 24th, 2022\n\nThe *nullability improvements* working group met to look at issues which were raised during LDM triage and/or have received significant community engagement.\n\n## Task<T> covariance\nhttps://github.com/dotnet/csharplang/issues/3950\n\nThe general scenario that people have complained about is:\n```cs\nusing System.Threading.Tasks;\n\n#nullable enable\n\npublic class C\n{\n   public Task<string?> M() // not async\n   {\n       return Task.FromResult(\"\"); // type of return value is Task<string>, which warns when converting to Task<string?>.\n   }\n}\n```\n\nWe saw that this was reported on a few different occasions. We think this is a fairly annoying papercut and that it would be nice to be able to make it \"just work\".\n\nA few options we considered to that end:\n\n### Option 0: special-case Task<T>\n\nIEquatable is already \"special\" in the compiler in that it is \"nullable-contravariant\", not fully contravariant: `IEquatable<string?>` is convertible to `IEquatable<string>`. This limited form of contravariance is primarily present for compat reasons, though there are design reasons one might want it to work this way as well.\n\n```cs\nIEquatable<string?> e1 = ...;\nIEquatable<string> e2 = e1; // ok\nIEquatable<string?> e3 = e2; // warning CS8619: Nullability of reference types in value of type 'IEquatable<string>' doesn't match target type 'IEquatable<string?>'.\n```\n\nBecause only the same few types have been used in the samples where people complain about *nullable-invariance*, we think it might make sense to just expand on it. Let the compiler assume that `Task<T>` and `ValueTask<T>` are *nullable-covariant*. We wouldn't check the implementations of these well-known types to decide if they are safely handling the variant type parameter.\n\nWe could also extend this to say that anything [task-like](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-7.0/task-types.md) is assumed to be *nullable-covariant*.\n\n### Option 1: [NullableOut] and [NullableIn]?\n\nIntroduce special attributes which denote that type parameters are *nullable-covariant* or *nullable-contravariant*.\n\n```cs\ninterface IEquatable<[NullableIn] T> { }\nclass Task<[NullableOut] T> { }\nstruct ImmutableArray<[NullableOut] T> { }\n```\n\nWe can imagine other interfaces which might want the *nullable-contravariance* used by `IEquatable`, such as `IEqualityOperators`, where `TSelf` is meant to be constrained to exactly the type which implements the interface, but the type argument may still vary on its nullability for incidental reasons (i.e. due to other constraints which happen to be applied to handle all the things a type parameter needs to be able to do).\n\n```cs\npublic interface IEqualityOperators<TSelf, TOther, TResult>\n        where TSelf : IEqualityOperators<TSelf, TOther, TResult>?\n{\n    static abstract TResult operator ==(TSelf? left, TOther? right);\n    static abstract TResult operator !=(TSelf? left, TOther? right);\n}\n```\n\nHowever, we think that a scenario where someone will actually be inconvenienced by this limitation is rare--to the point that we did not take the effort to actually sketch out such a scenario.\n\nWe think that if we added these attributes to the platform, we would want to add a practical amount of enforcement to ensure that nulls do not sneak in unexpectedly. For example, when `[NullableOut]` is used on a type parameter, we might want a warning if inputs of that type might be non-nullable. We're not sure how extensive this enforcement would need to be. In practice the amount of effort needed to provide a good user experience with these attributes could be high.\n\n```cs\nclass Task<[NullableOut] T>\n{\n    private T result; // maybe this needs a warning?\n    internal void SetResult1(T t) // warning: input of type 'T' should be nullable because the type parameter is nullable-covariant.\n    {\n        result = t; // ok\n    }\n\n    internal void SetResult1(T? t) // ok\n    {\n        result = t; // warning: possible null reference assignment.\n    }\n}\n```\n\nAdditional concerns we have with this approach:\n1. It may not be obvious for API authors when they need to add this attribute. Pretty much anything that exposes a read-only value of a parameterized type could be a good \"candidate\" for nullable covariance, for example.\n2. Nullable-oblivious types, or types the end user doesn't control in general, won't have this attribute, and users will continue to get warnings on variant conversions in those cases.\n    - To elaborate: Types whose original definitions are oblivious are still nullable-invariant in a nullable-enabled context. The constructed type `ObliviousGeneric<NullableAware>` is not convertible to `ObliviousGeneric<NullableAware?>`.\n\n### Option 2: `<out T>` in class types\n\nEric Lippert's [StackOverflow answer](https://stackoverflow.com/questions/2733346/why-isnt-there-generic-variance-for-classes-in-c-sharp-4-0/2734070#2734070) sheds some light on why type parameter variance was not implemented for class types originally. Since then we have added `readonly struct` and have considered `readonly class`, and it might be interesting in the future to extend readonly types to permit covariant type parameters, for example.\n\nHowever, to address the case people are actually complaining about, it feels a bit like using a wrecking ball to hit a nail. `Task<T>` is not readonly, and any change to actually make it covariant at the language level would be more of a hack.\n\n### Option 3: status quo (suppression needed or explicit type arguments)\n\nThe two workarounds currently recommended for the original scenario are to either suppress the conversion warning with `!` or to provide an explicit type argument when creating the object.\n```cs\nTask<string> x1 = ...;\nTask<string?> x2 = x1!; // could be doc'ed usage of suppression\nx2 = Task.FromResult<string?>(\"\"); // ok\n```\n\nThe current articles for `!` emphasize its use to assert that a variable is *not_null*. There's little coverage that the operator will suppress these conversion warnings as well. Adding this information, especially linked to the F1 service for the specific warning generated.\n\n### Conclusion\n\n**Option 0 (special-casing)** would be most palatable, but we're not sure yet whether to prioritize making any change here. It will depend on how the cost/benefit of addressing this compares to other nullable issues on the docket.\n\nUltimately, we think the main issue here is that when users encounter this, they will naturally think the compiler is telling them they're doing something wrong. It may take some research for users to conclude that actually, the conversion is fine, and they should just suppress the warning or provide the additional type information on the input side. Any way that we can make that process better (i.e. documentation, samples, editor support) would also help here.\n\n### Postscript\n\nAfter meeting I wondered if it would be possible to reduce warnings in some cases by using the target-type of an expression as an input to the nullable reinference process. This is slightly similar to what is planned for `IList<string?> e = [\"a\", \"b\", \"c\"]` in [collection literals](https://github.com/dotnet/csharplang/issues/5354).\n\nEssentially, in `Task<string?> task = Task.FromResult(\"value\")`, the type of `task` would be contributed to the inference of `TResult` in `Task<TResult> Task.FromResult<TResult>(TResult)`.\n- This step would probably only be done for nullable reference types, and would essentially be completely new, so it's difficult to say whether the design and implementation effort needed would be appropriate for the magnitude of the problem.\n- It's possible this would introduce a cyclic dependency in the reinference process which makes the approach unviable.\n- If it *did* work, it would address \"factory method\" issues in general, i.e. `ImmutableArray.Create<T>()`.\n\n## Next\n\nOur plan for the next working group is to do a higher-level overview of more nullable issues, and then dive into further depth in future sessions.\n- `[MemberNotNullWhenComplete]`: https://github.com/dotnet/csharplang/discussions/5657\n- LINQ: https://github.com/dotnet/roslyn/issues/37468\n- Defaultable value types: https://github.com/dotnet/csharplang/discussions/5337\n"
  },
  {
    "path": "meetings/working-groups/nullability-improvements/NI-2022-11-01.md",
    "content": "# Nullability improvements working group meeting for November 1st, 2022\n\n## `[MemberNotNullWhenComplete]`\nhttps://github.com/dotnet/csharplang/discussions/5657\n\nUsers are requesting the ability to specify postconditions which are only fulfilled after a task-returning method is awaited. We're seeing a relatively high amount of engagement (upvotes and thumbs up) on this compared to many other issues in the nullable space.\n\nA community member observed that there are very few usages of `[MemberNotNull]` on async methods in open source code, which bodes well for the possibility of breaking the existing behavior if we think it's the right thing for our users. We also think that the existing behavior on async methods is just broken. Currently, when an async method throws an exception, we treat it as fulfilling the postcondition, much like for a non-async method. This is because we think the caller won't actually be able to use whatever variable was expected to be not-null after the call--thus, nothing to warn about.\n\nHowever, in reality, when an async method throws an exception, it is packaged up into a Task and returned to the caller. It is not thrown until the task is awaited. Because pretty much any code can throw an exception, **no async method is able to reliably fulfill nullability postconditions as currently designed**. This is similar to an issue we recently fixed in [definite assignment](https://github.com/dotnet/roslyn/issues/43697#issuecomment-1267566839).\n\n[SharpLab](https://sharplab.io/#v2:C4LgTgrgdgPgAgJgIwFgBQcAMACOSB0AIgJYCGA5lAPYDOwxAxjfgMJUAmApgIJSkA2ATxrEaAbnRZcSAKwS0kgMy4E2FugDe6bDumYA/NmLBOAW3m7s23QG0AsmYBGnMADkqwVxH78AFH1NOKgAzX2MzAEoIgF1rHThlOAAOXAA2bDtuGkEoBl8IuOwtNEtLAAlOfgAHF3yLUp1w02wAXmwAIlJ2+oa4AE40/ABNYkr2OuwAeknsamwAd1IwKGIochpCgF90QoTpdLgAFmwK6tqI1oA+bGAACzAqednOJ4BRAA8GTir6Kig6wq7BAIQrFBo6FjYBitZ5PFgAkrggBuSxuMIY+Ey2VyE2m2E4n2+vygRhoN3ujxJq3YxDAnAYwCE5IeEHItxOlRqYGwpCg7CMuX4EC4/NW5M4uAA7Jx+XBUoVLBimvgACpUADKwDAq3IuJmc0Wyx1ABpsK4AEqvHnAbCQKD0QJbdCbIA)\n\n```cs\npublic class C\n{\n    string? item;\n    \n    [MemberNotNull(nameof(item))]\n    public async Task MAsync()\n    {\n        Helper();\n        item = \"a\";\n        await Task.Yield(); // no warnings\n    }\n\n    public static void Helper() => throw new Exception();\n    \n    public static void Main()\n    {\n        C c = new C();\n        var t = c.MAsync(); // exception is thrown indirectly through Helper and included in the returned Task\n        c.item.ToString(); // no warning, NRE at runtime\n    }\n}\n```\n\nWe think the most viable option to fix the issue here is to change the existing meaning of `[MemberNotNull]`, as well as other postconditions like `[NotNull]`, on Task-returning methods (methods which return `await`-able things), such that the postconditions are only applied if the call is *immediately awaited*. The only safe alternative would be to warn if a nullable postcondition attribute is used *at all* on an async method, which would be unfortunate.\n\nThus, the new \"happy path\" usage would look something like the following:\n\n```cs\npublic class C\n{\n    string? item;\n    \n    [MemberNotNull(nameof(item))]\n    public async Task MAsync()\n    {\n        await Task.Yield(); // no warning\n        item = \"a\";\n    }\n\n    public static void Main()\n    {\n        C c = new C();\n        await c.MAsync();\n        c.item.ToString(); // ok\n    }\n}\n```\n\nThe requirement to change behavior at call sites for any \"awaitable\" method call is because `async` is treated as an implementation detail, and it's not possible to determine whether a method from metadata is `async` or not. We'd prefer to have uniformity in usage across both source and metadata.\n\nThe requirement to *immediately await* rather than being able to store the task in a variable and await it later, for example, is because we won't be able to be sure about the ordering of effects in such cases:\n\n```cs\nvar task = c.MAsync();\nc.item = null;\nawait task;\nc.item.ToString(); // ok?\n```\n\nAlthough we're not sure such methods would occur in real code, we also considered the behavior of an API like the following:\n\n```cs\nnamespace System\n{\n    public static class File\n    {\n        public static async Task<bool> ExistsAsync([NotNull] string? path); // throws an exception if path is null\n    }\n}\n\npublic class C\n{\n    public static async Task M(string? path)\n    {\n        if (await File.ExistsAsync(path))\n        {\n            path.ToString(); // ok\n        }\n    }\n}\n```\n\n**Conclusion**: Overall, we are mildly favorable toward this feature request. We think it's possible to design the behavior our users actually want at a reasonable implementation cost--though if further examination reveals that cost is larger than expected, we may not be able to prioritize it. When we can, we'll prepare a full proposal for the behavior we want for the full language design meeting to consider.\n\n## Defaultable value types\nhttps://github.com/dotnet/csharplang/discussions/5337\n\nThe \"hero scenario\" for this feature is:\n```cs\n// ImmutableArray\nImmutableArray<int> arrOpt = default;\nforeach (var item in arr) // no warning, NRE at runtime\n{\n    Console.Write(item);\n}\n```\n\nIt would be nice if the language could understand when non-nullable reference type fields within structs could be null, and whether members of the struct are safe to use as a result.\n\nHowever, we did decide early on in the nullable reference types design to leave structs as a gap, just like we did with `new string[length]`--the language provides no assistance in determining whether an array of non-nullable reference types contains all non-null values.\n\nIt's particularly unappealing to introduce new syntax and attributes just to support this. We're curious if the situation could be improved without actually adding those--for example, how far could we take things by just tracking flow states for structs which contain non-nullable reference types, and slightly extending the usage/meaning of existing nullability attributes. However, it's not clear if we would reach a complete and usable enough state through such a strategy, especially when considering the space of possible behaviors for properties when accessed on a `default` receiver--the property could throw an exception, return the default value of the property type, return a non-null \"placeholder\" value, and so on. It's not clear what set of behaviors would meet the \"table stakes\" of usability while also not requiring a large amount of conceptual and implementation overhead.\n\n**Conclusion**: We think it's understood at this point that users must use caution when working with structs, and especially when they expose structs in libraries. This fact, combined with the relatively low level of engagement/enthusiasm on the discussion, leads us to think that this feature would not be a good use of our resources at this time.\n\n## LINQ\nhttps://github.com/dotnet/roslyn/issues/37468\n\nWe're seeing a fairly high upvote rate on issues tracking LINQ usability with nullable. The scenario where people are experiencing the most pain is:\n\n```cs\nIEnumerable<Widget> M(IEnumerable<string?> items)\n{\n    return items\n        .Where(i => i != null)\n        .Select(i => Widget.Parse(i)); // false warning: converting 'i' to non-nullable\n}\n\nclass Widget\n{\n    public static Widget Parse(string item) => throw null!;\n}\n```\n\nWe found that the equivalent scenario using query syntax appears to work at first glance. However, it is actually suppressing nullable warnings that we would expect. The query variable has oblivious nullability and its state is not tracked across operations in the query. It feels like the compiler should be able to flow nullable state information from the `where` to the `select` clause in examples like the following, but we haven't yet had the opportunity to make it work. Ideally, whatever solution we adopt to improve the LINQ experience will have parity between both the call-chaining and query forms.\n\n```cs\nIEnumerable<Widget> M(IEnumerable<string?> items)\n{\n    return from i in items\n        where i != null\n        select Widget.Parse(i); // ok\n}\n\nIEnumerable<Widget> M(IEnumerable<string?> items)\n{\n    return from i in items\n        select Widget.Parse(i); // should warn, but doesn't\n}\n```\n\nWe had a few thoughts and concerns when considering expanding on the support here:\n\nLINQ is extensible. You can define your own operators, and you can also reimplement the LINQ \"suite\" on non-IEnumerable containers while getting support for the query syntax. We would probably want to ensure that any usage of the \"query pattern\" would also benefit from any special support we add here. We would have to assume that the implementation adheres to the standard expectations for those operators.\n\nIt might be OK to just target the \"90% case\" versus providing full and rich support over all the standard operators. We also think this use case is valuable enough to introduce new attributes if necessary.\n\nWe considered whether it would be good enough to have a *special case* just for `Where(x => x != null)`, where the return value is somehow inferred to be `IEnumerable<NonNullThing>` and that type information flows into subsequent usages. It seems unfortunate to \"miss\" even slightly more complex cases like the following:\n\n```cs\nIEnumerable<C2> Transform(IEnumerable<C1> items)\n{\n    return items\n        .Where(i => i.field1 != null)\n        .Select(i => new C2 { field2 = i.field1 }); // would still warn\n}\n\nclass C1\n{\n    public string? field1;\n}\n\nclass C2\n{\n    public required string field2;\n}\n```\n\nWe also think it could be useful to somehow flow the state of collection elements across statements, like when using the Any or All operators:\n\n```cs\nList<string?> items = ...;\nif (items.All(i => i != null))\n{\n    UseNotNullItems(items);\n}\n```\n\nHowever, much like the *immediately awaited Task* scenario, it seems difficult to know how to \"invalidate\" the state of a collection once it is tested in this manner--for example, if someone calls `items.Add(null)` on a mutable collection after checking `.All()`. We might be able to reach a worthwhile level of tracking in such scenarios, but it's not clear.\n\n**Conclusion**: We're interested in improving support here. We will hold a dedicated meeting for this topic in order to more thoroughly explore the problem and decide what level of support we want to provide here.\n\n## Follow-up from last meeting\nAfter our last meeting we continued to think about the [Task covariance](https://github.com/dotnet/csharplang/issues/3950) issue, and have concluded that we should update the language documentation to capture the *suppress nullable conversion warnings* use case for the `!` suppression operator. Currently, we think this is the full extent that we want to invest in this specific area.\n"
  },
  {
    "path": "meetings/working-groups/nullability-improvements/NI-2022-11-07.md",
    "content": "# Nullability improvements working group meeting for November 7th, 2022\n\nOur focus today was on [improving nullable analysis of LINQ queries](https://github.com/dotnet/roslyn/issues/37468).\n\n## Special handling of `.Where(x => x != null)`\n\nWe considered a solution where we specially handle null tests on the collection element itself. For example:\n\n```cs\nIEnumerable<string> M(IEnumerable<string?> items)\n{\n    return items.Where(x => x != null); // no warning.\n}\n```\n\nWe think we could introduce a rule where the type of a `Where()` invocation expression is changed depending on the predicate which is passed in. (Specifically, the type argument of the return type would change its top level nullability.) However, we are not sure this solution is generally useful enough.\n\nIt has been also been [suggested](https://github.com/dotnet/runtime/issues/30381) on multiple occasions to add a `.WhereNotNull()` LINQ operator to the core library. This suggestion has been rejected by the runtime team. We found a number of drawbacks to this solution, including the fact that query expressions would need to be updated to use this operator, and that query providers would need to be updated to understand the operator.\n\n## Field tracking within collection elements\n\nWe think scenarios like the following are common and important to handle:\n\n```cs\nIEnumerable<HasNotNullable> M1(IEnumerable<HasNullable> enumerable)\n{\n    return enumerable\n        .Where(x => x.Item != null)\n        .Select(x => new HasNotNullable(x.Item)); // ok\n}\n\nrecord HasNullable(string? Item);\nrecord HasNotNullable(string Item);\n```\n\nNote that this *wouldn't* be handled by an approach which only updates the top-level nullable state, i.e. by adding a `.WhereNotNull()` operator to the core library.\n\nWe want to support a complete and coherent mental model for the analysis of these queries as much as possible. Users should be able to think of the above query as being *morally equivalent* to the following iterator method:\n\n```cs\nIEnumerable<HasNotNullable> M2(IEnumerable<HasNullable> enumerable)\n{\n    foreach (var x in enumerable)\n    {\n        if (x.Item != null)\n        {\n            yield return new HasNotNullable(x.Item); // ok\n        }\n    }\n}\n```\n\nWe also think that the filtering performed by operators like `.Where()` should be able to be consumed by custom downstream operators.\n\n```cs\nenumerable\n    .Where(x => x.Item != null)\n    .SelectAsArray(x => new HasNotNullable(x.Item)); // state of 'x.Item' is still propagated, although it seems like the compiler can't make a hard assumption that this lambda is operating on the collection element.\n```\n\nWe think this can be accomplished by associating a *slot* with a type argument, and when values of that type are materialized, we would copy the state from that *slot* in as the initial state of those values. For example:\n\n```cs\n// after visiting the 'Where()' invocation, we associate the type 'HasNullable' with a slot representing the when-true branch of 'x.Item != null' in the lambda.\nenumerable.Where(x => x.Item != null)\n    // Parameter 'x' has type 'HasNullable', and 'HasNullable' has an associated slot. We copy this slot as the initial state of the parameter.\n    .Select(x => new HasNotNullable(x.Item));\n```\n\nWe'd like to avoid thinking of this as a bona-fide type system addition--for example, where unspeakable types are inferred and flow through to represent the combination of field nullable states. As much as possible, we want to leverage the analogy of assigning variables whose field states were already modified:\n\n```cs\nvar x = GetHasNullable();\nx.Item = \"not null\";\nvar y = x;\ny.Item.ToString(); // no warning in currently shipped compiler\n```\n\nCurrently, we are still at the stage of *heavily* handwaving questions about the lifetimes of such slots and how to propagate this state only to variables which are actually associated with the tests from filtering lambdas.\n\n```cs\nenumerable.Where(x => x.Item != null)\n    .Select(x => new HasNotNullable(GetHasNullable().Item); // should still warn, since we didn't test the return value of 'GetHasNullable()'.\n```\n\nMore consideration is needed here. We'll try to organize our thoughts and explore this approach in more detail when we meet again.\n\n## Identifying filtering operators\n\nWe considered how to identify when a method should get the \"`Where()` method treatment\". For example, operators like `First()`, `Last()`, `SkipWhile()` and `TakeWhile()` would also want to propagate collection element nullable state based on the lambda argument.\n\nA few basic options we considered for identifying these methods include:\n1. Look specifically for `System.Linq.Enumerable.Where()` `System.Linq.Enumerable.First()`, etc., and don't include user-defined operators or operator \"suites\" on different collections.\n2. Look for any method which is callable on an enumerable receiver and which matches the naming pattern, i.e. `MyExtensions.Where<T>(this MyCollection<T>, Func<T, bool>)` would be automatically opted in to the new analysis behavior. This *slightly* resembles the translation of [query expressions](https://github.com/dotnet/csharpstandard/blob/draft-v7/standard/expressions.md#1118-query-expressions).\n3. Introduce an attribute which indicates a method output is being *filtered* by a predicate.\n\nWe sketched out a few possible names and shapes for \"filter\" attributes here:\n```cs\npublic static IEnumerable<T> Where<[NotNullWhenLambdaFlowStateNotNull]T>(this IEnumerable<T> enumerable, Predicate<T> predicate);\n\npublic static IEnumerable<T> Where<T>(this IEnumerable<T> enumerable, [Filter] Predicate<T> predicate);\n// or [NullFilter]?\n\n[return: Filter(nameof(predicate))]\npublic static IEnumerable<T> Where<T>(this IEnumerable<T> enumerable, Predicate<T> predicate);\n```\n\nAt this point, we think that filtering methods should onboard deliberately to the new analysis behavior, and we want user-defined operators, perhaps ones with names or shapes we didn't anticipate to be able to participate where possible. Therefore, we are leaning towards introducing a filtering attribute of some kind. When we meet again we will present and consider some more concrete designs for such an attribute.\n"
  },
  {
    "path": "meetings/working-groups/nullability-improvements/NI-2022-11-22.md",
    "content": "# Nullability improvements working group meeting for November 22nd, 2022\n\nWe continued our discussion on [nullable LINQ analysis](https://github.com/dotnet/roslyn/issues/37468), focusing particularly on introducing a \"filtering\" attribute which allows nullable state within predicate lambdas to flow out of the resulting collection.\n\nWe used the following attribute declaration as a starting point:\n```cs\nnamespace System.Diagnostics.CodeAnalysis;\n\n/// <summary>\n/// Can be applied to a parameter of a delegate type such as <see cref=\"Func<object, bool>\"/> which has a single parameter and returns <see langword=\"bool\"/>.\n///\n/// When this attribute is used, the language assumes that the predicate returns true for all values of its input type which are returned by the containing method.\n/// </summary>\n[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]\npublic sealed class NullableFilterAttribute : Attribute { }\n```\n\nWhere usage would look like the following:\n```cs\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace System.Linq;\n\npublic static class Enumerable\n{\n    public static IEnumerable<TSource> Where<TSource>(\n        this IEnumerable<TSource> source,\n        [NullableFilter] Func<TSource, bool> predicate)\n    {\n        // ...\n    }\n}\n```\n\nWhen a `[NullableFilter]` parameter is used, it is associated with the parameter type of the delegate. In this case, that parameter is `predicate`, the delegate parameter's type is `TSource`, and the containing method is `Where`. All values of type `TSource` which *flow out* of `Where` are assumed to have been passed in to a call to `predicate`, and a `true` value was returned from each call.\n\nOne of the first bits of feedback was on the name. We think this attribute is not itself about nullability. It's just that if lambdas passed as arguments for the predicate parameter do null tests, then null state information about the collection elements can propagate through. Other forms of static analysis could easily take advantage of the same assumption, that the predicate returned true for all elements returned from the containing method. Therefore, we think perhaps the attribute name `[Filter]` or `[Predicate]` would be more suitable.\n\nWe want to ensure we consider the suitability of this attribute for other APIs in [`System.Linq.Enumerable`](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable?view=net-7.0) that have overloads that apply a predicate to a sequence, such as:\n\n- `First`\n- `Last`\n- `TakeWhile`\n- ...\n\nRelating to the above, we'd like to consider what the impacts are with various signatures, especially with various return types. For example, for `Collection<T, T> Method<T>([NullableFilter] Func<T, bool> predicate)`, do both of the `T`s in the return type get the additional flow state from the predicate?\n\nWe're not sure whether we should have both \"predicate returned `true`\" and \"predicate returned `false`\" flavors of the attribute. If the implementation wanted to guarantee that a predicate returned `false`, they would need something like `[Filter(predicateReturnValue: false)]`. If we're not able to find compelling examples where people would want to adopt in this manner, we'll probably want to stick with just the \"predicate returns `true`\" flavor.\n\nWe also briefly considered whether this attribute can affect other outputs besides returns. For example, what if you had a method `void Where(IEnumerable<T>, [NullableFilter] Func<T, bool>, out IEnumerable<T>)`? At this point, we think there isn't a scenario involving `out` parameters, but we'll want to keep it in mind as we proceed with the design. It's worth noting that attributes like `[NotNullIfNotNull]` can be applied to both return values and `out` parameters (where the attributed thing is the *output* affected by some named input.)\n\nWe noted that some indirect usages which rely on a more \"set theory\" approach are unlikely to result in useful changes to flow analysis.\n```csharp\n// Bad usage that would be a problem if the attribute is on the method, not on the lambda expression:\nvar allNullValues = someCollection.Where(i => i is null); // IEnumerable<Widget?>\nallNullValues[0].ToString(); // warn because the predicate didn't contain a null check.\nvar dataToWrite = someCollection.Except(allNullValues); // lost track\n```\n\nWe are tentatively thinking of the state-propagation which occurs for a filtering attribute as *modifying/reinferring type arguments present in output positions*.\n```cs\nrecord Widget(string? Prop) { }\n\nvar en = widgets.Where(widget => widget.Prop != null); // IEnumerable<Widget+__predicateReturnedTrue>\nforeach (var item in en)\n{\n    item.Prop.ToString(); // ok\n}\n```\n\n```cs\n// lambda for 'lastChance' can't assume T passed the filter (it didn't in this case)\npublic static IEnumerable<T> Where(IEnumerable<T> source, [Filter] Func<T, bool> primary, Func<T, bool> lastChance)\n{\n    foreach (T item in source)\n    {\n        if (primary(item)) yield return item;\n        else if (lastChance(item)) yield return item;\n    }\n}\n```\n\nWe considered would happen when a filtered enumerable `en` is enumerated multiple times, potentially modifying its contents. Our conclusion is basically that we don't want to attempt to track changes to the collection element across statements. We think it is best to avoid any scheme where the initial state of elements in `en` depends on where `en` is used.\n```cs\nvar en = widgets.Where(widget => widget.Prop != null);\nforeach (var item in en)\n{\n    item.Prop = null;\n}\nforeach (var item in en)\n{\n    item.Prop.ToString(); // no warning and NRE at runtime\n}\n```\n\nWe think the NRE present above is similar to aliasing scenarios which already don't work:\n```cs\nvar item = new Widget(\"a\");\nvar item1 = item;\nitem1.Prop = null; // doesn't apply to `item`\nitem.Prop.ToString(); // NRE but no warning\n```\n\nWe also note that the language assumes that member method calls don't change the state of fields, unless specifically annotated in the signature:\n```cs\nvar en = widgets.Where(widget => widget.Prop != null);\n// When does the compiler decide a mutation has taken place?\n// mutation and repeated enumeration\nforeach (var item in en)\n{\n    item.M();\n}\nforeach (var item in en)\n{\n    item.Prop.ToString(); // ?\n}\n\n// similar to the following method scenario:\nlocal(item);\nitem.Prop.ToString(); // kaboom, no warning\nvoid local(Widget i) => i.Prop = null;\n```\n\nThere is still some ambiguity about when the collection element flow state disappears, particularly when the collection element state is contained in some mutable collection which we go on to mutate.\n```cs\nvar en = widgets.Where(widget => widget.Prop != null);\nvar arr = en.ToArray(); // T[] ToArray<T>(this IEnumerable<T>)\narr[0].Prop.ToString(); // ok? Do we remember that we passed the `widget.Prop != null` test?\nforeach (var item in arr)\n{\n    item.Prop.ToString(); // ok\n}\n\n// ToArray() followed by mutation\n// what happens here? do we just accept it?\n// Is this itself a warning--this is not a *Widget-with-non-null-Prop*, it's a *Widget-with-null-Prop*.\narr[0] = new Widget(null); \nforeach (var item in arr)\n{\n    item.Prop.ToString(); // do we still expect non-null-Props here?\n}\n\n// Concat()\nvar en1 = en.Concat(new Widget(Prop: null)); // \"unify\" into a standard Widget type\nforeach (var item in en1)\n{\n    item.Prop.ToString(); // warning\n}\n\n// Null tests through methods with nullable postcondition attributes\nvar en1 = widgets.Where(widget => !string.IsNullOrWhitespace(widget.Prop));\nforeach (var item in en1)\n{\n    item.Prop.ToString(); // ok (we expect the compiler to understand that widget.Prop is not-null when the predicate returns true)\n}\n```\n\nWe think that this scheme should be naturally composable, and for example, allow a sequence of `Where()` calls to just do the right thing.\n```cs\nrecord Widget(string? Prop) { }\n\nvar x = en.Where(w => w is not null) // IEnumerable<Widget>\n          .Where(w => w.Prop is not null); // IEnumerable<Widget+element-flow-state>\n```\n\nThere won't be checking of the implementation for correctness, so a Where method like the following will result in a misleading analysis at the call-site:\n\n```cs\nIEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> input, Func<TSource, bool> predicate)\n{\n    foreach (var item in input)\n    {\n        if (predicate(item)) { } // ignore result of the predicate call\n        yield return item;\n    }\n}\n```\n\nAs mentioned earlier, we want to take care to avoid inventing *flow-dependent typing* here. So there is some question on a technical level about whether to associate the collection element slot information with variables and expressions or with types. Also, we don't think this collection element information should appear in the public API for types.\n\nReview of https://github.com/dotnet/csharplang/blob/main/proposals/csharp-9.0/nullable-reference-types-specification.md could be helpful when we go deeper in attempting to formalize this.\n\n## Implementation brainstorming\n\nA subset of the working group brainstormed briefly about how the implementation would work. This part is more speculative than the rest, and depends on the design leading to it being fully formed and approved by the language design team.\n\nThe `NullableWalker` in Roslyn has a structure called `VisitResult` which is produced whenever an expression is visited. It currently contains an rvalue and lvalue flow state, and we think with this feature we might augment it to also include a map of \"filtered type\" to \"element flow state\".\n\nFor example, `en.Where(w => w.Prop is not null)` would have an entry for the type of `w` which points to the final state-when-true after `w.Prop is not null`. Then, when we access a member off of `en.Where(...)` whose type is a *filtered type*, we can get the slot for that element flow state and use it as the initial state of variables of the filtered type.\n\n## Next\n\nIn our next meeting we plan to dive deeper into the mechanics of the filtering attribute, and hopefully reach a point where we understand the solution we want well enough to write a proposal for it.\n"
  },
  {
    "path": "meetings/working-groups/params-improvements/PI-2022-10-25.md",
    "content": "# Params Improvements Working Group Meeting for October 25, 2022\nThis was the first meeting of the _`params` improvements_ working group.\nWe discussed extending `params` support to collection types other than arrays.\n\n## Agenda\n1. `params IEnumerable<T>`, `IList<T>`, etc.\n1. `params List<T>`, `ImmutableArray<T>`, etc.\n1. `params Span<T>`, `ReadOnlySpan<T>`\n1. Overload resolution and backward compatibility\n\n## Discussion\n\n### Interfaces and collection types: `params IEnumerable<T>`, `List<T>`, etc.\n\nPerhaps the most common request is support for `params IEnumerable<T>`. \n\nThis is potentially useful for scenarios where the `params` method simply iterates over the collection, and where callers might have an `IEnumerable<T>` instance rather than a `T[]` and are calling the method with _normal form_.\nHowever, when callers use _expanded form_, a `params IEnumerable<T>` may not provide any advantage over `params T[]` to the caller or callee.\n\nIf we extend `params` to support `IEnumerable<T>`, we should consider extending `params` support to other interface types and concrete collection types as well.\nIf so, what are the requirements of supported types?\n\nThe [_collection literals working group_](https://github.com/dotnet/csharplang/tree/main/meetings/working-groups/collection-literals) is already defining similar requirements for _constructible collection types_. Those types can be `interface` types or concrete `class`, `struct`, and `ref struct` types.\nThe _collection literals_ proposal specifies how the corresponding collection instances for _constructible collection types_ are constructed and populated.\n\nAny additional `params` types should match the _collection literals_ approach.\nThat is, for any particular `params` type, the code generated for `WriteLine(fmt, a, b, c)` should be equivalent to the code generated for `WriteLine(fmt, [a, b, c])`.\n\nThat said, the difference between an _expanded form_ call (with implicit collection) and a call using a _collection literal_ is just two characters, `[]`, so the advantage of `params` over _collection literals_ seems small.\nGiven that, we concluded we _should not extend `params`_ to arbitrary interfaces or collection types.\n\n### Spans: `params ReadOnlySpan<T>`, `Span<T>`\n\n`ReadOnlySpan<T>` has a couple of advantages over other potential `params` types.\n1. With runtime support, the compiler could create spans at call sites without allocating an underlying array on the heap.\n1. `T[]` and `Span<T>` are implicitly convertible to `ReadOnlySpan<T>`.\n\nThat means `params ReadOnlySpan<T>` is a reasonable alternative to `params T[]` in new APIs.\nAnd for existing APIs, adding a `params ReadOnlySpan<T>` overload could reduce allocations for current callers of a `params T[]` overload without changing the calling code.\n\nThe potential perf benefit, and the opportunity to replace `params T[]` with `params ReadOnlySpan<T>` seem sufficiently important that we should support `params ReadOnlySpan<T>` even if _collection literals_ provide similar optimizations for span literals - that is, even if the difference between using `params` and using a _collection literal_ is simply `[]`.\n\n`Span<T>` has the same benefits as `ReadOnlySpan<T>`, but `Span<T>` is only preferable to `ReadOnlySpan<T>` if the `params` method modifies the span.\nBut modifying a `params` span is not a pattern we should encourage - in part because modifications are not visible to callers where the compiler generated the `Span<T>` instance.\nIn short, we concluded we should support `params ReadOnlySpan<T>` but not `params Span<T>`.\n\n`params ReadOnlySpan<T>` should be implicitly `scoped` so the compiler can reuse the implicitly generated `ReadOnlySpan<T>` instance across multiple calls in the calling method.\n\nShould we also support `params scoped T[]`, to allowing sharing the array across callers?\n\n### Overload resolution and backward compatibility\n\nOverload resolution should prefer an overload with `params ReadOnlySpan<T>` over an overload with `params T[]`, to ensure call sites get benefit from reduced allocations.\n\nThat means adding a `params ReadOnlySpan<T>` overload to an API with a `params T[]` overload is a source breaking change.\n\n### Conclusions\nExtend `params` support to `ReadOnlySpan<T>` only.\n\n`params ReadOnlySpan<T>` parameters should be implicitly `scoped`.\n\nOverload resolution should prefer `params ReadOnlySpan<T>` over `params T[]`.\n\nConsider support for `params scoped T[]` as an open question.\n"
  },
  {
    "path": "meetings/working-groups/params-improvements/PI-2022-11-03.md",
    "content": "# Params Improvements Working Group Meeting for November 3, 2022\nThe second meeting of the _`params` improvements_ working group was focused on the code generated for arguments to `params ReadOnlySpan<T>`. \n\n## Span allocation\nThe compiler _may allocate a span on the stack_ when:\n- the span is implicitly allocated (as a `params` argument or as a [_collection literal_](https://github.com/dotnet/csharplang/issues/5354)),\n- the span length is known at compile time, and\n- the compiler can determine _through escape analysis_ that no references to the span escape the containing method.\n\nFor arguments to a `params ReadOnlySpan<T>` parameter (which is implicitly `scoped`), the conditions above are satisfied.\n\nWe have a [request](https://github.com/dotnet/runtime/issues/61135) with the runtime team to support _fixed size arrays_ of managed types, at least for fields.\nIf we have _fixed size array_ fields, we can define `struct` types with inline arrays and use locals for stack allocated arrays.\n\nFor example, consider a `FixedSizeArray2` type defined below which includes an inline 2 element array:\n```csharp\nstruct FixedSizeArray2<T>\n{\n    public T[2] Array; // pseudo-code for inline array\n}\n```\n\nWith that type, a call to `WriteLine(\"{0}, {1}\", x, y)` could be emitted as:\n```csharp\nvar _tmp1 = new FixedSizeArray2<object>();\n_tmp1.Array[0] = x;\n_tmp1.Array[1] = y;\nvar _tmp2 = new ReadOnlySpan<object>(_tmp.Array);\n\n// WriteLine(string format, params ReadOnlySpan<object> args);\nWriteLine(\"{0}, {1}\", _tmp2);\n```\n\nIdeally the BCL will provide types such as `FixedSizeArray1`, `FixedSizeArray2`, etc. for a limited number of array lengths.\nAnd if the compilation requires spans for other argument lengths, the compiler will generate and emit the additional types.\n\nThe number of arguments passed to a `params` parameter is _not considered_ when determining whether to implicitly allocate the span on the stack.\nTo avoid implicit stack allocation at a call site, the calling code should allocate the array explicitly with `new[] { ... }`.\nWe believe scenarios where stack allocation regardless of argument length becomes an issue are unlikely, and should be easy to work around, but we can adjust if necessary.\n\n## Span reuse\nThe compiler _may reuse a span_ when:\n- the span is implicitly allocated (as a `params` argument or as a [_collection literal_](https://github.com/dotnet/csharplang/issues/5354)),\n- the span length is known at compile time,\n- the compiler can determine _through escape analysis_ that no references to the span escape the containing method, and\n- the compiler can determine there are _no reachable aliases_ to the span in user code.\n\nFor arguments to a `params ReadOnlySpan<T>` parameter (which is implicitly `scoped`), the conditions above are satisfied.\n\nThe compiler will reuse a single span across all calls to `params ReadOnlySpan<T>` methods where the span element types are considered identical by the runtime.\n\nThe length of the reused span will be the length of the longest `params` argument list from all uses.\n(The actual span argument passed to a `params` method will be a slice of the reused span, with the expected length for the call.)\n\nReuse may be across distinct call sites _or_ repeated calls from the same call site.\nReuse is per thread of execution and within the same method only.\nNo reuse across _lambda expressions_ and the containing method.\nReusing spans across _local functions_ and the containing method is possible if the local function is not used as a delegate, although the implementation cost of such an optimization may outweigh the benefit.\n\nWhen exiting a scope, the compiler will ensure that no implicitly allocated span holds references from the scope.\n\nTo opt out of reuse at a call site, the calling code should allocate the span explicitly.\n\n_Should we only reuse spans that are allocated on the stack? If we also allow reuse of heap allocated buffers, that will require completely different code gen for managing allocations._\n\n## Collection literals\nWe will support stack allocation and reuse of spans for _collection literals_.\n\nFor collection literals that include a _spread operator_, the length of the resulting span is not known at compile time.\nFor those cases, we will choose a maximum length for stack allocation and generate code that falls back to heap allocation at runtime if that length is exceeded.\nAs per the _collection literals_ working group, a hidden diagnostic will be reported in cases where stack allocation may not be possible at runtime.\n\nFor instance, the expression `(ReadOnlySpan<int>)[..e]` could be emitted as:\n```csharp\nvar _tmp1 = new FixedSizeArray8<int>();\nReadOnlySpan<int> _tmp2;\nif (Enumerable.TryGetNonEnumeratedCount(e, out int n) && n <= 8)\n{\n    int i = 0;\n    foreach (var item in e)\n    {\n        _tmp1.Array[i++] = item;\n        if (i == n) break;\n    }\n    _tmp2 = new ReadOnlySpan<int>(_tmp1.Array, 0, n);\n}\nelse\n    _tmp2 = new ReadOnlySpan<int>(e.ToArray());\n```\n\n## Example\nConsider the following method with multiple calls to a `params` method:\n```csharp\n// static void WriteLine(string format, params ReadOnlySpan<object> args);\n\nstatic void WriteDictionary<K, V>(Dictionary<K, V> dictionary)\n{\n    WriteLine(\"Dictionary\");\n\n    foreach (var (k, v) in dictionary)\n        WriteLine(\"{0}, {1}\", k, v);\n\n    WriteLine(\"Count = {0}\", dictionary.Count);\n}\n```\n\nThe method could be lowered to:\n```csharp\nstatic void WriteDictionary<K, V>(Dictionary<K, V> dictionary)\n{\n    FixedSizeArray2 _tmp1 = new FixedSizeArray2();\n\n    WriteLine(\"Dictionary\",\n        new ReadOnlySpan<object>(Array.Empty<object>()); // no reuse\n\n    foreach (var (k, v) in dictionary)\n    {\n        _tmp1.Array[0] = k;\n        _tmp1.Array[1] = v;\n        WriteLine(\"{0}, {1}\",\n            new ReadOnlySpan(_tmp1.Array)); // reuse\n        Array.Clear(_tmp1.Array);           // clear\n    }\n\n    _tmp1.Array[0] = dictionary.Count;\n    WriteLine(\"Count = {0}\",\n        new ReadOnlySpan(_tmp1.Array, 0, 1)); // reuse\n}\n```\n"
  },
  {
    "path": "meetings/working-groups/ref-improvements/REF-2022-11-11.md",
    "content": "ref fields to ref struct\n===\n\n# Terminology\nRFRS: `ref` field to `ref struct`\n\n# TypedReference\nAll the discussion on RFRS is tied to how we eventually fully support `TypedReference` (remove it from restricted types list). The reason is that `TypedReference` can support storing anything. It can even store a `ref TypedReference` value which makes it equivalent to a type that has RFRS. \n\nThe language does not necessarily need to support this full complexity though. One simplification is that we only limit the arguments passed to `__makeref` to be those we logically support on `ref struct` fields today. That would allow `ref struct` values, or `ref` to normal `struct`, but not `ref` to `ref struct`. This means IL could construct instances that violate C# lifetime rules but that would be labeled as simply unsupported.\n\nHowever until we know how RFRS support will occur it's difficult to move forward with `TypedReference` support for fear we'd end up painting ourselves into a corner.\n\n# Lifetime notation \nWhen discussing `ref` and the associated lifetime challenges it helps to have an explicit notation syntax to fall back on for discussions. That will be done by using the `'a` notation. The letter following `'` is the lifetime name and it can be applied to any value or `ref` in code. By default named lifetimes have no relationship to each other but one can be created by adding `lifetime` constraints at the method body. \n\nFor example here is how the use of `scoped` is expressed in lifetime notation \n\n```csharp\nSpan<int> Read(scoped ref int i) {\n    ...\n}\n\n'b Span<int> Read('a ref 'b int i) {\n\n}\n```\n\nIn this case `scoped` becomes the `'a` lifetime. That enforces the behavior of `scoped` because the lifetime for returns is `'b`. There is no provided relationship between `'a` and `'b` hence no conversion and it cannot be returned. \n\nThe *return only* vs. *containing method* scopes can be explained using the following example:\n\n```csharp\nref struct RS { }\nSpan<int> Create(ref RS i) {\n    ...\n}\n\n'b Span<int> Create('b ref 'a RS i) {\n    where 'b <= 'a\n\n}\n```\n\nBy establishing a relationship between `'a` and `'b` it allows for both the value and the `ref` to be returned from the method. It also prevents cyclic assignment issues because the relationship does not allow for it from a lifetime (`'b` could be smaller than `'a`).\n\n# Complications around ref fields of ref struct\nThe immediate issue this causes is it creates layers of lifetimes in our types. Consider concretely: \n\n```csharp\nref struct RS { \n  ref 'a Span<byte> Field; \n}\n```\n\nThe value of the field has a lifetime that is independent of the containing instance. Typically when we look at a value there are two lifetimes to consider: the safe to escape and ref safe to escape. In the case of `RS` though there is also the lifetime of `Field`. \n\n```csharp\nvoid E() {  \n    // Only two lifetimes here: the value and the ref \n    Span<int> span = ...; \n\n    // Three lifetimes: value, ref and value of Field\n    RS rs = ...;\n}\n```\n\nThese lifetimes can now be arbitrarily deep. So a given struct can have `N` different lifetimes associated with it that we have to manage.  As the types get more fields this gets more complex because the lifetimes aren't necessarily linear either: \n\n```csharp\nref struct RS { \n  ref Span<byte> Field1;\n  ref Span<byte> Field2;\n}\n``` \n\nThere are two different ways we could think about this: \n\n```csharp\n// Option 1: simple but limiting\nref struct RS { \n  ref 'a Span<byte> Field1;\n  ref 'a Span<byte> Field2;\n}\n// Option 2: flexible but now we have a tree\nref struct RS { \n  ref 'a Span<byte> Field1;\n  ref 'b Span<byte> Field2;\n}\n```\n\nThese problems mostly manifest in the method arguments must match rule. This is the rule where we look at all of the `ref` going into the method and ensure that they can never be cross assigned in a way that would cause an unsafe reference to the stack. \n\n```csharp\nvoid Swap(ref Span<int> x, ref Span<int> y) {\n    ... \n}\n\nvoid Use(ref Span<int> span) {\n    Span<int> local = stackalloc int[42];\n    Swap(ref span, ref local);\n}\n```\nThe MAMM rules are intricate but can be simplified to the following: \n\n> Every `ref` argument to a method be assignable *from* every other `ref` argument in terms of lifetimes. \n\nBefore there were just two layers of lifetimes, now there are basically infinite and they **all** have to match. The problem with `ref` fields to `ref struct` is now virtually everything is a MAMM nightmare. Even an instance method on a `struct` is dealing with MAMM insanity.\n\nThe only way for MAMM to work in this scenario is for all the lifetimes involved to be equivalent. That really defeats the purpose of adding them. \n\n# Paths Forward \n\n## Implement RFRS\nThe consensus is that to fully support RFRS would likely require us to have full lifetime notations in the language. For example putting the lifetimes on `scoped` modifier. That would allow for example `scoped<a>`, `scoped<b>`, etc ... \n\nAt the same time, we don't have the supporting scenarios at this time to justify that work. It's possible that features like `params ReadOnlySpan<T>` will produce these. \n\n## Implement RFRS in a limited fashion\nMuch of the complexity of RFRS comes from the fields being as flexible as a `ref` parameter. The ability to ref re-assign, assign new values, etc ... drive the complexity particularly around MAMM. Perhaps if we limited their capabilities we could satisfy key scenarios without jumping off the complexity cliff. For example if we forced them to be `readonly ref`, `ref scoped`, etc ... would that help? \n\nThe `ref scoped` is likely the most plausible approach here. The key is whether we can define its meaning in such a way that it remains useful while keeping complexity low. The rules would also need to apply to `ref scoped` parameters too which increase the scenarios a bit.\n\n## Punt it \nThe explicit decision to not support RFRS for now should open the door for us exploring `ref struct` as generic arguments and implementing interfaces. There are existing scenarios that will sufficiently help drive this feature. \n\nNeed more due diligence to be certain that we don't close the door on RFRS in the future. \n\n# Next Steps\n\n1. Andy and Aaron are going to provide simplified samples where RFRS would be beneficial. \n2. Group will explore if there are ways to expose them in a limited way that does not force us off the complexity cliff. For example if they are required to be `readonly ref`, or `ref scoped` can be defined with sufficient restrictions, etc ... Do any of these both allow the scenarios that matter without forcing off the complexity cliff of full lifetime notations.\n3. Explore whether we can go forward with `ref struct` generics + interfaces without cutting off our ability to support RFRS at a later time\n\n"
  },
  {
    "path": "meetings/working-groups/ref-improvements/ignore-overloads-in-expressions.md",
    "content": "# Ignore overloads with ref struct parameters within Expression lambdas\n\nIgnore overloads with `ref struct` parameters when binding within `Expression` lambdas.\n\n## Motivation\n\nC#13 adds support for *`params` span*, and C# preview adds *first-class span types*. Both of these features allow overload resolution to prefer overloads with *span type* parameters in more cases than with earlier language versions.\n\nHowever, within an `Expression`, binding to a member that requires a `ref struct` instance may result in a compile-time or runtime error, and is therefore a breaking change.\n\nExample 1: `params` span, see [#110592](https://github.com/dotnet/runtime/issues/110592)\n\n```csharp\nExpression<Func<string, string, string>> expr =\n    (x, y) => string.Join(\"\", x, y); // String.Join(string?, params ReadOnlySpan<string?>)\n```\n\nExample 2: First-class span types, see [#109757](https://github.com/dotnet/runtime/issues/109757)\n\n```csharp\nExpression<Func<string[], string, bool>> expr =\n    (x, y) => x.Contains(y); // System.MemoryExtensions.Contains<T>(this ReadOnlySpan<T>, T)\n\nvar f = expr.Compile(preferInterpretation: true); // Exception\n```\n\n## Design\n\n[*12.6.4.2 Applicable function member*](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/expressions.md#12642-applicable-function-member) could be updated as follows:\n\n> - A static method is only applicable if the method group results from a *simple_name* or a *member_access* through a type.\n> - ...\n> - **Within an `Expression`, if any parameters of the candidate method, other than the implicit instance method receiver, may have a `ref struct` type, the candidate is not applicable.**\n\nNote that the disqualifying parameter:\n- May be a `params` parameter\n- May be an optional parameter\n- May have a *generic parameter* type with `allows ref struct`\n\n## Drawbacks\n\nIgnoring certain overloads may be a breaking change itself, in limited scenarios where `ref struct` instances are supported within an `Expression` currently. *Examples?*\n\n## Alternatives\n\n### No compiler change; add IDE fixer\n\nMake no additional compiler changes. Instead, require callers to rewrite `Expression` instances to work around the overload resolution changes. An IDE fixer could be provided to rewrite calls for these cases.\n\n### Support `ref struct` arguments within `Expression` lambdas\n\nThe [`Expression` interpreter](https://learn.microsoft.com/en-us/dotnet/api/system.linq.expressions.expression-1.compile?view=net-9.0#system-linq-expressions-expression-1-compile(system-boolean)) relies on *reflection*, so supporting these cases would require supporting `ref struct` arguments in reflection or rewriting parts of the interpreter.\n"
  },
  {
    "path": "meetings/working-groups/roles/extension-wg-2024-06-07.md",
    "content": "\r\n# Extensions WG 2024-06-07\r\n\r\n## Type erasure encoding\r\n\r\nWe need to encode the extension type (for extension-aware compiler) and the underlying type (erasure and for non-extension-aware tools).\r\n\r\nWe'll need to encode tuple names, dynamic bits, nullability, native integer for both types. \r\nIdeally, this should be done in a way that doesn't break tools that understand the current attribute/constructor encoding.\r\n\r\nOptions for encoding extension type:\r\n- generic attribute (pinging David to ask limitations/bugs on older frameworks)\r\n- attribute with typeof (may not refer to type parameters)\r\n- nested type\r\n- nested type with parallel method\r\n\r\nDecision: we'll spec out the parallel method in nested type design.\r\n\r\n### modopt\r\n```\r\n// source\r\nvoid M(E e)\r\n\r\n// codegen\r\nvoid M(C modopt(E) e)\r\n```\r\n\r\n```\r\nvirtual void M2(C c)\r\n// other assembly\r\noverride void M2(E e)\r\n```\r\n\r\nCon: binary break to change API from extension to underlying type and back\r\nCon: problem for override at language level (might be solvable)\r\nCon: need to new solution encode the second set of tuples names/dynamic/nullability\r\n\r\n### Generic attribute\r\n```\r\n// source\r\nvoid M(E e)\r\n\r\n// codegen\r\nvoid M([Extension<E>] Underlying e) // System.Extension`1 (new)\r\n```\r\nCon: Attribute doesn't exist downlevel (we should synthesize)\r\nCon: Generic attribute not supported before .NET 7 (prove there's enough support, or block off)\r\nCon: need to new solution encode the second set of tuples names/dynamic/nullability\r\n\r\n### Attribute with typeof\r\n\r\nLimitation with typeof in attribute referencing type parameter (typeof encoded as fully-qualified name, context-free, but no such syntax exists for type parameters)\r\n\r\n\r\n```\r\n\r\nclass C<T>\r\n{\r\n    void M(E<List<T>> e)\r\n    // encoding: void M([Extension(typeof(E<List<T>>))] object e) // not possible\r\n}\r\nexplicit extension E<U> for object { }\r\n```\r\n\r\n### Nested type\r\n\r\nDoesn't work with method type parameter. We could use a generic private implementation nested type with same number of type parameters.\r\n```\r\nexplicit extension E<T1, T2> where T2 : IDisposable { }\r\nclass C<T>\r\n{\r\n    // source: void M<U>(E<T, U> e) where U : IDisposable\r\n    void M<U>([Extension(\"Secret1\", \"Field1\")] Underlying e) // problem with method type parameter\r\n\r\n    private class Secret1<U> where U : IDisposable\r\n    {\r\n        E<T, U> Field1;\r\n    }\r\n}\r\n```\r\n\r\n### Nested type with parallel methods\r\n\r\nPro: Nested type reduces pollution of members for other tools\r\nPro: Runtime may not need to load the members of nested type (to be confirmed)\r\nPro: natural encoding of tuple names/dynamic/etc\r\nCon: copies all the parameters\r\nPro: it naturally offers a place to encode the second set of tuples names/dynamic/nullability information\r\n\r\nSecret class is abstract and parallel methods are abstract\r\nNote: Hard to point backwards from parallel method, so attribute is on visible method\r\n\r\n```\r\nclass C<T>\r\n{\r\n    [SecretMethod(\"Method1\")] // explicit matching, rather than complex auto-matching\r\n    U M<U>(U e, int x) where U : IDisposable\r\n\r\n    private abstract class Secret\r\n    {\r\n        abstract void/E<T, U1> Method1<U1>(E<T, U1> \"\", Secret \"\") where U1 : IDisposable;\r\n    }\r\n}\r\n```\r\n\r\n#### Optimization? one secret method per type to encode\r\n```\r\n    private class Secret\r\n    {\r\n        // More parameter cause more methods, but we can share\r\n        E<T, U1> Method1<U1> where U1 : IDisposable { }\r\n        E<T, U1> Method1<U2> where U1 : IDisposable { }\r\n    }\r\n```\r\n\r\n#### Optimization? remove parameters that don't involve extensions/erased\r\nWe could use parameter names encoding ordinals from original method:\r\n```\r\n    private class Secret\r\n    {\r\n        void Method1<U1>(E<T, U1> p0 /*, Secret x */) where U1 : IDisposable\r\n    }\r\n```\r\n\r\n#### Properties\r\n\r\n```\r\n   // E this[E e]\r\n   No parallel property, only have parallel accessors\r\n```\r\n\r\n#### Types?\r\n```\r\n   // class C<T> : I<E<T>> { }\r\n   class C<T> : [SecretField(\"Field1\")] I<Underlying>\r\n   {\r\n       private abstract class Secret\r\n       {\r\n          I<E<T>> Field1;\r\n       }\r\n   }\r\n```\r\n\r\n## Translation from instance methods to static metadata methods\r\n\r\nCLS rules for events requires a specific signature (single parameter), but we need a second parameter. See ECMA 335 II.22.28.\r\nHow bad is it? May break other compilers. Would those compilers allow to consume those methods or treat as invalid metadata?\r\nDisallow events?\r\n\r\n"
  },
  {
    "path": "meetings/working-groups/roles/extension-wg-2024-06-14.md",
    "content": "# Extensions WG 2024-06-14\r\n\r\nAgenda\r\n- type erasure\r\n\r\nTL;DR: we'll pursue the attribute with typeof-like string.\r\n\r\n## Type erasure\r\n\r\nWe did a quick recap of various options we'd considered so far, and explored using an attribute\r\nwith a string serialization to represent the erased types.\r\n\r\n1. modopts\r\n2. generic attribute\r\n3. attribute+typeof \r\n4. parallel method\r\n5. typeref/blobs\r\n\r\n### Attribute with typeof-like string\r\n\r\nThe main problem is how to represent type parameters, since they are currently disallowed in typeof inside attributes.  \r\nWe could extend the typeof format with existing convention \"!N\" (type parameters), \"!!N\" (method type parameters), stopping at first container (method or type) when resolving.  \r\nWe would use a `string` instead of a `Type`: `ExtensionAttribute(string encodedInformation)`.  \r\n```csharp\r\n// source\r\nvoid M(C<E<int>>)\r\n\r\n// metadata\r\nvoid M([ExtensionAttribute(\"E<int>\")] C<U>)\r\n```\r\n\r\nThere are some concerns with re-hydration reliability, but those are not worse than what typeof in attributes already encounters.  \r\nIn terms of specification, we would just say we use the existing (not well-specified) format from typeof and just add the type parameter case.  \r\nFor reflection users, this string would be less useful than a `Type`. Maybe some helper APIs could be offered (somewhere outside the compiler-synthesized attribute and not in roslyn).  \r\nThis format feels verbose (compared to typerefs), but it seems the most feasible and comparatively simpler overall compared to other options.  \r\n\r\nEncoding one attribute per typed entity (return type, parameter type, constraint type) fits with current codegen for tuple names, nullability, dynamic, etc. We will let the runtime team know in case this is a major concern.  \r\n\r\nWe need separate encoding for tuple names, nullability on non-erased type. This can be stored in the attribute itself.  \r\n```csharp\r\nclass ExtensionAttribute\r\n{\r\n    ExtensionAttribute(string) { }\r\n    Nullability { get; }\r\n    TupleNames { get; }\r\n    Dynamic { get; }\r\n}\r\n```\r\n\r\nAs for other such compiler-generated attributes, we'll disallow direct usage of this attribute in source.\r\n"
  },
  {
    "path": "meetings/working-groups/roles/extension-wg-2024-06-21.md",
    "content": "# Extensions WG 2024-06-21\r\n\r\n- update on instance invocation\r\n- open issue: what kind of type is an extension type?\r\n- spec: conversions, operators, adapting to existing type kind rules, any updates from design review (Mads)\r\n\r\n# Instance invocation\r\n\r\nSee description in https://github.com/dotnet/roslyn/pull/74012\r\n\r\nWe'll have follow-up issue for nullability of the extra parameter.  \r\nWe'll have follow-up issue for capturing the receiver when it is a type parameter.  \r\n\r\nNote: When implementing interfaces, a modopt(ExtensionAttribute) could be brought into the picture and cause a conflict/ambiguity.\r\n\r\n## Open issue: what kind of type is an extension type?\r\n\r\nMany sections of the spec need to consider the kind of type. Consider a few examples:  \r\n- the spec for a conditional element access `P?[A]B`\r\nconsiders whether `P` is a nullable value type. So it will need to handle the case\r\nwhere `P` is an instance of an extension type on a nullable value type,\r\n- the spec for an object creation considers whether the type is\r\na value_type, a type_parameter, a class_type or a struct_type,\r\n- the spec for satisfying constraints also consider what kind of type were dealing with.\r\n\r\nIt may be possible to address all those cases without changing each such section of the spec,\r\nbut rather by adding general rules (\"an extension on a class type is considered a class type\" or some such).\r\n\r\n1. extension type on class type is a class type, on a struct type is a struct type, on a type parameter is considered a type parameter, ... (not sure how to word this, maybe \"for purpose of\")\r\n2. but nullable value type needs to be handled case by case. System.Nullable<...>\r\n3. are there other cases we need to consider (keep an eye out)\r\n\r\nexplicit extension E<T> for T { void M(); }\r\nnew C().M();\r\nnew S().M();\r\n\r\n\r\n\r\n"
  },
  {
    "path": "meetings/working-groups/roles/extensions-2023-02-21.md",
    "content": "# Extensions 2023-02-21\n\nSince the latest syntax proposal is `implicit`/`explicit` `extension`, we're going\nto refer to the feature as \"extensions\" or \"extension types\", rather than \"roles\".\n\n## Allow omitting `implicit` or `explicit`?\n\nWithout `implicit` or `explicit`, `extension` would likely mean `implicit`.  \nBut that view is not obvious. There's a historical view where extensions come first\nand roles follow, but there's also a view where roles are fundational and extensions\nare roles plus implicit lookup rules...  \nFor now, we're leaning to require `implicit`/`explicit`. We can decide to relax this \nand pick what the default means later.\n\n## When to keep using extension methods?\n\nOverall, extension types are more powerful than extension methods.  \nBut we could think of two scenarios where one could prefer to use extension methods:\n1. Extending multiple times whilst sharing code:\n  ```\n  void M(this OneType one)\n  void M(this OtherType other)\n  ```\n2. Targeting a framework that doesn't support ref fields\n\n## Types may not be called \"extension\" \n\nAlthough there's no grammatical ambiguity (especially since we decided to require \n`implicit`/`explicit` before `extension`), it feels simpler from a language and\nimplementation point of view to disallow types named \"extension\".\n\nHere are some productions to consider:  \n`implicit extension E`  \n`explicit extension E`  \n`implicit operator`  \n`explicit operator`  \n`explicit I.operator(...)`  \n`explicit extension.operator(...)` // reserving keyword helps a bit\n\nOptions:\n1. add an error\n2. existing warning wave is sufficient\n\nDecision: let's go with (1).\n\n## Allow optional underlying type?\n\nThere are two scenarios where omitting the underlying type could be useful:\n1. partial scenarios, where the underlying type is derived from other parts  \n  `partial implicit extension R { }`\n2. deriving from other extension types, where the underlying type could be derived from the base extensions (somehow)  \n  `implicit extension R : R1, R2` \n\nDecision: we definitely see value in (1), but are not yet sure about (2). We can add that support later.\nLet's make room in the syntax and support (1) for now.\n\n## Explicit identity conversion for sideways conversions?\n\nIn the following example, should we give some kind of type safety so that \ninstances of `CustomerExtension` and `EmailExtension` don't mix?  \n```\nexplicit extension CustomerExtension for ReadOnlySpan<byte> : PersonExtension\nexplicit extension EmailExtension for ReadOnlySpan<byte>\n```\n\nOptions:\n1. implicit identity conversion all the way\n2. implicit up-down, but explicit sideways (Customer<->Email requires explicit conversion).  \n  2A. TODO: do we have an explicit identity conversion or an implicit one that warns? \n3. distinguish between up and down, ... \n4. explicit all the way\n\nThere's some benefits of such type safety, so we're interested to explore this more.   \nBut the notion of \"explicit identity conversion\" is problematic. Maybe we could spec this \nas having an implicit conversion that warns?  \n\nThere may be value in distinguishing identity conversions up and down as well.  \nThere could be validation scenarios on the way \"down\". This would need further exploration. How \ndoes a type opt into such validation? We couldn't use the presence of an explicit conversion operator,\nsince a user-defined conversion operator is problematic for an identity conversion (it would break the\nidentity invariant).  \nA \"validator\" would have to be bool-returning. If the validation succeeds, then we handle the conversion.  \nThis could come into play into patterns (almost like active patterns).  \n\nDecision: let's start with (2), consider \"validator\" for later on. \n"
  },
  {
    "path": "meetings/working-groups/roles/extensions-wg-2023-04-27.md",
    "content": "# Extensions 2023-02-21\n\n## Problem with lookup rules on implicit extensions\n\nThe issue is that the proposed rules would allow a member from a base implicit extension\nto be found by extension member lookups in two way: via import and via inheritance.  \nThis would result into having duplicates (same member appears twice in lookup) or conflicts\n(hidden member conflicts with hiding member).  \nBelow are a few examples. \n\n### Various examples\n```\n// No definition in Derived\nimplicit extension Base for object \n{\n    void M() { }\n}\nimplicit extension Derived for object : Base\n{\n}\n\nobject o = ...;\no.M(); \n```\n\n```\n// Hiding in Derived\nimplicit extension Base for object \n{\n    void M() { }\n}\nimplicit extension Derived for object : Base\n{\n    new void M() { }\n}\n\nobject o = ...;\no.M(); // ambiguous\n```\n\n```\n// Better in Base\nimplicit extension Base for object \n{\n    void M(int i) { }\n}\nimplicit extension Derived for object : Base\n{\n    void M(double d) { }\n}\n\nobject o = ...;\no.M(1); // Which does it pick?\n```\n\nBeyond those invocation scenarios, there are also non-invocation scenarios:\n\n```\n//  Non invocation\nimplicit extension Base for object \n{\n    int Prop => 0;\n}\nimplicit extension Derived for object : Base\n{\n}\n\nobject o = ...;\no.Prop; // find it twice, but it's only Base.Prop, so okay\n```\n\n```\n// Non invocation, shadowing\nimplicit extension Base for object \n{\n    int Prop => 0;\n}\nimplicit extension Derived for object : Base\n{\n    new long Prop => 0; // warning so you put \"new\"\n}\n\nobject o = ...;\no.Prop; // ambiguity (this is an argument for pruning)\nderived.Prop; // would find Derived.Prop\n```\n\n### Options\n\nWe considered a few different ways of handling this:\n\nFirst, we thought of relying on overload resolution to prefer more derived members. But this doesn't work for non-invocation scenarios.\n\nThen we considered removing/pruning base extensions from the set of candidates during extension member lookup.  \nThis means a member from a base extension is only visible via inheritance, but not via import when it\nis hidden.\n\nBut then we realized that existing lookup rules have to solve this already, as they are able to deal with \ninterface members in multi-inheritance scenarios, or in scenario with a type parameter with two interface constraints.\n\nHere's an example to illustrate the current behavior:\n```\nI2 i2 = default!;\nvar r2 = i2.Prop; // Finds I2.Prop, infers long\n\nI4 i4 = default!;\nvar r4 = i4.Prop; // Finds I2.Prop, infers long\n\npublic interface I1 { public int Prop { get; } }\npublic interface I2 : I1 { new public long Prop { get; } }\npublic interface I3 : I1 { }\npublic interface I4 : I2, I3 { }\n```\n\nWe tracked down the relevant rule from member lookup:  \n\"Next, members that are hidden by other members are removed from the set.\"\n\nConclusion: We'll incorporate a similar rule in extension member lookup.\n\n## Unification of base extensions?\n\nFor interfaces, we check that directly implemented interfaces cannot unify.\nFor example:\n\n```\ninterface I<T> { }\nclass C<U> : I<int>, I<U> // error\n{\n    void I<int>.M() { }\n    void I<U>.M() { }\n}\nC<int>.M() // allowing such unifying scenario would cause a problem here (because we would have two V-tables to merge)\n```\n\nDo we similarly need to check for potential unification of base extensions?\n\nThe scenario would be:\n```\nexplicit extension E<T> for object { }\nexplicit extension E2<U> for object : E<int>, E<U>\n{ \n    void M() { }\n}\n```\n\nWe couldn't think of a problem with allowing this at the moment. Lookup on `E2<int>` would work.  \nBut if we ended up having some special support for extension types in the runtime, we could have a problem.  \n\nConclusion: Let's move ahead to unblock basic scenario and revisit\n\n## Mixing implicit/explicit in a hierarchy\n\nDo we need some check on implicit/explicit consistency in an extension hierarchy?\n\nFor example:\n```\nimplicit extension Base for object { }\nexplicit extension Derived for object : Base { }\n```\n\n```\nexplicit extension Base for object { }\nimplicit extension Derived for object : Base { } // why? this may be scoped in a namespace\n```\n\nConclusion: Some of the mixing scenarios seem questionable, but adding a restriction\nwould not give much benefit/protection. So we'll allow any mix of implicit/explicit-ness.\n"
  },
  {
    "path": "meetings/working-groups/roles/extensions-wg-2023-06-07.md",
    "content": "# Extensions 2023-06-07\n\n## Reviewing the \"invocation expression\", \"member access\" and \"extension invocation\" sections\n\nWe reviewed the proposals in PR https://github.com/dotnet/csharplang/pull/7179 and discussed some open issues.  \n\n### Invoking members from extended type\n\nThe first issue is that we want to access members from the extended type on a type or value of an extension type.\n\n```csharp\nextension E for C\n{\n  void M()\n  {\n    this.MethodFromUnderlying(); // problem\n    MethodFromUnderlying(); // problem\n  }\n}\n```\n\nThe current proposal had a bullet in \"member access\" \nwhich would make member access scenarios work for non-invocations, \nbut that left invocations and simple name scenarios unsupported.\n\nDecision: we want those scenarios to work and we can achieve that \nby modifying \"member lookup\" to also find members from the underlying type.\nThe \"member lookup\" section already handles lookups \n\n### Pattern-based method binding\n\nThe second issue is that the proposed rules raise a question about how pattern-based invocations,\nsuch as the one involved in deconstruction.\n\nFor instance, should the following work?\n\n```csharp\nimplicit extension E for C\n{\n   public dynamic Deconstruct { get { ... } } \n}\n\nclass C\n{\n   void M()\n   {\n     (int i, int j) = this;\n   }\n}\n```\n\nDecision: If the scenario allowed instance properties today, then extension properties should work, if not, then not.\nSo, given that an instance `Deconstruct` property would not participate in deconstruction today,\nwe don't want an extension `Deconstruct` property to participate either.\n\nAny scenario that allowed extension methods should allow methods from extension types to participate.  \nThis means we'll need to review all pattern-based sections of the spec to come up with some language\nto only bind to methods in the extension type case. Maybe something like \"Do a member access and if that resolves to a method, then ...\"\nor \"if the expression ... resolves at compile-time to a unique instance or extension method or extension type method, that expression is evaluated\".  \n\nAlso, we'll need to make decisions for\nnon-invocation members, such as the `Current` property involved in a `foreach`, as those were not previously\ncovered by extension methods.\n\n## Forward compatible emit strategy for interface support \n\nWe briefly reviewed an alternative to the `ref struct` approach that is currently proposed.  \nWe will need to experiment and flesh out a proposal.\n"
  },
  {
    "path": "meetings/working-groups/roles/extensions-wg-2024-03-05.md",
    "content": "# Extensions WG 2024-03-05\r\n\r\n## finding extension members on underlying type\r\n\r\nJust like extension methods on a base type are eligible when given an instance of the derived type,\r\nextension members on the underlying type should be eligible when given an extension type or value.  \r\nThe extension member lookup rule was updated to look at the underlying type when given an extension type.\r\n\r\n```\r\nvar x = E1.Member;\r\nSystem.Console.Write(x);\r\n\r\nclass C { }\r\n\r\nextension E1 for C { }\r\n\r\nimplicit extension E2 for C\r\n{\r\n    public static string Member = \"ran\";\r\n}\r\n```\r\n\r\nDecision: that seems fine.\r\n\r\nNote: like other extension lookups, that would not apply on Simple Names. For example:\r\n```\r\nclass C { }\r\n\r\nextension E1 for C \r\n{ \r\n    void M()\r\n    {\r\n        var x = Member; // error\r\n        string s = Member; // error\r\n    }\r\n}\r\n\r\nimplicit extension E2 for C\r\n{\r\n    public static string Member = \"\";\r\n}\r\n```\r\n\r\n## merging extension methods and extension type members within same scope\r\n\r\nLDM decided that we should merge extension methods and extension members within the same scope.\r\nBut how should we deal with ambiguities, either of the same kind or of different kinds?\r\n\r\nDecision: let's be strict on merging different kinds of members (produce ambiguity).  \r\nProposal: Consider doing a breaking change or warning wave warning (would be error for extension case)?\r\n\r\n## preference for more specific extension members\r\n\r\nWe discussed two ways of doing this:\r\n1. stop once we find something on a more specific extension? (\"shadowing\" type of rule)\r\n2. ambiguity when different kinds are found, disambiguate within one kind when overload resolution involved? (no shadowing across different kinds)\r\n\r\nDecision: we'll pursue proposal 2.\r\n\r\n## Follow-up investigations\r\n\r\n1. Look at how lookup within a type works today (not inside an interface)\r\n  - for example, derived defines a field and base defines a method\r\n  - for example, derived defines a method and a base defines a field\r\n2. find existing merging logic for different kinds of members\r\n3. find existing logic for overload resolution picking between extension methods based on receiver\r\n4. need to understand how the field shadowing works in the following example:\r\n```\r\nSystem.Console.WriteLine(I4.F); \r\n\r\ninterface I1\r\n{\r\n    static int F = 1;\r\n}\r\n\r\ninterface I2 : I1 \r\n{\r\n    static int F = 2;\r\n}\r\n\r\ninterface I3 : I1 {}\r\n\r\ninterface I4 : I3, I2 {}\r\n```\r\n\r\n## brainstorm on inapplicable members hiding applicable ones\r\n\r\nWe did not cover this yet.\r\n\r\n```\r\nvar x = C.Member; // error: member lookup finds C.Member (method group) and lacks type arguments to apply to that match\r\n\r\nclass C \r\n{\r\n    public static void Member<T>() { }\r\n}\r\n\r\nimplicit extension E for C\r\n{\r\n    public static int Member = 42;\r\n}\r\n```\r\n"
  },
  {
    "path": "meetings/working-groups/roles/extensions-wg-2024-08-09.md",
    "content": "# Extensions WG 2024-08-09\n\n## Conversions\n\nWe reviewed proposed approach for conversions:\n- extend existing conversions rather than introduce a new \"extension conversion\n- extend categories of \"reference types\", \"value types\", \"nullable value types\", \"enum types\"\n- follow-ups: non-transitive identity conversion (`EInt1 => EInt2`), user-defined conversions\n\n## Reference nullability\n\nAllowing top-level nullability on underlying types is tempting for implicit scenarios, but it's going to cause problems on explicit scenarios.\nIf we define `explicit extension E for object? { }`, then do you get to say `E?`? Also would `E` be considered annotated or not?\nThis is already tracked as an open issue to investigate further.\n\n## Differences between extensions and structs you could write today?\n\n```\nimplicit extension JsonDoc for string { public void ExtensionMember() { } }\n```\nvs.\n```\nstruct JsonDoc\n{\n   public static implicit operator string(JsonDoc)\n   public static implicit operator JsonDoc(string)\n}\n```\n\nWith extensions you get the following benefits:\n- identity/standard conversion\n- List<[JsonDoc] string> vs. List<string>\n- extension conversions\n- `\"\".ExtensionMember()` (by virtue of `implicit`)\n\n## Relationship between implicit and explicit?\n\nEvery extensions can be used explicitly, but only implicit ones can come into play implicitly.\n\n## Brainstorming on naming extensions\n\nThe name \"JsonDoc\" brings a mental model of hierarchy or \"is-a\" relationship. This feels more natural for explicit usages.\nBut the name \"StringExtension\" does not bring such a mental model. This feels more natural for implicit usages.\n\n`JsonDoc s = \"\";`\n`StringExtension s = \"\";` // weird\n\n## Disambiguation for properties\n\nAllowing implicit extensions to be named explicitly helps for disambiguation.\n\n`StringExtension.ExtensionMember(receiver, args)` // fallback for extension methods \n\n```\nimplicit extension StringExtension1 for string { public int Prop { get; set; } }\nimplicit extension StringExtension2 for string { public int Prop { get; set; } }\n\n\"\".Prop // how to disambiguate?\n((StringExtension1)\"\").Prop\n```\n\n## Concern over type explosions\n\n```\nstatic class MemoryExtension\n{\n  public static void M1(this Type1)\n  public static void M2(this Type2)\n}\n```\nYou would need to split this into two extension types. One for Type1 and the other for Type2.\n\n"
  },
  {
    "path": "meetings/working-groups/roles/roles-2022-11-10.md",
    "content": "# Roles & extensions working group (2022-11-10)\n\n## Framing of phase 1 (extension everything)\n\nIn the last few months, much of our investigation into roles was focused on scenarios that involve adding an interface implementation to an existing type.  \nOur thinking was that we needed to figure out those harder scenarios first, so that we wouldn't risk painting ourselves into a design corner.  \nBut we believe using ref structs as part of the emit strategy for roles and extensions would protect this scenario.  \nSo we're going to explore this further in the next few meetings with the intention of carving a phase 1 for roles and extensions.  \nPhase 1 would allow extending existing types with new members, but interface scenarios would come in phase 2.\n\n## Syntax and usage scenarios\n\nThe syntax used below has not been thoroughly discussed yet. But it is good enough for discussion.  \nWe will need to revisit in a couple of weeks (definitely before any implementation work starts).\n\n## Emit strategy\n\nHere's an outline of the proposed emit strategy in a few scenarios:\n\n### Role type itself\n\n```csharp\nrole MyRole<T> : UnderlyingType where T : Constraint \n{\n    // Member declarations\n    void M()\n    {\n        ... usage of `this` with type `MyRole` ...\n        _ = this.ExistingMethod();\n        _ = this.existingField;\n        this.M();\n    }\n}\n```\nwould be emitted as:\n```csharp\nref struct MyRole<T> where T : Constraint // possibly with a special base type like `System.Role` or `System.Role<...>` or some other marker\n{\n    ref UnderlyingType @this;\n    MyRole(ref UnderlyingType underlying)\n    {\n        @this = ref underlying;\n    }\n\n    // Member declarations\n    void M()\n    {\n        ... usages of `this` are replaced with `@this` ...\n        _ = @this.ExistingMethod();\n        _ = @this.existingField;\n        this.M();\n    }\n}\n```\n\nInterfaces would be disallowed until phase 2.  \n\n### Role on a role\n\n```csharp\nrole MyRole2<T> : MyRole<T> where T : Constraint \n{\n  ...\n}\n```\nwould be emitted as:\n```csharp\n// Need to encode relationship to MyRole<T>. Maybe the @this field is sufficient.\nref struct MyRole2<T> where T : Constraint\n{\n    [Role(typeof(MyRole))] ref UnderlyingType @this;\n    // ... members ...\n}\n```\n\nOpen question: confirm whether the attribute is needed\n\n### Invocations on role member\n\nUsages of `MyRole.M()` on a `MyRole` local:\n```\nUnderlyingType underlying = ...;\nref MyRole role = ref underlying; // conversion creates a ref struct\nrole.M();\n```\nwould be emitted as:\n``` c#\nUnderlyingType /*MyRole*/ role = underlying;\nnew MyRole(ref role).M();\n```\n\n### What kind of conversion is this?\n\nFor `List<MyRole>` and `List<UnderlyingType>` to be convertible, we need identity conversion between `MyRole` and `UnderlyingType`.\n\nThen the role is only instantiated as part of the invocation and is short-lived.  \nOpen question: need to confirm this design and weight pros/cons.\n\nOpen question: How about structs?\n```\nUnderlyingStructType underlying = ...;\n((MyRole)underlying).M(); or declare a ref local\n```\n\n### Inferred type arguments in invocation\n\nThis erasure approach may run into some friction with a future phase 2, as phase 2 requires type arguments to use role types to satisfy certain interface constraints.  \nWhether the role type is erased into the underlying type is observable with type tests like `is IEnumerable<int>`. In phase 2, the role could add this interface on an underlying that doesn't have it.   \n\n```cs\nMyStruct m = new();\nref MyRole r = ref myStruct;\nvar x = M(ref r); // T is MyStruct /* MyRole */\nvar y = M2(ref r); // In phase 2, T would be MyRole, would we change what is emitted for calling M from phase 1?\n\nref T M<T>([Unscoped] ref T t) => ref t;\n\nref T M2<T>([Unscoped] ref T t) where T : IEnumerable<int> => ref t;\n\nref T M3<T>([Unscoped] ref T t)\n{\n    // problem with erasure\n    if (t is IEnumerable<int> i) ...\n}\n```\n\n### Usage as extension\n\nTo turn a role into an extension, its declaration needs to be changed (let's say from `role` to `extension`):\n```\nclass UnderlyingType\n{\n    void M1() { ... }\n    void M2() { ... }\n}\n\nnamespace MyRoleNamespace\n{\n    extension MyRole : UnderlyingType \n    { \n        void M2() { } \n        void M3() { }\n    }\n}\n```\n\nThen to use that extension, it needs to be brought into scope with `using MyRoleNamespace;`.\n\n#### Usages of `MyRole.M()` as an extension on an `UnderlyingType` local:\n```\nusing MyRoleNamespace;\nUnderlyingType underlying = ...;\nunderlying.M1();\nunderlying.M2();\nunderlying.M3();\n```\nwould be emitted as:\n```\nUnderlyingType underlying = ...;\nunderlying.M1();\nunderlying.M2();\nnew MyRole(ref underlying).M3();\n```\n\nIn terms of lookup rules, we would keep the same order as extensions today, namely that instance members win.\n\nIn the example, lookup for `M1`, `M2` or `M3` would be:\n1. instance members on UnderlyingType\n2. otherwise, fall back to extensions\n\n### Role type in signatures\n\n```\nMyRole M(MyRole role)\n```\nwould be emitted as `UnderlyingType` with an attribute:\n```\n[return: Role(typeof(MyRole))] UnderlyingType M([Role(typeof(MyRole))] UnderlyingType role)\n```\n\nThis encoding would allow callers of `M` to get the right return type (`MyRole`):\n```\nMyRole role1 = ...;\nvar role2 = M(role1); // var == MyRole\n```\n\n### What kinds of types can roles be defined on?\n\n```cs\nrole Role<T> : T {}\n\n// TODO: Confirm whether typeof in attribute can refer to T?\nRole<T> M<T>(Role<T> role)\n=>\n[return: Role(typeof(T))] UnderlyingType M<T>([Role(typeof(T))] UnderlyingType role)\n```\n\n```cs\nrole MyFunctionPointerRole : delegate*<...> { }\n// can't put function pointer in typeof in attribute\n\ndelegate*<MyRole> // nowhere to store attribute\n```\n\n### Encoding of roles in metadata\n\nSome possible encodings:\n1. attributes\n2. Custom modifiers (`modopt`)\n3. don't erase roles (need runtime support)\n\nPreviously, we were thinking of emitting erased roles like tuples or `dynamic`, ie. using an attribute.  \nBut that encoding scheme doesn't work so well for roles, because we need to encode types. This is not only more verbose, but it runs into some limitations.\nWe're going to explore the next alternative, ie. using `modopt`.\n\nUse a modopt on return type:\n```cs\nRole<T> M<T>(Role<T> role)\n```\nwould emit as:\n```cs\nmodopt(Role<T>) UnderlyingType M<T>(modopt(Role<T>) UnderlyingType role)\n```\n\nOne benefit of this approach is that modopt is allowed anywhere a type is allowed:\n`List<modopt(Role<int>) UnderlyingType>`\n\nA downside of this approach is that call sites need to spell out the entire signature, including modopts.  \nAlso, this implies that changing API from underlying type to role is a breaking change.   \n\nFinally, this implies that you could overload on role types:\n```\nvoid M(UnderlyingType underlying) { }\nvoid M(MyRole role) { }\n```\n\nOpen question: confirm we're okay with such compat behavior\n\n### Hiding\n\n### Next time\n- Compat behavior of modopt\n- Conversion\n- Repetition at call-site\n"
  },
  {
    "path": "meetings/working-groups/roles/roles-2023-01-23.md",
    "content": "# Roles WG 2023-01-23\n\nEarlier this week, we reviewed the proposed lookup rules. \nWe're continuing to review https://github.com/jcouv/csharplang/blob/roles-spec/proposals/roles.md\n\n## Static-ness\n\nRoles must support a non-static flavor and since any role can be turned into an extension,\nextensions must also support a non-static flavor.  \nBut it doesn't make sense to allow a non-static extension on a static underlying type.  \n\nThe proposal we're landing on is that roles/extensions would not require specifying \nstatic-ness. We would use the static-ness from the underlying type and disallow \nexplicit `static` modifiers.\n\nThis approach seems convenient for users. But allowing a `static` modifier could be useful\nto avoid emitting a ref field when possible. Some auto-detection might also be possible, but\nnot very attractive.\n\n## Is it necessary to place the nesting restriction?\n\nLet's remove the restriction. We can update the extension member lookup rules to first look in \nenclosing types then enclosing namespaces.  \nTreating types as scopes like namespaces invites allowing usings/imports in types, but let's not.  \n\n\n\n## Static imports\n\nIs it a general principle that an extension is in effect when its type can be accessed with a simple name? \nIf so, can a static using of an enclosing type bring a nested extension in effect?\n\nShould `using static C;` bring the nested extension into scope?  \n\n```\npublic class C\n{\n    public extension E \n    { \n    }\n}\n\nusing static C;\n// E an extension here?\n```\n\nYes, this would make sense. You could name the type `E` from that location,\nso the extension members should be in scope.\n\n## Modifiers\n\nSince we're allowing nested roles/extensions, then we'll allow the `private` modifier.  \nWe should allow the `file` modifier.\n\n## Underlying type\n\n### Pointer\n\nShould we disallow pointer types as underlying types?  \nThere is precedent with extension methods and some issues with metadata (`System.Role<pointer>`).  \nOn the other hand, it would be nice to support.  \nWe'll start by disallowing pointer types, but let's find an emit strategy that would allow them eventually.  \n\n### Nullability\n\nJust like for base types, we'll disallow top-level nullability in underlying types.\nNested nullability should be allowed, but it will not affect lookup.  \nWe may want to warn on mismatch on nullability when used.  \n\n### Ref structs\n\nWe would like to allow ref structs as underlying type for roles/extension, but \nour emit strategy relies on ref fields, which don't yet support ref structs.  \nMaybe the lifetime rules could allow this, given that the usage pattern is controlled/limited.  \n\n### Roles\n\nWe would like to allow role types as underlying types.\nMaybe we should even allow **multiple role types** in the definition of a role.  \n\n```\nrole DiamondRole : NarrowerUnderlyingType, BaseRole1, Interface1, BaseRole2, Interface2 { }\n```\n\nThe relationship between a role and it's \"base role\" would not be one of inheritance and virtual calls:\n```cs\nclass C\n{\n    void M() { ... }\n}\nrole R1 : C\n{\n    // New version adds below\n    //void M() { ... }\n}\n\n// Different library\nrole R2 : R1\n{\n    void M2()\n    {\n        M();\n    }\n}\n```\n\nWe still need to refine terminology.  \nSince members of a role shadow its underlying type, maybe we should emit a warning when shadowing a name? (need to add `new`)\n\n### Extensions\nExtensions are just roles, and roles are allowed in underlying role list. So extensions should be allowed too.\n\n### Extension syntax\n\nThe current syntax proposal puts the producer of a role in charge of making it\nan extension or not. Should we use a syntax that puts the consumer in charge instead?  \n```\nrole R { }\nusing R;\n```\n`extension role R`?\n`extension E : R;`?\n\n### What kind of type are roles/extensions?\n\nThe fact that roles are emitted a ref structs should be kept an implementation detail.  \nAs far as the language goes, roles would be a new kind of type. A role type would satisfy \nthe same generic constraints as its underlying type.\n\n```\nrole Role : SomeClassType;\nvoid M<T>() where T : class { }\nM<Role>(); // okay, `modopt(Role) Underlying`, Roslyn metadata reader can recover `Role`. Can reflection see custom modifiers?\n```\n\n\n"
  },
  {
    "path": "meetings/working-groups/roles/roles-2023-01-25.md",
    "content": "# Roles WG 2023-01-25\n\n## Language for relationships\n\nWe'll use \"augments\" for relationship to underlying type \n(comparable to \"inherits\" for relationship to base type).  \nWe'll use \"inherits\" for relationship to inherited roles \n(comparable to \"implements\" for relationship to implemented interfaces).  \n\n```csharp\nstruct U { }\nrole X : U { }\nrole Y : U, X, X1 { }\n```\n\"Y has underlying type U\"  \n\"Y augments U\"  \n\"Y inherits X and X1\"  \n\"Derived role Y inherits members from inherited roles X and X1\"  \n\n## Syntax for role underlying type list\n\nWe should assume multiple inheritance for now. Will update syntax to allow multiple inherited roles.  \nIn that syntax, the first type will be the underlying type.  \n`role R : I { } // First type is underlying type (not an implemented interface)`\n\n## Type parameters in extensions\n\nThe purpose of requiring all extension type parameters to \nappear in the underlying type is to help find a unique substitution \nwhen looking for compatible extensions.\n\nFor example, if you have `extension X<T> : U<T>` and then need to decide\nwhether it is compatible with the `U<int>` type, you need to find a unique\ncompatible substituted extension type `X<int>`.  \n\nThis rule does not apply to roles (assuming that we don't let consumers turn \na role into an extension after the fact).\n\n## Constraints \n\nWill need to spell out rules for all kinds of constraints, such as `struct`, `class`, etc.\n\n`where T : Extension`, `where T : Role`  \nWe'll disallow roles/extensions in type constraints for now. But this is assuming that\ncasting makes the experience acceptable and doesn't cause an issue with struct.\n\n## Definition of \"role type\"\n\nInterfaces don't have a base type, but have base interfaces.  \nSimilarly, roles don't have a base type, but have base roles.    \n\n`role R<T> : T where T : I1, I2 { }`\n`role R<T> : T where T : INumber<T> { }`\nA role may be a value or reference type, and this may not be known at compile-time. \n\n## Emit strategy\n\nThis will need more discussion, and we prefer to separate it from language-level questions.  \n`System.Role<T>` is harder to use for T being pointer, ref struct. Also implies runtime support.  \nWe don't want a breaking change when we reach phase C and you add an interface to an existing role.  \nWe'd rather limit amount of runtime work in phase B, if possible. \n\nA typeref is preferrable to some string.  \nWe brainstormed using a modopt for encoding the underlying type in a way that would support pointers and\nref structs. Maybe something like `System.Role<modopt(pointer) void>` or `ref struct S : modopt(pointer) System.Role`.  \nBut there is a deep restriction in compiler codebase. Internal/public API expose custom modifiers as named types.  \nThis restriction stems from the published version of 335, so if we take a dependency on being able to put Types \nin a modopt and not just TypeRefs, the runtime will want to doc the spec change in their 335 augments doc.\n\nAnother option for this position (underlying type) would be to use an attribute. This would not be sprawling.   \n\n## Extension type members\n\nWe should allow `new` and warn that you should use `new` when shadowing. \nShadowing includes underlying type and inherited roles.  \n\n```\nclass U { public void M() { } }\nrole R : U { /*new*/ public void M() { } } // wins when dealing with an R\n```\n```\nclass U { public void M() { } }\nextension X : U { /*new*/ public void M() { } } // ignored in some cases, but extension is a role so rule should apply anyways\nU u;\nu.M(); // U.M (ignored X.M)\nX x;\nx.M(); // X.M\n```\n```\nclass U { }\nrole R : U { public void M() { } }\nrole R2 : U, R { /*new*/ public void M() { } } // wins when dealing with an R2\n```\n\n## Accessing various members, qualifying names\n\nWill need to spec or disallow `base.` syntax.\nCasting seems an adequate solution to access hidden members: `((R)r2).M()`.  \nWe may not need a syntax like `base(R).` which was brainstormed for some other features.\n\nWe want to ensure that both of these are possible:  \nFrom an extension, need to access a hidden thing.  \nFrom an underlying type, still need to access the extension member when extension loses.  \n\n## Conversions\n\nShould allow conversion operators. Extension conversion is useful. \nExample: from `int` to `string` (done by `StringExtension`).  \nBut we should disallow user-defined conversions from/to underlying type \nor inherited roles, because a conversion already exists.  \nConversion to interface still disallowed.  \n"
  },
  {
    "path": "meetings/working-groups/roles/roles-2023-02-15.md",
    "content": "# Roles WG 2023-02-15\n\n## Syntax for base type list\n\nIn the proposal so far, we have a single base type list, which starts with an underlying\ntype and then continues with a mix of roles and interfaces.\n\n`role R : UnderlyingType, BaseRole1, Interface1, BaseRole2, Interface2`\n\nThis feels complicated and error-prone.  \nFor example, you might not notice that you forgot to specify an underlying type\nsince interfaces are allowed as underlying types.\n\n`role R : IUnderlyingInterface, Interface1, Interface2`\n\nOptions:  \n1. Keep as-is single list (underlying type followed by base roles followed by interfaces)\n  We might make this more readable by requiring some ordering of groups (don't mix base roles\n  and interfaces). But this seems stylistic and requires some decoder ring knowledge.\n  The readability issue may be mitigated by naming conventions (interfaces have `I`).\n2. No ordering requirement for base roles and interfaces\n  Users can organize the list themselves\n3. allow optional underlying type when a base role is present, ordering of groups\n  `role R : BaseRole(s), Interface(s)`\n  An issue is that order now affects meaning:\n  `role R : BaseRole1, Interface1` vs. `role R : Interface1, BaseRole1` \n4. Keyword for underlying type \n  `view VJsonView on type : views, interfaces`\n  `view VCustomer extends type : view, interfaces`\n  `view VJsonView of type : views, interfaces`\n  This provides an advantage for partials (keyword allows making underlying type optional with less ambiguity):  \n    `partial R : UnderlyingType, Interface1`\n    `partial R : Interface2` (currently error since missing underlying type)\n  We could also deal with an optional underlying type when base role(s) is present:  \n  `view VCustomer : views, interfaces` // infer\n  `extension of type : views, interfaces` // optional extension name\n  `role of type ...` // disallowed\n\nDecision: let's go with (4)\n\n## What keyword for underlying type?\n\nHere are some keywords we considered:  \n1. `extension E of U`\n2. `extension E extends U` (too verbose)\n3. `extension E on U`\n4. `extension E for U`\n5. `extension E over U`\n6. `this E of U`\n7. `extension E is U`\n8. `extension E override U` (misleading since no virtual/inheritance)\n9. `extension E using U` (two meanings for `using` already, not intent)\n10. `extension E from U`\n\nA few keywords stand out as potential candidates:  \n`of` suggests a property of the underlying thing  \n`on` suggests something added \"on top of\"  \n`for` is more like natural/English language (we have extensions for this type)  \n\nHere's what those could look like in context:\n1. `role R of U`\n2. `view V of U`\n3. `role R on U`\n4. `view V on U`\n5. `view V for U`\n6. `extension V for U`\n7. `extension Extension<T> for T`\n\nDecision: let's go with `for`. `of` would be second choice, `on` third.\n\n## Keyword for declaration of roles\n\nWe've considered a few candiates so far, but need a firmer decision since we're working on implementation.\n\n1. `role`\n2. `view` (this unfortunately already has connotations in various fields, from databases, UI, etc, but some of those can be misleading)\n3. `shape`\n4. `alias` (ambiguity with using aliases; empty roles are better aliases)\n5. modifiers `implicit` and `explicit`: \n  - A. `explicit extension Role for U` (it's a bit long-winded but makes it clear that they are variations of same feature)\n  - B. `explicit view Role for U`, `implicit view Extension for U` \n\nDecision: let's go with 5A\n"
  },
  {
    "path": "meetings/working-groups/unsafe-evolution/unsafe-alternative-syntax.md",
    "content": "# Alternative syntax for caller-unsafe\n\nThis proposal amends and references [Unsafe evolution](https://github.com/dotnet/csharplang/blob/main/proposals/unsafe-evolution.md). Read that one first!\n\n## Summary\n\nKey differences from the [Unsafe evolution](https://github.com/dotnet/csharplang/blob/main/proposals/unsafe-evolution.md) proposal:\n\n- Mark caller-unsafe members directly with the `[RequiresUnsafe]` attribute instead of repurposing the `unsafe` keyword to generate that.\n- Keep the existing meaning of `unsafe` as is: designating a code region as an unsafe context.\n- Use the proposed opt-in mechanism only to control the enforcement against invoking caller-unsafe members outside of unsafe regions. It does not affect what `unsafe` means or whether a member can be marked caller-unsafe.\n\n```csharp\npublic static class Unsafe\n{\n    [RequiresUnsafe] // Always allowed - even in older language versions\n    [System.CLSCompliant(false)] \n    public static ref T AsRef<T>(void* source) where T : allows ref struct { ... }\n    ...\n}\nvoid M()\n{\n    int i = 1;\n    int* ptr = &i; // No longer unsafe in either proposal\n    \n    Console.WriteLine(*ptr); // Error outside of unsafe region\n    ref int intRef = Unsafe.AsRef(ptr); // Error if enforcement is opted in\n    \n    unsafe\n    {\n        Console.WriteLine(*ptr); // Allowed in unsafe region\n        ref int intRef = Unsafe.AsRef(ptr); // Allowed in unsafe region\n    }\n}\n```\n\n## Motivation\n\nThis proposal is primarily motivated by avoiding breaking changes in the language, but does provide additional benefits.\n\n### Declaration vs consumption\n\nThe existing `unsafe` feature is all about where a user is allowed to *consume* unsafe operations. Both proposals add the ability to *declare* new unsafe operations - in the form of caller-unsafe members.\n\nHowever, the original proposal repurposes the syntax of the *consumption* feature for *declaration* purposes, muddling the distinction between the two.\n\n**With this proposal**, instead, declaration gets a separate syntax. Declaration is likely much more rare than consumption, and having a dedicated keyword seems unwarranted. An attribute seems just fine, especially since that's what the original proposal compiles down to anyway.\n\n### Language breaking changes\n\nBoth proposals support users introducing *API breaking changes* (mitigated by an opt-in mechanism) by marking existing APIs caller-unsafe.\n\nThe original proposal additionally introduces two *language breaking changes*:\n\n1. **Unsafe members**: Existing uses of `unsafe` on a member are generally intended only to make the member body an unsafe context. They may be used as a more convenient shorthand for wrapping the whole member body in an `unsafe` statement. However, with the new semantics of the original proposal, an `unsafe` member is now considered caller-unsafe, and existing calls to the member will break.\n2. **Unsafe types**: Existing uses of `unsafe` on a type are intended to make the type body an unsafe context. They may be used as a more convenient shorthand for marking each member unsafe. However, with the new semantics of the original proposal, an `unsafe` type is no longer an unsafe context, and unsafe operations within the type will break.\n\nWhen the language change is in effect, it is likely to break nearly every occurrence of `unsafe` on members and types! These breaks impose a hardship on users without accruing any additional safety benefits. Users need to do significant work just to get back to an equivalent state to what they had before.\n\nWe have never attempted a breaking change on even close to that scale in C#, and would need incredibly compelling arguments to change that stance. Arguments such as \"we truly have no other viable option.\" However:\n\n**With this proposal**, the language breaking changes go away. The `unsafe` modifier continues to mean what it has always meant: introducing an unsafe context.\n\n### Time of effect\n\nWith the original proposal, all of these changes to semantics take effect together, when an opt-in is specified:\n\n- The `unsafe` modifier on a member changes its meaning to an indicator that the member is caller-unsafe.\n- The `unsafe` modifier on a type changes its meaning to a no-op.\n- Some operations such as pointer types and many pointer expressions cease being considered unsafe.\n- A call to a caller-unsafe member outside of an unsafe context becomes an error.\n\nThis all-or-nothing approach to opt-in effectively means adoption must happen in bulk. It raises the burden for someone keen to make their code more safe: They cannot get enforcement of caller-unsafe calls until they have gone through the work of mitigating the language breaking change.\n\nArguably this makes the impact of the language breaking change even worse, because it doesn't happen cleanly on a C# version boundary. In new C# versions going forward, the meaning of `unsafe` in code will not be clear in and of itself, but will depend on a separate opt-in mechanism.\n\n**With this proposal**, on the other hand:\n\n- There *is* no language breaking change: the `unsafe` modifier keeps its meaning.\n- The relaxation of previously unsafe operations can happen cleanly on a language version boundary, and doesn't need to be tied to opt-in.\n- Marking a member caller-unsafe is independent of opt-in (and even of language version). `[RequiresUnsafe]` is just an attribute.\n- Only the *enforcement* of `[RequiresUnsafe]` is guarded by an opt-in.\n\n### Opt-in granularity\n\nThe original proposal envisions an opt-in mechanism as a mitigation for the fact that *newly marking an existing member caller-unsafe is an API breaking change*. It would be harsh to mark a number of existing members caller-unsafe in a new version of .NET if there weren't also a mechanism for people to manage the break to their consuming code.\n\nWhat about *new* caller-unsafe members, though? Presumably we and others will keep adding such members in significant numbers. Why should a modern C# user be allowed to avoid enforcement when calling those? After all, they won't have existing code already calling them outside an unsafe context.\n\nIt seems like the original proposal leaves safety on the table by treating new and existing members equally. While we may initially see a lot of existing members being annotated, over time the majority would shift to newly added members.\n\n**With this proposal** the caller-unsafe marker is an attribute. As such, it *could* use attribute arguments to specify whether a caller-unsafe member should be subject to opt-in or not. For instance, existing members could be annotated with something like `[RequiresUnsafe(optional:true)]` which lets their enforcement be controlled by an opt-in flag. New caller-unsafe members would just use `[RequiresUnsafe]` which defaults to `optional:false`. Over time, after an initial transition period, this would become the common case.\n\nLibraries could also use this to \"tighten the screws\" over several releases, limiting their users' ability to evade enforcement. \n\n*Note:* Such arguments on `RequiresUnsafe` are not part of this proposal. We're merely pointing out that the proposal, unlike the original one, *allows* for such a design.\n\n### Unsafe context in caller-unsafe members\n\nIn the original proposal, annotating a member as caller-unsafe *also* makes the whole member an unsafe context.\n\nThis means that the member's author doesn't get more fine-grained control over which parts of the member body may use unsafe operations. That's unfortunate, as it increases the surface area that needs to be manually audited for safety issues.\n\n**With this proposal** the `[RequiresUnsafe]` attribute does not imply that the member is an unsafe context. The author is free to mark the boundaries that make the most sense.\n\n### Meaningless uses of unsafe\n\nThe original proposal introduces a warning for a few places where the `unsafe` modifier is allowed only for compat purposes, but no longer has an effect.\n\n**With this proposal** there is no need for such a warning, since the meaning of `unsafe` doesn't change.\n\n## Detailed design\n\n- Keep the `unsafe` keyword with the same meaning in the same places as today: In every location it simply denotes a region of code as an unsafe context.\n\n- Remove certain operations from the set of language-defined unsafe operations, exactly as in the original proposal. This takes effect unconditionally for the C# version where it is introduced.\n\n- Designate caller-unsafe members directly with the `[RequiresUnsafe]` attribute instead of repurposing the `unsafe` keyword. The attribute does *not* automatically make member bodies unsafe contexts; an explicit `unsafe` region is needed for that.\n\n- Introduce a compiler opt-in mechanism that controls whether caller-unsafe methods are prevented from being called outside of unsafe contexts. When opted-in, the assembly gets marked with `[MemorySafetyRules]` just as in the original proposal.\n\n- Consider augmenting `[RequiresUnsafe]` with arguments to distinguish new vs existing caller-unsafe members and regulate the impact of the opt-in mechanism on the members' allowed use.\n\n- Other aspects remain unchanged from the original proposal, e.g.:\n    - Placement of `[RequiresUnsafe]` needs to obey the same restrictions as the original proposal lays out for `unsafe` on members.\n    - Delegates and lambdas must obey equivalent rules to the original proposal.\n    - Members marked `extern` are implicitly caller-unsafe.\n\nThere is an open question around \"compat mode\" below.\n\n## Drawbacks\n\n- **No dedicated syntax:** Unlike the original proposal, this version falls back to attributes to express the intended semantics. It wouldn't be the only place in the language where member annotations are by attribute, but maybe there are arguments why this situation is more common or important and deserves a keyword.\n- **Lack of \"uniformity\":** Arguably, using `unsafe` both to *produce* (on members) and *consume* (on blocks) unsafe operations is a simpler mental model. It's similar to how `Obsolete` members can call other `Obsolete` members.\n\n## Alternatives\n\n- **New keyword:** A dedicated keyword (or keyword combination) different from `unsafe` could be used instead of an attribute. This would still address many of the problems in the original proposal, in particular the language breaking changes.\n\n- **Different attribute name:** This proposal uses `[RequiresUnsafe]` because it is descriptive of the meaning and is what the original proposal compiles down to. But it's possible that another name might be better.\n\n## Open questions\n    \n### Compat mode\n\nThe original proposal suggests a \"compat mode\": When a compilation is \"opted-in\" to the new semantics but depends on an assembly that is not, a heuristic is applied to members of that assembly to decide whether they should be considered caller-unsafe. The heuristic involves the presence of pointer or function pointer types in the member's signature.\n\nThis allows some freedom in the order that compilations are opted-in, while preserving a measure of safety when consuming assemblies that are not.\n\nThe original proposal uses the presence of `[MemorySafetyRules]` in an assembly to determine whether it was annotated, which has some validity because if it didn't have the attribute it *couldn't* have been annotated. Essentially there's an assumption that when an assembly opts in it takes responsibility for appropriately annotating its members.\n\nIn this alternative proposal, is it still reasonable to use `[MemorySafetyRules]` as the only indication that members have been properly annotated and compat mode should not be used? After all they could have been annotated with `[RequiresUnsafe]` even *without* the assembly having been opted in. Perhaps any assembly with at least one `[RequiresUnsafe]` should also be considered annotated?\n\nThis seems a topic for further discussion."
  },
  {
    "path": "proposals/README.md",
    "content": "# C# Language Proposals\n\nLanguage proposals are living documents describing the current thinking about a given language feature.\n\nProposals can be either *active*, *inactive*, *rejected* or *done*. *Active* proposals are stored directly in the proposals folder, *inactive* and *rejected* proposals are stored in the [inactive](inactive) and [rejected](rejected) subfolders, and *done* proposals are archived in a folder corresponding to the language version they are part of.\n\n## Lifetime of a proposal\n\nA proposal starts its life when the language design team decides that it might make a good addition to the language some day. Typically it will start out being *active*, but if we want to capture an idea without wanting to work on it right now, a proposal can also start out in the *inactive* subfolder. Proposals may even start out directly in the *rejected* state, if we want to make a record of something we don't intend to do. For instance, if a popular and recurring request is not possible to implement, we can capture that as a rejected proposal.\n\nThe proposal may start out as an idea in a [discussion issue](https://github.com/dotnet/csharplang/labels/Discussion), or it may come from discussions in the Language Design Meeting, or arrive from many other fronts. The main thing is that the design team feels that it should be done, and that there's someone who is willing to write it up. Typically a member of the Language Design Team will assign themselves as a champion for the feature, tracked by a [Champion issue](https://github.com/dotnet/csharplang/labels/Proposal%20champion). The champion is responsible for moving the proposal through the design process.\n\nA proposal is *active* if it is moving forward through design and implementation toward an upcoming release. Once it is completely *done*, i.e. an implementation has been merged into a release and the feature has been specified, it is moved into a subdirectory corresponding to its release.\n\nIf a feature turns out not to be likely to make it into the language at all, e.g. because it proves unfeasible, does not seem to add enough value or just isn't right for the language, it will be [rejected](rejected). If a feature has reasonable promise but is not currently being prioritized to work on, it may be declared [inactive](inactive) to avoid cluttering the main folder. It is perfectly fine for work to happen on inactive or rejected proposals, and for them to be resurrected later. The categories are there to reflect current design intent.\n\n## Nature of a proposal\n\nA proposal should follow the [proposal template](proposal-template.md). A good proposal should:\n\n- Fit with the general spirit and aesthetic of the language.\n- Not introduce subtly alternate syntax for existing features.\n- Add a lot of value for a clear set of users.\n- Not add significantly to the complexity of the language, especially for new users.  \n\n## Discussion of proposals\n\nFeedback and discussion happens in [discussion issues](https://github.com/dotnet/csharplang/labels/Discussion). When a new proposal is added to the proposals folder, it should be announced in a discussion issue by the champion or proposal author. \n\n \n"
  },
  {
    "path": "proposals/anonymous-using-declarations.md",
    "content": "# Anonymous using declarations\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/8606>\n\n## Summary\n\nPermit `using` declarations whose variable is anonymous:\n\n```cs\nvoid M()\n{\n    using _ = GetDisposable();\n}\n```\n\n## Motivation\n\nThis statement form adds the final corner to the following square:\n\n|                  | **New variable name**       | **No new variable name** |\n|------------------|-----------------------------|--------------------------|\n| **New scope**    | `using (var name = expr) {` | `using (expr) {`         |\n| **No new scope** | `using var name = expr;`    | `using _ = expr;` 🆕      |\n\nIt has been wildly popular to remove or avoid nesting by preferring the bottom form inside the \"New variable\" column to the top form. However, there has been no corresponding opportunity in the other column. The absence of this corner has been painfully felt. When a language user doesn't want the extra nesting, but also has no use for the variable, this results in workarounds such as creating variables named `_`, `_1`, `_2`, and so on.\n\n```cs\nusing var _1 = factory.Lease(out var widget);\nusing var _2 = widget.BeginScope();\n```\n\nAnother place where this request comes up is when using ConfigureAwait for `await using`. The ConfigureAwait extension method on IAsyncDisposable returns a wrapper which is only good for disposal, and useless to place in a new variable. Yet users must place it in a new variable, or else they must increase nesting just because they're using ConfigureAwait.\n\n```cs\nvar stream = await client.GetStreamAsync(...).ConfigureAwait(false);\nawait using var _3 = stream.ConfigureAwait(false);\n```\n\nBy using throwaway variable names as seen in community discussions and the Roslyn codebase itself ([one example](https://github.com/dotnet/roslyn/blob/6b2b0e4c7c3e0470c44ad22653996231a013d8e1/src/Workspaces/Remote/Core/AbstractAssetProviderExtensions.cs#L54-L60)), language users are already attempting to use the language as though this feature existed.\n\n## Detailed design\n\n*using_statement* syntax is expanded to include a new *using_discard_statement* syntax, `'await'? 'using' '_' '=' expression ';'` (see [Specification](#specification)).\n\nThe lifetime of the resources acquired in a *using_discard_statement*, and the allowed locations for a *using_discard_statement*, are defined in the same way as for C# 8's [`using_declaration` syntax](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-8.0/using.md#using-declaration).\n\nThis proposal does not create support for multiple discards in a single using statement:\n\n```cs\n❌ NOT supported:\nusing _ = expr1, _ = expr2;\nusing _ = expr1, expr2;\n```\n\n*using_declaration* syntax is not expanded or unified. *using_declaration* is based on *implicitly_typed_local_variable_declaration* and *explicitly_typed_local_variable_declaration* which do not include *simple discards*. A *simple discard* is a special case of a *declaration_expression* ([§12.17](https://github.com/dotnet/csharpstandard/blob/draft-v9/standard/expressions.md#1217-declaration-expressions)). (Specification work for *using_declaration* is [ongoing](https://github.com/dotnet/csharpstandard/pull/672/files#diff-20796c21eeccfd2c773f2969d23440cbc04e7439f4777729aad5d602477c232fR2057) at the time of writing.)\n\n## Specification\n\n[§13.14 The using statement](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md#1314-the-using-statement) is updated as follows.\n\n```diff\n using_statement\n     : 'await'? 'using' '(' resource_acquisition ')' embedded_statement\n+    | using_discard_statement\n     ;\n\n resource_acquisition\n     : non_ref_local_variable_declaration\n     | expression\n     ;\n\n non_ref_local_variable_declaration\n     : implicitly_typed_local_variable_declaration\n     | explicitly_typed_local_variable_declaration\n     ;\n\n+using_discard_statement\n+    : 'await'? 'using' '_' '=' expression ';'\n+    ;\n```\n\nAdditions in **bold**:\n\n> If the form of *resource_acquisition* is *local_variable_declaration* then the type of the *local_variable_declaration* shall be either `dynamic` or a resource type. If the form of *resource_acquisition* is *expression*, **or the form of *using_statement* is *using_discard_statement* with its constituent *expression*,** then this expression shall have a resource type. If `await` is present, the resource type shall implement `System.IAsyncDisposable`.  A `ref struct` type cannot be the resource type for a `using` statement with the `await` modifier.\n\nRemovals in ~~strikeout~~, additions in **bold**:\n\n> ~~A `using` statement of the form:~~ **`using` statements of the other two forms:**\n>\n> ```csharp\n> using («expression») «statement»\n> ```\n>\n> **and:**\n>\n> ```csharp\n> using _ = «expression»;\n> ```\n>\n> ~~has~~ **have** the same possible formulations.\n\nA new subsection is added:\n\n> ### Using discard statements\n>\n> A *using discard statement* has the same semantics as, and can be rewritten as, the corresponding parenthesized form of the using statement, as follows:\n>\n> ```csharp\n> using _ = «expression»;\n> // statements\n> ```\n>\n> is semantically equivalent to\n>\n> ```csharp\n> using («expression»)\n> {\n>     // statements\n> }\n> ```\n>\n> and\n>\n> ```csharp\n> await using _ = «expression»;\n> // statements\n> ```\n>\n> is semantically equivalent to\n>\n> ```csharp\n> await using («expression»)\n> {\n>     // statements\n> }\n> ```\n>\n> A using discard statement shall not appear directly inside a `case` label, but, instead, may be within a block inside a `case` label.\n\n## Alternatives\n\n`using expr;` would be a consistent extrapolation from the existing constructs, where you simply remove the curly braces and parentheses and add a semicolon. However, this statement form would conflict with using directives, particularly in top-level statements.\n\n`using _ = expr;` *also* conflicts with using alias directives, but `_` has a strong sense of \"discard\" and is discouraged as an identifier name. (There is an [open question](#conflict-with-using-aliases-named-_-in-top-level-statements) on this point.)\n\n## Open questions\n\n### Simpler form versus standing out\n\nIn most cases, the expression in a using statement will not be of the form `A.B`. It is more common to call a constructor or method. In these common scenarios, there would be very little visual confusion:\n\n```cs\nusing someLock.BeginScope();\nusing new SomeResource(...);\n```\n\nThe compiler could disambiguate by checking whether the expression binds to a namespace or type versus to some other kind of expression. The human reader would only be confused if this feature was used in a misleading way. Even when the underlying syntax is the same, as in the following deliberately-contrived example, it is obvious from context that the first `using` below involves a namespace or type, and that the second `using` does not:\n\n```cs\nusing System.ComponentModel;\n\nvar result = TryXyz();\nusing result.Value;\n```\n\nIf this syntax was available, users could *also* write `using _ = expr;` as well in scenarios where they felt it improved clarity. It would work the same way as `using (_ = expr) {` does today. This option optimizes for the user's flexibility in expressiveness. Community feedback is already beginning to show a desire for this flexibility.\n\nShall we proceed to design the simpler form, allowing `using new SomeResource();` and getting `using _ = new SomeResource();` as a corollary, or shall we design the form that stands out visually with `_ =` as the only form?\n\n### Disallowed top-level expressions\n\nThis open question assumes the `using expr;` syntax.\n\nIf the top-level expression is a parenthesized expression, this syntax would conflict with `using (expr);` which compiles successfully with a warning about an empty statement. Shall we disallow the expression to be a parenthesized expression?\n\nIf the top-level expression is a simple assignment expression, this syntax would conflict in top-level statements with using alias directives: `using existingVariable = expr;`. Shall we disallow the expression to be a simple assignment expression, or disambiguate based on whether expr is a type or namespace?\n\n### Conflict with using aliases named `_` in top-level statements\n\nThis open question assumes the `using _ = expr;` syntax.\n\nA legal program may exist as follows:\n\n```cs\nusing _ = SomeNamespace;\n\nvar xyz = new _.SomeType();\n```\n\nDisallowing the use of `_` as an identifier has been previously discussed. Is there appetite for a tiny subset of this breaking change, disallowing `_` as an identifier *only* for using aliases and *only* in files with top-level statements?\n\nOther alternatives:\n\n- Disallow usings with discards in top-level statements\n- Only permit usings with discards in top-level statements when nested inside a block statement\n- Only permit usings with discards in top-level statements when following some other top-level statement\n- Always allow both forms, and prefer the existing meaning if the expression binds to a namespace or type, and prefer the new meaning if the expression binds to a value.\n"
  },
  {
    "path": "proposals/async-main-update.md",
    "content": "# Async main codegen update\n\n## Summary\n\nWe update the codegen for `async Task Main` to allow the compiler to use a separate helper from the runtime when present.\n\n## Motivation\n\nIn some scenarios, the runtime needs to be able to hook the real `Main` method, not just the `void` or `int` returning method that is generated to\nwrap the user-written `async Task` method. To facilitate this, we allow codegen to use a different method to call the real user-written `Main` method.\n\n## Detailed Design\n\nWe update section [§7.1](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/basic-concepts.md#71-application-startup) of the spec as\nfollows:\n\n```diff\n- Otherwise, the synthesized entry point waits for the returned task to complete, calling `GetAwaiter().GetResult()` on the task, using either the parameterless instance method or the extension method described by [§C.3](standard-library.md#c3-standard-library-types-not-defined-in-isoiec-23271). If the task fails, `GetResult()` will throw an exception, and this exception is propagated by the synthesized method.\n+ Otherwise, the synthesized entry point waits for the returned task to complete, either passing the task to `System.Runtime.CompilerServices.AsyncHelpers.HandleAsyncEntryPoint` (if it exists) or calling `GetAwaiter().GetResult()` on the task, using either the parameterless instance method or the extension method described by [§C.3](standard-library.md#c3-standard-library-types-not-defined-in-isoiec-23271). If the task fails, the calling method form will throw an exception, and this exception is propagated by the synthesized method.\n```\n\nThe compiler will look for the following APIs from the core libraries. We do not look at implementations defined outside the core library:\n\n```cs\nnamespace System.Runtime.CompilerServices;\n\npublic class AsyncHelpers\n{\n    public static void HandleAsyncEntryPoint(System.Threading.Tasks.Task task);\n    public static int HandleAsyncEntryPoint(System.Threading.Tasks.Task<int> task);\n}\n```\n\nWhen present the resulting transformation looks like this:\n\n```cs\n// Original code\npublic class C\n{\n    public static async Task Main()\n    {\n        await System.Threading.Tasks.Task.Yield();\n        Console.WriteLine(\"Hello world\");\n    }\n}\n\n// Lowered pseudocode, not including async state machine if present\npublic class C\n{\n    public static void $<Main>()\n    {\n        System.Runtime.CompilerServices.AsyncHelpers.HandleAsyncEntryPoint(Main());\n    }\n\n    public static async Task Main()\n    {\n        await System.Threading.Tasks.Task.Yield();\n        Console.WriteLine(\"Hello world\");\n    }\n}\n```\n\nSee also the approved API discussion in https://github.com/dotnet/runtime/issues/121046.\n"
  },
  {
    "path": "proposals/block-bodied-switch-expression-arms.md",
    "content": "# Block-bodied switch expression arms\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/8610>\n\n## Summary\n[summary]: #summary\n\nThis proposal is an enhancement to the new switch expressions added in C# 8.0: allowing multiple statements in a switch expression arm. We permit braces after the arrow, and use `break value;` to return a value from the switch expression arm.\n\n## Motivation\n[motivation]: #motivation\n\nThis addresses a common complaint we've heard since the release of switch expressions: users would like to execute multiple things in a switch-expression arm before returning a value. We knew that this would be a top request after initial release, and this is a proposal to address that. This is not a fully-featured proposal to replace [`sequence expressions`](https://github.com/dotnet/csharplang/issues/377). Rather, it is constrained to just address the complaints around switch expressions specifically. It could serve as a prototype for adding sequence expressions to the language at a later date in a similar manner, but isn't intended to support or replace them.\n\n## Detailed design\n[design]: #detailed-design\n\nWe allow users to put brackets after the arrow in a switch expression, instead of a single statement. These brackets contain a standard statement list, and the user must use a `break` statement to \"return\" a value from the block. The end of the block must not be reachable, as in a non-void returning method body. In other words, control is not permitted to flow off the end of this block. Any switch arm can choose to either have a block body, or a single expression body as currently. As an example:\n\n```cs\nvoid M(List<object> myObjects)\n{\n    var stringified = myObjects switch {\n        List<string> strings => string.Join(strings, \",\"),\n        List<MyType> others => {\n            string result = string.Empty;\n            foreach (var other in others)\n            {\n                if (other.IsFaulted) return;\n                else if (other.IsLastItem) break; // This breaks the foreach, not the switch\n\n                result += other.ToString();\n            }\n\n            break result;\n        },\n        _ => {\n            var message = $\"Unexpected type {myObjects.GetType()}\";\n            Logger.Error(message);\n            throw new InvalidOperationException(message);\n        }\n    };\n\n    Console.WriteLine(stringified);\n}\n```\n\nWe make the following changes to the  grammar:\n\n```antlr\nswitch_expression_arm\n    : pattern case_guard? '=>' expression\n    | pattern case_guard? '=>' block\n    ;\n\nbreak_statement\n    : 'break' expression? ';'\n    ;\n```\n\nIt is an error for the endpoint of a switch expression arm's block to be reachable. `break` with an expression is only allowed when the nearest enclosing `switch`, `while`, `do`, `for`, or `foreach` statement is a block-bodied switch expression arm. Additionally, when the nearest enclosing `switch`, `while`, `do`, `for`, or `foreach` statement is a block-bodied switch expression arm, an expressionless `break` is a compile-time error. When a pattern and case guard evaluate to true, the block is executed with control entering at the first statement of the block. The type of the switch expression is determined with the same algorithm as it does today, except that, for every block, all expressions used in a `break expression;` statement are used in determining the _best common type_ of the switch. As an example:\n\n```cs\nbool b = ...;\nvar o = ...;\n_ = o switch {\n    1 => (byte)1,\n    2 => {\n        if (b) break (short)2;\n        else break 3;\n    }\n    _ => 4L;\n};\n```\n\nThe arms contribute `byte`, `short`, `int`, and `long` as possible types, and the best common type algorithm will choose `long` as the resulting type of the switch expression.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nAs with any proposals, we will be complicating the language further by doing these proposals. With this proposal, we will effectively lock ourselves into a design for sequence expressions (should we ever decide to do them), or be left with an ugly wart on the language where we have two different syntax for similar end results.\n\n## Alternatives\n[alternatives]: #alternatives\n\nAn alternative is the more general-purpose sequence expressions proposal, https://github.com/dotnet/csharplang/issues/377. This (as currently proposed) would enable a more restrictive, but also more widely usable, feature that could be applied to solve the problems this proposal is addressing. Even if we don't do general purpose sequence expressions at the same time as this proposal, doing this form of block-bodied switch expressions would essentially serve as a prototype for how we'd do sequence expressions in the future (if we decide to do them at all), so we likely need to design ahead and ensure that we'd either be ok with this syntax in a general-purpose scenario, or that we're ok with rejecting general purpose sequence expressions as a whole.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n* Should we allow labels/gotos in the body? We need to make sure that any branches out of block bodies clean up the stack appropriately and that labels inside the body are scoped appropriately.\n\n* In a similar vein, should we allow return statements in the block body? The example shown above has these, but there might be unresolved questions around stack spilling, and this will be the first time we would introduce the ability to return from _inside_ an expression.\n"
  },
  {
    "path": "proposals/breaking-change-warnings.md",
    "content": "# Breaking change warnings\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/8865>\n\n## Summary\n[summary]: #summary\n\nAllow very limited breaking changes in C# when this enables significantly simpler feature designs that are easier to learn, understand and use. \n\nRetroactively add warnings in previous language versions to help identify and fix user code that would be vulnerable to such breaks upon a language version upgrade.\n\n## Motivation\n[motivation]: #motivation\n\nWe currently restrict new C# language features from causing any breaks (errors or behavior changes) to existing code, occasionally leading to unnatural and unintuitive design choices that make the language harder than necessary to learn and reason about.\n\nExamples include discards `_` (sometimes an identifier), `var` (sometimes a type name) and the upcoming `field` access in auto-properties.\n\nBreaking changes _should_ be rare and have limited impact, but sometimes they are the right thing to do. This proposal creates a mechanism by which the effects of such breaks are mitigated for existing code.  \n\n## Detailed design\n[design]: #detailed-design\n\nWhen a new language feature is added in C# version `n` that may cause existing code to error or work differently, such code is detected in C# versions `n - 1` and lower, and a warning is yielded with a suggestion for how to fortify the code against the future break.\n\nIt is customary that newer compilers are used to compile older versions of C#. The compiler that supports C# version `n` will implement these warnings when used to compiler older language versions.\n\n### Example: field access in auto-properties\n\nAs an example, let's say we introduce [field access in auto-properties](https://github.com/dotnet/csharplang/blob/e222e8b490b5c231430260c3fd3f8df8bcab9a3c/proposals/semi-auto-properties.md) in C# 13, with a design that introduces a new `field` parameter in scope within property accessors. This new `field` parameter would shadow access to any field etc. called `field` in existing property accessors, potentially altering its meaning. We would accompany that feature with a warning in C# 12 and lower for any code that uses the identifier `field` within a property accessor:\n\n``` c#\npublic class Entity\n{\n    string field;\n    public string Field\n    {\n        get { return field; }         // Warning in C# 12 and below\n        set { field = value.Trim(); } // Warning in C# 12 and below\n    }\n    ...\n}\n```\n\nIn C# 13 the warning would go away, and `field` in the accessors would start referencing the underlying generated field for `Field`, which would now be considered an auto-property. \n\n## Drawbacks\n[drawbacks]: #drawbacks\n\n### New warnings\n\nA small number of C# users will see new warnings on existing code after directly or indirectly upgrading their compiler. These warnings point out important problems with their code, should they want to move to a newer language version. \n\nHopefully users will find these warnings useful, and will prefer this early warning to finding themselves broken at a later stage. Users that do not find them useful - e.g. because they never plan to upgrade - can simply turn them off.\n\nTooling might embrace more sophisticated models here - \"turn off temporarily\", \"fix automatically\", etc. - that further mitigate any inconvenience of the experience, but that is outside of the scope of this proposal, and can be developed independently over time.\n\n### Missed warnings\n\nUpgrading to a new compiler must happen *before* upgrading to the new language version that the compiler supports, so technically there will always be a window of time to observe the warnings. \n\nHowever, users might upgrade both without a single compile in between, or they may have turned off the warnings and forgot to turn them on again.\n\nIt seems tooling can be helpful in avoiding situations where breaking change warnings are missed. For instance it could look for explicit `#pragma warning disable` directives for breaking change warnings \"from the past\", or try to \"check one last time\" on explicit language version upgrade gestures in the tool. Such features are outside of the scope of this proposal, and can be developed independently over time.\n\n## Alternatives\n[alternatives]: #alternatives\n\n### Don't break\n\nAn alternative is to stick to the current policy and continue to live with the feature contortions that result from avoiding breaking changes at all cost.\n\n### Break but don't mitigate\n\nAt the other end of the scale, we could allow breaking changes to the same limited level as proposed here, but simply not provide any language-level mechanism around it. Wherever code changes meaning, people will have to use docs and testing to find, debug and understand where things went wrong. Breaks may not yield errors, and differences in behavior may be subtle, so this will likely be more disruptive to users.\n\n### Upgrading tool\n\nThis is a variant of \"break don't mitigate\" where the tools people use to write C# code would direct them through a dedicated upgrade experience, which would do breaking change checking as one of its steps towards a new language version.\n\nThis seems like a \"boil the ocean\" approach, since everyone has to take that route, even though the vast majority of users won't be affected by the breaking change. Also, it suffers from the risk that people bypass the upgrade tool (e.g. by manually changing the version in their project file) and miss out on the checking.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\nFor every breaking change, there will be specific design considerations concerning the associated warnings: Which patterns in existing code will trigger them? Which fixes will they recommend?\n\n## Design meetings\n\n- [Mar 8, 2023](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-03-08.md#limited-breaking-changes-in-c): Based on discussion [#7033](https://github.com/dotnet/csharplang/discussions/7033) the LDM decided to continue to pursue the topic.\n"
  },
  {
    "path": "proposals/case-declarations.md",
    "content": "# Case Declarations\n\n## Summary\n\nA case declaration is a shorthand syntax for declaring a nested case of a closed type.\nIt infers much of what it is from context. \n\n```csharp\npublic closed record GateState\n{\n    case Closed;\n    case Locked;\n    case Open(float Percent);\n}\n```\n\nWhen used within a record declaration, it is the equivalent of writing:\n\n```csharp\npublic closed record GateState\n{\n    public sealed record Closed : GateState;\n    public sealed record Locked : GateState;\n    public sealed record Open(float Percent) : GateState;\n}\n```\n\n## Motivation\nTo provide a concise way to specify simple type cases of a closed type that can be transitioned into more complex declarations without falling off a syntax cliff.\n\n## Specification\n\n### Semantics\n- A case declaration can only be specified in the body of a closed class, record or union. \n\n- The existence of a case declaration is independent of other declarations in the containing class.\n\n### Declaration\nA case declaration includes the `case` keyword followed by a type declaration, similar to a class or record, without the keywords, modifiers or base type.\n\n```csharp\ncase Open(float Percent);\n```\n\n#### Grammar\nTBD\n\n#### Attributes\nA case declaration may declare custom attributes.\n\n```csharp\n[Attribute] case Open(float Percent);\n```\n\n#### Modifiers\nThe case declaration may not specify any modifiers. The class or record is always `public` and `sealed`. \n\n#### Partial Case Classes\nTBD. Probably not, since you cannot specify partial modifier.\n\n#### Type Parameters\nThe case declaration may not specify type parameters, as that would make exhaustiveness impossible, but it may refer to any type parameter declared by the containing class.\n\n#### Base Type\nA case declaration may not declare a base type. For a containing class or record, the case types base type is always the containing class.\n\n#### Interfaces\nA case declaration may declare interfaces.\n\n```csharp\ncase Open(float percent) : ISomeInterface { ... }\n```\n\n#### Body\nA case declaration may declare a body with member declarations.\n\n```csharp\ncase Open(float percent) : { pubic void SomeMethod() {...} }\n```\n\n----\n## Optional Features\n\nOptional features are suggestions for additional work that could be done to enhance the core proposal.\n\n### Singleton Case Classes\nCase declarations that are records without properties include a static property that is a singleton value for the class.\n\nFor example,\n```csharp\ncase Closed;\n```\nbecomes:\n```csharp\npublic sealed record Closed : GateState { \n    public static Closed Instance => field ??= new Closed();\n}\n```\n\nReferences to singleton case values can be reduced to referencing the static property.\n\n```csharp\nGateState state = GateState.Closed.Instance;\n```\n\nWith the addition of a static value operator feature, not specified here, the case declaration type can be converted to the singleton value when referenced in non-type contexts that would shorten this to:\n\n```csharp\nGateState state = GateState.Closed;\n```\n\nWith the addition of a target typed member lookup feature, not specified here, this would shorted further to:\n```csharp\nGateState state = Closed;\n```\n"
  },
  {
    "path": "proposals/closed-enums.md",
    "content": "# Closed Enums\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9011  \n\n## Summary\n\nAllow an enum type to be declared closed: \n\n``` c#\npublic closed enum Color\n{\n    Red,\n    Green,\n    Blue\n}\n```\n\nThis prevents creation of enum values other than the specified members.\n\nA consuming switch expression that covers all its specified members can therefore be concluded to \"exhaust\" the closed enum - it does not need to provide a default case to avoid warnings:\n\n``` c#\nColor color = ...;\n\nstring description = color switch\n{\n    Red => \"red\",\n    Green => \"green\",\n    Blue => \"blue\"\n    // No warning about missing cases\n};\n```\n\n## Motivation\n\nMany enum types are not intended to take on values beyond the declared members, but the language provides no way to express that intent, let alone guard against it happening. For consumers of the type this means that no set of enum values short of the full range of the underlying integral type will be considered to \"exhaust\" the enum type, and a switch expression needs to include a catch-all case to avoid warnings.\n\nClosed enums provide a way to indicate that the set of enum mebers is complete, and allow consuming code to rely on that for exhaustiveness in switch expressions.\n\n## Detailed design\n\n### Syntax\n\nAllow `closed` as a modifier on enum types. \n\n### Enforcement\n\nThe following restrictions apply to closed enum types compared to other enum types:\n\n- A closed enum must declare a member corresponding to the integral value `0`.\n- Explicit enumeration conversions are not allowed _to_ a closed enum type, except from a constant whose value corresponds to a declared member.\n- Operators that return a closed enum type are only allowed over constant operands, and it is an error for them to produce a value that is not a declared member.\n\n``` c#\nColor c = 0;         // Ok, all closed enums hve a member corresponding to the value `0`\nc = (Color)1;        // Ok, the constant `1` corresponds to the member `Green`\nc = (Color)10;       // Error, there is no member corresponding to the constant `10`\nc = (Color)myInt;    // Error, `myInt` is not constant\n_ = c == Color.Blue; // Ok, `==` does not return a closed enum\n_ = Color.Red + 1;   // Ok, operands are constant and result corresponds to the member `Green`\n_ = c + 1;           // Error, operand `c` is not constant\n```\n\n### Exhaustiveness in switches\n\nA `switch` expression that handles all of the members of a closed enum type will be considered to have exhausted that enum type. That means that some non-exhaustiveness warnings will no longer be given:\n\n``` c#\nColor c = ...;\n_ = c switch\n{\n    Red => ...,\n    Green => ...,\n    Blue => ...\n    // No warning about non-exhaustive switch\n};\n```\n\nOn the other hand this also means that it can be an error for the closed enum type to occur as a case after all its members:\n\n``` c#\nColor c = ...;\n_ = c switch\n{\n    Red => ...,\n    Green => ...,\n    Blue => ...,\n    Color => ... // Error, case cannot be reached\n};\n```\n\n### Lowering\n\nClosed enums are generated with a `Closed` attribute, to allow them to be recognized by a consuming compiler.\n\n## Drawbacks\n\nIt can be a breaking change to add a `closed` modifier to an existing enum, or to add an additional member to an existing closed enum. Before publishing a closed enum type, the author needs to consider the long term contract it implies with its consumers.\n\n## Alternatives\n\n- Instead of a new `closed` modifier, a closed enum could be designated with a `[Closed]` attribute.\n\n## Open questions\n\n- Can closed enums be generated into IL in a way that prevents other languages and compilers from allowing unintended operations on them even if they do not implement the feature?\n- Should closed `[Flags]` enums be supported? If so, they should allow the binary logical (bitwise) operators `&`, `|` and `^`.\n"
  },
  {
    "path": "proposals/closed-hierarchies.md",
    "content": "# Closed Hierarchies\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9499  \n\n## Summary\n\nAllow a class to be declared `closed`. This prevents directly derived classes from being declared in a different assembly:\n\n``` c#\n// Assembly 1\npublic closed record class GateState;\npublic record class Closed : GateState;\npublic record class Open(float Percent) : GateState;\n\n// Assembly 2\npublic record class Locked : GateState; // ERROR - 'GateState' is a closed class\n```\n\nSince all derived classes are declared in the closed class' assembly, a consuming `switch` expression that covers all of them can be concluded to \"exhaust\" the closed class - it does not need to provide a default case to avoid warnings.\n\n``` c#\n// Assembly 3\nGateState state = ...;\nstring description = state switch\n{\n    Closed => \"closed\",\n    Open(var percent) => $\"{percent}% open\"\n    // No warning about missing cases\n}; \n```\n\n## Motivation\n\nMany class types are not intended to be extended by anyone but their authors, but the language provides no way to express that intent, let alone guard against it happening. For consumers of the class this means that no set of derived classes will be considered to \"exhaust\" the base class, and a switch expression needs to include a catch-all case to avoid warnings.\n\nClosed classes provide a way to indicate that a set of derived classes is complete, and allow consuming code to rely on that for exhaustiveness in switch expressions.\n\n## Detailed design\n\n### Syntax\n\nAllow `closed` as a modifier on classes. A `closed` class is implicitly abstract whether or not the `abstract` modifier is specified. Thus, it cannot also have a `sealed` or `static` modifier. \n\nA class deriving from a closed class is *not* itself closed unless explicitly declared to be.\n\n### Same-assembly restriction\n\nIf a class in one assembly is declared `closed` then it is an error to directly derive from it in another assembly:\n\n``` c#\n// Assembly 1\npublic closed class CC { ... } \npublic class CO : CC { ... }     // Ok, same assembly\n\n// Assembly 2\npublic class C1 : CC { ... }     // Error, 'CC' is closed and in a different assembly\npublic class C2 : CO { ... }     // Ok, 'CO' is not closed\n```\n\n### Type parameter restriction\n\nIf a generic class directly derives from a closed class, then all of its type parameters must be used in the base class specification:\n\n```csharp\nclosed class C<T> { ... }\nclass D1<U> : C<U> { ... }   // Ok, 'U' is used in base class\nclass D2<V> : C<V[]> { ... } // Ok, 'V' is used in base class\nclass D3<W> : C<int> { ... } // Error, 'W' is not used in base class\n```\n\nThis rule is to ensure that there is a single generic instantiation of the derived type that \"exhausts\" a given generic instantiation of the closed base type.\n\n*Note:* This rule may not be sufficient if we allow closed interfaces at some point, because a) classes can implement multiple generic instantiations of the same interface, and b) interface type parameters can be co- or contravariant. At such point we'd need to refine the rule to continue to ensure that there's only ever one generic instantiation of a given derived type per generic instantiation of a closed base type.\n\n### Exhaustiveness in switches\n\nA `switch` expression that handles all of the direct descendants of a closed class will be considered to have exhausted that class. That means that some non-exhaustiveness warnings will no longer be given:\n\n``` c#\nCC cc = ...;\n_ = cc switch\n{\n    CO co => ...,\n    // No warning about non-exhaustive switch\n};\n```\n\nOn the other hand this also means that it can be an error for the closed base class to occur as a case after all its direct descendants:\n\n``` c#\n_ = cc switch\n{\n    CO co => ...,\n    CC cc => ..., // Error, case cannot be reached\n};\n```\n\n*Note:* There may not exist valid derived classes for certain generic instantiations of a closed base class. An exhaustive switch only needs to specify cases for derived types that are actually possible. \n\nFor example:\n\n```csharp\nclosed class C<T> { ... }\nclass D1<U> : C<U> { ... }\nclass D2<V> : C<V[]> { ... }\n```\n\nFor `C<string>`, for instance, there is no corresponding instantiation of `D2<...>`, and no case for `D2<...>` needs to be given in a switch:\n\n```csharp\nC<string> cs = ...;\n_ = cs switch\n{\n    D1<string> d1 => ...,\n    // No need for a 'D2<...>' case - no instantiation corresponds to 'C<string>'\n}\n```\n\n### Lowering\n\nClosed classes are generated with a `Closed` attribute, to allow them to be recognized by a consuming compiler.\n\n## Drawbacks\n\n- It can be a breaking change to add a `closed` modifier to an existing class, or to add an additional derived class from a closed class. Before publishing a closed class, the author needs to consider the long term contract it implies with its consumers.\n- Unless we find a way to prevent it, \"unauthorized\" derived classes may be allowed by unwitting other compilers, leading to the risk that the set of cases is not in fact closed at runtime.\n\n## Alternatives\n\n- Instead of a new `closed` modifier, a closed class could be designated with a `[Closed]` attribute.\n- The scope of where descendants are allowed could be narrowed further to a file (although that would not have a lot of precedent in C#) or to inside the body of the closed class as nested classes.\n- The closed set of allowed descendants could be given as a list instead of implied by where declarations occur. This would allow inclusion of classes in other assemblies.\n\n## Optional features\n\n- Interfaces could also be allowed to be closed. The rules would be very similar.\n\n## Open questions\n\n### ClosedAttribute\n\nWe propose using the following attribute to denote that a class is closed in metadata:\n\n```cs\nnamespace System.Runtime.CompilerServices\n{\n    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]\n    public sealed class ClosedAttribute : Attribute { }\n}\n```\n\n### Blocking subtyping from other languages/compilers\n\nCan closed classes be generated into IL in a way that prevents other languages and compilers from deriving from them even if they do not implement the feature?\n\nWe propose accomplishing this by adding `[CompilerFeatureRequired(\"ClosedClasses\")]` to all constructors of closed classes. Since constructors of abstract types can generally only be used in a constructor initializer, this seems to effectively prevent languages which don't understand the feature, from allowing user to declare a subclass of a closed class.\n\n```cs\n// Authoring assembly, built with .NET 10 SDK\nclosed class C1\n{\n    public C1() { }\n    public C1(int param) { }\n}\n\n// Consuming assembly, built with .NET 8 SDK\nclass C2 : C1\n{\n    public C2() { } // error: 'C1.C1()' requires compiler feature \"ClosedClasses\"\n    public C2() : base(42) { } // error: 'C1.C1(int)' requires compiler feature \"ClosedClasses\"\n}\n```\n\nMetadata \"view\" of `C1`:\n```cs\n[Closed]\nclass C1\n{\n    [CompilerFeatureRequired(\"ClosedClasses\")]\n    public C1() { }\n    [CompilerFeatureRequired(\"ClosedClasses\")]\n    public C1(int param) { }\n}\n```\n\n#### Use of multiple `[CompilerFeatureRequired]` attributes\n\nA [question came up](https://github.com/dotnet/roslyn/pull/82052#discussion_r2759549101) about a case where a closed class has required members:\n\n```cs\nclosed class C1\n{\n    public C() { }\n    public required string P { get; set; }\n}\n\n// Metadata:\nclass C1\n{\n    // Do we expect all of the following to be emitted?\n    // Or do we want to drop CompilerFeatureRequired(\"RequiredMembers\"), for example, on the assumption that 'any compiler that supports closed classes should also support required members'?(\"RequiredMembers\")?\n    [Obsolete(\"Types with required members are not supported in this version of your compiler\")]\n    [CompilerFeatureRequired(\"RequiredMembers\")]\n    [CompilerFeatureRequired(\"ClosedClasses\")]\n    public C1() { }\n}\n```\n\nDo we want to emit all attributes in the above sample or just a subset of them?\n\n### Same module restriction\n\nThe proposal text mentions that there must be a \"same assembly\" restriction. We propose strengthening this restriction so that subtypes may only be declared in the same module. That is, declaring a closed class in a netmodule, and subtyping it in a different module, should not be permitted, because it breaks the ability to determine the exhaustive set of subtypes from the context of the original declaration in a similar way as cross-assembly subtyping.\n\n### Permit explicit use of abstract modifier\n\nThe `closed` modifier also makes the class abstract. Should we permit both `closed` and `abstract` to be used on a declaration? Permitting it may give an impression that the `abstract` modifier is making a difference.\n\n```cs\nclosed abstract class C { } // equivalent to:\nclosed class C { }\n\n// compare with:\nabstract interface I // error\n{\n    abstract void M(); // ok\n}\ninternal class C { } // ok, explicitly specifying the default accessibility\n```\n\n### TODO: Should subtypes be marked in metadata?\nNote: this is more of an engineering question, and, probably should not be brought to LDM until we have evidence this solves a perf problem, we have considered the tradeoffs, etc.\n\nIt seems like when a closed type is referenced from metadata, there is a need to search its containing assembly for all possible subtypes of it, to check exhaustiveness of patterns in the consuming compilation. This might be expensive. Would there be a benefit in encoding on a closed type itself, the list of subtypes which have it as a base type?\n\nAt first glance, something like `[ClosedSubtype(typeof(Subtype1), typeof(Subtype2), typeof(GenericSubtype1<>), ...)]` in metadata seems viable. Note that the compiler would still need to examine the base type of each subtype to look at the way a generic closed type is being constructed, for example, to handle cases such as `class GenericSubtype1<T> : ClosedType<IEnumerable<T>>`. In this case, the amount and identities of the subtypes will depend on the specific type arguments to `ClosedType<T>`.\n"
  },
  {
    "path": "proposals/collection-expression-arguments.md",
    "content": "# Collection expression arguments\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/8887>\n\n## Motivation\n\nThe [*dictionary expression*](https://github.com/dotnet/csharplang/blob/main/proposals/dictionary-expressions.md)\nfeature has identified a need for collection expressions to pass along user-specified data in order to configure\nthe behavior of the final collection.  Specifically, dictionaries allow users to customize how their keys compare,\nusing them to define equality between keys, and sorting or hashing (in the case of sorted or hashed collections\nrespectively).  This need applies when creating any sort of dictionary type (like `D d = new D(...)`,\n`D d = D.CreateRange(...)` and even `IDictionary<...> d = <synthesized dict>`)\n\nTo support this, a new `with(...arguments...)` element is proposed as the first element of a collection expression\nlike so:\n\n```c#\nDictionary<string, int> nameToAge = [with(comparer), .. d1, .. d2, .. d3];\n```\n\n1. When translating to a `new CollectionType(...)` call, these `...arguments...` are used to determine the appropriate\nconstructor and are passed along accordingly.\n2. When translating to a `CollectionFactory.Create` call, these \n`...arguments...` are passed before with the `ReadOnlySpan<ElementType>` elements argument, all of which are \nused to determine the appropriate `Create` overload, and are passed along accordingly.\n3. When translating to an interface (like `IDictionary<,>`) only a single argument is allowed.  It implements one of\n   the well-known BCL comparer interfaces, and will be used to control the key comparing semantics of the final instance.\n\nThis syntax was chosen as it:\n\n1. Keeps all information within the `[...]` syntax.  Ensuring that the code still clearly indicates a collection being created.\n1. Does not imply calling a `new` constructor (when that isn't how all collections are created).\n1. Does not imply creating/copying the values of the collection multiple times (like a postfix `with { ... }` might.\n1. Does not contort order of operations, especially with C#'s consistent left-to-right expression evaluation ordering semantics.\n   For example, it does not evaluate the arguments used to construct a collection *after* evaluating the expressions used to\n   populate the collection.\n1. Does not force a user to read to the end of a (potentially large) collection expression to determine core behavioral semantics.\n   For example, having to see to the end of a hundred-line dictionary, only to find that, yes, it was using the right key comparer.\n1. Is both not subtle, while also not being excessively verbose.  For example, using `;` instead of `,` to indicate\n   arguments is a very easy piece of syntax to miss.  `with()` only adds 6 characters, and will easily stand out,\n   especially with syntax coloring of the `with` keyword.\n1. Reads nicely.  \"This is a collection expression 'with' these arguments, consisting of these elements.\"\n1. Solves the need for comparers for both dictionaries and sets.\n1. Ensures any user need for passing arguments, or any needs we ourselves have beyond comparers in the future are already handled.\n1. Does not conflict with any existing code (using https://grep.app/ to search).\n\n## Design Philosophy\n\nThe below section covers prior design philosophy discussions.  Including why certain forms were rejected. \n\nThere are two main directions we can go in to supply this user-defined data.  The first is to special case *only*\n values in the *comparer* space (which we define as types inheriting from the BCL's `IComparer<T>` or\n  `IEqualityComparer<T>` types).  The second is to provide a generalized mechanism to supply arbitrary arguments\n   to the final invoked API when creating collection expressions.  The primary *dictionary expression* specification\n    shows how we could do the former, while this specification seeks to do the latter.\n\nExaminations of the solutions for just passing *comparers* have revealed weaknesses in their approach if we wanted\n to expand them to *arbitrary arguments*.  For example:\n\n1. Reusing *element* syntax, like we do with the form: `[StringComparer.OrdinalIgnoreCase, \"mads\": 21]`. This works\n   well in a space where `KeyValuePair<,>` and comparers do not inherit from common types.  But it breaks down in a\n   world where one might do: `HashSet<object> h = [StringComparer.OrdinalIgnoreCase, \"v\"]`.  Is this passing along\n   a comparer?  Or attempting to put two object values into the set?\n\n2. Separating out arguments versus elements with subtle syntax (like using a semicolon instead of a comma to\n   separate them in `[comparer; v1]`). This risks very confusing situations where a user accidentally writes `[1; 2]`\n   (and gets a collection that passes '1' as, say, the 'capacity' argument for a `List<>`, and only contains the\n   single value '2'), when they intended `[1, 2]` (a collection with two elements).\n\nBecause of this, in order to support arbitrary arguments, we believe a more obvious syntax is needed to more\nclearly demarcate these values. Several other design concerns have also come up with in this space.  In no\nparticular order, these are:\n\n1. That the solution not be ambiguous and cause breaks with code that people are likely using with collection\n expressions today.  For example:\n\n    ```c#\n    List<Widget> c = [new(...), w1, w2, w3];\n    ```\n    \n    This is legal today, with the `new(...)` expression being a 'implicit object creation' that creates a new\n    widget.  We cannot repurpose this to pass along arguments to `List<>`'s constructor as it would *certainly*\n    break existing code.\n\n1. That the syntax not extend to outside of the `[...]` construct.  For example:\n\n    ```c#\n    HashSet<string> s = [...] with ...;\n    ```\n    \n    These syntaxes can be construed to mean that the collection is created first, and then recreated into a\n    differing form, implying multiple transformations of the data, and potentially unwanted higher costs\n    (even if that's not what is emitted).\n\n1. That `new` as a potential keyword to use *at all* in this space is undesirably confusing.  Both because\n   `[...]` *already* indicates that a *new* object is created, and because translations of the collection\n   expression may go through non-constructor APIs (for example, the *Create method* pattern).\n\n1. That the solution not be excessively verbose.  A core value proposition of collection expressions is\n   *brevity*. So if the form adds a large amount of syntactic scaffolding, it will feel like a step backwards,\n   and will undercut the value proposition of using collection-expressions, versus calling into the existing\n   APIs to make the collection.\n\nNote that a syntax like `new([...], ...)` runs afoul of both '2' and '3' above.  It makes it appear as if we\nare calling into a constructor (when we may not be) *and* it implies that a created collection expression is\npassed to that constructor, which is definitely is not.\n\nBased on all of the above, a small handful of options have come up that are felt to solve the needs of passing\narguments, without stepping out of bounds of the goals of collection expressions.\n\n## `[with(...arguments...)]` Design\n\n### Syntax:\n\n```diff\ncollection_element\n   : expression_element\n   | spread_element\n+  | with_element\n   ;\n\n+with_element\n+  : 'with' argument_list\n+  ;\n```\n\nThere is a syntactic ambiguity immediately introduced with this grammar production.  Similar to the ambiguity\nbetween `spread_element` and `expression_element` (explained [here](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#detailed-design), there is an immediate syntactic ambiguity between `with_element` and `expression_element`.\nSpecifically `with(<arguments>)` is both exactly the production-body for `with_element`, and is also reachable through\n`expression_element -> expression -> ... -> invocation_expression`. There is a simple overarching rule for\ncollection_elements. Specifically, if the element [lexically](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/lexical-structure.md)\nstarts with the token sequence `with` `(` then it is always treated as a `with_element`.\n\nThis is beneficial in two ways. First, a compiler implementation needs only look at the immediately following tokens\nit sees to determine what sort of element to parse. Second, correspondingly, a user can trivially understand what sort of element\nthey have without having to mentally try to parse what follows to see if they should think of it as a `with_element` or\nan `expression_element`.\n\n### Examples\n\nExamples of how this would look are:\n\n```c#\n// With an existing type:\n\n// Initialize to twice the capacity since we'll have to add\n// more values later.\nList<string> names = [with(capacity: values.Count * 2), .. values];\n```\n\nThese forms seem to \"read\" reasonably well.  In all those cases, the code is \"creating a collection expression,\n'with' the following arguments to pass along to control the final instance, and then the subsequent elements\nused to populate it.  For example, the first line \"creates a list of strings 'with' a capacity of two times the\ncount of the values about to be spread into it\"\n\nImportantly, this code has little chance of being overlooked like with forms such as: `[arg; element]`, while\nalso adding minimal verbosity, with a large amount of flexibility to pass any desired arguments along.\n\nThis would *technically* be a breaking change as `with(...)` *could* have been a call to a pre-existing method\ncalled `with`.  However, unlike `new(...)` which is a *known* and recommended way to create implicitly-typed\nvalues, `with(...)` is far less likely as a method name, running afoul of .Net naming for methods.  In the\nunlikely event that a user did have such a method, they would certainly be able to continue calling into the\nexisting method by using `@with(...)`.\n\nWe would translate this `with(...)` element like so:\n\n```c#\nList<string> names = [with(/*capacity*/10), ...]; // translates to:\n\n// argument_list *becomes* the argument list for the\n// constructor call. \n__result = new List<string>(10); // followed by normal initialization\n\n// or\n\nIList<string> names2 = [with(capacity: 20), ...]; // translates to:\n\n__result = new List<string>(20);\n```\n\nIn other words, the argument_list arguments would be passed to the appropriate constructor if we are calling\na constructor, or to the appropriate 'create method' if we are calling such a method.  We would also allow a\nsingle argument inheriting from the BCL *comparer* types to be provided when instantiating one of the destination\ndictionary interface types to control its behavior.\n\n## Conversions\n\nThe [conversions](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#conversions) section for collection-expressions is updated in the following manner:\n\n```diff\n> A struct or class type that implements System.Collections.IEnumerable where:\n\n-  * The type has an applicable constructor that can be invoked with no arguments, and the constructor is accessible at the location of the collection expression.\n+  a. the collection expression has no `with_element` and the type has an applicable constructor\n+     that can be invoked with no arguments, accessible at the location of the collection expression. or\n+  b. the collection expression has a `with_element` and the type has at least one constructor\n+     accessible at the location of the collection expression. \n```\n\nNote the actual arguments within the `argument_list` of the `with_element` do not affect if the conversion exists or not.  Just the presence or absence of the `with_element` itself.  The intuition here is simply that if the collection expression is written without one (like `[x, y, z]`) it would have to be to be able to call the constructor without args.  While if it is has `[with(...), x, y, z]` it could then call the appropriate constructor.  This also means that types that can *not* invoked with a no-argument constructor *can* be used with a collection expression, but *only*  if that collection expression that contains a `with_element`.\n\nThe actual determination of how a `with_element` will affect construction is given [below](#construction).\n\n## Construction\n\nConstruction is updated as follows.\n\nThe elements of a collection expression are evaluated in order, left to right.\nWithin *collection arguments*, the arguments are evaluated in order, left to right.\nEach element or argument is evaluated exactly once, and any further references refer to the results of this initial evaluation.\n\nIf *collection_arguments* is included and is not the first element in the collection expression, a compile-time error is reported.\n\nIf the *argument list* contains any values with *dynamic* type, a compile-time error is reported ([LDM-2025-01-22](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-01-22.md#conclusion-1)).\n\n### Constructors\n\nIf the target type is a *struct* or *class type* that implements `System.Collections.IEnumerable`, and the target type does not have a *create method*, and the target type is not a *generic parameter type* then:\n* [*Overload resolution*](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/expressions.md#1264-overload-resolution) is used to determine the best instance constructor from the candidates.\n* The set of candidate constructors is all accessible instance constructors declared on the target type that are applicable with respect to the *argument list* as defined in [*applicable function member*](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12642-applicable-function-member).\n* If a best instance constructor is found, the constructor is invoked with the *argument list*.\n  * If the constructor has a `params` parameter, the invocation may be in expanded form.\n* Otherwise, a binding error is reported.\n\n```csharp\n// List<T> candidates:\n//   List<T>()\n//   List<T>(IEnumerable<T> collection)\n//   List<T>(int capacity)\nList<int> l;\nl = [with(capacity: 3), 1, 2]; // new List<int>(capacity: 3)\nl = [with([1, 2]), 3];         // new List<int>(IEnumerable<int> collection)\nl = [with(default)];           // error: ambiguous constructor\n```\n\n### CollectionBuilderAttribute methods\n\nIf the target type is a type with a *create method*, then:\n* [*Overload resolution*](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/expressions.md#1264-overload-resolution) is used to determine the best create method from the candidates.\n* For each [*create method*](#create-methods) for the target type, we define a *projection method* with an identical signature to the create method but *without the last parameter*.\n* The set of *candidate projection methods* is the projection methods that are applicable with respect to the *argument list* as defined in [*applicable function member*](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12642-applicable-function-member).\n* If a best projection method is found, the corresponding create method is invoked with the *argument list* appended with a `ReadOnlySpan<T>` containing the elements.\n* Otherwise, a binding error is reported.\n\n```csharp\n[CollectionBuilder(typeof(MyBuilder), \"Create\")]\nclass MyCollection<T> { ... }\n\nclass MyBuilder\n{\n    public static MyCollection<T> Create<T>(ReadOnlySpan<T> elements);\n    public static MyCollection<T> Create<T>(IEqualityComparer<T> comparer, ReadOnlySpan<T> elements);\n}\n```\n\n```c#\nMyCollection<string> c1 = [with(GetComparer()), \"1\", \"2\"];\n// IEqualityComparer<string> _tmp1 = GetComparer();\n// ReadOnlySpan<string> _tmp2 = [\"1\", \"2\"];\n// c1 = MyBuilder.Create<string>(_tmp1, _tmp2);\n\nMyCollection<string> c2 = [with(), \"1\", \"2\"];\n// ReadOnlySpan<string> _tmp3 = [\"1\", \"2\"];\n// c2 = MyBuilder.Create<string>(_tmp3);\n```\n\n<a id=\"create-methods\"></a>\n#### CollectionBuilderAttribute: Create methods\n\nFor a collection expression where the target type *definition* has a `[CollectionBuilder]` attribute, the *create methods* are the following, **updated** from [*collection expressions: create methods*](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#create-methods).\n\n> A `[CollectionBuilder(...)]` attribute specifies the *builder type* and *method name* of a method to be invoked to construct an instance of the collection type.\n> \n> The *builder type* must be a non-generic `class` or `struct`.\n> \n> First, the set of applicable *create methods* `CM` is determined.\n> It consists of methods that meet the following requirements:\n> \n> * The method must have the name specified in the `[CollectionBuilder(...)]` attribute.\n> * The method must be defined on the *builder type* directly.\n> * The method must be `static`.\n> * The method must be accessible where the collection expression is used.\n> * The *arity* of the method must match the *arity* of the collection type.\n> * The method must have a **last** parameter of type `System.ReadOnlySpan<E>`, passed by value.\n> * There is an [*identity conversion*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/conversions.md#1022-identity-conversion), [*implicit reference conversion*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/conversions.md#1028-implicit-reference-conversions), or [*boxing conversion*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/conversions.md#1029-boxing-conversions) from the method return type to the *collection type*.\n> \n> Methods declared on base types or interfaces are ignored and not part of the `CM` set.\n\n> For a *collection expression* with a target type <code>C&lt;S<sub>0</sub>, S<sub>1</sub>, &mldr;&gt;</code> where the *type declaration* <code>C&lt;T<sub>0</sub>, T<sub>1</sub>, &mldr;&gt;</code> has an associated *builder method* <code>B.M&lt;U<sub>0</sub>, U<sub>1</sub>, &mldr;&gt;()</code>, the *generic type arguments* from the target type are applied in order &mdash; and from outermost containing type to innermost &mdash; to the *builder method*.\n\nThe key differences from the earlier algorithm are:\n* Create methods may have additional parameters *before* the `ReadOnlySpan<E>` parameter.\n* Multiple create methods are supported.\n\n### Interface target type\n\nIf the target type is an *interface type*, then:\n* [*Overload resolution*](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/expressions.md#1264-overload-resolution) is used to determine the best candidate method signature.\n* The set of candidate signatures is the signatures below for the target interface that are applicable with respect to the *argument list* as defined in [*applicable function member*](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12642-applicable-function-member).\n\n  |Interfaces|Candidate signatures|\n  |:---:|:---:|\n  |`IEnumerable<E>`<br>`IReadOnlyCollection<E>`<br>`IReadOnlyList<E>`|`()` (no parameters)|\n  |`ICollection<E>`<br>`IList<E>`|`List<E>()`<br>`List<E>(int)`|\n\n If a best method signature is found, the semantics are as follows:\n\n* The candidate signature for `IEnumerable<E>`, `IReadOnlyCollection<E>` and `IReadOnlyList<E>` is simply `()` and has the same meaning as not having the `with()` element at all.\n* The candidate signatures for `IList<T>` and `ICollection<T>` are the signatures of `List<T>()` and `List<T>(int)` constructors.  When constructing the value (see [Mutable Interface Translation](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#mutable-interface-translation)), the respective `List<T>` constructor will be invoked.\n* Otherwise, a binding error is reported.\n\n#### Dictionary-Interface target type\n\nThis is specified here as part of the feature defined in https://github.com/dotnet/csharplang/blob/main/proposals/dictionary-expressions.md.\n\nThe above list is augmented to have the following items:\n\n  |Interfaces|Candidate signatures|\n  |:---:|:---:|\n  |`IReadOnlyDictionary<K, V>`|`()` (no parameters)<br>`(IEqualityComparer<K>? comparer)`|\n  |`IDictionary<K, V>`|`Dictionary<K, V>()`<br>`Dictionary<K, V>(int)`<br>`Dictionary<K, V>(IEqualityComparer<K>)`<br>`Dictionary<K, V>(int, IEqualityComparer<K>)`|\n\n If a best method signature is found, the semantics are as followed:\n\n* The candidate signatures for `IReadOnlyDictionary<K, V>` are  `()` (which has the same meaning as not having the `with()` element at all), and `(IEqualityComparer<K>)`.  This comparer will be used to appropriately hash and compare the keys in the destination dictionary the compiler chooses to create (see [Non Mutable Interface Translation](https://github.com/dotnet/csharplang/blob/main/proposals/dictionary-expressions.md#non-mutable-interface-translation)). \n* The candidate signatures for `IDictionary<T>` are the signatures of `Dictionary<K, V>()`, `Dictionary<K, V>(int)`, `Dictionary<K, V>(IEqualityComparer<K>)` and `Dictionary<K, V>(int, IEqualityComparer<K>)`constructors.  When constructing the value (see [Mutable Interface Translation](https://github.com/dotnet/csharplang/blob/main/proposals/dictionary-expressions.md#mutable-interface-translation)), the respective `Dictionary<K, V>` constructor will be invoked.\n* Otherwise, a binding error is reported.\n\n```csharp\nIDictionary<string, int> d;\nIReadOnlyDictionary<string, int> r;\n\nd = [with(StringComparer.Ordinal)]; // new Dictionary<string, int>(StringComparer.Ordinal)\nr = [with(StringComparer.Ordinal)]; // new $PrivateImpl<string, int>(StringComparer.Ordinal)\n\nd = [with(capacity: 2)]; // new Dictionary<string, int>(capacity: 2)\nr = [with(capacity: 2)]; // error: 'capacity' parameter not recognized\nd = [with()];            // Legal: empty arguments supported for interfaces\n```\n\n### Other target types\n\nIf the target type is any other type, then a binding error is reported for the *argument list*, even if empty.\n\n```csharp\nSpan<int> a = [with(), 1, 2, 3]; // error: arguments not supported\nSpan<int> b = [with([1, 2]), 3]; // error: arguments not supported\n\nint[] a = [with(), 1, 2, 3]; // error: arguments not supported\nint[] b = [with(length: 1), 3]; // error: arguments not supported\n```\n\n## Ref safety\n\nWe adjust the [collection-expressions.md#ref-safety](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#ref-safety) rules to account for the `with()` element.\n\nSee also [§16.4.15 Safe context constraint](https://github.com/dotnet/csharpstandard/blob/draft-v7/standard/structs.md#16415-safe-context-constraint).\n\n### Create methods\n\nThis section applies to collection-expressions whose target type meets the constraints defined in [CollectionBuilderAttribute methods](#collectionbuilderattribute-methods).\n\nThe *safe-context* is determined by modifying a clause from [collection-expressions.md#ref-safety](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#ref-safety) (changes in **bold**):\n\n> * If the target type is a *ref struct type* with a [*create method*](#create-methods), the safe-context of the collection expression is the [*safe-context of an invocation*](https://github.com/dotnet/csharpstandard/blob/draft-v7/standard/structs.md#164126-method-and-property-invocation) of the create method where **the arguments are the `with()` element arguments followed by the collection expression as the argument for the last parameter (the `ReadOnlySpan<E>` parameter).**\n\nThe [*method arguments must match*](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/low-level-struct-improvements.md#method-arguments-must-match) constraint applies to the collection expression. Similarly to the *safe-context* determination above, the *method arguments must match* constraint is applied by treating the collection expression as an invocation of the create method, where the arguments are the `with()` element arguments followed by the collection expression as the argument for the last parameter.\n\n### Constructor calls\n\nThis section applies to collection-expressions whose target type meets the constraints defined in [Constructors](#constructors).\n\nFor a collection-expression of a *ref struct type* of the following form:  \n`[with(a₁, a₂, ..., aₙ), e₁, e₂, ..., eₙ]`\n\nThe *safe-context* of the collection expression is the narrowest of the *safe-contexts* of the following expressions:\n- An object creation expression `new C(a₁, a₂, ..., aₙ)`, where `C` is the target type\n- The element expressions `e₁, e₂, ..., eₙ` (either the expressions themselves, or the spread value in the case of a spread element).\n\nThe [*method arguments must match*](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/low-level-struct-improvements.md#method-arguments-must-match) constraint applies to the collection expression. The constraint is applied by treating the collection expression as an object creation of the form `new C(a₁, a₂, ..., aₙ) { e₁, e₂, ..., eₙ }` per [low-level-struct-improvements.md#rules-for-object-initializers](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/low-level-struct-improvements.md#rules-for-object-initializers).\n- Expression elements are treated as if they are collection element initializers.\n- Spread elements are treated similarly, by temporarily assuming that `C` has an `Add(SpreadType spread)` method, where `SpreadType` is the type of the spread value.\n\n## Answered questions\n\n### `dynamic` arguments\n\nShould arguments with `dynamic` type be allowed? That might require using the runtime binder for overload resolution, which would make it difficult to limit the set of candidates, for instance for collection builder cases.\n\n**Resolution:** Disallowed. [LDM-2025-01-22](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-01-22.md#conclusion-1)\n\n### `with()` breaking change\n\nThe proposed `with()` element is a breaking change.\n```csharp\nobject x, y, z = ...;\nobject[] items = [with(x, y), z]; // C#13: ok; C#14: error args not supported for object[]\n\nobject with(object x, object y) { ... }\n```\n\nConfirm the breaking change is acceptable, and whether breaking change should be tied to language version.\n\n**Resolution:** Keep previous behavior (no breaking change) when compiling with earlier language version. [LDM-2025-03-17](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-03-17.md#conclusion)\n\n### Should arguments affect collection expression conversion?\n\nShould collection arguments and the applicable methods affect convertibility of the collection expression?\n```csharp\nPrint([with(comparer: null), 1, 2, 3]); // ambiguous or Print<int>(HashSet<int>)?\n\nstatic void Print<T>(List<T> list) { ... }\nstatic void Print<T>(HashSet<T> set) { ... }\n```\n\nIf the arguments affect convertibility based on the applicable methods, arguments should probably affect type inference as well.\n```csharp\nPrint([with(comparer: StringComparer.Ordinal)]); // Print<string>(HashSet<string>)?\n```\n\nFor reference, similar cases with target-typed `new()` result in errors.\n```csharp\nPrint<int>(new(comparer: null));              // error: ambiguous\nPrint(new(comparer: StringComparer.Ordinal)); // error: type arguments cannot be inferred\n```\n\n**Resolution:** Collection arguments should be ignored in conversions and type inference. [LDM-2025-03-17](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-03-17.md#conclusion-1)\n\n### Collection builder method parameter order\n\nFor *collection builder* methods, should the span parameter be before or after any parameters for collection arguments?\n\nElements first would allow the arguments to be declared as optional.\n```csharp\nclass MySetBuilder\n{\n    public static MySet<T> Create<T>(ReadOnlySpan<T> items, IEqualityComparer<T> comparer = null) { ... }\n}\n```\n\nArguments first would allow the span to be a `params` parameter, to support calling directly in expanded form.\n```csharp\nvar s = MySetBuilder.Create(StringComparer.Ordinal, x, y, z);\n\nclass MySetBuilder\n{\n    public static MySet<T> Create<T>(IEqualityComparer<T> comparer, params ReadOnlySpan<T> items) { ... }\n}\n```\n\n**Resolution:** The span parameter for elements should be the last parameter. [LDM-2025-03-12](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-03-12.md#conclusion-1)\n\n### Arguments with earlier language version\n\nIs an error reported for `with()` when compiling with an earlier language version, or does `with` bind to another symbol in scope?\n\n**Resolution:** No breaking change for `with` inside a collection expression when compiling with earlier language versions. [LDM-2025-03-17](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-03-17.md#conclusion)\n\n### Target types where arguments are *required*\n\nShould collection expression conversions be supported to target types where arguments must be supplied because all of the constructors or factory methods require at least one argument?\n\nSuch types could be used with collection expressions that include explicit `with()` arguments but the types could not be used for `params` parameters.\n\nFor example, consider the following type constructed from a factory method:\n```csharp\nMyCollection<object> c;\nc = [];                  // error: no arguments\nc = [with(capacity: 1)]; // ok\n\n[CollectionBuilder(typeof(MyBuilder), \"Create\")]\nclass MyCollection<T> : IEnumerable<T> { ... }\n\nclass MyBuilder\n{\n    public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, int capacity) { ... }\n}\n```\n\nThe same question applies for when the constructor is called directly as in the example below.\n\nHowever, for the target types where the constructor is called directly, the collection expression *conversion* currently **requires a constructor callable with no arguments**, but the collection *arguments* are ignored when determining convertibility.\n\n```csharp\nc = [];                  // error: no arguments\nc = [with(capacity: 1)]; // error: no constructor callable with no arguments?\n\nclass MyCollection<T> : IEnumerable<T>\n{\n    public MyCollection(int capacity) { ... }\n    public void Add(T t) { ... }\n    // ...\n}\n```\n\n**Resolution:** Support conversions to target types where all constructors or factory methods require arguments, and require `with()` for the conversion. [LDM-2025-03-05](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-04-14.md#conclusion-2)\n\n### `__arglist`\n\nShould `__arglist` be supported in `with()` elements?\n\n```csharp\nclass MyCollection : IEnumerable\n{\n    public MyCollection(__arglist) { ... }\n    public void Add(object o) { }\n}\n\nMyCollection c;\nc = [with(__arglist())];    // ok\nc = [with(__arglist(x, y)]; // ok\n```\n\n**Resolution:** No support for `__arglist` in collection arguments unless free. [LDM-2025-03-05](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-04-14.md#conclusion-3)\n\n### Arguments for *interface types*\n\nShould arguments be supported for interface target types?\n\n```csharp\nICollection<int> c = [with(capacity: 4)];\nIReadOnlyDictionary<string, int> d = [with(comparer: StringComparer.Ordinal), ..values];\n```\n\n<details>\nIf so, which method signatures are used when binding the arguments?\n\nFor **mutable** interface types, the options are:\n1. Use the accessible constructors from the well-known type required for instantation: `List<T>` or `Dictionary<K, V>`.\n1. Use signatures independent of specific type, for instance using `new()` and `new(int capacity)` for `ICollection<T>` and `IList<T>` (see [*Construction*](#construction) for potential signatures for each interface).\n\nUsing the accessible constructors from a well-known type has the following implications:\n- Parameter names, optional-ness, `params`, are taken from the parameters directly.\n- All accessible constructors are included, even though that may not be useful for collection expressions, such as `List(IEnumerable<T>)` which would allow `IList<int> list = [with(1, 2, 3)];`.\n- The set of constructors may depend on the BCL version.\n\nRecomendation: Use the accessible constructors from the well-known types.  We have guaranteed we would use these types, so this just 'falls out' and is the clearest and simplest path to constructing these values.  \n\n\nFor **non-mutable** interface types, the options are similar:\n1. Do nothing.  This \n1. Use signatures independent of specific type, although the only scenario may be `new(IEqualityComparer<K> comparer)` for `IReadOnlyDictionary<K, V>` for C#14..\n\n\nUsing accessible constructors from some well known type (the strategy for mutable-interface-types) is not viable as there is no relation to any particular existing type, and the final type we may use and/or synthesize.  As such, there would have to be odd new requirements that the compiler be able to map any existing constructor of said type (even as it evolves) over to the non-mutable instance it actually generates.\n\nRecomendation: Use signatures independent of a specific type.  And, for C# 14, only support `new(IEqualityComparer<K> comparer)` for `IReadOnlyDictionary<K, V>` as that is the only non-mutable interface where we feel it is critical for usability/semantics to allow users to provide this.  Future C# releases can consider expanding on this set based on solid justifications provided.\n</details>\n\n**Resolution:** https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-04-23.md\n\nArguments are supported for interface target types.  For both mutable and non-mutable interfaces the set of arguments will be curated.  \n\nThe expected list (which still needs to be LDM ratified) is [Interface target type](#interface-target-type)\n\n### Empty argument lists\n\nShould we allow empty argument lists for some or all target types?\n\nAn empty `with()` would be equivalent to no `with()`. It might provide some consistency with non-empty cases, but it wouldn’t add any new capability.\n\n<details>\nThe meaning of an empty `with()` might be clearer for some target types than others:\n- For types where **constructors** are used, call the applicable constructor with no arguments.\n- For types with **`CollectionBuilderAttribute`**, call the applicable factory method with elements only.\n- For **interface types**, construct the well-known or implementation-defined type with no arguments.\n- However, for **arrays** and **spans**, where collection arguments are not otherwise supported, `with()` may be confusing.\n\n```csharp\nList<int>           l = [with()]; // ok? new List<int>()\nImmutableArray<int> m = [with()]; // ok? ImmutableArray.Create<int>()\n\nIList<int>       i = [with()]; // ok? new List<int>() or equivalent\nIEnumerable<int> e = [with()]; // ok?\n\nint[]     a = [with()]; // ok?\nSpan<int> s = [with()]; // ok?\n```\n</details>\n\n**Resolution:** https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-05-12.md#empty-argument-lists\n\n> We will allow with() for constructor types and builder types that can be called without arguments at all, and we will add empty constructor signatures for the interface (mutable and readonly) types. Arrays and spans will not allow with(), as there are no signatures that would fit them.\n\n## Open questions\n\n### Finalizing an open concern from https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-03-17.md#conclusion\n\n`with(...)` is a breaking change in the language with `[with(...)]`.  Before this feature, it means a collection expression with one element, which is the result of calling the `with`-invocation-expression.  After this feature, it is a collection, which has arguments passed to it. \n\nDo we want this break to occur only when a user picks a specific language version (like `C#-14/15`?).  In other words, if they are on an older langversion, they get the prior parsing logic, but on the newer version they get the newer parsing logic.  In  Or do we *always* want it to have the newer parsing logic, even on an older langversion?\n\nWe have prior art for both strategies.  `required`, for example, is always parsed with teh new logic, regardless of langversion.  Whereas, `record/field` and others chang their parsing logic depending on language version. \n\nFinally, this has overlap and impact with `Dictionary Expressions`, which introduces the `key:value` syntax for KVP-elements.  We want to establish the behavior we want for any lang version, and for `[with(...)]` on its own, and things like `[with(...) : expr]` or `[expr : with(...)]`.\n"
  },
  {
    "path": "proposals/compound-assignment-in-initializer-and-with.md",
    "content": "# Compound assignment in object initializer and `with` expression\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/9896>\n\n## Summary\n\nAllow compound assignments in an object initializer:\n\n```cs\nvar timer = new DispatcherTimer\n{\n    Interval = TimeSpan.FromSeconds(1d),\n    Tick += (_, _) => { /*actual work*/ },\n};\n```\n\nOr a `with` expression:\n\n```cs\nvar newCounter = counter with { Value -= 1 };\n```\n\n## Motivation\n\nIt's not uncommon, especially in UI frameworks, to create objects that both have values assigned and need events hooked up as part of initialization. While object initializers addressed the first part with a nice shorthand syntax, the latter still requires additional statements to be made. This makes it impossible to simply create these sorts of objects as a simple declaration expression, preventing their use in expression-bodied members or in nested constructs like collection initializers or switch expressions. Spilling the object creation expression out to a variable declaration statement makes things more verbose for such a simple concept.\n\nThe declarative UI story can be made much more complete with a small change to the language. Windows Forms in particular can immediately gain a more appetizing story for dynamic or manual creation of UI controls, both in vanilla form and when using third-party vendor frameworks that build on Windows Forms.\n\nThe applies to more than just events though as objects created (esp. based off another object with `with`) may want their initialized values to be relative to a prior or default state.\n\n## Detailed design\n\n### Object initializer design\n\nThe existing <https://github.com/dotnet/csharplang/blob/main/spec/expressions.md#object-initializers> will be updated to state:\n\n```diff\n member_initializer\n-    : initializer_target '=' initializer_value\n+    : initializer_target assignment_operator initializer_value\n     ;\n```\n\nThe spec language will be changed to:\n\n> If an initializer_target is followed by an equals (`'='`) sign, it can be followed by either an expression, an object initializer or a collection initializer.  If it is followed by any other assignment operator it can only be followed by an expression.\n>\n> If an initializer_target is followed by an equals (`'='`) sign it not possible for expressions within the object initializer to refer to the newly created object it is initializing.  If it is followed by any other assignment operator, the new value will be created by reading the value from the new created object and then writing back into it.\n>\n> A member initializer that specifies an expression after the assignment_operator is processed in the same way as an [assignment](https://github.com/dotnet/csharplang/blob/main/spec/expressions.md#assignment-operators) to the target.\n\n### `with` expression design\n\nThe existing [with expression](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-9.0/records.md#with-expression) spec will be updated to state:\n\n```diff\nmember_initializer\n-    : identifier '=' expression\n+    : identifier assignment_operator expression\n    ;\n```\n\nThe spec language will be changed to:\n\n> First, receiver's \"clone\" method (specified above) is invoked and its result is converted to the receiver's type. Then, each member_initializer is processed the same way as a corresponding assignment operation [assignment](https://github.com/dotnet/csharplang/blob/main/spec/expressions.md#assignment-operators) to a field or property access of the result of the conversion. Assignments are processed in lexical order.\n\n### Design notes\n\nThere is no concern that `new X() { a += b }` has meaning today (for example, as a collection initializer). That's because the spec mandates that a collection initializer's element_initializer is:\n\n```antlr\nelement_initializer\n    : non_assignment_expression\n    | '{' expression_list '}'\n    ;\n```\n\nBy requiring that all collection elements are `non_assignment_expression`, `a += b` is already disallowed as that is an assignment_expression.\n\n## Open questions\n\nIs this feature needed? For example, users could support some of these scenarios doing something like the following:\n\n```cs\nvar timer = new DispatcherTimer\n{\n    Interval = TimeSpan.FromSeconds(1d),\n}.Init(t => t.Tick += (_, _) => { /*actual work*/ }),\n```\n\nThat said, this would only work for non-init members, which seems unfortunate, and it is still clunky compared to the first-class experience of initializing all other members.\n"
  },
  {
    "path": "proposals/conditional-operator-access-syntax-refinement.md",
    "content": "# Conditional operator/access syntax refinement\n\n## Summary\n\nIntroduce whitespace-sensitive parsing rules to eliminate ambiguity between the conditional operator (`?:`)\nand null-conditional access operators (`?.` and `?[`). This change requires that tokens in null-conditional \noperators must be adjacent with no intervening characters, while conditional operators with certain operand\npatterns must have whitespace or comments between the `?` and the subsequent token.\n\n## Motivation\n\nThe C# language currently has potential ambiguities when parsing the `?` token followed by `[` or `.`, which\ncan be difficult to interpret both visually and syntactically.\n\n### Existing ambiguities\n\nConsider the sequence `a?[b`. This could be interpreted as:\n- A null-conditional indexing operation: `a?[b]` (index into `a` with `b` if `a` is not null)\n- The start of a conditional expression: `a ? [b] : expr` (if `a` is true, evaluate to collection expression\n  `[b]`, otherwise `expr`)\n\nWhile the parser can disambiguate by looking ahead for a `:` token, this creates visual ambiguity for readers.\n\nA true syntactic ambiguity exists with: `A ? [ B ] ? [ C ] : D`\n\nThis could be parsed as:\n- `(A?[B]) ? [C] : D` - conditional expression producing a collection, then null-conditional indexing\n- `A ? ([B]?[C]) : D` - conditional expression with nested conditional in the true branch\n\nThe language currently interprets this as the former, which is reasonable since the latter would involve\ncreating a collection expression solely to perform null-conditional indexing on it—a pattern with no practical use.\n\n### Additional motivation from target-typed static member access\n\nThis issue also arises in the context of [target-typed static member access](https://github.com/dotnet/csharplang/blob/main/proposals/target-typed-static-member-access.md). The sequence `a?.b` could be:\n- A null-conditional member access: `a?.b`\n- The start of a conditional expression with static member access: `a ? .b : expr`\n\nBy establishing whitespace-sensitivity rules, we eliminate these ambiguities entirely.\n\n### Precedent\n\nThe C# language already employs whitespace-sensitive parsing for the `>>` token sequence.\nAs stated in the specification:\n\n> `right_shift` is made up of the two tokens `>` and `>`. Similarly, `right_shift_assignment` is\n  made up of the two tokens `>` and `>=`. Unlike other productions in the syntactic grammar, no\n  characters of any kind (not even whitespace) are allowed between the two tokens in each of these\n  productions. These productions are treated specially in order to enable the correct handling of\n  type_parameter_lists.\n\nThis proposal extends the same concept to null-conditional operators.\n\n## Detailed design\n\n### Parsing rules\n\nThe following multi-character operators are modified to require that their constituent tokens be adjacent with no intervening characters:\n\n- **Null-conditional member access (`?.`)**: The `?` and `.` tokens must be adjacent\n- **Null-conditional indexing (`?[`)**: The `?` and `[` tokens must be adjacent\n\nSimilar to the `>>` production, no characters of any kind (not even whitespace, comments, or preprocessor directives) are allowed between these tokens.\n\nConversely, when the `?` token is followed by `[` or `.` in a conditional expression context, there **must** be at\nleast one intervening character (whitespace, comment, or preprocessor directive) between the `?` and the subsequent\ntoken.\n\n### Grammar changes\n\nThe existing grammar productions for null-conditional operators are unchanged:\n\n```g4\nnull_conditional_member_access\n    : primary_expression '?' '.' identifier type_argument_list?\n      (null_forgiving_operator? dependent_access)*\n    ;\nnull_conditional_element_access\n    : primary_expression '?' '[' argument_list ']'\n      (null_forgiving_operator? dependent_access)*\n    ;\n```\n\nBut explicit rules are added stating:\n\n> `?` `.` and `?` `[` are made up of the two tokens `?` followed by either `.` or `[`. Unlike other productions in the syntactic grammar, no characters of any kind (not even whitespace) are allowed between the two tokens in each of these productions.\n\nThe [Conditional Operator](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/expressions.md#1115-conditional-operator) section is updated to include the following rule:\n\n> A conditional expression of the form `b ? x : y` is not allowed to have `?` and `x` touch if `x` starts with a `.` or `[` token.  If `x` starts with either of those tokens, the expression will instead be interpreted as a  `null_conditional_member_access` or `null_conditional_element_access` respectively.\n\n\n### Examples\n\n**Valid null-conditional access (no space):**\n```csharp\nvar x = obj?[index];        // Null-conditional indexing\nvar y = obj?.Member;        // Null-conditional member access\n```\n\n**Valid conditional expressions (with space/comment):**\n```csharp\nvar x = condition ? [1, 2, 3] : [4, 5, 6];    // Conditional with collection expressions\nvar y = flag ? .StaticMember : expr;          // Conditional with static member access (possible future feature)\nvar z = test ?/*comment*/[x] : [y];      // Comment between tokens\n```\n\n**Invalid (violates adjacency requirement):**\n```csharp\nvar x = obj? [index];       // Error: space between ? and [\nvar y = obj? .Member;       // Error: space between ? and .\n```\n\n## Drawbacks\n\n### Breaking change\n\nThis is a breaking change. Code that currently uses whitespace between `?` and `[` for null-conditional indexing will no longer compile.  Similarly, code like `a?[b]:[c]` would break as well.  \n\nReal-world examples from existing codebases include:\n- `var aux_data = ctx? [\"auxData\"] as JObject;`\n- `var baseScheme = SchemeManager.GetHardCodedSchemes ()? [\"Base\"];`\n\nThese patterns would need to be updated to remove the whitespace: `ctx?[\"auxData\"]` and `SchemeManager.GetHardCodedSchemes()?[\"Base\"]`.\nSimilarly,  if `a?[b]:` was encountered, it would need to be updated to have explicit spaces to\npreserve parsing behavior.\n\nNote: Users using standard .Net tooling (like Visual Studio and `dotnet format`) would not be likely to run into this issue as the standard formatting engine already formats code such that it follows the syntax pattern codified here.  \n\n### Migration burden\n\nDevelopers will need to update their code when upgrading to the language version that includes this feature.\n\nThe compiler will be augmented to parse in the following fashion.  Note: the augmentations only affect what errors are reported in code that cannot be legally parsed.  Specifically, to help users potentially affected by this breaking change to update their code accordingly. \n\nGiven:\n\n```\nconditional_expression\n    : null_coalescing_expression\n    | null_coalescing_expression '?' expression ':' expression\n    ;\n```\n\n- If a `?` is seen after an `null_coalescing_expression`.  Then\n    - If the following token is not a `[` then normal `conditional_expression` parsing occurs.\n    - If the following token is a `[` then the first `expression` part of the `conditional_expression` is parsed out.\n        - If what follows is not a `:` and `[` was next to the `?` (e.g. `a?[b]`), then a `null_conditional_element_access` is parsed instead.\n        - If what follows is not a `:` and `[` was not next to the `?` (e.g. `a ? [b]`), then this is an error.  The parser should attempt to reparse this as a `null_conditional_element_access` expression.  If that succeeds, it should report that the `?` and `[` must be directly next to each other.  Otherwise, it should report a normal error that `:` was missing.\n        - Otherwise, what followed was a `:`\n            - If `?` was not touching the `[`, this is a `conditional_expression` (e.g. `a ? [b] :`), which should then consume the `:` and finish parsing the second `expression` portion of the `conditional_expression`.\n            - Otherwise, this is `a?[b]:` The parser should reparse after the `?` as a `null_conditional_element_access`. And return that expression upwards.  The `:` can then be consumed by a higher parse operation (like a higher `conditional_expression` parse).\n               - If no such higher parse operation exists to consume the `:`, the parser should see if it had a `null_conditional_element_access` followed by the colon (e.g. `a?[b] : c`).  It should then report that a space should be placed after the `?`.\n\nSimilar rules would be present for `?` followed by `.`, with `[` replaced with `.` in the above and `null_conditional_element_access` replaced with `null_conditional_member_access`.\n\nThis approach provides clear guidance for migration, also ensuring that the breaking change is manageable.\n\n## Design meetings\n\nLink to design notes that affect this proposal, and describe in one sentence for each what changes they led to.\n\n## Unresolved questions\n\n\n## Language version\n\nThis feature will be enabled only for the C# language version in which it ships, allowing existing code to\ncontinue compiling under previous language versions.\n\n\n"
  },
  {
    "path": "proposals/csharp-10.0/GlobalUsingDirective.md",
    "content": "# Global Using Directive\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/3428>\n\nSyntax for a using directive is extended with an optional `global` keyword that can precede the `using` keyword:\n```antlr\ncompilation_unit\n    : extern_alias_directive* global_using_directive* using_directive* global_attributes? namespace_member_declaration*\n    ;\n\nglobal_using_directive\n    : global_using_alias_directive\n    | global_using_namespace_directive\n    | global_using_static_directive\n    ;\n\nglobal_using_alias_directive\n    : 'global' 'using' identifier '=' namespace_or_type_name ';'\n    ;\n\nglobal_using_namespace_directive\n    : 'global' 'using' namespace_name ';'\n    ;\n    \nglobal_using_static_directive\n    : 'global' 'using' 'static' type_name ';'\n    ;\n```\n\n- The *global_using_directive*s are allowed only on the Compilation Unit level (cannot be used inside a *namespace_declaration*).\n- The *global_using_directive*s, if any, must precede any *using_directive*s. \n- The scope of a *global_using_directive*s extends over the *namespace_member_declaration*s of all compilation units within the program.\nThe scope of a *global_using_directive* specifically does not include other *global_using_directive*s. Thus, peer *global_using_directive*s or those from a different\ncompilation unit do not affect each other, and the order in which they are written is insignificant.\nThe scope of a *global_using_directive* specifically does not include *using_directive*s immediately contained in any compilation unit of the program.\n\nThe effect of adding a *global_using_directive* to a program can be thought of as the effect of adding a similar *using_directive* that resolves to the same target namespace or type to every compilation unit of the program. However, the target of a *global_using_directive* is resolved in context of the compilation unit that contains it. \n\n## [§7.7](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/basic-concepts.md#77-scopes)  Scopes\n\nThese are the relevant bullet points with proposed additions (which are **in bold**):\n*  The scope of name defined by an *extern_alias_directive* extends over the ***global_using_directive*s,** *using_directive*s, *global_attributes* and *namespace_member_declaration*s of its immediately containing compilation unit or namespace body. An *extern_alias_directive* does not contribute any new members to the underlying declaration space. In other words, an *extern_alias_directive* is not transitive, but, rather, affects only the compilation unit or namespace body in which it occurs.\n*  **The scope of a name defined or imported by a *global_using_directive* extends over the *global_attributes* and *namespace_member_declaration*s of all the *compilation_unit*s in the program.**\n\n## [§7.8](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#78-namespace-and-type-names)  Namespace and type names\n\nChanges are made to the algorithm determining the meaning of a *namespace_or_type_name* as follows.\n\nThis is the relevant bullet point with proposed additions (which are **in bold**):\n*   If the *namespace_or_type_name* is of the form `I` or of the form `I<A1, ..., Ak>`:\n    * If `K` is zero and the *namespace_or_type_name* appears within a generic method declaration ([§15.6](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#156-methods)) and if that declaration includes a type parameter ([§15.2.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#1523-type-parameters)) with name `I`, then the *namespace_or_type_name* refers to that type parameter.\n    * Otherwise, if the *namespace_or_type_name* appears within a type declaration, then for each instance type `T` ([§15.3.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#1532-the-instance-type)), starting with the instance type of that type declaration and continuing with the instance type of each enclosing class or struct declaration (if any):\n        * If `K` is zero and the declaration of `T` includes a type parameter with name `I`, then the *namespace_or_type_name* refers to that type parameter.\n        * Otherwise, if the *namespace_or_type_name* appears within the body of the type declaration, and `T` or any of its base types contain a nested accessible type having name `I` and `K` type parameters, then the *namespace_or_type_name* refers to that type constructed with the given type arguments. If there is more than one such type, the type declared within the more derived type is selected. Note that non-type members (constants, fields, methods, properties, indexers, operators, instance constructors, destructors, and static constructors) and type members with a different number of type parameters are ignored when determining the meaning of the *namespace_or_type_name*.\n    * If the previous steps were unsuccessful then, for each namespace `N`, starting with the namespace in which the *namespace_or_type_name* occurs, continuing with each enclosing namespace (if any), and ending with the global namespace, the following steps are evaluated until an entity is located:\n        * If `K` is zero and `I` is the name of a namespace in `N`, then:\n            * If the location where the *namespace_or_type_name* occurs is enclosed by a namespace declaration for `N` and the namespace declaration contains an *extern_alias_directive* or *using_alias_directive* that associates the name `I` with a namespace or type, **or any namespace declaration for `N` in the program contains a *global_using_alias_directive* that associates the name `I` with a namespace or type,** then the *namespace_or_type_name* is ambiguous and a compile-time error occurs.\n            * Otherwise, the *namespace_or_type_name* refers to the namespace named `I` in `N`.\n        * Otherwise, if `N` contains an accessible type having name `I` and `K` type parameters, then:\n            * If `K` is zero and the location where the *namespace_or_type_name* occurs is enclosed by a namespace declaration for `N` and the namespace declaration contains an *extern_alias_directive* or *using_alias_directive* that associates the name `I` with a namespace or type, **or any namespace declaration for `N` in the program contains a *global_using_alias_directive* that associates the name `I` with a namespace or type,** then the *namespace_or_type_name* is ambiguous and a compile-time error occurs.\n            * Otherwise, the *namespace_or_type_name* refers to the type constructed with the given type arguments.\n        * Otherwise, if the location where the *namespace_or_type_name* occurs is enclosed by a namespace declaration for `N`:\n            * If `K` is zero and the namespace declaration contains an *extern_alias_directive* or *using_alias_directive* that associates the name `I` with an imported namespace or type, **or any namespace declaration for `N` in the program contains a *global_using_alias_directive* that associates the name `I` with an imported namespace or type,** then the *namespace_or_type_name* refers to that namespace or type.\n            * Otherwise, if the namespaces and type declarations imported by the *using_namespace_directive*s and *using_alias_directive*s of the namespace declaration **and the namespaces and type declarations imported by the *global_using_namespace_directive*s and *global_using_static_directive*s of any namespace declaration for `N` in the program** contain exactly one accessible type having name `I` and `K` type parameters, then the *namespace_or_type_name* refers to that type constructed with the given type arguments.\n            * Otherwise, if the namespaces and type declarations imported by the *using_namespace_directive*s and *using_alias_directive*s of the namespace declaration **and the namespaces and type declarations imported by the *global_using_namespace_directive*s and *global_using_static_directive*s of any namespace declaration for `N` in the program** contain more than one accessible type having name `I` and `K` type parameters, then the *namespace_or_type_name* is ambiguous and an error occurs.\n    * Otherwise, the *namespace_or_type_name* is undefined and a compile-time error occurs.\n\n## Simple names [§12.8.4](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1284-simple-names)\n\nChanges are made to the *simple_name* evaluation rules as follows.\n\nThis is the relevant bullet point with proposed additions (which are **in bold**):\n*  Otherwise, for each namespace `N`, starting with the namespace in which the *simple_name* occurs, continuing with each enclosing namespace (if any), and ending with the global namespace, the following steps are evaluated until an entity is located:\n   *  If `K` is zero and `I` is the name of a namespace in `N`, then:\n      * If the location where the *simple_name* occurs is enclosed by a namespace declaration for `N` and the namespace declaration contains an *extern_alias_directive* or *using_alias_directive* that associates the name `I` with a namespace or type, **or any namespace declaration for `N` in the program contains a *global_using_alias_directive* that associates the name `I` with a namespace or type,** then the *simple_name* is ambiguous and a compile-time error occurs.\n      * Otherwise, the *simple_name* refers to the namespace named `I` in `N`.\n   *  Otherwise, if `N` contains an accessible type having name `I` and `K` type parameters, then:\n      * If `K` is zero and the location where the *simple_name* occurs is enclosed by a namespace declaration for `N` and the namespace declaration contains an *extern_alias_directive* or *using_alias_directive* that associates the name `I` with a namespace or type, **or any namespace declaration for `N` in the program contains a *global_using_alias_directive* that associates the name `I` with a namespace or type,** then the *simple_name* is ambiguous and a compile-time error occurs.\n      * Otherwise, the *namespace_or_type_name* refers to the type constructed with the given type arguments.\n   *  Otherwise, if the location where the *simple_name* occurs is enclosed by a namespace declaration for `N`:\n      * If `K` is zero and the namespace declaration contains an *extern_alias_directive* or *using_alias_directive* that associates the name `I` with an imported namespace or type, **or any namespace declaration for `N` in the program contains a *global_using_alias_directive* that associates the name `I` with an imported namespace or type,** then the *simple_name* refers to that namespace or type.\n      * Otherwise, if the namespaces and type declarations imported by the *using_namespace_directive*s and *using_static_directive*s of the namespace declaration **and the namespaces and type declarations imported by the *global_using_namespace_directive*s and *global_using_static_directive*s of any namespace declaration for `N` in the program** contain exactly one accessible type or non-extension static member having name `I` and `K` type parameters, then the *simple_name* refers to that type or member constructed with the given type arguments.\n      * Otherwise, if the namespaces and types imported by the *using_namespace_directive*s of the namespace declaration **and the namespaces and type declarations imported by the *global_using_namespace_directive*s and *global_using_static_directive*s of any namespace declaration for `N` in the program** contain more than one accessible type or non-extension-method static member having name `I` and `K` type parameters, then the *simple_name* is ambiguous and an error occurs.\n\n## Extension method invocations [§12.8.10.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#128103-extension-method-invocations)\n\nChanges are made to the algorithm to find the best *type_name* `C` as follows.\nThis is the relevant bullet point with proposed additions (which are **in bold**):\n*  Starting with the closest enclosing namespace declaration, continuing with each enclosing namespace declaration, and ending with the containing compilation unit, successive attempts are made to find a candidate set of extension methods:\n   * If the given namespace or compilation unit directly contains non-generic type declarations `Ci` with eligible extension methods `Mj`, then the set of those extension methods is the candidate set.\n   * If types `Ci` imported by *using_static_declarations* and directly declared in namespaces imported by *using_namespace_directive*s in the given namespace or compilation unit **and, if containing compilation unit is reached, imported by *global_using_static_declarations* and directly declared in namespaces imported by *global_using_namespace_directive*s in the program** directly contain eligible extension methods `Mj`, then the set of those extension methods is the candidate set.\n\n## Compilation units [§14.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/namespaces.md#142-compilation-units)\n\nA *compilation_unit* defines the overall structure of a source file. A compilation unit consists of **zero or more *global_using_directive*s followed by** zero or more *using_directive*s followed by zero or more *global_attributes* followed by zero or more *namespace_member_declaration*s.\n\n```antlr\ncompilation_unit\n    : extern_alias_directive* global_using_directive* using_directive* global_attributes? namespace_member_declaration*\n    ;\n```\n\nA C# program consists of one or more compilation units, each contained in a separate source file. When a C# program is compiled, all of the compilation units are processed together. Thus, compilation units can depend on each other, possibly in a circular fashion.\n\nThe *global_using_directive*s of a compilation unit affect the *global_attributes* and *namespace_member_declaration*s of all compilation units in the program.\n\n## Extern aliases [§14.4](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/namespaces.md#144-extern-alias-directives)\n\nThe scope of an *extern_alias_directive* extends over the ***global_using_directive*s,** *using_directive*s, *global_attributes* and *namespace_member_declaration*s of its immediately containing compilation unit or namespace body.\n\n## Using alias directives [§14.5.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/namespaces.md#1452-using-alias-directives)\n\nThe order in which *using_alias_directive*s are written has no significance, and resolution of the *namespace_or_type_name* referenced by a *using_alias_directive* is not affected by the *using_alias_directive* itself or by other *using_directive*s in the immediately containing compilation unit or namespace body, **and, if the *using_alias_directive* is immediately contained in a compilation unit, is not affected by the *global_using_directive*s in the program**. In other words, the *namespace_or_type_name* of a *using_alias_directive* is resolved as if the immediately containing compilation unit or namespace body had no *using_directive*s **and, if the *using_alias_directive* is immediately contained in a compilation unit, the program had no *global_using_directive*s**. A *using_alias_directive* may however be affected by *extern_alias_directive*s in the immediately containing compilation unit or namespace body.\n\n## Global Using alias directives\n\nA *global_using_alias_directive* introduces an identifier that serves as an alias for a namespace or type within the program.\n\n```antlr\nglobal_using_alias_directive\n    : 'global' 'using' identifier '=' namespace_or_type_name ';'\n    ;\n```\n\nWithin member declarations in any compilation unit of a program that contains a *global_using_alias_directive*, the identifier introduced by the *global_using_alias_directive* can be used to reference the given namespace or type.\n\nThe *identifier* of a *global_using_alias_directive* must be unique within the declaration space of any compilation unit of a program that contains the *global_using_alias_directive*.\n\nJust like regular members, names introduced by *global_using_alias_directive*s are hidden by similarly named members in nested scopes.\n\nThe order in which *global_using_alias_directive*s are written has no significance, and resolution of the *namespace_or_type_name* referenced by a *global_using_alias_directive* is not affected by the *global_using_alias_directive* itself or by other *global_using_directive*s or *using_directive*s in the program. In other words, the *namespace_or_type_name* of a *global_using_alias_directive* is resolved as if the immediately containing compilation unit had no *using_directive*s and the entire containing program had no *global_using_directive*s. A *global_using_alias_directive* may however be affected by *extern_alias_directive*s in the immediately containing compilation unit.\n\nA *global_using_alias_directive* can create an alias for any namespace or type.\n\nAccessing a namespace or type through an alias yields exactly the same result as accessing that namespace or type through its declared name.\n\nUsing aliases can name a closed constructed type, but cannot name an unbound generic type declaration without supplying type arguments.\n\n## Global Using namespace directives\n\nA *global_using_namespace_directive* imports the types contained in a namespace into the program, enabling the identifier of each type to be used without qualification.\n\n```antlr\nglobal_using_namespace_directive\n    : 'global' 'using' namespace_name ';'\n    ;\n```\n\nWithin member declarations in a program that contains a *global_using_namespace_directive*, the types contained in the given namespace can be referenced directly.\n\nA *global_using_namespace_directive* imports the types contained in the given namespace, but specifically does not import nested namespaces.\n\nUnlike a *global_using_alias_directive*, a *global_using_namespace_directive* may import types whose identifiers are already defined within a compilation unit of the program. In effect, in a given compilation unit, names imported by any *global_using_namespace_directive* in the program are hidden by similarly named members in the compilation unit.\n\nWhen more than one namespace or type imported by *global_using_namespace_directive*s or *global_using_static_directive*s in the same program contain types by the same name, references to that name as a *type_name* are considered ambiguous.\n\nFurthermore, when more than one namespace or type imported by *global_using_namespace_directive*s or *global_using_static_directive*s in the same program contain types or members by the same name, references to that name as a *simple_name* are considered ambiguous.\n\nThe *namespace_name* referenced by a *global_using_namespace_directive* is resolved in the same way as the *namespace_or_type_name* referenced by a *global_using_alias_directive*. Thus, *global_using_namespace_directive*s in the same program do not affect each other and can be written in any order.\n\n## Global Using static directives\n\nA *global_using_static_directive* imports the nested types and static members contained directly in a type declaration into the containing program, enabling the identifier of each member and type to be used without qualification.\n\n```antlr\nglobal_using_static_directive\n    : 'global' 'using' 'static' type_name ';'\n    ;\n```\n\nWithin member declarations in a program that contains a *global_using_static_directive*, the accessible nested types and static members (except extension methods) contained directly in the declaration of the given type can be referenced directly.\n\nA *global_using_static_directive* specifically does not import extension methods directly as static methods, but makes them available for extension method invocation.\n\nA *global_using_static_directive* only imports members and types declared directly in the given type, not members and types declared in base classes.\n\nAmbiguities between multiple *global_using_namespace_directive*s and *global_using_static_directives* are discussed in the section for *global_using_namespace_directive*s (above).\n\n## Qualified alias member [§14.8](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/namespaces.md#138-qualified-alias-member)\n\nChanges are made to the algorithm determining the meaning of a *qualified_alias_member* as follows.\n\nThis is the relevant bullet point with proposed additions (which are **in bold**):\n*  Otherwise, starting with the namespace declaration ([§14.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/namespaces.md#143-namespace-declarations)) immediately containing the *qualified_alias_member* (if any), continuing with each enclosing namespace declaration (if any), and ending with the compilation unit containing the *qualified_alias_member*, the following steps are evaluated until an entity is located:\n\n   * If the namespace declaration or compilation unit contains a *using_alias_directive* that associates `N` with a type, **or, when a compilation unit is reached, the program contains a *global_using_alias_directive* that associates `N` with a type,** then the *qualified_alias_member* is undefined and a compile-time error occurs.\n   * Otherwise, if the namespace declaration or compilation unit contains an *extern_alias_directive* or *using_alias_directive* that associates `N` with a namespace, ***or, when a compilation unit is reached, the program contains a *global_using_alias_directive* that associates `N` with a namespace,** then:\n     * If the namespace associated with `N` contains a namespace named `I` and `K` is zero, then the *qualified_alias_member* refers to that namespace.\n     * Otherwise, if the namespace associated with `N` contains a non-generic type named `I` and `K` is zero, then the *qualified_alias_member* refers to that type.\n     * Otherwise, if the namespace associated with `N` contains a type named `I` that has `K` type parameters, then the *qualified_alias_member* refers to that type constructed with the given type arguments.\n     * Otherwise, the *qualified_alias_member* is undefined and a compile-time error occurs.\n"
  },
  {
    "path": "proposals/csharp-10.0/async-method-builders.md",
    "content": "# AsyncMethodBuilder override\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/1407>\n\n## Summary\n[summary]: #summary\n\nAllow per-method override of the async method builder to use.\nFor some async methods we want to customize the invocation of `Builder.Create()` to use a different _builder type_.\n\n```C#\n[AsyncMethodBuilderAttribute(typeof(PoolingAsyncValueTaskMethodBuilder<>))] // new usage of AsyncMethodBuilderAttribute type\nstatic async ValueTask<int> ExampleAsync() { ... }\n```\n\n## Motivation\n[motivation]: #motivation\n\nToday, async method builders are tied to a given type used as a return type of an async method.  For example, any method that's declared as `async Task` uses `AsyncTaskMethodBuilder`, and any method that's declared as `async ValueTask<T>` uses `AsyncValueTaskMethodBuilder<T>`.  This is due to the `[AsyncMethodBuilder(Type)]` attribute on the type used as a return type, e.g. `ValueTask<T>` is attributed as `[AsyncMethodBuilder(typeof(AsyncValueTaskMethodBuilder<>))]`. This addresses the majority common case, but it leaves a few notable holes for advanced scenarios.\n\nIn .NET 5, an experimental feature was shipped that provides two modes in which `AsyncValueTaskMethodBuilder` and `AsyncValueTaskMethodBuilder<T>` operate.  The on-by-default mode is the same as has been there since the functionality was introduced: when the state machine needs to be lifted to the heap, an object is allocated to store the state, and the async method returns a `ValueTask{<T>}` backed by a `Task{<T>}`.  However, if an environment variable is set, all builders in the process switch to a mode where, instead, the `ValueTask{<T>}` instances are backed by reusable `IValueTaskSource{<T>}` implementations that are pooled.  Each async method has its own pool with a fixed maximum number of instances allowed to be pooled, and as long as no more than that number are ever returned to the pool to be pooled at the same time, `async ValueTask<{T}>` methods effectively become free of any GC allocation overhead.\n\nThere are several problems with this experimental mode, however, which is both why a) it's off by default and b) we're likely to remove it in a future release unless very compelling new information emerges (https://github.com/dotnet/runtime/issues/13633).\n- It introduces a behavioral difference for consumers of the returned `ValueTask{<T>}` if that `ValueTask` isn't being consumed according to spec.  When it's backed by a `Task`, you can do with the `ValueTask` things you can do with a `Task`, like await it multiple times, await it concurrently, block waiting for it to complete, etc.  But when it's backed by an arbitrary `IValueTaskSource`, such operations are prohibited, and automatically switching from the former to the latter can lead to bugs.  With the switch at the process level and affecting all `async ValueTask` methods in the process, whether you control them or not, it's too big a hammer.\n- It's not necessarily a performance win, and could represent a regression in some situations.  The implementation is trading the cost of pooling (accessing a pool isn't free) with the cost of GC, and in various situations the GC can win.  Again, applying the pooling to all `async ValueTask` methods in the process rather than being selective about the ones it would most benefit is too big a hammer.\n- It adds to the IL size of a trimmed application, even if the flag isn't set, and then to the resulting asm size.  It's possible that can be worked around with improvements to the implementation to teach it that for a given deployment the environment variable will always be false, but as it stands today, every `async ValueTask` method saw for example an ~2K binary footprint increase in aot images due to this option, and, again, that applies to all `async ValueTask` methods in the whole application closure.\n- Different methods may benefit from differing levels of control, e.g. the size of the pool employed because of knowledge of the method and how it's used, but the same setting is applied to all uses of the builder.  One could imagine working around that by having the builder code use reflection at runtime to look for some attribute, but that adds significant run-time expense, and likely on the startup path.\n\nOn top of all of these issues with the existing pooling, it's also the case that developers are prevented from writing their own customized builders for types they don't own.  If, for example, a developer wants to implement their own pooling support, they also have to introduce a brand new task-like type, rather than just being able to use `{Value}Task{<T>}`, because the attribute specifying the builder is only specifiable on the type declaration of the return type.\n\nWe need a way to have an individual async method opt-in to a specific builder.\n\n## Detailed design\n[design]: #detailed-design\n\n### Using AsyncMethodBuilderAttribute on methods\n\nIn `dotnet/runtime`, add `AttributeTargets.Method` to the targets for `System.Runtime.CompilerServices.AsyncMethodBuilderAttribute`:\n```csharp\nnamespace System.Runtime.CompilerServices\n{\n    /// <summary>\n    /// Indicates the type of the async method builder that should be used by a language compiler:\n    /// - to build the return type of an async method that is attributed,\n    /// - to build the attributed type when used as the return type of an async method.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Delegate | AttributeTargets.Enum, Inherited = false, AllowMultiple = false)]\n    public sealed class AsyncMethodBuilderAttribute : Attribute\n    {\n        /// <summary>Initializes the <see cref=\"AsyncMethodBuilderAttribute\"/>.</summary>\n        /// <param name=\"builderType\">The <see cref=\"Type\"/> of the associated builder.</param>\n        public AsyncMethodBuilderAttribute(Type builderType) => BuilderType = builderType;\n\n        /// <summary>Gets the <see cref=\"Type\"/> of the associated builder.</summary>\n        public Type BuilderType { get; }\n    }\n}\n```\n\nThis allows the attribute to be applied on methods or local functions or lambdas.\n\nExample of usage on a method:  \n```C#\n[AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder<>))] // new usage, referring to some custom builder type\nstatic async ValueTask<int> ExampleAsync() { ... }\n```\n\nIt is an error to apply the attribute multiple times on a given method.  \nIt is an error to apply the attribute to a lambda with an implicit return type.  \n\nA developer who wants to use a specific custom builder for all of their methods can do so by putting the relevant attribute on each method.  \n\n### Determining the builder type for an async method\n\nWhen compiling an async method, the builder type is determined by:\n1. using the builder type from the `AsyncMethodBuilder` attribute if one is present,\n2. otherwise, falling back to the builder type determined by previous approach. (see [spec for task-like types](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/task-types.md)).  \n\nIf an `AsyncMethodBuilder` attribute is present, we take the builder type specified by the attribute and construct it if necessary.  \n  If the override type is an open generic type, take the single type argument of the async method's return type and substitute it into the override type.  \n  If the override type is a bound generic type, then we produce an error.  \n  If the async method's return type does not have a single type argument, then we produce an error.  \n\nWe verify that the builder type is compatible with the return type of the async method:\n1. look for the public `Create` method with no type parameters and no parameters on the constructed builder type.  \n  It is an error if the method is not found.\n  It is an error if the method returns a type other than the constructed builder type.  \n2. look for the public `Task` property.  \n  It is an error if the property is not found.\n3. consider the type of that `Task` property (a task-like type):  \n  It is an error if the task-like type does not matches the return type of the async method.\n\nNote that it is not necessary for the return type of the method to be a task-like type.\n\n### Execution \n\nThe builder type determined above is used as part of the existing async method design.\n\nFor example, today if a method is defined as:\n```C#\npublic async ValueTask<T> ExampleAsync() { ... }\n```\nthe compiler will generate code akin to:\n```C#\n[AsyncStateMachine(typeof(<ExampleAsync>d__29))]\n[CompilerGenerated]\nstatic ValueTask<int> ExampleAsync()\n{\n    <ExampleAsync>d__29 stateMachine;\n    stateMachine.<>t__builder = AsyncValueTaskMethodBuilder<int>.Create();\n    stateMachine.<>1__state = -1;\n    stateMachine.<>t__builder.Start(ref stateMachine);\n    return stateMachine.<>t__builder.Task;\n}\n```\n\nWith this change, if the developer wrote:\n```C#\n[AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder<>))] // new usage, referring to some custom builder type\nstatic async ValueTask<int> ExampleAsync() { ... }\n```\nit would instead be compiled to:\n```C#\n[AsyncStateMachine(typeof(<ExampleAsync>d__29))]\n[CompilerGenerated]\n[AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder<>))] // retained but not necessary anymore\nstatic ValueTask<int> ExampleAsync()\n{\n    <ExampleAsync>d__29 stateMachine;\n    stateMachine.<>t__builder = PoolingAsyncValueTaskMethodBuilder<int>.Create(); // <>t__builder now a different type\n    stateMachine.<>1__state = -1;\n    stateMachine.<>t__builder.Start(ref stateMachine);\n    return stateMachine.<>t__builder.Task;\n}\n```\n\nJust those small additions enable:\n- Anyone to write their own builder that can be applied to async methods that return `Task<T>` and `ValueTask<T>`\n- As \"anyone\", the runtime to ship the experimental builder support as new public builder types that can be opted into on a method-by-method basis; the existing support would be removed from the existing builders.  Methods (including some we care about in the core libraries) can then be attributed on a case-by-case basis to use the pooling support, without impacting any other unattributed methods.\n\nand with minimal surface area changes or feature work in the compiler.\n\n\nNote that we need the emitted code to allow a different type being returned from `Create` method:\n```\nAsyncPooledBuilder _builder = AsyncPooledBuilderWithSize4.Create();\n```\n\nNote that this mechanism to change the the builder type cannot be used when the synthesized entry-point for top-level statements is async. An explicit entry-point should be used instead.  \n\n## Drawbacks\n[drawbacks]: #drawbacks\n\n* The syntax for applying such an attribute to a method is verbose.  The impact of this is lessened if a developer can apply it to multiple methods en mass, e.g. at the type or module level.\n\n## Alternatives\n[alternatives]: #alternatives\n\n- Implement a different task-like type and expose that difference to consumers.  `ValueTask` was made extensible via the `IValueTaskSource` interface to avoid that need, however.\n- Address just the ValueTask pooling part of the issue by enabling the experiment as the on-by-default-and-only implementation.  That doesn't address other aspects, such as configuring the pooling, or enabling someone else to provide their own builder.\n- Earlier versions of this document allowed for scoped override of builder types.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n1. **Replace or also create.** All of the examples in this proposal are about replacing a buildable task-like's builder.  Should the feature be scoped to just that? Or should you be able to use this attribute on a method with a return type that doesn't already have a builder (e.g. some common interface)?  That could impact overload resolution.\n2. **Private Builders**. Should the compiler support non-public async method builders? This is not spec'd today, but experimentally we only support public ones.  That makes some sense when the attribute is applied to a type to control what builder is used with that type, since anyone writing an async method with that type as the return type would need access to the builder.  However, with this new feature, when that attribute is applied to a method, it only impacts the implementation of that method, and thus could reasonably reference a non-public builder.  Likely we will want to support library authors who have non-public ones they want to use.\n"
  },
  {
    "path": "proposals/csharp-10.0/caller-argument-expression.md",
    "content": "# CallerArgumentExpression\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/287>\n\n## Summary\n[summary]: #summary\n\nAllow developers to capture the expressions passed to a method, to enable better error messages in diagnostic/testing APIs and reduce keystrokes.\n\n## Motivation\n[motivation]: #motivation\n\nWhen an assertion or argument validation fails, the developer wants to know as much as possible about where and why it failed. However, today's diagnostic APIs do not fully facilitate this. Consider the following method:\n\n```csharp\nT Single<T>(this T[] array)\n{\n    Debug.Assert(array != null);\n    Debug.Assert(array.Length == 1);\n\n    return array[0];\n}\n```\n\nWhen one of the asserts fail, only the filename, line number, and method name will be provided in the stack trace. The developer will not be able to tell which assert failed from this information-- they will have to open the file and navigate to the provided line number to see what went wrong.\n\nThis is also the reason testing frameworks have to provide a variety of assert methods. With xUnit, `Assert.True` and `Assert.False` are not frequently used because they do not provide enough context about what failed.\n\nWhile the situation is a bit better for argument validation because the names of invalid arguments are shown to the developer, the developer must pass these names to exceptions manually. If the above example were rewritten to use traditional argument validation instead of `Debug.Assert`, it would look like\n\n```csharp\nT Single<T>(this T[] array)\n{\n    if (array == null)\n    {\n        throw new ArgumentNullException(nameof(array));\n    }\n\n    if (array.Length != 1)\n    {\n        throw new ArgumentException(\"Array must contain a single element.\", nameof(array));\n    }\n\n    return array[0];\n}\n```\n\nNotice that `nameof(array)` must be passed to each exception, although it's already clear from context which argument is invalid.\n\n## Detailed design\n[design]: #detailed-design\n\nIn the above examples, including the string `\"array != null\"` or `\"array.Length == 1\"` in the assert message would help the developer determine what failed. Enter `CallerArgumentExpression`: it's an attribute the framework can use to obtain the string associated with a particular method argument. We would add it to `Debug.Assert` like so\n\n```csharp\npublic static class Debug\n{\n    public static void Assert(bool condition, [CallerArgumentExpression(\"condition\")] string message = null);\n}\n```\n\nThe source code in the above example would stay the same. However, the code the compiler actually emits would correspond to\n\n```csharp\nT Single<T>(this T[] array)\n{\n    Debug.Assert(array != null, \"array != null\");\n    Debug.Assert(array.Length == 1, \"array.Length == 1\");\n\n    return array[0];\n}\n```\n\nThe compiler specially recognizes the attribute on `Debug.Assert`. It passes the string associated with the argument referred to in the attribute's constructor (in this case, `condition`) at the call site. When either assert fails, the developer will be shown the condition that was false and will know which one failed.\n\nFor argument validation, the attribute cannot be used directly, but can be made use of through a helper class:\n\n```csharp\npublic static class Verify\n{\n    public static void Argument(bool condition, string message, [CallerArgumentExpression(\"condition\")] string conditionExpression = null)\n    {\n        if (!condition) throw new ArgumentException(message: message, paramName: conditionExpression);\n    }\n\n    public static void InRange(int argument, int low, int high,\n        [CallerArgumentExpression(\"argument\")] string argumentExpression = null,\n        [CallerArgumentExpression(\"low\")] string lowExpression = null,\n        [CallerArgumentExpression(\"high\")] string highExpression = null)\n    {\n        if (argument < low)\n        {\n            throw new ArgumentOutOfRangeException(paramName: argumentExpression,\n                message: $\"{argumentExpression} ({argument}) cannot be less than {lowExpression} ({low}).\");\n        }\n\n        if (argument > high)\n        {\n            throw new ArgumentOutOfRangeException(paramName: argumentExpression,\n                message: $\"{argumentExpression} ({argument}) cannot be greater than {highExpression} ({high}).\");\n        }\n    }\n\n    public static void NotNull<T>(T argument, [CallerArgumentExpression(\"argument\")] string argumentExpression = null)\n        where T : class\n    {\n        if (argument == null) throw new ArgumentNullException(paramName: argumentExpression);\n    }\n}\n\nstatic T Single<T>(this T[] array)\n{\n    Verify.NotNull(array); // paramName: \"array\"\n    Verify.Argument(array.Length == 1, \"Array must contain a single element.\"); // paramName: \"array.Length == 1\"\n\n    return array[0];\n}\n\nstatic T ElementAt<T>(this T[] array, int index)\n{\n    Verify.NotNull(array); // paramName: \"array\"\n    // paramName: \"index\"\n    // message: \"index (-1) cannot be less than 0 (0).\", or\n    //          \"index (6) cannot be greater than array.Length - 1 (5).\"\n    Verify.InRange(index, 0, array.Length - 1);\n\n    return array[index];\n}\n```\n\nA proposal to add such a helper class to the framework is underway at https://github.com/dotnet/corefx/issues/17068. If this language feature was implemented, the proposal could be updated to take advantage of this feature.\n\n### Extension methods\n\nThe `this` parameter in an extension method may be referenced by `CallerArgumentExpression`. For example:\n\n```csharp\npublic static void ShouldBe<T>(this T @this, T expected, [CallerArgumentExpression(\"this\")] string thisExpression = null) {}\n\ncontestant.Points.ShouldBe(1337); // thisExpression: \"contestant.Points\"\n```\n\n`thisExpression` will receive the expression corresponding to the object before the dot. If it's called with static method syntax, e.g. `Ext.ShouldBe(contestant.Points, 1337)`, it will behave as if first parameter wasn't marked `this`.\n\nThere should always be an expression corresponding to the `this` parameter. Even if an instance of a class calls an extension method on itself, e.g. `this.Single()` from inside a collection type, the `this` is mandated by the compiler so `\"this\"` will get passed. If this rule is changed in the future, we can consider passing `null` or the empty string.\n\n### Extra details\n\n- Like the other `Caller*` attributes, such as `CallerMemberName`, this attribute may only be used on parameters with default values.\n- Multiple parameters marked with `CallerArgumentExpression` are permitted, as shown above.\n- The attribute's namespace will be `System.Runtime.CompilerServices`.\n- If `null` or a string that is not a parameter name (e.g. `\"notAParameterName\"`) is provided, the compiler will pass in an empty string.\n- The type of the parameter `CallerArgumentExpressionAttribute` is applied to must have a standard conversion from `string`. This means no user-defined conversions from `string` are allowed, and in practice means the type of such a parameter must be `string`, `object`, or an interface implemented by `string`.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\n- People who know how to use decompilers will be able to see some of the source code at call sites for methods marked with this attribute. This may be undesirable/unexpected for closed-source software.\n\n- Although this is not a flaw in the feature itself, a source of concern may be that there exists a `Debug.Assert` API today that only takes a `bool`. Even if the overload taking a message had its second parameter marked with this attribute and made optional, the compiler would still pick the no-message one in overload resolution. Therefore, the no-message overload would have to be removed to take advantage of this feature, which would be a binary (although not source) breaking change.\n\n## Alternatives\n[alternatives]: #alternatives\n\n- If being able to see source code at call sites for methods that use this attribute proves to be a problem, we can make the attribute's effects opt-in. Developers will enable it through an assembly-wide `[assembly: EnableCallerArgumentExpression]` attribute they put in `AssemblyInfo.cs`.\n  - In the case the attribute's effects are not enabled, calling methods marked with the attribute would not be an error, to allow existing methods to use the attribute and maintain source compatibility. However, the attribute would be ignored and the method would be called with whatever default value was provided.\n\n```csharp\n// Assembly1\n\nvoid Foo(string bar); // V1\nvoid Foo(string bar, string barExpression = \"not provided\"); // V2\nvoid Foo(string bar, [CallerArgumentExpression(\"bar\")] string barExpression = \"not provided\"); // V3\n\n// Assembly2\n\nFoo(a); // V1: Compiles to Foo(a), V2, V3: Compiles to Foo(a, \"not provided\")\nFoo(a, \"provided\"); // V2, V3: Compiles to Foo(a, \"provided\")\n\n// Assembly3\n\n[assembly: EnableCallerArgumentExpression]\n\nFoo(a); // V1: Compiles to Foo(a), V2: Compiles to Foo(a, \"not provided\"), V3: Compiles to Foo(a, \"a\")\nFoo(a, \"provided\"); // V2, V3: Compiles to Foo(a, \"provided\")\n```\n\n- To prevent the [binary compatibility problem][drawbacks] from occurring every time we want to add new caller info to `Debug.Assert`, an alternative solution would be to add a `CallerInfo` struct to the framework that contains all the necessary information about the caller.\n\n```csharp\nstruct CallerInfo\n{\n    public string MemberName { get; set; }\n    public string TypeName { get; set; }\n    public string Namespace { get; set; }\n    public string FullTypeName { get; set; }\n    public string FilePath { get; set; }\n    public int LineNumber { get; set; }\n    public int ColumnNumber { get; set; }\n    public Type Type { get; set; }\n    public MethodBase Method { get; set; }\n    public string[] ArgumentExpressions { get; set; }\n}\n\n[Flags]\nenum CallerInfoOptions\n{\n    MemberName = 1, TypeName = 2, ...\n}\n\npublic static class Debug\n{\n    public static void Assert(bool condition,\n        // If a flag is not set here, the corresponding CallerInfo member is not populated by the caller, so it's\n        // pay-for-play friendly.\n        [CallerInfo(CallerInfoOptions.FilePath | CallerInfoOptions.Method | CallerInfoOptions.ArgumentExpressions)] CallerInfo callerInfo = default(CallerInfo))\n    {\n        string filePath = callerInfo.FilePath;\n        MethodBase method = callerInfo.Method;\n        string conditionExpression = callerInfo.ArgumentExpressions[0];\n        //...\n    }\n}\n\nclass Bar\n{\n    void Foo()\n    {\n        Debug.Assert(false);\n\n        // Translates to:\n\n        var callerInfo = new CallerInfo();\n        callerInfo.FilePath = @\"C:\\Bar.cs\";\n        callerInfo.Method = MethodBase.GetCurrentMethod();\n        callerInfo.ArgumentExpressions = new string[] { \"false\" };\n        Debug.Assert(false, callerInfo);\n    }\n}\n```\n\nThis was originally proposed at https://github.com/dotnet/csharplang/issues/87.\n\nThere are a few disadvantages of this approach:\n\n- Despite being pay-for-play friendly by allowing you to specify which properties you need, it could still hurt perf significantly by allocating an array for the expressions/calling `MethodBase.GetCurrentMethod` even when the assert passes.\n\n- Additionally, while passing a new flag to the `CallerInfo` attribute won't be a breaking change, `Debug.Assert` won't be guaranteed to actually receive that new parameter from call sites that compiled against an old version of the method.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\nTBD\n\n## Design meetings\n\nN/A\n"
  },
  {
    "path": "proposals/csharp-10.0/constant_interpolated_strings.md",
    "content": "# Constant Interpolated Strings\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/2951>\n\n## Summary\n[summary]: #summary\n\nEnables constants to be generated from interpolated strings of type string constant.\n\n## Motivation\n[motivation]: #motivation\n\nThe following code is already legal:\n```\npublic class C\n{\n    const string S1 = \"Hello world\";\n    const string S2 = \"Hello\" + \" \" + \"World\";\n    const string S3 = S1 + \" Kevin, welcome to the team!\";\n}\n```\nHowever, there have been many community requests to make the following also legal:\n```\npublic class C\n{\n    const string S1 = $\"Hello world\";\n    const string S2 = $\"Hello{\" \"}World\";\n    const string S3 = $\"{S1} Kevin, welcome to the team!\";\n}\n```\nThis proposal represents the next logical step for constant string generation, where existing string syntax that works in other situations is made to work for constants.\n\n## Detailed design\n[design]: #detailed-design\n\nThe following represent the updated specifications for constant expressions under this new proposal. Current specifications from which this was directly based on can be found in [§12.23](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1223-constant-expressions).\n\n### Constant Expressions\n\nA *constant_expression* is an expression that can be fully evaluated at compile-time.\n\n```antlr\nconstant_expression\n    : expression\n    ;\n```\n\nA constant expression must be the `null` literal or a value with one of  the following types: `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `char`, `float`, `double`, `decimal`, `bool`, `object`, `string`, or any enumeration type. Only the following constructs are permitted in constant expressions:\n\n*  Literals (including the `null` literal).\n*  References to `const` members of class and struct types.\n*  References to members of enumeration types.\n*  References to `const` parameters or local variables\n*  Parenthesized sub-expressions, which are themselves constant expressions.\n*  Cast expressions, provided the target type is one of the types listed above.\n*  `checked` and `unchecked` expressions\n*  Default value expressions\n*  Nameof expressions\n*  The predefined `+`, `-`, `!`, and `~` unary operators.\n*  The predefined `+`, `-`, `*`, `/`, `%`, `<<`, `>>`, `&`, `|`, `^`, `&&`, `||`, `==`, `!=`, `<`, `>`, `<=`, and `>=` binary operators, provided each operand is of a type listed above.\n*  The `?:` conditional operator.\n*  *Interpolated strings `${}`, provided that all components are constant expressions of type `string` and all interpolated components lack alignment and format specifiers.*\n\nThe following conversions are permitted in constant expressions:\n\n*  Identity conversions\n*  Numeric conversions\n*  Enumeration conversions\n*  Constant expression conversions\n*  Implicit and explicit reference conversions, provided that the source of the conversions is a constant expression that evaluates to the null value.\n\nOther conversions including boxing, unboxing and implicit reference conversions of non-null values are not permitted in constant expressions. For example:\n```csharp\nclass C \n{\n    const object i = 5;         // error: boxing conversion not permitted\n    const object str = \"hello\"; // error: implicit reference conversion\n}\n```\nthe initialization of i is an error because a boxing conversion is required. The initialization of str is an error because an implicit reference conversion from a non-null value is required.\n\nWhenever an expression fulfills the requirements listed above, the expression is evaluated at compile-time. This is true even if the expression is a sub-expression of a larger expression that contains non-constant constructs.\n\nThe compile-time evaluation of constant expressions uses the same rules as run-time evaluation of non-constant expressions, except that where run-time evaluation would have thrown an exception, compile-time evaluation causes a compile-time error to occur.\n\nUnless a constant expression is explicitly placed in an `unchecked` context, overflows that occur in integral-type arithmetic operations and conversions during the compile-time evaluation of the expression always cause compile-time errors ([§12.23](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1223-constant-expressions)).\n\nConstant expressions occur in the contexts listed below. In these contexts, a compile-time error occurs if an expression cannot be fully evaluated at compile-time.\n\n*  Constant declarations ([§15.4](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#154-constants)).\n*  Enumeration member declarations ([§19.4](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/enums.md#194-enum-members)).\n*  Default arguments of formal parameter lists ([§15.6.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#1562-method-parameters))\n*  `case` labels of a `switch` statement ([§13.8.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md#1383-the-switch-statement)).\n*  `goto case` statements ([§13.10.4](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md#13104-the-goto-statement)).\n*  Dimension lengths in an array creation expression ([§12.8.17.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#128175-array-creation-expressions)) that includes an initializer.\n*  Attributes ([§22](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/attributes.md#22-attributes)).\n\nAn implicit constant expression conversion ([§10.2.11](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#10211-implicit-constant-expression-conversions)) permits a constant expression of type `int` to be converted to `sbyte`, `byte`, `short`, `ushort`, `uint`, or `ulong`, provided the value of the constant expression is within the range of the destination type.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nThis proposal adds additional complexity to the compiler in exchange for broader applicability of interpolated strings. As these strings are fully evaluated at compile time, the valuable automatic formatting features of interpolated strings are less neccesary. Most use cases can be largely replicated through the alternatives below.\n\n## Alternatives\n[alternatives]: #alternatives\n\nThe current `+` operator for string concatenation can combine strings in a similar manner to the current proposal.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\nWhat parts of the design are still undecided?\n\n## Design meetings\n\nLink to design notes that affect this proposal, and describe in one sentence for each what changes they led to.\n\n\n"
  },
  {
    "path": "proposals/csharp-10.0/enhanced-line-directives.md",
    "content": "# Enhanced #line directives\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/4747>\n\n## Summary\n[summary]: #summary \nThe compiler applies the mapping defined by `#line` directives to diagnostic locations and sequence points emitted to the PDB.\n\nCurrently only the line number and file path can be mapped while the starting character is inferred from the source code. The proposal is to allow specifying full span mapping.\n\n## Motivation\n[motivation]: #motivation\n\nDSLs that generate C# source code (such as ASP.NET Razor) can't currently produce precise source mapping using `#line` directives. This results in degraded debugging experience in some cases as the sequence points emitted to the PDB can't map to the precise location in the original source code.\n\nFor example, the following Razor code\n```\n@page \"/\"\nTime: @DateTime.Now\n```\n\ngenerates code like so (simplified):\n\n```C#\n#line hidden\nvoid Render()\n{\n   _builder.Add(\"Time:\");\n#line 2 \"page.razor\"\n   _builder.Add(DateTime.Now);\n#line hidden\n}\n```\n\nThe above directive would map the sequence point emitted by the compiler for the `_builder.Add(DateTime.Now);` statement to the line 2, but the column would be off (16 instead of 7).\n\nThe Razor source generator actually incorrectly generates the following code:\n```C#\n#line hidden\nvoid Render()\n{\n   _builder.Add(\"Time:\");\n   _builder.Add(\n#line 2 \"page.razor\"\n      DateTime.Now\n#line hidden\n);\n}\n```\n\nThe intent was to preserve the starting character and it works for diagnostic location mapping. However, this does not work for sequence points since `#line` directive only applies to the sequence points that follow it. There is no sequence point in the middle of the  `_builder.Add(DateTime.Now);` statement (sequence points can only be emitted at IL instructions with empty evaluation stack). The `#line 2` directive in above code thus has no effect on the generated PDB and the debugger won't place a breakpoint or stop on the `@DateTime.Now` snippet in the Razor page. \n\nIssues addressed by this proposal: \nhttps://github.com/dotnet/roslyn/issues/43432\nhttps://github.com/dotnet/roslyn/issues/46526\n\n## Detailed design\n[design]: #detailed-design\n\nWe amend the syntax of `line_indicator` used in `pp_line` directive like so:\n\nCurrent:\n```\nline_indicator\n    : decimal_digit+ whitespace file_name\n    | decimal_digit+\n    | 'default'\n    | 'hidden'\n    ;\n```\n\nProposed:\n```\nline_indicator\n    : '(' decimal_digit+ ',' decimal_digit+ ')' '-' '(' decimal_digit+ ',' decimal_digit+ ')' whitespace decimal_digit+ whitespace file_name\n    | '(' decimal_digit+ ',' decimal_digit+ ')' '-' '(' decimal_digit+ ',' decimal_digit+ ')' whitespace file_name\n    | decimal_digit+ whitespace file_name\n    | decimal_digit+\n    | 'default'\n    | 'hidden'\n    ;\n```\n\nThat is, the `#line` directive would accept either 5 decimal numbers (_start line_, _start character_, _end line_, _end character_, _character offset_), \n4 decimal numbers (_start line_, _start character_, _end line_, _end character_), or a single one (_line_).\n\nIf _character offset_ is not specified its default value is 0, otherwise it specifies the number of UTF-16 characters. The number must be non-negative and less then length of the line following the #line directive in the unmapped file.\n\n(_start line_, _start character_)-(_end line_, _end character_) specifies a span in the mapped file. _start line_ and _end line_ are positive integers that specify line numbers. _start character_, _end character_ are positive integers that specify UTF-16 character numbers. _start line_, _start character_, _end line_, _end character_ are 1-based, meaning that the first line of the file and the first UTF-16 character on each line is assigned number 1.\n\n> The implementation would constraint these numbers so that they specify a valid [sequence point source span](https://github.com/dotnet/runtime/blob/main/docs/design/specs/PortablePdb-Metadata.md#sequence-points-blob):\n> - _start line_ - 1 is within range [0, 0x20000000) and not equal to 0xfeefee.\n> - _end line_ - 1 is within range [0, 0x20000000) and not equal to 0xfeefee.\n> - _start character_ - 1 is within range [0, 0x10000)\n> - _end character_ - 1 is within range [0, 0x10000)\n> - _end line_ is greater or equal to _start line_.\n> - _start line_ is equal to _end line_ then _end character_ is greater than _start character_.\n\n> Note that the numbers specified in the directive syntax are 1-based numbers but the actual spans in the PDB are zero-based. Hence the -1 adjustments above.\n\nThe mapped spans of sequence points and the locations of diagnostics that `#line` directive applies to are calculated as follows.\n\nLet _d_ be the zero-based number of the unmapped line containing the `#line` directive.\nLet span L = (start: (_start line_ - 1, _start character_ - 1), end: (_end line_ - 1, _end character_ - 1)) be zero-based span specified by the directive.\n\nFunction M that maps a position (line, character) within the scope of the `#line` directive in the source file containing the #line directive to a mapped position (mapped line, mapped character) is defined as follows:\n\n_M_(_l_, _c_) =\n\n  _l_ == _d_ + 1 => (_L.start.line_ + _l_ – _d_ – 1, _L.start.character_ + max(_c_ – _character offset_, 0))\n\n  _l_ > _d_ + 1 => (_L.start.line_ + _l_ – _d_ – 1, _c_)\n\nThe syntax constructs that sequence points are associated with are determined by the compiler implementation and not covered by this specification.\nThe compiler also decides for each sequence point its unmapped span. This span may partially or fully cover the associated syntax construct.\n\nOnce the unmapped spans are determined by the compiler the function _M_ defined above is applied to their starting and ending positions, with the exception of the ending position of all sequence points within the scope of the #line directive whose unmapped location is at line _d_ + 1 and character less than character offset. The end position of all these sequence points is _L.end_.\n\n> Example [5.i] demonstrates why it is necessary to provide the ability to specify the end position of the first sequence point span.\n\n> The above definition allows the generator of the unmapped source code to avoid intimate knowledge of which exact source constructs of the C# language produce sequence points. The mapped spans of the sequence points in the scope of the `#line` directive are derived from the relative position of the corresponding unmapped spans to the first unmapped span.\n\n> Specifying the _character offset_ allows the generator to insert any single-line prefix on the first line. This prefix is generated code that is not present in the mapped file. Such inserted prefix affects the value of the first unmapped sequence point span. Therefore the starting character of subsequent sequence point spans need to be offset by the length of the prefix (_character offset_). See example [2].\n\n![image](https://user-images.githubusercontent.com/41759/120511514-563c7e00-c37f-11eb-9436-20c2def68932.png)\n\n### Examples\n\nFor clarity the examples use `spanof('...')` and `lineof('...')` pseudo-syntax to express the mapped span start position and line number, respectively, of the specified code snippet.\n\n#### 1. First and subsequent spans\n\nConsider the following code with unmapped zero-based line numbers listed on the right:\n\n```\n#line (1,10)-(1,15) \"a\" // 3\n  A();B(                // 4\n);C();                  // 5\n    D();                // 6\n ```\n\nd = 3\nL = (0, 9)..(0, 14)\n\nThere are 4 sequence point spans the directive applies to with following unmapped and mapped spans:\n(4, 2)..(4, 5) => (0, 9)..(0, 14)\n(4, 6)..(5, 1) => (0, 15)..(1, 1)\n(5, 2)..(5, 5) => (1, 2)..(1, 5)\n(6, 4)..(6, 7) => (2, 4)..(2, 7)\n\n#### 2. Character offset\n\nRazor generates `  _builder.Add(` prefix of length 15 (including two leading spaces).\n\nRazor:\n```\n@page \"/\"                                  \n@F(() => 1+1, \n   () => 2+2\n) \n```\n\nGenerated C#:\n```C#\n#line hidden\nvoid Render()            \n{ \n#line spanof('F(...)') 15 \"page.razor\"  // 4\n  _builder.Add(F(() => 1+1,            // 5\n  () => 2+2                            // 6\n));                                    // 7\n#line hidden\n}\n);\n}\n```\n\nd = 4\nL = (1, 1)..(3,0)\n_character offset_ = 15\n\nSpans: \n- `_builder.Add(F(…));` => `F(…)`: (5, 2)..(7, 2) => (1, 1)..(3, 0)\n- `1+1` => `1+1`: (5, 23)..(5, 25) => (1, 9)..(1, 11)                                     \n- `2+2` => `2+2`: (6, 7)..(6, 9) => (2, 7)..(2, 9)\n\n#### 3. Razor: Single-line span\n\nRazor:\n```\n@page \"/\"\nTime: @DateTime.Now\n```\n\nGenerated C#:\n```C#\n#line hidden\nvoid Render()\n{\n  _builder.Add(\"Time:\");\n#line spanof('DateTime.Now') 15 \"page.razor\"\n  _builder.Add(DateTime.Now);\n#line hidden\n);\n}\n```\n\n#### 4. Razor: Multi-line span\n\nRazor:\n```\n@page \"/\"                                  \n@JsonToHtml(@\"\n{\n  \"\"key1\"\": \"value1\",\n  \"\"key2\"\": \"value2\"\n}\") \n```\n\nGenerated C#:\n```C#\n#line hidden\nvoid Render()\n{\n  _builder.Add(\"Time:\");\n#line spanof('JsonToHtml(@\"...\")') 15 \"page.razor\"\n  _builder.Add(JsonToHtml(@\"\n{\n  \"\"key1\"\": \"value1\",\n  \"\"key2\"\": \"value2\"\n}\"));\n#line hidden\n}\n);\n}\n```\n\n#### 5. Razor: block constructs\n\n##### i. block containing expressions\n\nIn this example, the mapped span of the first sequence point that is associated with the IL instruction that is emitted for the `_builder.Add(Html.Helper(() => ` statement\nneeds to cover the whole expression of `Html.Helper(...)` in the generated file `a.razor`. This is achieved by application of rule [1] to the end position of the sequence point.\n\n```\n@Html.Helper(() => \n{\n    <p>Hello World</p>\n    @DateTime.Now\n})\n```\n\n```C#\n#line spanof('Html.Helper(() => { ... })') 13 \"a.razor\"\n_builder.Add(Html.Helper(() => \n#line lineof('{') \"a.razor\"\n{\n#line spanof('DateTime.Now') 13 \"a.razor\"\n_builder.Add(DateTime.Now);\n#line lineof('}') \"a.razor\"\n}\n#line hidden\n)\n```\n\n##### ii. block containing statements\n\nUses existing `#line line file` form since\n\na) Razor does not add any prefix,\nb) `{` is not present in the generated file and there can't be a sequence point placed on it, therefore the span of the first unmapped sequence point is unknown to Razor.\n\nThe starting character of `Console` in the generated file must be aligned with the Razor file.\n\n```\n@{Console.WriteLine(1);Console.WriteLine(2);}\n```\n\n```C#\n#line lineof('@{') \"a.razor\"\n  Console.WriteLine(1);Console.WriteLine(2);\n#line hidden\n```\n\n##### iii. block containing top-level code (@code, @functions)\n\nUses existing `#line line file` form since\n\na) Razor does not add any prefix,\nb) `{` is not present in the generated file and there can't be a sequence point placed on it, therefore the span of the first unmapped sequence point is unknown to Razor.\n\nThe starting character of `[Parameter]` in the generated file must be aligned with the Razor file.\n\n```\n@code {\n    [Parameter]\n    public int IncrementAmount { get; set; }\n}\n```\n\n```C#\n#line lineof('[') \"a.razor\"\n    [Parameter]\n    public int IncrementAmount { get; set; }\n#line hidden\n```\n\n#### 6. Razor: `@for`, `@foreach`, `@while`, `@do`, `@if`, `@switch`, `@using`, `@try`, `@lock`\n\nUses existing `#line line file` form since\na) Razor does not add any prefix. \nb) the span of the first unmapped sequence point may not be known to Razor (or shouldn't need to know).\n\nThe starting character of the keyword in the generated file must be aligned with the Razor file.\n\n```\n@for (var i = 0; i < 10; i++)\n{\n}\n@if (condition)\n{\n}\nelse\n{\n}\n```\n\n```C#\n#line lineof('for') \"a.razor\"\n for (var i = 0; i < 10; i++)\n{\n}\n#line lineof('if') \"a.razor\"\n if (condition)\n{\n}\nelse\n{\n}\n#line hidden\n```\n"
  },
  {
    "path": "proposals/csharp-10.0/extended-property-patterns.md",
    "content": "# Extended property patterns\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/4394>\n\n## Summary\n[summary]: #summary\n\nAllow property subpatterns to reference nested members, for instance:\n```cs\nif (e is MethodCallExpression { Method.Name: \"MethodName\" })\n``` \nInstead of:\n```cs\nif (e is MethodCallExpression { Method: { Name: \"MethodName\" } })\n```\n\n## Motivation\n[motivation]: #motivation\n\nWhen you want to match a child property, nesting another recursive pattern adds too much noise which will hurt readability with no real advantage.\n\n## Detailed design\n[design]: #detailed-design\n\nThe [*property_pattern*](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-8.0/patterns.md#property-pattern) syntax is modified as follow:\n\n```diff\nproperty_pattern\n  : type? property_pattern_clause simple_designation?\n  ;\n\nproperty_pattern_clause\n  : '{' (subpattern (',' subpattern)* ','?)? '}'\n  ;\n\nsubpattern\n- : identifier ':' pattern\n+ : subpattern_name ':' pattern\n  ;\n\n+subpattern_name\n+ : identifier \n+ | subpattern_name '.' identifier\n+ ;\n```\n\nThe receiver for each name lookup is the type of the previous member *T0*, starting from the *input type* of the *property_pattern*. if *T* is a nullable type, *T0* is its underlying type, otherwise *T0* is equal to *T*.\n\nFor example, a pattern of the form `{ Prop1.Prop2: pattern }` is exactly equivalent to `{ Prop1: { Prop2: pattern } }`.\n\nNote that this will include the null check when *T* is a nullable value type or a reference type. This null check means that the nested properties available will be the properties of *T0*, not of *T*.\n\nRepeated member paths are allowed. The compilation of pattern matching can take advantage of common parts of patterns.\n"
  },
  {
    "path": "proposals/csharp-10.0/file-scoped-namespaces.md",
    "content": "# File Scoped Namespaces\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/137>\n\n## Summary\n\nFile scoped namespaces use a less verbose format for the typical case of files containing only one namespace.  The file scoped namespace format is `namespace X.Y.Z;` (note the semicolon and lack of braces).  This allows for files like the following:\n\n```c#\nnamespace X.Y.Z;\n\nusing System;\n\nclass X\n{\n}\n```\n\nThe semantics are that using the `namespace X.Y.Z;` form is equivalent to writing `namespace X.Y.Z { ... }` where the remainder of the file following the file-scoped namespace is in the `...` section of a standard namespace declaration.\n\n## Motivation\n\nAnalysis of the C# ecosystem shows that approximately 99.7% files are all of either one of these forms:\n\n```c#\nnamespace X.Y.Z\n{\n    // usings\n\n    // types\n}\n```\n\nor\n\n```c#\n// usings\n\nnamespace X.Y.Z\n{\n    // types\n}\n```\n\nHowever, both these forms force the user to indent the majority of their code and add a fair amount of ceremony for what is effectively a very basic concept.  This affects clarity, uses horizontal and vertical space, and is often unsatisfying for users both used to C# and coming from other languages (which commonly have less ceremony here).\n\nThe primary goal of the feature therefore is to meet the needs of the majority of the ecosystem with less unnecessary boilerplate.\n\n## Detailed design\n\nThis proposal takes the form of a diff to the existing compilation units ([§14.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/namespaces.md#142-compilation-units)) section of the specification.\n\n### Diff\n\n~~A *compilation_unit* defines the overall structure of a source file. A compilation unit consists of zero or more *using_directive*s followed by zero or more *global_attributes* followed by zero or more *namespace_member_declaration*s.~~\n\nA *compilation_unit* defines the overall structure of a source file. A compilation unit consists of zero or more *using_directive*s followed by zero or more *global_attributes* followed by a *compilation_unit_body*. A *compilation_unit_body* can either be a *file_scoped_namespace_declaration* or zero or more *statement*s and *namespace_member_declaration*s.\n\n```antlr\ncompilation_unit\n~~    : extern_alias_directive* using_directive* global_attributes? namespace_member_declaration*~~\n    : extern_alias_directive* using_directive* global_attributes? compilation_unit_body\n    ;\n\ncompilation_unit_body\n    : statement* namespace_member_declaration*\n    | file_scoped_namespace_declaration\n    ;\n```\n\n... unchanged ...\n\nA *file_scoped_namespace_declaration* will contribute members corresponding to the *namespace_declaration* it is semantically equivalent to.  See ([Namespace Declarations](#namespace-declarations)) for more details.\n\n## Namespace declarations\n\nA *namespace_declaration* consists of the keyword `namespace`, followed by a namespace name and body, optionally followed by a semicolon.\nA *file_scoped_namespace_declaration* consists of the keyword `namespace`, followed by a namespace name, a semicolon and an optional list of *extern_alias_directive*s, *using_directive*s and *type_declaration*s.\n\n```antlr\nnamespace_declaration\n    : 'namespace' qualified_identifier namespace_body ';'?\n    ;\n    \nfile_scoped_namespace_declaration\n    : 'namespace' qualified_identifier ';' extern_alias_directive* using_directive* type_declaration*\n    ;\n\n... unchanged ...\n```\n\n... unchanged ...\n\nthe two namespace declarations above contribute to the same declaration space, in this case declaring two classes with the fully qualified names `N1.N2.A` and `N1.N2.B`. Because the two declarations contribute to the same declaration space, it would have been an error if each contained a declaration of a member with the same name.\n\nA *file_scoped_namespace_declaration* permits a namespace declaration to be written without the `{ ... }` block.  For example:\n\n```csharp\nextern alias A;\nnamespace Name;\nusing B;\nclass C\n{\n}\n```\n\nis semantically equivalent to\n\n```csharp\nextern alias A;\nnamespace Name\n{\n    using B;\n    class C\n    {\n    }\n}\n```\n\nSpecifically, a *file_scoped_namespace_declaration* is treated the same as a *namespace_declaration* at the same location in the *compilation_unit* with the same *qualified_identifier*.  The *extern_alias_directive*s, *using_directive*s and *type_declaration*s of that *file_scoped_namespace_declaration* act as if they were declared in the same order inside the *namespace_body* of that *namespace_declaration*.\n\nA source file cannot contain both a *file_scoped_namespace_declaration* and a *namespace_declaration*.  A source file cannot contain multiple *file_scoped_namespace_declaration*s. A *compilation_unit* cannot contain both a *file_scoped_namespace_declaration* and any top level *statement*s. *type_declaration*s cannot precede a *file_scoped_namespace_declaration*.  \n\n## Extern aliases\n\n... unchanged ...\n"
  },
  {
    "path": "proposals/csharp-10.0/improved-definite-assignment.md",
    "content": "# Improved Definite Assignment Analysis\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/4465>\n\n## Summary\nDefinite assignment [§9.4](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/variables.md#94-definite-assignment) as specified has a few gaps which have caused users inconvenience. In particular, scenarios involving comparison to boolean constants, conditional-access, and null coalescing.\n\n## Related discussions and issues\ncsharplang discussion of this proposal: https://github.com/dotnet/csharplang/discussions/4240\n\nProbably a dozen or so user reports can be found via this or similar queries (i.e. search for \"definite assignment\" instead of \"CS0165\", or search in csharplang).\nhttps://github.com/dotnet/roslyn/issues?q=is%3Aclosed+is%3Aissue+label%3A%22Resolution-By+Design%22+cs0165\n\nI have included related issues in the scenarios below to give a sense of the relative impact of each scenario.\n\n## Scenarios\n\nAs a point of reference, let's start with a well-known \"happy case\" that does work in definite assignment and in nullable.\n```cs\n#nullable enable\n\nC c = new C();\nif (c != null && c.M(out object obj0))\n{\n    obj0.ToString(); // ok\n}\n\npublic class C\n{\n    public bool M(out object obj)\n    {\n        obj = new object();\n        return true;\n    }\n}\n```\n\n### Comparison to bool constant\n- https://github.com/dotnet/csharplang/discussions/801\n- https://github.com/dotnet/roslyn/issues/45582\n  - Links to 4 other issues where people were affected by this.\n```cs\nif ((c != null && c.M(out object obj1)) == true)\n{\n    obj1.ToString(); // undesired error\n}\n\nif ((c != null && c.M(out object obj2)) is true)\n{\n    obj2.ToString(); // undesired error\n}\n```\n\n### Comparison between a conditional access and a constant value\n\n- https://github.com/dotnet/roslyn/issues/33559\n- https://github.com/dotnet/csharplang/discussions/4214\n- https://github.com/dotnet/csharplang/issues/3659\n- https://github.com/dotnet/csharplang/issues/3485\n- https://github.com/dotnet/csharplang/issues/3659\n\nThis scenario is probably the biggest one. We do support this in nullable but not in definite assignment.\n\n```cs\nif (c?.M(out object obj3) == true)\n{\n    obj3.ToString(); // undesired error\n}\n```\n\n### Conditional access coalesced to a bool constant\n\n- https://github.com/dotnet/csharplang/discussions/916\n- https://github.com/dotnet/csharplang/issues/3365\n\nThis scenario is very similar to the previous one. This is also supported in nullable but not in definite assignment.\n\n```cs\nif (c?.M(out object obj4) ?? false)\n{\n    obj4.ToString(); // undesired error\n}\n```\n\n### Conditional expressions where one arm is a bool constant\n- https://github.com/dotnet/roslyn/issues/4272\n\nIt's worth pointing out that we already have special behavior for when the condition expression is constant (i.e. `true ? a : b`). We just unconditionally visit the arm indicated by the constant condition and ignore the other arm.\n\nAlso note that we haven't handled this scenario in nullable.\n\n```cs\nif (c != null ? c.M(out object obj4) : false)\n{\n    obj4.ToString(); // undesired error\n}\n```\n\n## Specification\n\n### ?. (null-conditional operator) expressions\nWe introduce a new section **?. (null-conditional operator) expressions**. See the null-conditional operator specification ([§12.8.8](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1288-null-conditional-member-access))and Precise rules for determining definite assignment [§9.4.4](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/variables.md#944-precise-rules-for-determining-definite-assignment) for context.\n\nAs in the definite assignment rules linked above, we refer to a given initially unassigned variable as *v*.\n\nWe introduce the concept of \"directly contains\". An expression *E* is said to \"directly contain\" a subexpression *E<sub>1</sub>* if it is not subject to a user-defined conversion [§10.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#105-user-defined-conversions) whose parameter is not of a non-nullable value type, and one of the following conditions holds:\n- *E* is *E<sub>1</sub>*. For example, `a?.b()` directly contains the expression `a?.b()`.\n- If *E* is a parenthesized expression `(E2)`, and *E<sub>2</sub>* directly contains *E<sub>1</sub>*.\n- If *E* is a null-forgiving operator expression `E2!`, and *E<sub>2</sub>* directly contains *E<sub>1</sub>*.\n- If *E* is a cast expression `(T)E2`, and the cast does not subject *E<sub>2</sub>* to a non-lifted user-defined conversion whose parameter is not of a non-nullable value type, and *E<sub>2</sub>* directly contains *E<sub>1</sub>*.\n\nFor an expression *E* of the form `primary_expression null_conditional_operations`, let *E<sub>0</sub>* be the expression obtained by textually removing the leading ? from each of the *null_conditional_operations* of *E* that have one, as in the linked specification above.\n\nIn subsequent sections we will refer to *E<sub>0</sub>* as the *non-conditional counterpart* to the null-conditional expression. Note that some expressions in subsequent sections are subject to additional rules that only apply when one of the operands directly contains a null-conditional expression.\n\n- The definite assignment state of *v* at any point within *E* is the same as the definite assignment state at the corresponding point within *E0*.\n- The definite assignment state of *v* after *E* is the same as the definite assignment state of *v* after *primary_expression*.\n\n#### Remarks\nWe use the concept of \"directly contains\" to allow us to skip over relatively simple \"wrapper\" expressions when analyzing conditional accesses that are compared to other values. For example, `((a?.b(out x))!) == true` is expected to result in the same flow state as `a?.b == true` in general.\n\nWe also want to allow analysis to function in the presence of a number of possible conversions on a conditional access. Propagating out \"state when not null\" is not possible when the conversion is user-defined, though, since we can't count on user-defined conversions to honor the constraint that the output is non-null only if the input is non-null. The only exception to this is when the user-defined conversion's input is a non-nullable value type. For example:\n```cs\npublic struct S1 { }\npublic struct S2 { public static implicit operator S2?(S1 s1) => null; }\n```\n\nThis also includes lifted conversions like the following:\n```cs\nstring x;\n\nS1? s1 = null;\n_ = s1?.M1(x = \"a\") ?? s1.Value.M2(x = \"a\");\n\nx.ToString(); // ok\n\npublic struct S1\n{\n    public S1 M1(object obj) => this;\n    public S2 M2(object obj) => new S2();\n}\npublic struct S2\n{\n    public static implicit operator S2(S1 s1) => default;\n}\n```\n\nWhen we consider whether a variable is assigned at a given point within a null-conditional expression, we simply assume that any preceding null-conditional operations within the same null-conditional expression succeeded.\n\nFor example, given a conditional expression `a?.b(out x)?.c(x)`, the non-conditional counterpart is `a.b(out x).c(x)`. If we want to know the definite assignment state of `x` before `?.c(x)`, for example, then we perform a \"hypothetical\" analysis of `a.b(out x)` and use the resulting state as an input to `?.c(x)`.\n\n### Boolean constant expressions\nWe introduce a new section \"Boolean constant expressions\":\n\nFor an expression *expr* where *expr* is a constant expression with a bool value:\n- The definite assignment state of *v* after *expr* is determined by:\n  - If *expr* is a constant expression with value *true*, and the state of *v* before *expr* is \"not definitely assigned\", then the state of *v* after *expr* is \"definitely assigned when false\".\n  - If *expr* is a constant expression with value *false*, and the state of *v* before *expr* is \"not definitely assigned\", then the state of *v* after *expr* is \"definitely assigned when true\".\n\n#### Remarks\n\nWe assume that if an expression has a constant value bool `false`, for example, it's impossible to reach any branch that requires the expression to return `true`. Therefore variables are assumed to be definitely assigned in such branches. This ends up combining nicely with the spec changes for expressions like `??` and `?:` and enabling a lot of useful scenarios.\n\nIt's also worth noting that we never expect to be in a conditional state *before* visiting a constant expression. That's why we do not account for scenarios such as \"*expr* is a constant expression with value *true*, and the state of *v* before *expr* is \"definitely assigned when true\".\n\n### ?? (null-coalescing expressions) augment\nWe augment section [§9.4.4.29](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/variables.md#94429--expressions) as follows:\n\nFor an expression *expr* of the form `expr_first ?? expr_second`:\n- ...\n- The definite assignment state of *v* after *expr* is determined by:\n  - ...\n  - If *expr_first* directly contains a null-conditional expression *E*, and *v* is definitely assigned after the non-conditional counterpart *E<sub>0</sub>*, then the definite assignment state of *v* after *expr* is the same as the definite assignment state of *v* after *expr_second*.\n\n#### Remarks\nThe above rule formalizes that for an expression like `a?.M(out x) ?? (x = false)`, either the `a?.M(out x)` was fully evaluated and produced a non-null value, in which case `x` was assigned, or the `x = false` was evaluated, in which case `x` was also assigned. Therefore `x` is always assigned after this expression.\n\nThis also handles the `dict?.TryGetValue(key, out var value) ?? false` scenario, by observing that *v* is definitely assigned after `dict.TryGetValue(key, out var value)`, and *v* is \"definitely assigned when true\" after `false`, and concluding that *v* must be \"definitely assigned when true\".\n\nThe more general formulation also allows us to handle some more unusual scenarios, such as:\n- `if (x?.M(out y) ?? (b && z.M(out y))) y.ToString();`\n- `if (x?.M(out y) ?? z?.M(out y) ?? false) y.ToString();`\n\n### ?: (conditional) expressions\nWe augment section [§9.4.4.30](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/variables.md#94430--expressions) as follows:\n\nFor an expression *expr* of the form `expr_cond ? expr_true : expr_false`:\n- ...\n- The definite assignment state of *v* after *expr* is determined by:\n  - ...\n  - If the state of *v* after *expr_true* is \"definitely assigned when true\", and the state of *v* after *expr_false* is \"definitely assigned when true\", then the state of *v* after *expr* is \"definitely assigned when true\".\n  - If the state of *v* after *expr_true* is \"definitely assigned when false\", and the state of *v* after *expr_false* is \"definitely assigned when false\", then the state of *v* after *expr* is \"definitely assigned when false\".\n\n#### Remarks\n\nThis makes it so when both arms of a conditional expression result in a conditional state, we join the corresponding conditional states and propagate it out instead of unsplitting the state and allowing the final state to be non-conditional. This enables scenarios like the following:\n\n```cs\nbool b = true;\nobject x = null;\nint y;\nif (b ? x != null && Set(out y) : x != null && Set(out y))\n{\n  y.ToString();\n}\n\nbool Set(out int x) { x = 0; return true; }\n```\n\nThis is an admittedly niche scenario, that compiles without error in the native compiler, but was broken in Roslyn in order to match the specification at the time. \n\n### ==/!= (relational equality operator) expressions\nWe introduce a new section **==/!= (relational equality operator) expressions**.\n\nThe general rules for expressions with embedded expressions [§9.4.4.23](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/variables.md#94423-general-rules-for-expressions-with-embedded-expressions) apply, except for the scenarios described below.\n\nFor an expression *expr* of the form `expr_first == expr_second`, where `==` is a predefined comparison operator ([§12.12](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1212-relational-and-type-testing-operators)) or a lifted operator ([§12.4.8](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1248-lifted-operators)), the definite assignment state of *v* after *expr* is determined by:\n  - If *expr_first* directly contains a null-conditional expression *E* and *expr_second* is a constant expression with value *null*, and the state of *v* after the non-conditional counterpart *E<sub>0</sub>* is \"definitely assigned\", then the state of *v* after *expr* is \"definitely assigned when false\".\n  - If *expr_first* directly contains a null-conditional expression *E* and *expr_second* is an expression of a non-nullable value type, or a constant expression with a non-null value, and the state of *v* after the non-conditional counterpart *E<sub>0</sub>* is \"definitely assigned\", then the state of *v* after *expr* is \"definitely assigned when true\".\n  - If *expr_first* is of type *boolean*, and *expr_second* is a constant expression with value *true*, then the definite assignment state after *expr* is the same as the definite assignment state after *expr_first*.\n  - If *expr_first* is of type *boolean*, and *expr_second* is a constant expression with value *false*, then the definite assignment state after *expr* is the same as the definite assignment state of *v* after the logical negation expression `!expr_first`.\n\nFor an expression *expr* of the form `expr_first != expr_second`, where `!=` is a predefined comparison operator ([§12.12](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1212-relational-and-type-testing-operators)) or a lifted operator (([§12.4.8](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1248-lifted-operators))), the definite assignment state of *v* after *expr* is determined by:\n  - If *expr_first* directly contains a null-conditional expression *E* and *expr_second* is a constant expression with value *null*, and the state of *v* after the non-conditional counterpart *E<sub>0</sub>* is \"definitely assigned\", then the state of *v* after *expr* is \"definitely assigned when true\".\n  - If *expr_first* directly contains a null-conditional expression *E* and *expr_second* is an expression of a non-nullable value type, or a constant expression with a non-null value, and the state of *v* after the non-conditional counterpart *E<sub>0</sub>* is \"definitely assigned\", then the state of *v* after *expr* is \"definitely assigned when false\".\n  - If *expr_first* is of type *boolean*, and *expr_second* is a constant expression with value *true*, then the definite assignment state after *expr* is the same as the definite assignment state of *v* after the logical negation expression `!expr_first`.\n  - If *expr_first* is of type *boolean*, and *expr_second* is a constant expression with value *false*, then the definite assignment state after *expr* is the same as the definite assignment state after *expr_first*.\n\nAll of the above rules in this section are commutative, meaning that if a rule applies when evaluated in the form `expr_second op expr_first`, it also applies in the form `expr_first op expr_second`.\n\n#### Remarks\nThe general idea expressed by these rules is:\n- if a conditional access is compared to `null`, then we know the operations definitely occurred if the result of the comparison is `false`\n- if a conditional access is compared to a non-nullable value type or a non-null constant, then we know the operations definitely occurred if the result of the comparison is `true`.\n- since we can't trust user-defined operators to provide reliable answers where initialization safety is concerned, the new rules only apply when a predefined `==`/`!=` operator is in use.\n\nWe may eventually want to refine these rules to thread through conditional state which is present at the end of a member access or call. Such scenarios don't really happen in definite assignment, but they do happen in nullable in the presence of `[NotNullWhen(true)]` and similar attributes. This would require special handling for `bool` constants in addition to just handling for `null`/non-null constants.\n\nSome consequences of these rules:\n- `if (a?.b(out var x) == true)) x() else x();` will error in the 'else' branch\n- `if (a?.b(out var x) == 42)) x() else x();` will error in the 'else' branch\n- `if (a?.b(out var x) == false)) x() else x();` will error in the 'else' branch\n- `if (a?.b(out var x) == null)) x() else x();` will error in the 'then' branch\n- `if (a?.b(out var x) != true)) x() else x();` will error in the 'then' branch\n- `if (a?.b(out var x) != 42)) x() else x();` will error in the 'then' branch\n- `if (a?.b(out var x) != false)) x() else x();` will error in the 'then' branch\n- `if (a?.b(out var x) != null)) x() else x();` will error in the 'else' branch\n\n### `is` operator and `is` pattern expressions\nWe introduce a new section **`is` operator and `is` pattern expressions**.\n\nFor an expression *expr* of the form `E is T`, where *T* is any type or pattern\n- The definite assignment state of *v* before *E* is the same as the definite assignment state of *v* before *expr*.\n- The definite assignment state of *v* after *expr* is determined by:\n  - If *E* directly contains a null-conditional expression, and the state of *v* after the non-conditional counterpart *E<sub>0</sub>* is \"definitely assigned\", and `T` is any type or a pattern that does not match a `null` input, then the state of *v* after *expr* is \"definitely assigned when true\".\n  - If *E* directly contains a null-conditional expression, and the state of *v* after the non-conditional counterpart *E<sub>0</sub>* is \"definitely assigned\", and `T` is a pattern that matches a `null` input, then the state of *v* after *expr* is \"definitely assigned when false\".\n  - If *E* is of type boolean and `T` is a pattern which only matches a `true` input, then the definite assignment state of *v* after *expr* is the same as the definite assignment state of *v* after E.\n  - If *E* is of type boolean and `T` is a pattern which only matches a `false` input, then the definite assignment state of *v* after *expr* is the same as the definite assignment state of *v* after the logical negation expression `!expr`.\n  - Otherwise, if the definite assignment state of *v* after E is \"definitely assigned\", then the definite assignment state of *v* after *expr* is \"definitely assigned\".\n\n#### Remarks\n\nThis section is meant to address similar scenarios as in the `==`/`!=` section above.\nThis specification does not address recursive patterns, e.g. `(a?.b(out x), c?.d(out y)) is (object, object)`. Such support may come later if time permits.\n\n## Additional scenarios\n\nThis specification doesn't currently address scenarios involving pattern switch expressions and switch statements. For example:\n\n```cs\n_ = c?.M(out object obj4) switch\n{\n    not null => obj4.ToString() // undesired error\n};\n```\n\nIt seems like support for this could come later if time permits.\n\nThere have been several categories of bugs filed for nullable which require we essentially increase the sophistication of pattern analysis. It is likely that any ruling we make which improves definite assignment would also be carried over to nullable.\n\nhttps://github.com/dotnet/roslyn/issues/49353  \nhttps://github.com/dotnet/roslyn/issues/46819  \nhttps://github.com/dotnet/roslyn/issues/44127\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nIt feels odd to have the analysis \"reach down\" and have special recognition of conditional accesses, when typically flow analysis state is supposed to propagate upward. We are concerned about how a solution like this could intersect painfully with possible future language features that do null checks.\n\n## Alternatives\n[alternatives]: #alternatives\n\nTwo alternatives to this proposal:\n1. Introduce \"state when null\" and \"state when not null\" to the language and compiler. This has been judged to be too much effort for the scenarios we are trying to solve, but that we could potentially implement the above proposal and then move to a \"state when null/not null\" model later on without breaking people.\n2. Do nothing.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\nThere are impacts on switch expressions that should be specified: https://github.com/dotnet/csharplang/discussions/4240#discussioncomment-343395\n\n## Design meetings\n\nhttps://github.com/dotnet/csharplang/discussions/4243\n"
  },
  {
    "path": "proposals/csharp-10.0/improved-interpolated-strings.md",
    "content": "# Improved Interpolated Strings\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/4487>\n\n## Summary\n\nWe introduce a new pattern for creating and using interpolated string expressions to allow for efficient formatting and use in both general `string` scenarios\nand more specialized scenarios such as logging frameworks, without incurring unnecessary allocations from formatting the string in the framework.\n\n## Motivation\n\nToday, string interpolation mainly lowers down to a call to `string.Format`. This, while general purpose, can be inefficient for a number of reasons:\n\n1. It boxes any struct arguments, unless the runtime has happened to introduce an overload of `string.Format` that takes exactly the correct types of arguments\nin exactly the correct order.\n    * This ordering is why the runtime is hesitant to introduce generic versions of the method, as it would lead to combinatoric explosion of generic instantiations\n    of a very common method.\n2. It has to allocate an array for the arguments in most cases.\n3. There is no opportunity to avoid instantiating the instance if it's not needed. Logging frameworks, for example, will recommend avoiding string interpolation\nbecause it will cause a string to be realized that may not be needed, depending on the current log-level of the application.\n4. It can never use `Span` or other ref struct types today, because ref structs are not allowed as generic type parameters, meaning that if a user wants to avoid\ncopying to intermediate locations they have to manually format strings.\n\nInternally, the runtime has a type called `ValueStringBuilder` to help deal with the first 2 of these scenarios. They pass a stackalloc'd buffer to the builder,\nrepeatedly call `AppendFormat` with every part, and then get a final string out. If the resulting string goes past the bounds of the stack buffer, they can then\nmove to an array on the heap. However, this type is dangerous to expose directly, as incorrect usage could lead to a rented array to be double-disposed, which\nthen will cause all sorts of undefined behavior in the program as two locations think they have sole access to the rented array. This proposal creates a way to\nuse this type safely from native C# code by just writing an interpolated string literal, leaving written code unchanged while improving every interpolated string\nthat a user writes. It also extends this pattern to allow for interpolated strings passed as arguments to other methods to use a handler pattern, defined by\nreceiver of the method, that will allow things like logging frameworks to avoid allocating strings that will never be needed, and giving C# users familiar,\nconvenient interpolation syntax.\n\n## Detailed Design\n\n### The handler pattern\n\nWe introduce a new handler pattern that can represent an interpolated string passed as an argument to a method. The simple English of the pattern is as follows:\n\nWhen an _interpolated\\_string\\_expression_ is passed as an argument to a method, we look at the type of the parameter. If the parameter type has a constructor\nthat can be invoked with 2 int parameters, `literalLength` and `formattedCount`, optionally takes additional parameters specified by an attribute on the original\nparameter, optionally has an out boolean trailing parameter, and the type of the original parameter has instance `AppendLiteral` and `AppendFormatted` methods that\ncan be invoked for every part of the interpolated string, then we lower the interpolation using that, instead of into a traditional call to\n`string.Format(formatStr, args)`. A more concrete example is helpful for picturing this:\n\n```cs\n// The handler that will actually \"build\" the interpolated string\"\n[InterpolatedStringHandler]\npublic ref struct TraceLoggerParamsInterpolatedStringHandler\n{\n    // Storage for the built-up string\n\n    private bool _logLevelEnabled;\n\n    public TraceLoggerParamsInterpolatedStringHandler(int literalLength, int formattedCount, Logger logger, out bool handlerIsValid)\n    {\n        if (!logger._logLevelEnabled)\n        {\n            handlerIsValid = false;\n            return;\n        }\n\n        handlerIsValid = true;\n        _logLevelEnabled = logger.EnabledLevel;\n    }\n\n    public void AppendLiteral(string s)\n    {\n        // Store and format part as required\n    }\n\n    public void AppendFormatted<T>(T t)\n    {\n        // Store and format part as required\n    }\n}\n\n// The logger class. The user has an instance of this, accesses it via static state, or some other access\n// mechanism\npublic class Logger\n{\n    // Initialization code omitted\n    public LogLevel EnabledLevel;\n\n    public void LogTrace([InterpolatedStringHandlerArguments(\"\")]TraceLoggerParamsInterpolatedStringHandler handler)\n    {\n        // Impl of logging\n    }\n}\n\nLogger logger = GetLogger(LogLevel.Info);\n\n// Given the above definitions, usage looks like this:\nvar name = \"Fred Silberberg\";\nlogger.LogTrace($\"{name} will never be printed because info is < trace!\");\n\n// This is converted to:\nvar name = \"Fred Silberberg\";\nvar receiverTemp = logger;\nvar handler = new TraceLoggerParamsInterpolatedStringHandler(literalLength: 47, formattedCount: 1, receiverTemp, out var handlerIsValid);\nif (handlerIsValid)\n{\n    handler.AppendFormatted(name);\n    handler.AppendLiteral(\" will never be printed because info is < trace!\");\n}\nreceiverTemp.LogTrace(handler);\n```\n\nHere, because `TraceLoggerParamsInterpolatedStringHandler` has a constructor with the correct parameters, we say that the interpolated string\nhas an implicit handler conversion to that parameter, and it lowers to the pattern shown above. The specese needed for this is a bit complicated,\nand is expanded below.\n\nThe rest of this proposal will use `Append...` to refer to either of `AppendLiteral` or `AppendFormatted` in cases when both are applicable.\n\n#### New attributes\n\nThe compiler recognizes the `System.Runtime.CompilerServices.InterpolatedStringHandlerAttribute`:\n\n```cs\nusing System;\nnamespace System.Runtime.CompilerServices\n{\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]\n    public sealed class InterpolatedStringHandlerAttribute : Attribute\n    {\n        public InterpolatedStringHandlerAttribute()\n        {\n        }\n    }\n}\n```\n\nThis attribute is used by the compiler to determine if a type is a valid interpolated string handler type.\n\nThe compiler also recognizes the `System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute`:\n\n```cs\nnamespace System.Runtime.CompilerServices\n{\n    [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]\n    public sealed class InterpolatedStringHandlerArgumentAttribute : Attribute\n    {\n        public InterpolatedHandlerArgumentAttribute(string argument);\n        public InterpolatedHandlerArgumentAttribute(params string[] arguments);\n\n        public string[] Arguments { get; }\n    }\n}\n```\n\nThis attribute is used on parameters, to inform the compiler how to lower an interpolated string handler pattern used in a parameter position.\n\n#### Interpolated string handler conversion\n\nType `T` is said to be an _applicable\\_interpolated\\_string\\_handler\\_type_ if it is attributed with `System.Runtime.CompilerServices.InterpolatedStringHandlerAttribute`.\nThere exists an implicit _interpolated\\_string\\_handler\\_conversion_ to `T` from an _interpolated\\_string\\_expression_, or an _additive\\_expression_ composed entirely of\n_interpolated\\_string\\_expression_s and using only `+` operators.\n\nFor simplicity in the rest of this speclet, _interpolated\\_string\\_expression_ refers to both a simple _interpolated\\_string\\_expression_, and to an _additive\\_expression_ composed\nentirely of _interpolated\\_string\\_expression_s and using only `+` operators.\n\nNote that this conversion always exists, regardless of whether there will be later errors when actually attempting to lower the interpolation using the handler pattern. This is\ndone to help ensure that there are predictable and useful errors and that runtime behavior doesn't change based on the content of an interpolated string.\n\n#### Applicable function member adjustments\n\nWe adjust the wording of the applicable function member algorithm ([§12.6.4.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12642-applicable-function-member))\nas follows (a new sub-bullet is added to each section, in bold):\n\nA function member is said to be an ***applicable function member*** with respect to an argument list `A` when all of the following are true:\n*  Each argument in `A` corresponds to a parameter in the function member declaration as described in Corresponding parameters ([§12.6.2.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12622-corresponding-parameters)), and any parameter to which no argument corresponds is an optional parameter.\n*  For each argument in `A`, the parameter passing mode of the argument (i.e., value, `ref`, or `out`) is identical to the parameter passing mode of the corresponding parameter, and\n   *  for a value parameter or a parameter array, an implicit conversion ([§10.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#102-implicit-conversions)) exists from the argument to the type of the corresponding parameter, or\n   *  **for a `ref` parameter whose type is a struct type, an implicit _interpolated\\_string\\_handler\\_conversion_ exists from the argument to the type of the corresponding parameter, or**\n   *  for a `ref` or `out` parameter, the type of the argument is identical to the type of the corresponding parameter. After all, a `ref` or `out` parameter is an alias for the argument passed.\n\nFor a function member that includes a parameter array, if the function member is applicable by the above rules, it is said to be applicable in its ***normal form***. If a function member that includes a parameter array is not applicable in its normal form, the function member may instead be applicable in its ***expanded form***:\n*  The expanded form is constructed by replacing the parameter array in the function member declaration with zero or more value parameters of the element type of the parameter array such that the number of arguments in the argument list `A` matches the total number of parameters. If `A` has fewer arguments than the number of fixed parameters in the function member declaration, the expanded form of the function member cannot be constructed and is thus not applicable.\n*  Otherwise, the expanded form is applicable if for each argument in `A` the parameter passing mode of the argument is identical to the parameter passing mode of the corresponding parameter, and\n   *  for a fixed value parameter or a value parameter created by the expansion, an implicit conversion ([§10.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#102-implicit-conversions)) exists from the type of the argument to the type of the corresponding parameter, or\n   *  **for a `ref` parameter whose type is a struct type, an implicit _interpolated\\_string\\_handler\\_conversion_ exists from the argument to the type of the corresponding parameter, or**\n   *  for a `ref` or `out` parameter, the type of the argument is identical to the type of the corresponding parameter.\n\nImportant note: this means that if there are 2 otherwise equivalent overloads, that only differ by the type of the _applicable\\_interpolated\\_string\\_handler\\_type_, these overloads will\nbe considered ambiguous. Further, because we do not see through explicit casts, it is possible that there could arise an unresolvable scenario where both applicable overloads use\n`InterpolatedStringHandlerArguments` and are totally uncallable without manually performing the handler lowering pattern. We could potentially make changes to the better function member\nalgorithm to resolve this if we so choose, but this scenario unlikely to occur and isn't a priority to address.\n\n#### Better conversion from expression adjustments\n\nWe change the better conversion from expression ([§12.6.4.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12645-better-conversion-from-expression)) section to the\nfollowing:\n\nGiven an implicit conversion `C1` that converts from an expression `E` to a type `T1`, and an implicit conversion `C2` that converts from an expression `E` to a type `T2`, `C1` is a ***better conversion*** than `C2` if:\n1. `E` is a non-constant _interpolated\\_string\\_expression_, `C1` is an _implicit\\_string\\_handler\\_conversion_, `T1` is an _applicable\\_interpolated\\_string\\_handler\\_type_, and `C2` is not an _implicit\\_string\\_handler\\_conversion_, or\n2. `E` does not exactly match `T2` and at least one of the following holds:\n    * `E` exactly matches `T1` ([§12.6.4.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12645-better-conversion-from-expression))\n    * `T1` is a better conversion target than `T2` ([§12.6.4.6](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12647-better-conversion-target))\n\nThis does mean that there are some potentially non-obvious overload resolution rules, depending on whether the interpolated string in question is a constant-expression or not. For example:\n\n```cs\nvoid Log(string s) { ... }\nvoid Log(TraceLoggerParamsInterpolatedStringHandler p) { ... }\n\nLog($\"\"); // Calls Log(string s), because $\"\" is a constant expression\nLog($\"{\"test\"}\"); // Calls Log(string s), because $\"{\"test\"}\" is a constant expression\nLog($\"{1}\"); // Calls Log(TraceLoggerParamsInterpolatedStringHandler p), because $\"{1}\" is not a constant expression\n```\n\nThis is introduced so that things that can simply be emitted as constants do so, and don't incur any overhead, while things that cannot be constant use the handler pattern.\n\n### InterpolatedStringHandler and Usage\n\nWe introduce a new type in `System.Runtime.CompilerServices`: `DefaultInterpolatedStringHandler`. This is a ref struct with many of the same semantics as `ValueStringBuilder`,\nintended for direct use by the C# compiler. This struct would look approximately like this:\n\n```cs\n// API Proposal issue: https://github.com/dotnet/runtime/issues/50601\nnamespace System.Runtime.CompilerServices\n{\n    [InterpolatedStringHandler]\n    public ref struct DefaultInterpolatedStringHandler\n    {\n        public DefaultInterpolatedStringHandler(int literalLength, int formattedCount);\n        public string ToStringAndClear();\n\n        public void AppendLiteral(string value);\n\n        public void AppendFormatted<T>(T value);\n        public void AppendFormatted<T>(T value, string? format);\n        public void AppendFormatted<T>(T value, int alignment);\n        public void AppendFormatted<T>(T value, int alignment, string? format);\n\n        public void AppendFormatted(ReadOnlySpan<char> value);\n        public void AppendFormatted(ReadOnlySpan<char> value, int alignment = 0, string? format = null);\n\n        public void AppendFormatted(string? value);\n        public void AppendFormatted(string? value, int alignment = 0, string? format = null);\n\n        public void AppendFormatted(object? value, int alignment = 0, string? format = null);\n    }\n}\n```\n\nWe make a slight change to the rules for the meaning of an _interpolated\\_string\\_expression_ ([§12.8.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1283-interpolated-string-expressions)):\n\n**If the type of an interpolated string is `string` and the type `System.Runtime.CompilerServices.DefaultInterpolatedStringHandler` exists, and the current context supports using that type, the string**\n**is lowered using the handler pattern. The final `string` value is then obtained by calling `ToStringAndClear()` on the handler type.**\n**Otherwise, if** the type of an interpolated string is `System.IFormattable` or `System.FormattableString` [the rest is unchanged]\n\nThe \"and the current context supports using that type\" rule is intentionally vague to give the compiler leeway in optimizing usage of this pattern. The handler type is likely to be a ref struct\ntype, and ref struct types are normally not permitted in async methods. For this particular case, the compiler would be allowed to make use the handler if none of the interpolation holes contain\nan `await` expression, as we can statically determine that the handler type is safely used without additional complicated analysis because the handler will be dropped after the interpolated string\nexpression is evaluated.\n\n**~~Open~~ Question**:\n\nDo we want to instead just make the compiler know about `DefaultInterpolatedStringHandler` and skip the `string.Format` call entirely? It would allow us to hide a method that we don't necessarily\nwant to put in people's faces when they manually call `string.Format`.\n\n_Answer_: Yes.\n\n**~~Open~~ Question**:\n\nDo we want to have handlers for `System.IFormattable` and `System.FormattableString` as well?\n\n_Answer_: No.\n\n### Handler pattern codegen\n\nIn this section, method invocation resolution refers to the steps listed in [§12.8.10.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#128102-method-invocations).\n\n#### Constructor resolution\n\nGiven an _applicable\\_interpolated\\_string\\_handler\\_type_ `T` and an _interpolated\\_string\\_expression_ `i`, method invocation resolution and validation for a valid constructor on `T`\nis performed as follows:\n\n1. Member lookup for instance constructors is performed on `T`. The resulting method group is called `M`.\n2. The argument list `A` is constructed as follows:\n    1. The first two arguments are integer constants, representing the literal length of `i`, and the number of _interpolation_ components in `i`, respectively.\n    2. If `i` is used as an argument to some parameter `pi` in method `M1`, and parameter `pi` is attributed with `System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute`,\n    then for every name `Argx` in the `Arguments` array of that attribute the compiler matches it to a parameter `px` that has the same name. The empty string is matched to the receiver\n    of `M1`.\n        * If any `Argx` is not able to be matched to a parameter of `M1`, or an `Argx` requests the receiver of `M1` and `M1` is a static method, an error is produced and no further\n        steps are taken.\n        * Otherwise, the type of every resolved `px` is added to the argument list, in the order specified by the `Arguments` array. Each `px` is passed with the same `ref` semantics as is specified in `M1`.\n    3. The final argument is a `bool`, passed as an `out` parameter.\n3. Traditional method invocation resolution is performed with method group `M` and argument list `A`. For the purposes of method invocation final validation, the context of `M` is treated\nas a _member\\_access_ through type `T`.\n    * If a single-best constructor `F` was found, the result of overload resolution is `F`.\n    * If no applicable constructors were found, step 3 is retried, removing the final `bool` parameter from `A`. If this retry also finds no applicable members, an error is produced and\n    no further steps are taken.\n    * If no single-best method was found, the result of overload resolution is ambiguous, an error is produced, and no further steps are taken.\n4. Final validation on `F` is performed.\n    * If any element of `A` occurred lexically after `i`, an error is produced and no further steps are taken.\n    * If any `A` requests the receiver of `F`, and `F` is an indexer being used as an _initializer\\_target_ in a _member\\_initializer_, then an error is reported and no further steps are taken.\n\nNote: the resolution here intentionally do _not_ use the actual expressions passed as other arguments for `Argx` elements. We only consider the types post-conversion. This makes sure that we\ndon't have double-conversion issues, or unexpected cases where a lambda is bound to one delegate type when passed to `M1` and bound to a different delegate type when passed to `M`.\n\nNote: We report an error for indexers uses as member initializers because of the order of evaluation for nested member initializers. Consider this code snippet:\n\n```cs\n\nvar x1 = new C1 { C2 = { [GetString()] = { A = 2, B = 4 } } };\n\n/* Lowering:\n__c1 = new C1();\nstring argTemp = GetString();\n__c1.C2[argTemp][1] = 2;\n__c1.C2[argTemp][3] = 4;\n\nPrints:\nGetString\nget_C2\nget_C2\n*/\n\nstring GetString()\n{\n    Console.WriteLine(\"GetString\");\n    return \"\";\n}\n\nclass C1\n{\n    private C2 c2 = new C2();\n    public C2 C2 { get { Console.WriteLine(\"get_C2\"); return c2; } set { } }\n}\n\nclass C2\n{\n    public C3 this[string s]\n    {\n        get => new C3();\n        set { }\n    }\n}\n\nclass C3\n{\n    public int A\n    {\n        get => 0;\n        set { }\n    }\n    public int B\n    {\n        get => 0;\n        set { }\n    }\n}\n```\n\nThe arguments to `__c1.C2[]` are evaluated _before_ the receiver of the indexer. While we could come up with a lowering that works for this scenario (either by creating a temp for `__c1.C2`\nand sharing it across both indexer invocations, or only using it for the first indexer invocation and sharing the argument across both invocations) we think that any lowering would be\nconfusing for what we believe is a pathological scenario. Therefore, we forbid the scenario entirely.\n\n**~~Open Question~~**:\n\nIf we use a constructor instead of `Create`, we'd improve runtime codegen, at the expense of narrowing the pattern a bit.\n\n_Answer_: We will restrict to constructors for now. We can revisit adding a general `Create` method later if the scenario arises.\n\n#### `Append...` method overload resolution\n\nGiven an _applicable\\_interpolated\\_string\\_handler\\_type_ `T` and an _interpolated\\_string\\_expression_ `i`, overload resolution for a set of valid `Append...` methods on `T` is\nperformed as follows:\n\n1. If there are any _interpolated\\_regular\\_string\\_character_ components in `i`:\n    1. Member lookup on `T` with the name `AppendLiteral` is performed. The resulting method group is called `Ml`.\n    2. The argument list `Al` is constructed with one value parameter of type `string`.\n    3. Traditional method invocation resolution is performed with method group `Ml` and argument list `Al`. For the purposes of method invocation final validation, the context of `Ml`\n    is treated as a _member\\_access_ through an instance of `T`.\n        * If a single-best method `Fi` is found and no errors were produced, the result of method invocation resolution is `Fi`.\n        * Otherwise, an error is reported.\n2. For every _interpolation_ `ix` component of `i`:\n    1. Member lookup on `T` with the name `AppendFormatted` is performed. The resulting method group is called `Mf`.\n    2. The argument list `Af` is constructed:\n        1. The first parameter is the `expression` of `ix`, passed by value.\n        2. If `ix` directly contains a _constant\\_expression_ component, then an integer value parameter is added, with the name `alignment` specified.\n        3. If `ix` is directly followed by an _interpolation\\_format_, then a string value parameter is added, with the name `format` specified.\n    3. Traditional method invocation resolution is performed with method group `Mf` and argument list `Af`. For the purposes of method invocation final validation, the context of `Mf`\n    is treated as a _member\\_access_ through an instance of `T`.\n        * If a single-best method `Fi` is found, the result of method invocation resolution is `Fi`.\n        * Otherwise, an error is reported.\n3. Finally, for every `Fi` discovered in steps 1 and 2, final validation is performed:\n    * If any `Fi` does not return `bool` by value or `void`, an error is reported.\n    * If all `Fi` do not return the same type, an error is reported.\n\n\nNote that these rules do not permit extension methods for the `Append...` calls. We could consider enabling that if we choose, but this is analogous to the enumerator\npattern, where we allow `GetEnumerator` to be an extension method, but not `Current` or `MoveNext()`.\n\nThese rules _do_ permit default parameters for the `Append...` calls, which will work with things like `CallerLineNumber` or `CallerArgumentExpression` (when supported by\nthe language).\n\nWe have separate overload lookup rules for base elements vs interpolation holes because some handlers will want to be able to understand the difference between the components\nthat were interpolated and the components that were part of the base string.\n\n**~~Open~~ Question**\n\nSome scenarios, like structured logging, want to be able to provide names for interpolation elements. For example, today a logging call might look like\n`Log(\"{name} bought {itemCount} items\", name, items.Count);`. The names inside the `{}` provide important structure information for loggers that help with ensuring output\nis consistent and uniform. Some cases might be able to reuse the `:format` component of an interpolation hole for this, but many loggers already understand format specifiers\nand have existing behavior for output formatting based on this info. Is there some syntax we can use to enable putting these named specifiers in?\n\nSome cases may be able to get away with `CallerArgumentExpression`, provided that support does land in C# 10. But for cases that invoke a method/property, that may not be\nsufficient.\n\n_Answer_:\n\nWhile there are some interesting parts to templated strings we could explore in an orthogonal language feature, we don't think a specific syntax here has much benefit over\nsolutions such as using a tuple: `$\"{(\"StructuredCategory\", myExpression)}\"`.\n\n#### Performing the conversion\n\nGiven an _applicable\\_interpolated\\_string\\_handler\\_type_ `T` and an _interpolated\\_string\\_expression_ `i` that had a valid constructor `Fc` and `Append...` methods `Fa` resolved,\nlowering for `i` is performed as follows:\n\n1. Any arguments to `Fc` that occur lexically before `i` are evaluated and stored into temporary variables in lexical order. In order to preserve lexical ordering, if `i` occurred as part\nof a larger expression `e`, any components of `e` that occurred before `i` will be evaluated as well, again in lexical order.\n2. `Fc` is called with the length of the interpolated string literal components, the number of _interpolation_ holes, any previously evaluated arguments, and a `bool` out argument\n(if `Fc` was resolved with one as the last parameter). The result is stored into a temporary value `ib`.\n    1. The length of the literal components is calculated after replacing any _open_brace_escape_sequence_ with a single `{`, and any _close_brace_escape_sequence_\n    with a single `}`.\n3. If `Fc` ended with a `bool` out argument, a check on that `bool` value is generated. If true, the methods in `Fa` will be called. Otherwise, they will not be called.\n4. For every `Fax` in `Fa`, `Fax` is called on `ib` with either the current literal component or _interpolation_ expression, as appropriate. If `Fax` returns a `bool`, the result is\nlogically anded with all preceding `Fax` calls.\n    1. If `Fax` is a call to `AppendLiteral`, the literal component is unescaped by replacing any _open_brace_escape_sequence_ with a single `{`, and any _close_brace_escape_sequence_\n    with a single `}`.\n5. The result of the conversion is `ib`.\n\nAgain, note that arguments passed to `Fc` and arguments passed to `e` are the same temp. Conversions may occur on top of the temp to convert to a form that `Fc` requires, but for example\nlambdas cannot be bound to a different delegate type between `Fc` and `e`.\n\n**~~Open~~ Question**\n\nThis lowering means that subsequent parts of the interpolated string after a false-returning `Append...` call don't get evaluated. This could potentially be very confusing, particularly\nif the format hole is side-effecting. We could instead evaluate all format holes first, then repeatedly call `Append...` with the results, stopping if it returns false. This would ensure\nthat all expressions get evaluated as one might expect, but we call as few methods as we need to. While the partial evaluation might be desirable for some more advanced cases, it is perhaps\nnon-intuitive for the general case.\n\nAnother alternative, if we want to always evaluate all format holes, is to remove the `Append...` version of the API and just do repeated `Format` calls. The handler can track whether it\nshould just be dropping the argument and immediately returning for this version.\n\n_Answer_: We will have conditional evaluation of the holes.\n\n**~~Open~~ Question**\n\nDo we need to dispose of disposable handler types, and wrap calls with try/finally to ensure that Dispose is called? For example, the interpolated string handler in the bcl might have a\nrented array inside it, and if one of the interpolation holes throws an exception during evaluation, that rented array could be leaked if it wasn't disposed.\n\n_Answer_: No. handlers can be assigned to locals (such as `MyHandler handler = $\"{MyCode()};`), and the lifetime of such handlers is unclear. Unlike foreach enumerators, where the lifetime\nis obvious and no user-defined local is created for the enumerator.\n\n### Impact on nullable reference types\n\nTo minimize complexity of the implementation, we have a few limitations on how we perform nullable analysis on interpolated string handler constructors used as arguments to a method or indexer.\nIn particular, we do not flow information from the constructor back through to the original slots of parameters or arguments from the original context, and we do not use constructor parameter\ntypes to inform generic type inference for type parameters in the containing method. An example of where this can have an impact is:\n\n```cs\nstring s = \"\";\nC c = new C();\nc.M(s, $\"\", c.ToString(), s.ToString()); // No warnings on c.ToString() or s.ToString(), as the `MaybeNull` does not flow back.\n\npublic class C\n{\n    public void M(string s1, [InterpolatedStringHandlerArgument(\"\", \"s1\")] CustomHandler c1, string s2, string s3) { }\n}\n\n[InterpolatedStringHandler]\npublic partial struct CustomHandler\n{\n    public CustomHandler(int literalLength, int formattedCount, [MaybeNull] C c, [MaybeNull] string s) : this()\n    {\n    }\n}\n```\n\n```cs\nstring? s = null;\nM(s, $\"\"); // Infers `string` for `T` because of the `T?` parameter, not `string?`, as flow analysis does not consider the unannotated `T` parameter of the constructor\n\nvoid M<T>(T? t, [InterpolatedStringHandlerArgument(\"s1\")] CustomHandler<T> c) { }\n\n[InterpolatedStringHandler]\npublic partial struct CustomHandler<T>\n{\n    public CustomHandler(int literalLength, int formattedCount, T t) : this()\n    {\n    }\n}\n```\n\n## Other considerations\n\n### Allow `string` types to be convertible to handlers as well\n\nFor type author simplicity, we could consider allowing expressions of type `string` to be implicitly-convertible to _applicable\\_interpolated\\_string\\_handler\\_types_. As proposed today,\nauthors will likely need to overload on both that handler type and regular `string` types, so their users don't have to understand the difference. This may be an annoying and non-obvious\noverhead, as a `string` expression can be viewed as an interpolation with `expression.Length` prefilled length and 0 holes to be filled.\n\nThis would allow new APIs to only expose a handler, without also having to expose a `string`-accepting overload. However, it won't get around the need for changes to better conversion from\nexpression, so while it would work it may be unnecessary overhead.\n\n_Answer_:\n\nWe think that this could end up being confusing, and there's an easy workaround for custom handler types: add a user-defined conversion from string.\n\n### Incorporating spans for heap-less strings\n\n`ValueStringBuilder` as it exists today has 2 constructors: one that takes a count, and allocates on the heap eagerly, and one that takes a `Span<char>`. That `Span<char>` is usually\na fixed size in the runtime codebase, around 250 elements on average. To truly replace that type, we should consider an extension to this where we also recognize `GetInterpolatedString`\nmethods that take a `Span<char>`, instead of just the count version. However, we see a few potential thorny cases to resolve here:\n\n* We don't want to stackalloc repeatedly in a hot loop. If we were to do this extension to the feature, we'd likely want to share the stackalloc'd span between loop\niterations. We know this is safe, as `Span<T>` is a ref struct that can't be stored on the heap, and users would have to be pretty devious to manage to extract a\nreference to that `Span` (such as creating a method that accepts such a handler then deliberately retrieving the `Span` from the handler and returning it to the\ncaller). However, allocating ahead of time produces other questions:\n    * Should we eagerly stackalloc? What if the loop is never entered, or exits before it needs the space?\n    * If we don't eagerly stackalloc, does that mean we introduce a hidden branch on every loop? Most loops likely won't care about this, but it could affect some tight loops that don't\n    want to pay the cost.\n* Some strings can be quite big, and the appropriate amount to `stackalloc` is dependent on a number of factors, including runtime factors. We don't really want the C# compiler and\nspecification to have to determine this ahead of time, so we'd want to resolve https://github.com/dotnet/runtime/issues/25423 and add an API for the compiler to call in these cases. It\nalso adds more pros and cons to the points from the previous loop, where we don't want to potentially allocate large arrays on the heap many times or before one is needed.\n\n_Answer_:\n\nThis is out of scope for C# 10. We can look at this in general when we look at the more general `params Span<T>` feature.\n\n### Non-try version of the API\n\nFor simplicity, this spec currently just proposes recognizing a `Append...` method, and things that always succeed (like `InterpolatedStringHandler`) would always return true from the method.\nThis was done to support partial formatting scenarios where the user wants to stop formatting if an error occurs or if it's unnecessary, such as the logging case, but could potentially\nintroduce a bunch of unnecessary branches in standard interpolated string usage. We could consider an addendum where we use just `FormatX` methods if no `Append...` method is present, but\nit does present questions about what we do if there's a mix of both `Append...` and `FormatX` calls.\n\n_Answer_:\n\nWe want the non-try version of the API. The proposal has been updated to reflect this.\n\n### Passing previous arguments to the handler\n\nThere is unfortunate lack of symmetry in the proposal at it currently exists: invoking an extension method in reduced form produces different semantics than invoking the extension method in\nnormal form. This is different from most other locations in the language, where reduced form is just a sugar. We propose adding an attribute to the framework that we will recognize when\nbinding a method, that informs the compiler that certain parameters should be passed to the constructor on the handler. Usage looks like this:\n\n```cs\nnamespace System.Runtime.CompilerServices\n{\n    [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]\n    public sealed class InterpolatedStringHandlerArgumentAttribute : Attribute\n    {\n        public InterpolatedStringHandlerArgumentAttribute(string argument);\n        public InterpolatedStringHandlerArgumentAttribute(params string[] arguments);\n\n        public string[] Arguments { get; }\n    }\n}\n```\n\nUsage of this is then:\n\n```cs\nnamespace System\n{\n    public sealed class String\n    {\n        public static string Format(IFormatProvider? provider, [InterpolatedStringHandlerArgument(\"provider\")] ref DefaultInterpolatedStringHandler handler);\n        …\n    }\n}\n\nnamespace System.Runtime.CompilerServices\n{\n    public ref struct DefaultInterpolatedStringHandler\n    {\n        public DefaultInterpolatedStringHandler(int baseLength, int holeCount, IFormatProvider? provider); // additional factory\n        …\n    }\n}\n\nvar formatted = string.Format(CultureInfo.InvariantCulture, $\"{X} = {Y}\");\n\n// Is lowered to\n\nvar tmp1 = CultureInfo.InvariantCulture;\nvar handler = new DefaultInterpolatedStringHandler(3, 2, tmp1);\nhandler.AppendFormatted(X);\nhandler.AppendLiteral(\" = \");\nhandler.AppendFormatted(Y);\nvar formatted = string.Format(tmp1, handler);\n```\n\nThe questions we need to answer:\n\n1. Do we like this pattern in general?\n2. Do we want to allow these arguments to come from after the handler parameter? Some existing patterns in the BCL, such as `Utf8Formatter`, put the value to be formatted _before_ the thing\nneeded to format into. To fit in best with these patterns, we'd likely want to allow this, but we need to decide if this out-of-order evaluate is ok.\n\n_Answer_:\n\nWe want to support this. The spec has been updated to reflect this. Arguments will be required to be specified in lexical order at the call site, and if a needed argument to the create method\nis specified after the interpolated string literal, an error is produced.\n\n### `await` usage in interpolation holes\n\nBecause `$\"{await A()}\"` is a valid expression today, we need to rationalize interpolation holes with await. We could solve this with a few rules:\n\n1. If an interpolated string used as a `string`, `IFormattable`, or `FormattableString` has an `await` in an interpolation hole, fall back to old-style formatter.\n2. If an interpolated string is subject to an _implicit\\_string\\_handler\\_conversion_ and _applicable\\_interpolated\\_string\\_handler\\_type_ is a `ref struct`, `await` is not allowed to be used\nin the format holes.\n\nFundamentally, this desugaring could use a ref struct in an async method as long as we guarantee that the `ref struct` will not need to be saved to the heap, which should be possible if we forbid\n`await`s in the interpolation holes.\n\nAlternatively, we could simply make all handler types non-ref structs, including the framework handler for interpolated strings. This would, however, preclude us from someday recognizing a `Span`\nversion that does not need to allocate any scratch space at all.\n\n_Answer_:\n\nWe will treat interpolated string handlers the same as any other type: this means that if the handler type is a ref struct and the current context doesn't allow the usage of ref structs, it is\nillegal to use handler here. The spec around lowering of string literals used as strings is intentionally vague to allow the compiler to decide on what rules it deems appropriate, but for custom\nhandler types they will have to follow the same rules as the rest of the language.\n\n### Handlers as ref parameters\n\nSome handlers might want to be passed as ref parameters (either `in` or `ref`). Should we allow either? And if so, what will a `ref` handler look like? `ref $\"\"` is confusing, as you're not actually\npassing the string by ref, you're passing the handler that is created from the ref by ref, and has similar potential issues with async methods.\n\n_Answer_:\n\nWe want to support this. The spec has been updated to reflect this. The rules should reflect the same rules that apply to extension methods on value types.\n\n### Interpolated strings through binary expressions and conversions\n\nBecause this proposal makes interpolated strings context sensitive, we would like to allow the compiler to treat a binary expression composed entirely of interpolated strings,\nor an interpolated string subjected to a cast, as an interpolated string literal for the purposes of overload resolution. For example, take the following scenario:\n\n```cs\nstruct Handler1\n{\n    public Handler1(int literalLength, int formattedCount, C c) => ...;\n    // AppendX... methods as necessary\n}\nstruct Handler2\n{\n    public Handler2(int literalLength, int formattedCount, C c) => ...;\n    // AppendX... methods as necessary\n}\n\nclass C\n{\n    void M(Handler1 handler) => ...;\n    void M(Handler2 handler) => ...;\n}\n\nc.M($\"{X}\"); // Ambiguous between the M overloads\n```\n\nThis would be ambiguous, necessitating a cast to either `Handler1` or `Handler2` in order to resolve. However, in making that cast, we would potentially throw away the information\nthat there is context from the method receiver, meaning that the cast would fail because there is nothing to fill in the information of `c`. A similar issue arises with binary concatenation\nof strings: the user could want to format the literal across several lines to avoid line wrapping, but would not be able to because that would no longer be an interpolated string literal\nconvertible to the handler type.\n\nTo resolve these cases, we make the following changes:\n\n* An _additive\\_expression_ composed entirely of _interpolated\\_string\\_expressions_ and using only `+` operators is considered to be an _interpolated\\_string\\_literal_ for the purposes of\nconversions and overload resolution. The final interpolated string is created by logically concatinating all individual _interpolated\\_string\\_expression_ components, from left to right.\n* A _cast\\_expression_ or a _relational\\_expression_ with operator `as` whose operand is an _interpolated\\_string\\_expressions_ is considered an _interpolated\\_string\\_expressions_ for the\npurposes of conversions and overload resolution.\n\n**Open Questions**:\n\nDo we want to do this? We don't do this for `System.FormattableString`, for example, but that can be broken out onto a different line, whereas this can be context-dependent and therefore not\nable to be broken out into a different line. There are also no overload resolution concerns with `FormattableString` and `IFormattable`.\n\n_Answer_:\n\nWe think that this is a valid use case for additive expressions, but that the cast version is not compelling enough at this time. We can add it later if necessary. The spec has been updated to\nreflect this decision.\n\n## Other use cases\n\nSee https://github.com/dotnet/runtime/issues/50635 for examples of proposed handler APIs using this pattern.\n"
  },
  {
    "path": "proposals/csharp-10.0/lambda-improvements.md",
    "content": "﻿# Lambda improvements\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/4934>\n\n## Summary\nProposed changes:\n1. Allow lambdas with attributes\n2. Allow lambdas with explicit return type\n3. Infer a natural delegate type for lambdas and method groups\n\n## Motivation\nSupport for attributes on lambdas would provide parity with methods and local functions.\n\nSupport for explicit return types would provide symmetry with lambda parameters where explicit types can be specified.\nAllowing explicit return types would also provide control over compiler performance in nested lambdas where overload resolution must bind the lambda body currently to determine the signature.\n\nA natural type for lambda expressions and method groups will allow more scenarios where lambdas and method groups may be used without an explicit delegate type, including as initializers in `var` declarations.\n\nRequiring explicit delegate types for lambdas and method groups has been a friction point for customers, and has become an impediment to progress in ASP.NET with recent work on [MapAction](https://github.com/dotnet/aspnetcore/pull/29878).\n\n[ASP.NET MapAction](https://github.com/dotnet/aspnetcore/pull/29878) without proposed changes (`MapAction()` takes a `System.Delegate` argument):\n```csharp\n[HttpGet(\"/\")] Todo GetTodo() => new(Id: 0, Name: \"Name\");\napp.MapAction((Func<Todo>)GetTodo);\n\n[HttpPost(\"/\")] Todo PostTodo([FromBody] Todo todo) => todo;\napp.MapAction((Func<Todo, Todo>)PostTodo);\n```\n\n[ASP.NET MapAction](https://github.com/dotnet/aspnetcore/pull/29878) with natural types for method groups:\n```csharp\n[HttpGet(\"/\")] Todo GetTodo() => new(Id: 0, Name: \"Name\");\napp.MapAction(GetTodo);\n\n[HttpPost(\"/\")] Todo PostTodo([FromBody] Todo todo) => todo;\napp.MapAction(PostTodo);\n```\n\n[ASP.NET MapAction](https://github.com/dotnet/aspnetcore/pull/29878) with attributes and natural types for lambda expressions:\n```csharp\napp.MapAction([HttpGet(\"/\")] () => new Todo(Id: 0, Name: \"Name\"));\napp.MapAction([HttpPost(\"/\")] ([FromBody] Todo todo) => todo);\n```\n\n## Attributes\nAttributes may be added to lambda expressions and lambda parameters.\nTo avoid ambiguity between method attributes and parameter attributes, a lambda expression with attributes must use a parenthesized parameter list.\nParameter types are not required.\n```csharp\nf = [A] () => { };        // [A] lambda\nf = [return:A] x => x;    // syntax error at '=>'\nf = [return:A] (x) => x;  // [A] lambda\nf = [A] static x => x;    // syntax error at '=>'\n\nf = ([A] x) => x;         // [A] x\nf = ([A] ref int x) => x; // [A] x\n```\n\nMultiple attributes may be specified, either comma-separated within the same attribute list or as separate attribute lists.\n```csharp\nvar f = [A1, A2][A3] () => { };    // ok\nvar g = ([A1][A2, A3] int x) => x; // ok\n``` \n\nAttributes are not supported for _anonymous methods_ declared with `delegate { }` syntax.\n```csharp\nf = [A] delegate { return 1; };         // syntax error at 'delegate'\nf = delegate ([A] int x) { return x; }; // syntax error at '['\n```\n\nThe parser will look ahead to differentiate a collection initializer with an element assignment from a collection initializer with a lambda expression.\n```csharp\nvar y = new C { [A] = x };    // ok: y[A] = x\nvar z = new C { [A] x => x }; // ok: z[0] = [A] x => x\n```\n\nThe parser will treat `?[` as the start of a conditional element access.\n```csharp\nx = b ? [A];               // ok\ny = b ? [A] () => { } : z; // syntax error at '('\n```\n\nAttributes on the lambda expression or lambda parameters will be emitted to metadata on the method that maps to the lambda.\n\nIn general, customers should not depend on how lambda expressions and local functions map from source to metadata. How lambdas and local functions are emitted can, and has, changed between compiler versions.\n\nThe changes proposed here are targeted at the `Delegate` driven scenario.\nIt should be valid to inspect the `MethodInfo` associated with a `Delegate` instance to determine the signature of the lambda expression or local function including any explicit attributes and additional metadata emitted by the compiler such as default parameters.\nThis allows teams such as ASP.NET to make available the same behaviors for lambdas and local functions as ordinary methods.\n\n## Explicit return type\nAn explicit return type may be specified before the parenthesized parameter list.\n```csharp\nf = T () => default;                    // ok\nf = short x => 1;                       // syntax error at '=>'\nf = ref int (ref int x) => ref x;       // ok\nf = static void (_) => { };             // ok\nf = async async (async async) => async; // ok?\n```\n\nThe parser will look ahead to differentiate a method call `T()` from a lambda expression `T () => e`.\n\nExplicit return types are not supported for anonymous methods declared with `delegate { }` syntax.\n```csharp\nf = delegate int { return 1; };         // syntax error\nf = delegate int (int x) { return x; }; // syntax error\n```\n\nMethod type inference should make an exact inference from an explicit lambda return type.\n```csharp\nstatic void F<T>(Func<T, T> f) { ... }\nF(int (i) => i); // Func<int, int>\n```\n\nVariance conversions are not allowed from lambda return type to delegate return type (matching similar behavior for parameter types).\n```csharp\nFunc<object> f1 = string () => null; // error\nFunc<object?> f2 = object () => x;   // warning\n```\n\nThe parser allows lambda expressions with `ref` return types within expressions without additional parentheses.\n```csharp\nd = ref int () => x; // d = (ref int () => x)\nF(ref int () => x);  // F((ref int () => x))\n```\n\n`var` cannot be used as an explicit return type for lambda expressions.\n```csharp\nclass var { }\n\nd = var (var v) => v;              // error: contextual keyword 'var' cannot be used as explicit lambda return type\nd = @var (var v) => v;             // ok\nd = ref var (ref var v) => ref v;  // error: contextual keyword 'var' cannot be used as explicit lambda return type\nd = ref @var (ref var v) => ref v; // ok\n```\n\n## Natural (function) type\nAn _anonymous function_ expression ([§12.19](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1219-anonymous-function-expressions)) (a _lambda expression_ or an _anonymous method_) has a natural type if the parameters types are explicit and the return type is either explicit or can be inferred (see [§12.6.3.13](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#116313-inferred-return-type)).\n\nA _method group_ has a natural type if all candidate methods in the method group have a common signature. (If the method group may include extension methods, the candidates include the containing type and all extension method scopes.)\n\nThe natural type of an anonymous function expression or method group is a _function_type_.\nA _function_type_ represents a method signature: the parameter types and ref kinds, and return type and ref kind.\nAnonymous function expressions or method groups with the same signature have the same _function_type_.\n\n_Function_types_ are used in a few specific contexts only:\n- implicit and explicit conversions\n- method type inference ([§12.6.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1263-type-inference)) and best common type ([§12.6.3.15](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#126315-finding-the-best-common-type-of-a-set-of-expressions))\n- `var` initializers\n\nA _function_type_ exists at compile time only: _function_types_ do not appear in source or metadata.\n\n### Conversions\nFrom a _function_type_ `F` there are implicit _function_type_ conversions:\n- To a _function_type_ `G` if the parameters and return types of `F` are variance-convertible to the parameters and return type of `G`\n- To `System.MulticastDelegate` or base classes or interfaces of `System.MulticastDelegate`\n- To `System.Linq.Expressions.Expression` or `System.Linq.Expressions.LambdaExpression`\n\nAnonymous function expressions and method groups already have _conversions from expression_ to delegate types and expression tree types (see anonymous function conversions [§10.7](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#107-anonymous-function-conversions) and method group conversions [§10.8](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#108-method-group-conversions)). Those conversions are sufficient for converting to strongly-typed delegate types and expression tree types. The _function_type_ conversions above add _conversions from type_ to the base types only: `System.MulticastDelegate`, `System.Linq.Expressions.Expression`, etc.\n\nThere are no conversions to a _function_type_ from a type other than a _function_type_.\nThere are no explicit conversions for _function_types_ since _function_types_ cannot be referenced in source.\n\nA conversion to `System.MulticastDelegate` or base type or interface realizes the anonymous function or method group as an instance of an appropriate delegate type.\nA conversion to `System.Linq.Expressions.Expression<TDelegate>` or base type realizes the lambda expression as an expression tree with an appropriate delegate type.\n\n```csharp\nDelegate d = delegate (object obj) { }; // Action<object>\nExpression e = () => \"\";                // Expression<Func<string>>\nobject o = \"\".Clone;                    // Func<object>\n```\n\n_Function_type_ conversions are not implicit or explicit standard conversions [§10.4](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#104-standard-conversions) and are not considered when determining whether a user-defined conversion operator is applicable to an anonymous function or method group.\nFrom evaluation of user defined conversions [§10.5.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#1053-evaluation-of-user-defined-conversions):\n\n> For a conversion operator to be applicable, it must be possible to perform a standard conversion ([§10.4](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#104-standard-conversions)) from the source type to the operand type of the operator, and it must be possible to perform a standard conversion from the result type of the operator to the target type.\n\n```csharp\nclass C\n{\n    public static implicit operator C(Delegate d) { ... }\n}\n\nC c;\nc = () => 1;      // error: cannot convert lambda expression to type 'C'\nc = (C)(() => 2); // error: cannot convert lambda expression to type 'C'\n```\n\nA warning is reported for an implicit conversion of a method group to `object`, since the conversion is valid but perhaps unintentional.\n```csharp\nRandom r = new Random();\nobject obj;\nobj = r.NextDouble;         // warning: Converting method group to 'object'. Did you intend to invoke the method?\nobj = (object)r.NextDouble; // ok\n```\n\n### Type inference\nThe existing rules for type inference are mostly unchanged (see [§12.6.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1263-type-inference)). There are however a **couple of changes** below to specific phases of type inference.\n\n#### First phase\nThe first phase ([§12.6.3.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12632-the-first-phase)) allows an anonymous function to bind to `Ti` even if `Ti` is not a delegate or expression tree type (perhaps a type parameter constrained to `System.Delegate` for instance).\n\n> For each of the method arguments `Ei`:\n> \n> *   If `Ei` is an anonymous function **and `Ti` is a delegate type or expression tree type**, an *explicit parameter type inference* is made from `Ei` to `Ti` **and an *explicit return type inference* is made from `Ei` to `Ti`.**\n> *   Otherwise, if `Ei` has a type `U` and `xi` is a value parameter then a *lower-bound inference* is made *from* `U` *to* `Ti`.\n> *   Otherwise, if `Ei` has a type `U` and `xi` is a `ref` or `out` parameter then an *exact inference* is made *from* `U` *to* `Ti`.\n> *   Otherwise, no inference is made for this argument.\n\n> #### **Explicit return type inference**\n> \n> **An *explicit return type inference* is made *from* an expression `E` *to* a type `T` in the following way:**\n> \n> *  **If `E` is an anonymous function with explicit return type `Ur` and `T` is a delegate type or expression tree type with return type `Vr` then an *exact inference* ([§12.6.3.9](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12639-exact-inferences)) is made *from* `Ur` *to* `Vr`.**\n\n#### Fixing\nFixing ([§12.6.3.12](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#126312-fixing)) ensures other conversions are preferred over _function_type_ conversions. (Lambda expressions and method group expressions only contribute to lower bounds so handling of _function_types_ is needed for lower bounds only.)\n\n> An *unfixed* type variable `Xi` with a set of bounds is *fixed* as follows:\n> \n> *  The set of *candidate types* `Uj` starts out as the set of all types in the set of bounds for `Xi` **where function types are ignored in lower bounds if there any types that are not function types**.\n> *  We then examine each bound for `Xi` in turn: For each exact bound `U` of `Xi` all types `Uj` which are not identical to `U` are removed from the candidate set. For each lower bound `U` of `Xi` all types `Uj` to which there is *not* an implicit conversion from `U` are removed from the candidate set. For each upper bound `U` of `Xi` all types `Uj` from which there is *not* an implicit conversion to `U` are removed from the candidate set.\n> *  If among the remaining candidate types `Uj` there is a unique type `V` from which there is an implicit conversion to all the other candidate types, then `Xi` is fixed to `V`.\n> *  Otherwise, type inference fails.\n\n### Best common type\nBest common type ([§12.6.3.15](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#116315-finding-the-best-common-type-of-a-set-of-expressions)) is defined in terms of type inference so the type inference changes above apply to best common type as well.\n```csharp\nvar fs = new[] { (string s) => s.Length, (string s) => int.Parse(s) }; // Func<string, int>[]\n```\n\n### `var`\nAnonymous functions and method groups with function types can be used as initializers in `var` declarations.\n```csharp\nvar f1 = () => default;           // error: cannot infer type\nvar f2 = x => x;                  // error: cannot infer type\nvar f3 = () => 1;                 // System.Func<int>\nvar f4 = string () => null;       // System.Func<string>\nvar f5 = delegate (object o) { }; // System.Action<object>\n\nstatic void F1() { }\nstatic void F1<T>(this T t) { }\nstatic void F2(this string s) { }\n\nvar f6 = F1;    // error: multiple methods\nvar f7 = \"\".F1; // error: the delegate type could not be inferred\nvar f8 = F2;    // System.Action<string> \n```\n\nFunction types are not used in assignments to discards.\n```csharp\nd = () => 0; // ok\n_ = () => 1; // error\n```\n\n### Delegate types\nThe delegate type for the anonymous function or method group with parameter types `P1, ..., Pn` and return type `R` is:\n- if any parameter or return value is not by value, or there are more than 16 parameters, or any of the parameter types or return are not valid type arguments (say, `(int* p) => { }`), then the delegate is a synthesized `internal` anonymous delegate type with signature that matches the anonymous function or method group, and with parameter names `arg1, ..., argn` or `arg` if a single parameter;\n- if `R` is `void`, then the delegate type is `System.Action<P1, ..., Pn>`;\n- otherwise the delegate type is `System.Func<P1, ..., Pn, R>`.\n\nThe compiler may allow more signatures to bind to `System.Action<>` and `System.Func<>` types in the future (if `ref struct` types are allowed type arguments for instance).\n\n`modopt()` or `modreq()` in the method group signature are ignored in the corresponding delegate type.\n\nIf two anonymous functions or method groups in the same compilation require synthesized delegate types with the same parameter types and modifiers and the same return type and modifiers, the compiler will use the same synthesized delegate type.\n\n### Overload resolution\n\nBetter function member ([§12.6.4.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12643-better-function-member)) is updated to prefer members where none of the conversions and none of the type arguments involved inferred types from lambda expressions or method groups.\n\n> #### Better function member\n> ...\n> Given an argument list `A` with a set of argument expressions `{E1, E2, ..., En}` and two applicable function members `Mp` and `Mq` with parameter types `{P1, P2, ..., Pn}` and `{Q1, Q2, ..., Qn}`, `Mp` is defined to be a ***better function member*** than `Mq` if\n>\n> 1. **for each argument, the implicit conversion from `Ex` to `Px` is not a _function_type_conversion_, and**\n>    *  **`Mp` is a non-generic method or `Mp` is a generic method with type parameters `{X1, X2, ..., Xp}` and for each type parameter `Xi` the type argument is inferred from an expression or from a type other than a _function_type_, and**\n>    *  **for at least one argument, the implicit conversion from `Ex` to `Qx` is a _function_type_conversion_, or `Mq` is a generic method with type parameters `{Y1, Y2, ..., Yq}` and for at least one type parameter `Yi` the type argument is inferred from a _function_type_, or**\n> 2. for each argument, the implicit conversion from `Ex` to `Qx` is not better than the implicit conversion from `Ex` to `Px`, and for at least one argument, the conversion from `Ex` to `Px` is better than the conversion from `Ex` to `Qx`.\n\nBetter conversion from expression ([§12.6.4.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12644-better-conversion-from-expression)) is updated to prefer conversions that did not involve inferred types from lambda expressions or method groups.\n\n> #### Better conversion from expression\n> \n> Given an implicit conversion `C1` that converts from an expression `E` to a type `T1`, and an implicit conversion `C2` that converts from an expression `E` to a type `T2`, `C1` is a ***better conversion*** than `C2` if:\n> 1. **`C1` is not a _function_type_conversion_ and `C2` is a _function_type_conversion_, or**\n> 2. `E` is a non-constant _interpolated\\_string\\_expression_, `C1` is an _implicit\\_string\\_handler\\_conversion_, `T1` is an _applicable\\_interpolated\\_string\\_handler\\_type_, and `C2` is not an _implicit\\_string\\_handler\\_conversion_, or\n> 3. `E` does not exactly match `T2` and at least one of the following holds:\n>     * `E` exactly matches `T1` ([§12.6.4.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12645-better-conversion-from-expression))\n>     * `T1` is a better conversion target than `T2` ([§12.6.4.7](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12647-better-conversion-target))\n\n## Syntax\n\n```antlr\nlambda_expression\n  : modifier* identifier '=>' (block | expression)\n  | attribute_list* modifier* type? lambda_parameters '=>' (block | expression)\n  ;\n\nlambda_parameters\n  : lambda_parameter\n  | '(' (lambda_parameter (',' lambda_parameter)*)? ')'\n  ;\n\nlambda_parameter\n  : identifier\n  | attribute_list* modifier* type? identifier equals_value_clause?\n  ;\n```\n\n## Open issues\n\nShould default values be supported for lambda expression parameters for completeness?\n\nShould `System.Diagnostics.ConditionalAttribute` be disallowed on lambda expressions since there are few scenarios where a lambda expression could be used conditionally?\n```csharp\n([Conditional(\"DEBUG\")] static (x, y) => Assert(x == y))(a, b); // ok?\n```\n\nShould the _function_type_ be available from the compiler API, in addition to the resulting delegate type?\n\nCurrently, the inferred delegate type uses `System.Action<>` or `System.Func<>` when parameter and return types are valid type arguments _and_ there are no more than 16 parameters, and if the expected `Action<>` or `Func<>` type is missing, an error is reported. Instead, should the compiler use `System.Action<>` or `System.Func<>` regardless of arity? And if the expected type is missing, synthesize a delegate type otherwise?\n"
  },
  {
    "path": "proposals/csharp-10.0/parameterless-struct-constructors.md",
    "content": "# Parameterless struct constructors\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/99>\n\n## Summary\nSupport parameterless constructors and instance field initializers for struct types.\n\n## Motivation\nExplicit parameterless constructors would give more control over minimally constructed instances of the struct type.\nInstance field initializers would allow simplified initialization across multiple constructors.\nTogether these would close an obvious gap between `struct` and `class` declarations.\n\nSupport for field initializers would also allow initialization of fields in `record struct` declarations without explicitly implementing the primary constructor.\n```csharp\nrecord struct Person(string Name)\n{\n    public object Id { get; init; } = GetNextId();\n}\n```\n\nIf struct field initializers are supported for constructors with parameters, it seems natural to extend that to parameterless constructors as well.\n```csharp\nrecord struct Person()\n{\n    public string Name { get; init; }\n    public object Id { get; init; } = GetNextId();\n}\n```\n\n## Proposal\n\n### Instance field initializers\nInstance field declarations for a struct may include initializers.\n\nAs with class field initializers [§15.5.6.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#15563-instance-field-initialization):\n> A variable initializer for an instance field cannot reference the instance being created. \n\nAn error is reported if a struct has field initializers and no declared instance constructors since the field initializers will not be run.\n```csharp\nstruct S { int F = 42; } // error: 'struct' with field initializers must include an explicitly declared constructor\n```\n\n### Constructors\nA struct may declare a parameterless instance constructor.\n\nA parameterless instance constructor is valid for all struct kinds including `struct`, `readonly struct`, `ref struct`, and `record struct`.\n\nIf no parameterless instance constructor is declared, the struct (see [§16.4.9](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/structs.md#1649-constructors)) ...\n> implicitly has a parameterless instance constructor which always returns the value that results from setting all value type fields to their default value and all reference type fields to null.\n\n### Modifiers\nA parameterless instance struct constructor must be declared `public`.\n```csharp\nstruct S0 { }                   // ok\nstruct S1 { public S1() { } }   // ok\nstruct S2 { internal S2() { } } // error: parameterless constructor must be 'public'\n```\n\nNon-public constructors are ignored when importing types from metadata.\n\nConstructors can be declared `extern` or `unsafe`.\nConstructors cannot be `partial`.\n\n### Executing field initializers\n_Instance variable initializers_ ([§15.11.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#15113-instance-variable-initializers)) is **modified** as follows:\n\n> When **a class** instance constructor has no constructor initializer, or it has a constructor initializer of the form `base(...)`, that constructor implicitly performs the initializations specified by the *variable_initializer*s of the instance fields declared in its class. This corresponds to a sequence of assignments that are executed immediately upon entry to the constructor and before the implicit invocation of the direct base class constructor.\n> \n> **When a struct instance constructor has no constructor initializer, that constructor implicitly performs the initializations specified by the *variable_initializer*s of the instance fields declared in its struct. This corresponds to a sequence of assignments that are executed immediately upon entry to the constructor.**\n> \n> **When a struct instance constructor has a `this()` constructor initializer that represents the _default parameterless constructor_, the declared constructor implicitly clears all instance fields and performs the initializations specified by the *variable_initializer*s of the instance fields declared in its struct. Immediately upon entry to the constructor, all value type fields are set to their default value and all reference type fields are set to `null`. Immediately after that, a sequence of assignments corresponding to the *variable_initializer*s are executed.**\n\n### Definite assignment\nInstance fields (other than `fixed` fields) must be definitely assigned in struct instance constructors that do not have a `this()` initializer (see [§16.4.9](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/structs.md#1649-constructors)).\n\n```csharp\nstruct S0 // ok\n{\n    int x;\n    object y;\n}\n\nstruct S1 // error: 'struct' with field initializers must include an explicitly declared constructor\n{\n    int x = 1;\n    object y;\n}\n\nstruct S2\n{\n    int x = 1;\n    object y;\n    public S2() { } // error in C# 10 (valid starting in C# 11): field 'y' must be assigned\n}\n\nstruct S3 // ok\n{\n    int x = 1;\n    object y;\n    public S3() { y = 2; }\n}\n```\n\n### No `base()` initializer\nA `base()` initializer is disallowed in struct constructors.\n\nThe compiler will not emit a call to the base `System.ValueType` constructor from struct instance constructors.\n\n### `record struct`\nAn error is reported if a `record struct` has field initializers and does not contain a primary constructor nor any instance constructors since the field initializers will not be run.\n```csharp\nrecord struct R0;                  // ok\nrecord struct R1 { int F = 42; }   // error: 'struct' with field initializers must include an explicitly declared constructor\nrecord struct R2() { int F = 42; } // ok\nrecord struct R3(int F);           // ok\n```\n\nA `record struct` with an empty parameter list will have a parameterless primary constructor.\n```csharp\nrecord struct R3();                // primary .ctor: public R3() { }\nrecord struct R4() { int F = 42; } // primary .ctor: public R4() { F = 42; }\n```\n\nAn explicit parameterless constructor in a `record struct` must have a `this` initializer that calls the primary constructor or an explicitly declared constructor.\n```csharp\nrecord struct R5(int F)\n{\n    public R5() { }                  // error: must have 'this' initializer that calls explicit .ctor\n    public R5(object o) : this() { } // ok\n    public int F =  F;\n}\n```\n\n### Fields\nThe implicitly-defined parameterless constructor will zero fields rather than calling any parameterless constructors for the field types. No warnings are reported that field constructors are ignored.\n_No change from C#9._\n\n```csharp\nstruct S0\n{\n    public S0() { }\n}\n\nstruct S1\n{\n    S0 F; // S0 constructor ignored\n}\n\nstruct S<T> where T : struct\n{\n    T F; // constructor (if any) ignored\n}\n```\n\n### `default` expression\n`default` ignores the parameterless constructor and generates a zeroed instance.\n_No change from C#9._\n```csharp\n// struct S { public S() { } }\n\n_ = default(S); // constructor ignored, no warning\n```\n\n### `new()`\nObject creation invokes the parameterless constructor if public; otherwise the instance is zeroed.\n_No change from C#9._\n```csharp\n// public struct PublicConstructor { public PublicConstructor() { } }\n// public struct PrivateConstructor { private PrivateConstructor() { } }\n\n_ = new PublicConstructor();  // call PublicConstructor::.ctor()\n_ = new PrivateConstructor(); // initobj PrivateConstructor\n```\n\nA warning wave may report a warning for use of `new()` with a struct type that has constructors but no parameterless constructor.\nNo warning will be reported when using substituting such a struct type for a type parameter with a `new()` or `struct` constraint.\n```csharp\nstruct S { public S(int i) { } }\nstatic T CreateNew<T>() where T : new() => new T();\n\n_ = new S();        // no warning called\n_ = CreateNew<S>(); // ok\n```\n\n### Uninitialized values\nA local or field of a struct type that is not explicitly initialized is zeroed.\nThe compiler reports a definite assignment error for an uninitialized struct that is not empty. \n_No change from C#9._\n```csharp\nNoConstructor s1;\nPublicConstructor s2;\ns1.ToString(); // error: use of unassigned local (unless type is empty)\ns2.ToString(); // error: use of unassigned local (unless type is empty)\n```\n\n### Array allocation\nArray allocation ignores any parameterless constructor and generates zeroed elements.\n_No change from C#9._\n```csharp\n// struct S { public S() { } }\n\nvar a = new S[1]; // constructor ignored, no warning\n```\n\n### Parameter default value `new()`\nA parameter default value of `new()` binds to the parameterless constructor if public (and reports an error that the value is not constant); otherwise the instance is zeroed.\n_No change from C#9._\n```csharp\n// public struct PublicConstructor { public PublicConstructor() { } }\n// public struct PrivateConstructor { private PrivateConstructor() { } }\n\nstatic void F1(PublicConstructor s1 = new()) { }  // error: default value must be constant\nstatic void F2(PrivateConstructor s2 = new()) { } // ok: initobj\n```\n\n### Type parameter constraints: `new()` and `struct`\nThe `new()` and `struct` type parameter constraints require the parameterless constructor to be `public` if defined (see Satisfying constraints - [§8.4.5](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#845-satisfying-constraints)).\n\nThe compiler assumes all structs satisfy `new()` and `struct` constraints.\n_No change from C#9._\n```csharp\n// public struct PublicConstructor { public PublicConstructor() { } }\n// public struct InternalConstructor { internal InternalConstructor() { } }\n\nstatic T CreateNew<T>() where T : new() => new T();\nstatic T CreateStruct<T>() where T : struct => new T();\n\n_ = CreateNew<PublicConstructor>();      // ok\n_ = CreateStruct<PublicConstructor>();   // ok\n\n_ = CreateNew<InternalConstructor>();    // compiles; may fail at runtime\n_ = CreateStruct<InternalConstructor>(); // compiles; may fail at runtime\n```\n\n`new T()` is emitted as a call to `System.Activator.CreateInstance<T>()`, and the compiler assumes the implementation of `CreateInstance<T>()` invokes the `public` parameterless constructor if defined.\n\n_With .NET Framework, `Activator.CreateInstance<T>()` invokes the parameterless constructor if the constraint is `where T : new()` but appears to ignore the parameterless constructor if the constraint is `where T : struct`._\n\n### Optional parameters\nConstructors with optional parameters are not considered parameterless constructors.\n_No change from C#9._\n```csharp\nstruct S1 { public S1(string s = \"\") { } }\nstruct S2 { public S2(params object[] args) { } }\n\n_ = new S1(); // ok: ignores constructor\n_ = new S2(); // ok: ignores constructor\n```\n\n### Metadata\nExplicit parameterless struct instance constructors will be emitted to metadata.\n\nPublic parameterless struct instance constructors will be imported from metadata; non-public struct instance constructors will be ignored.\n_No change from C#9._\n\n## See also\n\n- https://github.com/dotnet/roslyn/issues/1029\n\n## Design meetings\n\n- https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-04-28.md#open-questions-in-record-and-parameterless-structs\n- https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-03-10.md#parameterless-struct-constructors\n- https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-01-27.md#field-initializers\n"
  },
  {
    "path": "proposals/csharp-10.0/record-structs.md",
    "content": "# Record structs\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/4334>\n\nThe syntax for a record struct is as follows:\n\n```antlr\nrecord_struct_declaration\n    : attributes? struct_modifier* 'partial'? 'record' 'struct' identifier type_parameter_list?\n      parameter_list? struct_interfaces? type_parameter_constraints_clause* record_struct_body\n    ;\n\nrecord_struct_body\n    : struct_body\n    | ';'\n    ;\n```\n\nRecord struct types are value types, like other struct types. They implicitly inherit from the class `System.ValueType`.\nThe modifiers and members of a record struct are subject to the same restrictions as those of structs\n(accessibility on type, modifiers on members, `base(...)` instance constructor initializers,\ndefinite assignment for `this` in constructor, destructors, ...).\nRecord structs will also follow the same rules as structs for parameterless instance constructors and field initializers,\nbut this document assumes that we will lift those restrictions for structs generally.\n\nSee [§16.4.9](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/structs.md#1649-constructors)\nSee [parameterless struct constructors](./parameterless-struct-constructors.md) spec.\n\nRecord structs cannot use `ref` modifier.\n\nAt most one partial type declaration of a partial record struct may provide a `parameter_list`.\nThe `parameter_list` may be empty.\n\nRecord struct parameters cannot use `ref`, `out` or `this` modifiers (but `in` and `params` are allowed).\n\n## Members of a record struct\n\nIn addition to the members declared in the record struct body, a record struct type has additional synthesized members.\nMembers are synthesized unless a member with a \"matching\" signature is declared in the record struct body or\nan accessible concrete non-virtual member with a \"matching\" signature is inherited.\nTwo members are considered matching if they have the same\nsignature or would be considered \"hiding\" in an inheritance scenario.\nSee Signatures and overloading [§7.6](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/basic-concepts.md#76-signatures-and-overloading).\nIt is an error for a member of a record struct to be named \"Clone\".\n\nIt is an error for an instance field of a record struct to have an unsafe type.\n\nA record struct is not permitted to declare a destructor.\n\nThe synthesized members are as follows:\n\n### Equality members\n\nThe synthesized equality members are similar as in a record class (`Equals` for this type, `Equals` for `object` type, `==` and `!=` operators for this type),\\\nexcept for the lack of `EqualityContract`, null checks or inheritance.\n\nThe record struct implements `System.IEquatable<R>` and includes a synthesized strongly-typed overload of `Equals(R other)` where `R` is the record struct.\nThe method is `public`.\nThe method can be declared explicitly. It is an error if the explicit declaration does not match the expected signature or accessibility.\n\nIf `Equals(R other)` is user-defined (not synthesized) but `GetHashCode` is not, a warning is produced.\n\n```C#\npublic readonly bool Equals(R other);\n```\n\nThe synthesized `Equals(R)` returns `true` if and only if for each instance field `fieldN` in the record struct\nthe value of `System.Collections.Generic.EqualityComparer<TN>.Default.Equals(fieldN, other.fieldN)` where `TN` is the field type is `true`.\n\nThe record struct includes synthesized `==` and `!=` operators equivalent to operators declared as follows:\n```C#\npublic static bool operator==(R r1, R r2)\n    => r1.Equals(r2);\npublic static bool operator!=(R r1, R r2)\n    => !(r1 == r2);\n```\nThe `Equals` method called by the `==` operator is the `Equals(R other)` method specified above. The `!=` operator delegates to the `==` operator. It is an error if the operators are declared explicitly.\n\nThe record struct includes a synthesized override equivalent to a method declared as follows:\n```C#\npublic override readonly bool Equals(object? obj);\n```\nIt is an error if the override is declared explicitly. \nThe synthesized override returns `other is R temp && Equals(temp)` where `R` is the record struct.\n\nThe record struct includes a synthesized override equivalent to a method declared as follows:\n```C#\npublic override readonly int GetHashCode();\n```\nThe method can be declared explicitly.\n\nA warning is reported if one of `Equals(R)` and `GetHashCode()` is explicitly declared but the other method is not explicit.\n\nThe synthesized override of `GetHashCode()` returns an `int` result of combining the values of `System.Collections.Generic.EqualityComparer<TN>.Default.GetHashCode(fieldN)` for each instance field `fieldN` with `TN` being the type of `fieldN`.\n\nFor example, consider the following record struct:\n```C#\nrecord struct R1(T1 P1, T2 P2);\n```\n\nFor this record struct, the synthesized equality members would be something like:\n```C#\nstruct R1 : IEquatable<R1>\n{\n    public T1 P1 { get; set; }\n    public T2 P2 { get; set; }\n    public override bool Equals(object? obj) => obj is R1 temp && Equals(temp);\n    public bool Equals(R1 other)\n    {\n        return\n            EqualityComparer<T1>.Default.Equals(P1, other.P1) &&\n            EqualityComparer<T2>.Default.Equals(P2, other.P2);\n    }\n    public static bool operator==(R1 r1, R1 r2)\n        => r1.Equals(r2);\n    public static bool operator!=(R1 r1, R1 r2)\n        => !(r1 == r2);    \n    public override int GetHashCode()\n    {\n        return Combine(\n            EqualityComparer<T1>.Default.GetHashCode(P1),\n            EqualityComparer<T2>.Default.GetHashCode(P2));\n    }\n}\n```\n\n### Printing members: PrintMembers and ToString methods\n\nThe record struct includes a synthesized method equivalent to a method declared as follows:\n```C#\nprivate bool PrintMembers(System.Text.StringBuilder builder);\n```\n\nThe method does the following:\n1. for each of the record struct's printable members (non-static public field and readable property members), appends that member's name followed by \" = \" followed by the member's value separated with \", \",\n2. return true if the record struct has printable members.\n\nFor a member that has a value type, we will convert its value to a string representation using the most efficient method available to the target platform. At present that means calling `ToString` before passing to `StringBuilder.Append`.\n\nIf the record's printable members do not include a readable property with a non-`readonly` `get` accessor, then the synthesized `PrintMembers` is `readonly`. There is no requirement for the record's fields to be `readonly` for the `PrintMembers` method to be `readonly`.\n\nThe `PrintMembers` method can be declared explicitly.\nIt is an error if the explicit declaration does not match the expected signature or accessibility.\n\nThe record struct includes a synthesized method equivalent to a method declared as follows:\n```C#\npublic override string ToString();\n```\n\nIf the record struct's `PrintMembers` method is `readonly`, then the synthesized `ToString()` method is `readonly`.\n\nThe method can be declared explicitly. It is an error if the explicit declaration does not match the expected signature or accessibility.\n\nThe synthesized method:\n1. creates a `StringBuilder` instance,\n2. appends the record struct name to the builder, followed by \" { \",\n3. invokes the record struct's `PrintMembers` method giving it the builder, followed by \" \" if it returned true,\n4. appends \"}\",\n5. returns the builder's contents with `builder.ToString()`.\n\nFor example, consider the following record struct:\n\n``` csharp\nrecord struct R1(T1 P1, T2 P2);\n```\n\nFor this record struct, the synthesized printing members would be something like:\n\n```C#\nstruct R1 : IEquatable<R1>\n{\n    public T1 P1 { get; set; }\n    public T2 P2 { get; set; }\n\n    private bool PrintMembers(StringBuilder builder)\n    {\n        builder.Append(nameof(P1));\n        builder.Append(\" = \");\n        builder.Append(this.P1); // or builder.Append(this.P1.ToString()); if P1 has a value type\n        builder.Append(\", \");\n\n        builder.Append(nameof(P2));\n        builder.Append(\" = \");\n        builder.Append(this.P2); // or builder.Append(this.P2.ToString()); if P2 has a value type\n\n        return true;\n    }\n\n    public override string ToString()\n    {\n        var builder = new StringBuilder();\n        builder.Append(nameof(R1));\n        builder.Append(\" { \");\n\n        if (PrintMembers(builder))\n            builder.Append(\" \");\n\n        builder.Append(\"}\");\n        return builder.ToString();\n    }\n}\n```\n\n## Positional record struct members\n\nIn addition to the above members, record structs with a parameter list (\"positional records\") synthesize\nadditional members with the same conditions as the members above.\n\n### Primary Constructor\n\nA record struct has a public constructor whose signature corresponds to the value parameters of the\ntype declaration. This is called the primary constructor for the type. It is an error to have a primary\nconstructor and a constructor with the same signature already present in the struct.\nIf the type declaration does not include a parameter list, no primary constructor is generated.\n\n```csharp\nrecord struct R1\n{\n    public R1() { } // ok\n}\n\nrecord struct R2()\n{\n    public R2() { } // error: 'R2' already defines constructor with same parameter types\n}\n```\n\nInstance field declarations for a record struct are permitted to include variable initializers.\nIf there is no primary constructor, the instance initializers execute as part of the parameterless constructor.\nOtherwise, at runtime the primary constructor executes the instance initializers appearing in the record-struct-body.\n\nIf a record struct has a primary constructor, any user-defined constructor must have an\nexplicit `this` constructor initializer that calls the primary constructor or an explicitly declared constructor.\n\nParameters of the primary constructor as well as members of the record struct are in scope within initializers of instance fields or properties. \nInstance members would be an error in these locations (similar to how instance members are in scope in regular constructor initializers\ntoday, but an error to use), but the parameters of the primary constructor would be in scope and useable and\nwould shadow members. Static members would also be useable.\n\nA warning is produced if a parameter of the primary constructor is not read.\n\nThe definite assignment rules for struct instance constructors apply to the primary constructor of record structs. For instance, the following\nis an error:\n\n```csharp\nrecord struct Pos(int X) // definite assignment error in primary constructor\n{\n    private int x;\n    public int X { get { return x; } set { x = value; } } = X;\n}\n```\n\n### Properties\n\nFor each record struct parameter of a record struct declaration there is a corresponding public property\nmember whose name and type are taken from the value parameter declaration.\n\nFor a record struct:\n\n* A public `get` and `init` auto-property is created if the record struct has `readonly` modifier, `get` and `set` otherwise.\n  Both kinds of set accessors (`set` and `init`) are considered \"matching\". So the user may declare an init-only property\n  in place of a synthesized mutable one.\n  An inherited `abstract` property with matching type is overridden.\n  No auto-property is created if the record struct has an instance field with expected name and type.\n  It is an error if the inherited property does not have `public` `get` and `set`/`init` accessors.\n  It is an error if the inherited property or field is hidden.  \n  The auto-property is initialized to the value of the corresponding primary constructor parameter.\n  Attributes can be applied to the synthesized auto-property and its backing field by using `property:` or `field:`\n  targets for attributes syntactically applied to the corresponding record struct parameter.  \n\n### Deconstruct\n\nA positional record struct with at least one parameter synthesizes a public void-returning instance method called `Deconstruct` with an out\nparameter declaration for each parameter of the primary constructor declaration. Each parameter\nof the Deconstruct method has the same type as the corresponding parameter of the primary\nconstructor declaration. The body of the method assigns each parameter of the Deconstruct method\nto the value from an instance member access to a member of the same name.\nIf the instance members accessed in the body do not include a property with\na non-`readonly` `get` accessor, then the synthesized `Deconstruct` method is `readonly`.\nThe method can be declared explicitly. It is an error if the explicit declaration does not match\nthe expected signature or accessibility, or is static.\n\n## Allow `with` expression on structs\n\nIt is now valid for the receiver in a `with` expression to have a struct type.\n\nOn the right hand side of the `with` expression is a `member_initializer_list` with a sequence\nof assignments to *identifier*, which must be an accessible instance field or property of the receiver's\ntype.\n\nFor a receiver with struct type, the receiver is first copied, then each `member_initializer` is processed \nthe same way as an assignment to a field or property access of the result of the conversion. \nAssignments are processed in lexical order.\n\n## Improvements on records\n\n### Allow `record class`\n\nThe existing syntax for record types allows `record class` with the same meaning as `record`:\n\n```antlr\nrecord_declaration\n    : attributes? class_modifier* 'partial'? 'record' 'class'? identifier type_parameter_list?\n      parameter_list? record_base? type_parameter_constraints_clause* record_body\n    ;\n```\n\n### Allow user-defined positional members to be fields\n\nSee https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-10-05.md#changing-the-member-type-of-a-primary-constructor-parameter\n\nNo auto-property is created if the record has or inherits an instance field with expected name and type.\n\n## Allow parameterless constructors and member initializers in structs\n\nSee [parameterless struct constructors](./parameterless-struct-constructors.md) spec.\n\n## Open questions\n\n- how to recognize record structs in metadata? (we don't have an unspeakable clone method to leverage...)\n\n### Answered\n\n- confirm that we want to keep PrintMembers design (separate method returning `bool`) (answer: yes)\n- confirm we won't allow `record ref struct` (issue with `IEquatable<RefStruct>` and ref fields) (answer: yes)\n- confirm implementation of equality members. Alternative is that synthesized `bool Equals(R other)`, `bool Equals(object? other)` and operators all just delegate to `ValueType.Equals`. (answer: yes)\n- confirm that we want to allow field initializers when there is a primary constructor. Do we also want to allow parameterless struct constructors while we're at it (the Activator issue was apparently fixed)? (answer: yes, updated spec should be reviewed in LDM)\n- how much do we want to say about `Combine` method? (answer: as little as possible)\n- should we disallow a user-defined constructor with a copy constructor signature? (answer: no, there is no notion of copy constructor in the record structs spec)\n- confirm that we want to disallow members named \"Clone\". (answer: correct)\n- double-check that synthesized `Equals` logic is functionally equivalent to runtime implementation (e.g. float.NaN) (answer: confirmed in LDM)\n- could field- or property-targeting attributes be placed in the positional parameter list? (answer: yes, same as for record class)\n- `with` on generics? (answer: out of scope for C# 10)\n- should `GetHashCode` include a hash of the type itself, to get different values between `record struct S1;` and `record struct S2;`? (answer: no)\n"
  },
  {
    "path": "proposals/csharp-11.0/auto-default-structs.md",
    "content": "# Auto-default structs\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/5737>\n\n## Summary\n\nThis feature makes it so that in struct constructors, we identify fields which were not explicitly assigned by the user before returning or before use, and initialize them implicitly to `default` instead of giving definite assignment errors.\n\n## Motivation\n\nThis proposal is raised as a possible mitigation for usability issues found in dotnet/csharplang#5552 and dotnet/csharplang#5635, as well as addressing #5563 (all fields must be definitely assigned, but `field` is not accessible within the constructor).\n\n---\n\nSince C# 1.0, struct constructors have been required to definitely assign `this` as if it were an `out` parameter.\n\n```cs\npublic struct S\n{\n    public int x, y;\n    public S() // error: Fields 'S.x' and 'S.y' must be fully assigned before control is returned to the caller\n    {\n    }\n}\n```\n\nThis presents issues when setters are manually defined on semi-auto properties, since the compiler can't treat assignment of the property as equivalent to assignment of the backing field.\n\n```cs\npublic struct S\n{\n    public int X { get => field; set => field = value; }\n    public S() // error: struct fields aren't fully assigned. But caller can only assign 'this.field' by assigning 'this'.\n    {\n    }\n}\n```\nWe assume that introducing finer-grained restrictions for setters, such as a scheme where the setter doesn't take `ref this` but rather takes `out field` as a parameter, is going to be too niche and incomplete for some use cases.\n\nOne fundamental tension we are struggling with is that when struct properties have manually implemented setters, users often have to do some form of \"repetition\" of either repeatedly assigning or repeating their logic:\n```cs\nstruct S\n{\n    private int _x;\n    public int X\n    {\n        get => _x;\n        set => _x = value >= 0 ? value : throw new ArgumentOutOfRangeException();\n    }\n\n    // Solution 1: assign some value in the constructor before \"really\" assigning through the property setter.\n    public S(int x)\n    {\n        _x = default;\n        X = x;\n    }\n\n    // Solution 2: assign the field once in the constructor, repeating the implementation of the setter.\n    public S(int x)\n    {\n        _x = x >= 0 ? x : throw new ArgumentOutOfRangeException();\n    }\n}\n```\n\n## Previous discussion\nA small group has looked at this issue and considered a few possible solutions:\n1. Require users to assign `this = default` when semi-auto properties have manually implemented setters. We agree this is the wrong solution since it blows away values set in field initializers.\n2. Implicitly initialize all backing fields of auto/semi-auto properties.\n    - This solves the \"semi-auto property setters\" problem, and it squarely places explicitly declared fields under different rules: \"don't implicitly initialize my fields, but do implicitly initialize my auto-properties.\"\n3. Provide a way to assign the backing field of a semi-auto property and require users to assign it.\n    - This could be cumbersome compared to (2). An auto property is supposed to be \"automatic\", and perhaps that includes \"automatic\" initialization of the field. It could introduce confusion as to when the underlying field is being assigned by an assignment to the property, and when the property setter is being called.\n\nWe've also received [feedback](https://github.com/dotnet/csharplang/discussions/5635) from users who want to, for example, include a few field initializers in structs without having to explicitly assign everything. We can solve this issue as well as the \"semi-auto property with manually implemented setter\" issue at the same time.\n```cs\nstruct MagnitudeVector3d\n{\n    double X, Y, Z;\n    double Magnitude = 1;\n    public MagnitudeVector3d() // error: must assign 'X', 'Y', 'Z' before returning\n    {\n    }\n}\n```\n\n## Adjusting definite assignment\nInstead of performing a definite assignment analysis to give errors for unassigned fields on `this`, we do it to determine *which fields need to be initialized implicitly*. Such initialization is inserted at the *beginning of the constructor*.\n\n```cs\nstruct S\n{\n    int x, y;\n\n    // Example 1\n    public S()\n    {\n        // ok. Compiler inserts an assignment of `this = default`.\n    }\n\n    // Example 2\n    public S()\n    {\n        // ok. Compiler inserts an assignment of `y = default`.\n        x = 1;\n    }\n\n    // Example 3\n    public S()\n    {\n        // valid since C# 1.0. Compiler inserts no implicit assignments.\n        x = 1;\n        y = 2;\n    }\n\n    // Example 4\n    public S(bool b)\n    {\n        // ok. Compiler inserts assignment of `this = default`.\n        if (b)\n            x = 1;\n        else\n            y = 2;\n    }\n\n    // Example 5\n    void M() { }\n    public S(bool b)\n    {\n        // ok. Compiler inserts assignment of `y = default`.\n        x = 1;\n        if (b)\n            M();\n\n        y = 2;\n    }\n}\n```\n\nIn examples (4) and (5), the resulting codegen sometimes has \"double assignments\" of fields. This is generally fine, but for users who are concerned with such double assignments, we can emit what used to be definite assignment error diagnostics as *disabled-by-default* warning diagnostics.\n\n```cs\nstruct S\n{\n    int x;\n    public S() // warning: 'S.x' is implicitly initialized to 'default'.\n    {\n    }\n}\n```\n\nUsers who set the severity of this diagnostic to \"error\" will opt in to the pre-C# 11 behavior. Such users are essentially \"shut out\" of semi-auto properties with manually implemented setters.\n\n```cs\nstruct S\n{\n    public int X\n    {\n        get => field;\n        set => field = field < value ? value : field;\n    }\n\n    public S() // error: backing field of 'S.X' is implicitly initialized to 'default'.\n    {\n        X = 1;\n    }\n}\n```\n\nAt first glance, this feels like a \"hole\" in the feature, but it's **actually the right thing to do**. By enabling the diagnostic, the user is telling us that they don't want the compiler to implicitly initialize their fields in the constructor. There's no way to avoid the implicit initialization here, so the solution for them is to use a different way of initializing the field than a manually implemented setter, such as manually declaring the field and assigning it, or by including a field initializer.\n\nCurrently, the JIT does not eliminate dead stores through refs, which means that these implicit initializations do have a real cost. But that might be fixable. https://github.com/dotnet/runtime/issues/13727\n\nIt's worth noting that initializing individual fields instead of the entire instance is really just an optimization. The compiler should probably be free to implement whatever heuristic it wants, as long as it meets the invariant that fields which are not definitely assigned at all return points or before any non-field member access of `this` are implicitly initialized.\n\nFor example, if a struct has 100 fields, and just one of them is explicitly initialized, it might make more sense to do an `initobj` on the entire thing, than to implicitly emit `initobj` for the 99 other fields. However, an implementation which implicitly emits `initobj` for the 99 other fields would still be valid.\n\n## Changes to language specification\n\nWe adjust the following section of the standard:\n\nhttps://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12814-this-access\n> If the constructor declaration has no constructor initializer, the `this` variable behaves exactly the same as an `out` parameter of the struct type. In particular, this means that the variable shall be definitely assigned in every execution path of the instance constructor.\n\nWe adjust this language to read:\n\nIf the constructor declaration has no constructor initializer, the `this` variable behaves similarly to an `out` parameter of the struct type, except that it is not an error when the definite assignment requirements ([§9.4.1](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/variables.md#941-general)) are not met. Instead, we introduce the following behaviors:\n\n  1. When the `this` variable itself does not meet the requirements, then all unassigned instance variables within `this` at all points where requirements are violated are implicitly initialized to the default value ([§9.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/variables.md#93-default-values)) in an *initialization* phase before any other code in the constructor runs.\n2. When an instance variable *v* within `this` does not meet the requirements, or any instance variable at any level of nesting within *v* does not meet the requirements, then *v* is implicitly initialized to the default value in an *initialization* phase before any other code in the constructor runs.\n\n## Design meetings\n\nhttps://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-14.md#definite-assignment-in-structs\n"
  },
  {
    "path": "proposals/csharp-11.0/checked-user-defined-operators.md",
    "content": "# Checked user-defined operators\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/4665>\n\n## Summary\n[summary]: #summary\n\nC# should support defining `checked` variants of the following user-defined operators so that users can opt into or out of overflow behavior as appropriate:\n*  The `++` and `--` unary operators [§12.8.16](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12816-postfix-increment-and-decrement-operators) and [§12.9.6](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1296-prefix-increment-and-decrement-operators).\n*  The `-` unary operator [§12.9.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1293-unary-minus-operator).\n*  The `+`, `-`, `*`, and `/` binary operators [§12.10](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1210-arithmetic-operators).\n*  Explicit conversion operators.\n\n## Motivation\n[motivation]: #motivation\n\nThere is no way for a user to declare a type and support both checked and unchecked versions of an operator. This will make it hard to port various algorithms to use the proposed `generic math` interfaces exposed by the libraries team. Likewise, this makes it impossible to expose a type such as `Int128` or `UInt128` without the language simultaneously shipping its own support to avoid breaking changes.\n\n## Detailed design\n[design]: #detailed-design\n\n### Syntax\n\nGrammar at operators ([§15.10](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#1510-operators)) will be adjusted to allow\n`checked` keyword after the `operator` keyword right before the operator token:\n```antlr\noverloadable_unary_operator\n    : '+' | 'checked'? '-' | '!' | '~' | 'checked'? '++' | 'checked'? '--' | 'true' | 'false'\n    ;\n\noverloadable_binary_operator\n    : 'checked'? '+'   | 'checked'? '-'   | 'checked'? '*'   | 'checked'? '/'   | '%'   | '&'   | '|'   | '^'   | '<<'\n    | right_shift | '=='  | '!='  | '>'   | '<'   | '>='  | '<='\n    ;\n    \nconversion_operator_declarator\n    : 'implicit' 'operator' type '(' type identifier ')'\n    | 'explicit' 'operator' 'checked'? type '(' type identifier ')'\n    ;    \n```\n\nFor example:\n``` C#\npublic static T operator checked ++(T x) {...}\npublic static T operator checked --(T x) {...}\npublic static T operator checked -(T x) {...}\npublic static T operator checked +(T lhs, T rhs) {...}\npublic static T operator checked -(T lhs, T rhs) {...}\npublic static T operator checked *(T lhs, T rhs) {...}\npublic static T operator checked /(T lhs, T rhs) {...}\npublic static explicit operator checked U(T x) {...}\n```\n\n``` C#\npublic static T I1.operator checked ++(T x) {...}\npublic static T I1.operator checked --(T x) {...}\npublic static T I1.operator checked -(T x) {...}\npublic static T I1.operator checked +(T lhs, T rhs) {...}\npublic static T I1.operator checked -(T lhs, T rhs) {...}\npublic static T I1.operator checked *(T lhs, T rhs) {...}\npublic static T I1.operator checked /(T lhs, T rhs) {...}\npublic static explicit I1.operator checked U(T x) {...}\n```\n\nFor brevity below, an operator with the `checked` keyword is referred to as a `checked operator` and an operator without it is referred to as a `regular operator`. These terms are not applicable to operators that don't have a `checked` form.\n\n### Semantics\n\nA user-defined `checked operator` is expected to throw an exception when the result of an operation is too large to represent in the destination type. What does it mean to be too large actually depends on the nature of the destination type and is not prescribed by the language. Typically the exception thrown is a `System.OverflowException`, but the language doesn't have any specific requirements regarding this.\n\nA user-defined `regular operator` is expected to not throw an exception when the result of an operation is too large to represent in the destination type. Instead, it is expected to return an instance representing a truncated result. What does it mean to be too large and to be truncated actually depends on the nature of the destination type and is not prescribed by the language. \n\nAll existing user-defined operators out there that will have `checked` form supported fall into the category of `regular operators`. It is understood that many of them are likely to not follow the semantics specified above, but for the purpose of semantic analysis, compiler will assume that they are.\n\n### Checked vs. unchecked context within a `checked operator`\n\nChecked/unchecked context within the body of a `checked operator` is not affected by the presence of the `checked` keyword. In other words, the context is the same as immediately at the beginning of the operator declaration. The developer would need to explicitly switch the context if part of their algorithm cannot rely on default context.\n\n### Names in metadata\n\nSection \"I.10.3.1 Unary operators\" of ECMA-335 will be adjusted to include *op_CheckedIncrement*, *op_CheckedDecrement*, *op_CheckedUnaryNegation* as the names for methods implementing checked `++`, `--` and `-` unary operators.\n\nSection \"I.10.3.2 Binary operators\" of ECMA-335 will be adjusted to include *op_CheckedAddition*, *op_CheckedSubtraction*,\n*op_CheckedMultiply*, *op_CheckedDivision* as the names for methods implementing checked `+`, `-`, `*`, and `/` binary operators.\n\nSection \"I.10.3.3 Conversion operators\" of ECMA-335 will be adjusted to include *op_CheckedExplicit* as the name for a method\nimplementing checked explicit conversion operator.\n\n### Unary operators\n\nUnary `checked operators` follow the rules from [§15.10.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#15102-unary-operators).\n\nAlso, a `checked operator` declaration requires a pair-wise declaration of a `regular operator` (the return type should match as well). A compile-time error occurs otherwise. \n\n``` C#\npublic struct Int128\n{\n    // This is fine, both a checked and regular operator are defined\n    public static Int128 operator checked -(Int128 lhs);\n    public static Int128 operator -(Int128 lhs);\n\n    // This is fine, only a regular operator is defined\n    public static Int128 operator --(Int128 lhs);\n\n    // This should error, a regular operator must also be defined\n    public static Int128 operator checked ++(Int128 lhs);\n}\n```\n\n### Binary operators\n\nBinary `checked operators` follow the rules from [§15.10.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#15103-binary-operators).\n\nAlso, a `checked operator` declaration requires a pair-wise declaration of a `regular operator` (the return type should match as well). A compile-time error occurs otherwise. \n\n``` C#\npublic struct Int128\n{\n    // This is fine, both a checked and regular operator are defined\n    public static Int128 operator checked +(Int128 lhs, Int128 rhs);\n    public static Int128 operator +(Int128 lhs, Int128 rhs);\n\n    // This is fine, only a regular operator is defined\n    public static Int128 operator -(Int128 lhs, Int128 rhs);\n\n    // This should error, a regular operator must also be defined\n    public static Int128 operator checked *(Int128 lhs, Int128 rhs);\n}\n```\n\n### Candidate user-defined operators\n\nThe Candidate user operators ([§12.4.6](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1246-candidate-user-operators)) section will be adjusted as follows (additions/changes are in bold).\n\nGiven a type `T` and an operation `operator op(A)`, where `op` is an overloadable operator and `A` is an argument list, the set of candidate user-defined operators provided by `T` for `operator op(A)` is determined as follows:\n\n*  Determine the type `T0`. If `T` is a nullable type, `T0` is its underlying type, otherwise `T0` is equal to `T`.\n*  **Find the set of user-defined operators, `U`. This set consists of:**\n    *  **In `unchecked` evaluation context, all regular `operator op` declarations in `T0`.**\n    *  **In `checked` evaluation context, all checked and regular `operator op` declarations in `T0` except regular declarations that have pair-wise matching `checked operator` declaration.**\n*  For all `operator op` declarations in **`U`** and all lifted forms of such operators, if at least one operator is applicable ([§12.4.6 - Applicable function member](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1246-candidate-user-operators)) with respect to the argument list `A`, then the set of candidate operators consists of all such applicable operators in `T0`.\n*  Otherwise, if `T0` is `object`, the set of candidate operators is empty.\n*  Otherwise, the set of candidate operators provided by `T0` is the set of candidate operators provided by the direct base class of `T0`, or the effective base class of `T0` if `T0` is a type parameter.\n\nSimilar rules will be applied while determining the set of candidate operators in interfaces https://github.com/dotnet/csharplang/blob/main/meetings/2017/LDM-2017-06-27.md#shadowing-within-interfaces.\n\nThe section [§12.8.20](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12820-the-checked-and-unchecked-operators) will be adjusted to reflect the effect that the checked/unchecked context has on unary and binary operator overload resolution.\n\n#### Example #1:\n``` C#\npublic class MyClass\n{\n    public static void Add(Int128 lhs, Int128 rhs)\n    {\n        // Resolves to `op_CheckedAddition`\n        Int128 r1 = checked(lhs + rhs);\n\n        // Resolves to `op_Addition`\n        Int128 r2 = unchecked(lhs + rhs);\n\n        // Resolve to `op_Subtraction`\n        Int128 r3 = checked(lhs - rhs);\n\n        // Resolve to `op_Subtraction`\n        Int128 r4 = unchecked(lhs - rhs);\n\n        // Resolves to `op_CheckedMultiply`\n        Int128 r5 = checked(lhs * rhs);\n\n        // Error: Operator '*' cannot be applied to operands of type 'Int128' and 'Int128'\n        Int128 r6 = unchecked(lhs * rhs);\n    }\n\n    public static void Divide(Int128 lhs, byte rhs)\n    {\n        // Resolves to `op_Division` - it is a better match than `op_CheckedDivision`\n        Int128 r4 = checked(lhs / rhs);\n    }\n}\n\npublic struct Int128\n{\n    public static Int128 operator checked +(Int128 lhs, Int128 rhs);\n    public static Int128 operator +(Int128 lhs, Int128 rhs);\n\n    public static Int128 operator -(Int128 lhs, Int128 rhs);\n\n    // Cannot be declared in C# - missing unchecked operator, but could be declared by some other language\n    public static Int128 operator checked *(Int128 lhs, Int128 rhs);\n\n    public static Int128 operator checked /(Int128 lhs, int rhs);\n\n    public static Int128 operator /(Int128 lhs, byte rhs);\n}\n```\n\n#### Example #2:\n``` C#\nclass C\n{\n    static void Add(C2 x, C3 y)\n    {\n        object o;\n        \n        // error CS0034: Operator '+' is ambiguous on operands of type 'C2' and 'C3'\n        o = checked(x + y);\n        \n        // C2.op_Addition\n        o = unchecked(x + y);\n    }\n}\n\nclass C1\n{\n    // Cannot be declared in C# - missing unchecked operator, but could be declared by some other language\n    public static C1 operator checked + (C1 x, C3 y) => new C3();\n}\n\nclass C2 : C1\n{\n    public static C2 operator + (C2 x, C1 y) => new C2();\n}\n\nclass C3 : C1\n{\n}\n```\n\n#### Example #3:\n``` C#\nclass C\n{\n    static void Add(C2 x, C3 y)\n    {\n        object o;\n        \n        // error CS0034: Operator '+' is ambiguous on operands of type 'C2' and 'C3'\n        o = checked(x + y);\n        \n        // C1.op_Addition\n        o = unchecked(x + y);\n    }\n}\n\nclass C1\n{\n    public static C1 operator + (C1 x, C3 y) => new C3();\n}\n\nclass C2 : C1\n{\n    // Cannot be declared in C# - missing unchecked operator, but could be declared by some other language\n    public static C2 operator checked + (C2 x, C1 y) => new C2();\n}\n\nclass C3 : C1\n{\n}\n```\n\n### Conversion operators\n\nConversion `checked operators` follow the rules from [§15.10.4](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#15104-conversion-operators).\n\nHowever, a `checked operator` declaration requires a pair-wise declaration of a `regular operator`. A compile-time error occurs otherwise. \n\nThe following paragraph \n>The signature of a conversion operator consists of the source type and the target type. (This is the only form of member for which the return type participates in the signature.) The implicit or explicit classification of a conversion operator is not part of the operator's signature. Thus, a class or struct cannot declare both an implicit and an explicit conversion operator with the same source and target types.\n\nwill be adjusted to allow a type to declare checked and regular forms of explicit conversions with the same source and target types.\nA type will not be allowed to declare both an implicit and a checked explicit conversion operator with the same source and target types.\n\n### Processing of user-defined explicit conversions \n\nThe third bullet in [§10.5.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#1055-user-defined-explicit-conversions):\n>*  Find the set of applicable user-defined and lifted conversion operators, `U`. This set consists of the user-defined and lifted implicit or explicit conversion operators declared by the classes or structs in `D` that convert from a type encompassing or encompassed by `S` to a type encompassing or encompassed by `T`. If `U` is empty, the conversion is undefined and a compile-time error occurs.\n\nwill be replaced with the following bullet points:\n*  **Find the set of conversion operators, `U0`. This set consists of:**\n    *  **In `unchecked` evaluation context, the user-defined implicit or regular explicit conversion operators declared by the classes or structs in `D`.**\n    *  **In `checked` evaluation context, the user-defined implicit or regular/checked explicit conversion operators declared by the classes or structs in `D` except regular explicit conversion operators that have pair-wise matching `checked operator` declaration within the same declaring type.**\n*  Find the set of applicable user-defined and lifted conversion operators, `U`. This set consists of the user-defined and lifted implicit or explicit conversion operators **in `U0`** that convert from a type encompassing or encompassed by `S` to a type encompassing or encompassed by `T`. If `U` is empty, the conversion is undefined and a compile-time error occurs.\n\nThe Checked and unchecked operators [§11.8.20](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12820-the-checked-and-unchecked-operators) section will be adjusted to reflect the effect that the checked/unchecked context has on processing of user-defined explicit conversions.\n\n### Implementing operators\n\nA `checked operator` does not implement a `regular operator` and vice versa.\n\n### Linq Expression Trees \n\n`Checked operators` will be supported in Linq Expression Trees. A `UnaryExpression`/`BinaryExpression` node will be created with corresponding `MethodInfo`.\nThe following factory methods will be used:\n``` C#\npublic static UnaryExpression NegateChecked (Expression expression, MethodInfo? method);\n\npublic static BinaryExpression AddChecked (Expression left, Expression right, MethodInfo? method);\npublic static BinaryExpression SubtractChecked (Expression left, Expression right, MethodInfo? method);\npublic static BinaryExpression MultiplyChecked (Expression left, Expression right, MethodInfo? method);\n\npublic static UnaryExpression ConvertChecked (Expression expression, Type type, MethodInfo? method);\n```\n\nNote, that C# doesn't support assignments in expression trees, therefore checked increment/decrement will not be supported as well.\n\nThere is no factory method for checked divide. There is an open question regarding this - [Checked division in Linq Expression Trees](checked-user-defined-operators.md#checked-division-in-linq-expression-trees).\n\n### Dynamic\n\nWe will investigate the cost of adding support for checked operators in dynamic invocation in CoreCLR and pursue an implementation if the cost is not too high.\nThis is a quote from https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nThis adds additional complexity to the language and allows users to introduce more kinds of breaking changes to their types.\n\n## Alternatives\n[alternatives]: #alternatives\n\nThe generic math interfaces that the libraries plans to expose could expose named methods (such as `AddChecked`). The primary drawback is that this is less readable/maintainable and doesn't get the benefit of the language precedence rules around operators.\n\nThis section lists alternatives discussed, but not implemented\n\n<details>\n\n### Placement of the `checked` keyword\n\nAlternatively the `checked` keyword could be moved to the place right before the `operator` keyword:  \n``` C#\npublic static T checked operator ++(T x) {...}\npublic static T checked operator --(T x) {...}\npublic static T checked operator -(T x) {...}\npublic static T checked operator +(T lhs, T rhs) {...}\npublic static T checked operator -(T lhs, T rhs) {...}\npublic static T checked operator *(T lhs, T rhs) {...}\npublic static T checked operator /(T lhs, T rhs) {...}\npublic static explicit checked operator U(T x) {...}\n```\n\n``` C#\npublic static T checked I1.operator ++(T x) {...}\npublic static T checked I1.operator --(T x) {...}\npublic static T checked I1.operator -(T x) {...}\npublic static T checked I1.operator +(T lhs, T rhs) {...}\npublic static T checked I1.operator -(T lhs, T rhs) {...}\npublic static T checked I1.operator *(T lhs, T rhs) {...}\npublic static T checked I1.operator /(T lhs, T rhs) {...}\npublic static explicit checked I1.operator U(T x) {...}\n```\n\nOr it could be moved into the set of operator modifiers:\n```antlr\noperator_modifier\n    : 'public'\n    | 'static'\n    | 'extern'\n    | 'checked'\n    | operator_modifier_unsafe\n    ;\n```\n\n``` C#\npublic static checked T operator ++(T x) {...}\npublic static checked T operator --(T x) {...}\npublic static checked T operator -(T x) {...}\npublic static checked T operator +(T lhs, T rhs) {...}\npublic static checked T operator -(T lhs, T rhs) {...}\npublic static checked T operator *(T lhs, T rhs) {...}\npublic static checked T operator /(T lhs, T rhs) {...}\npublic static checked explicit operator U(T x) {...}\n```\n\n``` C#\npublic static checked T I1.operator ++(T x) {...}\npublic static checked T I1.operator --(T x) {...}\npublic static checked T I1.operator -(T x) {...}\npublic static checked T I1.operator +(T lhs, T rhs) {...}\npublic static checked T I1.operator -(T lhs, T rhs) {...}\npublic static checked T I1.operator *(T lhs, T rhs) {...}\npublic static checked T I1.operator /(T lhs, T rhs) {...}\npublic static checked explicit I1.operator U(T x) {...}\n```\n    \n### `unchecked` keyword\n\nThere were suggestions to support `unchecked` keyword at the same position as the `checked` keyword\nwith the following possible meanings:\n- Simply to explicitly reflect the regular nature of the operator, or\n- Perhaps to designate a distinct flavor of an operator that is supposed to be used in an `unchecked` context. The language could support `op_Addition`, `op_CheckedAddition`, and `op_UncheckedAddition` to help limit the number of breaking changes. This adds another layer of complexity that is likely not necessary in most code.\n\n### Operator names in ECMA-335\n\nAlternatively the operator names could be *op_UnaryNegationChecked*, *op_AdditionChecked*, *op_SubtractionChecked*,\n*op_MultiplyChecked*, *op_DivisionChecked*, with *Checked* at the end. However, it looks like there is already a pattern\nestablished to end the names with the operator word. For example, there is a *op_UnsignedRightShift* operator rather than\n*op_RightShiftUnsigned* operator.\n\n### `Checked operators` are inapplicable in an `unchecked` context\n\nThe compiler, when performing member lookup to find candidate user-defined operators within an `unchecked` context, could ignore `checked operators`. If metadata is encountered that only defines a `checked operator`, then a compilation error will occur.\n``` C#\npublic class MyClass\n{\n    public static void Add(Int128 lhs, Int128 rhs)\n    {\n        // Resolves to `op_CheckedMultiply`\n        Int128 r5 = checked(lhs * rhs);\n\n        // Error: Operator '*' cannot be applied to operands of type 'Int128' and 'Int128'\n        Int128 r5 = unchecked(lhs * rhs);\n    }\n}\n\npublic struct Int128\n{\n    public static Int128 operator checked *(Int128 lhs, Int128 rhs);\n}\n```\n\n### More complicated operator lookup and overload resolution rules in a `checked` context\n\nThe compiler, when performing member lookup to find candidate user-defined operators within a `checked` context will also consider applicable operators ending with `Checked`. That is, if the compiler was attempting to find applicable function members for the binary addition operator, it would look for both `op_Addition` and `op_AdditionChecked`. If the only applicable function member is a `checked operator`, it will be used. If both a `regular operator` and `checked operator` exist and are equally applicable the `checked operator` will be preferred. If both a `regular operator` and a `checked operator` exist but the `regular operator` is an exact match while the `checked operator` is not, the compiler will prefer the `regular operator`.\n``` C#\npublic class MyClass\n{\n    public static void Add(Int128 lhs, Int128 rhs)\n    {\n        // Resolves to `op_CheckedAddition`\n        Int128 r1 = checked(lhs + rhs);\n\n        // Resolves to `op_Addition`\n        Int128 r2 = unchecked(lhs + rhs);\n\n        // Resolve to `op_Subtraction`\n        Int128 r3 = checked(lhs - rhs);\n\n        // Resolve to `op_Subtraction`\n        Int128 r4 = unchecked(lhs - rhs);\n    }\n\n    public static void Multiply(Int128 lhs, byte rhs)\n    {\n        // Resolves to `op_Multiply` even though `op_CheckedMultiply` is also applicable\n        Int128 r4 = checked(lhs * rhs);\n    }\n}\n\npublic struct Int128\n{\n    public static Int128 operator checked +(Int128 lhs, Int128 rhs);\n    public static Int128 operator +(Int128 lhs, Int128 rhs);\n\n    public static Int128 operator -(Int128 lhs, Int128 rhs);\n\n    public static Int128 operator checked *(Int128 lhs, int rhs);\n    public static Int128 operator *(Int128 lhs, byte rhs);\n}\n```\n\n### Yet another way to build the set of candidate user-defined operators \n\n#### Unary operator overload resolution\n\nAssuming that `regular operator` matches `unchecked` evaluation context, `checked operator` matches `checked` evaluation context\nand an operator that doesn't have `checked` form (for example, `+`) matches either context, the first bullet in [§12.4.4 - Unary operator overload resolution](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1244-unary-overload-resolution):\n>*  The set of candidate user-defined operators provided by `X` for the operation `operator op(x)` is determined using the rules of [§12.4.6 - Candidate user-defined operators](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1246-candidate-user-defined-operators).\n\nwill be replaced with the following two bullet points:\n*  The set of candidate user-defined operators provided by `X` for the operation `operator op(x)` **matching the current checked/unchecked context** is determined using the rules of [Candidate user-defined operators](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1246-candidate-user-defined-operators).\n*  If the set of candidate user-defined operators is not empty, then this becomes the set of candidate operators for the operation. Otherwise, the set of candidate user-defined operators provided by `X` for the operation `operator op(x)` **matching the opposite checked/unchecked context** is determined using the rules of [§12.4.6 - Candidate user-defined operators](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1246-candidate-user-defined-operators).\n\n#### Binary operator overload resolution\n\nAssuming that `regular operator` matches `unchecked` evaluation context, `checked operator` matches `checked` evaluation context\nand an operator that doesn't have a `checked` form (for example, `%`) matches either context, the first bullet in [§12.4.5 - Binary operator overload resolution](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1245-binary-overload-resolution):\n>*  The set of candidate user-defined operators provided by `X` and `Y` for the operation `operator op(x,y)` is determined. The set consists of the union of the candidate operators provided by `X` and the candidate operators provided by `Y`, each determined using the rules of [§12.4.6 - Candidate user-defined operators](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1246-candidate-user-defined-operators). If `X` and `Y` are the same type, or if `X` and `Y` are derived from a common base type, then shared candidate operators only occur in the combined set once.\n\nwill be replaced with the following two bullet points:\n*  The set of candidate user-defined operators provided by `X` and `Y` for the operation `operator op(x,y)` **matching the current checked/unchecked context** is determined. The set consists of the union of the candidate operators provided by `X` and the candidate operators provided by `Y`, each determined using the rules of [§12.4.6 - Candidate user-defined operators](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1246-candidate-user-defined-operators). If `X` and `Y` are the same type, or if `X` and `Y` are derived from a common base type, then shared candidate operators only occur in the combined set once.\n*  If the set of candidate user-defined operators is not empty, then this becomes the set of candidate operators for the operation. Otherwise, the set of candidate user-defined operators provided by `X` and `Y` for the operation `operator op(x,y)` **matching the opposite checked/unchecked context** is determined. The set consists of the union of the candidate operators provided by `X` and the candidate operators provided by `Y`, each determined using the rules of [§12.4.6 - Candidate user-defined operators](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1246-candidate-user-defined-operators). If `X` and `Y` are the same type, or if `X` and `Y` are derived from a common base type, then shared candidate operators only occur in the combined set once.\n\n##### Example #1:\n``` C#\npublic class MyClass\n{\n    public static void Add(Int128 lhs, Int128 rhs)\n    {\n        // Resolves to `op_CheckedAddition`\n        Int128 r1 = checked(lhs + rhs);\n\n        // Resolves to `op_Addition`\n        Int128 r2 = unchecked(lhs + rhs);\n\n        // Resolve to `op_Subtraction`\n        Int128 r3 = checked(lhs - rhs);\n\n        // Resolve to `op_Subtraction`\n        Int128 r4 = unchecked(lhs - rhs);\n\n        // Resolves to `op_CheckedMultiply`\n        Int128 r5 = checked(lhs * rhs);\n\n        // Resolves to `op_CheckedMultiply`\n        Int128 r5 = unchecked(lhs * rhs);\n    }\n\n    public static void Divide(Int128 lhs, byte rhs)\n    {\n        // Resolves to `op_CheckedDivision`\n        Int128 r4 = checked(lhs / rhs);\n    }\n}\n\npublic struct Int128\n{\n    public static Int128 operator checked +(Int128 lhs, Int128 rhs);\n    public static Int128 operator +(Int128 lhs, Int128 rhs);\n\n    public static Int128 operator -(Int128 lhs, Int128 rhs);\n\n    public static Int128 operator checked *(Int128 lhs, Int128 rhs);\n\n    public static Int128 operator checked /(Int128 lhs, int rhs);\n    public static Int128 operator /(Int128 lhs, byte rhs);\n}\n```\n\n##### Example #2:\n``` C#\nclass C\n{\n    static void Add(C2 x, C3 y)\n    {\n        object o;\n        \n        // C1.op_CheckedAddition\n        o = checked(x + y);\n        \n        // C2.op_Addition\n        o = unchecked(x + y);\n    }\n}\n\nclass C1\n{\n    public static C1 operator checked + (C1 x, C3 y) => new C3();\n}\n\nclass C2 : C1\n{\n    public static C2 operator + (C2 x, C1 y) => new C2();\n}\n\nclass C3 : C1\n{\n}\n```\n\n##### Example #3:\n``` C#\nclass C\n{\n    static void Add(C2 x, C3 y)\n    {\n        object o;\n        \n        // C2.op_CheckedAddition\n        o = checked(x + y);\n        \n        // C1.op_Addition\n        o = unchecked(x + y);\n    }\n}\n\nclass C1\n{\n    public static C1 operator + (C1 x, C3 y) => new C3();\n}\n\nclass C2 : C1\n{\n    public static C2 operator checked + (C2 x, C1 y) => new C2();\n}\n\nclass C3 : C1\n{\n}\n```\n\n##### Example #4:\n``` C#\nclass C\n{\n    static void Add(C2 x, byte y)\n    {\n        object o;\n        \n        // C1.op_CheckedAddition\n        o = checked(x + y);\n        \n        // C2.op_Addition\n        o = unchecked(x + y);\n    }\n\n    static void Add2(C2 x, int y)\n    {\n        object o;\n        \n        // C2.op_Addition\n        o = checked(x + y);\n        \n        // C2.op_Addition\n        o = unchecked(x + y);\n    }\n}\n\nclass C1\n{\n    public static C1 operator checked + (C1 x, byte y) => new C1();\n}\n\nclass C2 : C1\n{\n    public static C2 operator + (C2 x, int y) => new C2();\n}\n```\n\n##### Example #5:\n``` C#\nclass C\n{\n    static void Add(C2 x, byte y)\n    {\n        object o;\n        \n        // C2.op_CheckedAddition\n        o = checked(x + y);\n        \n        // C1.op_Addition\n        o = unchecked(x + y);\n    }\n\n    static void Add2(C2 x, int y)\n    {\n        object o;\n        \n        // C1.op_Addition\n        o = checked(x + y);\n        \n        // C1.op_Addition\n        o = unchecked(x + y);\n    }\n}\n\nclass C1\n{\n    public static C1 operator + (C1 x, int y) => new C1();\n}\n\nclass C2 : C1\n{\n    public static C2 operator checked + (C2 x, byte y) => new C2();\n}\n```\n\n#### Processing of user-defined explicit conversions \n\nAssuming that `regular operator` matches `unchecked` evaluation context and `checked operator` matches `checked` evaluation context,\nthe third bullet in [§10.5.3 Evaluation of user-defined conversions](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#1053-evaluation-of-user-defined-conversions):\n>*  Find the set of applicable user-defined and lifted conversion operators, `U`. This set consists of the user-defined and lifted implicit or explicit conversion operators declared by the classes or structs in `D` that convert from a type encompassing or encompassed by `S` to a type encompassing or encompassed by `T`. If `U` is empty, the conversion is undefined and a compile-time error occurs.\n\nwill be replaced with the following bullet points:\n*  Find the set of applicable user-defined and lifted explicit conversion operators **matching the current checked/unchecked context**, `U0`. This set consists of the user-defined and lifted explicit conversion operators declared by the classes or structs in `D` that **match the current checked/unchecked context** and convert from a type encompassing or encompassed by `S` to a type encompassing or encompassed by `T`.\n*  Find the set of applicable user-defined and lifted explicit conversion operators **matching the opposite checked/unchecked context**, `U1`. If `U0` is not empty, `U1` is empty. Otherwise, this set consists of the user-defined and lifted explicit conversion operators declared by the classes or structs in `D` that **match the opposite checked/unchecked context** and convert from a type encompassing or encompassed by `S` to a type encompassing or encompassed by `T`.\n*  Find the set of applicable user-defined and lifted conversion operators, `U`. This set consists of operators from `U0`, `U1`, and the user-defined and lifted implicit conversion operators declared by the classes or structs in `D` that convert from a type encompassing or encompassed by `S` to a type encompassing or encompassed by `T`. If `U` is empty, the conversion is undefined and a compile-time error occurs.\n\n### Yet another another way to build the set of candidate user-defined operators \n\n#### Unary operator overload resolution\n\nThe first bullet in section [§12.4.4](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1244-unary-operator-overload-resolution) will be adjusted as follows (additions are in bold).\n*  The set of candidate user-defined operators provided by `X` for the operation `operator op(x)` is determined using the rules of \"Candidate user-defined operators\" section below. **If the set contains at least one operator in checked form, all operators in regular form are removed from the set.**\n\nThe section [§12.8.20](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12820-the-checked-and-unchecked-operators) will be adjusted to reflect the effect that the checked/unchecked context has on unary operator overload resolution.\n\n#### Binary operator overload resolution\n\nThe first bullet in section [§12.4.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1245-binary-operator-overload-resolution) will be adjusted as follows (additions are in bold).\n*  The set of candidate user-defined operators provided by `X` and `Y` for the operation `operator op(x,y)` is determined. The set consists of the union of the candidate operators provided by `X` and the candidate operators provided by `Y`, each determined using the rules of \"Candidate user-defined operators\" section below. If `X` and `Y` are the same type, or if `X` and `Y` are derived from a common base type, then shared candidate operators only occur in the combined set once. **If the set contains at least one operator in checked form, all operators in regular form are removed from the set.**\n\nThe Checked and unchecked operators [§12.8.20](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12820-the-checked-and-unchecked-operators) section will be adjusted to reflect the effect that the checked/unchecked context has on binary operator overload resolution.\n\n#### Candidate user-defined operators\n\nThe [§12.4.6 - Candidate user-defined operators](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1246-candidate-user-defined-operators) section will be adjusted as follows (additions are in bold).\n\nGiven a type `T` and an operation `operator op(A)`, where `op` is an overloadable operator and `A` is an argument list, the set of candidate user-defined operators provided by `T` for `operator op(A)` is determined as follows:\n\n*  Determine the type `T0`. If `T` is a nullable type, `T0` is its underlying type, otherwise `T0` is equal to `T`.\n*  For all `operator op` declarations **in their checked and regular forms in `checked` evaluation context and only in their regular form in `unchecked` evaluation context** in `T0` and all lifted forms of such operators, if at least one operator is applicable ([§12.6.4.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12642-applicable-function-member)) with respect to the argument list `A`, then the set of candidate operators consists of all such applicable operators in `T0`.\n*  Otherwise, if `T0` is `object`, the set of candidate operators is empty.\n*  Otherwise, the set of candidate operators provided by `T0` is the set of candidate operators provided by the direct base class of `T0`, or the effective base class of `T0` if `T0` is a type parameter.\n\nSimilar filtering will be applied while determining the set of candidate operators in interfaces https://github.com/dotnet/csharplang/blob/main/meetings/2017/LDM-2017-06-27.md#shadowing-within-interfaces.\n\nThe [§12.8.20](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12820-the-checked-and-unchecked-operators) section will be adjusted to reflect the effect that the checked/unchecked context has on unary and binary operator overload resolution.\n\n##### Example #1:\n``` C#\npublic class MyClass\n{\n    public static void Add(Int128 lhs, Int128 rhs)\n    {\n        // Resolves to `op_CheckedAddition`\n        Int128 r1 = checked(lhs + rhs);\n\n        // Resolves to `op_Addition`\n        Int128 r2 = unchecked(lhs + rhs);\n\n        // Resolve to `op_Subtraction`\n        Int128 r3 = checked(lhs - rhs);\n\n        // Resolve to `op_Subtraction`\n        Int128 r4 = unchecked(lhs - rhs);\n\n        // Resolves to `op_CheckedMultiply`\n        Int128 r5 = checked(lhs * rhs);\n\n        // Error: Operator '*' cannot be applied to operands of type 'Int128' and 'Int128'\n        Int128 r5 = unchecked(lhs * rhs);\n    }\n\n    public static void Divide(Int128 lhs, byte rhs)\n    {\n        // Resolves to `op_CheckedDivision`\n        Int128 r4 = checked(lhs / rhs);\n    }\n}\n\npublic struct Int128\n{\n    public static Int128 operator checked +(Int128 lhs, Int128 rhs);\n    public static Int128 operator +(Int128 lhs, Int128 rhs);\n\n    public static Int128 operator -(Int128 lhs, Int128 rhs);\n\n    public static Int128 operator checked *(Int128 lhs, Int128 rhs);\n\n    public static Int128 operator checked /(Int128 lhs, int rhs);\n    public static Int128 operator /(Int128 lhs, byte rhs);\n}\n```\n\n##### Example #2:\n``` C#\nclass C\n{\n    static void Add(C2 x, C3 y)\n    {\n        object o;\n        \n        // C1.op_CheckedAddition\n        o = checked(x + y);\n        \n        // C2.op_Addition\n        o = unchecked(x + y);\n    }\n}\n\nclass C1\n{\n    public static C1 operator checked + (C1 x, C3 y) => new C3();\n}\n\nclass C2 : C1\n{\n    public static C2 operator + (C2 x, C1 y) => new C2();\n}\n\nclass C3 : C1\n{\n}\n```\n\n##### Example #3:\n``` C#\nclass C\n{\n    static void Add(C2 x, C3 y)\n    {\n        object o;\n        \n        // C2.op_CheckedAddition\n        o = checked(x + y);\n        \n        // C1.op_Addition\n        o = unchecked(x + y);\n    }\n}\n\nclass C1\n{\n    public static C1 operator + (C1 x, C3 y) => new C3();\n}\n\nclass C2 : C1\n{\n    public static C2 operator checked + (C2 x, C1 y) => new C2();\n}\n\nclass C3 : C1\n{\n}\n```\n\n##### Example #4:\n``` C#\nclass C\n{\n    static void Add(C2 x, byte y)\n    {\n        object o;\n        \n        // C2.op_Addition\n        o = checked(x + y);\n        \n        // C2.op_Addition\n        o = unchecked(x + y);\n    }\n\n    static void Add2(C2 x, int y)\n    {\n        object o;\n        \n        // C2.op_Addition\n        o = checked(x + y);\n        \n        // C2.op_Addition\n        o = unchecked(x + y);\n    }\n}\n\nclass C1\n{\n    public static C1 operator checked + (C1 x, byte y) => new C1();\n}\n\nclass C2 : C1\n{\n    public static C2 operator + (C2 x, int y) => new C2();\n}\n```\n\n##### Example #5:\n``` C#\nclass C\n{\n    static void Add(C2 x, byte y)\n    {\n        object o;\n        \n        // C2.op_CheckedAddition\n        o = checked(x + y);\n        \n        // C1.op_Addition\n        o = unchecked(x + y);\n    }\n\n    static void Add2(C2 x, int y)\n    {\n        object o;\n        \n        // C1.op_Addition\n        o = checked(x + y);\n        \n        // C1.op_Addition\n        o = unchecked(x + y);\n    }\n}\n\nclass C1\n{\n    public static C1 operator + (C1 x, int y) => new C1();\n}\n\nclass C2 : C1\n{\n    public static C2 operator checked + (C2 x, byte y) => new C2();\n}\n```\n#### Processing of user-defined explicit conversions \n\nThe third bullet in [§10.5.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#1055-user-defined-explicit-conversions):\n>*  Find the set of applicable user-defined and lifted conversion operators, `U`. This set consists of the user-defined and lifted implicit or explicit conversion operators declared by the classes or structs in `D` that convert from a type encompassing or encompassed by `S` to a type encompassing or encompassed by `T`. If `U` is empty, the conversion is undefined and a compile-time error occurs.\n\nwill be replaced with the following bullet points:\n*  Find the set of applicable user-defined and lifted explicit conversion operators, `U0`. This set consists of the user-defined and lifted explicit conversion operators declared by the classes or structs in `D` **in their checked and regular forms in `checked` evaluation context and only in their regular form in `unchecked` evaluation context** and convert from a type encompassing or encompassed by `S` to a type encompassing or encompassed by `T`.\n*  If `U0` contains at least one operator in checked form, all operators in regular form are removed from the set.\n*  Find the set of applicable user-defined and lifted conversion operators, `U`. This set consists of operators from `U0`, and the user-defined and lifted implicit conversion operators declared by the classes or structs in `D` that convert from a type encompassing or encompassed by `S` to a type encompassing or encompassed by `T`. If `U` is empty, the conversion is undefined and a compile-time error occurs.\n\nThe Checked and unchecked operators [§12.8.20](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12820-the-checked-and-unchecked-operators) section will be adjusted to reflect the effect that the checked/unchecked context has on processing of user-defined explicit conversions.\n\n### Checked vs. unchecked context within a `checked operator`\n\nThe compiler could treat the default context of a `checked operator` as checked. The developer would need to explicitly use `unchecked` if part of their algorithm should not participate in the `checked context`. However, this might not work well in the future if we start allowing `checked`/`unchecked` tokens as modifiers on operators to set the context within the body. The modifier and the keyword could contradict each other. Also, we wouldn't be able to do the same (treat default context as unchecked) for a `regular operator` because that would be a breaking change.\n\n</details>\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\nShould the language allow `checked` and `unchecked` modifiers on methods (e.g. `static checked void M()`)?\nThis would allow removing nesting levels for methods that require it.\n\n### Checked division in Linq Expression Trees\n\nThere is no factory method to create a checked division node and there is no `ExpressionType.DivideChecked` member.\nWe could still use the following factory method to create regular divide node with `MethodInfo` pointing to the `op_CheckedDivision` method.\nConsumers will have to check the name to infer the context.\n``` C#\npublic static BinaryExpression Divide (Expression left, Expression right, MethodInfo? method);\n```\n\nNote, even though [§12.8.20](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12820-the-checked-and-unchecked-operators) section\nlists `/` operator as one of the operators affected by checked/unchecked evaluation context, IL doesn't have a special op code to perform checked division.\nCompiler always uses the factory method reardless of the context today.\n\n*Proposal:*\nChecked user-defined devision will not be supported in Linq Expression Trees.\n\n### (Resolved) Should we support implicit checked conversion operators?\n\nIn general, implicit conversion operators are not supposed to throw.\n\n*Proposal:*\nNo.\n\n*Resolution:*\nApproved - https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-07.md#checked-implicit-conversions\n\n## Design meetings\n\nhttps://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-07.md\nhttps://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md\nhttps://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-14.md\nhttps://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-23.md\n\n\n"
  },
  {
    "path": "proposals/csharp-11.0/extended-nameof-scope.md",
    "content": "# Extended `nameof` scope\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/373>\n\n## Summary\n\nAllow `nameof(parameter)` inside an attribute on a method or parameter.\nFor example:\n- `[MyAttribute(nameof(parameter))] void M(int parameter) { }`\n- `[MyAttribute(nameof(TParameter))] void M<TParameter>() { }`\n- `void M(int parameter, [MyAttribute(nameof(parameter))] int other) { }`\n\n## Motivation\n\nAttributes like `NotNullWhen` or `CallerExpression` need to refer to parameters, but those parameters are currently not in scope.\n\n## Detailed design\n\n[Methods](https://github.com/dotnet/csharplang/blob/master/spec/classes.md#methods)\n\nThe method's *type_parameters* are in scope throughout the *method_declaration*, and can be used to form types throughout that scope in *return_type*, *method_body*, and *type_parameter_constraints_clauses* but not in *attributes*, **except within a `nameof` expression in *attributes*.**\n\n[Method parameters](https://github.com/dotnet/csharplang/blob/master/spec/classes.md#method-parameters)\n\nA method declaration creates a separate declaration space for parameters, type parameters and local variables. Names are introduced into this declaration space by the type parameter list and the formal parameter list of the method and by local variable declarations in the block of the method.\n**Names are introduced into this declaration space by the type parameter list and the formal parameter list of the method in `nameof` expressions in attributes placed on the method or its parameters.**\n\n\\[...]   \nWithin the block of a method, formal parameters can be referenced by their identifiers in simple_name expressions (Simple names).\n**Within a `nameof` expression in attributes placed on the method or its parameters, formal parameters can be referenced by their identifiers in *simple_name* expressions.**\n\n[Anonymous function signatures](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12192-anonymous-function-signatures)\n\nThe scope of the parameters of the anonymous function is the anonymous_function_body (§7.7) **and `nameof` expressions in attributes placed on the anonymous function or its parameters**.\n\n[Delegate declarations](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/delegates.md#202-delegate-declarations)\n\n**The scope of the parameters of the delegate is `nameof` expressions in attributes placed on the declaration, its type parameters or its parameters**.\n\n[Simple names](https://github.com/dotnet/csharplang/blob/master/spec/expressions.md#simple-names)\n\nA *simple_name* is either of the form `I` or of the form `I<A1,...,Ak>`, where `I` is a single identifier and `<A1,...,Ak>` is an optional *type_argument_list*. When no *type_argument_list* is specified, consider `K` to be zero. The *simple_name* is evaluated and classified as follows:\n\n- If `K` is zero and the *simple_name* appears within a block and if the block's (or an enclosing block's) local variable declaration space (Declarations) contains a local variable, parameter or constant with name `I`, then the *simple_name* refers to that local variable, parameter or constant and is classified as a variable or value.\n- If `K` is zero and the *simple_name* appears within the body of a generic method declaration and if that declaration includes a type parameter with name `I`, then the *simple_name* refers to that type parameter.\n- **If `K` is zero and the *simple_name* appears within a `nameof` expression in an attribute on the method declaration or its parameters and if that declaration includes a parameter or type parameter with name `I`, then the *simple_name* refers to that parameter or type parameter.**\n- Otherwise, for each instance type `T` (The instance type), starting with the instance type of the immediately enclosing type declaration and continuing with the instance type of each enclosing class or struct declaration (if any):  \n\\[...]\n- Otherwise, for each namespace `N`, starting with the namespace in which the *simple_name* occurs, continuing with each enclosing namespace (if any), and ending with the global namespace, the following steps are evaluated until an entity is located:  \n\\[...]\n- Otherwise, the simple_name is undefined and a compile-time error occurs.\n\n[Scopes](https://github.com/dotnet/csharplang/blob/master/spec/basic-concepts.md#scopes)\n\n- The scope of a type parameter declared by a type_parameter_list on a method_declaration is \\[...] **and `nameof` expressions in an attribute on the method declaration or its parameters.**\n- The scope of a parameter declared in a method_declaration (Methods) is the *method_body* of that method_declaration **and `nameof` expressions in an attribute on the method declaration or its parameters.**\n\n## Related spec sections\n- [Declarations](https://github.com/dotnet/csharplang/blob/master/spec/basic-concepts.md#declarations)\n"
  },
  {
    "path": "proposals/csharp-11.0/file-local-types.md",
    "content": "# File-local types\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/5529>\n\n## Summary\n[summary]: #summary\n\nPermit a `file` modifier on top-level type declarations. The type only exists in the file where it is declared.\n\n```cs\n// File1.cs\nnamespace NS;\n\nfile class Widget\n{\n}\n\n// File2.cs\nnamespace NS;\n\nfile class Widget // different symbol than the Widget in File1\n{\n}\n\n// File3.cs\nusing NS;\n\nvar widget = new Widget(); // error: The type or namespace name 'Widget' could not be found.\n```\n\n## Motivation\n[motivation]: #motivation\n\nOur primary motivation is from source generators. Source generators work by adding files to the user's compilation.\n1. Those files should be able to contain implementation details which are hidden from the rest of the compilation, yet are usable throughout the file they are declared in.\n2. We want to reduce the need for generators to \"search\" for type names which won't collide with declarations in user code or code from other generators.\n\n## Detailed design\n[design]: #detailed-design\n\n- We add the `file` modifier to the following modifier sets:\n  - [class](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#1536-class-modifiers)\n  - [struct](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/structs.md#1622-struct-modifiers)\n  - [interface](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/interfaces.md#1822-interface-modifiers)\n  - [enum](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/enums.md#193-enum-modifiers)\n  - [delegate](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/delegates.md#202-delegate-declarations)\n  - record\n  - record struct.\n- The `file` modifier can only be used on a top-level type.\n\nWhen a type has the `file` modifier, it is said to be a *file-local* type.\n\n### Accessibility\nThe `file` modifier is not classified as an accessibility modifier. No accessibility modifiers can be used in combination with `file` on a type. `file` is treated as an independent concept from accessibility. Since file-local types can't be nested, only the default accessibility `internal` is usable with `file` types.\n\n```cs\npublic file class C1 { } // error\ninternal file class C2 { } // error\nfile class C3 { } // ok\n```\n\n### Naming\nThe implementation guarantees that file-local types in different files with the same name will be distinct to the runtime. The type's accessibility and name in metadata is implementation-defined. The intention is to permit the compiler to adopt any future access-limitation features in the runtime which are suited to the feature. It's expected that in the initial implementation, an `internal` accessibility would be used and an unspeakable generated name will be used which depends on the file the type is declared in.\n\n### Lookup\nWe amend the [member lookup](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#125-member-lookup) section as follows (new text in **bold**):\n\n> - Next, if `K` is zero, all nested types whose declarations include type parameters are removed. If `K` is not zero, all members with a different number of type parameters are removed. When `K` is zero, methods having type parameters are not removed, since the type inference process ([§11.6.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1263-type-inference)) might be able to infer the type arguments.\n> - **Next, let *F* be the compilation unit which contains the expression where member lookup is occurring. All members which are file-local types and are not declared in *F* are removed from the set.**\n> - **Next, if the set of accessible members contains file-local types, all members which are not file-local types are removed from the set.**\n\n#### Remarks\nThese rules disallow usage of file-local types outside the file in which they are declared.\n\nThese rules also permit a file-local type to *shadow* a namespace or a non-file-local type:\n```cs\n// File1.cs\nclass C\n{\n    public static void M() { }\n}\n```\n\n```cs\n// File2.cs\nfile class C\n{\n    public static void M() { }\n}\n\nclass Program\n{\n    static void Main()\n    {\n        C.M(); // refers to the 'C' in File2.cs\n    }\n}\n```\n\nNote that we don't update the [scopes](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/basic-concepts.md#77-scopes) section of the spec. This is because, as the spec states:\n\n> The ***scope*** of a name is the region of program text within which it is possible to refer to the entity declared by the name without qualification of the name.\n\nIn effect, scope only impacts the lookup of non-qualified names. This isn't quite the right concept for us to leverage because we need to also impact the lookup of qualified names:\n\n```cs\n// File1.cs\nnamespace NS1\n{\n    file class C\n    {\n        public static void M() { }\n    }\n}\n\nnamespace NS2\n{\n    class Program\n    {\n        public static void M()\n        {\n            C.M(); // error: C is not in scope\n            NS1.C.M(); // ok: C can be accessed through NS1.\n        }\n    }\n}\n```\n\n```cs\n// File2.cs\nnamespace NS1\n{\n    class Program\n    {\n        C.M(); // error\n        NS1.C.M(); // error\n    }\n}\n```\n\nTherefore, we don't specify the feature in terms of which scope the type is contained in, but rather as additional \"filtering rules\" in member lookup.\n\n### Attributes\nFile-local classes are permitted to be attribute types, and can be used as attributes within both file-local types and non-file-local types, just as if the attribute type were a non-file-local type. The metadata name of the file-local attribute type still goes through the same name generation strategy as other file-local types. This means detecting the presence of a file-local type by a hard-coded string name is likely to be impractical, because it requires depending on the internal name generation strategy of the compiler, which may change over time. However, detecting via `typeof(MyFileLocalAttribute)` works.\n\n```cs\nusing System;\nusing System.Linq;\n\nfile class MyFileLocalAttribute : Attribute { }\n\n[MyFileLocalAttribute]\npublic class C\n{\n    public static void Main()\n    {\n        var attribute = typeof(C).CustomAttributes.Where(attr => attr.AttributeType == typeof(MyFileLocalAttribute)).First();\n        Console.Write(attribute); // outputs the generated name of the file-local attribute type\n    }\n}\n```\n\n### Usage in signatures\nThere is a general need to prevent file-local types from appearing in member parameters, returns, and type parameter constraints where the file-local type might not be in scope at the point of usage of the member.\n\nNote that non-file-local types are permitted to implement file-local interfaces, similar to how types can implement less-accessible interfaces. Depending on the types present in the interface members, it could result in a violation of the rules in the following section.\n\n#### Only allow signature usage in members of file-local types\nPerhaps the simplest way to ensure this is to enforce that file-local types can only appear in signatures or as base types of other file-local types:\n\n```cs\nfile class FileBase\n{\n}\n\npublic class Derived : FileBase // error\n{\n    private FileBase M2() => new FileBase() // error\n}\n\nfile class FileDerived : FileBase // ok\n{\n    private FileBase M2() => new FileBase(); // ok\n}\n```\n\nNote that this does restrict usage in explicit implementations, even though such usages are safe. We do this in order to simplify the rules for the initial iteration of the feature.\n\n```cs\nfile interface I\n{\n    void M(I i);\n}\n\nclass C : I\n{\n    void I.M(I i) { } // error\n}\n```\n\n### `global using static`\nIt is a compile-time error to use a file-local type in a `global using static` directive, i.e.\n\n```cs\nglobal using static C; // error\n\nfile class C\n{\n    public static void M() { }\n}\n```\n\n### Implementation/overrides\nfile-local type declarations can implement interfaces, override virtual methods, etc. just like regular type declarations.\n\n```cs\nfile struct Widget : IEquatable<Widget>\n{\n    public bool Equals(Widget other) => true;\n}\n```\n"
  },
  {
    "path": "proposals/csharp-11.0/generic-attributes.md",
    "content": "# Generic Attributes\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/124>\n\n## Summary\n[summary]: #summary\n\nWhen generics were introduced in C# 2.0, attribute classes were not allowed to participate. We can make the language more composable by removing (rather, loosening) this restriction. The .NET Core runtime has added support for generic attributes. Now, all that's missing is support for generic attributes in the compiler.\n\n## Motivation\n[motivation]: #motivation\n\nCurrently attribute authors can take a `System.Type` as a parameter and have users pass a `typeof` expression to provide the attribute with types that it needs. However, outside of analyzers, there's no way for an attribute author to constrain what types are allowed to be passed to an attribute via `typeof`. If attributes could be generic, then attribute authors could use the existing system of type parameter constraints to express the requirements for the types they take as input.\n\n## Detailed design\n[design]: #detailed-design\n\nThe following section is amended: [§15.2.4.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#15242-base-classes)\n> The direct base class of a class type must not be any of the following types: System.Array, System.Delegate, System.MulticastDelegate, System.Enum, or System.ValueType. ~~Furthermore, a generic class declaration cannot use System.Attribute as a direct or indirect base class.~~\n\nOne important note is that the following section of the spec is *unaffected* when referencing the point of usage of an attribute, i.e. within an attribute list: Type parameters - [§8.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/types.md#85-type-parameters).\n\n> A type parameter cannot be used anywhere within an attribute.\n\nThis means that when a generic attribute is used, its construction needs to be fully \"closed\", i.e. not containing any type parameters, which means the following is still disallowed:\n\n```cs\nusing System;\nusing System.Collections.Generic;\n\npublic class Attr<T1> : Attribute { }\n\npublic class Program<T2>\n{\n    [Attr<T2>] // error\n    [Attr<List<T2>>] // error\n    void M() { }\n}\n```\n\nWhen a generic attribute is used in an attribute list, its type arguments have the same restrictions that `typeof` has on its argument. For example, `[Attr<dynamic>]` is an error. This is because \"attribute-dependent\" types like `dynamic`, `List<string?>`, `nint`, and so on can't be fully represented in the final IL for an attribute type argument, because there isn't a symbol to \"attach\" the `DynamicAttribute` or other well-known attribute to.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nRemoving the restriction, reasoning out the implications, and adding the appropriate tests is work.\n\n## Alternatives\n[alternatives]: #alternatives\n\nAttribute authors who want users to be able to discover the requirements for the types they provide to attributes need to write analyzers and guide their users to use those analyzers in their builds.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n- [x] What does `AllowMultiple = false` mean on a generic attribute? If we have `[Attr<string>]` and `[Attr<object>]` both used on a symbol, does that mean \"multiple\" of the attribute are in use?\n    - For now we are inclined to take the more restrictive route here and consider the attribute class's original definition when deciding whether multiple of it have been applied. In other words, `[Attr<string>]` and `[Attr<object>]` applied together is incompatible with `AllowMultiple = false`.\n\n## Design meetings\n\n- https://github.com/dotnet/csharplang/blob/main/meetings/2017/LDM-2017-02-21.md#generic-attributes\n    - At the time there was a concern that we would have to gate the feature on whether the target runtime supports it. (However, we now only support C# 10 on .NET 6. It would be nice for the implementation to be aware of what minimum target framework supports the feature, but seems less essential today.)\n"
  },
  {
    "path": "proposals/csharp-11.0/list-patterns.md",
    "content": "# List patterns\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/3435>\n\n## Summary\n\nLets you to match an array or a list with a sequence of patterns e.g. `array is [1, 2, 3]` will match an integer array of the length three with 1, 2, 3 as its elements, respectively.\n\n## Detailed design\n\nThe pattern syntax is modified as follow:\n\n```antlr\nlist_pattern_clause\n  : '[' (pattern (',' pattern)* ','?)? ']'\n  ;\n\nlist_pattern\n  : list_pattern_clause simple_designation?\n  ;\n\nslice_pattern\n  : '..' pattern?\n  ;\n\nprimary_pattern\n  : list_pattern\n  | slice_pattern\n  | // all of the pattern forms previously defined\n  ;\n```\nThere are two new patterns:\n\n- The *list_pattern* is used to match elements.\n- A *slice_pattern* is only permitted once and only directly in a *list_pattern_clause* and discards _**zero or more**_ elements.\n\n#### Pattern compatibility\n\nA *list_pattern* is compatible with any type that is *countable* as well as *indexable* — it has an accessible indexer that takes an `Index` as an argument or otherwise an accessible indexer with a single `int` parameter. If both indexers are present, the former is preferred.  \n\nA *slice_pattern* with a subpattern is compatible with any type that is *countable* as well as *sliceable* — it has an accessible indexer that takes a `Range` as an argument or otherwise an accessible `Slice` method with two `int` parameters. If both are present, the former is preferred.\n\nA *slice_pattern* without a subpattern is compatible with any type that is compatible with a *list_pattern*.\n\nThis set of rules is derived from the [***range indexer pattern***](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-8.0/ranges.md#implicit-index-support).\n\n#### Subsumption checking\n\nSubsumption checking works just like [positional patterns with `ITuple`](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-8.0/patterns.md#positional-pattern) - corresponding subpatterns are matched by position plus an additional node for testing length.\n\nFor example, the following code produces an error because both patterns yield the same DAG:\n\n```cs\ncase [_, .., 1]: // expr.Length is >= 2 && expr[^1] is 1\ncase [.., _, 1]: // expr.Length is >= 2 && expr[^1] is 1\n```\nUnlike:\n```cs\ncase [_, 1, ..]: // expr.Length is >= 2 && expr[1] is 1\ncase [.., 1, _]: // expr.Length is >= 2 && expr[^2] is 1\n```\n\nThe order in which subpatterns are matched at runtime is unspecified, and a failed match may not attempt to match all subpatterns.\n\nGiven a specific length, it's possible that two subpatterns refer to the same element, in which case a test for this value is inserted into the decision DAG.\n\n- For instance, `[_, >0, ..] or [.., <=0, _]` becomes `length >= 2 && ([1] > 0 || length == 3 || [^2] <= 0)` where the length value of 3 implies the other test.\n- Conversely, `[_, >0, ..] and [.., <=0, _]` becomes `length >= 2 && [1] > 0 && length != 3 && [^2] <= 0` where the length value of 3 disallows the other test.\n\nAs a result, an error is produced for something like `case [.., p]: case [p]:` because at runtime, we're matching the same element in the second case.\n\nIf a slice subpattern matches a list or a length value, subpatterns are treated as if they were a direct subpattern of the containing list. For instance, `[..[1, 2, 3]]` subsumes a pattern of the form `[1, 2, 3]`.\n\nThe following assumptions are made on the members being used:\n\n- The property that makes the type *countable* is assumed to always return a non-negative value, if and only if the type is *indexable*. For instance, the pattern `{ Length: -1 }` can never match an array.\n- The member that makes the type *sliceable* is assumed to be well-behaved, that is, the return value is never null and that it is a proper subslice of the containing list. \n\nThe behavior of a pattern-matching operation is undefined if any of the above assumptions doesn't hold.\n\n#### Lowering\n\nA pattern of the form `expr is [1, 2, 3]` is equivalent to the following code:\n```cs\nexpr.Length is 3\n&& expr[new Index(0, fromEnd: false)] is 1\n&& expr[new Index(1, fromEnd: false)] is 2\n&& expr[new Index(2, fromEnd: false)] is 3\n```\nA *slice_pattern* acts like a proper discard i.e. no tests will be emitted for such pattern, rather it only affects other nodes, namely the length and indexer. For instance, a pattern of the form `expr is [1, .. var s, 3]`  is equivalent to the following code (if compatible via explicit `Index` and `Range` support):\n```cs\nexpr.Length is >= 2\n&& expr[new Index(0, fromEnd: false)] is 1\n&& expr[new Range(new Index(1, fromEnd: false), new Index(1, fromEnd: true))] is var s\n&& expr[new Index(1, fromEnd: true)] is 3\n```\nThe *input type* for the *slice_pattern* is the return type of the underlying `this[Range]` or `Slice` method with two exceptions: For `string` and arrays, `string.Substring` and `RuntimeHelpers.GetSubArray` will be used, respectively.\n\n## Unresolved questions\n\n1. Should we support multi-dimensional arrays? (answer [LDM 2021-05-26]: Not supported. If we want to make a general MD-array focused release, we would want to revisit all the areas they're currently lacking, not just list patterns.)\n2. Should we accept a general *pattern* following `..` in a *slice_pattern*? (answer [LDM 2021-05-26]: Yes, any pattern is allowed after a slice.)\n3. By this definition, the pattern `[..]` tests for `expr.Length >= 0`. Should we omit such test, assuming `Length` is always non-negative? (answer [LDM 2021-05-26]: `[..]` will not emit a Length check)\n"
  },
  {
    "path": "proposals/csharp-11.0/low-level-struct-improvements.md",
    "content": "# Low Level Struct Improvements\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issues: <https://github.com/dotnet/csharplang/issues/1147>, <https://github.com/dotnet/csharplang/issues/6476>\n\n## Summary\nThis proposal is an aggregation of several different proposals for `struct` performance improvements: `ref` fields and the ability to override lifetime defaults. The goal being a design which takes into account the various proposals to create a single overarching feature set for low level `struct` improvements.\n\n> Note: Previous versions of this spec used the terms \"ref-safe-to-escape\" and \"safe-to-escape\", which were introduced in the [Span safety](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-7.2/span-safety.md) feature specification. The [ECMA standard committee](https://www.ecma-international.org/task-groups/tc49-tg2/) changed the names to [\"ref-safe-context\"](https://learn.microsoft.com/dotnet/csharp/language-reference/language-specification/variables#972-ref-safe-contexts) and [\"safe-context\"](https://learn.microsoft.com/dotnet/csharp/language-reference/language-specification/structs#16412-safe-context-constraint), respectively. The values of the safe context have been refined to use \"declaration-block\", \"function-member\", and \"caller-context\" consistently. The speclets had used different phrasing for these terms, and also used \"safe-to-return\" as a synonym for \"caller-context\". This speclet has been updated to use the terms in the C# 7.3 standard.\n\nNot all the features outlined in this document have been implemented in C# 11. C# 11 includes:\n\n1. `ref` fields and `scoped`\n1. `[UnscopedRef]`\n\nThese features remain open proposals for a future version of C#:\n\n1. `ref` fields to `ref struct`\n1. Sunset restricted types\n\n## Motivation\nEarlier versions of C# added a number of low level performance features to the language: `ref` returns, `ref struct`, function pointers, etc. ... These enabled .NET developers to write highly performant code while continuing to leverage the C# language rules for type and memory safety.  It also allowed the creation of fundamental performance types in the .NET libraries like `Span<T>`.\n\nAs these features have gained traction in the .NET ecosystem developers, both internal and external, have been providing us with information on remaining friction points in the ecosystem. Places where they still need to drop to `unsafe` code to get their work done, or require the runtime to special case types like `Span<T>`. \n\nToday `Span<T>` is accomplished by using the `internal` type `ByReference<T>` which the runtime effectively treats as a `ref` field. This provides the benefit of `ref` fields but with the downside that the language provides no safety verification for it, as it does for other uses of `ref`. Further only dotnet/runtime can use this type as it's `internal`, so 3rd parties can not design their own primitives based on `ref` fields. Part of the [motivation for this work](https://github.com/dotnet/runtime/issues/32060) is to remove `ByReference<T>` and use proper `ref` fields in all code bases. \n\nThis proposal plans to address these issues by building on top of our existing low level features. Specifically it aims to:\n\n- Allow `ref struct` types to declare `ref` fields.\n- Allow the runtime to fully define `Span<T>` using the C# type system and remove special case type like `ByReference<T>`\n- Allow `struct` types to return `ref` to their fields.\n- Allow runtime to remove `unsafe` uses caused by limitations of lifetime defaults\n- Allow the declaration of safe `fixed` buffers for managed and unmanaged types in `struct`\n\n## Detailed Design \nThe rules for `ref struct` safety are defined in the [span safety document](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/span-safety.md) using the previous terms. Those rules have been incorporated into the C# 7 standard in [§9.7.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/variables.md#972-ref-safe-contexts) and [§16.4.12](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/structs.md#16412-safe-context-constraint). This document will describe the required changes to this document as a result of this proposal. Once accepted as an approved feature these changes will be incorporated into that document.\n\nOnce this design is complete our `Span<T>` definition will be as follows:\n\n<a name=\"new-span\"></a>\n\n```c#\nreadonly ref struct Span<T>\n{\n    readonly ref T _field;\n    readonly int _length;\n\n    // This constructor does not exist today but will be added as a part \n    // of changing Span<T> to have ref fields. It is a convenient, and\n    // safe, way to create a length one span over a stack value that today \n    // requires unsafe code.\n    public Span(ref T value)\n    {\n        _field = ref value;\n        _length = 1;\n    }\n}\n```\n\n### Provide ref fields and scoped\nThe language will allow developers to declare `ref` fields inside of a `ref struct`. This can be useful for example when encapsulating large mutable `struct` instances or defining high performance types like `Span<T>` in libraries besides the runtime.\n\n``` C#\nref struct S \n{\n    public ref int Value;\n}\n```\n\nA `ref` field will be emitted into metadata using the `ELEMENT_TYPE_BYREF` signature. This is no different than how we emit `ref` locals or `ref` arguments. For example `ref int _field` will be emitted as `ELEMENT_TYPE_BYREF ELEMENT_TYPE_I4`. This will require us to update ECMA335 to allow this entry but this should be rather straight forward.\n\nDevelopers can continue to initialize a `ref struct` with a `ref` field using the `default` expression in which case all declared `ref` fields will have the value `null`. Any attempt to use such fields will result in a `NullReferenceException` being thrown.\n\n```c#\nref struct S \n{\n    public ref int Value;\n}\n\nS local = default;\nlocal.Value.ToString(); // throws NullReferenceException\n```\n\nWhile the C# language pretends that a `ref` cannot be `null` this is legal at the runtime level and has well defined semantics. Developers who introduce `ref` fields into their types need to be aware of this possibility and should be **strongly** discouraged from leaking this detail into consuming code. Instead `ref` fields should be validated as non-null using the [runtime helpers](https://github.com/dotnet/runtime/pull/40008) and throwing when an uninitialized `struct` is used incorrectly.\n\n```c#\nref struct S1 \n{\n    private ref int Value;\n\n    public int GetValue()\n    {\n        if (System.Runtime.CompilerServices.Unsafe.IsNullRef(ref Value))\n        {\n            throw new InvalidOperationException(...);\n        }\n\n        return Value;\n    }\n}\n```\n\nA `ref` field can be combined with `readonly` modifiers in the following ways:\n\n- `readonly ref`: this is a field that cannot be ref reassigned outside a constructor or `init` methods. It can be value assigned though outside those contexts\n- `ref readonly`: this is a field that can be ref reassigned but cannot be value assigned at any point. This how an `in` parameter could be ref reassigned to a `ref` field.\n- `readonly ref readonly`: a combination of `ref readonly` and `readonly ref`. \n\n```c#\nref struct ReadOnlyExample\n{\n    ref readonly int Field1;\n    readonly ref int Field2;\n    readonly ref readonly int Field3;\n\n    void Uses(int[] array)\n    {\n        Field1 = ref array[0];  // Okay\n        Field1 = array[0];      // Error: can't assign ref readonly value (value is readonly)\n        Field2 = ref array[0];  // Error: can't repoint readonly ref\n        Field2 = array[0];      // Okay\n        Field3 = ref array[0];  // Error: can't repoint readonly ref\n        Field3 = array[0];      // Error: can't assign ref readonly value (value is readonly)\n    }\n}\n```\n\nA `readonly ref struct` will require that `ref` fields are declared `readonly ref`. There is no requirement that they are declared `readonly ref readonly`. This does allow a `readonly struct` to have indirect mutations via such a field but that is no different than a `readonly` field that pointed to a reference type today ([more details](#reason-readonly-shallow))\n\nA `readonly ref` will be emitted to metadata using the `initonly` flag, same as any other field. A `ref readonly` field will be attributed with `System.Runtime.CompilerServices.IsReadOnlyAttribute`. A `readonly ref readonly` will be emitted with both items.\n\nThis feature requires runtime support and changes to the ECMA spec. As such these will only be enabled when the corresponding feature flag is set in corelib. The issue tracking the exact API is tracked here https://github.com/dotnet/runtime/issues/64165\n\nThe set of changes to our safe context rules necessary to allow `ref` fields is small and targeted. The rules already account for `ref` fields existing and being consumed from APIs. The changes need to focus on only two aspects: how they are created and how they are ref reassigned. \n\nFirst the rules establishing *ref-safe-context* values for fields need to be updated for `ref` fields as follows:\n\n<a name=\"rules-field-lifetimes\"></a>\n\n> An expression in the form `ref e.F` *ref-safe-context* as follows:\n> 1. If `F` is a `ref` field its *ref-safe-context* is the *safe-context* of `e`.\n> 2. Else if `e` is of a reference type, it has *ref-safe-context* of *caller-context*\n> 3. Else its *ref-safe-context* is taken from the *ref-safe-context* of `e`.\n\nThis does not represent a rule change though as the rules have always accounted for `ref` state to exist inside a `ref struct`. This is in fact how the `ref` state in `Span<T>` has always worked and the consumption rules correctly account for this. The change here is just accounting for developers to be able to access `ref` fields directly and ensure they do so by the existing rules implicitly applied to `Span<T>`. \n\nThis does mean though that `ref` fields can be returned as `ref` from a `ref struct` but normal fields cannot.\n\n```c#\nref struct RS\n{\n    ref int _refField;\n    int _field;\n\n    // Okay: this falls into bullet one above. \n    public ref int Prop1 => ref _refField;\n\n    // Error: This is bullet four above and the ref-safe-context of `this`\n    // in a `struct` is function-member.\n    public ref int Prop2 => ref _field;\n}\n```\n\nThis may seem like an error at first glance but this is a deliberate design point. Again though, this is not a new rule being created by this proposal, it is instead acknowledging the existing rules `Span<T>` behaved by now that developers can declare their own `ref` state.\n\nNext the rules for ref reassignment need to be adjusted for the presence of `ref` fields. The primary scenario for ref reassignment is `ref struct` constructors storing `ref` parameters into `ref` fields. The support will be more general but this is the core scenario. To support this the rules for ref reassignment will be adjusted to account for `ref` fields as follows:\n\n#### Ref reassignment rules\n<a name=\"rules-ref-reassignment\"></a>\n\nThe left operand of the `= ref` operator must be an expression that binds to a ref local variable, a ref parameter (other than `this`), an out parameter, **or a ref field**.\n\n> For a ref reassignment in the form `e1 = ref e2` both of the following must be true:\n> 1. `e2` must have *ref-safe-context* at least as large as the *ref-safe-context* of `e1`\n> 2. `e1` must have the same *safe-context* as `e2` [Note](#examples-ref-reassignment-safety)\n\nThat means the desired `Span<T>` constructor works without any extra annotation:\n\n```c#\nreadonly ref struct Span<T>\n{\n    readonly ref T _field;\n    readonly int _length;\n\n    public Span(ref T value)\n    {\n        // Falls into the `x.e1 = ref e2` case, where `x` is the implicit `this`. The \n        // safe-context of `this` is *return-only* and ref-safe-context of `value` is \n        // *caller-context* hence this is legal.\n        _field = ref value;\n        _length = 1;\n    }\n}\n```\n\nThe change to ref reassignment rules means `ref` parameters can now escape from a method as a `ref` field in a `ref struct` value. As discussed in the [compat considerations section](#new-span-challenges) this can change the rules for existing APIs that never intended for `ref` parameters to escape as a `ref` field. The lifetime rules for parameters are based solely on their declaration not on their usage. All `ref` and `in` parameters have *ref-safe-context* of *caller-context* and hence can now be returned by `ref` or a `ref` field. In order to support APIs having `ref` parameters that can be escaping or non-escaping, and thus restore C# 10 call site semantics, the language will introduce limited lifetime annotations.\n\n#### `scoped` modifier\n<a name=\"rules-scoped\"></a>\n\nThe keyword `scoped` will be used to restrict the lifetime of a value. It can be applied to a `ref` or a value that is a `ref struct` and has the impact of restricting the *ref-safe-context* or *safe-context* lifetime, respectively, to the *function-member*. For example: \n\n| Parameter or Local | ref-safe-context | safe-context |\n|---|---|---|\n| `Span<int> s` | *function-member* | *caller-context* | \n| `scoped Span<int> s` | *function-member* | *function-member* | \n| `ref Span<int> s` | *caller-context* | *caller-context* | \n| `scoped ref Span<int> s` | *function-member* | *caller-context* | \n\nIn this relationship the *ref-safe-context* of a value can never be wider the *safe-context*.  \n\nThis allows for APIs in C# 11 to be annotated such that they have the same rules as C# 10:\n\n```c#\nSpan<int> CreateSpan(scoped ref int parameter)\n{\n    // Just as with C# 10, the implementation of this method isn't relevant to callers.\n}\n\nSpan<int> BadUseExamples(int parameter)\n{\n    // Legal in C# 10 and legal in C# 11 due to scoped ref\n    return CreateSpan(ref parameter);\n\n    // Legal in C# 10 and legal in C# 11 due to scoped ref\n    int local = 42;\n    return CreateSpan(ref local);\n\n    // Legal in C# 10 and legal in C# 11 due to scoped ref\n    Span<int> span = stackalloc int[42];\n    return CreateSpan(ref span[0]);\n}\n```\n\nThe `scoped` annotation also means that the `this` parameter of a `struct` can now be defined as `scoped ref T`. Previously it had to be special cased in the rules as `ref` parameter that had different *ref-safe-context* rules than other `ref` parameters (see all the references to including or excluding the receiver in the safe context rules). Now it can be expressed as a general concept throughout the rules which further simplifies them.\n\nThe `scoped` annotation can also be applied to the following locations:\n\n- locals: This annotation sets the lifetime as *safe-context*, or *ref-safe-context* in case of a `ref` local, to of *function-member* irrespective of the initializer lifetime. \n\n```c#\nSpan<int> ScopedLocalExamples()\n{\n    // Error: `span` has a safe-context of *function-member*. That is true even though the \n    // initializer has a safe-context of *caller-context*. The annotation overrides the \n    // initializer\n    scoped Span<int> span = default;\n    return span;\n\n    // Okay: the initializer has safe-context of *caller-context* hence so does `span2` \n    // and the return is legal.\n    Span<int> span2 = default;\n    return span2;\n\n    // The declarations of `span3` and `span4` are functionally identical because the \n    // initializer has a safe-context of *function-member* meaning the `scoped` annotation\n    // is effectively implied on `span3`\n    Span<int> span3 = stackalloc int[42];\n    scoped Span<int> span4 = stackalloc int[42];\n}\n```\n\nOther uses for `scoped` on locals are discussed [below](#examples-scoped-locals).\n\nThe `scoped` annotation cannot be applied to any other location including returns, fields, array elements, etc ... Further while `scoped` has impact when applied to any `ref`, `in` or `out` it only has impact when applied to values which are `ref struct`. Having declarations like `scoped int` has no impact because a non `ref struct` is always safe to return. The compiler will create a diagnostic for such cases to avoid developer confusion.\n\n#### Change the behavior of `out` parameters\n<a name=\"out-compat-change\"></a>\n\nTo further limit the impact of the compat change of making `ref` and `in` parameters returnable as `ref` fields, the language will change the default *ref-safe-context* value for `out` parameters to be *function-member*. Effectively `out` parameters are implicitly `scoped out` going forward. From a compat perspective this means they cannot be returned by `ref`:\n\n```c#\nref int Sneaky(out int i) \n{\n    i = 42;\n\n    // Error: ref-safe-context of out is now function-member\n    return ref i;\n}\n```\n\nThis will increase the flexibility of APIs that return `ref struct` values and have `out` parameters because it does not have to consider the parameter being captured by reference anymore. This is important because it's a common pattern in reader style APIs:\n\n```c#\nSpan<byte> Read(Span<byte> buffer, out int read)\n{\n    // .. \n}\n\nSpan<byte> Use()\n{\n    var buffer = new byte[256];\n\n    // If we keep current `out` ref-safe-context this is an error. The language must consider\n    // the `read` parameter as returnable as a `ref` field\n    //\n    // If we change `out` ref-safe-context this is legal. The language does not consider the \n    // `read` parameter to be returnable hence this is safe\n    int read;\n    return Read(buffer, out read);\n}\n```\n\nThe language will also no longer consider arguments passed to an `out` parameter to be returnable. Treating the input to an `out` parameter as returnable was extremely confusing to developers. It essentially subverts the intent of `out` by forcing developers to consider the value passed by the caller which is never used except in languages that don't respect `out`. Going forward languages that support `ref struct` must ensure the original value passed to an `out` parameter is never read. \n\nC# achieves this via it's definite assignment rules. That both achieves our ref safe context rules as well as allowing for existing code which assigns and then returns `out` parameters values.\n\n```c#\nSpan<int> StrangeButLegal(out Span<int> span)\n{\n    span = default;\n    return span;\n}\n```\n\nTogether these changes mean the argument to an `out` parameter does not contribute *safe-context* or *ref-safe-context* values to method invocations. This significantly reduces the overall compat impact of `ref` fields as well as simplifies how developers think about `out`. An argument to an `out` parameter does not contribute to the return, it is simply an output. \n\n#### Infer *safe-context* of declaration expressions\n<a id=\"infer-safe-to-escape-of-declaration-expressions\"></a>\nThe *safe-context* of a declaration variable from an `out` argument (`M(x, out var y)`) or deconstruction (`(var x, var y) = M()`) is the *narrowest* of the following:\n* caller-context\n* if out variable is marked `scoped`, then *declaration-block* (i.e. function-member or narrower).\n* if out variable's type is `ref struct`, consider all arguments to the containing invocation, including the receiver:\n  * *safe-context* of any argument where its corresponding parameter is not `out` and has *safe-context* of *return-only* or wider\n  * *ref-safe-context* of any argument where its corresponding parameter has *ref-safe-context* of *return-only* or wider\n    \nSee also [Examples of inferred *safe-context* of declaration expressions](#examples-of-inferred-safe-context-of-declaration-expressions).\n\n#### Implicitly `scoped` parameters\n<a name=\"implicitly-scoped\"></a>\nOverall there are two `ref` location which are implicitly declared as `scoped`:\n- `this` on a `struct` instance method\n- `out` parameters \n\nThe ref safe context rules will be written in terms of `scoped ref` and `ref`. For ref safe context purposes an `in` parameter is equivalent to `ref` and `out` is equivalent to `scoped ref`. Both `in` and `out` will only be specifically called out when it is important to the semantic of the rule. Otherwise they are just considered `ref` and `scoped ref` respectively.\n\nWhen discussing the *ref-safe-context* of arguments that correspond to `in` parameters they will be generalized as `ref` arguments in the spec. In the case the argument is an lvalue then the *ref-safe-context* is that of the lvalue, otherwise it is *function-member*. Again `in` will only be called out here when it is important to the semantic of the current rule.\n\n#### Return-only safe context\n<a name=\"return-only\"></a>\nThe design also requires that the introduction of a new safe-context: *return-only*. This is similar to *caller-context* in that it can be returned but it can **only** be returned through a `return` statement. \n\nThe details of *return-only* is that it's a context which is greater than *function-member* but smaller than *caller-context*. An expression provided to a `return` statement must be at least *return-only*. As such most existing rules fall out. For example assignment into a `ref` parameter from an expression with a *safe-context* of *return-only* will fail because it's smaller than the `ref` parameter's *safe-context* which is *caller-context*. The need for this new escape context will be discussed [below](#rules-unscoped). \n\nThere are three locations which default to *return-only*:\n- A `ref` or `in` parameter will have a *ref-safe-context* of *return-only*. This is done in part for `ref struct` to prevent [silly cyclic assignment](#cyclic-assignment) issues. It is done uniformly though to simplify the model as well as minimize compat changes.\n- A `out` parameter for a `ref struct` will have *safe-context* of *return-only*. This allows for return and `out` to be equally expressive. This does not have the silly cyclic assignment problem because `out` is implicitly `scoped` so the *ref-safe-context* is still smaller than the *safe-context*.\n- A `this` parameter for a `struct` constructor will have a *safe-context* of *return-only*. This falls out due to being modeled as `out` parameters. \n\nAny expression or statement which explicitly returns a value from a method or lambda must have a *safe-context*, and if applicable a *ref-safe-context*, of at least *return-only*. That includes `return` statements, expression bodied members and lambda expressions.\n\nLikewise any assignment to an `out` must have a *safe-context* of at least *return-only*. This is not a special case though, this just follows from the existing assignment rules.\n\nNote: An expression whose type is not a `ref struct` type always has a *safe-context* of *caller-context*. \n\n#### Rules for method invocation\n<a name=\"rules-method-invocation\"></a>\n\nThe ref safe context rules for method invocation will be updated in several ways. The first is by recognizing the impact that `scoped` has on arguments. For a given argument `expr` that is passed to parameter `p`:\n\n> 1. If `p` is `scoped ref` then `expr` does not contribute *ref-safe-context* when considering arguments.\n> 2. If `p` is `scoped` then `expr` does not contribute *safe-context* when considering arguments. \n> 3. If `p` is `out` then `expr` does not contribute *ref-safe-context* or *safe-context* [more details](#out-compat-change)\n\nThe language \"does not contribute\" means the arguments are simply not considered when calculating the *ref-safe-context* or *safe-context* value of the method return respectively. That is because the values can't contribute to that lifetime as the `scoped` annotation prevents it.\n\nThe method invocation rules can now be simplified. The receiver no longer needs to be special cased, in the case of `struct` it is now simply a `scoped ref T`. The value rules need to change to account for `ref` field returns:\n\n> A value resulting from a method invocation `e1.M(e2, ...)`, where `M()` does not return ref-to-ref-struct, has a *safe-context* taken from the narrowest of the following:\n> 1. The *caller-context*\n> 2. When the return is a `ref struct` the *safe-context* contributed by all argument expressions\n> 3. When the return is a `ref struct` the *ref-safe-context* contributed by all `ref` arguments\n>\n> If `M()` does return ref-to-ref-struct, the *safe-context* is the same as the *safe-context* of all arguments which are ref-to-ref-struct. It is an error if there are multiple arguments with different *safe-context* because of [method arguments must match](#rules-method-arguments-must-match).\n\nThe `ref` calling rules can be simplified to:\n\n> A value resulting from a method invocation `ref e1.M(e2, ...)`, where `M()` does not return ref-to-ref-struct, is *ref-safe-context* the narrowest of the following contexts:\n> 1. The *caller-context*\n> 2. The *safe-context* contributed by all argument expressions\n> 3. The *ref-safe-context* contributed by all `ref` arguments\n>\n> If `M()` does return ref-to-ref-struct, the *ref-safe-context* is the narrowest *ref-safe-context* contributed by all arguments which are ref-to-ref-struct.\n\nThis rule now lets us define the two variants of desired methods:\n\n```c#\nSpan<int> CreateWithoutCapture(scoped ref int value)\n{\n    // Error: value Rule 3 specifies that the safe-context be limited to the ref-safe-context\n    // of the ref argument. That is the *function-member* for value hence this is not allowed.\n    return new Span<int>(ref value);\n}\n\nSpan<int> CreateAndCapture(ref int value)\n{\n    // Okay: value Rule 3 specifies that the safe-context be limited to the ref-safe-context\n    // of the ref argument. That is the *caller-context* for value hence this is not allowed.\n    return new Span<int>(ref value);\n}\n\nSpan<int> ComplexScopedRefExample(scoped ref Span<int> span)\n{\n    // Okay: the safe-context of `span` is *caller-context* hence this is legal.\n    return span;\n\n    // Okay: the local `refLocal` has a ref-safe-context of *function-member* and a \n    // safe-context of *caller-context*. In the call below it is passed to a \n    // parameter that is `scoped ref` which means it does not contribute \n    // ref-safe-context. It only contributes its safe-context hence the returned\n    // rvalue ends up as safe-context of *caller-context*\n    Span<int> local = default;\n    ref Span<int> refLocal = ref local;\n    return ComplexScopedRefExample(ref refLocal);\n\n    // Error: similar analysis as above but the safe-context of `stackLocal` is \n    // *function-member* hence this is illegal\n    Span<int> stackLocal = stackalloc int[42];\n    return ComplexScopedRefExample(ref stackLocal);\n}\n```\n\n#### Rules for object initializers\n\nThe *safe-context* of an object initializer expression is narrowest of:\n\n1. The *safe-context* of the constructor call.\n2. The *safe-context* and *ref-safe-context* of arguments to member initializer indexers that can escape to the receiver.\n3. The *safe-context* of the RHS of assignments in member initializers to non-readonly setters or *ref-safe-context* in case of ref assignment.\n\nAnother way of modeling this is to think of any argument to a member initializer that can be assigned to the receiver as being an argument to the constructor. This is because the member initializer is effectively a constructor call.\n\n```c#\nSpan<int> heapSpan = default;\nSpan<int> stackSpan = stackalloc int[42];\nvar x = new S(ref heapSpan)\n{\n    Field = stackSpan;\n}\n\n// Can be modeled as \nvar x = new S(ref heapSpan, stackSpan);\n```\n\nThis modeling is important because it demonstrates that our [MAMM](#rules-method-arguments-must-match) need to account specially for member initializers. Consider that this particular case needs to be illegal as it allows for a value with a narrower *safe-context* to be assigned to a higher one.\n\n### Method arguments must match\n<a name=\"rules-method-arguments-must-match\"></a>\n\nThe presence of `ref` fields means the rules around method arguments must match need to be updated as a `ref` parameter can now be stored as a field in a `ref struct` argument to the method. Previously the rule only had to consider another `ref struct` being stored as a field. The impact of this is discussed in [the compat considerations](#compat-considerations). The new rule is ... \n\n> For any method invocation `e.M(a1, a2, ... aN)`\n> 1. Calculate the narrowest *safe-context* from:\n>     - *caller-context*\n>     - The *safe-context* of all arguments\n>     - The *ref-safe-context* of all ref arguments whose corresponding parameters have a *ref-safe-context* of *caller-context*\n> 2. All `ref` arguments of `ref struct` types must be assignable by a value with that *safe-context*. This is a case where `ref` does **not** generalize to include `in` and `out`\n\n> For any method invocation `e.M(a1, a2, ... aN)`\n> 1. Calculate the narrowest *safe-context* from:\n>     - *caller-context*\n>     - The *safe-context* of all arguments\n>     - The *ref-safe-context* of all ref arguments whose corresponding parameters are not `scoped` \n> 2. All `out` arguments of `ref struct` types must be assignable by a value with that *safe-context*.\n\nThe presence of `scoped` allows developers to reduce the friction this rule creates by marking parameters which are not returned as `scoped`. This removes their arguments from (1) in both cases above and provides greater flexibility to callers.\n\nImpact of this change is discussed more deeply [below](#examples-method-arguments-must-match). Overall this will allow developers to make call sites more flexible by annotating non-escaping ref-like values with `scoped`.\n\n#### Parameter scope variance\n<a name=\"scoped-mismatch\"></a>\n\nThe `scoped` modifier and `[UnscopedRef]` attribute (see [below](#rules-unscoped)) on parameters also impacts our object overriding, interface implementation and `delegate` conversion rules. The signature for an override, interface implementation or `delegate` conversion can: \n- Add `scoped` to a `ref` or `in` parameter\n- Add `scoped` to a `ref struct` parameter\n- Remove `[UnscopedRef]` from an `out` parameter\n- Remove `[UnscopedRef]` from a `ref` parameter of a `ref struct` type\n\nAny other difference with respect to `scoped` or `[UnscopedRef]` is considered a mismatch.\n\nThe compiler will report a diagnostic for _unsafe scoped mismatches_ across overrides, interface implementations, and delegate conversions when:\n- The method has a `ref` or `out` parameter of `ref struct` type with a mismatch of adding `[UnscopedRef]` (not removing `scoped`).\n  (In this case, a [silly cyclic assignment](#cyclic-assignment) is possible, hence no other parameters are necessary.)\n- Or both of these are true:\n  - The method returns a `ref struct` or returns a `ref` or `ref readonly`, or the method has a `ref` or `out` parameter of `ref struct` type.\n  - The method has at least one additional `ref`, `in`, or `out` parameter, or a parameter of `ref struct` type.\n\nThe diagnostic is not reported in other cases because:\n- The methods with such signatures cannot capture the refs passed in, so any scoped mismatch is not dangerous.\n- These include very common and simple scenarios (e.g., plain old `out` parameters which are used in `TryParse` method signatures)\n  and reporting scoped mismatches just because they are used across language version 11 (and hence the `out` parameter is differently scoped) would be confusing.\n\nThe diagnostic is reported as an _error_ if the mismatched signatures are both using C#11 ref safe context rules; otherwise, the diagnostic is a _warning_.\n\nThe scoped mismatch warning may be reported on a module compiled with C#7.2 ref safe context rules where `scoped` is not available. In some such cases, it may be necessary to suppress the warning if the other mismatched signature cannot be modified.\n\nThe `scoped` modifier and `[UnscopedRef]` attribute also have the following effects on method signatures:\n- The `scoped` modifier and `[UnscopedRef]` attribute do not affect hiding\n- Overloads cannot differ only on `scoped` or `[UnscopedRef]`\n\nThe section on `ref` field and `scoped` is long so wanted to close with a brief summary of the proposed breaking changes:\n\n* A value that has *ref-safe-context* to the *caller-context* is returnable by `ref` or `ref` field.\n* A `out` parameter would have a  *safe-context* of *function-member*.\n\nDetailed Notes:\n- A `ref` field can only be declared inside of a `ref struct` \n- A `ref` field cannot be declared `static`, `volatile` or `const`\n- A `ref` field cannot have a type that is `ref struct`\n- The reference assembly generation process must preserve the presence of a `ref` field inside a `ref struct` \n- A `readonly ref struct` must declare its `ref` fields as `readonly ref`\n- For by-ref values the `scoped` modifier must appear before `in`, `out`, or `ref`\n- The span safety rules document will be updated as outlined in this document\n- The new ref safe context rules will be in effect when either \n    - The core library contains the feature flag indicating support for `ref` fields\n    - The `langversion` value is 11 or higher\n\n### Syntax\n[13.6.2 Local variable declarations](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md#1362-local-variable-declarations): added `'scoped'?`.\n```antlr\nlocal_variable_declaration\n    : 'scoped'? local_variable_mode_modifier? local_variable_type local_variable_declarators\n    ;\n\nlocal_variable_mode_modifier\n    : 'ref' 'readonly'?\n    ;\n```\n\n[13.9.4 The `for` statement](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md#1394-the-for-statement): added `'scoped'?` _indirectly_ from `local_variable_declaration`.\n\n[13.9.5 The `foreach` statement](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md#1395-the-foreach-statement): added `'scoped'?`.\n```antlr\nforeach_statement\n    : 'foreach' '(' 'scoped'? local_variable_type identifier 'in' expression ')'\n      embedded_statement\n    ;\n```\n\n[12.6.2 Argument lists](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1262-argument-lists): added `'scoped'?` for `out` declaration variable.\n```antlr\nargument_value\n    : expression\n    | 'in' variable_reference\n    | 'ref' variable_reference\n    | 'out' ('scoped'? local_variable_type)? identifier\n    ;\n```\n\n[12.7 Deconstruction expressions](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#127-deconstruction):\n```antlr\n[TBD]\n```\n\n[15.6.2 Method parameters](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#1562-method-parameters): added `'scoped'?` to `parameter_modifier`.\n```antlr\nfixed_parameter\n    : attributes? parameter_modifier? type identifier default_argument?\n    ;\n\nparameter_modifier\n    | 'this' 'scoped'? parameter_mode_modifier?\n    | 'scoped' parameter_mode_modifier?\n    | parameter_mode_modifier\n    ;\n\nparameter_mode_modifier\n    : 'in'\n    | 'ref'\n    | 'out'\n    ;\n```\n\n[20.2 Delegate declarations](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/delegates.md#202-delegate-declarations): added `'scoped'?` _indirectly_ from `fixed_parameter`.\n\n[12.19 Anonymous function expressions](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1219-anonymous-function-expressions): added `'scoped'?`.\n```antlr\nexplicit_anonymous_function_parameter\n    : 'scoped'? anonymous_function_parameter_modifier? type identifier\n    ;\n\nanonymous_function_parameter_modifier\n    : 'in'\n    | 'ref'\n    | 'out'\n    ;\n```\n\n### Sunset restricted types\nThe compiler has a concept of a set of \"restricted types\" which is largely undocumented. These types were given a special status because in C# 1.0 there was no general purpose way to express their behavior. Most notably the fact that the types can contain references to the execution stack. Instead the compiler had special knowledge of them and restricted their use to ways that would always be safe: disallowed returns, cannot use as array elements, cannot use in generics, etc ...\n\nOnce `ref` fields are available and extended to support `ref struct` these types can be correctly defined in C# using a combination of `ref struct` and `ref` fields. Therefore when the compiler detects that a runtime supports `ref` fields it will no longer have a notion of restricted types. It will instead use the types as they are defined in the code. \n\nTo support this our ref safe context rules will be updated as follows:\n\n- `__makeref` will be treated as a method with the signature `static TypedReference __makeref<T>(ref T value)`\n- `__refvalue` will be treated as a method with the signature `static ref T __refvalue<T>(TypedReference tr)`. The expression `__refvalue(tr, int)` will effectively use the second argument as the type parameter.\n- `__arglist` as a parameter will have a *ref-safe-context* and *safe-context* of *function-member*. \n- `__arglist(...)` as an expression will have a *ref-safe-context* and *safe-context* of *function-member*. \n\nConforming runtimes will ensure that `TypedReference`, `RuntimeArgumentHandle` and `ArgIterator` are defined as `ref struct`. Further `TypedReference` must be viewed as having a `ref` field to a `ref struct` for any possible type (it can store any value). That combined with the above rules will ensure references to the stack do not escape beyond their lifetime.\n\nNote: strictly speaking this is a compiler implementation detail vs. part of the language. But given the relationship with `ref` fields it is being included in the language proposal for simplicity.\n\n### Provide unscoped\nOne of the most notable friction points is the inability to return fields by `ref` in instance members of a `struct`. This means developers can't create `ref` returning methods / properties and have to resort to exposing fields directly. This reduces the usefulness of `ref` returns in `struct` where it is often the most desired. \n\n```c#\nstruct S\n{\n    int _field;\n\n    // Error: this, and hence _field, can't return by ref\n    public ref int Prop => ref _field;\n}\n```\n\nThe [rationale](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-7.2/span-safety.md#struct-this-escape) for this default is reasonable but there is nothing inherently wrong with a `struct` escaping `this` by reference, it is simply the default chosen by the ref safe context rules. \n\n<a name=\"rules-unscoped\"></a>\n\nTo fix this the language will provide the opposite of the `scoped` lifetime annotation by supporting an `UnscopedRefAttribute`. This can be applied to any `ref` and it will change the *ref-safe-context* to be one level wider than its default. For example:\n\n| UnscopedRef applied to | Original *ref-safe-context* | New *ref-safe-context* |\n| --- | --- | --- |\n| instance member | function-member | return-only |\n| `in` / `ref` parameter | return-only | caller-context |\n| `out` parameter | function-member | return-only |\n\nWhen applying `[UnscopedRef]` to an instance method of a `struct` it has the impact of modifying the implicit `this` parameter. This means `this` acts as an unannotated `ref` of the same type. \n\n```c#\nstruct S\n{\n    int field; \n\n    // Error: `field` has the ref-safe-context of `this` which is *function-member* because \n    // it is a `scoped ref`\n    ref int Prop1 => ref field;\n\n    // Okay: `field` has the ref-safe-context of `this` which is *caller-context* because \n    // it is a `ref`\n    [UnscopedRef] ref int Prop1 => ref field;\n}\n```\n\nThe annotation can also be placed on `out` parameters to restore them to C# 10 behavior.\n\n```c#\nref int SneakyOut([UnscopedRef] out int i)\n{\n    i = 42;\n    return ref i;\n}\n```\n\nFor the purposes of ref safe context rules, such an `[UnscopedRef] out` is considered simply a `ref`. Similar to how `in` is considered `ref` for lifetime purposes. \n\nThe `[UnscopedRef]` annotation will be disallowed on `init` members and constructors inside `struct`. Those members are already special with respect to `ref` semantics as they view `readonly` members as mutable. This means taking `ref` to those members appears as a simple `ref`, not `ref readonly`. This is allowed within the boundary of constructors and `init`. Allowing `[UnscopedRef]` would permit such a `ref` to incorrectly escape outside the constructor and permit mutation after `readonly` semantics had taken place.\n\nThe attribute type will have the following definition:\n\n```c#\nnamespace System.Diagnostics.CodeAnalysis\n{\n    [AttributeUsage(\n        AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter,\n        AllowMultiple = false,\n        Inherited = false)]\n    public sealed class UnscopedRefAttribute : Attribute\n    {\n    }\n}\n```\n\nDetailed Notes:\n- An instance method or property annotated with `[UnscopedRef]` has *ref-safe-context* of `this` set to the *caller-context*.\n- A member annotated with `[UnscopedRef]` cannot implement an interface.\n- It is an error to use `[UnscopedRef]` on \n    - A member that is not declared on a `struct`\n    - A `static` member, `init` member or constructor on a `struct`\n    - A parameter marked `scoped`\n    - A parameter passed by value\n    - A parameter passed by reference that is not implicitly scoped\n\n### ScopedRefAttribute\nThe `scoped` annotations will be emitted into metadata via the type `System.Runtime.CompilerServices.ScopedRefAttribute` attribute. The attribute will be matched by namespace-qualified name so the definition does not need to appear in any specific assembly.\n\nThe `ScopedRefAttribute` type is for compiler use only - it is not permitted in source. The type declaration is synthesized by the compiler if not already included in the compilation.\n\nThe type will have the following definition:\n\n```c#\nnamespace System.Runtime.CompilerServices\n{\n    [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]\n    internal sealed class ScopedRefAttribute : Attribute\n    {\n    }\n}\n```\n\nThe compiler will emit this attribute on the parameter with `scoped` syntax. This will only be emitted when the syntax causes the value to differ from its default state. For example `scoped out` will cause no attribute to be emitted.\n\n### RefSafetyRulesAttribute\nThere are several differences in the _ref safe context_ rules between C#7.2 and C#11. Any of these differences could result in breaking changes when recompiling with C#11 against references compiled with C#10 or earlier.\n1. unscoped `ref`/`in`/`out` parameters may escape a method invocation as a `ref` field of a `ref struct` in C#11, not in C#7.2\n1. `out` parameters are implicitly scoped in C#11, and unscoped in C#7.2\n1. `ref`/`in` parameters to `ref struct` types are implicitly scoped in C#11, and unscoped in C#7.2\n\nTo reduce the chance of breaking changes when recompiling with C#11, we will update the C#11 compiler to use the ref safe context rules _for method invocation_ that _match the rules that were used to analyze the method declaration_. Essentially, when analyzing a call to a method compiled with an older compiler, the C#11 compiler will use C#7.2 ref safe context rules. \n\nTo enable this, the compiler will emit a new `[module: RefSafetyRules(11)]` attribute when the module is compiled with `-langversion:11` or higher or compiled with a corlib containing the feature flag for `ref` fields.\n\nThe argument to the attribute indicates the language version of the _ref safe context_ rules used when the module was compiled.\nThe version is currently fixed at `11` regardless of the actual language version passed to the compiler.\n\nThe expectation is that future versions of the compiler will update the ref safe context rules and emit attributes with distinct versions.\n\nIf the compiler loads a module that includes a `[module: RefSafetyRules(version)]` _with a `version` other than `11`_, the compiler will report an error for the unrecognized version if there are any calls to methods declared in that module.\n\nWhen the C#11 compiler _analyzes a method call_:\n- If the module containing the method declaration includes `[module: RefSafetyRules(version)]`, where `version` is `11`, the method call is analyzed with C#11 rules.\n- If the module containing the method declaration is from source, and compiled with `-langversion:11` or with a corlib containing the feature flag for `ref` fields, the method call is analyzed with C#11 rules.\n- _If the module containing the method declaration references `System.Runtime { ver: 7.0 }`, the method call is analyzed with C#11 rules. This rule is a temporary mitigation for modules compiled with earlier previews of C#11 / .NET 7 and will be removed later._\n- Otherwise, the method call is analyzed with C#7.2 rules.\n\nA pre-C#11 compiler will ignore any `RefSafetyRulesAttribute` and analyze method calls with C#7.2 rules only.\n\nThe `RefSafetyRulesAttribute` will be matched by namespace-qualified name so the definition does not need to appear in any specific assembly.\n\nThe `RefSafetyRulesAttribute` type is for compiler use only - it is not permitted in source. The type declaration is synthesized by the compiler if not already included in the compilation.\n\n```csharp\nnamespace System.Runtime.CompilerServices\n{\n    [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]\n    internal sealed class RefSafetyRulesAttribute : Attribute\n    {\n        public RefSafetyRulesAttribute(int version) { Version = version; }\n        public readonly int Version;\n    }\n}\n```\n\n### Safe fixed size buffers\n\nSafe fixed size buffers was not delivered in C# 11. This feature may be implemented in a future version of C#.\n\n<details>\n\nThe language will relax the restrictions on fixed sized arrays such that they can be declared in safe code and the element type can be managed or unmanaged.  This will make types like the following legal:\n\n```c#\ninternal struct CharBuffer\n{\n    internal char Data[128];\n}\n```\n\nThese declarations, much like their `unsafe` counter parts, will define a sequence of `N` elements in the containing type. These members can be accessed with an indexer and can also be converted to `Span<T>` and `ReadOnlySpan<T>` instances.\n\nWhen indexing into a `fixed` buffer of type `T` the `readonly` state of the container must be taken into account.  If the container is `readonly` then the indexer returns `ref readonly T` else it returns `ref T`. \n\nAccessing a `fixed` buffer without an indexer has no natural type however it is convertible to `Span<T>` types. In the case the container is `readonly` the buffer is implicitly convertible to `ReadOnlySpan<T>`, else it can implicitly convert to `Span<T>` or `ReadOnlySpan<T>` (the `Span<T>` conversion is considered *better*). \n\nThe resulting `Span<T>` instance will have a length equal to the size declared on the `fixed` buffer. The *safe-context* of the returned value will be equal to the *safe-context* of the container, just as it would if the backing data was accessed as a field.\n\nFor each `fixed` declaration in a type where the element type is `T` the language will generate a corresponding `get` only indexer method whose return type is `ref T`. The indexer will be annotated with the `[UnscopedRef]` attribute as the implementation will be returning fields of the declaring type. The accessibility of the member will match the accessibility on the `fixed` field.\n\nFor example, the signature of the indexer for `CharBuffer.Data` will be the following:\n\n```c#\n[UnscopedRef] internal ref char DataIndexer(int index) => ...;\n```\n\nIf the provided index is outside the declared bounds of the `fixed` array then an `IndexOutOfRangeException` will be thrown. In the case a constant value is provided then it will be replaced with a direct reference to the appropriate element. Unless the constant is outside the declared bounds in which case a compile time error would occur.\n\nThere will also be a named accessor generated for each `fixed` buffer that provides by value `get` and `set` operations. Having this means that `fixed` buffers will more closely resemble existing array semantics by having a `ref` accessor as well as byval `get` and `set` operations. This means compilers will have the same flexibility when emitting code consuming `fixed` buffers as they do when consuming arrays. This should make operations like `await` over `fixed` buffers easier to emit. \n\nThis also has the added benefit that it will make `fixed` buffers easier to consume from other languages. Named indexers is a feature that has existed since the 1.0 release of .NET. Even languages which cannot directly emit a named indexer can generally consume them (C# is actually a good example of this).\n\nThe backing storage for the buffer will be generated using the `[InlineArray]` attribute. This is a mechanism discussed in [issue 12320](https://github.com/dotnet/runtime/issues/12320) which allows specifically for the case of efficiently declaring sequence of fields of the same type. This particular issue is still under active discussion and the expectation is that the implementation of this feature will follow however that discussion goes.\n\n</details>\n\n### Initializers with `ref` values in `new` and `with` expressions\n\nIn section [12.8.17.3 Object initializers](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#128173-object-initializers), we update the grammar to:\n\n```antlr\ninitializer_value\n    : 'ref' expression // added\n    | expression\n    | object_or_collection_initializer\n    ;\n```\n\nIn the section for [`with` expression](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-9.0/records.md#with-expression), we update the grammar to:\n```antlr\nmember_initializer\n    : identifier '=' 'ref' expression // added\n    | identifier '=' expression\n    ;\n```\n\nThe left operand of the assignment must be an expression that binds to a ref field.  \nThe right operand must be an expression that yields an lvalue designating a value of the same type as the left operand.  \n\nWe add a similar rule to [ref local reassignment](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-7.3/ref-local-reassignment.md):  \nIf the left operand is a writeable ref (i.e. it designates anything other than a `ref readonly` field), then the right operand must be a writeable lvalue.\n\nThe escape rules for [constructor invocations](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-7.2/span-safety.md#constructor-invocations) remain:\n> A `new` expression that invokes a constructor obeys the same rules as a method invocation that is considered to return the type being constructed.\n\nNamely the rules of [method invocation](#rules-method-invocation) updated above:\n> An rvalue resulting from a method invocation `e1.M(e2, ...)` has *safe-context* from the smallest of the following contexts:\n> 1. The *caller-context*\n> 2. The *safe-context* contributed by all argument expressions\n> 3. When the return is a `ref struct` then *ref-safe-context* contributed by all `ref` arguments\n\nFor a `new` expression with initializers, the initializer expressions count as arguments (they contribute their *safe-context*) and the `ref` initializer expressions count as `ref` arguments (they contribute their *ref-safe-context*), recursively.\n\n## Changes in unsafe context\n\nPointer types ([section 23.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#233-pointer-types)) are extended to allow managed types as referent type.\nSuch pointer types are written as a managed type followed by a `*` token. They produce a warning.\n\nThe address-of operator ([section 23.6.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#2365-the-address-of-operator)) is relaxed to accept a variable with a managed type as its operand.\n\nThe `fixed` statement ([section 23.7](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#237-the-fixed-statement)) is relaxed to accept _fixed_pointer_initializer_ that is the address of a variable of managed type `T` or that is an expression of an _array_type_ with elements of a managed type `T`.\n\nThe stack allocation initializer ([section 12.8.22](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12822-stack-allocation)) is similarly relaxed.\n\n## Considerations\nThere are considerations other parts of the development stack should consider when evaluating this feature.\n\n### Compat Considerations\n<a name=\"compat-considerations\">\n\nThe challenge in this proposal is the compatibility implications this design has to our existing [span safety rules](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-7.2/span-safety.md), or [§9.7.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/variables.md#972-ref-safe-contexts). While those rules fully support the concept of a `ref struct` having `ref` fields they do not allow for APIs, other than `stackalloc`, to capture `ref` state that refers to the stack. The ref safe context rules have a [hard assumption](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-7.2/span-safety.md#span-constructor), or [§16.4.12.8](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/structs.md#164128-constructor-invocations) that a constructor of the form `Span(ref T value)` does not exist. That means the safety rules do not account for a `ref` parameter being able to escape as a `ref` field hence it allows for code like the following.\n\n```c#\nSpan<int> CreateSpanOfInt()\n{\n    // This is legal according to the 7.2 span rules because they do not account\n    // for a constructor in the form Span(ref T value) existing. \n    int local = 42;\n    return new Span<int>(ref local);\n}\n```\n\n<a name=\"ways-to-escape\"></a>\n\nEffectively there are three ways for a `ref` parameter to escape from a method invocation: \n\n1. By value return\n2. By `ref` return\n3. By `ref` field in `ref struct` that is returned or passed as `ref` / `out` parameter\n\nThe existing rules only account for (1) and (2). They do not account for (3) hence gaps like returning locals as `ref` fields are not accounted for. This design must change the rules to account for (3). This will have a small impact to compatibility for existing APIs. Specifically it will impact APIs that have the following properties.\n\n- Have a `ref struct` in the signature\n    - Where the `ref struct` is a return type, `ref` or `out` parameter\n    - Has an additional `in` or `ref` parameter excluding the receiver\n\nIn C# 10 callers of such APIs never had to consider that `ref` state input to the API could be captured as a `ref` field. That allowed for several patterns to exist, safely in C# 10, that will be unsafe in C# 11 due to the ability for `ref` state to escape as a `ref` field. For example:\n\n<a name=\"new-span-challenges\"></a>\n\n```c#\nSpan<int> CreateSpan(ref int parameter)\n{\n    // The implementation of this method is irrelevant when considering the lifetime of the \n    // returned Span<T>. The ref safe context rules only look at the method signature, not the \n    // implementation. In C# 10 ref fields didn't exist hence there was no way for `parameter`\n    // to escape by ref in this method\n}\n\nSpan<int> BadUseExamples(int parameter)\n{\n    // Legal in C# 10 but would be illegal with ref fields\n    return CreateSpan(ref parameter);\n\n    // Legal in C# 10 but would be illegal with ref fields\n    int local = 42;\n    return CreateSpan(ref local);\n\n    // Legal in C# 10 but would be illegal with ref fields\n    Span<int> span = stackalloc int[42];\n    return CreateSpan(ref span[0]);\n}\n```\n\nThe impact of this compatibility break is expected to be very small. The impacted API shape made little sense in the absence of `ref` fields hence it is unlikely customers created many of these. Experiments running tools to spot this API shape over existing repositories back up that assertion. The only repository with any significant counts of this shape is [dotnet/runtime](https://github.com/dotnet/runtime) and that is because that repo can create `ref` fields via the `ByReference<T>` intrinsic type.\n\nEven so the design must account for such APIs existing because it expresses a valid pattern, just not a common one. Hence the design must give developers the tools to restore the existing lifetime rules when upgrading to C# 10. Specifically it must provide mechanisms that allow developers to annotate `ref` parameters as unable to escape by `ref` or `ref` field. That allows customers to define APIs in C# 11 that have the same C# 10 callsite rules.\n\n### Reference Assemblies\nA reference assembly for a compilation using features described in this proposal must maintain the elements that convey ref safe context information. That means all lifetime annotation attributes must be preserved in their original position. Any attempt to replace or omit them can lead to invalid reference assemblies.\n\nRepresenting `ref` fields is more nuanced. Ideally a `ref` field would appear in a reference assembly as would any other field. However a `ref` field represents a change to the metadata format and that can cause issues with tool chains that are not updated to understand this metadata change. A concrete example is C++/CLI which will likely error if it consumes a `ref` field. Hence it's advantageous if `ref` fields can be omitted from reference assemblies in our core libraries. \n\nA `ref` field by itself has no impact on ref safe context rules. As a concrete example consider that flipping the existing `Span<T>` definition to use a `ref` field has no impact on consumption. Hence the `ref` itself can be omitted safely. However a `ref` field does have other impacts to consumption that must be preserved: \n\n- A `ref struct` which has a `ref` field is never considered `unmanaged` \n- The type of the `ref` field impacts infinite generic expansion rules. Hence if the type of a `ref` field contains a type parameter that must be preserved \n\nGiven those rules here is a valid reference assembly transformation for a `ref struct`: \n\n```c#\n// Impl assembly \nref struct S<T>\n{\n    ref T _field;\n}\n\n// Ref assembly \nref struct S<T>\n{\n    object _o; // force managed \n    T _f; // maintain generic expansion protections\n}\n```\n\n### Annotations\nLifetimes are most naturally expressed using types. A given program's lifetimes are safe when the lifetime types type check. While the syntax of C# implicitly adds lifetimes to values, there is an underlying type system that describes the fundamental rules here. It's often easier to discuss the implication of changes to the design in terms of these rules so they are included here for discussion sake.\n\nNote that this is not meant to be a 100% complete documentation. Documenting every single behavior isn't a goal here. Instead it's meant to establish a general understanding and common verbiage by which the model, and potential changes to it, can be discussed.\n\nUsually it's not necessary to directly talk about lifetime types. The exceptions are places where lifetimes can vary based on particular \"instantiation\" sites. This is a kind of polymorphism and we call these varying lifetimes \"generic lifetimes\", represented as generic parameters. C# does not provide syntax for expressing lifetime generics, so we define an implicit \"translation\" from C# to an expanded lowered language that contains explicit generic parameters.\n\nThe below examples make use of named lifetimes. The syntax `$a` refers to a lifetime named `a`. It is a lifetime that has no meaning by itself but can be given a relationship to other lifetimes via the `where $a : $b` syntax. This establishes that `$a` is convertible to `$b`. It may help to think of this as establishing that `$a` is a lifetime at least as long as `$b`.\n\nThere are a few predefined lifetimes for convenience and brevity below:\n\n- `$heap`: this is the lifetime of any value that exists on the heap. It is available in all contexts and method signatures.\n- `$local`: this is the lifetime of any value that exists on the method stack. It's effectively a name place holder for *function-member*. It is implicitly defined in methods and can appear in method signatures except for any output position.\n- `$ro`: name place holder for *return only*\n- `$cm`: name place holder for *caller-context* \n\nThere are a few predefined relationships between lifetimes:\n\n- `where $heap : $a` for all lifetimes `$a`\n- `where $cm : $ro` \n- `where $x : $local` for all predefined lifetimes. User defined lifetimes have no relationship to local unless explicitly defined.\n\nLifetime variables when defined on types can be invariant or covariant. These are expressed using the same syntax as generic parameters:\n\n```csharp\n// $this is covariant\n// $a is invariant\nref struct S<out $this, $a> \n```\n\nThe lifetime parameter `$this` on type definitions is _not_ predefined but it does have a few rules associated with it when it is defined:\n- It must be the first lifetime parameter.\n- It must be covariant: `out $this`. \n- The lifetime of `ref` fields must be convertible to `$this`\n- The `$this` lifetime of all non-ref fields must be `$heap` or `$this`.\n\nThe lifetime of a ref is expressed by providing a lifetime argument to the ref. For example a `ref` that refers to the heap is expressed as `ref<$heap>`.\n\nWhen defining a constructor in the model the name `new` will be used for the method. It is necessary to have a parameter list for the returned value as well as the constructor arguments. This is necessary to express the relationship between constructor inputs and the constructed value. Rather than having `Span<$a><$ro>` the model will use `Span<$a> new<$ro>` instead. The type of `this` in the constructor, including lifetimes, will be the defined return value.\n\nThe basic rules for the lifetime are defined as:\n\n- All lifetimes are expressed syntactically as generic arguments, coming before type arguments. This is true for predefined lifetimes except `$heap` and `$local`. \n- All types `T` that are not a `ref struct` implicitly have lifetime of `T<$heap>`. This is implicit, there is no need to write `int<$heap>` in every sample.\n- For a `ref` field defined as `ref<$l0> T<$l1, $l2, ... $ln>`:\n    - All lifetimes `$l1` through `$ln` must be invariant. \n    - The lifetime of `$l0` must be convertible to `$this`\n- For a `ref` defined as `ref<$a> T<$b, ...>`, `$b` must be convertible to `$a`\n- The `ref` of a variable has a lifetime defined by:\n    - For a `ref` local, parameter, field or return of type `ref<$a> T` the lifetime is `$a`\n    - `$heap` for all reference types and fields of reference types\n    - `$local` for everything else\n- An assignment or return is legal when the underlying type conversion is legal\n- Lifetimes of expressions can be made explicit by using cast annotations:\n    - `(T<$a> expr)` the value lifetime is explicitly `$a` for `T<...>`\n    - `ref<$a> (T<$b>)expr` the value lifetime is `$b` for `T<...>` and the ref lifetime is `$a`.\n\nFor the purpose of lifetime rules a `ref` is considered part of the type of the expression for purposes of conversions. It is logically represented by converting `ref<$a> T<...>` to `ref<$a, T<...>>` where `$a` is covariant and `T` is invariant. \n\nNext let's define the rules that allow us to map C# syntax to the underlying model.\n\nFor brevity sake a type which has no explicit lifetime parameters treated as if there is `out $this` defined and applied to all fields of the type. A type with a `ref` field must define explicit lifetime parameters.\n\nThese rules exists to support our existing invariant that `T` can be assigned to `scoped T` for all types. That maps down to `T<$a, ...>` being assignable to `T<$local, ...>` for all lifetimes known to be convertible to `$local`. Further this supports other items like being able to assign `Span<T>` from the heap to those on the stack. This does exclude types where fields have differing lifetimes for non-ref values but that is the reality of C# today. Changing that would require a significant change of C# rules that would need to be mapped out. \n\nThe type of `this` for a type `S<out $this, ...>` inside an instance method is implicitly defined as the following:\n- For normal instance method: `ref<$local> S<$cm, ...>`\n- For instance method annotated with `[UnscopedRef]`: `ref<$ro> S<$cm, ...>`\n\nThe lack of an explicit `this` parameter forces the implicit rules here. For complex samples and discussions consider writing as a `static` method and making `this` an explicit parameter.\n\n```csharp\nref struct S<out $this>\n{\n    // Implicit this can make discussion confusing \n    void M<$ro, $cm>(ref<$ro> S<$cm> s) {  }\n\n    // Rewrite as explicit this to simplify discussion\n    static void M<$ro, $cm>(ref<$local> S<$cm> this, ref<$ro> S<$cm> s) { }\n}\n```\n\nThe C# method syntax maps to the model in the following ways: \n\n- `ref` parameters have a ref lifetime of `$ro`\n- parameters of type `ref struct` have a this lifetime of `$cm`\n- ref returns have a ref lifetime of `$ro`\n- returns of type `ref struct` have a value lifetime of `$ro`\n- `scoped` on a parameter or `ref` changes the ref lifetime to be `$local`\n\nGiven that let's explore a simple example that demonstrates the model here: \n\n```csharp\nref int M1(ref int i) => ...\n\n// Maps to the following. \n\nref<$ro> int Identity<$ro>(ref<$ro> int i)\n{\n    // okay: has ref lifetime $ro which is equal to $ro\n    return ref i;\n\n    // okay: has ref lifetime $heap which convertible $ro\n    int[] array = new int[42];\n    return ref array[0];\n\n    // error: has ref lifetime $local which has no conversion to $a hence \n    // it's illegal\n    int local = 42;\n    return ref local;\n}\n```\n\nNow let's explore the same example using a `ref struct`: \n\n```csharp\nref struct S\n{\n    ref int Field;\n\n    S(ref int f)\n    {\n        Field = ref f;\n    }\n}\n\nS M2(ref int i, S span1, scoped S span2) => ...\n\n// Maps to \n\nref struct S<out $this>\n{\n    // Implicitly \n    ref<$this> int Field;\n\n    S<$ro> new<$ro>(ref<$ro> int f)\n    {\n        Field = ref f;\n    }\n}\n\nS<$ro> M2<$ro>(\n    ref<$ro> int i,\n    S<$ro> span1)\n    S<$local> span2)\n{\n    // okay: types match exactly\n    return span1;\n\n    // error: has lifetime $local which has no conversion to $ro\n    return span2;\n\n    // okay: type S<$heap> has a conversion to S<$ro> because $heap has a\n    // conversion to $ro and the first lifetime parameter of S<> is covariant\n    return default(S<$heap>)\n\n    // okay: the ref lifetime of ref $i is $ro so this is just an \n    // identity conversion\n    S<$ro> local = new S<$ro>(ref $i);\n    return local;\n\n    int[] array = new int[42];\n    // okay: S<$heap> is convertible to S<$ro>\n    return new S<$heap>(ref<$heap> array[0]);\n\n    // okay: the parameter of the ctor is $ro ref int and the argument is $heap ref int. These \n    // are convertible.\n    return new S<$ro>(ref<$heap> array[0]);\n\n    // error: has ref lifetime $local which has no conversion to $a hence \n    // it's illegal\n    int local = 42;\n    return ref local;\n}\n```\n\nNext let's see how this helps with the cyclic self assignment problem:\n\n```csharp\nref struct S\n{\n    int field;\n    ref int refField;\n\n    static void SelfAssign(ref S s)\n    {\n        s.refField = ref s.field;\n    }\n}\n\n// Maps to \n\nref struct S<out $this>\n{\n    int field;\n    ref<$this> int refField;\n\n    static void SelfAssign<$ro, $cm>(ref<$ro> S<$cm> s)\n    {\n        // error: the types work out here to ref<$cm> int = ref<$ro> int and that is \n        // illegal as $ro has no conversion to $cm (the relationship is the other direction)\n        s.refField = ref<$ro> s.field;\n    }\n}\n```\n\nNext let's see how this helps with the silly capture parameter problem: \n\n```csharp\nref struct S\n{\n    ref int refField;\n\n    void Use(ref int parameter)\n    {\n        // error: this needs to be an error else every call to this.Use(ref local) would fail \n        // because compiler would assume the `ref` was captured by ref.\n        this.refField = ref parameter;\n    }\n}\n\n// Maps to \n\nref struct S<out $this>\n{\n    ref<$this> int refField;\n    \n    // Using static form of this method signature so the type of this is explicit. \n    static void Use<$ro, $cm>(ref<$local> S<$cm> @this, ref<$ro> int parameter)\n    {\n        // error: the types here are:\n        //  - refField is ref<$cm> int\n        //  - ref parameter is ref<$ro> int\n        // That means the RHS is not convertible to the LHS ($ro is not covertible to $cm) and \n        // hence this reassignment is illegal\n        @this.refField = ref<$ro> parameter;\n    }\n}\n```\n\n## Open Issues\n\n### Change the design to avoid compat breaks\nThis design proposes several compatibility breaks with our existing ref-safe-context rules. Even though the breaks are believed to be minimally impactful significant consideration was given to a design which had no breaking changes.\n\nThe compat preserving design though was significantly more complex than this one. In order to preserve compat `ref` fields need distinct lifetimes for the ability to return by `ref` and return by `ref` field. Essentially it requires us to provide *ref-field-safe-context* tracking for all parameters to a method. This needs to be calculated for all expressions and tracked in all values virtually everywhere that *ref-safe-context* is tracked today.\n\nFurther this value has relationships with *ref-safe-context*. For example it's non-sensical to have a value can be returned as a `ref` field but not directly as `ref`. That is because `ref` fields can be trivially returned by `ref` already (`ref` state in a `ref struct` can be returned by `ref` even when the containing value cannot). Hence the rules further need constant adjustment to ensure these values are sensible with respect to each other. \n\nAlso it means the language needs syntax to represent `ref` parameters that can be returned in three different ways: by `ref` field, by `ref` and by value. The default being returnable by `ref`. Going forward though the more natural return, particularly when `ref struct` are involved is expected to be by `ref` field or `ref`. That means new APIs require an extra syntax annotation to be correct by default. This is undesirable. \n\nThese compat changes though will impact methods that have the following properties:\n\n- Have a `Span<T>` or `ref struct`\n    - Where the `ref struct` is a return type, `ref` or `out` parameter\n    - Has an additional `in` or `ref` parameter (excluding the receiver)\n\nTo understand the impact it's helpful to break APIs into categories:\n\n1. Want consumers to account for `ref` being captured as a `ref` field. Prime example is the `Span(ref T value)` constructors \n2. Do not want consumers to account for `ref` being captured as a `ref` field. These though break into two categories\n    1. Unsafe APIs. These are APIS inside the `Unsafe` and `MemoryMarshal` types, of which `MemoryMarshal.CreateSpan` is the most prominent. These APIs do capture the `ref` unsafely but they are also known to be unsafe APIs.\n    2. Safe APIs. These are APIs which take `ref` parameters for efficiency but it is not actually captured anywhere. Examples are small but one is `AsnDecoder.ReadEnumeratedBytes`\n\nThis change primarily benefits (1) above. These are expected to make up the majority of APIs that take a `ref` and return a `ref struct` going forward. The changes negatively impact (2.1) and (2.2) as it breaks the existing calling semantics because the lifetime rules change. \n\nThe APIs in category (2.1) though are largely authored by Microsoft or by developers who stand the most to benefit from `ref` fields (the Tanner's of the world). It is reasonable to assume this class of developers would be amenable to a compatibility tax on upgrade to C# 11 in the form of a few annotations to retain the existing semantics if `ref` fields were provided in return.\n\nThe APIs in category (2.2) are the biggest issue. It is unknown how many such APIs exist and it's unclear if these would be more / less frequent in 3rd party code. The expectation is there is a very small number of them, particularly if we take the compat break on `out`. Searches so far have revealed a very small number of these existing in `public` surface area. This is a hard pattern to search for though as it requires semantic analysis. Before taking this change a tool based approach would be needed to verify the assumptions around this impacting a small number of known cases.\n\nFor both cases in category (2) though the fix is straight forward. The `ref` parameters that do not want to be considered capturable must add `scoped` to the `ref`. In (2.1) this will likely also force the developer to use `Unsafe` or `MemoryMarshal` but that is expected for unsafe style APIs.\n\nIdeally the language could reduce the impact of silent breaking changes by issuing a warning when an API silently falls into the troublesome behavior. That would be a method that both takes a `ref`, returns `ref struct` but does not actually capture the `ref` in the `ref struct`. The compiler could issue a diagnostic in that case informing developers such `ref` should be annotated as `scoped ref` instead. \n\n**Decision** This design can be achieved but the resulting feature is more difficult to use to the point the decision was made to take the compat break.\n\n**Decision** The compiler will provide a warning when a method meets the criteria but does not capture the `ref` parameter as a `ref` field. This should suitably warn customers on upgrade about the potential issues they are creating\n\n### Keywords vs. attributes\nThis design calls for using attributes to annotate the new lifetime rules. This also could've been done just as easily with contextual keywords. For instance `[DoesNotEscape]` could map to `scoped`. However keywords, even the contextual ones, generally must meet a very high bar for inclusion. They take up valuable language real estate and are more prominent parts of the language. This feature, while valuable, is going to serve a minority of C# developers.\n\nOn the surface that would seem to favor not using keywords but there are two important points to consider: \n\n1. The annotations will effect program semantics. Having attributes impact program semantics is a line C# is reluctant to cross and it's unclear if this is the feature that should justify the language taking that step.\n1. The developers most likely to use this feature intersect strongly with the set of developers that use function pointers. That feature, while also used by a minority of developers, did warrant a new syntax and that decision is still seen as sound. \n\nTaken together this means syntax should be considered.\n\nA rough sketch of the syntax would be: \n\n- `[RefDoesNotEscape]` maps to `scoped ref` \n- `[DoesNotEscape]` maps to `scoped`\n- `[RefDoesEscape]` maps to `unscoped`\n\n**Decision** Use syntax for `scoped` and `scoped ref`; use attribute for `unscoped`.\n\n### Allow fixed buffer locals\nThis design allows for safe `fixed` buffers that can support any type. One possible extension here is allowing such `fixed` buffers to be declared as local variables. This would allow a number of existing `stackalloc` operations to be replaced with a `fixed` buffer. It would also expand the set of scenarios we could have stack style allocations as `stackalloc` is limited to unmanaged element types while `fixed` buffers are not. \n\n```c#\nclass FixedBufferLocals\n{\n    void Example()\n    {\n        Span<int> span = stackalloc int[42];\n        int buffer[42];\n    }\n}\n```\n\nThis holds together but does require us to extend the syntax for locals a bit.  Unclear if this is or isn't worth the extra complexity. Possible we could decide no for now and bring back later if sufficient need is demonstrated.\n\nExample of where this would be beneficial: https://github.com/dotnet/runtime/pull/34149\n\n**Decision** hold off on this for now\n\n### To use modreqs or not\nA decision needs to be made if methods marked with new lifetime attributes should or should not translate to `modreq` in emit. There would be effectively a 1:1 mapping between annotations and `modreq` if this approach was taken.\n\nThe rationale for adding a `modreq` is the attributes change the semantics of ref safe context rules. Only languages which understand these semantics should be calling the methods in question. Further when applied to OHI scenarios, the lifetimes become a contract that all derived methods must implement. Having the annotations exist without `modreq` can lead to situations where `virtual` method chains with conflicting lifetime annotations are loaded (can happen if only one part of `virtual` chain is compiled and other is not). \n\nThe initial ref safe context work did not use `modreq` but instead relied on languages and the framework to understand. At the same time though all of the elements that contribute to the ref safe context rules are a strong part of the method signature: `ref`, `in`, `ref struct`, etc ... Hence any change to the existing rules of a method already results in a binary change to the signature. To give the new lifetime annotations the same impact they will need `modreq` enforcement.\n\nThe concern is whether or not this is overkill. It does have the negative impact that making signatures more flexible, by say adding `[DoesNotEscape]` to a parameter, will result in a binary compat change. That trade off means that over time frameworks like BCL likely won't be able to relax such signatures. It could be mitigated to a degree by taking some approach the language does with `in` parameters and only apply `modreq` in virtual positions. \n\n**Decision** Do not use `modreq` in metadata. The difference between `out` and `ref` is not `modreq` but they now have different ref safe context values. There is no real benefit to only half enforcing the rules with `modreq` here.\n\n### Allow multi-dimensional fixed buffers\nShould the design for `fixed` buffers be extended to include multi-dimensional style arrays? Essentially allowing for declarations like the following:\n\n```c#\nstruct Dimensions\n{\n    int array[42, 13];\n}\n```\n\n**Decision** Do not allow for now\n\n### Violating scoped\nThe runtime repository has several non-public APIs that capture `ref` parameters as `ref` fields. These are unsafe because the lifetime of the resulting value is not tracked. For example the `Span<T>(ref T value, int length)` constructor.\n\nThe majority of these APIs will likely choose to have proper lifetime tracking on the return which will be achieved simply by updating to C# 11. A few though will want to keep their current semantics of not tracking the return value because their entire intent is to be unsafe. The most notable examples are `MemoryMarshal.CreateSpan` and `MemoryMarshal.CreateReadOnlySpan`. This will be achieved by marking the parameters as `scoped`.\n\nThat means the runtime needs an established pattern for unsafely removing `scoped` from a parameter:\n\n1. `Unsafe.AsRef<T>(in T value)` could expand its existing purpose by changing to `scoped in T value`. This would allow it to both remove `in` and `scoped` from parameters. It then becomes the universal \"remove ref safety\" method\n2. Introduce a new method whose entire purpose is to remove `scoped`: `ref T Unsafe.AsUnscoped<T>(scoped in T value)`. This removes `in` as well because if it did not then callers still need a combination of method calls to \"remove ref safety\" at which point the existing solution is likely sufficient.\n\n### Unscoped this by default?\nThe design only has two locations which are `scoped` by default: \n\n- `this` is `scoped ref` \n- `out` is `scoped ref`\n\nThe decision on `out` is to significantly reduce the compat burden of `ref` fields and at the same time is a more natural default. It lets developers actually think of `out` as data flowing outward only where as if it's `ref` then the rules must consider data flowing in both directions. This leads to significant developer confusion.\n\nThe decision on `this` is undesirable because it means a `struct` cannot return a field by `ref`. This is an important scenario to high perf developers and the `[UnscopedRef]` attribute was added essentially for this one scenario.\n\nKeywords have a high bar and adding it for a single scenario is suspect. As such thought was given to whether we could avoid this keyword at all by making `this` simply `ref` by default and not `scoped ref`. All members that need `this` to be `scoped ref` could do so by marking the method `scoped` (as a method can be marked `readonly` to create a `readonly ref` today).\n\nOn a normal `struct` this is mostly a positive change as it only introduces compat issues when a member has a `ref` return. There are **very** few of these methods and a tool could spot these and convert them to `scoped` members quickly. \n\nOn a `ref struct` this change introduces significantly bigger compat issues. Consider the following:\n\n```c#\nref struct Sneaky\n{\n    int Field;\n    ref int RefField;\n\n    public void SelfAssign()\n    {\n        // This pattern of ref reassign to fields on this inside instance methods would now\n        // completely legal.\n        RefField = ref Field;\n    }\n\n    static Sneaky UseExample()\n    {\n        Sneaky local = default;\n\n        // Error: this is illegal, and must be illegal, by our existing rules as the \n        // ref-safe-context of local is now an input into method arguments must match. \n        local.SelfAssign();\n\n        // This would be dangerous as local now has a dangerous `ref` but the above \n        // prevents us from getting here.\n        return local;\n    }\n}\n```\n\nEssentially it would mean all instance method invocations on *mutable* `ref struct` locals would be illegal unless the local was further marked as `scoped`. The rules have to consider the case where fields were ref reassigned to other fields in `this`. A `readonly ref struct` doesn't have this problem because the `readonly` nature prevents ref reassignment. Still this would be a significant back compat breaking change as it would impact virtually every existing mutable `ref struct`. \n\nA `readonly ref struct` though is still problematic once we expand to having `ref` fields to `ref struct`. It allows for the same basic problem by just moving the capture into the value of the `ref` field: \n\n```c#\nreadonly ref struct ReadOnlySneaky\n{\n    readonly int Field;\n    readonly ref ReadOnlySpan<int> Span;\n\n    public void SelfAssign()\n    {\n        // Instance method captures a ref to itself\n        Span = new ReadOnlySpan<int>(ref Field, 1);\n    }\n}\n```\n\nSome thought was given to the idea of having `this` have different defaults based on the type of `struct` or member. For example:\n\n - `this` as `ref`: `struct`, `readonly ref struct` or `readonly member`\n - `this` as `scoped ref`: `ref struct` or `readonly ref struct` with `ref` field to `ref struct`\n\n This minimizes compat breaks and maximizes flexibility but at the cost of complicating the story for customers. It also doesn't fully solve the problem because future features, like safe `fixed` buffers, require that a mutable `ref struct` have `ref` returns for fields which don't work by this design alone as it would fall into the `scoped ref` category. \n\n**Decision** Keep `this` as `scoped ref`. That means the preceding sneaky examples produce compiler errors.\n\n### ref fields to ref struct\nThis feature opens up a new set of ref safe context rules because it allows for a `ref` field to refer to a `ref struct`. This generic nature of `ByReference<T>` meant that up until now the runtime could not have such a construct. As a result all of our rules are written under the assumption this is not possible. The `ref` field feature is largely not about making new rules but codifying the existing rules in our system. Allowing `ref` fields to `ref struct` requires us to codify new rules because there are several new scenarios to consider.\n\nThe first is that a `readonly ref` is now capable of storing `ref` state. For example:\n\n```c#\nreadonly ref struct Container\n{\n    readonly ref Span<int> Span;\n\n    void Store(Span<int> span)\n    {\n        Span = span;\n    }\n}\n```\n\nThis means when thinking about method arguments must match rules we must consider `readonly ref T` is potential method output when `T` potentially has a `ref` field to a `ref struct`.\n\nThe second issue is language must consider a new type of safe context: *ref-field-safe-context*. All `ref struct` which transitively contain a `ref` field have another escape scope representing the value(s) in the `ref` field(s). In the case of multiple `ref` fields they can be collectively tracked as a single value. The default value for this for parameters is *caller-context*. \n\n```c#\nref struct Nested\n{\n    ref Span<int> Span;\n}\n\nSpan<int> M(ref Nested nested) => nested.Span;\n```\n\nThis value is not related to the *safe-context* of the container; that is as the container context gets smaller it has no impact on the *ref-field-safe-context* of the `ref` field values. Further the *ref-field-safe-context* can never be smaller than the *safe-context* of the container.\n\n```c#\nref struct Nested\n{\n    ref Span<int> Span;\n}\n\nvoid M(ref Nested nested)\n{\n    scoped ref Nested refLocal = ref nested;\n\n    // the ref-field-safe-context of local is still *caller-context* which means the following\n    // is illegal\n    refLocal.Span = stackalloc int[42];\n\n    scoped Nested valLocal = nested;\n\n    // the ref-field-safe-context of local is still *caller-context* which means the following\n    // is still illegal\n    valLocal.Span = stackalloc int[42];\n}\n```\n\nThis *ref-field-safe-context* has essentially always existed. Up until now `ref` fields could only point to normal `struct` hence it was trivially collapsed to *caller-context*.  To support `ref` fields to `ref struct` our existing rules need to be updated to take into account this new *ref-safe-context*.\n\nThird the rules for ref reassignment need to be updated to ensure that we don't violate *ref-field-context* for the values. Essentially for `x.e1 = ref e2` where the type of `e1` is a `ref struct` the *ref-field-safe-context* must be equal. \n\nThese problems are very solvable. The compiler team has sketched out a few versions of these rules and they largely fall out from our existing analysis. The problem is there is no consuming code for such rules that helps prove out there correctness and usability. This makes us very hesitant to add support because of the fear we'll pick wrong defaults and back the runtime into usability corner when it does take advantage of this. This concern is particularly strong because .NET 8 likely pushes us in this direction with `allow T: ref struct` and `Span<Span<T>>`. The rules would be better written if it's done in conjunction with consumption code.\n\n**Decision** Delay allowing `ref` field to `ref struct` until .NET 8 where we have scenarios that will help drive the rules around these scenarios. This has not been implemented as of .NET 9\n\n### What will make C# 11.0?\nThe features outlined in this document don't need to be implemented in a single pass. Instead they can be implemented in phases across several language releases in the following buckets:\n\n1. `ref` fields and `scoped`\n2. `[UnscopedRef]`\n3. `ref` fields to `ref struct`\n4. Sunset restricted types\n5. fixed sized buffers\n\nWhat gets implemented in which release is merely a scoping exercise. \n\n**Decision** Only (1) and (2) made C# 11.0. The rest will be considered in future versions of C#.\n\n## Future Considerations\n\n### Advanced lifetime annotations\nThe lifetime annotations in this proposal are limited in that they allow developers to change the default escape / don't escape behavior of values. This does add powerful flexibility to our model but it does not radically change the set of relationships that can be expressed. At the core the C# model is still effectively binary: can a value be returned or not?\n\nThat allows limited lifetime relationships to be understood. For example a value that can't be returned from a method has a smaller lifetime than one that can be returned from a method. There is no way to describe the lifetime relationship between values that can be returned from a method though. Specifically there is no way to say that one value has a larger lifetime than the other once it's established both can be returned from a method. The next step in our lifetime evolution would be allowing such relationships to be described. \n\nOther methods such as Rust allow this type of relationship to be expressed and hence can implement more complex `scoped` style operations. Our language could similarly benefit if such a feature were included. At the moment there is no motivating pressure to do this but if there is in the future our `scoped` model could be expanded to include it in a fairly straight forward fashion. \n\nEvery `scoped` could be assigned a named lifetime by adding a generic style argument to the syntax. For example `scoped<'a>` is a value that has lifetime `'a`. Constraints like `where` could then be used to describe the relationships between these lifetimes.\n\n```c#\nvoid M(scoped<'a> ref MyStruct s, scoped<'b> Span<int> span)\n  where 'b >= 'a\n{\n    s.Span = span;\n}\n```\n\nThis method defines two lifetimes `'a` and `'b` and their relationship, specifically that `'b` is greater than `'a`. This allows for the callsite to have more granular rules for how values can be safely passed into methods vs. the more coarse grained rules present today.\n\n## Related Information\n\n### Issues\nThe following issues are all related to this proposal:\n\n- https://github.com/dotnet/csharplang/issues/1130\n- https://github.com/dotnet/csharplang/issues/1147\n- https://github.com/dotnet/csharplang/issues/992\n- https://github.com/dotnet/csharplang/issues/1314\n- https://github.com/dotnet/csharplang/issues/2208\n- https://github.com/dotnet/runtime/issues/32060\n- https://github.com/dotnet/runtime/issues/61135\n- https://github.com/dotnet/csharplang/discussions/78\n\n### Proposals\nThe following proposals are related to this proposal:\n\n- https://github.com/dotnet/csharplang/blob/725763343ad44a9251b03814e6897d87fe553769/proposals/fixed-sized-buffers.md\n\n### Existing samples\n\n[Utf8JsonReader](https://github.com/dotnet/runtime/blob/f1a7cb3fdd7ffc4ce7d996b7ac6867ffe2c953b9/src/libraries/System.Text.Json/src/System/Text/Json/Reader/Utf8JsonReader.cs#L523-L528)\n\nThis particular snippet requires unsafe because it runs into issues with passing around a `Span<T>` which can be stack allocated to an instance method on a `ref struct`. Even though this parameter is not captured the language must assume it is and hence needlessly causes friction here.\n\n[Utf8JsonWriter](https://github.com/dotnet/runtime/blob/f1a7cb3fdd7ffc4ce7d996b7ac6867ffe2c953b9/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.String.cs#L122-L127)\n\nThis snippet wants to mutate a parameter by escaping elements of the data. The escaped data can be stack allocated for efficiency. Even though the parameter is not escaped the compiler assigns it a *safe-context* of outside the enclosing method because it is a parameter. This means in order to use stack allocation the implementation must use `unsafe` in order to assign back to the parameter after escaping the data.\n\n### Fun Samples\n\n#### ReadOnlySpan\\<T>\n\n```c#\npublic readonly ref struct ReadOnlySpan<T>\n{\n    readonly ref readonly T _value;\n    readonly int _length;\n\n    public ReadOnlySpan(in T value)\n    {\n        _value = ref value;\n        _length = 1;\n    }\n}\n```\n\n#### Frugal list\n\n```c#\nstruct FrugalList<T>\n{\n    private T _item0;\n    private T _item1;\n    private T _item2;\n\n    public int Count = 3;\n\n    public FrugalList(){}\n\n    public ref T this[int index]\n    {\n        [UnscopedRef] get\n        {\n            switch (index)\n            {\n                case 0: return ref _item0;\n                case 1: return ref _item1;\n                case 2: return ref _item2;\n                default: throw null;\n            }\n        }\n    }\n}\n```\n\n### Examples and Notes \nBelow are a set of examples demonstrating how and why the rules work the way they do. Included are several examples showing dangerous behaviors and how the rules prevent them from happening. It's important to keep these in mind when making adjustments to the proposal.\n\n#### Ref reassignment and call sites\n\nDemonstrating how [ref reassignment](#rules-ref-reassignment) and [method invocation](#rules-method-invocation) work together.\n\n```c#\nref struct RS\n{\n    ref int _refField;\n\n    public ref int Prop => ref _refField;\n\n    public RS(int[] array)\n    {\n        _refField = ref array[0];\n    }\n\n    public RS(ref int i)\n    {\n        _refField = ref i;\n    }\n\n    public RS CreateRS() => ...;\n\n    public ref int M1(RS rs)\n    {\n        // The call site arguments for Prop contribute here:\n        //   - `rs` contributes no ref-safe-context as the corresponding parameter, \n        //      which is `this`, is `scoped ref`\n        //   - `rs` contribute safe-context of *caller-context*\n        // \n        // This is an lvalue invocation and the arguments contribute only safe-context \n        // values of *caller-context*. That means `local1` has ref-safe-context of \n        // *caller-context*\n        ref int local1 = ref rs.Prop;\n\n        // Okay: this is legal because `local` has ref-safe-context of *caller-context*\n        return ref local1;\n\n        // The arguments contribute here:\n        //   - `this` contributes no ref-safe-context as the corresponding parameter\n        //     is `scoped ref`\n        //   - `this` contributes safe-context of *caller-context*\n        //\n        // This is an rvalue invocation and following those rules the safe-context of \n        // `local2` will be *caller-context*\n        RS local2 = CreateRS();\n\n        // Okay: this follows the same analysis as `ref rs.Prop` above\n        return ref local2.Prop;\n\n        // The arguments contribute here:\n        //   - `local3` contributes ref-safe-context of *function-member*\n        //   - `local3` contributes safe-context of *caller-context*\n        // \n        // This is an rvalue invocation which returns a `ref struct` and following those \n        // rules the safe-context of `local4` will be *function-member*\n        int local3 = 42;\n        var local4 = new RS(ref local3);\n\n        // Error: \n        // The arguments contribute here:\n        //   - `local4` contributes no ref-safe-context as the corresponding parameter\n        //     is `scoped ref`\n        //   - `local4` contributes safe-context of *function-member*\n        // \n        // This is an lvalue invocation and following those rules the ref-safe-context \n        // of the return is *function-member*\n        return ref local4.Prop;\n    }\n}\n```\n\n#### Ref reassignment and unsafe escapes\n<a name=\"examples-ref-reassignment-safety\"></a>\n\nThe reason for the following line in the [ref reassignment rules](#rules-ref-reassignment) may not be obvious at first glance:\n\n> `e1` must have the same *safe-context* as `e2`\n\nThis is because the lifetime of the values pointed to by `ref` locations are invariant. The indirection prevents us from allowing any kind of variance here, even to narrower lifetimes. If narrowing is allowed then it opens up the following unsafe code:\n\n```csharp\nvoid Example(ref Span<int> p)\n{\n    Span<int> local = stackalloc int[42];\n    ref Span<int> refLocal = ref local;\n\n    // Error:\n    // The safe-context of refLocal is narrower than p. For a non-ref reassignment \n    // this would be allowed as its safe to assign wider lifetimes to narrower ones.\n    // In the case of ref reassignment though this rule prevents it as the \n    // safe-context values are different.\n    refLocal = ref p;\n\n    // If it were allowed this would be legal as the safe-context of refLocal\n    // is *caller-context* and that is satisfied by stackalloc. At the same time\n    // it would be assigning through p and escaping the stackalloc to the calling\n    // method\n    // \n    // This is equivalent of saying p = stackalloc int[13]!!! \n    refLocal = stackalloc int[13];\n}\n```\n\nFor a `ref` to non `ref struct` this rule is trivially satisfied as the values all have the same *safe-context*. This rule really only comes into play when the value is a `ref struct`. \n\nThis behavior of `ref` will also be important in a future where we allow `ref` fields to `ref struct`. \n\n#### scoped locals\n<a name=\"examples-scoped-locals\"></a>\n\nThe use of `scoped` on locals will be particularly helpful to code patterns which conditionally assign values with different *safe-context* to locals. It means code no longer needs to rely on initialization tricks like `= stackalloc byte[0]` to define a local *safe-context* but now can simply use `scoped`. \n\n```c#\n// Old way \n// Span<byte> span = stackalloc byte[0];\n// New way \nscoped Span<byte> span;\nint len = ...;\nif (len < MaxStackLen)\n{\n    span = stackalloc byte[len];\n}\nelse\n{\n    span = new byte[len];\n}\n```\n\nThis pattern comes up frequently in low level code. When the `ref struct` involved is `Span<T>` the above trick can be used. It is not applicable to other `ref struct` types though and can result in low level code needing to resort to `unsafe` to work around the inability to properly specify the lifetime. \n\n#### scoped parameter values\n<a name=\"examples-method-arguments-must-match\"></a>\n\nOne source of repeated friction in low level code is the default escape for parameters is permissive. They are *safe-context* to the *caller-context*. This is a sensible default because it lines up with the coding patterns of .NET as a whole. In low level code though there is a larger use of  `ref struct` and this default can cause friction with other parts of the ref safe context rules.\n\nThe main friction point occurs because of the [method arguments must match](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-7.2/span-safety.md#method-arguments-must-match) rule. This rule most commonly comes into play with instance methods on `ref struct` where at least one parameter is also a `ref struct`. This is a common pattern in low level code where `ref struct` types commonly leverage `Span<T>` parameters in their methods. For example it will occur on any writer style `ref struct` that uses `Span<T>` to pass around buffers.\n\nThis rule exists to prevent scenarios like the following:\n\n```c#\nref struct RS\n{\n    Span<int> _field;\n    void Set(Span<int> p)\n    {\n        _field = p;\n    }\n\n    static void DangerousCode(ref RS p)\n    {\n        Span<int> span = stackalloc int[] { 42 };\n\n        // Error: if allowed this would let the method return a reference to \n        // the stack\n        p.Set(span);\n    }\n}\n```\n\nEssentially this rule exists because the language must assume that all inputs to a method escape to their maximum allowed *safe-context*. When there are `ref` or `out` parameters, including the receivers, it's possible for the inputs to escape as fields of those `ref` values (as happens in `RS.Set` above).\n\nIn practice though there are many such methods which pass `ref struct` as parameters that never intend to capture them in output. It is just a value that is used within the current method. For example:\n\n```c#\nref struct JsonReader\n{\n    Span<char> _buffer;\n    int _position;\n\n    internal bool TextEquals(ReadOnlySpan<char> text)\n    {\n        var current = _buffer.Slice(_position, text.Length);\n        return current == text;\n    }\n}\n\nclass C\n{\n    static void M(ref JsonReader reader)\n    {\n        Span<char> span = stackalloc char[4];\n        span[0] = 'd';\n        span[1] = 'o';\n        span[2] = 'g';\n\n        // Error: The safe-context of `span` is function-member \n        // while `reader` is outside function-member hence this fails\n        // by the above rule.\n        if (reader.TextEquals(span))\n        {\n            ...\n        }\n    }\n}\n```\n\nIn order to work around this low level code will resort to `unsafe` tricks to lie to the compiler about the lifetime of their `ref struct`. This significantly reduces the value proposition of `ref struct` as they are meant to be a means to avoid `unsafe` while continuing to write high performance code.\n\nThis is where `scoped` is an effective tool on `ref struct` parameters because it removes them from consideration as being returned from the method according to the updated [method arguments must match rule](#rules-method-arguments-must-match). A `ref struct` parameter which is consumed, but never returned, can be labeled as `scoped` to make call sites more flexible. \n\n```c#\nref struct JsonReader\n{\n    Span<char> _buffer;\n    int _position;\n\n    internal bool TextEquals(scoped ReadOnlySpan<char> text)\n    {\n        var current = _buffer.Slice(_position, text.Length);\n        return current == text;\n    }\n}\n\nclass C\n{\n    static void M(ref JsonReader reader)\n    {\n        Span<char> span = stackalloc char[4];\n        span[0] = 'd';\n        span[1] = 'o';\n        span[2] = 'g';\n\n        // Okay: the compiler never considers `span` as capturable here hence it doesn't\n        // contribute to the method arguments must match rule\n        if (reader.TextEquals(span))\n        {\n            ...\n        }\n    }\n}\n```\n\n#### Preventing tricky ref assignment from readonly mutation\n<a name=\"tricky-ref-assignment\"></a>\nWhen a `ref` is taken to a `readonly` field in a constructor or `init` member the type is `ref` not `ref readonly`. This is a long standing behavior that allows for code like the following:\n\n```c#\nstruct S\n{\n    readonly int i; \n\n    public S(string s)\n    {\n        M(ref i);\n    }\n\n    static void M(ref int i) { }\n}\n```\n\nThat does pose a potential problem though if such a `ref` were able to be stored into a `ref` field on the same type. It would allow for direct mutation of a `readonly struct` from an instance member:\n\n```c#\nreadonly ref struct S\n{ \n    readonly int i; \n    readonly ref int r; \n    public S()\n    {\n        i = 0;\n        // Error: `i` has a narrower scope than `r`\n        r = ref i;\n    }\n\n    public void Oops()\n    {\n        r++;\n    }\n}\n```\n\nThe proposal prevents this though because it violates the ref safe context rules. Consider the following:\n\n- The *ref-safe-context* of `this` is *function-member* and *safe-context* is *caller-context*. These are both standard for `this` in a `struct` member.\n- The *ref-safe-context* of `i` is *function-member*. This falls out from the [field lifetimes rules](#rules-field-lifetimes). Specifically rule 4.\n\nAt that point the line `r = ref i` is illegal by [ref reassignment rules](#rules-ref-reassignment). \n\nThese rules were not intended to prevent this behavior but do so as a side effect. It's important to keep this in mind for any future rule update to evaluate the impact to scenarios like this.\n\n#### Silly cyclic assignment\n<a name=\"cyclic-assignment\"></a>\nOne aspect this design struggled with is how freely a `ref` can be returned from a method. Allowing all `ref` to be returned as freely as normal values is likely what most developers intuitively expect. However it allows for pathological scenarios that the compiler must consider when calculating ref safety. Consider the following: \n\n```c#\nref struct S\n{\n    int field;\n    ref int refField;\n\n    static void SelfAssign(ref S s)\n    {\n        // Error: s.field can only escape the current method through a return statement\n        s.refField = ref s.field;\n    }\n}\n```\n\nThis is not a code pattern that we expect any developers to use. Yet when a `ref` can be returned with the same lifetime as a value it is legal under the rules. The compiler must consider all legal cases when evaluating a method call and this leads to such APIs being effectively unusable. \n\n```c#\nvoid M(ref S s)\n{\n    ...\n}\n\nvoid Usage()\n{\n    // safe-context to caller-context\n    S local = default; \n\n    // Error: compiler is forced to assume the worst and concludes a self assignment\n    // is possible here and must issue an error.\n    M(ref local);\n}\n```\n\nTo make these APIs usable the compiler ensures that the `ref` lifetime for a `ref` parameter is smaller than lifetime of any references in the associated parameter value. This is the rationale for having *ref-safe-context* for `ref` to `ref struct` be *return-only* and `out` be *caller-context*. That prevents cyclic assignment because of the difference in lifetimes.\n\nNote that `[UnscopedRef]` [promotes](#rules-unscoped) the *ref-safe-context* of any `ref` to `ref struct` values to *caller-context*\nand hence it allows for cyclic assignment and forces a viral use of `[UnscopedRef]` up the call chain:\n\n```c#\nS F()\n{\n    S local = new();\n    // Error: self assignment possible inside `S.M`.\n    S.M(ref local);\n    return local;\n}\n\nref struct S\n{\n    int field;\n    ref int refField;\n\n    public static void M([UnscopedRef] ref S s)\n    {\n        // Allowed: s has both safe-context and ref-safe-context of caller-context\n        s.refField = ref s.field;\n    }\n}\n```\n\nSimilarly `[UnscopedRef] out` allows a cyclic assignment because the parameter has both *safe-context* and *ref-safe-context* of *return-only*.\n\nPromoting `[UnscopedRef] ref` to *caller-context* is useful when the type is *not* a `ref struct`\n(note that we want to keep the rules simple so they don't distinguish between refs to ref vs non-ref structs):\n\n```c#\nint x = 1;\nF(ref x).RefField = 2;\nConsole.WriteLine(x); // prints 2\n\nstatic S F([UnscopedRef] ref int x)\n{\n    S local = new();\n    local.M(ref x);\n    return local;\n}\n\nref struct S\n{\n    public ref int RefField;\n\n    public void M([UnscopedRef] ref int data)\n    {\n        RefField = ref data;\n    }\n}\n```\n\nIn terms of advanced annotations the `[UnscopedRef]` design creates the following:\n\n```\nref struct S { }\n\n// C# code\nS Create1(ref S p)\nS Create2([UnscopedRef] ref S p)\n\n// Annotation equivalent\nscoped<'b> S Create1(scoped<'a> ref scoped<'b> S)\nscoped<'a> S Create2(scoped<'a> ref scoped<'b> S)\n  where 'b >= 'a\n```\n\n#### readonly cannot be deep through ref fields\n<a name=\"reason-readonly-shallow\"></a>\n\nConsider the below code sample:\n\n```c#\nref struct S\n{\n    ref int Field;\n\n    readonly void Method()\n    {\n        // Legal or illegal?\n        Field = 42;\n    }\n}\n```\n\nWhen designing the rules for `ref` fields on `readonly` instances in a vacuum the rules can be validly designed such that the above is legal or illegal. Essentially `readonly` can validly be deep through a `ref` field or it can apply only to the `ref`. Applying only to the `ref` prevents ref reassignment but allows normal assignment which changes the referred to value.\n\nThis design does not exist in a vacuum though, it is designing rules for types that already effectively have `ref` fields. The most prominent of which, `Span<T>`, already has a strong dependency on `readonly` not being deep here. Its primary scenario is the ability to assign to the `ref` field through a `readonly` instance. \n\n```c#\nreadonly ref struct SpanOfOne\n{\n    readonly ref int Field;\n\n    public ref int this[int index]\n    {\n        get\n        {\n            if (index != 1)\n                throw new Exception();\n            return ref Field;\n        }\n    }\n}\n```\n\nThis means we must choose the shallow interpretation of `readonly`.\n\n#### Modeling constructors \nOne subtle design question is: How are constructors bodies modeled for ref safety? Essentially how is the following constructor analyzed? \n\n```c#\nref struct S\n{\n    ref int field;\n\n    public S(ref int f)\n    {\n        field = ref f;\n    }\n}\n```\n\nThere are roughly two approaches:\n\n1. Model as a `static` method where `this` is a local where its *safe-context* is *caller-context*\n2. Model as a `static` method where `this` is an `out` parameter. \n\nFurther a constructor must meet the following invariants:\n\n1. Ensure that `ref` parameters can be captured as `ref` fields. \n2. Ensure that `ref` to fields of `this` cannot be escaped through `ref` parameters. That would violate [tricky ref assignment](#tricky-ref-assignment). \n\nThe intent is to pick the form that satisfies our invariants without introduction of any special rules for constructors. Given that the best model for constructors is viewing `this` as an `out` parameter. The *return only* nature of the `out` allows us to satisfy all the invariants above without any special casing: \n\n```c#\npublic static void ctor(out S @this, ref int f)\n{\n    // The ref-safe-context of `ref f` is *return-only* which is also the \n    // safe-context of `this.field` hence this assignment is allowed\n    @this.field = ref f;\n}\n```\n\n#### Method arguments must match\nThe method arguments must match rule is a common source of confusion for developers. It's a rule which has a number of special cases that are hard to understand unless you are familiar with the reasoning behind the rule. For the sake of better understanding the reasons for the rule we will simplify *ref-safe-context* and *safe-context* to simply *context*. \n\nMethods can pretty liberally return state passed to them as parameters. Essentially any reachable state which is unscoped can be returned (including returning by `ref`). This can be returned directly through a `return` statement or indirectly by assigning into a `ref` value. \n\nDirect returns don't pose much problems for ref safety. The compiler simply needs to look at all the returnable inputs to a method and then it effectively restricts the return value to be the minimum *context* of the input. That return value then goes through normal processing.\n\nIndirect returns pose a significant problem because all `ref` are both an input and output to the method. These outputs already have a known *context*. The compiler can't infer new ones, it has to consider them at their current level. That means the compiler has to look at every single `ref` which is assignable in the called method, evaluate it's *context*, and then verify no returnable input to the method has a smaller *context* than that `ref`. If any such case exists then the method call must be illegal because it could violate `ref` safety. \n\nMethod arguments must match is the process by which the compiler asserts this safety check.\n\nA different way to evaluate this which is often easier for developers to consider is to do the following exercise: \n\n1. Look at the method definition identify all places where state can be indirectly returned:\n    a. Mutable `ref` parameters pointing to `ref struct`\n    b. Mutable `ref` parameters with ref assignable `ref` fields\n    c. Assignable `ref` params or `ref` fields pointing to `ref struct` (consider recursively)\n2. Look at the call site\n    a. Identify the contexts that line up with the locations identified above\n    b. Identify the contexts of all inputs to the method that are returnable (don't line up with `scoped` parameters)\n\nIf any value in 2.b is smaller than 2.a then the method call must be illegal. Let's look at a few examples to illustrate the rules:\n\n```c#\nref struct R { }\n\nclass Program\n{\n    static void F0(ref R a, scoped ref R b) => throw null;\n\n    static void F1(ref R x, scoped R y)\n    {\n        F0(ref x, ref y);\n    }\n}\n```\n\nLooking at the call to `F0` lets go through (1) and (2). The parameters with potential for indirect return are `a` and `b` as both can be directly assigned. The arguments which line up to those parameters are:\n\n- `a` which maps to `x` that has *context* of *caller-context*\n- `b` which maps to `y` that has with *context* of *function-member*\n\nThe set of returnable input to the method are\n\n- `x` with *escape-scope* of *caller-context*\n- `ref x` with *escape-scope* of *caller-context*\n- `y` with *escape-scope* of *function-member*\n\nThe value `ref y` is not returnable since it maps to a `scoped ref` hence it is not considered an input. But given that there is at least one input with a smaller *escape scope* (`y` argument) than one of the outputs (`x` argument) the method call is illegal. \n\nA different variation is the following:\n\n```c#\nref struct R { }\n\nclass Program\n{\n    static void F0(ref R a, ref int b) => throw null;\n\n    static void F1(ref R x)\n    {\n        int y = 42;\n        F0(ref x, ref y);\n    }\n}\n```\n\nAgain the parameters with potential for indirect return are `a` and `b` as both can be directly assigned. But `b` can be excluded because it does not point to a `ref struct` hence cannot be used to store `ref` state. Thus we have:\n\n- `a` which maps to `x` that has *context* of *caller-context*\n\nThe set of returnable input to the method are:\n\n- `x` with *context* of *caller-context*\n- `ref x` with *context* of *caller-context*\n- `ref y` with *context* of *function-member*\n\nGiven that there is at least one input with a smaller *escape scope* (`ref y` argument) than one of the outputs (`x` argument) the method call is illegal. \n\nThis is the logic that the method arguments must match rule is trying to encompass. It goes further as it considers both `scoped` as a way to remove inputs from consideration and `readonly` as a way to remove `ref` as an output (can't assign into a `readonly ref` so it can't be a source of output). These special cases do add complexity to the rules but it's done so for the benefit of the developer. The compiler seeks to remove all inputs and outputs it knows can't contribute to the result to give developers maximum flexibility when calling a member. Much like overload resolution it's worth the effort to make our rules more complex when it creates more flexibility for consumers.\n\n#### Examples of inferred *safe-context* of declaration expressions\n<a id=\"examples-of-inferred-safe-to-escape-of-declaration-expressions\"></a>\n\nRelated to [Infer *safe-context* of declaration expressions](#infer-safe-to-escape-of-declaration-expressions).\n    \n```cs\nref struct RS\n{\n    public RS(ref int x) { } // assumed to be able to capture 'x'\n\n    static void M0(RS input, out RS output) => output = input;\n\n    static void M1()\n    {\n        var i = 0;\n        var rs1 = new RS(ref i); // safe-context of 'rs1' is function-member\n        M0(rs1, out var rs2); // safe-context of 'rs2' is function-member\n    }\n\n    static void M2(RS rs1)\n    {\n        M0(rs1, out var rs2); // safe-context of 'rs2' is function-member\n    }\n\n    static void M3(RS rs1)\n    {\n        M0(rs1, out scoped var rs2); // 'scoped' modifier forces safe-context of 'rs2' to the current local context (function-member or narrower).\n    }\n}\n\n```\n\nNote that the local context which results from the `scoped` modifier is the narrowest which could possibly be used for the variable--to be any narrower would mean the expression refers to variables which are only declared in a narrower context than the expression.\n"
  },
  {
    "path": "proposals/csharp-11.0/new-line-in-interpolation.md",
    "content": "# Allow new-lines in all interpolations\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/1528>\n\n* [x] Proposed\n* [x] Implementation: https://github.com/dotnet/roslyn/pull/56853\n* [x] Specification: this file.\n\n## Summary\n[summary]: #summary\n\nThe language today treats non-verbatim and verbatim interpolated strings (`$\"\"` and `$@\"\"` respectively) differently.  The primary *sensible* difference for these is that a non-verbatim interpolated string works like a normal string and cannot contain newlines in its text segments, and must instead use escapes (like `\\r\\n`).  Conversely, a verbatim interpolated string can contain newlines in its text segments (like a verbatim string), and doesn't escape newlines or other character (except for `\"\"` to escape a quote itself).\n\nThis is all reasonable and will not change with this proposal.\n\nWhat is unreasonable today is that we extend the restriction on 'no newlines' in a non-verbatim interpolated string *beyond* its text segments into the *interpolations* themselves.  This means, for example, that you cannot write the following:\n\n```c#\nvar v = $\"Count is\\t: { this.Is.A.Really(long(expr))\n                            .That.I.Should(\n                                be + able)[\n                                    to.Wrap()] }.\";\n```\n\nUltimately, the 'interpolation must be on a single line itself' rule is just a restriction of the current implementation.  That restriction really isn't necessary, and can be annoying, and would be fairly trivial to remove (see work https://github.com/dotnet/roslyn/pull/54875 to show how).   In the end, all it does is force the dev to place things on a single line, or force them into a verbatim interpolated string (both of which may be unpalatable).\n\nThe interpolation expressions themselves are not text, and shouldn't be beholden to any escaping/newline rules therin.  \n\n## Specification change\n\n```diff\nsingle_regular_balanced_text_character\n-    : '<Any character except / (U+002F), @ (U+0040), \\\" (U+0022), $ (U+0024), ( (U+0028), ) (U+0029), [ (U+005B), ] (U+005D), { (U+007B), } (U+007D) and new_line_character>'\n-    | '</ (U+002F), if not directly followed by / (U+002F) or * (U+002A)>'\n+    : <Any character except @ (U+0040), \\\" (U+0022), $ (U+0024), ( (U+0028), ) (U+0029), [ (U+005B), ] (U+005D), { (U+007B), } (U+007D)>\n+    | comment\n    ;\n```\n\n## LDM Discussions\n\nhttps://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-09-20.md\n"
  },
  {
    "path": "proposals/csharp-11.0/numeric-intptr.md",
    "content": "# Numeric IntPtr\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/6065>\n\n## Summary\n[summary]: #summary\n\nThis is a revision on the initial native integers feature ([spec](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-9.0/native-integers.md)), where the `nint`/`nuint` types were distinct from the underlying types `System.IntPtr`/`System.UIntPtr`.\nIn short, we now treat `nint`/`nuint` as simple types aliasing `System.IntPtr`/`System.UIntPtr`, like we do for `int` in relation to `System.Int32`. The `System.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr` runtime feature flag triggers this new behavior.\n\n## Design\n[design]: #design\n\n### 8.3.5 Simple types\n\nC# provides a set of predefined `struct` types called the simple types. The simple types are identified through keywords, but these keywords are simply aliases for predefined `struct` types in the `System` namespace, as described in the table below.\n\n**Keyword** | **Aliased type**\n----------- | ------------------\n  `sbyte`   |   `System.SByte`\n  `byte`    |   `System.Byte`\n  `short`   |   `System.Int16`\n  `ushort`  |   `System.UInt16`\n  `int`     |   `System.Int32`\n  `uint`    |   `System.UInt32`\n  **`nint`**     |   **`System.IntPtr`**\n  **`nuint`**    |   **`System.UIntPtr`**\n  `long`    |   `System.Int64`\n  `ulong`   |   `System.UInt64`\n  `char`    |   `System.Char`\n  `float`   |   `System.Single`\n  `double`  |   `System.Double`\n  `bool`    |   `System.Boolean`\n  `decimal` |   `System.Decimal`\n\n\\[...]\n\n### 8.3.6 Integral types\n\nC# supports **eleven** integral types: `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, **`nint`, `nuint`**, `long`, `ulong`, and `char`. \\[...]\n\n## 8.8 Unmanaged types\n\nIn other words, an *unmanaged_type* is one of the following:\n- `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, **`nint`, `nuint`**, `long`, `ulong`, `char`, `float`, `double`, `decimal`, or `bool`.\n- Any *enum_type*.\n- Any user-defined *struct_type* that is not a constructed type and contains fields of *unmanaged_type*s only.\n- In unsafe code, any *pointer_type*.\n\n### 10.2.3 Implicit numeric conversions\n\nThe implicit numeric conversions are:\n\n- From `sbyte` to `short`, `int`, **`nint`**, `long`, `float`, `double`, or `decimal`.\n- From `byte` to `short`, `ushort`, `int`, `uint`, **`nint`, `nuint`**, `long`, `ulong`, `float`, `double`, or `decimal`.\n- From `short` to `int`, **`nint`**, `long`, `float`, `double`, or `decimal`.\n- From `ushort` to `int`, `uint`, **`nint`, `nuint`**, `long`, `ulong`, `float`, `double`, or `decimal`.\n- From `int` to **`nint`**, `long`, `float`, `double`, or `decimal`.\n- From `uint` to **`nuint`**, `long`, `ulong`, `float`, `double`, or `decimal`.\n- **From `nint` to `long`, `float`, `double`, or `decimal`.**\n- **From `nuint` to `ulong`, `float`, `double`, or `decimal`.**\n- From `long` to `float`, `double`, or `decimal`.\n- From `ulong` to `float`, `double`, or `decimal`.\n- From `char` to `ushort`, `int`, `uint`, **`nint`, `nuint`**, `long`, `ulong`, `float`, `double`, or `decimal`.\n- From `float` to `double`.\n\n\\[...]\n\n### 10.2.11 Implicit constant expression conversions\n\nAn implicit constant expression conversion permits the following conversions:\n\n- A *constant_expression* of type `int` can be converted to type `sbyte`, `byte`, `short`, `ushort`, `uint`, **`nint`, `nuint`**, or `ulong`, provided the value of the *constant_expression* is within the range of the destination type.\n\\[...]\n\n### 10.3.2 Explicit numeric conversions\n\nThe explicit numeric conversions are the conversions from a *numeric_type* to another *numeric_type* for which an implicit numeric conversion does not already exist:\n\n- From `sbyte` to `byte`, `ushort`, `uint`, **`nuint`**, `ulong`, or `char`.\n- From `byte` to `sbyte` or `char`.\n- From `short` to `sbyte`, `byte`, `ushort`, `uint`, **`nuint`**, `ulong`, or `char`.\n- From `ushort` to `sbyte`, `byte`, `short`, or `char`.\n- From `int` to `sbyte`, `byte`, `short`, `ushort`, `uint`, **`nuint`**, `ulong`, or `char`.\n- From `uint` to `sbyte`, `byte`, `short`, `ushort`, `int`, **`nint`**, or `char`.\n- From `long` to `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, **`nint`, `nuint`**, `ulong`, or `char`.\n- **From `nint` to `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `nuint`, `ulong`, or `char`.**\n- **From `nuint` to `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `nint`, `long`, or `char`.**\n- From `ulong` to `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, **`nint`, `nuint`**, `long`, or `char`.\n- From `char` to `sbyte`, `byte`, or `short`.\n- From `float` to `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, **`nint`, `nuint`**, `long`, `ulong`, `char`, or `decimal`.\n- From `double` to `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, **`nint`, `nuint`**, `long`, `ulong`, `char`, `float`, or `decimal`.\n- From `decimal` to `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, **`nint`, `nuint`**, `long`, `ulong`, `char`, `float`, or `double`.\n\n\\[...]\n\n### 10.3.3 Explicit enumeration conversions\n\nThe explicit enumeration conversions are:\n\n- From `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, **`nint`, `nuint`**, `long`, `ulong`, `char`, `float`, `double`, or `decimal` to any *enum_type*.\n- From any *enum_type* to `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, **`nint`, `nuint`**, `long`, `ulong`, `char`, `float`, `double`, or `decimal`.\n- From any *enum_type* to any other *enum_type*.\n\n#### 12.6.4.7 Better conversion target\n\nGiven two types `T₁` and `T₂`, `T₁` is a ***better conversion target*** than `T₂` if one of the following holds:\n\n- An implicit conversion from `T₁` to `T₂` exists and no implicit conversion from `T₂` to `T₁` exists\n- `T₁` is `Task<S₁>`, `T₂` is `Task<S₂>`, and `S₁` is a better conversion target than `S₂`\n- `T₁` is `S₁` or `S₁?` where `S₁` is a signed integral type, and `T₂` is `S₂` or `S₂?` where `S₂` is an unsigned integral type. Specifically: \\[...]\n\n### 12.8.12 Element access\n\n\\[...] The number of expressions in the *argument_list* shall be the same as the rank of the *array_type*, and each expression shall be of type `int`, `uint`, **`nint`, `nuint`**, `long`, or `ulong,` or shall be implicitly convertible to one or more of these types.\n\n#### 11.8.12.2 Array access\n\n\\[...] The number of expressions in the *argument_list* shall be the same as the rank of the *array_type*, and each expression shall be of type `int`, `uint`, **`nint`, `nuint`**, `long`, or `ulong,` or shall be implicitly convertible to one or more of these types.\n\n\\[...] The run-time processing of an array access of the form `P[A]`, where `P` is a *primary_no_array_creation_expression* of an *array_type* and `A` is an *argument_list*, consists of the following steps:\n\\[...]\n- The index expressions of the *argument_list* are evaluated in order, from left to right. Following evaluation of each index expression, an implicit conversion to one of the following types is performed: `int`, `uint`, **`nint`, `nuint`**, `long`, `ulong`. The first type in this list for which an implicit conversion exists is chosen. \\[...]\n\n### 12.8.16 Postfix increment and decrement operators\n\nUnary operator overload resolution is applied to select a specific operator implementation. Predefined `++` and `--` operators exist for the following types: `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, **`nint`, `nuint`,** `long`, `ulong`, `char`, `float`, `double`, `decimal`, and any enum type.\n\n### 12.9.2 Unary plus operator\n\nThe predefined unary plus operators are:\n\n```csharp\n...\nnint operator +(nint x);\nnuint operator +(nuint x);\n```\n\n### 12.9.3 Unary minus operator\n\nThe predefined unary minus operators are:\n\n- Integer negation:\n\n  ```csharp\n  ...\n  nint operator –(nint x);\n  ```  \n\n### 12.8.16 Postfix increment and decrement operators\n\nPredefined `++` and `--` operators exist for the following types: `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, **`nint`, `nuint`**, `long`, `ulong`, `char`, `float`, `double`, `decimal`, and any enum type.\n\n### 11.7.19 Default value expressions\n\nIn addition, a *default_value_expression* is a constant expression if the type is one of the following value types: `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, **`nint`, `nuint`**, `long`, `ulong`, `char`, `float`, `double`, `decimal`, `bool,` or any enumeration type.\n\n### 12.9.5 Bitwise complement operator\n\nThe predefined bitwise complement operators are:\n\n```csharp\n...\nnint operator ~(nint x);\nnuint operator ~(nuint x);\n```\n\n### 12.9.6 Prefix increment and decrement operators\n\nPredefined `++` and `--` operators exist for the following types: `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, **`nint`, `nuint`**, `long`, `ulong`, `char`, `float`, `double`, `decimal`, and any enum type.\n\n## 12.10 Arithmetic operators\n\n### 12.10.2 Multiplication operator\n\nThe predefined multiplication operators are listed below. The operators all compute the product of `x` and `y`.\n\n- Integer multiplication:\n\n  ```csharp\n  ...\n  nint operator *(nint x, nint y);\n  nuint operator *(nuint x, nuint y);\n  ```\n\n### 12.10.3 Division operator\n\nThe predefined division operators are listed below. The operators all compute the quotient of `x` and `y`.\n\n- Integer division:\n\n  ```csharp\n  ...\n  nint operator /(nint x, nint y);\n  nuint operator /(nuint x, nuint y);\n  ```\n\n### 12.10.4 Remainder operator\n\nThe predefined remainder operators are listed below. The operators all compute the remainder of the division between `x` and `y`.\n\n- Integer remainder:\n\n  ```csharp\n  ...\n  nint operator %(nint x, nint y);\n  nuint operator %(nuint x, nuint y);\n  ```\n\n### 12.10.5 Addition operator\n\n- Integer addition:\n\n  ```csharp\n  ...\n  nint operator +(nint x, nint y);\n  nuint operator +(nuint x, nuint y);\n  ```\n\n### 12.10.6 Subtraction operator\n\n- Integer subtraction:\n\n  ```csharp\n  ...\n  nint operator –(nint x, nint y);\n  nuint operator –(nuint x, nuint y);\n  ```\n\n## 12.11 Shift operators\n\nThe predefined shift operators are listed below.\n\n- Shift left:\n\n  ```csharp\n  ...\n  nint operator <<(nint x, int count);\n  nuint operator <<(nuint x, int count);\n  ```\n\n- Shift right:\n\n  ```csharp\n  ...\n  nint operator >>(nint x, int count);\n  nuint operator >>(nuint x, int count);\n  ```\n\n  The `>>` operator shifts `x` right by a number of bits computed as described below.\n\n  When `x` is of type `int`, **`nint`** or `long`, the low-order bits of `x` are discarded, the remaining bits are shifted right, and the high-order empty bit positions are set to zero if `x` is non-negative and set to one if `x` is negative.\n\n  When `x` is of type `uint`, **`nuint`** or `ulong`, the low-order bits of `x` are discarded, the remaining bits are shifted right, and the high-order empty bit positions are set to zero.\n\n- Unsigned shift right:\n\n  ```csharp\n  ...\n  nint operator >>>(nint x, int count);\n  nuint operator >>>(nuint x, int count);\n  ```\n\nFor the predefined operators, the number of bits to shift is computed as follows:\n\\[...]\n- When the type of `x` is `nint` or `nuint`, the shift count is given by the low-order five bits of `count` on a 32 bit platform, or the lower-order six bits of `count` on a 64 bit platform.  \n\n\n## 12.12 Relational and type-testing operators\n\n### 12.12.2 Integer comparison operators\n\nThe predefined integer comparison operators are:\n\n```csharp\n...\nbool operator ==(nint x, nint y);\nbool operator ==(nuint x, nuint y);\n\nbool operator !=(nint x, nint y);\nbool operator !=(nuint x, nuint y);\n\nbool operator <(nint x, nint y);\nbool operator <(nuint x, nuint y);\n\nbool operator >(nint x, nint y);\nbool operator >(nuint x, nuint y);\n\nbool operator <=(nint x, nint y);\nbool operator <=(nuint x, nuint y);\n\nbool operator >=(nint x, nint y);\nbool operator >=(nuint x, nuint y);\n```\n\n## 12.12 Logical operators\n\n### 12.12.2 Integer logical operators\n\nThe predefined integer logical operators are:\n\n```csharp\n...\nnint operator &(nint x, nint y);\nnuint operator &(nuint x, nuint y);\n\nnint operator |(nint x, nint y);\nnuint operator |(nuint x, nuint y);\n\nnint operator ^(nint x, nint y);\nnuint operator ^(nuint x, nuint y);\n```\n\n## 12.22 Constant expressions\n\nA constant expression may be either a value type or a reference type. If a constant expression is a value type, it must be one of the following types: `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, **`nint`, `nuint`**, `long`, `ulong`, `char`, `float`, `double`, `decimal`, `bool,` or any enumeration type.\n\n\\[...]\n\nAn implicit constant expression conversion permits a constant expression of type `int` to be converted to `sbyte`, `byte`, `short`, `ushort`, `uint`, **`nint`, `nuint`,** or `ulong`, provided the value of the constant expression is within the range of the destination type.\n\n## 17.4 Array element access\n\nArray elements are accessed using *element_access* expressions of the form `A[I₁, I₂, ..., Iₓ]`, where `A` is an expression of an array type and each `Iₑ` is an expression of type `int`, `uint`, **`nint`, `nuint`,** `long`, `ulong`, or can be implicitly converted to one or more of these types. The result of an array element access is a variable, namely the array element selected by the indices.\n\n## 23.5 Pointer conversions\n\n### 23.5.1 General\n\n\\[...]\n\nAdditionally, in an unsafe context, the set of available explicit conversions is extended to include the following explicit pointer conversions:\n\n- From any *pointer_type* to any other *pointer_type*.\n- From `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, **`nint`, `nuint`,** `long`, or `ulong` to any *pointer_type*.\n- From any *pointer_type* to `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, **`nint`, `nuint`,** `long`, or `ulong`.\n\n### 23.6.4 Pointer element access\n\n\\[...]\nIn a pointer element access of the form `P[E]`, `P` shall be an expression of a pointer type other than `void*`, and `E` shall be an expression that can be implicitly converted to `int`, `uint`, **`nint`, `nuint`,** `long`, or `ulong`.\n\n### 23.6.7 Pointer arithmetic\n\nIn an unsafe context, the `+` operator and `–` operator can be applied to values of all pointer types except `void*`. Thus, for every pointer type `T*`, the following operators are implicitly defined:\n\n```csharp\n[...]\nT* operator +(T* x, nint y);\nT* operator +(T* x, nuint y);\nT* operator +(nint x, T* y);\nT* operator +(nuint x, T* y);\nT* operator -(T* x, nint y);\nT* operator -(T* x, nuint y);\n```\n\nGiven an expression `P` of a pointer type `T*` and an expression `N` of type `int`, `uint`, **`nint`, `nuint`,** `long`, or `ulong`, the expressions `P + N` and `N + P` compute the pointer value of type `T*` that results from adding `N * sizeof(T)` to the address given by `P`. Likewise, the expression `P – N` computes the pointer value of type `T*` that results from subtracting `N * sizeof(T)` from the address given by `P`.\n\n## Various considerations\n\n### Breaking changes\n\nOne of the main impacts of this design is that `System.IntPtr` and `System.UIntPtr` gain some built-in operators (conversions, unary and binary).  \nThose include `checked` operators, which means that the following operators on those types will now throw when overflowing:\n- `IntPtr + int`\n- `IntPtr - int`\n- `IntPtr -> int`\n- `long -> IntPtr`\n- `void* -> IntPtr`\n\n### Metadata encoding\n\nThis design means that `nint` and `nuint` can simply be emitted as `System.IntPtr` and `System.UIntPtr`, without the use of `System.Runtime.CompilerServices.NativeIntegerAttribute`.   \nSimilarly, when loading metadata `NativeIntegerAttribute` can be ignored.\n\n"
  },
  {
    "path": "proposals/csharp-11.0/pattern-match-span-of-char-on-string.md",
    "content": "# Pattern match `Span<char>` on a constant string\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/8640>\n\n## Summary\n[summary]: #summary\n\nPermit pattern matching a `Span<char>` and a `ReadOnlySpan<char>` on a constant string.\n\n## Motivation\n[motivation]: #motivation\n\nFor perfomance, usage of `Span<char>` and `ReadOnlySpan<char>` is preferred over string in many scenarios. The framework has added many new APIs to allow you to use `ReadOnlySpan<char>` in place of a `string`.\n\nA common operation on strings is to use a switch to test if it is a particular value, and the compiler optimizes such a switch. However there is currently no way to do the same on a `ReadOnlySpan<char>` efficiently, other than implementing the switch and the optimization manually.\n\nIn order to encourage adoption of `ReadOnlySpan<char>` we allow pattern matching a `ReadOnlySpan<char>`, on a constant `string`, thus also allowing it to be used in a switch.\n\n```csharp\nstatic bool Is123(ReadOnlySpan<char> s)\n{\n    return s is \"123\";\n}\n\nstatic bool IsABC(Span<char> s)\n{\n    return s switch { \"ABC\" => true, _ => false };\n}\n```\n\n## Detailed design\n[design]: #detailed-design\n\nWe alter the [spec](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/patterns.md#1123-constant-pattern) for constant patterns as follows (the proposed addition is shown in bold):\n\n> Given a pattern input value `e` and a constant pattern `P` with converted value `v`,\n>\n> - if *e* has integral type or enum type, or a nullable form of one of those, and *v* has integral type, the pattern `P` *matches* the value *e* if result of the expression `e == v` is `true`; otherwise\n> - **If *e* is of type `System.Span<char>` or `System.ReadOnlySpan<char>`, and *c* is a constant string, and *c* does not have a constant value of `null`, then the pattern is considered matching if `System.MemoryExtensions.SequenceEqual<char>(e, System.MemoryExtensions.AsSpan(c))` returns `true`.**\n> - the pattern `P` *matches* the value *e* if `object.Equals(e, v)` returns `true`.\n\n### Well-known members\n`System.Span<T>` and `System.ReadOnlySpan<T>` are matched by name, must be `ref struct`s, and can be defined outside corlib.\n\n`System.MemoryExtensions` is matched by name and can be defined outside corlib.\n\nThe signature of `System.MemoryExtensions.SequenceEqual` overloads must match:\n- `public static bool SequenceEqual<T>(System.Span<T>, System.ReadOnlySpan<T>)`\n- `public static bool SequenceEqual<T>(System.ReadOnlySpan<T>, System.ReadOnlySpan<T>)`\n\nThe signature of `System.MemoryExtensions.AsSpan` must match:\n- `public static System.ReadOnlySpan<char> AsSpan(string)`\n\nMethods with optional parameters are excluded from consideration.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nNone\n\n## Alternatives\n[alternatives]: #alternatives\n\nNone\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n1. Should matching be defined independently from `MemoryExtensions.SequenceEqual()` etc.?\n\n    > ... the pattern is considered matching if `e.Length == c.Length` and `e[i] == c[i]` for all characters in `e`.\n\n    _Recommendation: Define in terms of `MemoryExtensions.SequenceEqual()` for performance. If `MemoryExtensions` is missing, report compile error._\n\n2. Should matching against `(string)null` be allowed?\n\n    If so, should `(string)null` subsume `\"\"` since `MemoryExtensions.AsSpan(null) == MemoryExtensions.AsSpan(\"\")`?\n    ```csharp\n    static bool IsEmpty(ReadOnlySpan<char> span)\n    {\n        return span switch\n        {\n            (string)null => true, // ok?\n            \"\" => true,           // error: unreachable?\n            _ => false,\n        };\n    }\n    ```\n\n    _Recommendation: Constant pattern `(string)null` should be reported as an error._\n\n3. Should the constant pattern match include a runtime type test of the expression value for `Span<char>` or `ReadOnlySpan<char>`?\n    ```csharp\n    static bool Is123<T>(Span<T> s)\n    {\n        return s is \"123\"; // test for Span<char>?\n    }\n\n    static bool IsABC<T>(Span<T> s)\n    {\n        return s is Span<char> and \"ABC\"; // ok?\n    }\n\n    static bool IsEmptyString<T>(T t) where T : ref struct\n    {\n        return t is \"\"; // test for ReadOnlySpan<char>, Span<char>, string?\n    }\n    ```\n\n    _Recommendation: No implicit runtime type test for constant pattern. (`IsABC<T>()` example is allowed because the type test is explicit.)_\n\n    **This recommendation was not implemented. All of the preceding samples produce a compiler error.**\n\n4. Should subsumption consider constant string patterns, list patterns, and `Length` property pattern?\n    ```csharp\n    static int ToNum(ReadOnlySpan<char> s)\n    {\n        return s switch\n        {\n            { Length: 0 } => 0,\n            \"\" => 1,        // error: unreachable?\n            ['A',..] => 2,\n            \"ABC\" => 3,     // error: unreachable?\n            _ => 4,\n        };\n    }\n    ```\n\n    _Recommendation: Same subsumption behavior as used when the expression value is `string`. (Does that mean no subsumption between constant strings, list patterns, and `Length`, other than treating `[..]` as matching any?)_\n\n## Design meetings\n\nhttps://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-10-07.md#readonlyspanchar-patterns\n"
  },
  {
    "path": "proposals/csharp-11.0/raw-string-literal.md",
    "content": "# Raw string literal\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/8647>\n\n## Summary\nAllow a new form of string literal that starts with a minimum of three `\"\"\"` characters (but no maximum), optionally followed by a `new_line`, the content of the string, and then ends with the same number of quotes that the literal started with.  For example:\n\n```\nvar xml = \"\"\"\n          <element attr=\"content\"/>\n          \"\"\";\n```\n\nBecause the nested contents might itself want to use `\"\"\"` then the starting/ending delimiters can be longer like so:\n\n```\nvar xml = \"\"\"\"\n          Ok to use \"\"\" here\n          \"\"\"\";\n```\n\nTo make the text easy to read and allow for indentation that developers like in code, these string literals will naturally remove the indentation specified on the last line when producing the final literal value.  For example, a literal of the form:\n\n```\nvar xml = \"\"\"\n          <element attr=\"content\">\n            <body>\n            </body>\n          </element>\n          \"\"\";\n```\n\nWill have the contents:\n\n```\n<element attr=\"content\">\n  <body>\n  </body>\n</element>\n```\n\nThis allows code to look natural, while still producing literals that are desired, and avoiding runtime costs if this required the use of specialized string manipulation routines.\n\nIf the indentation behavior is not desired, it is also trivial to disable like so:\n\n```\nvar xml = \"\"\"\n          <element attr=\"content\">\n            <body>\n            </body>\n          </element>\n\"\"\";\n```\n\nA single line form is also supported.  It starts with a minimum of three `\"\"\"` characters (but no maximum), the content of the string (which cannot contain any `new_line` characters), and then ends with the same number of quotes that the literal started with.  For example:\n\n```\nvar xml = \"\"\"<summary><element attr=\"content\"/></summary>\"\"\";\n```\n\nInterpolated raw strings are also supported.  In this case, the string specifies the number of braces needed to start an interpolation (determined by the number of dollar signs present at the start of the literal).  Any brace sequence with fewer braces than that is just treated as content.  For example:\n\n```\nvar json = $$\"\"\"\n             {\n                \"summary\": \"text\",\n                \"length\" : {{value.Length}},\n             };\n             \"\"\";\n```\n\n## Motivation\n\nC# lacks a general way to create simple string literals that can contain effectively any arbitrary text.  All C# string literal forms today need some form of escaping in case the contents use some special character (always if a delimiter is used).  This prevents easily having literals containing other languages in them (for example, an XML, HTML or JSON literal).  \n\nAll current approaches to form these literals in C# today always force the user to manually escape the contents.  Editing at that point can be highly annoying as the escaping cannot be avoided and must be dealt with whenever it arises in the contents.  This is particularly painful for regexes, especially when they contain quotes or backslashes.  Even with a verbatim (`@\"\"`) string, quotes themselves must be escaped leading to a mix of C# and regex interspersed. `{` and `}` are similarly frustrating in interpolated (`$\"\"`) strings.\n\nThe crux of the problem is that all our strings have a fixed start/end delimiter.   As long as that is the case, we will always have to have an escaping mechanism as the string contents may need to specify that end delimiter in their contents.  This is particularly problematic as that delimiter `\"` is exceedingly common in many languages.\n\nTo address this, this proposal allows for flexible start and end delimiters so that they can always be made in a way that will not conflict with the content of the string.\n\n## Goals\n\n1. Provide a mechanism that will allow *all* string values to be provided by the user without the need for *any* escape-sequences whatsoever.  Because all strings must be representable without escape-sequences, it must always be possible for the user to specify delimiters that will be guaranteed to not collide with any text contents.\n2. Support interpolations in the same fashion.  As above, because *all* strings must be representable without escapes, it must always be possible for the user to specify an `interpolation` delimiter that will be guaranteed to not collide with any text contents.  Importantly, languages that use our *interpolation* delimiter characters (`{` and `}`) should feel first-class and not painful to use.\n3. Multiline string literals should look pleasant in code and should not make indentation within the compilation unit look strange.  Importantly, literal values that themselves have no indentation should not be forced to occupy the first column of the file as that can break up the flow of code and will look unaligned with the rest of the code that surrounds it.\n    * This behavior should be easy to override while keeping literals clear and easy to read.\n4. For all strings that do not themselves contain a `new_line` or start or end with a quote (`\"`) character, it should be possible to represent the string literal itself on a single line.\n    - Optionally, with extra complexity, we could refine this to state that: For all strings that do not themselves contain a `new_line` (but can start or end with a quote `\"` character), it should be possible to represent the string literal itself on a single line.  For more details see the expanded proposal in the `Drawbacks` section.\n\n## Detailed design (non-interpolation case)\n\nWe will add a new `string_literal` production with the following form:\n\n```\nstring_literal\n    : regular_string_literal\n    | verbatim_string_literal\n    | raw_string_literal\n    ;\n\nraw_string_literal\n    : single_line_raw_string_literal\n    | multi_line_raw_string_literal\n    ;\n\nraw_string_literal_delimiter\n    : \"\"\"\n    | \"\"\"\"\n    | \"\"\"\"\"\n    | etc.\n    ;\n\nraw_content\n    : not_new_line+\n    ;\n\nsingle_line_raw_string_literal\n    : raw_string_literal_delimiter raw_content raw_string_literal_delimiter\n    ;\n\nmulti_line_raw_string_literal\n    : raw_string_literal_delimiter whitespace* new_line (raw_content | new_line)* new_line whitespace* raw_string_literal_delimiter\n    ;\n\nnot_new_line\n    : <any unicode character that is not new_line>\n    ;\n```\n\nThe ending delimiter to a `raw_string_literal` must match the starting delimiter.  So if the starting delimiter is `\"\"\"\"\"` the ending delimiter must be that as well.  \n\nThe above grammar for a `raw_string_literal` should be interpreted as:\n\n1. It starts with at least three quotes (but no upper bound on quotes).\n2. It then continues with contents on the same line as the starting quotes.  These contents on the same line can be blank, or non-blank. 'blank' is synonymous with 'entirely whitespace'.\n3. If the contents on that same line is non-blank no further content can follow. In other words the literal is required to end with the same number of quotes on that same line.\n4. If the contents on the same line is blank, then the literal can continue with a `new_line` and some number of subsequent content lines and `new_line`s.\n    - A content line is any text except a `new_line`.\n    - It then ends with a `new_line` some number (possibly zero) of `whitespace` and the same number of quotes that the literal started with.\n\n## Raw string literal value\n\nThe portions between the starting and ending `raw_string_literal_delimiter` are used to form the value of the `raw_string_literal` in the following fashion:\n\n* In the case of `single_line_raw_string_literal` the value of the literal will exactly be the contents between the starting and ending `raw_string_literal_delimiter`.\n* In the case of `multi_line_raw_string_literal` the initial `whitespace* new_line` and the final `new_line whitespace*` is not part of the value of the string.  However, the final `whitespace*` portion preceding the `raw_string_literal_delimiter` terminal is considered the 'indentation whitespace' and will affect how the other lines are interpreted.\n* To get the final value the sequence of `(raw_content | new_line)*` is walked and the following is performed:\n    * If it a `new_line` the content of the `new_line` is added to the final string value.\n    * If it is not a 'blank' `raw_content` (i.e. `not_new_line+` contains a non-`whitespace` character):\n        * the 'indentation whitespace' must be a prefix of the `raw_content`.  It is an error otherwise.\n        * the 'indentation whitespace' is stripped from the start of `raw_content` and the remainder is added to the final string value.\n    * If it is a 'blank' `raw_content` (i.e. `not_new_line+` is entirely `whitespace`):\n        * the 'indentation whitespace' must be a prefix of the `raw_content` or the `raw_content` must be a prefix of of the 'indentation whitespace'.  It is an error otherwise.\n        * as much of the 'indentation whitespace' is stripped from the start of `raw_content` and any remainder is added to the final string value.\n\n## Clarifications:\n\n1. A `single_line_raw_string_literal` is not capable of representing a string with a `new_line` value in it.  A `single_line_raw_string_literal` does not participate in the 'indentation whitespace' trimming.  Its value is always the exact characters between the starting and ending delimiters.  \n\n2. Because a `multi_line_raw_string_literal` ignores the final `new_line` of the last content line, the following represents a string with no starting `new_line` and no terminating `new_line`\n\n```\nvar v1 = \"\"\"\n         This is the entire content of the string.\n         \"\"\";\n```\n\nThis maintains symmetry with how the starting `new_line` is ignored, and it also provides a uniform way to ensure the 'indentation whitespace' can always be adjusted. To represent a string with a terminal `new_line` an extra line must be provided like so:\n\n```\nvar v1 = \"\"\"\n         This string ends with a new line.\n\n         \"\"\";\n```\n\n3. A `single_line_raw_string_literal` cannot represent a string value that starts or ends with a quote (`\"`) though an augmentation to this proposal is provided in the `Drawbacks` section that shows how that could be supported.\n\n4. A `multi_line_raw_string_literal` starts with `whitespace* new_line` following the initial `raw_string_literal_delimiter`.  This content after the delimiter is entirely ignored and is not used in any way when determining the value of the string.  This allows for a mechanism to specify a `raw_string_literal` whose content starts with a `\"` character itself.  For example:\n\n```\nvar v1 = \"\"\"\n         \"The content of this string starts with a quote\n         \"\"\";\n```\n\n5. A `raw_string_literal` can also represent content that end with a quote (`\"`).  This is supported as the terminating delimiter must be on its own line. For example:\n\n```\nvar v1 = \"\"\"\n         \"The content of this string starts and ends with a quote\"\n         \"\"\";\n```\n\n```\nvar v1 = \"\"\"\n         \"\"The content of this string starts and ends with two quotes\"\"\n         \"\"\";\n```\n\n5. The requirement that a 'blank' `raw_content` be either a prefix of the 'indentation whitespace' or the 'indentation whitespace' must be a prefix of it helps ensure confusing scenarios with mixed whitespace do not occur, especially as it would be unclear what should happen with that line.  For example, the following case is illegal:\n\n```\nvar v1 = \"\"\"\n         Start\n<tab>\n         End\n         \"\"\";\n```\n\n6. Here the 'indentation whitespace' is nine space characters, but the 'blank' `raw_content` does not start with a prefix of that.  There is no clear answer as to how that `<tab>` line should be treated at all.  Should it be ignored?  Should it be the same as `.........<tab>`?  As such, making it illegal seems the clearest for avoiding confusion.\n\n7. The following cases are legal though and represent the same string:\n\n```\nvar v1 = \"\"\"\n         Start\n<four spaces>\n         End\n         \"\"\";\n```\n\n```\nvar v1 = \"\"\"\n         Start\n<nine spaces>\n         End\n         \"\"\";\n```\n\nIn both these cases, the 'indentation whitespace' will be nine spaces.  And in both cases, we will remove as much of that prefix as possible, leading the 'blank' `raw_content` in each case to be empty (not counting every `new_line`).  This allows users to not have to see and potentially fret about whitespace on these lines when they copy/paste or edit these lines.\n\n8. In the case though of:\n\n```\nvar v1 = \"\"\"\n         Start\n<ten spaces>\n         End\n         \"\"\";\n```\n\nThe 'indentation whitespace' will still be nine spaces.  Here though, we will remove as much of the 'indentation whitespace' as possible, and the 'blank' `raw_content` will contribute a single space to the final content.  This allows for cases where the content does need whitespace on these lines that should be preserved.\n\n9. The following is technically not legal:\n\n```\nvar v1 = \"\"\"\n         \"\"\";\n```\n\nThis is because the start of the raw string must have a `new_line` (which it does) but the end must have a `new_line` as well (which it does not).  The minimal legal `raw_string_literal` is:\n\n```\nvar v1 = \"\"\"\n\n         \"\"\";\n```\n\nHowever, this string is decidedly uninteresting as it is equivalent to `\"\"`.\n\n## Indentation examples\n\nThe 'indentation whitespace' algorithm can be visualized on several inputs like so. The following examples use the vertical bar character `|` to illustrate the first column in the resultant raw string:\n\n### Example 1 - Standard case\n```\nvar xml = \"\"\"\n          <element attr=\"content\">\n            <body>\n            </body>\n          </element>\n          \"\"\";\n```\n\nis interpreted as\n\n```\nvar xml = \"\"\"\n          |<element attr=\"content\">\n          |  <body>\n          |  </body>\n          |</element>\n           \"\"\";\n```\n\n### Example 2 - End delimiter on same line as content.\n\n```\nvar xml = \"\"\"\n          <element attr=\"content\">\n            <body>\n            </body>\n          </element>\"\"\";\n```\n\nThis is illegal.  The last content line must end with a `new_line`.\n\n\n### Example 3 - End delimiter before start delimiter\n\n```\nvar xml = \"\"\"\n          <element attr=\"content\">\n            <body>\n            </body>\n          </element>\n\"\"\";\n```\n\nis interpreted as\n\n```\nvar xml = \"\"\"\n|          <element attr=\"content\">\n|            <body>\n|            </body>\n|          </element>\n\"\"\";\n```\n\n### Example 4 - End delimiter after start delimiter\n\n```\nvar xml = \"\"\"\n          <element attr=\"content\">\n            <body>\n            </body>\n          </element>\n              \"\"\";\n```\n\nThis is illegal.  The lines of content must start with the 'indentation whitespace'\n\n### Example 5 - Empty blank line\n```\nvar xml = \"\"\"\n          <element attr=\"content\">\n            <body>\n            </body>\n\n          </element>\n          \"\"\";\n```\n\nis interpreted as\n\n```\nvar xml = \"\"\"\n          |<element attr=\"content\">\n          |  <body>\n          |  </body>\n          |\n          |</element>\n           \"\"\";\n```\n\n\n### Example 6 - Blank line with less whitespace than prefix (dots represent spaces)\n```\nvar xml = \"\"\"\n          <element attr=\"content\">\n            <body>\n            </body>\n....\n          </element>\n          \"\"\";\n```\n\nis interpreted as\n\n```\nvar xml = \"\"\"\n          |<element attr=\"content\">\n          |  <body>\n          |  </body>\n          |\n          |</element>\n           \"\"\";\n```\n\n\n\n### Example 7 - Blank line with more whitespace than prefix (dots represent spaces)\n```\nvar xml = \"\"\"\n          <element attr=\"content\">\n            <body>\n            </body>\n..............\n          </element>\n          \"\"\";\n```\n\nis interpreted as\n\n```\nvar xml = \"\"\"\n          |<element attr=\"content\">\n          |  <body>\n          |  </body>\n          |....\n          |</element>\n           \"\"\";\n```\n\n## Detailed design (interpolation case)\n\nInterpolations in normal interpolated strings (e.g. `$\"...\"`) are supported today through the use of the `{` character to start an `interpolation` and the use of an `{{` escape-sequence to insert an actual open brace character.  Using this same mechanism would violate goals '1' and '2' of this proposal.  Languages that have `{` as a core character (examples being JavaScript, JSON, Regex, and even embedded C#) would now need escaping, undoing the purpose of raw string literals.\n\nTo support interpolations we introduce them in a different fashion than normal `$\"` interpolated strings.  Specifically, an `interpolated_raw_string_literal` will start with some number of `$` characters.  The count of these indicates how many `{` (and `}`) characters are needed in the content of the literal to delimit the `interpolation`.  Importantly, there continues to be no escaping mechanism for curly braces.  Rather, just as with quotes (`\"`) the literal itself can always ensure it specifies delimiters for the interpolations that are certain to not collide with any of the rest of the content of the string.  For example a JSON literal containing interpolation holes can be written like so:\n\n```c#\nvar v1 = $$\"\"\"\n         {\n            \"orders\": \n            [\n                { \"number\": {{order_number}} }\n            ]\n         }\n         \"\"\"\n```\n\nHere, the `{{...}}` matches the requisite count of two braces specified by the `$$` delimiter prefix.  In the case of a single `$` that means the interpolation is specified just as `{...}` as in normal interpolated string literals.  Importantly, this means that an interpolated literal with `N` `$` characters can have a sequence of `2*N-1` braces (of the same type in a row).  The last `N` braces will start (or end) an interpolation, and the remaining `N-1` braces will just be content.  For example:\n\n```c#\nvar v1 = $$\"\"\"X{{{1+1}}}Z\"\"\";\n```\n\nIn this case the inner two `{{` and `}}` braces belong to the interpolation, and the outer singular braces are just content.  So the above string is equivalent to the content `X{2}Z`. Having `2*N` (or more) braces is always an error.  To have longer sequences of braces as content, the number of `$` characters must be increased accordingly.\n\nInterpolated raw string literals are defined as:\n\n```\ninterpolated_raw_string_literal\n    : single_line_interpolated_raw_string_literal\n    | multi_line_interpolated_raw_string_literal\n    ;\n\ninterpolated_raw_string_start\n    : $\n    | $$\n    | $$$\n    | etc.\n    ;\n\ninterpolated_raw_string_literal_delimiter\n    : interpolated_raw_string_start raw_string_literal_delimiter\n    ;\n\nsingle_line_interpolated_raw_string_literal\n    : interpolated_raw_string_literal_delimiter interpolated_raw_content raw_string_literal_delimiter\n    ;\n\nmulti_line_interpolated_raw_string_literal\n    : interpolated_raw_string_literal_delimiter whitespace* new_line (interpolated_raw_content | new_line)* new_line whitespace* raw_string_literal_delimiter\n    ;\n\ninterpolated_raw_content\n    : (not_new_line | raw_interpolation)+\n    ;\n\nraw_interpolation\n    : raw_interpolation_start interpolation raw_interpolation_end\n    ;\n\nraw_interpolation_start\n    : {\n    | {{\n    | {{{\n    | etc.\n    ;\n\nraw_interpolation_end\n    : }\n    | }}\n    | }}}\n    | etc.\n    ;\n\n```\n\nThe above is similar to the definition of `raw_string_literal` but with some important differences.  A `interpolated_raw_string_literal` should be interpreted as:\n\n1. It starts with at least one dollar sign (but no upper bound) and then three quotes (also with no upper bound).\n2. It then continues with content on the same line as the starting quotes.  This content on the same line can be blank, or non-blank. 'blank' is synonymous with 'entirely whitespace'.\n3. If the content on that same line is non-blank no further content can follow.  In other words the literal is required to end with the same number of quotes on that same line.\n4. If the contents on the same line is blank, then the literal can continue with a `new_line` and some number of subsequent content lines and `new_line`s.\n    - A content line is any text except a `new_line`.\n    - A content line can contain multiple `raw_interpolation` occurrences at any position.  The `raw_interpolation` must start with an equal number of open braces (`{`) as the number of dollar signs at the start of the literal.\n    - If 'indentation whitespace' is not-empty, a `raw_interpolation` cannot immediately follow a `new_line`.\n    - The `raw_interpolation` will following the normal rules specified at [§12.8.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1283-interpolated-string-expressions).  Any `raw_interpolation` must end with the same number of close braces (`}`) as dollar signs and open braces.\n    - Any `interpolation` can itself contain new-lines within in the same manner as an `interpolation` in a normal `verbatim_string_literal` (`@\"\"`).\n    - It then ends with a `new_line` some number (possibly zero) of `whitespace` and the same number of quotes that the literal started with.\n\nComputation of the interpolated string value follows the same rules as a normal `raw_string_literal` except updated to handle lines containing `raw_interpolation`s.  Building the string value happens in the same fashion, just with the interpolation holes replaced with whatever values those expressions produce at runtime.  If the `interpolated_raw_string_literal` is converted to a `FormattableString` then the values of the interpolations are passed in their respective order to the `arguments` array to `FormattableString.Create`.  The rest of the content of the `interpolated_raw_string_literal` *after* the 'indentation whitespace' has been stripped from all lines will be used to generate the `format` string passed to `FormattableString.Create`, except with appropriately numbered `{N}` contents in each location where a `raw_interpolation` occurred (or `{N,constant}` in the case if its `interpolation` is of the form `expression ',' constant_expression`).\n\nThere is an ambiguity in the above specification.  Specifically when a section of `{` in text and `{` of an interpolation abut. For example:\n\n```\nvar v1 = $$\"\"\"\n         {{{order_number}}}\n         \"\"\"\n```\n\nThis could be interpreted as: `{{ {order_number } }}` or `{ {{order_number}} }`.  However, as the former is illegal (no C# expression could start with `{`) it would be pointless to interpret that way.  So we interpret in the latter fashion, where the innermost `{` and `}` braces form the interpolation, and any outermost ones form the text.  In the future this might be an issue if the language ever supports any expressions that are surrounded by braces.  However, in that case, the recommendation would be to write such a case like so: `{{({some_new_expression_form})}}`.  Here, parentheses would help designate the expression portion from the rest of the literal/interpolation.  This has precedence already with how ternary conditional expressions need to be wrapped to not conflict with the formatting/alignment specifier of an interpolation (e.g. `{(x ? y : z)}`).\n\n## Drawbacks\n\nRaw string literals add more complexity to the language.  We already have many string literal forms already for numerous purposes.  `\"\"` strings, `@\"\"` strings, and `$\"\"` strings already have a lot of power and flexibility.  But they all lack a way to provide raw contents that never need escaping.\n\nThe above rules do not support the case of [4.a](#goals):\n\n4. ...\n    - Optionally, with extra complexity, we could refine this to state that: For all strings that do not themselves contain a `new_line` (but can start or end with a quote `\"` character), it should be possible to represent the string literal itself on a single line.\n\nThat's because we have no means to know that a starting or ending quote (`\"`) should belong to the contents and not the delimiter itself.  If this is an important scenario we want to support though, we can add a parallel `'''` construct to go along with the `\"\"\"` form.  With that parallel construct, a single line string that start and ends with `\"` can be written easily as `'''\"This string starts and ends with quotes\"'''` along with the parallel construct `\"\"\"'This string starts and ends with apostrophes'\"\"\"`.  This may also be desirable to support to help visually separate out quote characters, which may help when embedding languages that primarily use one quote character much more than then other.\n\n## Alternatives\n\nhttps://github.com/dotnet/csharplang/discussions/89 covers many options here.  Alternatives are numerous, but i feel stray too far into complexity and poor ergonomics.  This approach opts for simplicity where you just keep increasing the start/end quote length until there is no concern about a conflict with the string contents.  It also allows the code you write to look well indented, while still producing a dedented literal that is what most code wants.\n\nOne of the most interesting potential variations though is the use of `` ` `` (or ` ``` `) fences for these raw string literals.  This would have several benefits:\n1. It would avoid all the issues with strings starting er ending with quotes.\n2. It would look familiar to markdown.  Though that in itself is potentially not a good thing as users might expect markdown interpretation.\n3. A raw string literal would only have to start and end with a single character in most cases, and would only need multiple in the much rarer case of contents that contain back-ticks themselves.\n4. It would feel natural to extend this in the future with ` ```xml `, again akin to markdown.  Though, of course, that is also true of the `\"\"\"` form.\n\nOverall though, the net benefit here seems small.  In keeping with C# history, i think `\"` should continue to be the `string literal` delimiter, just as it is for `@\"\"` and `$\"\"`.\n\n## Design meetings\n\n### ~~Open issues to discuss~~  Resolved issues:\n\n- [x] should we have a single line form?  We technically could do without it.  But it would mean simple strings not containing a newline would always take at least three lines.  I think we should  It's very heavyweight to force single line constructs to be three lines just to avoid escaping.\n\nDesign decision: Yes, we will have a single line form.\n\n- [x] should we require that multiline *must* start with a newline?  I think we should.  It also gives us the ability to support things like `\"\"\"xml` in the future.\n\nDesign decision: Yes, we will require that multiline must start with a newline\n\n- [x] should the automatic dedenting be done at all?  I think we should.  It makes code look so much more pleasant.\n\nDesign decision: Yes, automatic dedenting will be done.\n\n- [x] should we restrict common-whitespace from mixing whitespace types?  I don't think we should.  Indeed, there is a common indentation strategy called \"tab for indentation, space for alignment\".  It would be very natural to use this to align the end delimiter with the start delimiter in a case where the start delimiter doesn't start on a tab stop.\n\nDesign decision: We will not have any restrictions on mixing whitespace.\n\n- [x] should we use something else for the fences?  `` ` `` would match markdown syntax, and would mean we didn't need to always start these strings with three quotes.  Just one would suffice for the common case.\n\nDesign decision: We will use `\"\"\"`\n\n- [x] should we have a requirement that the delimiter have more quotes than the longest sequence of quotes in the string value?  Technically it's not required.  for example:\n\n```\nvar v = \"\"\"\n        contents\"\"\"\"\"\n        \"\"\"\n```\n\nThis is a string with `\"\"\"` as the delimiter.  Several community members have stated this is confusing and we should require in a case like this that the delimiter always have more characters.  That would then be:\n\n```\nvar v = \"\"\"\"\"\"\n        contents\"\"\"\"\"\n        \"\"\"\"\"\"\n```\n\nDesign decision: Yes, the delimiter must be longer than any sequence of quotes in the string itself.\n"
  },
  {
    "path": "proposals/csharp-11.0/relaxing_shift_operator_requirements.md",
    "content": "# Relaxing shift operator requirements\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/4666>\n\n## Summary\n[summary]: #summary\n\nThe shift operator requirements will be relaxed so that the right-hand side operand is no longer restricted to only be `int`.\n\n## Motivation\n[motivation]: #motivation\n\nWhen working with types other than `int`, it is not uncommon that you shift using the result of another computation,\nsuch as shifting based on the `leading zero count`. The natural type of something like a `leading zero count` is the\nsame as the input type (`TSelf`) and so in many cases, this requires you to convert that result to `int` before shifting,\neven if that result is already within range.\n\nWithin the context of the generic math interfaces the libraries are planning to expose, this is potentially problematic\nas the type is not well known and so the conversion to `int` may not be possible or even well-defined.\n\n## Detailed design\n[design]: #detailed-design\n\n### Shift operators\n\n[§12.11](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1211-shift-operators) should be reworded as follows:\n```diff\n- When declaring an overloaded shift operator, the type of the first operand must always be the class or struct containing the operator declaration,\nand the type of the second operand must always be int.\n+ When declaring an overloaded shift operator, the type of the first operand must always be the class or struct containing the operator declaration.\n```\n\nThat is, the restriction that the first operand be the class or struct containing the operator declaration remains.\nWhile the restriction that the second operand must be `int` is removed.\n\n### Binary operators\n\n[§14.10.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#15103-binary-operators) should be reworded as follows:\n```diff\n-*  A binary `<<` or `>>` operator must take two parameters, the first of which must have type `T` or `T?` and the second of which must have type `int` or `int?`, and can return any type.\n+*  A binary `<<` or `>>` operator must take two parameters, the first of which must have type `T` or `T?`, and can return any type.\n```\n\nThat is, the restriction that the first parameter be `T` or `T?` remains.\nWhile the restriction that the second operand must be `int` or `int?` is removed.\n\n### Binary operator overload resolution\n\nThe first bullet point at [§11.4.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1245-binary-operator-overload-resolution)\nshould be reworded as follows:\n\n*  The set of candidate user-defined operators provided by `X` and `Y` for the operation `operator op(x,y)` is determined. The set consists of the union of the candidate operators provided by `X` and **, unless the operator is a shift operator,** the candidate operators provided by `Y`, each determined using the rules of Candidate user-defined operators [§11.4.6](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1246-candidate-user-defined-operators). If `X` and `Y` are the same type, or if `X` and `Y` are derived from a common base type, then shared candidate operators only occur in the combined set once.\n\nThat is, for shift operators, candidate operators are only those provided by type `X`.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nUsers will be able to define operators that do not follow the recommended guidelines, such as implementing `cout << \"string\"` in C#.\n\n## Alternatives\n[alternatives]: #alternatives\n\nThe generic math interfaces being exposed by the libraries could expose explicitly named methods instead.\nThis may make code more difficult to read/maintain. \n\nThe generic math interfaces could require the shift take `int` and that a conversion be performed.\nThis conversion may be expensive or may be not possible depending on the type in question.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\nIs there concern around preserving the \"intent\" around why the second operand was restricted to `int`?\n\n## Design meetings\n\nhttps://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md\n"
  },
  {
    "path": "proposals/csharp-11.0/required-members.md",
    "content": "# Required Members\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/3630>\n\n## Summary\n\nThis proposal adds a way of specifying that a property or field is required to be set during object initialization, forcing the instance creator to provide an initial value for the\nmember in an object initializer at the creation site.\n\n## Motivation\n\nObject hierarchies today require a lot of boilerplate to carry data across all levels of the hierarchy. Let's look at a simple hierarchy involving a `Person` as might be defined in\nC# 8:\n\n```cs\nclass Person\n{\n    public string FirstName { get; }\n    public string MiddleName { get; }\n    public string LastName { get; }\n\n    public Person(string firstName, string lastName, string? middleName = null)\n    {\n        FirstName = firstName;\n        LastName = lastName;\n        MiddleName = middleName ?? string.Empty;\n    }\n}\n\nclass Student : Person\n{\n    public int ID { get; }\n    public Student(int id, string firstName, string lastName, string? middleName = null)\n        : base(firstName, lastName, middleName)\n    {\n        ID = id;\n    }\n}\n```\n\nThere's lots of repetition going on here:\n\n1. At the root of the hierarchy, the type of each property had to be repeated twice, and the name had to be repeated four times.\n2. At the derived level, the type of each inherited property had to be repeated once, and the name had to be repeated twice.\n\nThis is a simple hierarchy with 3 properties and 1 level of inheritance, but many real-world examples of these types of hierarchies go many levels deeper, accumulating larger and\nlarger numbers of properties to pass along as they do so. Roslyn is one such codebase, for example, in the various tree types that make our CSTs and ASTs. This nesting is tedious\nenough that we have code generators to generate the constructors and definitions of these types, and many customers take similar approaches to the problem. C# 9 introduces records,\nwhich for some scenarios can make this better:\n\n```cs\nrecord Person(string FirstName, string LastName, string MiddleName = \"\");\nrecord Student(int ID, string FirstName, string LastName, string MiddleName = \"\") : Person(FirstName, LastName, MiddleName);\n```\n\n`record`s eliminate the first source of duplication, but the second source of duplication remains unchanged: unfortunately, this is the source of duplication that grows as the\nhierarchy grows, and is the most painful part of the duplication to fix up after making a change in the hierarchy as it required chasing the hierarchy through all of its locations,\npossibly even across projects and potentially breaking consumers.\n\nAs a workaround to avoid this duplication, we have long seen consumers embracing object initializers as a way of avoiding writing constructors. Prior to C# 9, however, this had 2\nmajor downsides:\n\n1. The object hierarchy has to be fully mutable, with `set` accessors on every property.\n2. There is no way to ensure that every instantiation of an object from the graph sets every member.\n\nC# 9 again addressed the first issue here, by introducing the `init` accessor: with it, these properties can be set on object creation/initialization, but not subsequently. However,\nwe again still have the second issue: properties in C# have been optional since C# 1.0. Nullable reference types, introduced in C# 8.0, addressed part of this issue: if a constructor\ndoes not initialize a non-nullable reference-type property, then the user is warned about it. However, this doesn't solve the problem: the user here wants to not repeat large parts\nof their type in the constructor, they want to pass the _requirement_ to set properties on to their consumers. It also doesn't provide any warnings about `ID` from `Student`, as that\nis a value type. These scenarios are extremely common in database model ORMs, such as EF Core, which need to have a public parameterless constructor but then drive nullability of the\nrows based on the nullability of the properties.\n\nThis proposal seeks to address these concerns by introducing a new feature to C#: required members. Required members will be required to be initialized by consumers, rather than by\nthe type author, with various customizations to allow flexibility for multiple constructors and other scenarios.\n\n## Detailed Design\n\n`class`, `struct`, and `record` types gain the ability to declare a _required\\_member\\_list_. This list is the list of all the properties and fields of a type that are considered\n_required_, and must be initialized during the construction and initialization of an instance of the type. Types inherit these lists from their base types automatically, providing\na seamless experience that removes boilerplate and repetitive code.\n\n### `required` modifier\n\nWe add `'required'` to the list of modifiers in _field\\_modifier_ and _property\\_modifier_. The _required\\_member\\_list_ of a type is composed of all the members that have had\n`required` applied to them. Thus, the `Person` type from earlier now looks like this:\n\n```cs\npublic class Person\n{\n    // The default constructor requires that FirstName and LastName be set at construction time\n    public required string FirstName { get; init; }\n    public string MiddleName { get; init; } = \"\";\n    public required string LastName { get; init; }\n}\n```\n\nAll constructors on a type that has a _required\\_member\\_list_ automatically advertise a _contract_ that consumers of the type must initialize all of the properties in the list. It\nis an error for a constructor to advertise a contract that requires a member that is not at least as accessible as the constructor itself. For example:\n\n```cs\npublic class C\n{\n    public required int Prop { get; protected init; }\n\n    // Advertises that Prop is required. This is fine, because the constructor is just as accessible as the property initer.\n    protected C() {}\n\n    // Error: ctor C(object) is more accessible than required property Prop.init.\n    public C(object otherArg) {}\n}\n```\n\n`required` is only valid in `class`, `struct`, and `record` types. It is not valid in `interface` types. `required` cannot be combined with the following modifiers:\n\n* `fixed`\n* `ref readonly`\n* `ref`\n* `const`\n* `static`\n\n`required` is not allowed to be applied to indexers.\n\nThe compiler will issue a warning when `Obsolete` is applied to a required member of a type and:\n\n1. The type is not marked `Obsolete`, or\n2. Any constructor not attributed with `SetsRequiredMembersAttribute` is not marked `Obsolete`.\n\n### `SetsRequiredMembersAttribute`\n\nAll constructors in a type with required members, or whose base type specifies required members, must have those members set by a consumer when that constructor is called. In order to\nexempt constructors from this requirement, a constructor can be attributed with `SetsRequiredMembersAttribute`, which removes these requirements. The constructor body is not validated\nto ensure that it definitely sets the required members of the type.\n\n`SetsRequiredMembersAttribute` removes _all_ requirements from a constructor, and those requirements are not checked for validity in any way. NB: this is the escape hatch if inheriting\nfrom a type with an invalid required members list is necessary: mark the constructor of that type with `SetsRequiredMembersAttribute`, and no errors will be reported.\n\nIf a constructor `C` chains to a `base` or `this` constructor that is attributed with `SetsRequiredMembersAttribute`, `C` must also be attributed with `SetsRequiredMembersAttribute`.\n\nFor record types, we will emit `SetsRequiredMembersAttribute` on the synthesized copy constructor of a record if the record type or any of its base types have required members.\n\nNB: An earlier version of this proposal had a larger metalanguage around initialization, allowing adding and removing individual required members from a constructor, as well as validation\nthat the constructor was setting all required members. This was deemed too complex for the initial release, and removed. We can look at adding more complex contracts and modifications as\na later feature.\n\n### Enforcement\n\nFor every constructor `Ci` in type `T` with required members `R`, consumers calling `Ci` must do one of:\n\n* Set all members of `R` in an _object\\_initializer_ on the _object\\_creation\\_expression_,\n* Or set all members of `R` via the _named\\_argument\\_list_ section of an _attribute\\_target_.\n\nunless `Ci` is attributed with `SetsRequiredMembers`.\n\nIf the current context does not permit an _object\\_initializer_ or is not an _attribute\\_target_, and `Ci` is not attributed with `SetsRequiredMembers`, then it is an error to call `Ci`.\n\n### `new()` constraint\n\nA type with a parameterless constructor that advertises a _contract_ is not allowed to be substituted for a type parameter constrained to `new()`, as there is no way\nfor the generic instantiation to ensure that the requirements are satisfied.\n\n### `struct` `default`s\n\nRequired members are not enforced on instances of `struct` types created with `default` or `default(StructType)`. They are enforced for `struct` instances created with `new StructType()`,\neven when `StructType` has no parameterless constructor and the default struct constructor is used.\n\n### Accessibility\n\nIt is an error to mark a member required if the member cannot be set in any context where the containing type is visible.\n* If the member is a field, it cannot be `readonly`.\n* If the member is a property, it must have a setter or initer at least as accessible as the member's containing type.\n\nThis means the following cases are not allowed:\n\n```cs\ninterface I\n{\n    int Prop1 { get; }\n}\npublic class Base\n{\n    public virtual int Prop2 { get; set; }\n\n    protected required int _field; // Error: _field is not at least as visible as Base. Open question below about the protected constructor scenario\n\n    public required readonly int _field2; // Error: required fields cannot be readonly\n    protected Base() { }\n\n    protected class Inner\n    {\n        protected required int PropInner { get; set; } // Error: PropInner cannot be set inside Base or Derived\n    }\n}\npublic class Derived : Base, I\n{\n    required int I.Prop1 { get; } // Error: explicit interface implementions cannot be required as they cannot be set in an object initializer\n\n    public required override int Prop2 { get; set; } // Error: this property is hidden by Derived.Prop2 and cannot be set in an object initializer\n    public new int Prop2 { get; }\n\n    public required int Prop3 { get; } // Error: Required member must have a setter or initer\n\n    public required int Prop4 { get; internal set; } // Error: Required member setter must be at least as visible as the constructor of Derived\n}\n```\n\nIt is an error to hide a `required` member, as that member can no longer be set by a consumer.\n\nWhen overriding a `required` member, the `required` keyword must be included on the method signature. This is done so that if we ever want to allow\nunrequiring a property with an override in the future, we have design space to do so.\n\nOverrides are allowed to mark a member `required` where it was not `required` in the base type. A member so-marked is added to the required members\nlist of the derived type.\n\nTypes are allowed to override required virtual properties. This means that if the base virtual property has storage, and the derived type tries to\naccess the base implementation of that property, they could observe uninitialized storage. NB: This is a general C# anti-pattern, and we don't think that\nthis proposal should attempt to address it.\n\n### Effect on nullable analysis\n\nMembers that are marked `required` are not required to be initialized to a valid nullable state at the end of a constructor. All `required` members from this type and any base types are considered\nby nullable analysis to be default at the beginning of any constructor in that type, unless chaining to a `this` or `base` constructor that is attributed with `SetsRequiredMembersAttribute`.\n\nNullable analysis will warn about all `required` members from the current and base types that do not have a valid nullable state at the end of a constructor attributed with `SetsRequiredMembersAttribute`.\n\n```cs\n#nullable enable\npublic class Base\n{\n    public required string Prop1 { get; set; }\n\n    public Base() {}\n\n    [SetsRequiredMembers]\n    public Base(int unused) { Prop1 = \"\"; }\n}\npublic class Derived : Base\n{\n    public required string Prop2 { get; set; }\n\n    [SetsRequiredMembers]\n    public Derived() : base()\n    {\n    } // Warning: Prop1 and Prop2 are possibly null.\n\n    [SetsRequiredMembers]\n    public Derived(int unused) : base()\n    {\n        Prop1.ToString(); // Warning: possibly null dereference\n        Prop2.ToString(); // Warning: possibly null dereference\n    }\n\n    [SetsRequiredMembers]\n    public Derived(int unused, int unused2) : this()\n    {\n        Prop1.ToString(); // Ok\n        Prop2.ToString(); // Ok\n    }\n\n    [SetsRequiredMembers]\n    public Derived(int unused1, int unused2, int unused3) : base(unused1)\n    {\n        Prop1.ToString(); // Ok\n        Prop2.ToString(); // Warning: possibly null dereference\n    }\n}\n```\n\n### Metadata Representation\n\nThe following 2 attributes are known to the C# compiler and required for this feature to function:\n\n```cs\nnamespace System.Runtime.CompilerServices\n{\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]\n    public sealed class RequiredMemberAttribute : Attribute\n    {\n        public RequiredMemberAttribute() {}\n    }\n}\n\nnamespace System.Diagnostics.CodeAnalysis\n{\n    [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)]\n    public sealed class SetsRequiredMembersAttribute : Attribute\n    {\n        public SetsRequiredMembersAttribute() {}\n    }\n}\n```\n\nIt is an error to manually apply `RequiredMemberAttribute` to a type.\n\nAny member that is marked `required` has a `RequiredMemberAttribute` applied to it. In addition, any type that defines such members is marked with\n`RequiredMemberAttribute`, as a marker to indicate that there are required members in this type. Note that if type `B` derives from `A`, and `A`\ndefines `required` members but `B` does not add any new or override any existing `required` members, `B` will not be marked with a `RequiredMemberAttribute`.\nTo fully determine whether there are any required members in `B`, checking the full inheritance hierarchy is necessary.\n\nAny constructor in a type with `required` members that does not have `SetsRequiredMembersAttribute` applied to it is marked with two attributes:\n1. `System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute` with the feature name `\"RequiredMembers\"`.\n2. `System.ObsoleteAttribute` with the string `\"Types with required members are not supported in this version of your compiler\"`, and the attribute is\nmarked as an error, to prevent any older compilers from using these constructors.\n\nWe don't use a `modreq` here because it is a goal to maintain binary compat: if the last `required` property was removed from a type, the compiler would no\nlonger synthesize this `modreq`, which is a binary-breaking change and all consumers would need to be recompiled. A compiler that understands `required`\nmembers will ignore this obsolete attribute. Note that members can come from base types as well: even if there are no new `required` members in the current\ntype, if any base type has `required` members, this `Obsolete` attribute will be generated. If the constructor already has an `Obsolete` attribute, no\nadditional `Obsolete` attribute will be generated.\n\nWe use both `ObsoleteAttribute` and `CompilerFeatureRequiredAttribute` because the latter is new this release, and older compilers don't understand it. In the\nfuture, we may be able to drop the `ObsoleteAttribute` and/or not use it to protect new features, but for now we need both for full protection.\n\nTo build the full list of `required` members `R` for a given type `T`, including all base types, the following algorithm is run:\n\n1. For every `Tb`, starting with `T` and working through the base type chain until `object` is reached.\n2. If `Tb` is marked with `RequiredMemberAttribute`, then all members of `Tb` marked with `RequiredMemberAttribute` are gathered into `Rb`\n    1. For every `Ri` in `Rb`, if `Ri` is overridden by any member of `R`, it is skipped.\n    2. Otherwise, if any `Ri` is hidden by a member of `R`, then the lookup of required members fails and no further steps are taken. Calling any\n    constructor of `T` not attributed with `SetsRequiredMembers` issues an error.\n    3. Otherwise, `Ri` is added to `R`.\n\n## Open Questions\n\n### Nested member initializers\n\nWhat will the enforcement mechanisms for nested member initializers be? Will they be disallowed entirely?\n\n```cs\nclass Range\n{\n    public required Location Start { get; init; }\n    public required Location End { get; init; }\n}\n\nclass Location\n{\n    public required int Column { get; init; }\n    public required int Line { get; init; }\n}\n\n_ = new Range { Start = { Column = 0, Line = 0 }, End = { Column = 1, Line = 0 } } // Would this be allowed if Location is a struct type?\n_ = new Range { Start = new Location { Column = 0, Line = 0 }, End = new Location { Column = 1, Line = 0 } } // Or would this form be necessary instead?\n```\n\n## Discussed Questions\n\n### Level of enforcement for `init` clauses\n\nThe `init` clause feature wasn't implemented in C# 11. It remains an active proposal.\n\n<details>\n\nDo we strictly enforce that members specified in an `init` clause without an initializer must initialize all members? It seems likely that we do, otherwise we create an\neasy pit-of-failure. However, we also run the risk of reintroducing the same problems we solved with `MemberNotNull` in C# 9. If we want to strictly enforce this, we\nwill likely need a way for a helper method to indicate that it sets a member. Some possible syntaxes we've discussed for this:\n\n* Allow `init` methods. These methods are only allowed to be called from a constructor or from another `init` method, and can access `this` as if it's in the constructor\n(ie, set `readonly` and `init` fields/properties). This can be combined with `init` clauses on such methods. A `init` clause would be considered satisfied if the member\nin the clause is definitely assigned in the body of the method/constructor. Calling a method with a `init` clause that includes a member counts as assigning to that member.\nIf we do decided that this is a route we want to pursue, now or in the future, it seems likely that we should not use `init` as the keyword for the init clause on a\nconstructor, as that would be confusing.\n* Allow the `!` operator to suppress the warning/error explicitly. If initializing a member in a complicated way (such as in a shared method), the user can add a `!`\nto the init clause to indicate the compiler should not check for initialization.\n\n**Conclusion**: After discussion we like the idea of the `!` operator. It allows the user to be intentional about more complicated scenarios while also not creating a large design hole\naround init methods and annotating every method as setting members X or Y. `!` was chosen because we already use it for suppressing nullable warnings, and using it to\ntell the compiler \"I'm smarter than you\" in another place is a natural extension of the syntax form.\n\n</details>\n\n### Required interface members\n\nThis proposal does not allow interfaces to mark members as required. This protects us from having to figure out complex scenarios around `new()` and interface\nconstraints in generics right now, and is directly related to both factories and generic construction. In order to ensure that we have design space in this area, we\nforbid `required` in interfaces, and forbid types with _required\\_member\\_lists_ from being substituted for type parameters constrained to `new()`. When we want to\ntake a broader look at generic construction scenarios with factories, we can revisit this issue.\n\n### Syntax questions\n\nThe `init` clause feature wasn't implemented in C# 11. It remains an active proposal.\n\n<details>\n\n* Is `init` the right word? `init` as a postfix modifier on the constructor might interfere if we ever want to reuse it for factories and also enable `init`\nmethods with a prefix modifier. Other possibilities:\n    * `set`\n* Is `required` the right modifier for specifying that all members are initialized? Others suggested:\n    * `default`\n    * `all`\n    * With a ! to indicate complex logic\n* Should we require a separator between the `base`/`this` and the `init`?\n    * `:` separator\n    * ',' separator\n* Is `required` the right modifier? Other alternatives that have been suggested:\n    * `req`\n    * `require`\n    * `mustinit`\n    * `must`\n    * `explicit`\n\n**Conclusion**: We have removed the `init` constructor clause for now, and are proceeding with `required` as the property modifier.\n\n</details>\n\n### Init clause restrictions\n\nThe `init` clause feature wasn't implemented in C# 11. It remains an active proposal.\n\n<details>\n\nShould we allow access to `this` in the init clause? If we want the assignment in `init` to be a shorthand for assigning the member in the constructor itself, it seems\nlike we should.\n\nAdditionally, does it create a new scope, like `base()` does, or does it share the same scope as the method body? This is particularly important for things like local\nfunctions, which the init clause may want to access, or for name shadowing, if an init expression introduces a variable via `out` parameter.\n\n**Conclusion**: `init` clause has been removed.\n\n</details>\n\n### Accessibility requirements and `init`\n\nThe `init` clause feature wasn't implemented in C# 11. It remains an active proposal.\n\n<details>\n\nIn versions of this proposal with the `init` clause, we talked about being able to have the following scenario:\n\n```cs\npublic class Base\n{\n    protected required int _field;\n\n    protected Base() {} // Contract required that _field is set\n}\npublic class Derived : Base\n{\n    public Derived() : init(_field = 1) // Contract is fulfilled and _field is removed from the required members list\n    {\n    }\n}\n```\n\nHowever, we have removed the `init` clause from the proposal at this point, so we need to decide whether to allow this scenario in a limited fashion. The options we\nhave are:\n\n1. Disallow the scenario. This is the most conservative approach, and the rules in the [Accessibility](#accessibility) are currently written with this assumption\nin mind. The rule is that any member that is required must be at least as visible as its containing type.\n2. Require that all constructors are either:\n    1. No more visible than the least-visible required member.\n    2. Have the `SetsRequiredMembersAttribute` applied to the constructor.\nThese would ensure that anyone who can see a constructor can either set all the things it exports, or there is nothing to set. This could be useful for types that are\nonly ever created via static `Create` methods or similar builders, but the utility seems overall limited.\n3. Readd a way to remove specific parts of the contract to the proposal, as discussed in [LDM](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-10-25.md)\npreviously.\n\n**Conclusion**: Option 1, all required members must be at least as visible as their containing type.\n\n</details>\n\n### Override rules\n\nThe current spec says that the `required` keyword needs to be copied over and that overrides can make a member _more_ required, but not less. Is that what we want to do?\nAllowing removal of requirements needs more contract modification abilities than we are currently proposing.\n\n**Conclusion**: Adding `required` on override is allowed. If the overridden member is `required`, the overridding member must also be\n`required`.\n\n### Alternative metadata representation\n\nWe could also take a different approach to metadata representation, taking a page from extension methods. We could put a `RequiredMemberAttribute` on the type to indicate\nthat the type contains required members, and then put a `RequiredMemberAttribute` on each member that is required. This would simplify the lookup sequence (no need to do\nmember lookup, just look for members with the attribute).\n\n**Conclusion**: Alternative approved.\n\n### Metadata Representation\n\nThe [Metadata Representation](#metadata-representation) needs to be approved. We additionally need to decide whether these attributes should be included in the BCL.\n\n1. For `RequiredMemberAttribute`, this attribute is more akin to the general embedded attributes we use for nullable/nint/tuple member names, and will not be manually\napplied by the user in C#. It's possible that other languages might want to manually apply this attribute, however.\n2. `SetsRequiredMembersAttribute`, on the other hand, is directly used by consumers, and thus should likely be in the BCL.\n\nIf we go with the alternative representation in the previous section, that might change the calculus on `RequiredMemberAttribute`: instead of being similar to the general\nembedded attributes for `nint`/nullable/tuple member names, it's closer to `System.Runtime.CompilerServices.ExtensionAttribute`, which has been in the framework since\nextension methods shipped.\n\n**Conclusion**: We will put both attributes in the BCL.\n\n### Warning vs Error\n\nShould not setting a required member be a warning or an error? It is certainly possible to trick the system, via `Activator.CreateInstance(typeof(C))` or similar, which\nmeans we may not be able to fully guarantee all properties are always set. We also allow suppression of the diagnostics at the constructor-site by using the `!`, which\nwe generally do not allow for errors. However, the feature is similar to readonly fields or init properties, in that we hard error if users attempt to set such a member\nafter initialization, but they can be circumvented by reflection.\n\n**Conclusion**: Errors.\n"
  },
  {
    "path": "proposals/csharp-11.0/static-abstracts-in-interfaces.md",
    "content": "# Static abstract members in interfaces\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/4436>\n\n## Summary\n[summary]: #summary\n\nAn interface is allowed to specify abstract static members that implementing classes and structs are then required to provide an explicit or implicit implementation of. The members can be accessed off of type parameters that are constrained by the interface.\n\n## Motivation\n[motivation]: #motivation\n\nThere is currently no way to abstract over static members and write generalized code that applies across types that define those static members. This is particularly problematic for member kinds that *only* exist in a static form, notably operators.\n\nThis feature allows generic algorithms over numeric types, represented by interface constraints that specify the presence of given operators. The algorithms can therefore be expressed in terms of such operators:\n\n``` c#\n// Interface specifies static properties and operators\ninterface IAddable<T> where T : IAddable<T>\n{\n    static abstract T Zero { get; }\n    static abstract T operator +(T t1, T t2);\n}\n\n// Classes and structs (including built-ins) can implement interface\nstruct Int32 : …, IAddable<Int32>\n{\n    static Int32 IAddable.operator +(Int32 x, Int32 y) => x + y; // Explicit\n    public static int Zero => 0;                          // Implicit\n}\n\n// Generic algorithms can use static members on T\npublic static T AddAll<T>(T[] ts) where T : IAddable<T>\n{\n    T result = T.Zero;                   // Call static operator\n    foreach (T t in ts) { result += t; } // Use `+`\n    return result;\n}\n\n// Generic method can be applied to built-in and user-defined types\nint sixtyThree = AddAll(new [] { 1, 2, 4, 8, 16, 32 });\n```\n\n## Syntax\n\n### Interface members\n\nThe feature would allow static interface members to be declared virtual. \n\n#### Rules before C# 11\nBefore C# 11, instance members in interfaces are implicitly abstract (or virtual if they have a default implementation), but can optionally have an `abstract` (or `virtual`) modifier. Non-virtual instance members must be explicitly marked as `sealed`. \n\nStatic interface members today are implicitly non-virtual, and do not allow `abstract`, `virtual` or `sealed` modifiers.\n\n#### Proposal\n\n##### Abstract static members\nStatic interface members other than fields are allowed to also have the `abstract` modifier. Abstract static members are not allowed to have a body (or in the case of properties, the accessors are not allowed to have a body). \n\n``` c#\ninterface I<T> where T : I<T>\n{\n    static abstract void M();\n    static abstract T P { get; set; }\n    static abstract event Action E;\n    static abstract T operator +(T l, T r);\n    static abstract bool operator ==(T l, T r);\n    static abstract bool operator !=(T l, T r);\n    static abstract implicit operator T(string s);\n    static abstract explicit operator string(T t);\n}\n```\n\n##### Virtual static members\nStatic interface members other than fields are allowed to also have the `virtual` modifier. Virtual static members are required to have a body. \n\n``` c#\ninterface I<T> where T : I<T>\n{\n    static virtual void M() {}\n    static virtual T P { get; set; }\n    static virtual event Action E;\n    static virtual T operator +(T l, T r) { throw new NotImplementedException(); }\n}\n```\n\n##### Explicitly non-virtual static members\nFor symmetry with non-virtual instance members, static members (except fields) should be allowed an optional `sealed` modifier, even though they are non-virtual by default:\n\n``` c#\ninterface I0\n{\n    static sealed void M() => Console.WriteLine(\"Default behavior\");\n    \n    static sealed int f = 0;\n    \n    static sealed int P1 { get; set; }\n    static sealed int P2 { get => f; set => f = value; }\n    \n    static sealed event Action E1;\n    static sealed event Action E2 { add => E1 += value; remove => E1 -= value; }\n    \n    static sealed I0 operator +(I0 l, I0 r) => l;\n}\n```\n\n### Implementation of interface members\n\n#### Today's rules\n\nClasses and structs can implement abstract instance members of interfaces either implicitly or explicitly. An implicitly implemented interface member is a normal (virtual or non-virtual) member declaration of the class or struct that just \"happens\" to also implement the interface member. The member can even be inherited from a base class and thus not even be present in the class declaration.\n\nAn explicitly implemented interface member uses a qualified name to identify the interface member in question. The implementation is not directly accessible as a member on the class or struct, but only through the interface.\n\n#### Proposal\n\nNo new syntax is needed in classes and structs to facilitate implicit implementation of static abstract interface members. Existing static member declarations serve that purpose.\n\nExplicit implementations of static abstract interface members use a qualified name along with the `static` modifier.\n\n``` c#\nclass C : I<C>\n{\n    string _s;\n    public C(string s) => _s = s;\n    static void I<C>.M() => Console.WriteLine(\"Implementation\");\n    static C I<C>.P { get; set; }\n    static event Action I<C>.E // event declaration must use field accessor syntax\n    {\n        add { ... }\n        remove { ... }\n    }\n    static C I<C>.operator +(C l, C r) => new C($\"{l._s} {r._s}\");\n    static bool I<C>.operator ==(C l, C r) => l._s == r._s;\n    static bool I<C>.operator !=(C l, C r) => l._s != r._s;\n    static implicit I<C>.operator C(string s) => new C(s);\n    static explicit I<C>.operator string(C c) => c._s;\n}\n```\n\n## Semantics\n\n### Operator restrictions\n\nToday all unary and binary operator declarations have some requirement involving at least one of their operands to be of type `T` or `T?`, where `T` is the instance type of the enclosing type.\n\nThese requirements need to be relaxed so that a restricted operand is allowed to be of a type parameter that counts as \"the instance type of the enclosing type\".\n\nIn order for a type parameter `T` to count as \"the instance type of the enclosing type\", it must meet the following requirements:\n- `T` is a direct type parameter on the interface in which the operator declaration occurs, and\n- `T` is *directly* constrained by what the spec calls the \"instance type\" - i.e. the surrounding interface with its own type parameters used as type arguments.\n\n### Equality operators and conversions\n\nAbstract/virtual declarations of `==` and `!=` operators, as well as abstract/virtual declarations of implicit and explicit conversion operators will be allowed in interfaces. Derived interfaces will be allowed to implement them too.\n\nFor `==` and `!=` operators, at least one parameter type must be a type parameter that counts as \"the instance type of the enclosing type\", as defined in the previous section. \n\n### Implementing static abstract members\n\nThe rules for when a static member declaration in a class or struct is considered to implement a static abstract interface member, and for what requirements apply when it does, are the same as for instance members.\n\n***TBD:** There may be additional or different rules necessary here that we haven't yet thought of.*\n\n### Interfaces as type arguments\n\nWe discussed the issue raised by https://github.com/dotnet/csharplang/issues/5955 and decided to add a restriction around usage of an interface as a type argument (https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-03-28.md#type-hole-in-static-abstracts). Here is the restriction as it was proposed by https://github.com/dotnet/csharplang/issues/5955 and approved by the LDM.\n\nAn interface containing or inheriting a static abstract/virtual member that does not have most specific implementation in the interface cannot be used as a type argument. If all static abstract/virtual members have most specific implementation, the interface can be used as a type argument.\n\n### Accessing static abstract interface members\n\nA static abstract interface member `M` may be accessed on a type parameter `T` using the expression `T.M` when `T` is constrained by an interface `I` and `M` is an accessible static abstract member of `I`.\n\n``` c#\nT M<T>() where T : I<T>\n{\n    T.M();\n    T t = T.P;\n    T.E += () => { };\n    return t + T.P;\n}\n```\n\nAt runtime, the actual member implementation used is the one that exists on the actual type provided as a type argument.\n\n``` c#\nC c = M<C>(); // The static members of C get called\n```\n\nSince query expressions are spec'ed as a syntactic rewrite, C# actually lets you use a *type* as the query source, as long as it has static members for the query operators you use! In other words, if the *syntax* fits, we allow it!\nWe think this behavior was not intentional or important in the original LINQ, and we don't want to do the work to support it on type parameters. If there are scenarios out there we will hear about them, and can choose to embrace this later.\n\n### Variance safety [§18.2.3.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/interfaces.md#18232-variance-safety)\n\nVariance safety rules should apply to signatures of static abstract members. The addition proposed in\nhttps://github.com/dotnet/csharplang/blob/main/proposals/csharp-9.0/variance-safety-for-static-interface-members.md#variance-safety\nshould be adjusted from\n\n*These restrictions do not apply to occurrences of types within declarations of static members.* \n\nto\n\n*These restrictions do not apply to occurrences of types within declarations of **non-virtual, non-abstract** static members.*\n\n### [§10.5.4](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#1054-user-defined-implicit-conversions) User defined implicit conversions\n\nThe following bullet points\n\n- Determine the types `S`, `S₀` and `T₀`.\n  - If `E` has a type, let `S` be that type.\n  - If `S` or `T` are nullable value types, let `Sᵢ` and `Tᵢ` be their underlying types, otherwise let `Sᵢ` and `Tᵢ` be `S` and `T`, respectively.\n  - If `Sᵢ` or `Tᵢ` are type parameters, let `S₀` and `T₀` be their effective base classes, otherwise let `S₀` and `T₀` be `Sₓ` and `Tᵢ`, respectively.\n- Find the set of types, `D`, from which user-defined conversion operators will be considered. This set consists of `S0` (if `S0` is a class or struct), the base classes of `S0` (if `S0` is a class), and `T0` (if `T0` is a class or struct).\n- Find the set of applicable user-defined and lifted conversion operators, `U`. This set consists of the user-defined and lifted implicit conversion operators declared by the classes or structs in `D` that convert from a type encompassing `S` to a type encompassed by `T`. If `U` is empty, the conversion is undefined and a compile-time error occurs.\n\nare adjusted as follows:\n\n- Determine the types `S`, `S₀` and `T₀`.\n  - If `E` has a type, let `S` be that type.\n  - If `S` or `T` are nullable value types, let `Sᵢ` and `Tᵢ` be their underlying types, otherwise let `Sᵢ` and `Tᵢ` be `S` and `T`, respectively.\n  - If `Sᵢ` or `Tᵢ` are type parameters, let `S₀` and `T₀` be their effective base classes, otherwise let `S₀` and `T₀` be `Sₓ` and `Tᵢ`, respectively.\n- Find the set of applicable user-defined and lifted conversion operators, `U`. \n  - Find the set of types, `D1`, from which user-defined conversion operators will be considered. This set consists of `S0` (if `S0` is a class or struct), the base classes of `S0` (if `S0` is a class), and `T0` (if `T0` is a class or struct).\n  - Find the set of applicable user-defined and lifted conversion operators, `U1`. This set consists of the user-defined and lifted implicit conversion operators declared by the classes or structs in `D1` that convert from a type encompassing `S` to a type encompassed by `T`.\n  - If `U1` is not empty, then `U` is `U1`. Otherwise,\n    - Find the set of types, `D2`, from which user-defined conversion operators will be considered. This set consists of `Sᵢ` *effective interface set* and their base interfaces (if `Sᵢ` is a type parameter), and `Tᵢ` *effective interface set* (if `Tᵢ` is a type parameter).\n    - Find the set of applicable user-defined and lifted conversion operators, `U2`. This set consists of the user-defined and lifted implicit conversion operators declared by the interfaces in `D2` that convert from a type encompassing `S` to a type encompassed by `T`.\n    - If `U2` is not empty, then `U` is `U2`\n- If `U` is empty, the conversion is undefined and a compile-time error occurs.\n\n### [§10.3.9](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#1039-user-defined-explicit-conversions)  User-defined explicit conversions\n\nThe following bullet points\n\n- Determine the types `S`, `S₀` and `T₀`.\n  - If `E` has a type, let `S` be that type.\n  - If `S` or `T` are nullable value types, let `Sᵢ` and `Tᵢ` be their underlying types, otherwise let `Sᵢ` and `Tᵢ` be `S` and `T`, respectively.\n  - If `Sᵢ` or `Tᵢ` are type parameters, let `S₀` and `T₀` be their effective base classes, otherwise let `S₀` and `T₀` be `Sᵢ` and `Tᵢ`, respectively.\n- Find the set of types, `D`, from which user-defined conversion operators will be considered. This set consists of `S0` (if `S0` is a class or struct), the base classes of `S0` (if `S0` is a class), `T0` (if `T0` is a class or struct), and the base classes of `T0` (if `T0` is a class).\n- Find the set of applicable user-defined and lifted conversion operators, `U`. This set consists of the user-defined and lifted implicit or explicit conversion operators declared by the classes or structs in `D` that convert from a type encompassing or encompassed by `S` to a type encompassing or encompassed by `T`. If `U` is empty, the conversion is undefined and a compile-time error occurs.\n\nare adjusted as follows:\n\n- Determine the types `S`, `S₀` and `T₀`.\n  - If `E` has a type, let `S` be that type.\n  - If `S` or `T` are nullable value types, let `Sᵢ` and `Tᵢ` be their underlying types, otherwise let `Sᵢ` and `Tᵢ` be `S` and `T`, respectively.\n  - If `Sᵢ` or `Tᵢ` are type parameters, let `S₀` and `T₀` be their effective base classes, otherwise let `S₀` and `T₀` be `Sᵢ` and `Tᵢ`, respectively.\n- Find the set of applicable user-defined and lifted conversion operators, `U`.\n  - Find the set of types, `D1`, from which user-defined conversion operators will be considered. This set consists of `S0` (if `S0` is a class or struct), the base classes of `S0` (if `S0` is a class), `T0` (if `T0` is a class or struct), and the base classes of `T0` (if `T0` is a class).\n  - Find the set of applicable user-defined and lifted conversion operators, `U1`. This set consists of the user-defined and lifted implicit or explicit conversion operators declared by the classes or structs in `D1` that convert from a type encompassing or encompassed by `S` to a type encompassing or encompassed by `T`.\n  - If `U1` is not empty, then `U` is `U1`. Otherwise,\n    - Find the set of types, `D2`, from which user-defined conversion operators will be considered. This set consists of `Sᵢ` *effective interface set* and their base interfaces (if `Sᵢ` is a type parameter), and `Tᵢ` *effective interface set* and their base interfaces (if `Tᵢ` is a type parameter).\n    - Find the set of applicable user-defined and lifted conversion operators, `U2`. This set consists of the user-defined and lifted implicit or explicit conversion operators declared by the interfaces in `D2` that convert from a type encompassing or encompassed by `S` to a type encompassing or encompassed by `T`.\n    - If `U2` is not empty, then `U` is `U2`\n- If `U` is empty, the conversion is undefined and a compile-time error occurs.\n\n### Default implementations\n\nAn *additional* feature to this proposal is to allow static virtual members in interfaces to have default implementations, just as instance virtual/abstract members do. \n\nOne complication here is that default implementations would want to call other static virtual members \"virtually\". Allowing static virtual members to be called directly on the interface would require flowing a hidden type parameter representing the \"self\" type that the current static method really got invoked on. This seems complicated, expensive and potentially confusing.\n\nWe discussed a simpler version which maintains the limitations of the current proposal that static virtual members can *only* be invoked on type parameters. Since interfaces with static virtual members will often have an explicit type parameter representing a \"self\" type, this wouldn't be a big loss: other static virtual members could just be called on that self type. This version is a lot simpler, and seems quite doable.\n\nAt https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-24.md#default-implementations-of-abstract-statics we decided to support Default Implementations of static members following/expanding the rules established in https://github.com/dotnet/csharplang/blob/main/proposals/csharp-8.0/default-interface-methods.md accordingly.  \n\n### Pattern matching\n\nGiven the following code, a user might reasonably expect it to print \"True\" (as it would if the constant pattern was written inline):\n\n```cs\nM(1.0);\n\nstatic void M<T>(T t) where T : INumberBase<T>\n{\n    Console.WriteLine(t is 1); // Error. Cannot use a numeric constant\n    Console.WriteLine((t is int i) && (i is 1)); \n}\n```\n\nHowever, because the input type of the pattern is not `double`, the constant `1` pattern will first type check the incoming `T` against `int`. This is unintuitive, so it is blocked until a future C# version adds better handling for numeric matching against types derived from `INumberBase<T>`. To do so, we will say that, we will explicitly recognize `INumberBase<T>` as the type that all \"numbers\" will derive from, and block the pattern if we're trying to match a numeric constant pattern against a number type that we can't represent the pattern in (ie, a type parameter constrained to `INumberBase<T>`, or a user-defined number type that inherits from `INumberBase<T>`).\n\nFormally, we add an exception to the definition of *pattern-compatible* for constant patterns:\n\n> A constant pattern tests the value of an expression against a constant value. The constant may be any constant expression, such as a literal, the name of a declared `const` variable, or an enumeration constant. When the input value is not an open type, the constant expression is implicitly converted to the type of the matched expression; if the type of the input value is not *pattern-compatible* with the type of the constant expression, the pattern-matching operation is an error. **If the constant expression being matched against is a numeric value, the input value is a type that inherits from `System.Numerics.INumberBase<T>`, and there is no constant conversion from the constant expression to the type of the input value, the pattern-matching operation is an error.**\n\nWe also add a similar exception for relational patterns:\n\n> When the input is a type for which a suitable built-in binary relational operator is defined that is applicable with the input as its left operand and the given constant as its right operand, the evaluation of that operator is taken as the meaning of the relational pattern. Otherwise we convert the input to the type of the expression using an explicit nullable or unboxing conversion. It is a compile-time error if no such conversion exists. **It is a compile-time error if the input type is a type parameter constrained to or a type inheriting from `System.Numerics.INumberBase<T>` and the input type has no suitable built-in binary relational operator defined.** The pattern is considered not to match if the conversion fails. If the conversion succeeds then the result of the pattern-matching operation is the result of evaluating the expression e OP v where e is the converted input, OP is the relational operator, and v is the constant expression.\n\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\n- \"static abstract\" is a new concept and will meaningfully add to the conceptual load of C#.\n- It's not a cheap feature to build. We should make sure it's worth it.\n\n## Alternatives\n[alternatives]: #alternatives\n\n### Structural constraints\n\nAn alternative approach would be to have \"structural constraints\" directly and explicitly requiring the presence of specific operators on a type parameter. The drawbacks of that are:\n    - This would have to be written out every time. Having a named constraint seems better.\n    - This is a whole new kind of constraint, whereas the proposed feature utilizes the existing concept of interface constraints.\n    - It would only work for operators, not (easily) other kinds of static members.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n### Static abstract interfaces and static classes\n\nSee https://github.com/dotnet/csharplang/issues/5783 and https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-16.md#static-abstract-interfaces-and-static-classes for more information.\n\n## Design meetings\n\n- https://github.com/dotnet/csharplang/blob/master/meetings/2021/LDM-2021-02-08.md\n- https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-04-05.md\n- https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-06-29.md\n- https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-24.md\n- https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-16.md\n- https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-03-28.md\n- https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-04-06.md\n- https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-06-06.md\n"
  },
  {
    "path": "proposals/csharp-11.0/unsigned-right-shift-operator.md",
    "content": "# Unsigned right shift operator\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/4682>\n\n## Summary\n[summary]: #summary\n\nAn unsigned right shift operator will be supported by C# as a built-in operator (for primitive integral types) and as a user-defined operator. \n\n## Motivation\n[motivation]: #motivation\n\nWhen working with signed integral value, it is not uncommon that you need to shift bits right without replicating\nthe high order bit on each shift. While this can be achieved for primitive integral types with a regular shift\noperator, a cast to an unsigned type before the shift operation and a cast back after it is required. Within the\ncontext of the generic math interfaces the libraries are planning to expose, this is potentially more problematic\nas the type might not necessary have an unsigned counterpart defined or known upfront by the generic math code,\nyet an algorithm might rely on ability to perform an unsigned right shift operation.\n\n## Detailed design\n[design]: #detailed-design\n\n### Operators and punctuators\n\nSection [§6.4.6](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/lexical-structure.md#646-operators-and-punctuators) will be adjusted\nto include `>>>` operator - the unsigned right shift operator:\n\n```antlr\nunsigned_right_shift\n    : '>>>'\n    ;\n\nunsigned_right_shift_assignment\n    : '>>>='\n    ;\n```\n\nNo characters of any kind (not even whitespace) are allowed between the tokens in *unsigned_right_shift* and *unsigned_right_shift_assignment* productions. These productions are treated specially in order to enable the correct  handling of *type_parameter_list*s.\n\n### Shift operators\n\nSection [§12.11](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1211-shift-operators) will be adjusted\nto include `>>>` operator - the unsigned right shift operator:\n\nThe `<<`, `>>` and `>>>` operators are used to perform bit shifting operations.\n\n```antlr\nshift_expression\n    : additive_expression\n    | shift_expression '<<' additive_expression\n    | shift_expression right_shift additive_expression\n    | shift_expression unsigned_right_shift additive_expression\n    ;\n```\n\nFor an operation of the form `x << count` or `x >> count` or `x >>> count`, binary operator overload resolution ([§12.4.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1245-binary-operator-overload-resolution)) is applied to select a specific operator implementation. The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.\n\nThe predefined unsigned shift operators will support the same set of signatures\nthat predefined signed shift operators support today in the current implementation.\n\n*  Shift right:\n\n   ```csharp\n   int operator >>>(int x, int count);\n   uint operator >>>(uint x, int count);\n   long operator >>>(long x, int count);\n   ulong operator >>>(ulong x, int count);\n   nint operator >>>(nint x, int count);\n   nuint operator >>>(nuint x, int count);\n   ```\n\n   The `>>>` operator shifts `x` right by a number of bits computed as described below.\n\n   The low-order bits of `x` are discarded, the remaining bits are shifted right, and the high-order empty bit positions are set to zero.\n\nFor the predefined operators, the number of bits to shift is computed as follows:\n\n*  When the type of `x` is `int` or `uint`, the shift count is given by the low-order five bits of `count`. In other words, the shift count is computed from `count & 0x1F`.\n*  When the type of `x` is `long` or `ulong`, the shift count is given by the low-order six bits of `count`. In other words, the shift count is computed from `count & 0x3F`.\n\nIf the resulting shift count is zero, the shift operators simply return the value of `x`.\n\nShift operations never cause overflows and produce the same results in `checked` and `unchecked` contexts.\n\n### Assignment operators\n\nSection [§12.21](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1221-assignment-operators) will be adjusted to include\n*unsigned_right_shift_assignment* as follows:\n\n```antlr\nassignment_operator\n    : '='\n    | '+='\n    | '-='\n    | '*='\n    | '/='\n    | '%='\n    | '&='\n    | '|='\n    | '^='\n    | '<<='\n    | right_shift_assignment\n    | unsigned_right_shift_assignment\n    ;\n```\n\n### Integral types\n\nThe Integral types [§8.3.6](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/types.md#836-integral-types) section will be adjusted to include information about `>>>` operator. The relevant bullet point is the following:\n\n*  For the binary `<<`, `>>` and `>>>` operators, the left operand is converted to type `T`, where `T` is the first of `int`, `uint`, `long`, and `ulong` that can fully represent all possible values of the operand. The operation is then performed using the precision of type `T`, and the type of the result is `T`.\n\n### Constant expressions\n\nOperator `>>>` will be added to the set of constructs permitted in constant expressions at\n[§12.23](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1223-constant-expressions).\n\n### Operator overloading\n\nOperator `>>>` will be added to the set of overloadable binary operators at [§12.4.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1243-operator-overloading).\n\n### Lifted operators\n\nOperator `>>>` will be added to the set of binary operators permitting a lifted form at [§12.4.8](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1248-lifted-operators).\n\n### Operator precedence and associativity\n\nSection [§12.4.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1242-operator-precedence-and-associativity) will be adjusted to add `>>>` operator to the \"Shift\" category and `>>>=` operator to the \"Assignment and lambda expression\" category.\n\n### Grammar ambiguities\n\nThe `>>>` operator is subject to the same grammar ambiguities described at [§6.2.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/lexical-structure.md#625-grammar-ambiguities) as a regular `>>` operator.\n\n### Operators\n\nThe [§15.10](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#1510-operators) section will be adjusted to include `>>>` operator.\n\n```antlr\noverloadable_binary_operator\n    : '+'   | '-'   | '*'   | '/'   | '%'   | '&'   | '|'   | '^'   | '<<'\n    | right_shift | unsigned_right_shift | '=='  | '!='  | '>'   | '<'   | '>='  | '<='\n    ;\n```\n\n### Binary operators\n\nThe signature of a `>>>` operator is subject to the same rules as those at [§15.10.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#15103-binary-operators)\nfor the signature of a `>>` operator.\n\n### Metadata name\n\nSection \"I.10.3.2 Binary operators\" of ECMA-335 already reserved the name for an unsigned right shift operator - op_UnsignedRightShift.\n\n### Linq Expression Trees\n\nThe `>>>` operator will not be supported in Linq Expression Trees because semantics of predefined `>>>` operators on signed types cannot be accurately represented without adding conversions to an unsigned type and back. See https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md#unsigned-right-shift-operator for more information.\n\n### Dynamic Binding \n\nIt looks like dynamic binding uses values of System.Linq.Expressions.ExpressionType enum to communicate\nbinary operator kind to the runtime binder. Since we don't have a member specifically representing\nan unsigned right shift operator, dynamic binding for `>>>` operator will not be supported and the\nstatic and dynamic binding ([§12.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#123-static-and-dynamic-binding)) section \nwill be adjusted to reflect that.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\n<!-- Why should we *not* do this? -->\n\n## Alternatives\n[alternatives]: #alternatives\n\n### Linq Expression Trees\n\nThe `>>>` operator will be supported in Linq Expressioin Trees.\n- For a user-defined operator, a BinaryExpression node pointing to the operator method will be created.\n- For predefined operators\n  -  when the first operand is an ansigned type, a BinaryExpression node will be created.\n  -  when the first operand is a signed type, a conversion for the first operand to an unsigned type will be added, a BinaryExpression node will be created and conversion for the result back to the signed type will be added.\n\nFor example:\n``` C#\nExpression<System.Func<int, int, int>> z = (x, y) => x >>> y; // (x, y) => Convert((Convert(x, UInt32) >> y), Int32)\n```\n\n`Resolution:`\n\nRejected, see https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md#unsigned-right-shift-operator for more information.\n\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n<!-- What parts of the design are still undecided? -->\n\n## Design meetings\n\nhttps://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md\n"
  },
  {
    "path": "proposals/csharp-11.0/utf8-string-literals.md",
    "content": "Utf8 Strings Literals\n===\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/184>\n\n## Summary\nThis proposal adds the ability to write UTF8 string literals in C# and have them automatically encoded into their UTF-8 `byte` representation.\n\n## Motivation\nUTF8 is the language of the web and its use is necessary in significant portions of the .NET stack. While much of data comes in the form of `byte[]` off the network stack there is still significant uses of constants in the code. For example networking stack has to commonly write constants like `\"HTTP/1.0\\r\\n\"`, `\" AUTH\"` or . `\"Content-Length: \"`. \n\nToday there is no efficient syntax for doing this as C# represents all strings using UTF16 encoding. That means developers have to choose between the convenience of encoding at runtime which incurs overhead, including the time spent at startup actually performing the encoding operation (and allocations if targeting a type that doesn't actually require them), or manually translating the bytes and storing in a `byte[]`. \n\n```c# \n// Efficient but verbose and error prone\nstatic ReadOnlySpan<byte> AuthWithTrailingSpace => new byte[] { 0x41, 0x55, 0x54, 0x48, 0x20 };\nWriteBytes(AuthWithTrailingSpace);\n\n// Incurs allocation and startup costs performing an encoding that could have been done at compile-time\nstatic readonly byte[] s_authWithTrailingSpace = Encoding.UTF8.GetBytes(\"AUTH \");\nWriteBytes(s_authWithTrailingSpace);\n\n// Simplest / most convenient but terribly inefficient\nWriteBytes(Encoding.UTF8.GetBytes(\"AUTH \"));\n```\n\nThis trade off is a pain point that comes up frequently for our partners in the runtime, ASP.NET and Azure. Often times it causes them to leave performance on the table because they don't want to go through the hassle of writing out the `byte[]` encoding by hand.\n\nTo fix this we will allow for UTF8 literals in the language and encode them into the UTF8 `byte[]` at compile time.\n\n## Detailed design\n\n### `u8` suffix on string literals\n\nThe language will provide the `u8` suffix on string literals to force the type to be UTF8.\nThe suffix is case-insensitive, `U8` suffix will be supported and will have the same meaning as `u8` suffix.\n\nWhen the `u8` suffix is used, the value of the literal is a `ReadOnlySpan<byte>` containing a UTF-8 byte representation of the string.\nA null terminator is placed beyond the last byte in memory (and outside the length of the `ReadOnlySpan<byte>`) in order to handle some\ninterop scenarios where the call expects null terminated strings.\n\n```c#\nstring s1 = \"hello\"u8;             // Error\nvar s2 = \"hello\"u8;                // Okay and type is ReadOnlySpan<byte>\nReadOnlySpan<byte> s3 = \"hello\"u8; // Okay.\nbyte[] s4 = \"hello\"u8;             // Error - Cannot implicitly convert type 'System.ReadOnlySpan<byte>' to 'byte[]'.\nbyte[] s5 = \"hello\"u8.ToArray();   // Okay.\nSpan<byte> s6 = \"hello\"u8;         // Error - Cannot implicitly convert type 'System.ReadOnlySpan<byte>' to 'System.Span<byte>'.\n```\n\nSince the literals would be allocated as global constants, the lifetime of the resulting `ReadOnlySpan<byte>` would not prevent it from being returned or passed around to elsewhere. However, certain contexts, most notably within async functions, do not allow locals of ref struct types, so there would be a usage penalty in those situations, with a `ToArray()` call or similar being required.\n\nA `u8` literal doesn't have a constant value. That is because `ReadOnlySpan<byte>` cannot be the type of a constant today. If the definition of `const` is expanded\nin the future to consider `ReadOnlySpan<byte>`, then this value should also be considered a constant. Practically though this means a `u8`\nliteral cannot be used as the default value of an optional parameter.\n\n```c#\n// Error: The argument is not constant\nvoid Write(ReadOnlySpan<byte> message = \"missing\"u8) { ... } \n```\n\nWhen the input text for the literal is a malformed UTF16 string, then the language will emit an error:\n\n```c#\nvar bytes = \"hello \\uD8\\uD8\"u8; // Error: malformed UTF16 input string\n\nvar bytes2 = \"hello \\uD801\\uD802\"u8; // Allowed: invalid UTF16 values, but it's correctly formed.\n```\n\n### Addition operator\n\nA new bullet point will be added to [§12.10.5 Addition operator](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12105-addition-operator) as follows.\n\n- UTF8 byte representation concatenation:\n\n  ```csharp\n  ReadOnlySpan<byte> operator +(ReadOnlySpan<byte> x, ReadOnlySpan<byte> y);\n  ```\n\n  This binary `+` operator performs byte sequences concatenation and is applicable if and only if both operands are semantically UTF8 byte representations.\n  An operand is semantically a UTF8 byte representation when it is either a value of a `u8` literal, or a value produced by the UTF8 byte representation concatenation operator. \n\n  The result of the UTF8 byte representation concatenation is a `ReadOnlySpan<byte>` that consists of the bytes of the left operand followed by the bytes of the right operand. A null terminator is placed beyond the last byte in memory (and outside the length of the `ReadOnlySpan<byte>`) in order to handle some\ninterop scenarios where the call expects null terminated strings.\n\n### Lowering\n\nThe language will lower the UTF8 encoded strings exactly as if the developer had typed the resulting `byte[]` literal in code. For example:\n\n```c#\nReadOnlySpan<byte> span = \"hello\"u8;\n\n// Equivalent to\n\nReadOnlySpan<byte> span = new ReadOnlySpan<byte>(new byte[] { 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x00 }).\n                               Slice(0,5); // The `Slice` call will be optimized away by the compiler.\n```\n\nThat means all optimizations that apply to the `new byte[] { ... }` form will apply to utf8 literals as well. This means the call site will be allocation free as C# will optimize this to be stored in the `.data` section of the PE file.\n\nMultiple consecutive applications of UTF8 byte representation concatenation operators are collapsed into a single creation of `ReadOnlySpan<byte>` with byte array containing the final byte sequence.\n\n```c#\nReadOnlySpan<byte> span = \"h\"u8 + \"el\"u8 + \"lo\"u8;\n\n// Equivalent to\n\nReadOnlySpan<byte> span = new ReadOnlySpan<byte>(new byte[] { 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x00 }).\n                               Slice(0,5); // The `Slice` call will be optimized away by the compiler.\n```\n\n## Drawbacks\n### Relying on core APIs\nThe compiler implementation will use `UTF8Encoding` for both invalid string detection as well as translation to `byte[]`. The exact APIs will possibly depend on which target framework the compiler is using. But `UTF8Encoding` will be the workhorse of the implementation.\n\nHistorically the compiler has avoided using runtime APIs for literal processing. That is because it takes control of how constants are processed away from the language and into the runtime. Concretely it means items like bug fixes can change constant encoding and mean that the outcome of C# compilation depends on which runtime the compiler is executing on. \n\nThis is not a hypothetical problem. Early versions of Roslyn used `double.Parse` to handle floating point constant parsing. That caused a number of problems. First it meant that some floating point values had different representations between the native compiler and Roslyn. Second as .NET core evolved and fixed long standing bugs in the `double.Parse` code it meant that the meaning of those constants changed in the language depending on what runtime the compiler executed on. As a result the compiler ended up writing its own version of floating point parsing code and removing the dependency on `double.Parse`. \n\nThis scenario was discussed with the runtime team and we do not feel it has the same problems we've hit before. The UTF8 parsing is stable across runtimes and there are no known issues in this area that are areas for future compat concerns. If one does come up we can re-evaluate the strategy. \n\n## Alternatives\n### Target type only\nThe design could rely on target typing only and remove the `u8` suffix on `string` literals. In the majority of cases today the `string` literal is being assigned directly to a `ReadOnlySpan<byte>` hence it's unnecessary. \n\n```c#\nReadOnlySpan<byte> span = \"Hello World;\" \n```\n\nThe `u8` suffix exists primarily to support two scenarios: `var` and overload resolution. For the latter consider the following use case: \n\n```c# \nvoid Write(ReadOnlySpan<byte> span) { ... } \nvoid Write(string s) {\n    var bytes = Encoding.UTF8.GetBytes(s);\n    Write(bytes.AsSpan());\n}\n```\n\nGiven the implementation it is better to call `Write(ReadOnlySpan<byte>)` and the `u8` suffix makes this convenient: `Write(\"hello\"u8)`. Lacking that developers need to resort to awkward casting `Write((ReadOnlySpan<byte>)\"hello\")`. \n\nStill this is a convenience item, the feature can exist without it and it is non-breaking to add it at a later time. \n\n### Wait for Utf8String type\nWhile the .NET ecosystem is standardizing on `ReadOnlySpan<byte>` as the defacto Utf8 string type today it's possible the runtime will introduce an actual `Utf8String` type is the future.\n\nWe should evaluate our design here in the face of this possible change and reflect on whether we'd regret the decisions we've made. This should be weighed though against the realistic probability we'll introduce `Utf8String`, a probability which seems to decrease every day we find `ReadOnlySpan<byte>` as an acceptable alternative.\n\nIt seems unlikely that we would regret the target type conversion between string literals and `ReadOnlySpan<byte>`. The use of `ReadOnlySpan<byte>` as utf8 is embedded in our APIs now and hence there is still value in the conversion even if `Utf8String` comes along and is a \"better\" type. The language could simply prefer conversions to `Utf8String` over `ReadOnlySpan<byte>`.\n\nIt seems more likely that we'd regret the `u8` suffix pointing to `ReadOnlySpan<byte>` instead of `Utf8String`. It would be similar to how we regret that `stackalloc int[]` has a natural type of `int*` instead of `Span<int>`. This is not a deal breaker though, just an inconvenience.\n\n### Conversions between `string` constants and `byte` sequences\n\nThe conversions in this section have not been implemented. These conversions remain active proposals.\n\n<details>\n\nThe language will allow conversions between `string` constants and `byte` sequences where the text is converted into the equivalent UTF8 byte representation. Specifically the compiler will allow _string_constant_to_UTF8_byte_representation_conversion_ - implicit conversions from `string` constants to `byte[]`, `Span<byte>`, and `ReadOnlySpan<byte>`.\nA new bullet point will be added to the implicit conversions [§10.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#102-implicit-conversions) section. This conversion is not a standard conversion [§10.4](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#104-standard-conversions).\n\n```c# \nbyte[] array = \"hello\";             // new byte[] { 0x68, 0x65, 0x6c, 0x6c, 0x6f }\nSpan<byte> span = \"dog\";            // new byte[] { 0x64, 0x6f, 0x67 }\nReadOnlySpan<byte> span = \"cat\";    // new byte[] { 0x63, 0x61, 0x74 }\n```\n\nWhen the input text for the conversion is a malformed UTF16 string then the language will emit an error:\n\n```c#\nconst string text = \"hello \\uD801\\uD802\";\nbyte[] bytes = text; // Error: the input string is not valid UTF16\n```\n\nThe predominant usage of this feature is expected to be with literals but it will work with any `string` constant value.\nA conversion from a `string` constant with `null` value will be supported as well. The result of the conversion will be `default`\nvalue of the target type.\n\n```c#\nconst string data = \"dog\"\nReadOnlySpan<byte> span = data;     // new byte[] { 0x64, 0x6f, 0x67 }\n```\n\nIn the case of any constant operation on strings, such as `+`, the encoding to UTF8 will occur on the final `string` vs. happening for the individual parts and then concatenating the results. This ordering is important to consider because it can impact whether or not the conversion succeeds. \n\n```c#\nconst string first = \"\\uD83D\";  // high surrogate\nconst string second = \"\\uDE00\"; // low surrogate\nReadOnlySpan<byte> span = first + second;\n```\n\nThe two parts here are invalid on their own as they are incomplete portions of a surrogate pair. Individually there is no correct translation to UTF8 but together they form a complete surrogate pair that can be successfully translated to UTF8.\n\nThe _string_constant_to_UTF8_byte_representation_conversion_ is not allowed in Linq Expression Trees.\n\nWhile the inputs to these conversions are constants and the data is fully encoded at compile time, the conversion is **not** considered constant by the language. That is because arrays are not constant today. If the definition of `const` is expanded in the future to consider arrays then these conversions should also be considered. Practically though this means a result of these conversions cannot be used as the default value of an optional parameter. \n\n```c#\n// Error: The argument is not constant\nvoid Write(ReadOnlySpan<byte> message = \"missing\") { ... } \n```\n\nOnce implemented string literals will have the same problem that other literals have in the language: what type they represent depends on how they are used. C# provides a literal suffix to disambiguate the meaning for other literals. For example developers can write `3.14f` to force the value to be a `float` or `1l` to force the value to be a `long`.\n\n</details>\n\n## Unresolved questions\n\nThe first three design questions relate to string to `Span<byte>` / `ReadOnlySpan<byte>` conversions.They haven't been implemented.\n\n<details>\n\n### (Resolved) Conversions between a `string` constant with `null` value and `byte` sequences\n\nWhether this conversion is supported and, if so, how it is performed is not specified.\n\n*Proposal:* \n\nAllow implicit conversions from a `string` constant with `null` value to `byte[]`, `Span<byte>`, and `ReadOnlySpan<byte>`. The result of the conversion is `default` value of the target type.\n\n*Resolution:*\n\nThe proposal is approved - https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#conversions-from-null-literals.\n\n### (Resolved) Where does _string_constant_to_UTF8_byte_representation_conversion_ belong?\n\nIs _string_constant_to_UTF8_byte_representation_conversion_ a bullet point in the implicit conversions [§10.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#102-implicit-conversions) section on its own, or is it part of [§10.2.11](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#10211-implicit-constant-expression-conversions), or does it belong to some other existing implicit conversions group?\n\n*Proposal:* \n\nIt is a new bullet point in implicit conversions [§10.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#102-implicit-conversions), similar to \"Implicit interpolated string conversions\" or \"Method group conversions\". It doesn't feel like it belongs to \"Implicit constant expression conversions\" because, even though the source is a constant expression, the result is never a constant expression. Also, \"Implicit constant expression conversions\" are considered to be \"Standard implicit conversions\" [§10.4.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#1042-standard-implicit-conversions), which is likely to lead to non-trivial behavior changes involving user-defined conversions.\n\n*Resolution:*\n\nWe will introduce a new conversion kind for string constant to UTF-8 bytes - https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#conversion-kinds\n\n### (Resolved) Is _string_constant_to_UTF8_byte_representation_conversion_ a standard conversion\n\nIn addition to \"pure\" Standard Conversions (the standard conversions are those pre-defined conversions that can occur as part of a user-defined conversion), compiler also treats some predefined conversions as \"somewhat\" standard. For example, an implicit interpolated string conversion can occur as part of a user-defined conversion if there is an explicit cast to the target type in code. As if it is a Standard Explicit Conversion, even though it is an implicit conversion not explicitly included into the set of standard implicit or explicit conversions. For example:\n\n``` C#\nclass C\n{\n    static void Main()\n    {\n        C1 x = $\"hello\"; // error CS0266: Cannot implicitly convert type 'string' to 'C1'. An explicit conversion exists (are you missing a cast?)\n        var y = (C1)$\"dog\"; // works\n    }\n}\n\nclass C1\n{\n    public static implicit operator C1(System.FormattableString x) => new C1();\n}\n```\n\n*Proposal:* \n\nThe new conversion is not a standard conversion. This will avoid non-trivial behavior changes involving user-defined conversions. For example, we won't need to worry about user-defined cinversions under implicit tuple literal conversions, etc.\n\n*Resolution:*\n\nNot a standard conversion, for now - https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#implicit-standard-conversion.\n\n</details>\n\n### (Resolved) Linq Expression Tree conversion\n\nShould _string_constant_to_UTF8_byte_representation_conversion_ be allowed in context of a Linq Expression Tree conversion?\nWe can disallow it for now, or we could simply include the \"lowered\" form into the tree. For example:\n``` C#\nExpression<Func<byte[]>> x = () => \"hello\";           // () => new [] {104, 101, 108, 108, 111}\nExpression<FuncSpanOfByte> y = () => \"dog\";           // () => new Span`1(new [] {100, 111, 103}) \nExpression<FuncReadOnlySpanOfByte> z = () => \"cat\";   // () => new ReadOnlySpan`1(new [] {99, 97, 116})\n```\n\nWhat about string literals with `u8` suffix? We could surface those as byte array creations:\n``` C#\nExpression<Func<byte[]>> x = () => \"hello\"u8;           // () => new [] {104, 101, 108, 108, 111}\n```\n\n*Resolution:*\n\nDisallow in Linq Expression Trees - https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#expression-tree-representation.\n\n### (Resolved) The natural type of a string literal with `u8` suffix\n\nThe \"Detailed design\" section says: \"The natural type though will be `ReadOnlySpan<byte>`.\" At the same time: \"When the `u8` suffix is used the literal can still be converted to any of the allowed types: `byte[]`, `Span<byte>` or `ReadOnlySpan<byte>`.\" \n\nThere are several disadvantages with this approach:\n- `ReadOnlySpan<byte>` is not available on desktop framework;\n- There are no existing conversions from `ReadOnlySpan<byte>` to `byte[]` or `Span<byte>`. In order to support them we will likely need to treat the literals as target typed. Both the language rules and implementation will become more complicated.  \n\n*Proposal:* \n\nThe natural type will be `byte[]`. It is readily available on all frameworks. BTW, at runtime we will always be starting with creating a byte array, even with the original proposal. We also don't need any special conversion rules to support conversions to `Span<byte>` and `ReadOnlySpan<byte>`. There are already implicit user-defined conversions from `byte[]` to `Span<byte>` and `ReadOnlySpan<byte>`. There is even implicit user-defined conversion to `ReadOnlyMemory<byte>` (see the \"Depth of the conversion\" question below). There is a disadvantage, language doesn't allow chaining user-defined conversions. So, the following code will not compile:\n```C#\nusing System;\nclass C\n{\n    static void Main()\n    {\n        var y = (C2)\"dog\"u8; // error CS0030: Cannot convert type 'byte[]' to 'C2'\n        var z = (C3)\"cat\"u8; // error CS0030: Cannot convert type 'byte[]' to 'C3'\n    }\n}\n\nclass C2\n{\n    public static implicit operator C2(Span<byte> x) => new C2();\n}\n\nclass C3\n{\n    public static explicit operator C3(ReadOnlySpan<byte> x) => new C3();\n}\n```\nHowever, as with any user-defined conversion, an explicit cast can be used to make one user-defined conversion a part of another user-defined conversion.\n\nIt feels like all motivating scenarios are going to be addressed with `byte[]` as the natural type, but the language rules and implementation will be significantly simpler.\n\n*Resolution:*\n\nThe proposal is approved - https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#natural-type-of-u8-literals.\nWe will likely want to have a deeper debate about whether `u8` string literals should have a type of a mutable array, but we don't\nthink that debate is necessary for now.\n\nOnly the explicit conversion operator has been implemented.\n\n### (Resolved) Depth of the conversion\nWill it also work anywhere that a byte[] could work? Consider: \n\n```c# \nstatic readonly ReadOnlyMemory<byte> s_data1 = \"Data\"u8;\nstatic readonly ReadOnlyMemory<byte> s_data2 = \"Data\";\n```\n\nThe first example likely should work because of the natural type that comes from `u8`.\n\nThe second example is hard to make work because it requires conversions in both directions. That is unless we add `ReadOnlyMemory<byte>` as one of the allowed conversion types. \n\n*Proposal:* \n\nDon't do anything special.\n\n*Resolution:*\n\nNo new conversion targets added for now https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#conversion-depth. Neither conversion compiles.\n\n### (Resolved) Overload resolution breaks\n\nThe following API would become ambiguous:\n\n```c#\nM(\"\");\nstatic void M1(ReadOnlySpan<char> charArray) => ...;\nstatic void M1(byte[] byteArray) => ...;\n```\n\nWhat should we do to address this?\n\n*Proposal:* \n\nSimilar to https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/lambda-improvements.md#overload-resolution, Better function member ([§11.6.4.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12643-better-function-member)) is updated to prefer members where none of the conversions involved require converting `string` constants to UTF8 `byte` sequences.\n\n> #### Better function member\n> ...\n> Given an argument list `A` with a set of argument expressions `{E1, E2, ..., En}` and two applicable function members `Mp` and `Mq` with parameter types `{P1, P2, ..., Pn}` and `{Q1, Q2, ..., Qn}`, `Mp` is defined to be a ***better function member*** than `Mq` if\n>\n> 1. **for each argument, the implicit conversion from `Ex` to `Px` is not a _string_constant_to_UTF8_byte_representation_conversion_, and for at least one argument, the implicit conversion from `Ex` to `Qx` is a _string_constant_to_UTF8_byte_representation_conversion_, or**\n> 2. for each argument, the implicit conversion from `Ex` to `Px` is not a _function_type_conversion_, and\n>    *  `Mp` is a non-generic method or `Mp` is a generic method with type parameters `{X1, X2, ..., Xp}` and for each type parameter `Xi` the type argument is inferred from an expression or from a type other than a _function_type_, and\n>    *  for at least one argument, the implicit conversion from `Ex` to `Qx` is a _function_type_conversion_, or `Mq` is a generic method with type parameters `{Y1, Y2, ..., Yq}` and for at least one type parameter `Yi` the type argument is inferred from a _function_type_, or\n> 3. for each argument, the implicit conversion from `Ex` to `Qx` is not better than the implicit conversion from `Ex` to `Px`, and for at least one argument, the conversion from `Ex` to `Px` is better than the conversion from `Ex` to `Qx`.\n\nNote that the addition of this rule is not going to cover scenarios with instance methods becoming applicable and \"shadowing\" extension methods. For example:\n``` C#\nusing System;\n\nclass Program\n{\n    static void Main()\n    {\n        var p = new Program();\n        Console.WriteLine(p.M(\"\"));\n    }\n\n    public string M(byte[] b) => \"byte[]\";\n}\n\nstatic class E\n{\n    public static string M(this object o, string s) => \"string\";\n}\n```\nBehavior of this code will silently change from printing \"string\" to printing \"byte[]\".\n\nAre we Ok with this behavior change? Should it be documented as a breaking change?\n\nNote that there is no proposal to make _string_constant_to_UTF8_byte_representation_conversion_ unavailable when C#10 language version is targeted. In that case, the example above becomes an error rather than returns to C#10 behavior. This follows a general principle that target language version doesn't affect semantics of the language.\n\nAre we Ok with this behavior? Should it be documented as a breaking change?\n\nThe new rule also is not going to prevent breaks involving tuple literal conversions. For example,\n``` C#\nclass C\n{\n    static void Main()\n    {\n        System.Console.Write(Test((\"s\", 1)));\n    }\n\n    static string Test((object, int) a) => \"object\";\n    static string Test((byte[], int) a) => \"array\";\n}\n```\nis going to silently print \"array\" instead of \"object\". \n\nAre we Ok with this behavior? Should it be documented as a breaking change? Perhaps we could complicate the new rule to dig into the tuple literal conversions.\n\n*Resolution:*\n\nThe prototype will not adjust any rules here, so we can hopefully see what breaks in practice - https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#breaking-changes.\n\n### (Resolved) Should `u8` suffix be case-insensitive?\n\n*Proposal:* \n\nSupport `U8` suffix as well for consistency with numeric suffixes.\n\n*Resolution:*\n\nApproved - https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#suffix-case-sensitivity.\n\n## Examples today\nExamples of where runtime has manually encoded the UTF8 bytes today\n\n- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/Common/src/System/Net/Http/aspnetcore/Http2/Hpack/StatusCodes.cs#L13-L78\n- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Memory/src/System/Buffers/Text/Base64Encoder.cs#L581-L591\n- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Net.HttpListener/src/System/Net/Windows/HttpResponseStream.Windows.cs#L284\n- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs#L30\n- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs#L852\n- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs#L35-L42\n \nExamples where we leave perf on the table\n- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Net.Security/src/System/Net/Security/Pal.Managed/SafeChannelBindingHandle.cs#L16-L17\n- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs#L37-L43\n- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs#L78\n- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpCommands.cs#L669-L687\n\n## Design meetings\n\nhttps://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md\nhttps://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-04-18.md\nhttps://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-06-06.md\n"
  },
  {
    "path": "proposals/csharp-12.0/collection-expressions.md",
    "content": "# Collection expressions\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/8652>\n\n## Summary\n[summary]: #summary\n\nCollection expressions introduce a new terse syntax, `[e1, e2, e3, etc]`, to create common collection values.  Inlining other collections into these values is possible using a spread element `..e` like so: `[e1, ..c2, e2, ..c2]`.\n\nSeveral collection-like types can be created without requiring external BCL support.  These types are:\n\n* [Array types](https://github.com/dotnet/csharplang/blob/main/spec/types.md#array-types), such as `int[]`.\n* [`Span<T>`](https://learn.microsoft.com/dotnet/api/system.span-1) and [`ReadOnlySpan<T>`](https://learn.microsoft.com/dotnet/api/system.readonlyspan-1).\n* Types that support [collection initializers](https://github.com/dotnet/csharplang/blob/main/spec/expressions.md#collection-initializers), such as [`List<T>`](https://learn.microsoft.com/dotnet/api/system.collections.generic.list-1).\n\nFurther support is present for collection-like types not covered under the above through a new attribute and API pattern that can be adopted directly on the type itself.\n\n## Motivation\n[motivation]: #motivation\n\n* Collection-like values are hugely present in programming, algorithms, and especially in the C#/.NET ecosystem.  Nearly all programs will utilize these values to store data and send or receive data from other components. Currently, almost all C# programs must use many different and unfortunately verbose approaches to create instances of such values. Some approaches also have performance drawbacks. Here are some common examples:\n\n  * Arrays, which require either `new Type[]` or `new[]` before the `{ ... }` values.\n  * Spans, which may use `stackalloc` and other cumbersome constructs.\n  * Collection initializers, which require syntax like `new List<T>` (lacking inference of a possibly verbose `T`) prior to their values, and which can cause multiple reallocations of memory because they use N `.Add` invocations without supplying an initial capacity.\n  * Immutable collections, which require syntax like `ImmutableArray.Create(...)` to initialize the values, and which can cause intermediary allocations and data copying. More efficient construction forms (like `ImmutableArray.CreateBuilder`) are unwieldy and still produce unavoidable garbage.\n\n* Looking at the surrounding ecosystem, we also find examples everywhere of list creation being more convenient and pleasant to use.  TypeScript, Dart, Swift, Elm, Python, and more opt for a succinct syntax for this purpose, with widespread usage, and to great effect. Cursory investigations have revealed no substantive problems arising in those ecosystems with having these literals built in.\n\n* C# has also added [list patterns](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/list-patterns.md) in C# 11.  This pattern allows matching and deconstruction of list-like values using a clean and intuitive syntax.  However, unlike almost all other pattern constructs, this matching/deconstruction syntax lacks the corresponding construction syntax.\n\n* Getting the best performance for constructing each collection type can be tricky. Simple solutions often waste both CPU and memory.  Having a literal form allows for maximum flexibility from the compiler implementation to optimize the literal to produce at least as good a result as a user could provide, but with simple code.  Very often the compiler will be able to do better, and the specification aims to allow the implementation large amounts of leeway in terms of implementation strategy to ensure this.\n\nAn inclusive solution is needed for C#. It should meet the vast majority of casse for customers in terms of the collection-like types and values they already have. It should also feel natural in the language and mirror the work done in pattern matching.\n\nThis leads to a natural conclusion that the syntax should be like `[e1, e2, e3, e-etc]` or `[e1, ..c2, e2]`, which correspond to the pattern equivalents of `[p1, p2, p3, p-etc]` and `[p1, ..p2, p3]`.\n\n## Detailed design\n[design]: #detailed-design\n\nThe following [grammar](https://github.com/dotnet/csharplang/blob/main/spec/expressions.md#primary-expressions) productions are added:\n\n```diff\nprimary_no_array_creation_expression\n  ...\n+ | collection_expression\n  ;\n\n+ collection_expression\n  : '[' ']'\n  | '[' collection_element ( ',' collection_element )* ']'\n  ;\n\n+ collection_element\n  : expression_element\n  | spread_element\n  ;\n\n+ expression_element\n  : expression\n  ;\n\n+ spread_element\n  : '..' expression\n  ;\n```\n\nThe grammar for `collection_element` is known to introduce a syntax ambiguity.  Specifically `.. expr` is both exactly the production-body for `spread_element`, and is also reachable through `expression_element -> expression -> ... -> range_expression`.  There is a simple overarching\nrule for `collection_elements`.  Specifically, if the element [lexically](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/lexical-structure.md) starts with `..` then it is *always* treated as a `spread_element`.  For example, `..x ? y : z;` is always treated as a `spread_element`\n(so `.. (x ? y : z)`) even though it can be legally parsed as an expression (like `(..x) ? y : z`).\n\nThis is beneficial in two ways.  First, a compiler implementation needs only look at the very first token it sees to determine what to parse\nnext (a `spread_element` or `expression_element`).  Second, correspondingly, a user can trivially understand what sort of element they have without\nhaving to mentally try to parse what follows to see if they should think of it as a spread or an expression.\n\nCollection literals are [target-typed](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-7.1/target-typed-default.md#motivation).\n\n### Spec clarifications\n[spec-clarifications]: #spec-clarifications\n\n* For brevity, `collection_expression` will be referred to as \"literal\" in the following sections.\n* `expression_element` instances will commonly be referred to as `e1`, `e_n`, etc.\n* `spread_element` instances will commonly be referred to as `..s1`, `..s_n`, etc.\n* *span type* means either `Span<T>` or `ReadOnlySpan<T>`.\n* Literals will commonly be shown as `[e1, ..s1, e2, ..s2, etc]` to convey any number of elements in any order.  Importantly, this form will be used to represent all cases such as:\n\n  * Empty literals `[]`\n  * Literals with no `expression_element` in them.\n  * Literals with no `spread_element` in them.\n  * Literals with arbitrary ordering of any element type.\n\n* The *iteration type* of `..s_n` is the type of the *iteration variable* determined as if `s_n` were used as the expression being iterated over in a [`foreach_statement`](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md#1395-the-foreach-statement).\n* Variables starting with `__name` are used to represent the results of the evaluation of `name`, stored in a location so that it is only evaluated once.  For example `__e1` is the evaluation of `e1`.\n* `List<T>`, `IEnumerable<T>`, etc. refer to the respective types in the `System.Collections.Generic` namespace.\n* The specification defines a [translation](#collection-literal-translation) of the literal to existing C# constructs.  Similar to the [*query expression translation*](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12203-query-expression-translation), the literal is itself only legal if the translation would result in legal code.  The purpose of this rule is to avoid having to repeat other rules of the language that are implied (for example, about convertibility of expressions when assigned to storage locations).\n* An implementation is not required to translate literals exactly as specified below.  Any translation is legal if the same result is produced and there are no observable differences in the production of the result.\n  * For example, an implementation could translate literals like `[1, 2, 3]` directly to a `new int[] { 1, 2, 3 }` expression that itself bakes the raw data into the assembly, eliding the need for `__index` or a sequence of instructions to assign each value. Importantly, this does mean if any step of the translation might cause an exception at runtime that the program state is still left in the state indicated by the translation.\n\n* References to 'stack allocation' refer to any strategy to allocate on the stack and not the heap.  Importantly, it does not imply or require that that strategy be through the actual `stackalloc` mechanism.  For example, the use of [inline arrays](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/inline-arrays.md) is also an allowed and desirable approach to accomplish stack allocation where available. Note that in C# 12, inline arrays can't be initialized with a collection expression. That remains an open proposal.\n\n* Collections are assumed to be well-behaved.  For example:\n\n  * It is assumed that the value of `Count` on a collection will produce that same value as the number of elements when enumerated.\n  * The types used in this spec defined in the `System.Collections.Generic` namespace are presumed to be side-effect free.  As such, the compiler can optimize scenarios where such types might be used as intermediary values, but otherwise not be exposed.\n  * It is assumed that a call to some applicable `.AddRange(x)` member on a collection will result in the same final value as iterating over `x` and adding all of its enumerated values individually to the collection with `.Add`.\n  * The behavior of collection literals with collections that are not well-behaved is undefined.\n\n## Conversions\n[conversions]: #conversions\n\nA *collection expression conversion* allows a collection expression to be converted to a type.\n\nAn implicit *collection expression conversion* exists from a collection expression to the following types:\n* A single dimensional *array type* `T[]`, in which case the *element type* is `T`\n* A *span type*:\n  * `System.Span<T>`\n  * `System.ReadOnlySpan<T>`  \n  In which case the *element type* is `T`\n* A *type* with an appropriate *[create method](#create-methods)*, in which case the *element type* is the [*iteration type*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/statements.md#1295-the-foreach-statement) determined from a `GetEnumerator` instance method or enumerable interface, not from an extension method\n* A *struct* or *class type* that implements `System.Collections.IEnumerable` where:\n  * The *type* has an *[applicable](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/expressions.md#11642-applicable-function-member)* constructor that can be invoked with no arguments, and the constructor is accessible at the location of the collection expression.\n  * If the collection expression has any elements, the *type* has an instance or extension method `Add` where:\n    * The method can be invoked with a single value argument.\n    * If the method is generic, the type arguments can be inferred from the collection and argument.\n    * The method is accessible at the location of the collection expression.\n\n    In which case the *element type* is the [*iteration type*](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md#1395-the-foreach-statement) of the *type*.\n* An *interface type*:\n  * `System.Collections.Generic.IEnumerable<T>`\n  * `System.Collections.Generic.IReadOnlyCollection<T>`\n  * `System.Collections.Generic.IReadOnlyList<T>`\n  * `System.Collections.Generic.ICollection<T>`\n  * `System.Collections.Generic.IList<T>`  \n  In which case the *element type* is `T`\n\nThe implicit conversion exists if the type has an *element type* `T` where for each *element* `Eᵢ` in the collection expression:\n* If `Eᵢ` is an *expression element*, there is an implicit conversion from `Eᵢ` to `T`.\n* If `Eᵢ` is a *spread element* `..Sᵢ`, there is an implicit conversion from the *iteration type* of `Sᵢ` to `T`.\n\nThere is no *collection expression conversion* from a collection expression to a multi dimensional *array type*.\n\nTypes for which there is an implicit collection expression conversion from a collection expression are the valid *target types* for that collection expression.\n\nThe following additional implicit conversions exist from a *collection expression*:\n\n* To a *nullable value type* `T?` where there is a *collection expression conversion* from the collection expression to a value type `T`. The conversion is a *collection expression conversion* to `T` followed by an *implicit nullable conversion* from `T` to `T?`.\n\n* To a reference type `T` where there is a *[create method](#create-methods)* associated with `T` that returns a type `U` and an *implicit reference conversion* from `U` to `T`. The conversion is a *collection expression conversion* to `U` followed by an *implicit reference conversion* from `U` to `T`.\n\n* To an interface type `I` where there is a *[create method](#create-methods)* associated with `I` that returns a type `V` and an *implicit boxing conversion* from `V` to `I`. The conversion is a *collection expression conversion* to `V` followed by an *implicit boxing conversion* from `V` to `I`.\n\n## Create methods\n[create-methods]: #create-methods\n\nA *create method* is indicated with a `[CollectionBuilder(...)]` attribute on the *collection type*.\nThe attribute specifies the *builder type* and *method name* of a method to be invoked to construct an instance of the collection type.\n\n```c#\nnamespace System.Runtime.CompilerServices\n{\n    [AttributeUsage(\n        AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface,\n        Inherited = false,\n        AllowMultiple = false)]\n    public sealed class CollectionBuilderAttribute : System.Attribute\n    {\n        public CollectionBuilderAttribute(Type builderType, string methodName);\n        public Type BuilderType { get; }\n        public string MethodName { get; }\n    }\n}\n```\nThe attribute can be applied to a `class`, `struct`, `ref struct`, or `interface`.\nThe attribute is not inherited although the attribute can be applied to a base `class` or an `abstract class`.\n\nThe *builder type* must be a non-generic `class` or `struct`.\n\nFirst, the set of applicable *create methods* `CM` is determined.  \nIt consists of methods that meet the following requirements:\n\n* The method must have the name specified in the `[CollectionBuilder(...)]` attribute. \n* The method must be defined on the *builder type* directly.\n* The method must be `static`.\n* The method must be accessible where the collection expression is used.\n* The *arity* of the method must match the *arity* of the collection type.\n* The method must have a single parameter of type `System.ReadOnlySpan<E>`, passed by value.\n* There is an [*identity conversion*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/conversions.md#1022-identity-conversion), [*implicit reference conversion*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/conversions.md#1028-implicit-reference-conversions), or [*boxing conversion*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/conversions.md#1029-boxing-conversions) from the method return type to the *collection type*.\n\nMethods declared on base types or interfaces are ignored and not part of the `CM` set.\n\nIf the `CM` set is empty, then the *collection type* doesn't have an *element type* and doesn't have a *create method*. None of the following steps apply.\n\nIf only one method among those in the `CM` set has an [*identity conversion*](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#1022-identity-conversion) from `E` to the *element type* of the *collection type*, that is the *create method* for the *collection type*. Otherwise, the *collection type* doesn't have a *create method*.\n\nAn error is reported if the `[CollectionBuilder]` attribute does not refer to an invokable method with the expected signature.\n\nFor a *collection expression* with a target type <code>C&lt;S<sub>0</sub>, S<sub>1</sub>, &mldr;&gt;</code> where the *type declaration* <code>C&lt;T<sub>0</sub>, T<sub>1</sub>, &mldr;&gt;</code> has an associated *builder method* <code>B.M&lt;U<sub>0</sub>, U<sub>1</sub>, &mldr;&gt;()</code>, the *generic type arguments* from the target type are applied in order &mdash; and from outermost containing type to innermost &mdash; to the *builder method*.\n\nThe span parameter for the *create method* can be explicitly marked `scoped` or `[UnscopedRef]`. If the parameter is implicitly or explicitly `scoped`, the compiler *may* allocate the storage for the span on the stack rather than the heap.\n\nFor example, a possible *create method* for `ImmutableArray<T>`:\n\n```csharp\n[CollectionBuilder(typeof(ImmutableArray), \"Create\")]\npublic struct ImmutableArray<T> { ... }\n\npublic static class ImmutableArray\n{\n    public static ImmutableArray<T> Create<T>(ReadOnlySpan<T> items) { ... }\n}\n```\n\nWith the *create method* above, `ImmutableArray<int> ia = [1, 2, 3];` could be emitted as:\n\n```csharp\n[InlineArray(3)] struct __InlineArray3<T> { private T _element0; }\n\nSpan<int> __tmp = new __InlineArray3<int>();\n__tmp[0] = 1;\n__tmp[1] = 2;\n__tmp[2] = 3;\nImmutableArray<int> ia =\n    ImmutableArray.Create((ReadOnlySpan<int>)__tmp);\n```\n\n## Construction\n[construction]: #construction\n\nThe elements of a collection expression are *evaluated* in order, left to right.\nEach element is evaluated exactly once, and any further references to the elements refer to the results of this initial evaluation.\n\nA spread element may be *iterated* before or after the subsequent elements in the collection expression are *evaluated*.\n\nAn unhandled exception thrown from any of the methods used during construction will be uncaught and will prevent further steps in the construction.\n\n`Length`, `Count`, and `GetEnumerator` are assumed to have no side effects.\n\n---\n\nIf the target type is a *struct* or *class type* that implements `System.Collections.IEnumerable`, and the target type does not have a *[create method](#create-methods)*, the construction of the collection instance is as follows:\n\n* The elements are evaluated in order. Some or all elements may be evaluated *during* the steps below rather than before.\n\n* The compiler *may* determine the *known length* of the collection expression by invoking [*countable*](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-8.0/ranges.md#adding-index-and-range-support-to-existing-library-types) properties &mdash; or equivalent properties from well-known interfaces or types &mdash; on each *spread element expression*.\n\n* The constructor that is applicable with no arguments is invoked.\n\n* For each element in order:\n  * If the element is an *expression element*, the applicable `Add` instance or extension method is invoked with the element *expression* as the argument. (Unlike classic [*collection initializer behavior*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/expressions.md#117154-collection-initializers), element evaluation and `Add` calls are not necessarily interleaved.)\n  * If the element is a *spread element* then one of the following is used:\n    * An applicable `GetEnumerator` instance or extension method is invoked on the *spread element expression* and for each item from the enumerator the applicable `Add` instance or extension method is invoked on the *collection instance* with the item as the argument. If the enumerator implements `IDisposable`, then `Dispose` will be called after enumeration, regardless of exceptions.\n    * An applicable `AddRange` instance or extension method is invoked on the *collection instance* with the spread element *expression* as the argument.\n    * An applicable `CopyTo` instance or extension method is invoked on the *spread element expression* with the collection instance and `int` index as arguments.\n\n* During the construction steps above, an applicable `EnsureCapacity` instance or extension method *may* be invoked one or more times on the *collection instance* with an `int` capacity argument.\n\n---\n\nIf the target type is an *array*, a *span*, a type with a *[create method](#create-methods)*, or an *interface*, the construction of the collection instance is as follows:\n\n* The elements are evaluated in order. Some or all elements may be evaluated *during* the steps below rather than before.\n\n* The compiler *may* determine the *known length* of the collection expression by invoking [*countable*](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-8.0/ranges.md#adding-index-and-range-support-to-existing-library-types) properties &mdash; or equivalent properties from well-known interfaces or types &mdash; on each *spread element expression*.\n\n* An *initialization instance* is created as follows:\n  * If the target type is an *array* and the collection expression has a *known length*, an array is allocated with the expected length.\n  * If the target type is a *span* or a type with a *create method*, and the collection has a *known length*, a span with the expected length is created referring to contiguous storage.\n  * Otherwise intermediate storage is allocated.\n\n* For each element in order:\n  * If the element is an *expression element*, the initialization instance *indexer* is invoked to add the evaluated expression at the current index.\n  * If the element is a *spread element* then one of the following is used:\n    * A member of a well-known interface or type is invoked to copy items from the spread element expression to the initialization instance.\n    * An applicable `GetEnumerator` instance or extension method is invoked on the *spread element expression* and for each item from the enumerator, the initialization instance *indexer* is invoked to add the item at the current index. If the enumerator implements `IDisposable`, then `Dispose` will be called after enumeration, regardless of exceptions.\n    * An applicable `CopyTo` instance or extension method is invoked on the *spread element expression* with the initialization instance and `int` index as arguments.\n\n* If intermediate storage was allocated for the collection, a collection instance is allocated with the actual collection length and the values from the initialization instance are copied to the collection instance, or if a span is required the compiler *may* use a span of the actual collection length from the intermediate storage. Otherwise the initialization instance is the collection instance.\n\n* If the target type has a *create method*, the create method is invoked with the span instance.\n\n---\n\n> *Note:*\n> The compiler may *delay* adding elements to the collection &mdash; or *delay* iterating through spread elements &mdash; until after evaluating subsequent elements. (When subsequent spread elements have *countable* properties that would allow calculating the expected length of the collection before allocating the collection.) Conversely, the compiler may *eagerly* add elements to the collection &mdash; and *eagerly* iterate through spread elements &mdash; when there is no advantage to delaying.\n>\n> Consider the following collection expression:\n> ```c#\n> int[] x = [a, ..b, ..c, d];\n> ```\n> \n> If spread elements `b` and `c` are *countable*, the compiler could delay adding items from `a` and `b` until after `c` is evaluated, to allow allocating the resulting array at the expected length. After that, the compiler could eagerly add items from `c`, before evaluating `d`.\n> ```c#\n> var __tmp1 = a;\n> var __tmp2 = b;\n> var __tmp3 = c;\n> var __result = new int[2 + __tmp2.Length + __tmp3.Length];\n> int __index = 0;\n> __result[__index++] = __tmp1;\n> foreach (var __i in __tmp2) __result[__index++] = __i;\n> foreach (var __i in __tmp3) __result[__index++] = __i;\n> __result[__index++] = d;\n> x = __result;\n> ```\n\n## Empty collection literal\n\n* The empty literal `[]` has no type.  However, similar to the [*null-literal*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/lexical-structure.md#6457-the-null-literal), this literal can be implicitly converted to any [*constructible*](#conversions) collection type.\n\n    For example, the following is not legal as there is no *target type* and there are no other conversions involved:\n\n    ```c#\n    var v = []; // illegal\n    ```\n\n* Spreading an empty literal is permitted to be elided.  For example:\n\n    ```c#\n    bool b = ...\n    List<int> l = [x, y, .. b ? [1, 2, 3] : []];\n    ```\n\n    Here, if `b` is false, it is not required that any value actually be constructed for the empty collection expression since it would immediately be spread into zero values in the final literal.\n\n* The empty collection expression is permitted to be a singleton if used to construct a final collection value that is known to not be mutable.  For example:\n\n    ```c#\n    // Can be a singleton, like Array.Empty<int>()\n    int[] x = []; \n\n    // Can be a singleton. Allowed to use Array.Empty<int>(), Enumerable.Empty<int>(),\n    // or any other implementation that can not be mutated.\n    IEnumerable<int> y = [];\n\n    // Must not be a singleton.  Value must be allowed to mutate, and should not mutate\n    // other references elsewhere.\n    List<int> z = [];\n    ```\n\n## Ref safety\n[ref-safety]: #ref-safety\n\nSee [*safe context constraint*](https://github.com/dotnet/csharpstandard/blob/draft-v7/standard/structs.md#164121-general) for definitions of the *safe-context* values: *declaration-block*, *function-member*, and *caller-context*.\n\nThe *safe-context* of a collection expression is:\n\n* The safe-context of an empty collection expression `[]` is the *caller-context*.\n\n* If the target type is a *span type* `System.ReadOnlySpan<T>`, and `T` is one of the *primitive types* `bool`, `sbyte`, `byte`, `short`, `ushort`, `char`, `int`, `uint`, `long`, `ulong`, `float`, or `double`, and the collection expression contains *constant values only*, the safe-context of the collection expression is the *caller-context*.\n\n* If the target type is a *span type* `System.Span<T>` or `System.ReadOnlySpan<T>`, the safe-context of the collection expression is the *declaration-block*.\n\n* If the target type is a *ref struct type* with a [*create method*](#create-methods), the safe-context of the collection expression is the [*safe-context of an invocation*](https://github.com/dotnet/csharpstandard/blob/draft-v7/standard/structs.md#164126-method-and-property-invocation) of the create method where the collection expression is the span argument to the method.\n\n* Otherwise the safe-context of the collection expression is the *caller-context*.\n\nA collection expression with a safe-context of *declaration-block* cannot escape the enclosing scope, and the compiler *may* store the collection on the stack rather than the heap.\n\nTo allow a collection expression for a ref struct type to escape the *declaration-block*, it may be necessary to cast the expression to another type.\n\n```csharp\nstatic ReadOnlySpan<int> AsSpanConstants()\n{\n    return [1, 2, 3]; // ok: span refers to assembly data section\n}\n\nstatic ReadOnlySpan<T> AsSpan2<T>(T x, T y)\n{\n    return [x, y];    // error: span may refer to stack data\n}\n\nstatic ReadOnlySpan<T> AsSpan3<T>(T x, T y, T z)\n{\n    return (T[])[x, y, z]; // ok: span refers to T[] on heap\n}\n```\n\n## Type inference\n[type-inference]: #type-inference\n\n```c#\nvar a = AsArray([1, 2, 3]);          // AsArray<int>(int[])\nvar b = AsListOfArray([[4, 5], []]); // AsListOfArray<int>(List<int[]>)\n\nstatic T[] AsArray<T>(T[] arg) => arg;\nstatic List<T[]> AsListOfArray<T>(List<T[]> arg) => arg;\n```\n\nThe [*type inference*](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1263-type-inference) rules are updated as follows.\n\nThe existing rules for the [*first phase*](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12632-the-first-phase) are extracted to a new *input type inference* section, and a  rule is added to *input type inference* and *output type inference* for collection expression expressions.\n\n> 11.6.3.2 The first phase\n>\n> For each of the method arguments `Eᵢ`:\n>\n> * An *input type inference* is made *from* `Eᵢ` *to* the corresponding *parameter type* `Tᵢ`.\n>\n> An *input type inference* is made *from* an expression `E` *to* a type `T` in the following way:\n>\n> * If `E` is a *collection expression* with elements `Eᵢ`, and `T` is a type with an *element type* `Tₑ` or `T` is a *nullable value type* `T0?` and `T0` has an *element type* `Tₑ`, then for each `Eᵢ`:\n>   * If `Eᵢ` is an *expression element*, then an *input type inference* is made *from* `Eᵢ` *to* `Tₑ`.\n>   * If `Eᵢ` is a *spread element* with an [*iteration type*](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md#1395-the-foreach-statement) `Sᵢ`, then a [*lower-bound inference*](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#126310-lower-bound-inferences) is made *from* `Sᵢ` *to* `Tₑ`.\n> * *[existing rules from first phase]* ...\n\n> 11.6.3.7 Output type inferences\n>\n> An *output type inference* is made *from* an expression `E` *to* a type `T` in the following way:\n>\n> * If `E` is a *collection expression* with elements `Eᵢ`, and `T` is a type with an *element type* `Tₑ` or `T` is a *nullable value type* `T0?` and `T0` has an *element type* `Tₑ`, then for each `Eᵢ`:\n>   * If `Eᵢ` is an *expression element*, then an *output type inference* is made *from* `Eᵢ` *to* `Tₑ`.\n>   * If `Eᵢ` is a *spread element*, no inference is made from `Eᵢ`.\n> * *[existing rules from output type inferences]* ...\n\n## Extension methods\n\nNo changes to [*extension method invocation*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/expressions.md#128103-extension-method-invocations) rules. \n\n> 12.8.10.3 Extension method invocations\n>\n> An extension method `Cᵢ.Mₑ` is *eligible* if:\n>\n> * ...\n> * An implicit identity, reference, or boxing conversion exists from *expr* to the type of the first parameter of `Mₑ`.\n\nA collection expression does not have a natural type so the existing conversions from *type* are not applicable. As a result, a collection expression cannot be used directly as the first parameter for an extension method invocation.\n\n```c#\nstatic class Extensions\n{\n    public static ImmutableArray<T> AsImmutableArray<T>(this ImmutableArray<T> arg) => arg;\n}\n\nvar x = [1].AsImmutableArray();           // error: collection expression has no target type\nvar y = [2].AsImmutableArray<int>();      // error: ...\nvar z = Extensions.AsImmutableArray([3]); // ok\n```\n\n## Overload resolution\n[overload-resolution]: #overload-resolution\n\n[*Better conversion from expression*](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12645-better-conversion-from-expression) is updated to prefer certain target types in collection expression conversions.\n\nIn the updated rules:\n* A *span_type* is one of:\n  * `System.Span<T>`\n  * `System.ReadOnlySpan<T>`.\n* An *array_or_array_interface* is one of:\n  * an *array type*\n  * one of the following *interface types* implemented by an *array type*:\n    * `System.Collections.Generic.IEnumerable<T>`\n    * `System.Collections.Generic.IReadOnlyCollection<T>`\n    * `System.Collections.Generic.IReadOnlyList<T>`\n    * `System.Collections.Generic.ICollection<T>`\n    * `System.Collections.Generic.IList<T>`\n\n> Given an implicit conversion `C₁` that converts from an expression `E` to a type `T₁`, and an implicit conversion `C₂` that converts from an expression `E` to a type `T₂`, `C₁` is a ***better conversion*** than `C₂` if one of the following holds:\n>\n> * **`E` is a *collection expression* and one of the following holds:**\n>   * **`T₁` is `System.ReadOnlySpan<E₁>`, and `T₂` is `System.Span<E₂>`, and an implicit conversion exists from `E₁` to `E₂`**\n>   * **`T₁` is `System.ReadOnlySpan<E₁>` or `System.Span<E₁>`, and `T₂` is an *array_or_array_interface* with *element type* `E₂`, and an implicit conversion exists from `E₁` to `E₂`**\n>   * **`T₁` is not a *span_type*, and `T₂` is not a *span_type*, and an implicit conversion exists from `T₁` to `T₂`**\n> * **`E` is not a *collection expression* and one of the following holds:**\n>   * `E` exactly matches `T₁` and `E` does not exactly match `T₂`\n>   * `E` exactly matches both or neither of `T₁` and `T₂`, and `T₁` is a [*better conversion target*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/expressions.md#11646-better-conversion-target) than `T₂`\n> * `E` is a method group, ...\n\nExamples of differences with overload resolution between array initializers and collection expressions:\n```c#\nstatic void Generic<T>(Span<T> value) { }\nstatic void Generic<T>(T[] value) { }\n\nstatic void SpanDerived(Span<string> value) { }\nstatic void SpanDerived(object[] value) { }\n\nstatic void ArrayDerived(Span<object> value) { }\nstatic void ArrayDerived(string[] value) { }\n\n// Array initializers\nGeneric(new[] { \"\" });      // string[]\nSpanDerived(new[] { \"\" });  // ambiguous\nArrayDerived(new[] { \"\" }); // string[]\n\n// Collection expressions\nGeneric([\"\"]);              // Span<string>\nSpanDerived([\"\"]);          // Span<string>\nArrayDerived([\"\"]);         // ambiguous\n```\n\n## Span types\n[span-types]: #span-types\n\nThe span types `ReadOnlySpan<T>` and `Span<T>` are both [*constructible collection types*](#conversions).  Support for them follows the design for [`params Span<T>`](https://github.com/dotnet/csharplang/blob/main/proposals/rejected/params-span.md). Specifically, constructing either of those spans will result in an array T[] created on the [stack](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/unsafe-code.md#229-stack-allocation) if the params array is within limits (if any) set by the compiler. Otherwise the array will be allocated on the heap.\n\nIf the compiler chooses to allocate on the stack, it is not required to translate a literal directly to a `stackalloc` at that specific point.  For example, given:\n\n```c#\nforeach (var x in y)\n{\n    Span<int> span = [a, b, c];\n    // do things with span\n}\n```\n\nThe compiler is allowed to translate that using `stackalloc` as long as the `Span` meaning stays the same and [*span-safety*](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-7.2/span-safety.md) is maintained.  For example, it can translate the above to:\n\n```c#\nSpan<int> __buffer = stackalloc int[3];\nforeach (var x in y)\n{\n    __buffer[0] = a\n    __buffer[1] = b\n    __buffer[2] = c;\n    Span<int> span = __buffer;\n    // do things with span\n}\n```\n\nThe compiler can also use [inline arrays](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/inline-arrays.md), if available, when choosing to allocate on the stack. Note that in C# 12, inline arrays can't be initialized with a collection expression. That feature is an open proposal.\n\nIf the compiler decides to allocate on the heap, the translation for `Span<T>` is simply:\n\n```c#\nT[] __array = [...]; // using existing rules\nSpan<T> __result = __array;\n```\n\n## Collection literal translation\n[collection-literal-translation]: #collection-literal-translation\n\nA collection expression has a *known length* if the compile-time type of each *spread element* in the collection expression is [*countable*](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-8.0/ranges.md#adding-index-and-range-support-to-existing-library-types).\n\n### Interface translation\n[interface-translation]: #interface-translation\n\n#### Non-mutable interface translation\n[non-mutable-interface-translation]: #non-mutable-interface-translation\n\nGiven a target type which does not contain mutating members, namely `IEnumerable<T>`, `IReadOnlyCollection<T>`, and `IReadOnlyList<T>`, a compliant implementation is required to produce a value that implements that interface. If a type is synthesized, it is recommended the synthesized type implements all these interfaces, as well as `ICollection<T>` and `IList<T>`, regardless of which interface type was targeted. This ensures maximal compatibility with existing libraries, including those that introspect the interfaces implemented by a value in order to light up performance optimizations.\n\nIn addition, the value must implement the nongeneric `ICollection` and `IList` interfaces. This enables collection expressions to support dynamic introspection in scenarios such as data binding.\n\nA compliant implementation is free to:\n\n1. Use an existing type that implements the required interfaces.\n1. Synthesize a type that implements the required interfaces.\n\nIn either case, the type used is allowed to implement a larger set of interfaces than those strictly required.\n\nSynthesized types are free to employ any strategy they want to implement the required interfaces properly.  For example, a synthesized type might inline the elements directly within itself, avoiding the need for additional internal collection allocations.  A synthesized type could also not use any storage whatsoever, opting to compute the values directly.  For example, returning `index + 1` for `[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]`.\n\n1. The value must return `true` when queried for `ICollection<T>.IsReadOnly` (if implemented) and nongeneric `IList.IsReadOnly` and `IList.IsFixedSize`.  This ensures consumers can appropriately tell that the collection is non-mutable, despite implementing the mutable views.\n1. The value must throw on any call to a mutation method (like `IList<T>.Add`).  This ensures safety, preventing a non-mutable collection from being accidentally mutated.\n\n#### Mutable interface translation\n[mutable-interface-translation]: #mutable-interface-translation\n\nGiven target type that contains mutating members, namely `ICollection<T>` or `IList<T>`:\n\n1. The value must be an instance of `List<T>`.\n\n### Known length translation\n[known-length-translation]: #known-length-translation\n\nHaving a *known length* allows for efficient construction of a result with the potential for no copying of data and no unnecessary slack space in a result.\n\nNot having a *known length* does not prevent any result from being created. However, it may result in extra CPU and memory costs producing the data, then moving to the final destination.\n\n* For a *known length* literal `[e1, ..s1, etc]`, the translation first starts with the following:\n\n  ```c#\n  int __len = count_of_expression_elements +\n              __s1.Count;\n              ...\n              __s_n.Count;\n    ```\n\n* Given a target type `T` for that literal:\n\n  * If `T` is some `T1[]`, then the literal is translated as:\n\n    ```c#\n    T1[] __result = new T1[__len];\n    int __index = 0;\n\n    __result[__index++] = __e1;\n    foreach (T1 __t in __s1)\n        __result[__index++] = __t;\n\n    // further assignments of the remaining elements\n    ```\n\n    The implementation is allowed to utilize other means to populate the array.  For example, utilizing efficient bulk-copy methods like `.CopyTo()`.\n\n  * If `T` is some `Span<T1>`, then the literal is translated as the same as above, except that the `__result` initialization is translated as:\n\n    ```c#\n    Span<T1> __result = new T1[__len];\n\n    // same assignments as the array translation\n    ```\n\n    The translation may use `stackalloc T1[]` or an [*inline array*](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/inline-arrays.md) rather than `new T1[]` if [*span-safety*](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-7.2/span-safety.md) is maintained.\n\n  * If `T` is some `ReadOnlySpan<T1>`, then the literal is translated the same as for the `Span<T1>` case except that the final result will be that `Span<T1>` [implicitly converted](https://learn.microsoft.com/dotnet/api/system.span-1.op_implicit#system-span-1-op-implicit(system-span((-0)))-system-readonlyspan((-0))) to a `ReadOnlySpan<T1>`.\n\n    A `ReadOnlySpan<T1>` where `T1` is some primitive type, and all collection elements are constant does not need its data to be on the heap, or on the stack.  For example, an implementation could construct this span directly as a reference to portion of the data segment of the program.\n\n    The above forms (for arrays and spans) are the base representations of the collection expression and are used for the following translation rules:\n\n    * If `T` is some `C<S0, S1, …>` which has a corresponding [create-method](#create-methods) `B.M<U0, U1, …>()`, then the literal is translated as:\n\n      ```c#\n      // Collection literal is passed as is as the single B.M<...>(...) argument\n      C<S0, S1, …> __result = B.M<S0, S1, …>([...])\n      ```\n\n      As the *create method* must have an argument type of some instantiated `ReadOnlySpan<T>`, the translation rule for spans applies when passing the collection expression to the create method.\n\n    * If `T` supports [collection initializers](https://github.com/dotnet/csharplang/blob/main/spec/expressions.md#collection-initializers), then:\n\n      * if the type `T` contains an accessible constructor with a single parameter `int capacity`, then the literal is translated as:\n\n        ```c#\n        T __result = new T(capacity: __len);\n        __result.Add(__e1);\n        foreach (var __t in __s1)\n            __result.Add(__t);\n\n        // further additions of the remaining elements\n        ```\n\n        Note: the name of the parameter is required to be `capacity`.\n\n        This form allows for a literal to inform the newly constructed type of the count of elements to allow for efficient allocation of internal storage.  This avoids wasteful reallocations as the elements are added.\n\n      * otherwise, the literal is translated as:\n\n        ```c#\n        T __result = new T();\n\n        __result.Add(__e1);\n        foreach (var __t in __s1)\n            __result.Add(__t);\n\n        // further additions of the remaining elements\n        ```\n\n        This allows creating the target type, albeit with no capacity optimization to prevent internal reallocation of storage.\n\n### Unknown length translation\n[unknown-length-translation]: #unknown-length-translation\n\n* Given a target type `T` for an *unknown length* literal:\n\n  * If `T` supports [collection initializers](https://github.com/dotnet/csharplang/blob/main/spec/expressions.md#collection-initializers), then the literal is translated as:\n\n    ```c#\n    T __result = new T();\n\n    __result.Add(__e1);\n    foreach (var __t in __s1)\n        __result.Add(__t);\n\n    // further additions of the remaining elements\n    ```\n\n    This allows spreading of any iterable type, albeit with the least amount of optimization possible.\n\n  * If `T` is some `T1[]`, then the literal has the same semantics as:\n\n    ```c#\n    List<T1> __list = [...]; /* initialized using predefined rules */\n    T1[] __result = __list.ToArray();\n    ```\n\n    The above is inefficient though; it creates the intermediary list, and then creates a copy of the final array from it.  Implementations are free to optimize this away, for example producing code like so:\n\n    ```c#\n    T1[] __result = <private_details>.CreateArray<T1>(\n        count_of_expression_elements);\n    int __index = 0;\n\n    <private_details>.Add(ref __result, __index++, __e1);\n    foreach (var __t in __s1)\n        <private_details>.Add(ref __result, __index++, __t);\n\n    // further additions of the remaining elements\n\n    <private_details>.Resize(ref __result, __index);\n    ```\n\n    This allows for minimal waste and copying, without additional overhead that library collections might incur.\n\n    The counts passed to `CreateArray` are used to provide a starting size hint to prevent wasteful resizes.\n\n  * If `T` is some *span type*, an implementation may follow the above `T[]` strategy, or any other strategy with the same semantics, but better performance.  For example, instead of allocating the array as a copy of the list elements, `CollectionsMarshal.AsSpan(__list)` could be used to obtain a span value directly.\n\n## Unsupported scenarios\n[unsupported-scenarios]: #unsupported-scenarios\n\nWhile collection literals can be used for many scenarios, there are a few that they are not capable of replacing.  These include:\n\n* Multi-dimensional arrays (e.g. `new int[5, 10] { ... }`). There is no facility to include the dimensions, and all collection literals are either linear or map structures only.\n* Collections which pass special values to their constructors. There is no facility to access the constructor being used.\n* Nested collection initializers, e.g. `new Widget { Children = { w1, w2, w3 } }`.  This form needs to stay since it has very different semantics from `Children = [w1, w2, w3]`.  The former calls `.Add` repeatedly on `.Children` while the latter would assign a new collection over `.Children`.  We could consider having the latter form fall back to adding to an existing collection if `.Children` can't be assigned, but that seems like it could be extremely confusing.\n\n## Syntax ambiguities\n[syntax-ambiguities]: #syntax-ambiguities\n\n* There are two \"true\" syntactic ambiguities where there are multiple legal syntactic interpretations of code that uses a `collection_literal_expression`.\n\n  * The `spread_element` is ambiguous with a [`range_expression`](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-8.0/ranges.md#systemrange).  One could technically have:\n\n    ```c#\n    Range[] ranges = [range1, ..e, range2];\n    ```\n\n    To resolve this, we can either:\n\n    * Require users to parenthesize `(..e)` or include a start index `0..e` if they want a range.\n    * Choose a different syntax (like `...`) for spread.  This would be unfortunate for the lack of consistency with slice patterns.\n\n* There are two cases where there isn't a true ambiguity but where the syntax greatly increases parsing complexity.  While not a problem given engineering time, this does still increase cognitive overhead for users when looking at code.\n\n  * Ambiguity between `collection_literal_expression` and `attributes` on statements or local functions.  Consider:\n\n    ```c#\n    [X(), Y, Z()]\n    ```\n\n    This could be one of:\n\n    ```c#\n    // A list literal inside some expression statement\n    [X(), Y, Z()].ForEach(() => ...);\n\n    // The attributes for a statement or local function\n    [X(), Y, Z()] void LocalFunc() { }\n    ```\n\n    Without complex lookahead, it would be impossible to tell without consuming the entirety of the literal.\n\n    Options to address this include:\n\n    * Allow this, doing the parsing work to determine which of these cases this is.\n    * Disallow this, and require the user wrap the literal in parentheses like `([X(), Y, Z()]).ForEach(...)`.\n    * Ambiguity between a `collection_literal_expression` in a `conditional_expression` and a `null_conditional_operations`.  Consider:\n\n    ```c#\n    M(x ? [a, b, c]\n    ```\n\n    This could be one of:\n\n    ```c#\n    // A ternary conditional picking between two collections\n    M(x ? [a, b, c] : [d, e, f]);\n\n    // A null conditional safely indexing into 'x':\n    M(x ? [a, b, c]);\n    ```\n\n    Without complex lookahead, it would be impossible to tell without consuming the entirety of the literal.\n\n    Note: this is a problem even without a *natural type* because target typing applies through `conditional_expressions`.\n\n    As with the others, we could require parentheses to disambiguate.  In other words, presume the `null_conditional_operation` interpretation unless written like so: `x ? ([1, 2, 3]) :`.  However, that seems rather unfortunate. This sort of code does not seem unreasonable to write and will likely trip people up.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\n* This introduces [yet another form](https://xkcd.com/927/) for collection expressions on top of the myriad ways we already have. This is extra complexity for the language.  That said, this also makes it possible to unify on one ~~ring~~ syntax to rule them all, which means existing codebases can be simplified and moved to a uniform look everywhere.\n* Using `[`...`]` instead of `{`...`}` moves away from the syntax we've generally used for arrays and collection initializers already.  Specifically that it uses `[`...`]` instead of `{`...`}`.  However, this was already settled on by the language team when we did list patterns.  We attempted to make `{`...`}` work with list patterns and ran into insurmountable issues.  Because of this, we moved to `[`...`]` which, while new for C#, feels natural in many programming languages and allowed us to start fresh with no ambiguity.  Using `[`...`]` as the corresponding literal form is complementary with our latest decisions, and gives us a clean place to work without problem.\n\nThis does introduce warts into the language.  For example, the following are both legal and (fortunately) mean the exact same thing:\n\n```c#\nint[] x = { 1, 2, 3 };\nint[] x = [ 1, 2, 3 ];\n```\n\nHowever, given the breadth and consistency brought by the new literal syntax, we should consider recommending that people move to the new form.  IDE suggestions and fixes could help in that regard.\n\n## Alternatives\n[alternatives]: #alternatives\n\n* What other designs have been considered? What is the impact of not doing this?\n\n## Resolved questions\n[resolved]: #resolved-questions\n\n* Should the compiler use `stackalloc` for stack allocation when *inline arrays* are not available and the *iteration type* is a primitive type?\n\n  Resolution: No. Managing a `stackalloc` buffer requires additional effort over an *inline array* to ensure the buffer is not allocated repeatedly when the collection expression is within a loop. The additional complexity in the compiler and in the generated code outweighs the benefit of stack allocation on older platforms.\n\n* In what order should we evaluate literal elements compared with Length/Count property evaluation?  Should we evaluate all elements first, then all lengths?  Or should we evaluate an element, then its length, then the next element, and so on?\n\n  Resolution: We evaluate all elements first, then everything else follows that.\n\n* Can an *unknown length* literal create a collection type that needs a *known length*, like an array, span, or Construct(array/span) collection?  This would be harder to do efficiently, but it might be possible through clever use of pooled arrays and/or builders.\n\n  Resolution: Yes, we allow creating a fixes-length collection from an *unknown length* literal.  The compiler is permitted to implement this in as efficient a manner as possible.\n\n  The following text exists to record the original discussion of this topic.\n\n  <details>\n\n  Users could always make an *unknown length* literal into a *known length* one with code like this:\n\n  ```c#\n  ImmutableArray<int> x = [a, ..unknownLength.ToArray(), b];\n  ```\n\n  However, this is unfortunate due to the need to force allocations of temporary storage.  We could potentially be more efficient if we controlled how this was emitted.\n\n  </details>\n\n* Can a `collection_expression` be target-typed to an `IEnumerable<T>` or other collection interfaces?\n\n  For example:\n\n  ```c#\n  void DoWork(IEnumerable<long> values) { ... }\n  // Needs to produce `longs` not `ints` for this to work.\n  DoWork([1, 2, 3]);\n  ```\n\n  Resolution: Yes, a literal can be target-typed to any interface type `I<T>` that `List<T>` implements.  For example, `IEnumerable<long>`. This is the same as target-typing to `List<long>` and then assigning that result to the specified interface type. The following text exists to record the original discussion of this topic.\n\n  <details>\n\n  The open question here is determining what underlying type to actually create.  One option is to look at the proposal for [`params IEnumerable<T>`](https://github.com/dotnet/csharplang/issues/179).  There, we would generate an array to pass the values along, similar to what happens with `params T[]`.\n\n  </details>\n\n* Can/should the compiler emit `Array.Empty<T>()` for `[]`?  Should we mandate that it does this, to avoid allocations whenever possible?\n\n    Yes. The compiler should emit `Array.Empty<T>()` for any case where this is legal and the final result is non-mutable.  For example, targeting `T[]`, `IEnumerable<T>`, `IReadOnlyCollection<T>` or `IReadOnlyList<T>`.  It should not use `Array.Empty<T>` when the target is mutable (`ICollection<T>` or `IList<T>`).\n\n* Should we expand on collection initializers to look for the very common `AddRange` method? It could be used by the underlying constructed type to perform adding of spread elements potentially more efficiently.  We might also want to look for things like `.CopyTo` as well.  There may be drawbacks here as those methods might end up causing excess allocations/dispatches versus directly enumerating in the translated code.\n\n    Yes.  An implementation is allowed to utilize other methods to initialize a collection value, under the presumption that these methods have well-defined semantics, and that collection types should be \"well behaved\".  In practice though, an implementation should be cautious as benefits in one way (bulk copying) may come with negative consequences as well (for example, boxing a struct collection).\n\n    An implementation should take advantage in the cases where there are no downsides.  For example, with an `.AddRange(ReadOnlySpan<T>)` method.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n* Should we allow inferring the *element type* when the *iteration type* is \"ambiguous\" (by some definition)?\nFor example:\n```csharp\nCollection x = [1L, 2L];\n\n// error CS1640: foreach statement cannot operate on variables of type 'Collection' because it implements multiple instantiations of 'IEnumerable<T>'; try casting to a specific interface instantiation\nforeach (var x in new Collection) { }\n\nstatic class Builder\n{\n    public Collection Create(ReadOnlySpan<long> items) => throw null;\n}\n\n[CollectionBuilder(...)]\nclass Collection : IEnumerable<int>, IEnumerable<string>\n{\n    IEnumerator<int> IEnumerable<int>.GetEnumerator() => throw null;\n    IEnumerator<string> IEnumerable<string>.GetEnumerator() => throw null;\n    IEnumerator IEnumerable.GetEnumerator() => throw null;\n}\n```\n\n* Should it be legal to create and immediately index into a collection literal?  Note: this requires an answer to the unresolved question below of whether collection literals have a *natural type*.\n* Stack allocations for huge collections might blow the stack.  Should the compiler have a heuristic for placing this data on the heap?  Should the language be unspecified to allow for this flexibility?  We should follow the spec for [`params Span<T>`](https://github.com/dotnet/csharplang/issues/1757).\n* Do we need to target-type `spread_element`?  Consider, for example:\n\n  ```c#\n  Span<int> span = [a, ..b ? [c] : [d, e], f];\n  ```\n\n  Note: this may commonly come up in the following form to allow conditional inclusion of some set of elements, or nothing if the condition is false:\n\n  ```c#\n  Span<int> span = [a, ..b ? [c, d, e] : [], f];\n  ```\n\n  In order to evaluate this full literal, we need to evaluate the element expressions within.  That means being able to evaluate `b ? [c] : [d, e]`.  However, absent a target type to evaluate this expression in the context of, and absent any sort of *natural type*, this would we would be unable to determine what to do with either `[c]` or `[d, e]` here.\n\n  To resolve this, we could say that when evaluating a literal's `spread_element` expression, there was an implicit target type equivalent to the target type of the literal itself.  So, in the above, that would be rewritten as:\n\n  ```c#\n  int __e1 = a;\n  Span<int> __s1 = b ? [c] : [d, e];\n  int __e2 = f;\n\n  Span<int> __result = stackalloc int[2 + __s1.Length];\n  int __index = 0;\n\n  __result[__index++] = a;\n  foreach (int __t in __s1)\n    __result[index++] = __t;\n  __result[__index++] = f;\n\n  Span<int> span = __result;\n  ```\n\n### Specification of a [*constructible*](#conversions) collection type utilizing a [*create method*](#create-methods) is sensitive to the context at which conversion is classified\n\nAn existence of the conversion in this case depends on the notion of an [*iteration type*](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md#1395-the-foreach-statement)\nof the *collection type*. If there is a *create method* that takes a `ReadOnlySpan<T>` where `T` is the *iteration type*, the conversion exists. Otherwise, it doesn't.\n\nHowever, an [*iteration type*](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md#1395-the-foreach-statement)\nis sensitive to the context at which `foreach` is performed. For the same *collection type* it can be different based on what extension methods\nare in scope, and it can also be undefined.\n\nThat feels fine for the purpose of `foreach` when the type isn't designed to be\nforeach-able on itself. If it is, extension methods cannot change how the type is foreach-ed over, no matter what the context is.\n\nHowever, that feels somewhat strange for a conversion to be context sensitive like that. Effectively the conversion is \"unstable\".\nA *collection type* explicitly designed to be *constructible* is allowed to leave out a definition of a very important detail - its *iteration type*.\nLeaving the type \"unconvertible\" on itself.\n\nHere is an example:\n``` C#\nusing System;\nusing System.Collections.Generic;\nusing System.Runtime.CompilerServices;\n\n[CollectionBuilder(typeof(MyCollectionBuilder), nameof(MyCollectionBuilder.Create))]\nclass MyCollection\n{\n}\nclass MyCollectionBuilder\n{\n    public static MyCollection Create(ReadOnlySpan<long> items) => throw null;\n    public static MyCollection Create(ReadOnlySpan<string> items) => throw null;\n}\n\nnamespace Ns1\n{\n    static class Ext\n    {\n        public static IEnumerator<long> GetEnumerator(this MyCollection x) => throw null;\n    }\n    \n    class Program\n    {\n        static void Main()\n        {\n            foreach (var l in new MyCollection())\n            {\n                long s = l;\n            }\n        \n            MyCollection x1 = [\"a\", // error CS0029: Cannot implicitly convert type 'string' to 'long'\n                               2];\n        }\n    }\n}\n\nnamespace Ns2\n{\n    static class Ext\n    {\n        public static IEnumerator<string> GetEnumerator(this MyCollection x) => throw null;\n    }\n    \n    class Program\n    {\n        static void Main()\n        {\n            foreach (var l in new MyCollection())\n            {\n                string s = l;\n            }\n        \n            MyCollection x1 = [\"a\",\n                               2]; // error CS0029: Cannot implicitly convert type 'int' to 'string'\n        }\n    }\n}\n\nnamespace Ns3\n{\n    class Program\n    {\n        static void Main()\n        {\n            // error CS1579: foreach statement cannot operate on variables of type 'MyCollection' because 'MyCollection' does not contain a public instance or extension definition for 'GetEnumerator'\n            foreach (var l in new MyCollection())\n            {\n            }\n        \n            MyCollection x1 = [\"a\", 2]; // error CS9188: 'MyCollection' has a CollectionBuilderAttribute but no element type.\n        }\n    }\n}\n```\n\nGiven the current design, if the type doesn't define *iteration type* itself, compiler is unable to reliably validate\nan application of a `CollectionBuilder` attribute. If we don't know the *iteration type*, we don't know what the\nsignature of the *create method* should be. If the *iteration type* comes from context, there is no guarantee that\nthe type is always going to be used in a similar context.\n\n[Params Collections](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-13.0/params-collections.md#method-parameters) feature\nis also affected by this. It feels strange to be unable to reliably predict element type of a `params` parameter at the\ndeclaration point. The current proposal also requires to ensure that the *create method* is at least as accessible as the\n`params` *collection type*. It is impossible to perform this check in a reliable fashion, unless the *collection type*\ndefines its *iteration type* itself.\n\nNote, that we also have https://github.com/dotnet/roslyn/issues/69676 opened for compiler, which basically observes the same\nissue, but talks about it from the perspective of optimization. \n\n#### Proposal\n\nRequire a type utilizing `CollectionBuilder` attribute to define its *iteration type* on itself.\nIn other words this means, that the type should either implement `IEnumarable`/`IEnumerable<T>`, or \nit should have public `GetEnumerator` method with the right signature (this excludes any extension methods).\n\nAlso, right now [*create method*](#create-methods) is required to \"be accessible where the collection expression is used\".\nThis is another point of context dependency based on accessibility. The purpose of this method is very similar to\nthe purpose of a user-defined conversion method, and that one must be public. Therefore, we should consider\nrequiring the *create method* to be public as well.\n\n#### Conclusion\n\nApproved with modifications [LDM-2024-01-08](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-01-08.md#iteration-type-of-collectionbuilderattribute-collections)\n\n### The notion of [*iteration type*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/statements.md#1295-the-foreach-statement) is not applied consistently throughout [*conversions*](#conversions)\n\n> * To a *struct* or *class type* that implements `System.Collections.Generic.IEnumerable<T>` where:\n>   * For each *element* `Ei` there is an *implicit conversion* to `T`.\n\nIt looks like an assumption is made that `T` is necessary the *iteration type* of the *struct* or *class type* in this case.\nHowever, that assumption is incorrect. Which can lead to a very strange behavior. For example:\n``` C#\nusing System.Collections;\nusing System.Collections.Generic;\n\nclass MyCollection : IEnumerable<long>\n{\n    IEnumerator<long> IEnumerable<long>.GetEnumerator() => throw null;\n    IEnumerator IEnumerable.GetEnumerator() => throw null;\n\n    public void Add(string l) => throw null;\n    \n    public IEnumerator<string> GetEnumerator() => throw null; \n}\n\nclass Program\n{\n    static void Main()\n    {\n        foreach (var l in new MyCollection())\n        {\n            string s = l; // Iteration type is string\n        }\n        \n        MyCollection x1 = [\"a\", // error CS0029: Cannot implicitly convert type 'string' to 'long'\n                           2];\n        MyCollection x2 = new MyCollection() { \"b\" };\n    }\n}\n```\n\n> * To a *struct* or *class type* that implements `System.Collections.IEnumerable` and *does not implement* `System.Collections.Generic.IEnumerable<T>`.\n\nIt looks like implementation assumes that the *iteration type* is `object`, but the specification leaves this fact unspecified,\nand simply doesn't require each *element* to convert to anything. In general, however, the *iteration type* is not\nnecessary the `object` type. Which can be observed in the following example:\n``` C#\nusing System.Collections;\nusing System.Collections.Generic;\n\nclass MyCollection : IEnumerable\n{\n    public IEnumerator<string> GetEnumerator() => throw null; \n    IEnumerator IEnumerable.GetEnumerator() => throw null;\n}\n\nclass Program\n{\n    static void Main()\n    {\n        foreach (var l in new MyCollection())\n        {\n            string s = l; // Iteration type is string\n        }\n    }\n}\n```\n\nThe notion of *iteration type* is fundamental to [Params Collections](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-13.0/params-collections.md#applicable-function-member) feature.\nAnd this issue leads to a strange discrepancy between the two features. For Example:\n\n``` C#\nusing System.Collections;\nusing System.Collections.Generic;\n\nclass MyCollection : IEnumerable<long>\n{\n    IEnumerator<long> IEnumerable<long>.GetEnumerator() => throw null;\n    IEnumerator IEnumerable.GetEnumerator() => throw null;\n\n    public IEnumerator<string> GetEnumerator() => throw null; \n\n    public void Add(long l) => throw null; \n    public void Add(string l) => throw null; \n}\n\nclass Program\n{\n    static void Main()\n    {\n        Test(\"2\"); // error CS0029: Cannot implicitly convert type 'string' to 'long'\n        Test([\"2\"]); // error CS1503: Argument 1: cannot convert from 'collection expressions' to 'string'\n        Test(3); // error CS1503: Argument 1: cannot convert from 'int' to 'string'\n        Test([3]); // Ok\n\n        MyCollection x1 = [\"2\"]; // error CS0029: Cannot implicitly convert type 'string' to 'long'\n        MyCollection x2 = [3];\n    }\n\n    static void Test(params MyCollection a)\n    {\n    }\n}\n```\n\n``` C#\nusing System.Collections;\nusing System.Collections.Generic;\n\nclass MyCollection : IEnumerable\n{\n    IEnumerator IEnumerable.GetEnumerator() => throw null;\n\n    public IEnumerator<string> GetEnumerator() => throw null; \n    public void Add(object l) => throw null;\n}\n\nclass Program\n{\n    static void Main()\n    {\n        Test(\"2\", 3); // error CS1503: Argument 2: cannot convert from 'int' to 'string'\n        Test([\"2\", 3]); // Ok\n    }\n\n    static void Test(params MyCollection a)\n    {\n    }\n}\n```\n\nIt will probably be good to align one way or the other.\n\n#### Proposal\n\nSpecify convertibility of *struct* or *class type* that implements `System.Collections.Generic.IEnumerable<T>` or `System.Collections.IEnumerable`\nin terms of *iteration type* and require an *implicit conversion* for each *element* `Ei` to the *iteration type*.\n\n#### Conclusion\n\nApproved [LDM-2024-01-08](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-01-08.md#iteration-type-in-conversions)\n\n### Should *collection expression conversion* require availability of a minimal set of APIs for construction?\n\nA *constructible* collection type according to [*conversions*](#conversions) can actually be not constructible,\nwhich is likely to lead to some unexpected overload resolution behavior. For example:\n``` C#\nclass C1\n{\n    public static void M1(string x)\n    {\n    }\n    public static void M1(char[] x)\n    {\n    }\n    \n    void Test()\n    {\n        M1(['a', 'b']); // error CS0121: The call is ambiguous between the following methods or properties: 'C1.M1(string)' and 'C1.M1(char[])'\n    }\n}\n```\n\nHowever, the 'C1.M1(string)' is not a candidate that can be used because:\n```\nerror CS1729: 'string' does not contain a constructor that takes 0 arguments\nerror CS1061: 'string' does not contain a definition for 'Add' and no accessible extension method 'Add' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?)\n```\n\nHere is another example with a user-defined type and a stronger error that doesn't even mention a valid candidate:\n``` C#\nusing System.Collections;\nusing System.Collections.Generic;\n\nclass C1 : IEnumerable<char>\n{\n    public static void M1(C1 x)\n    {\n    }\n    public static void M1(char[] x)\n    {\n    }\n\n    void Test()\n    {\n        M1(['a', 'b']); // error CS1061: 'C1' does not contain a definition for 'Add' and no accessible extension method 'Add' accepting a first argument of type 'C1' could be found (are you missing a using directive or an assembly reference?)\n    }\n\n    public static implicit operator char[](C1 x) => throw null;\n    IEnumerator<char> IEnumerable<char>.GetEnumerator() => throw null;\n    IEnumerator IEnumerable.GetEnumerator() => throw null;\n}\n```\n\nIt looks like the situation is very similar to what we used to have with method group to delegate conversions. I.e.\nthere were scenarios where the conversion existed, but was erroneous. We decided to improve that by ensuring that,\nif conversion is erroneous, then it doesn't exist.\n\nNote, that with \"Params Collections\" feature we will be running into a similar issue. It might be good to disallow\nusage of `params` modifier for not constructible collections. However in the current proposal that check is based on \n[*conversions*](#conversions) section. Here is an example:\n\n``` C#\nusing System.Collections;\nusing System.Collections.Generic;\n\nclass C1 : IEnumerable<char>\n{\n    public static void M1(params C1 x) // It is probably better to report an error about an invalid `params` modifier\n    {\n    }\n    public static void M1(params ushort[] x)\n    {\n    }\n\n    void Test()\n    {\n        M1('a', 'b'); // error CS1061: 'C1' does not contain a definition for 'Add' and no accessible extension method 'Add' accepting a first argument of type 'C1' could be found (are you missing a using directive or an assembly reference?)\n        M2('a', 'b'); // Ok\n    }\n\n    public static void M2(params ushort[] x)\n    {\n    }\n\n    IEnumerator<char> IEnumerable<char>.GetEnumerator() => throw null;\n    IEnumerator IEnumerable.GetEnumerator() => throw null;\n}\n```\n\nIt looks like the issue was somewhat discussed previously, see https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-10-02.md#collection-expressions.\nAt that time an argument was made that the rules, as specified right now, are consistent with how interpolated string handlers\nare specified. Here is a quote:\n\n>In particular, interpolated string handlers were originally specified this way, but we revised the specification after considering this issue.\n\nWhile there is some similarity, there is also an important distinction worth\nconsidering. Here is a quote from https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/improved-interpolated-strings.md#interpolated-string-handler-conversion:\n\n> Type `T` is said to be an _applicable\\_interpolated\\_string\\_handler\\_type_ if it is attributed with `System.Runtime.CompilerServices.InterpolatedStringHandlerAttribute`.\nThere exists an implicit _interpolated\\_string\\_handler\\_conversion_ to `T` from an _interpolated\\_string\\_expression_, or an _additive\\_expression_ composed entirely of\n_interpolated\\_string\\_expression_s and using only `+` operators.\n\nThe target type must have a special attribute which is a strong indicator of author's intent for the type to be\nan interpolated string handler. It is fair to assume that presence of the attribute is not a coincidence.\nIn contrast, the fact that a type is \"enumerable\", doesn't necessary mean that there was author's intent for\nthe type to be constructible. A presence of a *[create method](#create-methods)*, however, which is indicated with\na `[CollectionBuilder(...)]` attribute on the *collection type*, feels like a strong indicator of author's intent\nfor the type to be constructible.\n\n#### Proposal\n\nFor a *struct* or *class type* that implements `System.Collections.IEnumerable` and that does not have a [*create method*](#create-methods)\n[*conversions*](#conversions) section should require presence of at least the following APIs:\n- An accessible constructor that is applicable with no arguments.\n- An accessible `Add` instance or extension method that can be invoked with value of *iteration type* as the argument.\n\nFor the purpose of [Params Collections](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-13.0/params-collections.md#method-parameters) feature,\nsuch types are valid `params` types when these APIs are declared public and are instance (vs. extension) methods.\n\n#### Conclusion\n\nApproved with modifications [LDM-2024-01-10](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-01-10.md)\n"
  },
  {
    "path": "proposals/csharp-12.0/experimental-attribute.md",
    "content": "ExperimentalAttribute\n=====================\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nReport warnings for references to types and members marked with `System.Diagnostics.CodeAnalysis.ExperimentalAttribute`.\n```cs\nnamespace System.Diagnostics.CodeAnalysis\n{\n    [AttributeUsage(AttributeTargets.Assembly |\n                    AttributeTargets.Module |\n                    AttributeTargets.Class |\n                    AttributeTargets.Struct |\n                    AttributeTargets.Enum |\n                    AttributeTargets.Constructor |\n                    AttributeTargets.Method |\n                    AttributeTargets.Property |\n                    AttributeTargets.Field |\n                    AttributeTargets.Event |\n                    AttributeTargets.Interface |\n                    AttributeTargets.Delegate, Inherited = false)]\n    public sealed class ExperimentalAttribute : Attribute\n    {\n        public ExperimentalAttribute(string diagnosticId)\n        {\n            DiagnosticId = diagnosticId;\n        }\n\n        public string DiagnosticId { get; }\n        public string? UrlFormat { get; set; }\n        public string? Message { get; set; }\n    }\n}\n```\n\n## Reported diagnostic\n\nAlthough the diagnostic is technically a warning, so that the compiler allows suppressing it,\nit is treated as an error for purpose of reporting. This causes the build to fail if the diagnostic\nis not suppressed.  \n\nThe diagnostic is reported for any reference to a type or member that is either:\n- marked with the attribute,\n- in an assembly or module marked with the attribute,\n\nexcept when the reference occurs within `[Experimental]` members, when it is automatically suppressed.\n\nIt is also possible to suppress the diagnostic by usual means, such as an explicit compiler option or `#pragma`.  \nFor example, if the API is marked with `[Experimental(\"DiagID\")]` or `[Experimental(\"DiagID\", UrlFormat = \"https://example.org/{0}\")]`, \nthe diagnostic can be suppressed with `#pragma warning disable DiagID`.\n\nAn error is produced if the diagnostic ID given to the experimental attribute is not a [valid C# identifier](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/lexical-structure.md#643-identifiers).  \n\nIf a value for `Message` property is not provided, the diagnostic message is a specific message, where `'{0}'` is the fully-qualified type or member name.\n```\n'{0}' is for evaluation purposes only and is subject to change or removal in future updates.\n```\n\nIf a value for `Message` property is provided, the diagnostic message is a specific message, where `'{0}'` is the fully-qualified type or member name\nand `'{1}'` is the `Message`.\n```\n'{0}' is for evaluation purposes only and is subject to change or removal in future updates: '{1}'.\n```\n\nThe attribute is not inherited from base types or overridden members.\n\n## ObsoleteAttribute and DeprecatedAttribute\n\nWarnings for `[Experimental]` are reported within `[Obsolete]` or `[Deprecated]` members.  \nWarnings and errors for `[Obsolete]` and `[Deprecated]` are reported inside `[Experimental]` members.  \nBut warnings and errors for `[Obsolete]` and `[Deprecated]` are reported instead of `[Experimental]` if there are multiple attributes.  \n"
  },
  {
    "path": "proposals/csharp-12.0/inline-arrays.md",
    "content": "Inline Arrays\n=====\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/7431>\n\n## Summary\n\nProvide a general-purpose and safe mechanism for consuming struct types utilizing\n[InlineArrayAttribute](https://github.com/dotnet/runtime/issues/61135) feature.\nProvide a general-purpose and safe mechanism for declaring inline arrays within C# classes, structs, and interfaces.\n\n> Note: Previous versions of this spec used the terms \"ref-safe-to-escape\" and \"safe-to-escape\", which were introduced in the [Span safety](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-7.2/span-safety.md) feature specification. The [ECMA standard committee](https://www.ecma-international.org/task-groups/tc49-tg2/) changed the names to [\"ref-safe-context\"](https://learn.microsoft.com/dotnet/csharp/language-reference/language-specification/variables#972-ref-safe-contexts) and [\"safe-context\"](https://learn.microsoft.com/dotnet/csharp/language-reference/language-specification/structs#16412-safe-context-constraint), respectively. The values of the safe context have been refined to use \"declaration-block\", \"function-member\", and \"caller-context\" consistently. The speclets had used different phrasing for these terms, and also used \"safe-to-return\" as a synonym for \"caller-context\". This speclet has been updated to use the terms in the C# 7.3 standard.\n\n## Motivation\n\nThis proposal plans to address the many limitations of https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#238-fixed-size-buffers.\nSpecifically it aims to allow:\n- accessing elements of struct types utilizing [InlineArrayAttribute](https://github.com/dotnet/runtime/issues/61135) feature;\n- the declaration of inline arrays for managed and unmanaged types in a `struct`, `class`, or `interface`.\n\nAnd provide language safety verification for them.\n\n\n## Detailed Design \n\nRecently runtime added [InlineArrayAttribute](https://github.com/dotnet/runtime/issues/61135) feature.\nIn short, a user can declare a structure type like the following:\n\n``` C#\n[System.Runtime.CompilerServices.InlineArray(10)]\npublic struct Buffer\n{\n    private object _element0;\n}\n```\n\nRuntime provides a special type layout for the `Buffer` type:\n- The size of the type is extended to fit 10 (the number comes from the InlineArray attribute) elements of `object`\n  type (the type comes from the type of the only instance field in the struct, `_element0` in this example).\n- The first element is aligned with the instance field and with the beginning of the struct\n- The elements are laid out sequentially in memory as though they are elements of an array.\n\nRuntime provides regular GC tracking for all elements in the struct.\n\nThis proposal will refer to types like this as \"inline array types\".\n\nElements of an inline array type can be accessed through pointers or through span instances returned by\n[System.Runtime.InteropServices.MemoryMarshal.CreateSpan](https://learn.microsoft.com/dotnet/api/system.runtime.interopservices.memorymarshal.createspan)/[System.Runtime.InteropServices.MemoryMarshal.CreateReadOnlySpan](https://learn.microsoft.com/dotnet/api/system.runtime.interopservices.memorymarshal.createreadonlyspan) APIs. However, neither\nthe pointer approach, nor the APIs provide type and bounds checking out of the box.\n\nLanguage will provide a type-safe/ref-safe way for accessing elements of inline array types. The access will be span based. \nThis limits support to inline array types with element types that can be used as a type argument.\nFor example, a pointer type cannot be used as an element type. Other examples the span types.\n\n### Obtaining instances of span types for an inline array type\n\nSince there is a guarantee that the first element in an inline array type is aligned at the beginning of the type (no gap), compiler will use the\nfollowing code to get a `Span` value:\n``` C#\nMemoryMarshal.CreateSpan(ref Unsafe.As<TBuffer, TElement>(ref buffer), size);\n```\n\nAnd the following code to get a `ReadOnlySpan` value:\n``` C#\nMemoryMarshal.CreateReadOnlySpan(ref Unsafe.As<TBuffer, TElement>(ref Unsafe.AsRef(in buffer)), size);\n```\n\nIn order to reduce IL size at use sites compiler should be able to add two generic reusable helpers into private implementation detail type and\nuse them across all use sites in the same program.\n\n``` C#\npublic static System.Span<TElement> InlineArrayAsSpan<TBuffer, TElement>(ref TBuffer buffer, int size) where TBuffer : struct\n{\n    return MemoryMarshal.CreateSpan(ref Unsafe.As<TBuffer, TElement>(ref buffer), size);\n}\n\npublic static System.ReadOnlySpan<TElement> InlineArrayAsReadOnlySpan<TBuffer, TElement>(in TBuffer buffer, int size) where TBuffer : struct\n{\n    return MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As<TBuffer, TElement>(ref Unsafe.AsRef(in buffer)), size);\n}\n```\n\n### Element access\n\nThe [Element access](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12821-element-access) will be extended\nto support inline array element access.\n\nAn *element_access* consists of a *primary_no_array_creation_expression*, followed by a “`[`” token, followed by an *argument_list*, followed by a “`]`” token. The *argument_list* consists of one or more *argument*s, separated by commas.\n\n```ANTLR\nelement_access\n    : primary_no_array_creation_expression '[' argument_list ']'\n    ;\n```\n\nThe *argument_list* of an *element_access* is not allowed to contain `ref` or `out` arguments.\n\nAn *element_access* is dynamically bound ([§11.3.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1233-dynamic-binding)) if at least one of the following holds:\n\n- The *primary_no_array_creation_expression* has compile-time type `dynamic`.\n- At least one expression of the *argument_list* has compile-time type `dynamic` and the *primary_no_array_creation_expression* does not have an array type,\n  **and the *primary_no_array_creation_expression* does not have an inline array type or there is more than one item in the argument list**.\n\nIn this case, the compiler classifies the *element_access* as a value of type `dynamic`. The rules below to determine the meaning of the *element_access* are then applied at run-time, using the run-time type instead of the compile-time type of those of the *primary_no_array_creation_expression* and *argument_list* expressions which have the compile-time type `dynamic`. If the *primary_no_array_creation_expression* does not have compile-time type `dynamic`, then the element access undergoes a limited compile-time check as described in [§11.6.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1265-compile-time-checking-of-dynamic-member-invocation).\n\nIf the *primary_no_array_creation_expression* of an *element_access* is a value of an *array_type*, the *element_access* is an array access ([§12.8.12.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#128122-array-access)). **If the *primary_no_array_creation_expression* of an *element_access* is a variable or value of an inline array type and the *argument_list* consists of a single argument, the *element_access* is an inline array element access.** Otherwise, the *primary_no_array_creation_expression* shall be a variable or value of a class, struct, or interface type that has one or more indexer members, in which case the *element_access* is an indexer access ([§12.8.12.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#128123-indexer-access)).\n\n#### Inline array element access\n\nFor an inline array element access, the *primary_no_array_creation_expression* of the *element_access* must be a variable or value of an inline array type. Furthermore, the *argument_list* of an inline array element access is not allowed to contain named arguments. The *argument_list* must contain a single expression, and the expression must be \n- of type `int`, or\n- implicitly convertible to `int`, or\n- implicitly convertible to `System.Index`, or \n- implicitly convertible to `System.Range`. \n\n##### When the expression type is int\n\nIf *primary_no_array_creation_expression* is a writable variable, the result of evaluating an inline array element access is a writable variable\nequivalent to invoking [`public ref T this[int index] { get; }`](https://learn.microsoft.com/dotnet/api/system.span-1.item) with\nthat integer value on an instance of `System.Span<T>` returned by `System.Span<T> InlineArrayAsSpan` method on *primary_no_array_creation_expression*. For the purpose of ref-safety analysis the *ref-safe-context*/*safe-context*\nof the access are equivalent to the same for an invocation of a method with the signature `static ref T GetItem(ref InlineArrayType array)`.\nThe resulting variable is considered movable if and only if *primary_no_array_creation_expression* is movable.\n\nIf *primary_no_array_creation_expression* is a readonly variable, the result of evaluating an inline array element access is a readonly variable\nequivalent to invoking [`public ref readonly T this[int index] { get; }`](https://learn.microsoft.com/dotnet/api/system.readonlyspan-1.item) with\nthat integer value on an instance of `System.ReadOnlySpan<T>` returned by `System.ReadOnlySpan<T> InlineArrayAsReadOnlySpan`\nmethod on *primary_no_array_creation_expression*. For the purpose of ref-safety analysis the *ref-safe-context*/*safe-context*\nof the access are equivalent to the same for an invocation of a method with the signature `static ref readonly T GetItem(in InlineArrayType array)`.\nThe resulting variable is considered movable if and only if *primary_no_array_creation_expression* is movable.\n\nIf *primary_no_array_creation_expression* is a value, the result of evaluating an inline array element access is a value\nequivalent to invoking [`public ref readonly T this[int index] { get; }`](https://learn.microsoft.com/dotnet/api/system.readonlyspan-1.item) with\nthat integer value on an instance of `System.ReadOnlySpan<T>` returned by `System.ReadOnlySpan<T> InlineArrayAsReadOnlySpan`\nmethod on *primary_no_array_creation_expression*. For the purpose of ref-safety analysis the *ref-safe-context*/*safe-context*\nof the access are equivalent to the same for an invocation of a method with the signature `static T GetItem(InlineArrayType array)`. \n\nFor example:\n``` C#\n[System.Runtime.CompilerServices.InlineArray(10)]\npublic struct Buffer10<T>\n{\n    private T _element0;\n}\n\nvoid M1(Buffer10<int> x)\n{\n    ref int a = ref x[0]; // Ok, equivalent to `ref int a = ref InlineArrayAsSpan<Buffer10<int>, int>(ref x, 10)[0]`\n}\n\nvoid M2(in Buffer10<int> x)\n{\n    ref readonly int a = ref x[0]; // Ok, equivalent to `ref readonly int a = ref InlineArrayAsReadOnlySpan<Buffer10<int>, int>(in x, 10)[0]`\n    ref int b = ref x[0]; // An error, `x` is a readonly variable => `x[0]` is a readonly variable\n}\n\nBuffer10<int> GetBuffer() => default;\n\nvoid M3()\n{\n    int a = GetBuffer()[0]; // Ok, equivalent to `int a = InlineArrayAsReadOnlySpan<Buffer10<int>, int>(GetBuffer(), 10)[0]` \n    ref readonly int b = ref GetBuffer()[0]; // An error, `GetBuffer()[0]` is a value\n    ref int c = ref GetBuffer()[0]; // An error, `GetBuffer()[0]` is a value\n}\n```\n\nIndexing into an inline array with a constant expression outside of the declared inline array bounds is a compile time error.\n\n##### When the expression is implicitly convertible to `int`\n\nThe expression is converted to int and then the element access is interpreted as described in **When the expression type is int** section.\n\n##### When the expression implicitly convertible to `System.Index`\n\nThe expression is converted to `System.Index`, which is then transformed to an int-based index value as described at https://github.com/dotnet/csharplang/blob/main/proposals/csharp-8.0/ranges.md#implicit-index-support, assuming that the\nlength of the collection is known at compile time and is equal to the amount of elements in the inline array type of\nthe *primary_no_array_creation_expression*. Then the element access is interpreted as described in\n**When the expression type is int** section.\n\n##### When the expression implicitly convertible to `System.Range`\n\nIf *primary_no_array_creation_expression* is a writable variable, the result of evaluating an inline array element access is a value\nequivalent to invoking [`public Span<T> Slice (int start, int length)`](https://learn.microsoft.com/dotnet/api/system.span-1.slice)\non an instance of `System.Span<T>` returned by `System.Span<T> InlineArrayAsSpan` method on *primary_no_array_creation_expression*.\nFor the purpose of ref-safety analysis the *ref-safe-context*/*safe-context* of the access are equivalent to the same\nfor an invocation of a method with the signature `static System.Span<T> GetSlice(ref InlineArrayType array)`.\n\nIf *primary_no_array_creation_expression* is a readonly variable, the result of evaluating an inline array element access is a value\nequivalent to invoking [`public ReadOnlySpan<T> Slice (int start, int length)`](https://learn.microsoft.com/dotnet/api/system.readonlyspan-1.slice)\non an instance of `System.ReadOnlySpan<T>` returned by `System.ReadOnlySpan<T> InlineArrayAsReadOnlySpan`\nmethod on *primary_no_array_creation_expression*.\nFor the purpose of ref-safety analysis the *ref-safe-context*/*safe-context* of the access are equivalent to the same\nfor an invocation of a method with the signature `static System.ReadOnlySpan<T> GetSlice(in InlineArrayType array)`.\n\nIf *primary_no_array_creation_expression* is a value, an error is reported. \n\nThe arguments for the `Slice` method invocation are calculated from the index expression converted to `System.Range` as described at\nhttps://github.com/dotnet/csharplang/blob/main/proposals/csharp-8.0/ranges.md#implicit-range-support, assuming that the length of the collection\nis known at compile time and is equal to the amount of elements in the inline array type of the *primary_no_array_creation_expression*.\n\nCompiler can omit the `Slice` call if it is known at compile time that `start` is 0 and `length` is less or equal to the amount of elements in the\ninline array type. Compiler can also report an error if it is known at compile time that slicing goes out of inline array bounds.\n\nFor example:\n``` C#\nvoid M1(Buffer10<int> x)\n{\n    System.Span<int> a = x[..]; // Ok, equivalent to `System.Span<int> a = InlineArrayAsSpan<Buffer10<int>, int>(ref x, 10).Slice(0, 10)`\n}\n\nvoid M2(in Buffer10<int> x)\n{\n    System.ReadOnlySpan<int> a = x[..]; // Ok, equivalent to `System.ReadOnlySpan<int> a = InlineArrayAsReadOnlySpan<Buffer10<int>, int>(in x, 10).Slice(0, 10)`\n    System.Span<int> b = x[..]; // An error, System.ReadOnlySpan<int> cannot be converted to System.Span<int>\n}\n\nBuffer10<int> GetBuffer() => default;\n\nvoid M3()\n{\n    _ = GetBuffer()[..]; // An error, `GetBuffer()` is a value\n}\n```\n\n\n### Conversions\n\nA new conversion, an inline array conversion, from expression will be added. The inline array conversion is\na [standard conversion](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#104-standard-conversions).\n\nThere is an implicit conversion from expression of an inline array type to the following types:\n- `System.Span<T>`\n- `System.ReadOnlySpan<T>`\n\nHowever, converting a readonly variable to `System.Span<T>` or converting a value to either type is an error.\n\nFor example:\n``` C#\nvoid M1(Buffer10<int> x)\n{\n    System.ReadOnlySpan<int> a = x; // Ok, equivalent to `System.ReadOnlySpan<int> a = InlineArrayAsReadOnlySpan<Buffer10<int>, int>(in x, 10)`\n    System.Span<int> b = x; // Ok, equivalent to `System.Span<int> b = InlineArrayAsSpan<Buffer10<int>, int>(ref x, 10)`\n}\n\nvoid M2(in Buffer10<int> x)\n{\n    System.ReadOnlySpan<int> a = x; // Ok, equivalent to `System.ReadOnlySpan<int> a = InlineArrayAsReadOnlySpan<Buffer10<int>, int>(in x, 10)`\n    System.Span<int> b = x; // An error, readonly mismatch\n}\n\nBuffer10<int> GetBuffer() => default;\n\nvoid M3()\n{\n    System.ReadOnlySpan<int> a = GetBuffer(); // An error, ref-safety\n    System.Span<int> b = GetBuffer(); // An error, ref-safety\n}\n```\n\nFor the purpose of ref-safety analysis the *safe-context* of the conversion is equivalent to *safe-context*\nfor an invocation of a method with the signature `static System.Span<T> Convert(ref InlineArrayType array)`, or\n`static System.ReadOnlySpan<T> Convert(in InlineArrayType array)`.\n\n\n### List patterns\n\n[List patterns](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/list-patterns.md) will not be supported for instances\nof inline array types.\n\n### Definite assignment checking\n\nRegular definite assignment rules are applicable to variables that have an inline array type. \n\n### Collection literals\n\nAn instance of an inline array type is a valid expression in a [*spread_element*](collection-expressions.md#detailed-design).\n\nThe following feature did not ship in C# 12. It remains an open proposal. The code in this example generates **CS9174**:\n\n<details>\n\nAn inline array type is a valid *constructible collection* target type for a [collection expression](collection-expressions.md).\nFor example:\n``` C#\nBuffer10<int> b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // initializes user-defined inline array\n```\n\nThe length of the collection literal must match the length of the target inline array type. If the length of the literal\nis known at compile time and it doesn't match the target length, an error is reported. Otherwise, an exception is going\nto be thrown at runtime once the mismatch is encountered. The exact exception type is TBD. Some candidates are:\nSystem.NotSupportedException, System.InvalidOperationException.\n</details>\n\n### Validation of the InlineArrayAttribute applications\n\nCompiler will validate the following aspects of the InlineArrayAttribute applications:\n- The target type is a [non-record](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-06-17.md#conclusion-3) struct\n- The target type has only one field\n- Specified length > 0\n- The target struct doesn't have an explicit layout specified\n\n### Inline Array elements in an object initializer\n\nBy default, element initialization will not be supported via *initializer_target* of form `'[' argument_list ']'`\n(see https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#128173-object-initializers):  \n``` C#\nstatic C M2() => new C() { F = {[0] = 111} }; // error CS1913: Member '[0]' cannot be initialized. It is not a field or property.\n\nclass C\n{\n    public Buffer10<int> F;\n}\n```\n\nHowever, if the inline array type explicitly defines suitable indexer, object initializer will use it:\n``` C#\nstatic C M2() => new C() { F = {[0] = 111} }; // Ok, indexer is invoked\n\nclass C\n{\n    public Buffer10<int> F;\n}\n\n[System.Runtime.CompilerServices.InlineArray(10)]\npublic struct Buffer10<T>\n{\n    private T _element0;\n\n    public T this[int i]\n    {\n        get => this[i];\n        set => this[i] = value;\n    }\n}\n```\n\n\n### The foreach statement\n\n[The foreach statement](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md#1395-the-foreach-statement) will be adjusted\nto allow usage of an inline array type as a collection in a foreach statement.\n\nFor example:\n``` C#\nforeach (var a in getBufferAsValue())\n{\n    WriteLine(a);\n}\n\nforeach (var b in getBufferAsWritableVariable())\n{\n    WriteLine(b);\n}\n\nforeach (var c in getBufferAsReadonlyVariable())\n{\n    WriteLine(c);\n}\n\nBuffer10<int> getBufferAsValue() => default;\nref Buffer10<int> getBufferAsWritableVariable() => default;\nref readonly Buffer10<int> getBufferAsReadonlyVariable() => default;\n```\n\nis equivalent to:\n``` C#\nBuffer10<int> temp = getBufferAsValue();\nforeach (var a in (System.ReadOnlySpan<int>)temp)\n{\n    WriteLine(a);\n}\n\nforeach (var b in (System.Span<int>)getBufferAsWritableVariable())\n{\n    WriteLine(b);\n}\n\nforeach (var c in (System.ReadOnlySpan<int>)getBufferAsReadonlyVariable())\n{\n    WriteLine(c);\n}\n```\n\nWe will support `foreach` over inline arrays, even if it starts as restricted in `async` methods due to involvement of the span types into the translation.\n\n## Open design questions\n\n## Alternatives\n\n### Inline array type syntax\n\nThe grammar at https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/types.md#821-general will be adjusted as follows:\n``` diff antlr\narray_type\n    : non_array_type rank_specifier+\n    ;\n\nrank_specifier\n    : '[' ','* ']'\n+   | '[' constant_expression ']' \n    ;\n```\n\nThe type of the *constant_expression* must be implicitly convertible to type `int`, and the value must be a non-zero positive integer.\n\nThe relevant part of the https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/arrays.md#1721-general section will be adjusted as follows.\n\nThe grammar productions for array types are provided in https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/types.md#821-general.\n\nAn array type is written as a *non_array_type* followed by one or more *rank_specifier*s.\n\nA *non_array_type* is any *type* that is not itself an *array_type*.\n\nThe rank of an array type is given by the leftmost *rank_specifier* in the *array_type*: A *rank_specifier* indicates that\nthe array is an array with a rank of one plus the number of “`,`” tokens in the *rank_specifier*.\n\nThe element type of an array type is the type that results from deleting the leftmost *rank_specifier*:\n\n- An array type of the form `T[ constant_expression ]` is an anonymous inline array type with\n  length denoted by *constant_expression* and a non-array element type `T`.\n- An array type of the form `T[ constant_expression ][R₁]...[Rₓ]` is an anonymous inline array type with\n  length denoted by *constant_expression* and an element type `T[R₁]...[Rₓ]`.\n- An array type of the form `T[R]` (where R is not a *constant_expression*) is a regular array type with rank `R` and a non-array element type `T`.\n- An array type of the form `T[R][R₁]...[Rₓ]` (where R is not a *constant_expression*) is a regular array type with rank `R` and an element type `T[R₁]...[Rₓ]`.\n\nIn effect, the *rank_specifier*s are read from left to right *before* the final non-array element type.\n\n> *Example*: The type in `int[][,,][,]` is a single-dimensional array of three-dimensional arrays of two-dimensional arrays of `int`. *end example*\n\nAt run-time, a value of a regular array type can be `null` or a reference to an instance of that array type.\n\n> *Note*: Following the rules of https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/arrays.md#176-array-covariance,\n> the value may also be a reference to a covariant array type. *end note*\n\nAn anonymous inline array type is a compiler synthesized inline array type with internal accessibility. The element type must be a \ntype that can be used as a type argument. Unlike an explicitly declared inline array type, an anonymous inline array type cannot be\nreferenced by name, it can be referenced only by *array_type* syntax. In context of the same program, any two *array_type*s\ndenoting inline array types of the same element type and of the same length, refer to the same anonymous inline array type. \n\nBesides internal accessibility, compiler will prevent consumption of APIs utilizing anonymous inline array types across assembly boundaries\nby using a required custom modifier (exact type TBD) applied to an anonymous inline array type reference in the signature.\n\n#### Array creation expressions\n\n[Array creation expressions](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#128175-array-creation-expressions)\n\n```ANTLR\narray_creation_expression\n    : 'new' non_array_type '[' expression_list ']' rank_specifier*\n      array_initializer?\n    | 'new' array_type array_initializer\n    | 'new' rank_specifier array_initializer\n    ;\n```\n\nGiven the current grammar, use of a *constant_expression* in place of the *expression_list* already has meaning of\nallocating a regular single-dimensional array type of the specified length. Therefore, *array_creation_expression* will continue\nto represent an allocation of a regular array.\n\nHowever, the new form of the *rank_specifier* could be used to incorporate an anonymous inline array type into the element type of\nthe allocated array.\n\nFor example, the following expressions create a regular array of length 2 with an element type of an anonymous inline array type\nwith element type int and length 5:\n``` C#\nnew int[2][5];\nnew int[][5] {default, default};\nnew [] {default(int[5]), default(int[5])};\n```\n\n#### Array initializers\n\nArray initializers were not implemented in C# 12. This section remains an active proposal. \n\n<details>\n\nThe [Array initializers](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/arrays.md#177-array-initializers) section\nwill be adjusted to allow use of *array_initializer* to initialize inline array types (no changes to the grammar necessary).\n\n```ANTLR\narray_initializer\n    : '{' variable_initializer_list? '}'\n    | '{' variable_initializer_list ',' '}'\n    ;\n\nvariable_initializer_list\n    : variable_initializer (',' variable_initializer)*\n    ;\n    \nvariable_initializer\n    : expression\n    | array_initializer\n    ;\n```\n\nThe length of the inline array must be explicitly provided by the target type.\n\nFor example:\n``` C#\nint[5] a = {1, 2, 3, 4, 5}; // initializes anonymous inline array of length 5\nBuffer10<int> b = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // initializes user-defined inline array\nvar c = new int[][] {{11, 12}, {21, 22}, {31, 32}}; // An error for the nested array initializer\nvar d = new int[][2] {{11, 12}, {21, 22}, {31, 32}}; // An error for the nested array initializer\n```\n\n</details>\n\n### Detailed Design (Option 2)\n\nNote, that for the purpose of this proposal a term \"fixed-size buffer\" refers to a the proposed \"safe fixed-size buffer\" feature rather than to a buffer described at https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#238-fixed-size-buffers.\n\nIn this design, fixed-size buffer types do not get general special treatment by the language.\nThere is a special syntax to declare members that represent fixed-size buffers and new rules around consuming those members.\nThey are not fields from the language point of view.\n\nThe grammar for *variable_declarator* in https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#155-fields\nwill be extended to allow specifying the size of the buffer:\n\n``` diff antlr\nfield_declaration\n    : attributes? field_modifier* type variable_declarators ';'\n    ;\n\nfield_modifier\n    : 'new'\n    | 'public'\n    | 'protected'\n    | 'internal'\n    | 'private'\n    | 'static'\n    | 'readonly'\n    | 'volatile'\n    | unsafe_modifier   // unsafe code support\n    ;\n\nvariable_declarators\n    : variable_declarator (',' variable_declarator)*\n    ;\n    \nvariable_declarator\n    : identifier ('=' variable_initializer)?\n+   | fixed_size_buffer_declarator\n    ;\n    \nfixed_size_buffer_declarator\n    : identifier '[' constant_expression ']'\n    ;    \n```\n\nA *fixed_size_buffer_declarator* introduces a fixed-size buffer of a given element type.\n\nThe buffer element type is the *type* specified in `field_declaration`. A fixed-size buffer declarator introduces a new member and consists of an identifier that names the member, followed by a constant expression enclosed in `[` and `]` tokens. The constant expression denotes the number of elements in the member introduced by that fixed-size buffer declarator. The type of the constant expression must be implicitly convertible to type `int`, and the value must be a non-zero positive integer.\n\nThe elements of a fixed-size buffer shall be laid out sequentially in memory as though they are elements of an array.\n\nA *field_declaration* with a *fixed_size_buffer_declarator* in an interface must have `static` modifier.\n\nDepending on the situation (details are specified below), an access to a fixed-size buffer member is classified as a value (never a variable) of either\n`System.ReadOnlySpan<S>` or `System.Span<S>`, where S is the element type of the fixed-size buffer. Both types provide indexers returning a reference to a\nspecific element with appropriate \"readonly-ness\", which prevents direct assignment to the elements when language rules don't permit that.\n\nThis limits the set of types that can be used as a fixed-size buffer element type to types that can be used as type arguments. For example, a pointer type cannot be used as an element type.\n\nThe resulting span instance will have a length equal to the size declared on the fixed-size buffer.\nIndexing into the span with a constant expression outside of the declared fixed-size buffer bounds is a compile time error.\n\nThe *safe-context* of the value will be equal to the *safe-context* of the container, just as it would if the backing data was accessed as a field.\n\n#### Fixed-size buffers in expressions\n\nMember lookup of a fixed-size buffer member proceeds exactly like member lookup of a field.\n\nA fixed-size buffer can be referenced in an expression using a *simple_name* or a *member_access* .\n\nWhen an instance fixed-size buffer member is referenced as a simple name, the effect is the same as a member access of the form `this.I`, where `I` is the fixed-size buffer member. When a static fixed-size buffer member is referenced as a simple name, the effect is the same as a member access of the form `E.I`, where `I` is the fixed-size buffer member and `E` is the declaring type.\n\n##### Non-readonly fixed-size buffers\n\nIn a member access of the form `E.I`, if `E` is of a struct type and a member lookup of `I` in that struct type identifies a non-readonly instance fixed-size member,\nthen `E.I` is evaluated and classified as follows:\n\n- If `E` is classified as a value, then `E.I` can be used only as a *primary_no_array_creation_expression* of\n  an [element access](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12812-element-access)\n  with index of `System.Index` type, or of a type implicitly convertible to int. Result of the element access is\n  a fixed-size member's element at the specified position, classified as a value.   \n- Otherwise, if `E` is classified as a readonly variable and the result of the expression is classified as a value of type `System.ReadOnlySpan<S>`,\n  where S is the element type of `I`. The value can be used to access member's elements.\n- Otherwise, `E` is classified as a writable variable and the result of the expression is classified as a value of type `System.Span<S>`,\n  where S is the element type of `I`. The value can be used to access member's elements.\n\nIn a member access of the form `E.I`, if `E` is of a class type and a member lookup of `I` in that class type identifies a non-readonly instance fixed-size member,\nthen `E.I` is evaluated and classified as a value of type `System.Span<S>`, where S is the element type of `I`.\n\nIn a member access of the form `E.I`, if member lookup of `I` identifies a non-readonly static fixed-size member,\nthen `E.I` is evaluated and classified as a value of type `System.Span<S>`, where S is the element type of `I`.\n\n##### Readonly fixed-size buffers\n\nWhen a *field_declaration* includes a `readonly` modifier, the member introduced by the fixed_size_buffer_declarator is a ***readonly fixed-size buffer***.\nDirect assignments to elements of a readonly fixed-size buffer can only occur in an instance constructor, init member or static constructor in the same type.\nSpecifically, direct assignments to an element of readonly fixed-size buffer are permitted only in the following contexts:\n\n- For an instance member, in the instance constructors or init member of the type that contains the member declaration; for a static member,\n  in the static constructor of the type that contains the member declaration. These are also the only contexts in which it is valid to pass\n  an element of readonly fixed-size buffer as an `out` or `ref` parameter.\n\nAttempting to assign to an element of a readonly fixed-size buffer or pass it as an `out` or `ref` parameter in any other context is a compile-time error.\nThis is achieved by the following.\n\nA member access for a readonly fixed-size buffer is evaluated and classified as follows:\n\n- In a member access of the form `E.I`, if `E` is of a struct type and `E` is classified as a value, then `E.I` can be used only as a\n  *primary_no_array_creation_expression* of an [element access](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12812-element-access)\n  with index of `System.Index` type, or of a type implicitly convertible to int. Result of the element access is a fixed-size member's element at the specified\n  position, classified as a value.\n- If access occurs in a context where direct assignments to an element of readonly fixed-size buffer are permitted, the result of the expression\n  is classified as a value of type `System.Span<S>`, where S is the element type of the fixed-size buffer. The value can be used to access member's elements.\n- Otherwise, the expression is classified as a value of type `System.ReadOnlySpan<S>`, where S is the element type of the fixed-size buffer.\n  The value can be used to access member's elements.\n\n#### Definite assignment checking\n\nFixed-size buffers are not subject to definite assignment-checking, and fixed-size buffer members are ignored for purposes of definite-assignment checking of struct type variables.\n\nWhen a fixed-size buffer member is static or the outermost containing struct variable of a fixed-size buffer member is a static variable, an instance variable of a class instance, or an array element, the elements of the fixed-size buffer are automatically initialized to their default values. In all other cases, the initial content of a fixed-size buffer is undefined.\n\n#### Metadata\n\n##### Metadata emit and code generation\n\nFor metadata encoding compiler will rely on recently added [`System.Runtime.CompilerServices.InlineArrayAttribute`](https://github.com/dotnet/runtime/issues/61135). \n\nFixed-size buffers like the following pseudocode:\n``` C#\n// Not valid C#\npublic partial class C\n{\n    public int buffer1[10];\n    public readonly int buffer2[10];\n}\n```\nwill be emitted as  fields of a specially decorated struct type.\n\nEquivalent C# code will be:\n\n``` C#\npublic partial class C\n{\n    public Buffer10<int> buffer1;\n    public readonly Buffer10<int> buffer2;\n}\n\n[System.Runtime.CompilerServices.InlineArray(10)]\npublic struct Buffer10<T>\n{\n    private T _element0;\n\n    [UnscopedRef]\n    public System.Span<T> AsSpan()\n    {\n        return System.Runtime.InteropServices.MemoryMarshal.CreateSpan(ref _element0, 10);\n    }\n\n    [UnscopedRef]\n    public readonly System.ReadOnlySpan<T> AsReadOnlySpan()\n    {\n        return System.Runtime.InteropServices.MemoryMarshal.CreateReadOnlySpan(\n                    ref System.Runtime.CompilerServices.Unsafe.AsRef(in _element0), 10);\n    }\n}\n```\n\nThe actual naming conventions for the type and its members are TBD. The framework will likely include a set of predefined \"buffer\" types that cover\na limited set of buffer sizes. When a predefined type doesn't exist, compiler will synthesize it in the module being built. Names of the generated types\nwill be \"speakable\" in order to support consumption from other languages. \n\nA code generated for an access like: \n``` C#\npublic partial class C\n{\n    void M1(int val)\n    {\n        buffer1[1] = val;\n    }\n\n    int M2()\n    {\n        return buffer2[1];\n    }\n}\n```\n\nwill be equivalent to:\n``` C#\npublic partial class C\n{\n    void M1(int val)\n    {\n        buffer.AsSpan()[1] = val;\n    }\n\n    int M2()\n    {\n        return buffer2.AsReadOnlySpan()[1];\n    }\n}\n```\n\n##### Metadata import\n\nWhen compiler imports a field declaration of type *T* and the following conditions are all met:\n- *T* is a struct type decorated with the `InlineArray` attribute, and\n- The first instance field declared within *T* has type *F*, and\n- There is a `public System.Span<F> AsSpan()` within *T*, and \n- There is a `public readonly System.ReadOnlySpan<T> AsReadOnlySpan()` or `public System.ReadOnlySpan<T> AsReadOnlySpan()` within *T*. \n\nthe field will be treated as C# fixed-size buffer with element type *F*. Otherwise, the field will be treated as a regular field of type *T*.\n\n\n### Method or property group like approach in the language\n\nOne thought is to treat these members more like method groups, in that they aren't automatically a value in and of themselves,\nbut can be made into one if necessary. Here’s how that would work:\n- Safe fixed-size buffer accesses have their own classification (just like e.g. method groups and lambdas)\n- They can be indexed directly as a language operation (not via span types) to produce a variable (which is readonly\n  if the buffer is in a readonly context, just the same as fields of a struct)\n- They have implicit conversions-from-expression to `Span<T>` and `ReadOnlySpan<T>`, but use of the former is an error if\n  they are in a readonly context\n- Their natural type is `ReadOnlySpan<T>`, so that’s what they contribute if they participate in type inference (e.g., var, best-common-type or generic)\n\n### C/C++ fixed-size buffers\n\nC/C++ has a different notion of fixed-size buffers. For example, there is a notion of \"zero-length fixed sized buffers\",\nwhich is often used as a way to indicate that the data is \"variable length\". It is not a goal of this proposal to be\nable to interop with that.\n\n\n## LDM meetings\n\n- https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-04-03.md#fixed-size-buffers\n- https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-04-10.md#fixed-size-buffers\n- https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-05-01.md#fixed-size-buffers\n- https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-05-03.md#inline-arrays\n- https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-05-17.md#inline-arrays\n- https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-06-17.md#inline-arrays-as-record-structs\n"
  },
  {
    "path": "proposals/csharp-12.0/lambda-method-group-defaults.md",
    "content": "# Optional and parameter array parameters for lambdas and method groups\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/6051>\n\n## Summary\n\n[summary]: #summary\n\nTo build on top of the lambda improvements introduced in C# 10 (see [relevant background](#relevant-background)), we propose adding support for default parameter values and `params` arrays in lambdas. This would enable users to implement the following lambdas:\n\n```csharp\nvar addWithDefault = (int addTo = 2) => addTo + 1;\naddWithDefault(); // 3\naddWithDefault(5); // 6\n\nvar counter = (params int[] xs) => xs.Length;\ncounter(); // 0\ncounter(1, 2, 3); // 3\n```\n\nSimilarly, we will allow the same kind of behavior for method groups:\n```csharp\nvar addWithDefault = AddWithDefaultMethod;\naddWithDefault(); // 3\naddWithDefault(5); // 6\n\nvar counter = CountMethod;\ncounter(); // 0\ncounter(1, 2); // 2\n\nint AddWithDefaultMethod(int addTo = 2) {\n  return addTo + 1;\n}\nint CountMethod(params int[] xs) {\n  return xs.Length;\n}\n```\n\n## Relevant background\n[Lambda Improvements in C# 10](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/lambda-improvements.md)\n\n[Method group conversion specification §10.8](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#108-method-group-conversions)\n\n## Motivation\n\n[motivation]: #motivation\n\nApp frameworks in the .NET ecosystem leverage lambdas heavily to allow users to quickly write business logic associated with an endpoint.\n\n```csharp\nvar app = WebApplication.Create(args);\n\napp.MapPost(\"/todos/{id}\", (TodoService todoService, int id, string task) => {\n  var todo = todoService.Create(id, task);\n  return Results.Created(todo);\n});\n```\n\nLambdas don't currently support setting default values on parameters, so if a developer wanted to build an application that was resilient to scenarios where users didn't provide data, they're left to either use local functions or set the default values within the lambda body, as opposed to the more succinct proposed syntax.\n\n```csharp\nvar app = WebApplication.Create(args);\n\napp.MapPost(\"/todos/{id}\", (TodoService todoService, int id, string task = \"foo\") => {\n  var todo = todoService.Create(id, task);\n  return Results.Created(todo);\n});\n```\n\nThe proposed syntax also has the benefit of reducing confusing differences between lambdas and local functions, making it easier to reason about constructs and \"grow up\" lambdas to functions without compromising features, particularly in other scenarios where lambdas are used in APIs where method groups can also be provided as references.\nThis is also the main motivation for supporting the `params` array which is not covered by the aforementioned use-case scenario.\n\nFor example: \n```csharp\nvar app = WebApplication.Create(args);\n\nResult TodoHandler(TodoService todoService, int id, string task = \"foo\") {\n  var todo = todoService.Create(id, task);\n  return Results.Created(todo);\n}\n\napp.MapPost(\"/todos/{id}\", TodoHandler);\n```\n\n## Previous behavior\nBefore C# 12, when a user implements a lambda with an optional or `params` parameter, the compiler raises an error.\n\n```csharp\nvar addWithDefault = (int addTo = 2) => addTo + 1; // error CS1065: Default values are not valid in this context.\nvar counter = (params int[] xs) => xs.Length; // error CS1670: params is not valid in this context\n```\n\nWhen a user attempts to use a method group where the underlying method has an optional or `params` parameter, this information isn't propagated, so the call to the method doesn't typecheck due to a mismatch in the number of expected arguments.\n```cs\nvoid M1(int i = 1) { }\nvar m1 = M1; // Infers Action<int>\nm1(); // error CS7036: There is no argument given that corresponds to the required parameter 'obj' of 'Action<int>'\n\nvoid M2(params int[] xs) { }\nvar m2 = M2; // Infers Action<int[]>\nm2(); // error CS7036: There is no argument given that corresponds to the required parameter 'obj' of 'Action<int[]>'\n```\n\n## New behavior\n\nFollowing this proposal (part of C# 12), default values and `params` can be applied to lambda parameters with the following behavior:\n\n```csharp\nvar addWithDefault = (int addTo = 2) => addTo + 1;\naddWithDefault(); // 3\naddWithDefault(5); // 6\n\nvar counter = (params int[] xs) => xs.Length;\ncounter(); // 0\ncounter(1, 2, 3); // 3\n```\n\nDefault values and `params` can be applied to method group parameters by specifically defining such method group:\n\n```cs\nint AddWithDefault(int addTo = 2) {\n  return addTo + 1;\n}\n\nvar add1 = AddWithDefault; \nadd1(); // ok, default parameter value will be used\n\nint Counter(params int[] xs) {\n  return xs.Length;\n}\n\nvar counter1 = Counter;\ncounter1(1, 2, 3); // ok, `params` will be used\n```\n\n## Breaking change\n\nBefore C# 12, the inferred type of a method group is `Action` or `Func` so the following code compiles:\n```csharp\nvoid WriteInt(int i = 0) {\n  Console.Write(i);\n}\n\nvar writeInt = WriteInt; // Inferred as Action<int>\nDoAction(writeInt, 3); // Ok, writeInt is an Action<int>\n\nvoid DoAction(Action<int> a, int p) {\n  a(p);\n}\n\nint Count(params int[] xs) {\n  return xs.Length;\n}\nvar counter = Count; // Inferred as Func<int[], int>\nDoFunction(counter, 3); // Ok, counter is a Func<int[], int>\n\nint DoFunction(Func<int[], int> f, int p) {\n  return f(new[] { p });\n}\n```\nFollowing this change (part of C# 12), code of this nature ceases to compile in .NET SDK 7.0.200 or later.\n\n```csharp\nvoid WriteInt(int i = 0) {\n  Console.Write(i);\n}\n\nvar writeInt = WriteInt; // Inferred as anonymous delegate type\nDoAction(writeInt, 3); // Error, cannot convert from anonymous delegate type to Action\n\nvoid DoAction(Action<int> a, int p) {\n  a(p);\n}\n\nint Count(params int[] xs) {\n  return xs.Length;\n}\nvar counter = Count; // Inferred as anonymous delegate type\nDoFunction(counter, 3); // Error, cannot convert from anonymous delegate type to Func\n\nint DoFunction(Func<int[], int> f, int p) {\n  return f(new[] { p });\n}\n```\nThe impact of this breaking change needs to be considered. Fortunately, the use of `var` to infer the type of a method group has\nonly been supported since C# 10, so only code which has been written since then which explicitly relies on this behavior would break.\n\n## Detailed design\n\n[design]: #detailed-design\n\n### Grammar and parser changes\nThis enhancement requires the following changes to the grammar for lambda expressions.\n```diff\n lambda_expression\n   : modifier* identifier '=>' (block | expression)\n-  | attribute_list* modifier* type? lambda_parameters '=>' (block | expression)\n+  | attribute_list* modifier* type? lambda_parameter_list '=>' (block | expression)\n   ;\n\n+lambda_parameter_list\n+  : lambda_parameters (',' parameter_array)?\n+  | parameter_array\n+  ;\n\n lambda_parameter\n   : identifier\n-  | attribute_list* modifier* type? identifier\n+  | attribute_list* modifier* type? identifier default_argument?\n   ;\n```\n\nNote that this allows default parameter values and `params` arrays only for lambdas, not for anonymous methods declared with `delegate { }` syntax.\n\nSame rules as for method parameters ([§15.6.2](https://github.com/dotnet/csharpstandard/blob/draft-v7/standard/classes.md#1562-method-parameters)) apply for lambda parameters:\n- A parameter with a `ref`, `out` or `this` modifier cannot have a *default_argument*.\n- A *parameter_array* may occur after an optional parameter, but cannot have a default value – the omission of arguments for a *parameter_array* would instead result in the creation of an empty array.\n\nNo changes to the grammar are necessary for method groups since this proposal would only change their semantics.\n\nThe following addition (in bold) is required to anonymous function conversions ([§10.7](https://github.com/dotnet/csharpstandard/blob/draft-v7/standard/conversions.md#107-anonymous-function-conversions)):\n\n> Specifically, an anonymous function `F` is compatible with a delegate type `D` provided:\n>\n> - [...]\n> - If `F` has an explicitly typed parameter list, each parameter in `D` has the same type and modifiers as the corresponding parameter in `F` **ignoring `params` modifiers and default values**.\n\n### Updates of prior proposals\n\nThe following addition (in bold) is required to the [function types](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/lambda-improvements.md#natural-function-type) specification in a prior proposal:\n\n> A _method group_ has a natural type if all candidate methods in the method group have a common signature **including default values and `params` modifiers**. (If the method group may include extension methods, the candidates include the containing type and all extension method scopes.)\n\n> The natural type of an anonymous function expression or method group is a *function_type*. A *function_type* represents a method signature: the parameter types, **default values, ref kinds, `params` modifiers**, and return type and ref kind. Anonymous function expressions or method groups with the same signature have the same *function_type*.\n\nThe following addition (in bold) is required to the [delegate types](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/lambda-improvements.md#delegate-types) specification in a prior proposal:\n\n> The delegate type for the anonymous function or method group with parameter types `P1, ..., Pn` and return type `R` is:\n>\n> - if any parameter or return value is not by value, **or any parameter is optional or `params`**, or there are more than 16 parameters, or any of the parameter types or return are not valid type arguments (say, `(int* p) => { }`), then the delegate is a synthesized `internal` anonymous delegate type with signature that matches the anonymous function or method group, and with parameter names `arg1, ..., argn` or `arg` if a single parameter;\n> [...]\n\n### Binder changes\n\n#### Synthesizing new delegate types\nAs with the behavior for delegates with `ref` or `out` parameters, delegate types are synthesized for lambdas or method groups defined with optional or `params` parameters.\nNote that in the below examples, the notation `a'`, `b'`, etc. is used to represent these anonymous delegate types.\n\n```csharp\nvar addWithDefault = (int addTo = 2) => addTo + 1;\n// internal delegate int a'(int arg = 2);\nvar printString = (string toPrint = \"defaultString\") => Console.WriteLine(toPrint);\n// internal delegate void b'(string arg = \"defaultString\");\nvar counter = (params int[] xs) => xs.Length;\n// internal delegate int c'(params int[] arg);\nstring PathJoin(string s1, string s2, string sep = \"/\") { return $\"{s1}{sep}{s2}\"; }\nvar joinFunc = PathJoin;\n// internal delegate string d'(string arg1, string arg2, string arg3 = \" \");\n```\n\n#### Conversion and unification behavior \nAnonymous delegates with optional parameters will be unified when the same parameter (based on position) has the same default value, regardless of parameter name.\n\n```csharp\nint E(int j = 13) {\n  return 11;\n}\n\nint F(int k = 0) {\n  return 3;\n}\n\nint G(int x = 13) {\n  return 4;\n}\n\nvar a = (int i = 13) => 1;\n// internal delegate int b'(int arg = 13);\nvar b = (int i = 0) => 2;\n// internal delegate int c'(int arg = 0);\nvar c = (int i = 13) => 3;\n// internal delegate int b'(int arg = 13);\nvar d = (int c = 13) => 1;\n// internal delegate int b'(int arg = 13);\n\nvar e = E;\n// internal delegate int b'(int arg = 13);\nvar f = F;\n// internal delegate int c'(int arg = 0);\nvar g = G;\n// internal delegate int b'(int arg = 13);\n\na = b; // Not allowed\na = c; // Allowed\na = d; // Allowed\nc = e; // Allowed\ne = f; // Not Allowed\nb = f; // Allowed\ne = g; // Allowed\n\nd = (int c = 10) => 2; // Warning: default parameter value is different between new lambda\n                       // and synthesized delegate b'. We won't do implicit conversion\n```\n\nAnonymous delegates with an array as the last parameter will be unified when the last parameter has the same `params` modifier and array type, regardless of parameter name.\n\n```csharp\nint C(int[] xs) {\n  return xs.Length;\n}\n\nint D(params int[] xs) {\n  return xs.Length;\n}\n\nvar a = (int[] xs) => xs.Length;\n// internal delegate int a'(int[] xs);\nvar b = (params int[] xs) => xs.Length;\n// internal delegate int b'(params int[] xs);\n\nvar c = C;\n// internal delegate int a'(int[] xs);\nvar d = D;\n// internal delegate int b'(params int[] xs);\n\na = b; // Not allowed\na = c; // Allowed\nb = c; // Not allowed\nb = d; // Allowed\n\nc = (params int[] xs) => xs.Length; // Warning: different delegate types; no implicit conversion\nd = (int[] xs) => xs.Length; // OK. `d` is `delegate int (params int[] arg)`\n```\n\nSimilarly, there is of course compatibility with named delegates that already support optional and `params` parameters.\nWhen default values or `params` modifiers differ in a conversion, the source one will be unused if it's in a lambda expression, since the lambda cannot be called in any other way.\nThat might seem counter-intuitive to users, hence a warning will be emitted when the source default value or `params` modifier is present and different from the target one.\nIf the source is a method group, it can be called on its own, hence no warning will be emitted.\n\n```csharp\ndelegate int DelegateNoDefault(int x);\ndelegate int DelegateWithDefault(int x = 1);\n\nint MethodNoDefault(int x) => x;\nint MethodWithDefault(int x = 2) => x;\nDelegateNoDefault d1 = MethodWithDefault; // no warning: source is a method group\nDelegateWithDefault d2 = MethodWithDefault; // no warning: source is a method group\nDelegateWithDefault d3 = MethodNoDefault; // no warning: source is a method group\nDelegateNoDefault d4 = (int x = 1) => x; // warning: source present, target missing\nDelegateWithDefault d5 = (int x = 2) => x; // warning: source present, target different\nDelegateWithDefault d6 = (int x) => x; // no warning: source missing, target present\n\ndelegate int DelegateNoParams(int[] xs);\ndelegate int DelegateWithParams(params int[] xs);\n\nint MethodNoParams(int[] xs) => xs.Length;\nint MethodWithParams(params int[] xs) => xs.Length;\nDelegateNoParams d7 = MethodWithParams; // no warning: source is a method group\nDelegateWithParams d8 = MethodNoParams; // no warning: source is a method group\nDelegateNoParams d9 = (params int[] xs) => xs.Length; // warning: source present, target missing\nDelegateWithParams d10 = (int[] xs) => xs.Length; // no warning: source missing, target present\n```\n\n### IL/runtime behavior\n\nThe default parameter values will be emitted to metadata. The IL for this feature will be very similar in nature to the IL emitted for lambdas with `ref` and `out` parameters. A class which\ninherits from `System.Delegate` or similar will be generated, and the `Invoke` method will include `.param` directives to set default parameter values or `System.ParamArrayAttribute` &ndash; \njust as would be the case for a standard named delegate with optional or `params` parameters.\n\nThese delegate types can be inspected at runtime, as normal.\nIn code, users can introspect the `DefaultValue` in the `ParameterInfo` associated with the lambda or method group by using the associated `MethodInfo`.\n\n```csharp\nvar addWithDefault = (int addTo = 2) => addTo + 1;\nint AddWithDefaultMethod(int addTo = 2)\n{\n    return addTo + 1;\n}\n\nvar defaultParm = addWithDefault.Method.GetParameters()[0].DefaultValue; // 2\n\nvar add1 = AddWithDefaultMethod;\ndefaultParm = add1.Method.GetParameters()[0].DefaultValue; // 2\n```\n\n## Open questions\n\nNeither of these have been implemented. They remain open proposals.\n\n**Open question:** how does this interact with the existing `DefaultParameterValue` attribute?\n\n**Proposed answer:** For parity, permit the `DefaultParameterValue` attribute on lambdas and ensure that the delegate generation behavior matches for default parameter values supported via the syntax.\n\n```csharp\nvar a = (int i = 13) => 1;\n// same as\nvar b = ([DefaultParameterValue(13)] int i) => 1;\nb = a; // Allowed\n```\n\n**Open question:** First, note that this is outside the scope of the current proposal but it might be worth discussing in the future.\nDo we want to support defaults with implicitly typed lambda parameters? I.e., \n\n```csharp\ndelegate void M1(int i = 3);\nM1 m = (x = 3) => x + x; // Ok\n\ndelegate void M2(long i = 2);\nM2 m = (x = 3.0) => ...; //Error: cannot convert implicitly from long to double\n```\nThis inference leads to some tricky conversion issues which would require more discussion.\n\nThere are also parsing performance considerations here. For instance, today the term\n`(x = ` could never be the start of a lambda expression. If this syntax was allowed for lambda defaults, then the parser\nwould need a larger lookahead (scanning all the way until a `=>` token) in order to determine whether a term is a lambda or not.\n\n## Design meetings\n\n- [LDM 2022-10-10](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-10-10.md#params-support-for-lambda-default-parameters): decision to add support for `params` in the same way as default parameter values.\n"
  },
  {
    "path": "proposals/csharp-12.0/primary-constructors.md",
    "content": "# Primary constructors\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/2691>\n\n## Summary\n[summary]: #summary\n\nClasses and structs can have a parameter list, and their base class specification can have an argument list.\nPrimary constructor parameters are in scope throughout the class or struct declaration, and if they are captured by a function member or anonymous function, they are appropriately stored (e.g. as unspeakable private fields of the declared class or struct).\n\nThe proposal \"retcons\" the primary constructors already available on records in terms of this more general feature with some additional members synthesized.\n\n## Motivation\n[motivation]: #motivation\n\nThe ability of a class or struct in C# to have more than one constructor provides for generality, but at the expense of some tedium in the declaration syntax, because the constructor input and the class state need to be cleanly separated.\n\nPrimary constructors put the parameters of one constructor in scope for the whole class or struct to be used for initialization or directly as object state. The trade-off is that any other constructors must call through the primary constructor.\n\n``` c#\npublic class B(bool b) { } // base class\n\npublic class C(bool b, int i, string s) : B(b) // b passed to base constructor\n{\n    public int I { get; set; } = i; // i used for initialization\n    public string S // s used directly in function members\n    {\n        get => s;\n        set => s = value ?? throw new ArgumentNullException(nameof(S));\n    }\n    public C(string s) : this(true, 0, s) { } // must call this(...)\n}\n```\n\n## Detailed design\n[design]: #detailed-design\n\nThis describes the generalized design across records and non-records, and then details how the existing primary constructors for records are specified by adding a set of synthesized members in the presence of a primary constructor.\n\n### Syntax\nClass and struct declarations are augmented to allow a parameter list on the type name, an argument list on the base class, and a body consisting of just a `;`:\n\n``` antlr\nclass_declaration\n  : attributes? class_modifier* 'partial'? class_designator identifier type_parameter_list?\n  parameter_list? class_base? type_parameter_constraints_clause* class_body\n  ;\n  \nclass_designator\n  : 'record' 'class'?\n  | 'class'\n  \nclass_base\n  : ':' class_type argument_list?\n  | ':' interface_type_list\n  | ':' class_type  argument_list? ',' interface_type_list\n  ;  \n  \nclass_body\n  : '{' class_member_declaration* '}' ';'?\n  | ';'\n  ;\n  \nstruct_declaration\n  : attributes? struct_modifier* 'partial'? 'record'? 'struct' identifier type_parameter_list?\n    parameter_list? struct_interfaces? type_parameter_constraints_clause* struct_body\n  ;\n\nstruct_body\n  : '{' struct_member_declaration* '}' ';'?\n  | ';'\n  ;\n  \ninterface_declaration\n  : attributes? interface_modifier* 'partial'? 'interface'\n    identifier variant_type_parameter_list? interface_base?\n    type_parameter_constraints_clause* interface_body\n  ;  \n    \ninterface_body\n  : '{' interface_member_declaration* '}' ';'?\n  | ';'\n  ;\n\nenum_declaration\n  : attributes? enum_modifier* 'enum' identifier enum_base? enum_body\n  ;\n\nenum_body\n  : '{' enum_member_declarations? '}' ';'?\n  | '{' enum_member_declarations ',' '}' ';'?\n  | ';'\n  ;\n```\n\n***Note:*** These productions replace `record_declaration` in [Records](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-9.0/records.md#records) and `record_struct_declaration` in [Record structs](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/record-structs.md#record-structs), which both become obsolete. \n\nIt is an error for a `class_base` to have an `argument_list` if the enclosing `class_declaration` does not contain a `parameter_list`. At most one partial type declaration of a partial class or struct may provide a `parameter_list`. The parameters in the `parameter_list` of a `record` declaration must all be value parameters.\n\nNote, according to this proposal `class_body`, `struct_body`, `interface_body` and `enum_body` are allowed to consist of just a `;`.\n\nA class or struct with a `parameter_list` has an implicit public constructor whose signature corresponds to the value parameters of the type declaration. This is called the ***primary constructor*** for the type, and causes the implicitly declared parameterless constructor, if present, to be suppressed. It is an error to have a primary constructor and a constructor with the same signature already present in the type declaration.\n\n### Lookup\n\nThe [lookup of simple names](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1284-simple-names) is augmented to handle primary constructor parameters. The changes are highlighted in **bold** in the following excerpt:\n\n> - Otherwise, for each instance type `T` ([§15.3.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#1532-the-instance-type)), starting with the instance type of the immediately enclosing type declaration and continuing with the instance type of each enclosing class or struct declaration (if any):\n>   - **If the declaration of `T` includes a primary constructor parameter `I` and the reference occurs within the `argument_list` of `T`'s `class_base` or within an initializer of a field, property or event of `T`, the result is the primary constructor parameter `I`**\n>   - **Otherwise,** if `e` is zero and the declaration of `T` includes a type parameter with name `I`, then the *simple_name* refers to that type parameter.\n>   - Otherwise, if a member lookup ([§12.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#125-member-lookup)) of `I` in `T` with `e` type arguments produces a match:\n>     - If `T` is the instance type of the immediately enclosing class or struct type and the lookup identifies one or more methods, the result is a method group with an associated instance expression of `this`. If a type argument list was specified, it is used in calling a generic method ([§12.8.10.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#128102-method-invocations)).\n>     - Otherwise, if `T` is the instance type of the immediately enclosing class or struct type, if the lookup identifies an instance member, and if the reference occurs within the *block* of an instance constructor, an instance method, or an instance accessor ([§12.2.1](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1221-general)), the result is the same as a member access ([§12.8.7](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1287-member-access)) of the form `this.I`. This can only happen when `e` is zero.\n>     - Otherwise, the result is the same as a member access ([§12.8.7](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1287-member-access)) of the form `T.I` or `T.I<A₁, ..., Aₑ>`.\n>   - **Otherwise, if the declaration of `T` includes a primary constructor parameter `I`, the result is the primary constructor parameter `I`.**\n\nThe first addition corresponds to the change incurred by [primary constructors on records](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-9.0/records.md#primary-constructor), and ensures that primary constructor parameters are found before any corresponding fields within initializers and base class arguments. It extends this rule to static initializers as well. However, since records always have an instance member with the same name as the parameter, the extension can only lead to a change in an error message. Illegal access to a parameter vs. illegal access to an instance member.  \n\nThe second addition allows primary constructor parameters to be found elsewhere within the type body, but only if not shadowed by members.\n\nIt is an error to reference a primary constructor parameter if the reference does not occur within one of the following:\n- a `nameof` argument\n- an initializer of an instance field, property or event of the declaring type (type declaring primary constructor with the parameter).\n- the `argument_list` of `class_base` of the declaring type.\n- the body of an instance method (note that instance constructors are excluded) of the declaring type.\n- the body of an instance accessor of the declaring type.\n\nIn other words, primary constructor parameters are in scope throughout the declaring type body. They shadow members of the declaring type within\nan initializer of a field, property or event of the declaring type, or within the `argument_list` of `class_base` of the declaring type. They are shadowed by members of the declaring type everywhere else.\n\nThus, in the following declaration:\n\n``` c#\nclass C(int i)\n{\n    protected int i = i; // references parameter\n    public int I => i; // references field\n}\n```\n\nThe initializer for the field `i` references the parameter `i`, whereas the body of the property `I` references the field `i`.\n\n#### Warn on shadowing by a member from base\n\nCompiler will produce a warning on usage of an identifier when a base member shadows a primary constructor parameter\nif that primary constructor parameter was not passed to the base type via its constructor.\n\nA primary constructor parameter is considered to be passed to the base type via its constructor when all the following conditions\nare true for an argument in *class_base*:\n- The argument represents an implicit or explicit identity conversion of a primary constructor parameter;\n- The argument is not part of an expanded `params` argument;\n\n## Semantics\n\nA primary constructor leads to the generation of an instance constructor on the enclosing type with the given parameters. If the `class_base` has an argument list, the generated instance constructor will have a `base` initializer with the same argument list.\n\nPrimary constructor parameters in class/struct declarations can be declared `ref`, `in` or `out`. Declaring `ref` or `out` parameters remains illegal in primary constructors of record declaration.\n\nAll instance member initializers in the class body will become assignments in the generated constructor.\n\nIf a primary constructor parameter is referenced from within an instance member, and the reference is not inside of a `nameof` argument, it is captured into the state of the enclosing type, so that it remains accessible after the termination of the constructor. A likely implementation strategy is via a private field using a mangled name. In a readonly struct the capture fields will be readonly. Therefore, access to captured parameters of a readonly struct will have similar restrictions as access to readonly fields. Access to captured parameters within a readonly member will have similar restrictions as access to instance fields in the same context.\n\nCapturing is not allowed for parameters that have ref-like type, and capturing is not allowed for `ref`, `in` or `out` parameters. This is similar to a limitation for capturing in lambdas. \n\nIf a primary constructor parameter is only referenced from within instance member initializers, those can directly reference the parameter of the generated constructor, as they are executed as part of it.\n\nPrimary Constructor will do the following sequence of operations:\n1.\tParameter values are stored in capture fields, if any.\n2.\tInstance initializers are executed\n3.\tBase constructor initializer is called\n\nParameter references in any user code are replaced with corresponding capture field references.\n\nFor instance this declaration:\n\n``` c#\npublic class C(bool b, int i, string s) : B(b) // b passed to base constructor\n{\n    public int I { get; set; } = i; // i used for initialization\n    public string S // s used directly in function members\n    {\n        get => s;\n        set => s = value ?? throw new ArgumentNullException(nameof(value));\n    }\n    public C(string s) : this(true, 0, s) { } // must call this(...)\n}\n```\n\nGenerates code similar to the following:\n\n``` c#\npublic class C : B\n{\n    public int I { get; set; }\n    public string S\n    {\n        get => __s;\n        set => __s = value ?? throw new ArgumentNullException(nameof(value));\n    }\n    public C(string s) : this(0, s) { ... } // must call this(...)\n    \n    // generated members\n    private string __s; // for capture of s\n    public C(bool b, int i, string s)\n    {\n        __s = s; // capture s\n        I = i; // run I's initializer\n        B(b) // run B's constructor\n    }\n}\n```\n\nIt is an error for a non-primary constructor declaration to have the same parameter list as the primary constructor. All non-primary constructor declarations must use a `this` initializer, so that the primary constructor is ultimately called.\n\nRecords produce a warning if a primary constructor parameter isn't read within the (possibly generated) instance initializers or base initializer. Similar warnings will be reported for primary constructor parameters in classes and structures:\n- for a by-value parameter, if the parameter is not captured and is not read within any instance initializers or base initializer.\n- for an `in` parameter, if the parameter is not read within any instance initializers or base initializer. \n- for a `ref` parameter, if the parameter is not read or written to within any instance initializers or base initializer. \n\n### Identical simple names and type names\n\nThere is a special language rule for scenarios often referred to as \"Color Color\" scenarios - [Identical simple names and type names](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12872-identical-simple-names-and-type-names). \n\n>In a member access of the form `E.I`, if `E` is a single identifier, and if the meaning of `E` as a *simple_name* ([§12.8.4](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1274-simple-names)) is a constant, field, property, local variable, or parameter with the same type as the meaning of `E` as a *type_name* ([§7.8.1](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/basic-concepts.md#781-general)), then both possible meanings of `E` are permitted. The member lookup of `E.I` is never ambiguous, since `I` shall necessarily be a member of the type `E` in both cases. In other words, the rule simply permits access to the static members and nested types of `E` where a compile-time error would otherwise have occurred.\n\nWith respect to primary constructors, the rule affects whether an identifier within an instance member should be treated as a type reference, or as a primary constructor parameter reference, which, in turn, captures the parameter into the the state of the enclosing type. Even though \"the member lookup of `E.I` is never ambiguous\", when lookup yields a member group, in some cases it is impossible to determine whether a member access refers to a static member or an instance member without fully resolving (binding) the member access. At the same time, capturing a primary constructor parameter changes properties of enclosing type in a way that affects semantic analysis. For example, the type might become unmanaged and fail certain constraints because of that. \nThere are even scenarios for which binding can succeed either way, depending on whether the parameter is considered captured or not. For example:\n``` C#\nstruct S1(Color Color)\n{\n    public void Test()\n    {\n        Color.M1(this); // Error: ambiguity between parameter and typename\n    }\n}\n\nclass Color\n{\n    public void M1<T>(T x, int y = 0)\n    {\n        System.Console.WriteLine(\"instance\");\n    }\n    \n    public static void M1<T>(T x) where T : unmanaged\n    {\n        System.Console.WriteLine(\"static\");\n    }\n}\n```\n\nIf we treat receiver ```Color``` as a value, we capture the parameter and 'S1' becomes managed. Then the static method becomes inapplicable due to the constraint and we would call instance method. However, if we treat the receiver as a type, we don't capture the parameter and 'S1' remains unmanaged, then both methods are applicable, but the static method is \"better\" because it doesn't have an optional parameter. Neither choice leads to an error, but each would result in distinct behavior.\n\nGiven this, compiler will produce an ambiguity error for a member access `E.I` when all the following conditions are met:\n- Member lookup of `E.I` yields a member group containing instance and static members at the same time. Extension methods applicable to the receiver type are treated as instance methods for the purpose of this check.\n- If `E` is treated as a simple name, rather than a type name, it would refer to a primary constructor parameter and would capture the parameter into the state of the enclosing type. \n\n### Double storage warnings\n\nIf a primary constructor parameter is passed to the base and *also* captured, there's a high risk that it is inadvertently stored twice in the object. \n\nCompiler will produce a warning for `in` or by value argument in a `class_base` `argument_list` when all the following conditions are true:\n- The argument represents an implicit or explicit identity conversion of a primary constructor parameter;\n- The argument is not part of an expanded `params` argument;\n- The primary constructor parameter is captured into the state of the enclosing type.\n\nCompiler will produce a warning for a `variable_initializer` when all the following conditions are true:\n- The variable initializer represents an implicit or explicit identity conversion of a primary constructor parameter;\n- The primary constructor parameter is captured into the state of the enclosing type.\n\nFor example:\n``` c#\npublic class Person(string name)\n{\n    public string Name { get; set; } = name;   // warning: initialization\n    public override string ToString() => name; // capture\n}\n```\n\n## Attributes targeting primary constructors\n\nAt https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-03-13.md we decided to embrace\nthe https://github.com/dotnet/csharplang/issues/7047 proposal.\n\nThe \"method\" attribute target is allowed on a *class_declaration*/*struct_declaration* with *parameter_list* and results in the\ncorresponding primary constructor having that attribute.\nAttributes with the `method` target on a *class_declaration*/*struct_declaration* without *parameter_list* are are ignored\nwith a warning.\n\n``` C#\n[method: FooAttr] // Good\npublic partial record Rec(\n    [property: Foo] int X,\n    [field: NonSerialized] int Y\n);\n[method: BarAttr] // warning CS0657: 'method' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'type'. All attributes in this block will be ignored.\npublic partial record Rec\n{\n    public void Frobnicate()\n    {\n        ...\n    }\n}\n[method: Attr] // Good\npublic record MyUnit1();\n[method: Attr] // warning CS0657: 'method' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'type'. All attributes in this block will be ignored.\npublic record MyUnit2;\n```\n\n## Primary constructors on records\n\nWith this proposal, records no longer need to separately specify a primary constructor mechanism. Instead, record (class and struct) declarations that have primary constructors would follow the general rules, with these simple additions:\n\n- For each primary constructor parameter, if a member with the same name already exists, it must be an instance property or field. If not, a public init-only auto-property of the same name is synthesized with a property initializer assigning from the parameter.\n- A deconstructor is synthesized with out parameters to match the primary constructor parameters.\n- If an explicit constructor declaration is a \"copy constructor\" - a constructor that takes a single parameter of the enclosing type - it is not required to call a `this` initializer, and will not execute the member initializers present in the record declaration.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\n* The allocation size of constructed objects is less obvious, as the compiler determines whether to allocate a field for a primary constructor parameter based on the full text of the class. This risk is similar to the implicit capture of variables by lambda expressions.\n* A common temptation (or accidental pattern) might be to capture the \"same\" parameter at multiple levels of inheritance as it is passed up the constructor chain instead of explicitly allotting it a protected field at the base class, leading to duplicated allocations for the same data in objects. This is very similar to today's risk of overriding auto-properties with auto-properties. \n* As proposed here, there is no place for additional logic that might usually be expressed in constructor bodies. The \"primary constructor bodies\" extension below addresses that.\n* As proposed, execution order semantics are subtly different from within ordinary constructors, delaying member initializers to after the base calls. This could probably be remedied, but at the cost of some of the extension proposals (notably \"primary constructor bodies\").\n* The proposal only works for scenarios where a single constructor can be designated primary.\n* There is no way to express separate accessibility of the class and the primary constructor. An example is when public constructors all delegate to one private \"build-it-all\" constructor. If necessary, syntax could be proposed for that later.\n\n\n## Alternatives\n[alternatives]: #alternatives\n\n### No capture\n\nA much simpler version of the feature would prohibit primary constructor parameters from occurring in member bodies. Referencing them would be an error. Fields would have to be explicitly declared if storage is desired beyond the initialization code.\n\n``` c#\npublic class C(string s)\n{\n    public string S1 => s; // Nope!\n    public string S2 { get; } = s; // Still allowed\n}\n```\n\nThis could still be evolved to the full proposal at a later time, and would avoid a number of decisions and complexities, at the cost of removing less boilerplate initially, and probably also seeming unintuitive. \n\n### Explicit generated fields\n\nAn alternative approach is for primary constructor parameters to always and visibly generate a field of the same name. Instead of closing over the parameters in the same manner as local and anonymous functions, there would explicitly be a generated member declaration, similar to the public properties generated for primary construcor parameters in records. Just like for records, if a suitable member already exists, one would not be generated.\n\nIf the generated field is private it could still be elided when it is not used as a field in member bodies. In classes, however, a private field would often not be the right choice, because of the state duplication it could cause in derived classes. An option here would be to instead generating a protected field in classes, encouraging reuse of storage across inheritance layers. However, then we would not be able to elide the declaration, and would incur allocation cost for every primary constructor parameter.\n\nThis would align non-record primary constructors more closely with record ones, in that members are always (at least conceptually) generated, albeit different kinds of members with different accessibilities. But it would also lead to surprising differences from how parameters and locals are captured elsewhere in C#. If we were ever to allow local classes, for example, they would capture enclosing parameters and locals implicitly. Visibly generating shadowing fields for them would not seem to be a reasonable behavior.\n\nAnother problem often raised with this approach is that many developers have different naming conventions for parameters and fields. Which should be used for the primary constructor parameter? Either choice would lead to inconsistency with the rest of the code.\n\nFinally, visibly generating member declarations is really the name of the game for records, but much more surprising and \"out of character\" for non-record classes and structs. All in all, those are the reasons why the main proposal opts for implicit capture, with sensible behavior (consistent with records) for explicit member declarations when they are desired.\n\n### Remove instance members from initializer scope\n\nThe lookup rules above are intended to allow for the current behavior of primary constructor parameters in records when a corresponding member is manually declared, and to explain the behavior of the generated member when it is not. This requires lookup to differ between \"initialization scope\" (this/base initializers, member initializers) and \"body scope\" (member bodies), which the above proposal achieves by changing *when* primary constructor parameters are looked for, depending on where the reference occurs.\n\nAn observation is that referencing an instance member with a simple name in initializer scope always leads to an error. Instead of merely shadowing instance members in those places, could we simply take them out of scope? That way, there wouldn't be this weird conditional ordering of scopes.\n\nThis alternative is probably possible, but it would have some consequences that are somewhat far-reaching and potentially undesirable. First of all, if we remove instance members from initializer scope then a simple name that *does* correspond to an instance member and *not* to a primary constructor parameter could accidentally bind to something outside of the type declaration! This seems like it would rarely be intentional, and an error would be better.\n\nFurthermore, *static* members are fine to reference in initialization scope. So we would have to distinguish between static and instance members in lookup, something we don't do today. (We do distinguish in overload resolution but that is not in play here). So that would have to also be changed, leading to yet more situations where e.g. in static contexts something would bind \"further out\" rather than error because it found an instance member.\n\nAll in all this \"simplification\" would lead to quite a downstream complication that no-one asked for.\n\n## Possible extensions\n[extensions]: #possible-extensions\n\nThese are variations or additions to the core proposal that may be considered in conjunction with it, or at a later stage if deemed useful.\n\n### Primary constructor parameter access within constructors\n\nThe rules above make it an error to reference a primary constructor parameter within another constructor. This could be allowed within the *body* of other constructors, though, since the primary constructor runs first. However it would need to remain disallowed within the argument list of the `this` initializer.\n\n``` c#\npublic class C(bool b, int i, string s) : B(b)\n{\n    public C(string s) : this(b, s) // b still disallowed\n    { \n        i++; // could be allowed\n    }\n}\n```\n\nSuch access would still incur capture, as that would be the only way the constructor body could get at the variable after the primary constructor has already run. \n\nThe prohibition on primary constructor parameters in the this-initializer's arguments could be weakened to allow them, but make them not definitely assigned, but that does not seem useful.\n\n### Allow constructors without a `this` initializer\n\nConstructors without a `this` initializer (i.e. with an implicit or explicit `base` initializer) could be allowed. Such a constructor would *not* run instance field, property and event initializers, as those would be considered to be part of the primary constructor only.\n\nIn the presence of such base-calling constructors, there are a couple of options for how primary constructor parameter capture is handled. The simplest is to completely disallow capture in this situation. Primary constructor parameters would be for initialization only when such constructors exist.\n\nAlternatively, if combined with the previously described option to allow access to primary constructor parameters within constructors, the parameters could enter the constructor body as not definitely assigned, and ones that are captured would need to be definitely assigned by the end of the constructor body. They would essentially be implicit out parameters. That way, captured primary constructor parameters would always have a sensible (i.e. explicitly assigned) value by the time they are consumed by other function members.\n\nAn attraction of this extension (in either form) is that it fully generalizes the current exemption for \"copy constructors\" in records, without leading to situations where uninitialized primary constructor parameters are observed. Essentially, constructors that initialize the object in alternative ways are fine. The capture-related restrictions would not be a breaking change for existing manually defined copy constructors in records, because records never capture their primary constructor parameters (they generate fields instead).\n\n``` c#\npublic class C(bool b, int i, string s) : B(b)\n{\n    public int I { get; set; } = i; // i used for initialization\n    public string S // s used directly in function members\n    {\n        get => s;\n        set => s = value ?? throw new ArgumentNullException(nameof(value));\n    }\n    public C(string s2) : base(true) // cannot use `string s` because it would shadow\n    { \n        s = s2; // must initialize s because it is captured by S\n    }\n    protected C(C original) : base(original) // copy constructor\n    {\n        this.s = original.s; // assignment to b and i not required because not captured\n    }\n}\n```\n\n### Primary constructor bodies\n\nConstructors themselves often contain parameter validation logic or other nontrivial initialization code that cannot be expressed as initializers.\n\nPrimary constructors could be extended to allow statement blocks to appear directly in the class body. Those statements would be inserted in the generated constructor at the point where they appear between initializing assignments, and would thus be executed interspersed with initializers. For instance:\n\n``` c#\npublic class C(int i, string s) : B(s)\n{\n    {\n        if (i < 0) throw new ArgumentOutOfRangeException(nameof(i));\n    }\n\tint[] a = new int[i];\n    public int S => s;\n}\n```\n\nA lot of this scenario might be adequately be covered if we were to introduce \"final initializers\" which run after the constructors *and* any object/collection initializers have completed. However, argument validation is one thing that would ideally happen as early as possible.\n\nPrimary constructor bodies could also provide a place for allowing an access modifier for the primary constructor, allowing it to deviate from the accessibility of the enclosing type.\n\n### Combined parameter and member declarations\n\nA possible and often mentioned addition could be to allow primary constructor parameters to be annotated so that they would *also* declare a member on the type. Most commonly it is proposed to allow an access specifier on the parameters to trigger the member generation:\n\n``` c#\npublic class C(bool b, protected int i, string s) : B(b) // i is a field as well as a parameter\n{\n    void M()\n    {\n        ... i ... // refers to the field i\n        ... s ... // closes over the parameter s\n    }\n}\n```\n\nThere are some problems: \n  - What if a property is desired, not a field? Having `{ get; set; }` syntax inline in a parameter list does not seem appetizing.\n  - What if different naming conventions are used for parameters and fields? Then this feature would be useless.\n  \nThis is a potential future addition that can be adopted or not. The current proposal leaves the possibility open.\n\n## Open questions\n\n### Lookup order for type parameters\n\nThe https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/primary-constructors.md#lookup section specifies that type parameters\nof declaring type should come before type's primary constructor parameters in every context where those parameters are in scope. However,\nwe already have existing behavior with records - primary constructor parameters come before type parameters in base initializer and field\ninitializers. \n\nWhat should we do about this discrepancy?\n- Adjust the rules to match the behavior.\n- Adjust the behavior (a possible breaking change).\n- Disallow a primiry constructor parameter to use type parameter's name (a possible breaking change).\n- Do nothing, accept the inconsistency between the spec and implementation.\n\n#### Conclusion:\n\nAdjust the rules to match the behavior (https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-09-25.md#primary-constructors).\n\n### Field targeting attributes for captured primary constructor parameters\n\nShould we allow field targeting attributes for captured primary constructor parameters?\n\n``` C#\nclass C1([field: Test] int x) // Parameter is captured, the attribute goes to the capture field\n{\n    public int X => x;\n}\nclass C2([field: Test] int x) // Parameter is not captured, the attribute is ignored with a warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'param'. All attributes in this block will be ignored.\n{\n    public int X = x;\n}\n```\n\nRight now the attributes are ignored with the warning regardless of whether the parameter is captured.\n\nNote that for records, field targeted attributes are allowed when a property is synthesized for it. The attributes \ngo on the backing field then.\n\n``` C#\nrecord R1([field: Test]int X); // Ok, the attribute goes on the backing field\nrecord R2([field: Test]int X) // warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'param'. All attributes in this block will be ignored.\n{\n    public int X = X;\n}\n```\n#### Conclusion:\nNot allowed (https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-05-03.md#attributes-on-captured-parameters).\n\n### Warn on shadowing by a member from base\n\nShould we report a warning when a member from base is shadowing a primary constructor parameter inside a member (see https://github.com/dotnet/csharplang/discussions/7109#discussioncomment-5666621)?\n\n#### Conclusion:\n\nAn alternative design is approved - https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-05-08.md#primary-constructors\n\n### Capturing instance of the enclosing type in a closure\n\nWhen a parameter captured into the state of the enclosing type is also referenced in a lambda inside an instance initializer or a base initializer, the lambda and the state of the enclosing type should refer to the same location for the parameter.\nFor example:\n``` C#\npartial class C1\n{\n    public System.Func<int> F1 = Execute1(() => p1++);\n}\n\npartial class C1 (int p1)\n{\n    public int M1() { return p1++; }\n    static System.Func<int> Execute1(System.Func<int> f)\n    {\n        _ = f();\n        return f;\n    }\n}\n```\nSince naive implementation of capturing a parameter into the state of the type simply captures the parameter in a private instance field, the lambda needs to refer to the same field. As a result, it needs to be able to access the instance of the type. This requires capturing `this` into a closure before the base constructor is invoked. That, in turn, results in safe, but an unverifiable IL. Is this acceptable? \n\nAlternatively we could:\n- Disallow lambdas like that;\n- Or, instead, capture parameters like that in an instance of a separate class (yet another closure), and share that instance between the closure and the instance of the enclosing type. Thus eliminating the need to capture `this` in a closure.\n\n#### Conclusion:\nWe are comfortable with capturing `this` into a closure before the base constructor is invoked\n(https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-02-15.md).\nThe runtime team didn't find the IL pattern problematic as well.\n\n### Assigning to `this` within a struct\n\nC# allows to assign to `this` within a struct. If the struct captures a primary constructor parameter, the assignment is going to overwrite its value, which might be not obvious to the user. Do we want to report a warning for assignments like this?  \n\n``` C#\nstruct S(int x)\n{\n    int X => x;\n    \n    void M(S s)\n    {\n        this = s; // 'x' is overwritten\n    }\n}\n```\n\n#### Conclusion:\n\nAllowed, no warning (https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-02-15.md).\n\n### Double storage warning for initialization plus capture\n\nWe have a warning if a primary constructor parameter is passed to the base and *also* captured, because there's a high risk that it is inadvertently stored twice in the object. \n\nIt seems that there's a similar risk if a parameter is used to initialize a member, and is also captured. Here's a small example:\n\n``` c#\npublic class Person(string name)\n{\n    public string Name { get; set; } = name;   // initialization\n    public override string ToString() => name; // capture\n}\n```\n\nFor a given instance of `Person`, changes to `Name` would not be reflected in the output of `ToString`, which is probably unintended on the developer's part.\n\nShould we introduce a double storage warning for this situation?\n\nThis is how it would work:\n\nThe compiler will produce a warning for a `variable_initializer` when all the following conditions are true:\n- The variable initializer represents an implicit or explicit identity conversion of a primary constructor parameter;\n- The primary constructor parameter is captured into the state of the enclosing type.\n\n#### Conclusion:\n\nApproved, see https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-05-15.md#primary-constructors \n\n## LDM meetings\n\n- https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-10-17.md\n- https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-01-18.md\n- https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-02-15.md\n- https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-02-22.md\n- https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-03-13.md\n- https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-05-03.md#primary-constructors\n- https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-05-08.md#primary-constructors\n- https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-05-15.md#primary-constructors\n- https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-09-25.md#primary-constructors\n\n"
  },
  {
    "path": "proposals/csharp-12.0/ref-readonly-parameters.md",
    "content": "# `ref readonly` parameters\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/6010>\n\n## Summary\n[summary]: #summary\n\nAllow parameter declaration-site modifier `ref readonly` and change callsite rules as follows:\n\n| Callsite annotation  | `ref` parameter | `ref readonly` parameter | `in` parameter | `out` parameter |\n|----------------------|-----------------|--------------------------|----------------|-----------------|\n| `ref`                | Allowed         | **Allowed**              | **Warning**    | Error           |\n| `in`                 | Error           | **Allowed**              | Allowed        | Error           |\n| `out`                | Error           | **Error**                | Error          | Allowed         |\n| No annotation        | Error           | **Warning**              | Allowed        | Error           |\n\n(Note that there is one change to the existing rules: `in` parameter with `ref` callsite annotation produces a warning instead of an error.)\n\nChange argument value rules as follows:\n\n| Value kind | `ref` parameter | `ref readonly` parameter | `in` parameter | `out` parameter |\n|------------|-----------------|--------------------------|----------------|-----------------|\n| rvalue     | Error           | **Warning**              | Allowed        | Error           |\n| lvalue     | Allowed         | **Allowed**              | Allowed        | Allowed         |\n\nWhere lvalue means a variable (i.e., a value with a location; does not have to be writable/assignable)\nand rvalue means any kind of value.\n\n## Motivation\n[motivation]: #motivation\n\nC# 7.2 [introduced `in` parameters](https://github.com/dotnet/csharplang/blob/c8c1615fcad4ca016a97b7260ad497aad53ebc78/proposals/csharp-7.2/readonly-ref.md#solution-in-parameters) as a way to pass readonly references.\n`in` parameters allow both lvalues and rvalues and can be used without any annotation at the callsite.\nHowever, APIs which capture or return references from their parameters would like to disallow rvalues and also enforce some indication at the callsite that a reference is being captured.\n`ref readonly` parameters are ideal in such cases as they warn if used with rvalues or without any annotation at the callsite.\n\nFurthermore, there are APIs that need only read-only references but use\n\n- `ref` parameters since they were introduced before `in` became available and changing to `in` would be a source and binary breaking change, e.g., `QueryInterface`, or\n- `in` parameters to accept readonly references even though passing rvalues to them doesn't really make sense, e.g., `ReadOnlySpan<T>..ctor(in T value)`, or\n- `ref` parameters to disallow rvalues even though they don't mutate the passed reference, e.g., `Unsafe.IsNullRef`.\n\nThese APIs could migrate to `ref readonly` parameters without breaking users.\nFor details on binary compatibility, see the proposed [metadata encoding][metadata].\nSpecifically, changing\n\n- `ref` → `ref readonly` would only be a binary breaking change for virtual methods,\n- `ref` → `in` would also be a binary breaking change for virtual methods, but not a source breaking change (because the rules change to only warn for `ref` arguments passed to `in` parameters),\n- `in` → `ref readonly` would not be a breaking change (but no callsite annotation or rvalue would result in a warning),\n  - note that this would be a source breaking change for users using older compiler versions (as they interpret `ref readonly` parameters as `ref` parameters, disallowing `in` or no annotation at the callsite) and new compiler versions with `LangVersion <= 11` (for consistency with older compiler versions, an error will be emitted that `ref readonly` parameters are not supported unless the corresponding arguments are passed with the `ref` modifier).\n\nIn the opposite direction, changing\n\n- `ref readonly` → `ref` would be potentially a source breaking change (unless only `ref` callsite annotation was used and only readonly references used as arguments), and a binary breaking change for virtual methods,\n- `ref readonly` → `in` would not be a breaking change (but `ref` callsite annotation would result in a warning).\n\nNote that the rules outlined above apply to method signatures, but not to delegate signatures.\nFor example, changing `ref` to `in` in a delegate signature can be a source breaking change\n(if a user is assigning a method with `ref` parameter to that delegate type, it would become an error after the API change).\n\n## Detailed design\n[design]: #detailed-design\n\nIn general, rules for `ref readonly` parameters are the same as specified for `in` parameters in [their proposal](https://github.com/dotnet/csharplang/blob/c8c1615fcad4ca016a97b7260ad497aad53ebc78/proposals/csharp-7.2/readonly-ref.md), except where explicitly changed in this proposal.\n\n### Parameter declarations\n[declarations]: #parameter-declarations\n\nNo changes in grammar are necessary.\nThe modifier `ref readonly` will be allowed for parameters.\nApart from normal methods, `ref readonly` will be allowed for indexer parameters (like `in` but unlike `ref`),\nbut disallowed for operator parameters (like `ref` but unlike `in`).\n\nDefault parameter values will be allowed for `ref readonly` parameters with a warning since they are equivalent to passing rvalues.\nThis allows API authors to change `in` parameters with default values to `ref readonly` parameters without introducing a source breaking change.\n\n### Value kind checks\n[value-kind-checks]: #value-kind-checks\n\nNote that even though `ref` argument modifier is allowed for `ref readonly` parameters, nothing changes w.r.t. value kind checks, i.e.,\n\n- `ref` can only be used with assignable values;\n- to pass readonly references, one has to use the `in` argument modifier instead;\n- to pass rvalues, one has to use no modifier (which results in a warning for `ref readonly` parameters as described in [the summary of this proposal][summary]).\n\n### Overload resolution\n[overload-resolution]: #overload-resolution\n\nOverload resolution will allow mixing `ref`/`ref readonly`/`in`/no callsite annotations and parameter modifiers as denoted by the table in [the summary of this proposal][summary], i.e., all *allowed* and *warning* cases will be considered as possible candidates during overload resolution.\nSpecifically, there's a change in existing behavior where methods with `in` parameter will match calls with the corresponding argument marked as `ref`&mdash;this change will be gated on LangVersion.\n\nHowever, the warning for passing an argument with no callsite modifier to a `ref readonly` parameter will be suppressed if the parameter is\n\n- the receiver in an extension method invocation,\n- used implicitly as part of custom collection initializer or interpolated string handler.\n\nBy-value overloads will be preferred over `ref readonly` overloads in case there is no argument modifier (`in` parameters have the same behavior).\n\n#### Method conversions\n[method-conversions]: #method-conversions\n\nSimilarly, for the purpose of anonymous function [[§10.7](https://github.com/dotnet/csharpstandard/blob/47912d4fdae2bb8c3750e6485bdc6509560ec6bf/standard/conversions.md#107-anonymous-function-conversions)] and method group [[§10.8](https://github.com/dotnet/csharpstandard/blob/47912d4fdae2bb8c3750e6485bdc6509560ec6bf/standard/conversions.md#108-method-group-conversions)] conversions, these modifiers are considered compatible\n(but any allowed conversion between different modifiers results in a warning):\n\n- `ref readonly` parameter of the target method is allowed to match `in` or `ref` parameter of the delegate,\n- `in` parameter of the target method is allowed to match `ref readonly` or, gated on LangVersion, `ref` parameter of the delegate.\n- Note: `ref` parameter of the target method is *not* allowed to match `in` nor `ref readonly` parameter of the delegate.\n\nFor example:\n\n```cs\nDIn dIn = (ref int p) => { }; // error: cannot match `ref` to `in`\nDRef dRef = (in int p) => { }; // warning: mismatch between `in` and `ref`\nDRR dRR = (ref int p) => { }; // error: cannot match `ref` to `ref readonly`\ndRR = (in int p) => { }; // warning: mismatch between `in` and `ref readonly`\ndIn = (ref readonly int p) => { }; // warning: mismatch between `ref readonly` and `in`\ndRef = (ref readonly int p) => { }; // warning: mismatch between `ref readonly` and `ref`\ndelegate void DIn(in int p);\ndelegate void DRef(ref int p);\ndelegate void DRR(ref readonly int p);\n```\n\nNote that there is no change in behavior of [function pointer conversions](https://github.com/dotnet/csharplang/blob/4b17ebb49654d21d4e96f415339c15c9f8a9ccde/proposals/csharp-9.0/function-pointers.md#function-pointer-conversions).\nAs a reminder, implicit function pointer conversions are disallowed if there is a mismatch between reference kind modifiers, and explicit casts are always allowed without any warnings.\n\n### Signature matching\n[signature-matching]: #signature-matching\n\nMembers declared in a single type cannot differ in signature solely by `ref`/`out`/`in`/`ref readonly`.\nFor other purposes of signature matching (e.g., hiding or overriding), `ref readonly` can be interchanged with `in` modifier, but that results in a warning at the declaration site [[§7.6](https://github.com/dotnet/csharpstandard/blob/47912d4fdae2bb8c3750e6485bdc6509560ec6bf/standard/basic-concepts.md#76-signatures-and-overloading)].\nThis doesn't apply when matching `partial` declaration with its implementation and when matching interceptor signature with intercepted signature.\nNote that there is no change in overriding for `ref`/`in` and `ref readonly`/`ref` modifier pairs, they cannot be interchanged, because the signatures aren't binary compatible.\nFor consistency, the same is true for other signature matching purposes (e.g., hiding).\n\n### Metadata encoding\n[metadata]: #metadata-encoding\n\nAs a reminder,\n\n- `ref` parameters are emitted as plain byref types (`T&` in IL),\n- `in` parameters are like `ref` plus they are annotated with `System.Runtime.CompilerServices.IsReadOnlyAttribute`.\n  In C# 7.3 and later, they are also emitted with `[in]` and if virtual, `modreq(System.Runtime.InteropServices.InAttribute)`.\n\n`ref readonly` parameters will be emitted as `[in] T&`, plus annotated with the following attribute:\n\n```cs\nnamespace System.Runtime.CompilerServices\n{\n    [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]\n    public sealed class RequiresLocationAttribute : Attribute\n    {\n    }\n}\n```\n\nFurthermore, if virtual, they will be emitted with `modreq(System.Runtime.InteropServices.InAttribute)` to ensure binary compatibility with `in` parameters.\nNote that unlike `in` parameters, no `[IsReadOnly]` will be emitted for `ref readonly` parameters to avoid increasing metadata size and also to make older compiler versions interpret `ref readonly` parameters as `ref` parameters (and hence `ref` → `ref readonly` won't be a source breaking change even between different compiler versions).\n\nThe `RequiresLocationAttribute` will be matched by namespace-qualified name and synthesized by the compiler if not already included in the compilation.\n\nSpecifying the attribute in source will be an error if it's applied to a parameter, similarly to `ParamArrayAttribute`.\n\n#### Function pointers\n[funcptrs]: #function-pointers\n\nIn function pointers, `in` parameters are emitted with `modreq(System.Runtime.InteropServices.InAttribute)` (see [function pointers proposal](https://github.com/dotnet/csharplang/blob/0376b4cc500b1370da86d26be634c9acf9d60b71/proposals/csharp-9.0/function-pointers.md#metadata-representation-of-in-out-and-ref-readonly-parameters-and-return-types)).\n`ref readonly` parameters will be emitted without that `modreq`, but instead with `modopt(System.Runtime.CompilerServices.RequiresLocationAttribute)`.\nOlder compiler versions will ignore the `modopt` and hence interpret `ref readonly` parameters as `ref` parameters (consistent with older compiler behavior for normal methods with `ref readonly` parameters as described above)\nand new compiler versions aware of the `modopt` will use it to recognize `ref readonly` parameters to emit warnings during [conversions][method-conversions] and [invocations][overload-resolution].\nFor consistency with older compiler versions, new compiler versions with `LangVersion <= 11` will report errors that `ref readonly` parameters are not supported unless the corresponding arguments are passed with the `ref` modifier.\n\nNote that it is a binary break to change modifiers in function pointer signatures if they are part of public APIs, hence it will be a binary break when changing `ref` or `in` to `ref readonly`.\nHowever, a source break will only occur for callers with `LangVersion <= 11` when changing `in` → `ref readonly` (if invoking the pointer with `in` callsite modifier), consistent with normal methods.\n\n## Breaking changes\n[breaking-changes]: #breaking-changes\n\nThe `ref`/`in` mismatch relaxation in overload resolution introduces a behavior breaking change demonstrated in the following example:\n\n```cs\nclass C\n{\n    string M(in int i) => \"C\";\n    static void Main()\n    {\n        int i = 5;\n        System.Console.Write(new C().M(ref i));\n    }\n}\nstatic class E\n{\n    public static string M(this C c, ref int i) => \"E\";\n}\n```\n\nIn C#&nbsp;11, the call binds to `E.M`, hence `\"E\"` is printed.\nIn C#&nbsp;12, `C.M` is allowed to bind (with a warning) and no extension scopes are searched since we have an applicable candidate, hence `\"C\"` is printed.\n\nThere is also a source breaking change due to the same reason.\nThe example below prints `\"1\"` in C#&nbsp;11, but fails to compile with an ambiguity error in C#&nbsp;12:\n\n```cs\nvar i = 5;\nSystem.Console.Write(C.M(null, ref i));\n\ninterface I1 { }\ninterface I2 { }\nstatic class C\n{\n    public static string M(I1 o, ref int x) => \"1\";\n    public static string M(I2 o, in int x) => \"2\";\n}\n```\n\nThe examples above demonstrate the breaks for method invocations, but since they are caused by overload resolution changes, they can be similarly triggered for method conversions.\n\n## Alternatives\n[alternatives]: #alternatives\n\n#### [Parameter declarations][declarations]\n\nAPI authors could annotate `in` parameters designed to accept only lvalues with a custom attribute and provide an analyzer to flag incorrect usages.\nThis would not allow API authors to change signatures of existing APIs that opted to use `ref` parameters to disallow rvalues.\nCallers of such APIs would still need to perform extra work to get a `ref` if they have access only to a `ref readonly` variable.\nChanging these APIs from `ref` to `[RequiresLocation] in` would be a source breaking change (and in case of virtual methods, also a binary breaking change).\n\nInstead of allowing the modifier `ref readonly`, the compiler could recognize when a special attribute (like `[RequiresLocation]`) is applied to a parameter.\nThis was discussed in [LDM 2022-04-25](https://github.com/dotnet/csharplang/blob/c8c1615fcad4ca016a97b7260ad497aad53ebc78/meetings/2022/LDM-2022-04-25.md#ref-readonly-method-parameters), deciding this is a language feature, not an analyzer, so it should look like one.\n\n#### [Value kind checks][value-kind-checks]\n\nPassing lvalues without any modifiers to `ref readonly` parameters could be permitted without any warnings, similarly to C++'s implicit byref parameters.\nThis was discussed in [LDM 2022-05-11](https://github.com/dotnet/csharplang/blob/c8c1615fcad4ca016a97b7260ad497aad53ebc78/meetings/2022/LDM-2022-05-11.md#ref-readonly-method-parameters), noting that the primary motivation for `ref readonly` parameters are APIs which capture or return references from these parameters, so marker of some kind is a good thing.\n\nPassing rvalue to a `ref readonly` could be an error, not a warning.\nThat was initially accepted in [LDM 2022-04-25](https://github.com/dotnet/csharplang/blob/c8c1615fcad4ca016a97b7260ad497aad53ebc78/meetings/2022/LDM-2022-04-25.md#ref-readonly-method-parameters), but later e-mail discussions relaxed this because we would lose the ability to change existing APIs without breaking users.\n\n`in` could be the \"natural\" callsite modifier for `ref readonly` parameters and using `ref` could result in warnings.\nThis would ensure a consistent code style and make it obvious at the callsite that the reference is readonly (unlike `ref`).\nIt was initially accepted in [LDM 2022-04-25](https://github.com/dotnet/csharplang/blob/c8c1615fcad4ca016a97b7260ad497aad53ebc78/meetings/2022/LDM-2022-04-25.md#ref-readonly-method-parameters).\nHowever, warnings could be a friction point for API authors to move from `ref` to `ref readonly`.\nAlso, `in` has been redefined as `ref readonly` + convenience features, hence this was rejected in [LDM 2022-05-11](https://github.com/dotnet/csharplang/blob/c8c1615fcad4ca016a97b7260ad497aad53ebc78/meetings/2022/LDM-2022-05-11.md#ref-readonly-method-parameters).\n\n### Pending LDM review\n[to-review]: #pending-ldm-review\n\nNone of the following options were implemented in C# 12. They remains potential proposals.\n\n#### [Parameter declarations][declarations]\n\nInverse ordering of modifiers (`readonly ref` instead of `ref readonly`) could be allowed.\nThis would be inconsistent with how `readonly ref` returns and fields behave (inverse ordering is disallowed or means something different, respectively) and could clash with readonly parameters if implemented in the future.\n\nDefault parameter values could be an error for `ref readonly` parameters.\n\n#### [Value kind checks][value-kind-checks]\n\nErrors could be emitted instead of warnings when passing rvalues to `ref readonly` parameters or mismatching callsite annotations and parameter modifiers.\nSimilarly, special `modreq` could be used instead of an attribute to ensure `ref readonly` parameters are distinct from `in` parameters on the binary level.\nThis would provide stronger guarantees, so it would be good for new APIs, but prevent adoption in existing runtime APIs which cannot introduce breaking changes.\n\nValue kind checks could be relaxed to allow passing readonly references via `ref` into `in`/`ref readonly` parameters.\nThat would be similar to how ref assignments and ref returns work today&mdash;they also allow passing references as readonly via the `ref` modifier on the source expression.\nHowever, the `ref` there is usually close to the place where the target is declared as `ref readonly`, so it is clear we are passing a reference as readonly, unlike invocations whose argument and parameter modifiers are usually far apart.\nFurthermore, they allow *only* the `ref` modifier unlike arguments which allow also `in`, hence `in` and `ref` would become interchangeable for arguments, or `in` would become practically obsolete if users wanted to make their code consistent (they would probably use `ref` everywhere since it's the only modifier allowed for ref assignments and ref returns).\n\n#### [Overload resolution][overload-resolution]\n\nOverload resolution, overriding, and conversion could disallow interchangeability of `ref readonly` and `in` modifiers.\n\nThe overload resolution change for existing `in` parameters could be taken unconditionally (not considering LangVersion), but that would be a breaking change.\n\nInvoking an extension method with `ref readonly` receiver could result in warning \"Argument 1 should be passed with `ref` or `in` keyword\" as would happen for non-extension invocations with no callsite modifiers (user could fix such warning by turning the extension method invocation into static method invocation).\nThe same warning could be reported when using custom collection initializer or interpolated string handler with `ref readonly` parameter, although user could not work around it.\n\n`ref readonly` overloads could be preferred over by-value overloads when there is no callsite modifier or there could be an ambiguity error.\n\n#### [Method conversions][method-conversions]\n\nWe could allow `ref` parameter of the target method to match `in` and `ref readonly` parameter of the delegate.\nThis would enable API authors to change for example `ref` to `in` in delegate signatures without breaking their users\n(consistently with what is allowed for normal method signatures).\nHowever, it would also result in the following violation of `readonly` guarantees with just a warning:\n\n```cs\nclass Program\n{\n    static readonly int f = 123;\n    static void Main()\n    {\n        var d = (in int x) => { };\n        d = (ref int x) => { x = 42; }; // warning: mismatch between `ref` and `in`\n        d(f); // changes value of `f` even though it is `readonly`!\n        System.Console.WriteLine(f); // prints 42\n    }\n}\n```\n\nFunction pointer conversions could warn on `ref readonly`/`ref`/`in` mismatch, but if we wanted to gate that on LangVersion, a significant implementation investment would be required as today type conversions do not need access to compilation.\nFurthermore, even though mismatch is currently an error, it is easy for users to add a cast to allow the mismatch if they want.\n\n#### [Metadata encoding][metadata]\n\nSpecifying the `RequiresLocationAttribute` in source could be allowed, similarly to `In` and `Out` attributes.\nAlternatively, it could be an error when applied in other contexts than just parameters, similarly to `IsReadOnly` attribute; to preserve further design space.\n\nFunction pointer `ref readonly` parameters could be emitted with different `modopt`/`modreq` combinations (note that \"source break\" in this table means for callers with `LangVersion <= 11`):\n\n| Modifiers                             | Can be recognized across compilations | Old compilers see them as | `ref` → `ref readonly` | `in` → `ref readonly` |\n|---------------------------------------|---------------------------------------|---------------------------|------------------------|-----------------------|\n| `modreq(In) modopt(RequiresLocation)` | yes                                   | `in`                      | binary, source break   | binary break          |\n| `modreq(In)`                          | no                                    | `in`                      | binary, source break   | ok                    |\n| `modreq(RequiresLocation)`            | yes                                   | unsupported               | binary, source break   | binary, source break  |\n| `modopt(RequiresLocation)`            | yes                                   | `ref`                     | binary break           | binary, source break  |\n\nWe could emit both `[RequiresLocation]` and `[IsReadOnly]` attributes for `ref readonly` parameters.\nThen `in` → `ref readonly` would not be a breaking change even for older compiler versions, but `ref` → `ref readonly` would become a source breaking change for older compiler versions (as they would interpret `ref readonly` as `in`, disallowing `ref` modifiers) and new compiler versions with `LangVersion <= 11` (for consistency).\n\nWe could make the behavior for `LangVersion <= 11` different from the behavior for older compiler versions.\nFor example, it could be an error whenever a `ref readonly` parameter is called (even when using the `ref` modifier at the callsite),\nor it could be always allowed without any errors.\n\n#### [Breaking changes][breaking-changes]\n\nThis proposal suggests accepting a behavior breaking change because it should be rare to hit, is gated by LangVersion, and users can work around it by calling the extension method explicitly.\nInstead, we could mitigate it by\n\n- disallowing the `ref`/`in` mismatch (that would only prevent migration to `in` for old APIs that used `ref` because `in` wasn't available yet),\n- modifying the overload resolution rules to continue looking for a better match (determined by betterness rules specified below) when there's a ref kind mismatch introduced in this proposal,\n  - or alternatively continue only for `ref` vs. `in` mismatch, not the others (`ref readonly` vs. `ref`/`in`/by-value).\n\n##### Betterness rules\n\nThe following example currently results in three ambiguity errors for the three invocations of `M`.\nWe could add new betterness rules to resolve the ambiguities.\nThis would also resolve the source breaking change described earlier.\nOne way would be to make the example print `221` (where `ref readonly` parameter is matched with `in` argument since it would be a warning to call it with no modifier whereas for `in` parameter that's allowed).\n\n```cs\ninterface I1 { }\ninterface I2 { }\nclass C\n{\n    static string M(I1 o, in int i) => \"1\";\n    static string M(I2 o, ref readonly int i) => \"2\";\n    static void Main()\n    {\n        int i = 5;\n        System.Console.Write(M(null, ref i));\n        System.Console.Write(M(null, in i));\n        System.Console.Write(M(null, i));\n    }\n}\n```\n\nNew betterness rules could mark as worse the parameter whose argument could have been passed with a different argument modifier to make it better.\nIn other words, user should be always able to turn a worse parameter into a better parameter by changing its corresponding argument modifier.\nFor example, when an argument is passed by `in`, a `ref readonly` parameter is preferred over an `in` parameter because user could pass the argument by-value to choose the `in` parameter.\nThis rule is just an extension of by-value/`in` preference rule that is in effect today (it's the last overload resolution rule and the whole overload is better if any of its parameter is better and none is worse than the corresponding parameter of another overload).\n\n| argument    | better parameter | worse parameter     |\n|-------------|------------------|---------------------|\n| `ref`/`in`  | `ref readonly`   | `in`                |\n| `ref`       | `ref`            | `ref readonly`/`in` |\n| by-value    | by-value/`in`    | `ref readonly`      |\n| `in`        | `in`             | `ref`               |\n\nWe should handle method conversions similarly.\nThe following example currently results in two ambiguity errors for the two delegate assignments.\nNew betterness rules could prefer a method parameter whose refness modifier matches the corresponding target delegate parameter refness modifier over one that has a mismatch.\nHence, the following example would print `12`.\n\n```cs\nclass C\n{\n    void M(I1 o, ref readonly int x) => System.Console.Write(\"1\");\n    void M(I2 o, ref int x) => System.Console.Write(\"2\");\n    void Run()\n    {\n        D1 m1 = this.M;\n        D2 m2 = this.M; // currently ambiguous\n\n        var i = 5;\n        m1(null, in i);\n        m2(null, ref i);\n    }\n    static void Main() => new C().Run();\n}\ninterface I1 { }\ninterface I2 { }\nclass X : I1, I2 { }\ndelegate void D1(X s, ref readonly int x);\ndelegate void D2(X s, ref int x);\n```\n\n## Design meetings\n\n- [LDM 2022-04-25](https://github.com/dotnet/csharplang/blob/c8c1615fcad4ca016a97b7260ad497aad53ebc78/meetings/2022/LDM-2022-04-25.md#ref-readonly-method-parameters): feature accepted\n- [LDM 2022-05-09](https://github.com/dotnet/csharplang/blob/c8c1615fcad4ca016a97b7260ad497aad53ebc78/meetings/2022/LDM-2022-05-09.md#ref-readonly-parameters): discussion split into three parts\n- [LDM 2022-05-11](https://github.com/dotnet/csharplang/blob/c8c1615fcad4ca016a97b7260ad497aad53ebc78/meetings/2022/LDM-2022-05-11.md#ref-readonly-method-parameters): allowed `ref` and no callsite annotation for `ref readonly` parameters\n"
  },
  {
    "path": "proposals/csharp-12.0/using-alias-types.md",
    "content": "# Allow using alias directive to reference any kind of Type\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/8645>\n\n## Summary\nRelax the using_alias_directive ([§13.5.2](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#1352-using-alias-directives)) to allow it to point at any sort of type, not just named types.  This would support types not allowed today, like: tuple types, pointer types, array types, etc.  For example, this would now be allowed:\n\n```c#\nusing Point = (int x, int y);\n```\n\n## Motivation\nFor ages, C# has had the ability to introduce aliases for namespaces and named types (classes, delegated, interfaces, records and structs).  This worked acceptably well as it provided a means to introduce non-conflicting names in cases where a normal named pulled in from `using_directive`s might be ambiguous, and it allowed a way to provide a simpler name when dealing with complex generic types.  However, the rise of additional complex type symbols in the language has caused more use to arise where aliases would be valuable but are currently not allowed.  For example, both tuples and function-pointers often can have large and complex regular textual forms that can be painful to continually write out, and a burden to try to read.  Aliases would help in these cases by giving a short, developer-provided, name that can then be used in place of those full structural forms.\n\n## Detailed design\nWe will change the grammar of `using_alias_directive` thusly:\n\n```\nusing_alias_directive\n-    : 'using' identifier '=' namespace_or_type_name ';'\n+    : 'using' identifier '=' (namespace_name | type) ';'\n    ;\n```\n\nTop-level reference type nullability annotations are disallowed.\n\nInterestingly, most of the spec language in [§13.5.2](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#1352-using-alias-directives) does not need to change.  Most language in it already refers to 'namespace or type', for example:\n\n> A using_alias_directive introduces an identifier that serves as an alias for a namespace or type within the immediately enclosing compilation unit or namespace body.\n\nThis remains true, just that the grammar now allows the 'type' to be any arbitrary type, not the limited set allowed for by `namespace_or_type_name` previously.\n\nThe sections that do need updating are:\n\n```diff\n- The order in which using_alias_directives are written has no significance, and resolution of the namespace_or_type_name referenced by a using_alias_directive is not affected by the using_alias_directive itself or by other using_directives in the immediately containing compilation unit or namespace body. In other words, the namespace_or_type_name of a using_alias_directive is resolved as if the immediately containing compilation unit or namespace body had no using_directives. A using_alias_directive may however be affected by extern_alias_directives in the immediately containing compilation unit or namespace body. In the example\n+ The order in which using_alias_directives are written has no significance, and resolution of the `(namespace_name | type)` referenced by a using_alias_directive is not affected by the using_alias_directive itself or by other using_directives in the immediately containing compilation unit or namespace body. In other words, the `(namespace_name | type)` of a using_alias_directive is resolved as if the immediately containing compilation unit or namespace body had no using_directives. A using_alias_directive may however be affected by extern_alias_directives in the immediately containing compilation unit or namespace body. In the example\n```\n\n```diff\n- The namespace_name referenced by a using_namespace_directive is resolved in the same way as the namespace_or_type_name referenced by a using_alias_directive. Thus, using_namespace_directives in the same compilation unit or namespace body do not affect each other and can be written in any order.\n+ The namespace_name referenced by a using_namespace_directive is resolved in the same way as the namespace_or_type_name referenced by a using_alias_directive. Thus, using_namespace_directives in the same compilation unit or namespace body do not affect each other and can be written in any order.\n```\n\n```diff\n+ It is illegal for a using alias type to be a nullable reference type.\n\n    1. `using X = string?;` is not legal.\n    2. `using X = List<string?>;` is legal.  The alias is to `List<...>` which is itself not a nullable reference type itself, even though it contains one as a type argument.\n    3. `using X = int?;` is legal.  This is a nullable *value* type, not a nullable *reference* type.\n```\n\n## Supporting aliases to types containing pointers.\n\nA new [unsafe context](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/unsafe-code.md#222-unsafe-contexts) is added through an optional 'unsafe' keyword in the using_alias_directive production:\n\n```diff\nusing_alias_directive\n+    : 'using' 'unsafe'? identifier '=' (namespace_name | type) ';'\n    ;\n    \nusing_static_directive\n+    : 'using' 'static' 'unsafe'? type_name ';'\n    ;\n\n+ 'unsafe' can only be used with an using_alias_directive or using_static_directive, not a using_directive.\n+ The 'unsafe' keyword present in a 'using_alias_directive' causes the entire textual extent of the 'type' portion (not the 'namespace_name' portion) to become an unsafe context. \n+ The 'unsafe' keyword present in a 'using_static_directive' causes the entire textual extent of the 'type_name' portion to become an unsafe context. \n```\n\n\n"
  },
  {
    "path": "proposals/csharp-13.0/collection-expressions-better-conversion.md",
    "content": "# Better conversion from collection expression element\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/8374>\n\n## Summary\n\nUpdates to the better conversion rules to be more consistent with `params`, and better handle current ambiguity scenarios. For example, `ReadOnlySpan<string>` vs `ReadOnlySpan<object>` can currently\ncause ambiguities during overload resolution for `[\"\"]`.\n\n## Detailed Design\n\nThe following are the better conversion from expression rules. These replace the rules in https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#overload-resolution.\n\nThese rules are:\n\n> Given an implicit conversion `C₁` that converts from an expression `E` to a type `T₁`, and an implicit conversion `C₂` that converts from an expression `E` to a type `T₂`, `C₁` is a ***better conversion*** than `C₂` if one of the following holds:\n> * **`E` is a *collection expression*, and `C₁` is a ***better collection conversion from expression*** than `C₂`**\n> * **`E` is not a *collection expression* and one of the following holds:**\n>   * `E` exactly matches `T₁` and `E` does not exactly match `T₂`\n>   * `E` exactly matches both or neither of `T₁` and `T₂`, and `T₁` is a [*better conversion target*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/expressions.md#11646-better-conversion-target) than `T₂`\n> * `E` is a method group, ...\n\nWe add a new definition for ***better collection conversion from expression***, as follows:\n\nGiven:\n- `E` is a collection expression with element expressions `[EL₁, EL₂, ..., ELₙ]`\n- `T₁` and `T₂` are collection types\n- `E₁` is the element type of `T₁`\n- `E₂` is the element type of `T₂`\n- `CE₁ᵢ` are the series of conversions from `ELᵢ` to `E₁`\n- `CE₂ᵢ` are the series of conversions from `ELᵢ` to `E₂`\n\nIf there is an identity conversion from `E₁` to `E₂`, then the element conversions are as good as each other. Otherwise, the element conversions to `E₁` are ***better than the element conversions*** to `E₂` if:\n- For every `ELᵢ`, `CE₁ᵢ` is at least as good as `CE₂ᵢ`, and\n- There is at least one i where `CE₁ᵢ` is better than `CE₂ᵢ`\nOtherwise, neither set of element conversions is better than the other, and they are also not as good as each other.  \nConversion comparisons are made using better conversion from expression if `ELᵢ` is not a spread element. If `ELᵢ` is a spread element, we use better conversion from the element type of the spread collection to `E₁` or `E₂`, respectively.\n\n`C₁` is a ***better collection conversion from expression*** than `C₂` if:\n- Both `T₁` and `T₂` are not *span types*, and `T₁` is implicitly convertible to `T₂`, and `T₂` is not implicitly convertible to `T₁`, or\n- `E₁` does not have an identity conversion to `E₂`, and the element conversions to `E₁` are ***better than the element conversions*** to `E₂`, or\n- `E₁` has an identity conversion to `E₂`, and one of the following holds:\n   - `T₁` is `System.ReadOnlySpan<E₁>`, and `T₂` is `System.Span<E₂>`, or\n   - `T₁` is `System.ReadOnlySpan<E₁>` or `System.Span<E₁>`, and `T₂` is an *array_or_array_interface* with *element type* `E₂`\n\nOtherwise, neither collection type is better, and the result is ambiguous.\n\n> [!NOTE]\n> These rules mean that methods that expose overloads that take different element types and without a conversion between the collection types are ambiguous for empty collection expressions. As an example:\n> ```cs\n> public void M(ReadOnlySpan<int> ros) { ... }\n> public void M(Span<int?> span) { ... }\n>\n> M([]); // Ambiguous\n> ```\n\n### Scenarios:\n\nIn plain English, the collection types themselves must be either the same, or unambiguously better (ie, `List<T>` and `List<T>` are the same, `List<T>` is unambiguously better than `IEnumerable<T>`, and `List<T>` and `HashSet<T>` cannot be compared), and\nthe element conversions for the better collection type must also be the same or better (ie, we can't decide between `ReadOnlySpan<object>` and `Span<string>` for `[\"\"]`, the user needs to make that decision). More examples of this are:\n\n| `T₁` | `T₂` | `E` | `C₁` Conversions | `C₂` Conversions | `CE₁ᵢ` vs `CE₂ᵢ` | Outcome |\n|--------|--------|------------|----------------|----------------|---------------------|---------|\n| `List<int>` | `List<byte>` | `[1, 2, 3]` | `[Identity, Identity, Identity]` | `[Implicit Constant, Implicit Constant, Implicit Constant]` | `CE₁ᵢ` is better | `List<int>` is picked |\n| `List<int>` | `List<byte>` | `[(int)1, (byte)2]` | `[Identity, Implicit Numeric]` | Not applicable | `T₂` is not applicable | `List<int>` is picked |\n| `List<int>` | `List<byte>` | `[1, (byte)2]` | `[Identity, Implicit Numeric]` | `[Implicit Constant, Identity]` | Neither is better | Ambiguous |\n| `List<int>` | `List<byte>` | `[(byte)1, (byte)2]` | `[Implicit Numeric, Implicit Numeric]` | `[Identity, Identity]` | `CE₂ᵢ` is better | `List<byte>` is picked |\n| `List<int?>` | `List<long>` | `[1, 2, 3]` | `[Implicit Nullable, Implicit Nullable, Implicit Nullable]` | `[Implicit Numeric, Implicit Numeric, Implicit Numeric]` | Neither is better | Ambiguous |\n| `List<int?>` | `List<ulong>` | `[1, 2, 3]` | `[Implicit Nullable, Implicit Nullable, Implicit Nullable]` | `[Implicit Numeric, Implicit Numeric, Implicit Numeric]` | `CE₁ᵢ` is better | `List<int?>` is picked |\n| `List<short>` | `List<long>` | `[1, 2, 3]` | `[Implicit Numeric, Implicit Numeric, Implicit Numeric]` | `[Implicit Numeric, Implicit Numeric, Implicit Numeric]` | `CE₁ᵢ` is better | `List<short>` is picked |\n| `IEnumerable<int>` | `List<byte>` | `[1, 2, 3]` | `[Identity, Identity, Identity]` | `[Implicit Constant, Implicit Constant, Implicit Constant]` | `CE₁ᵢ` is better | `IEnumerable<int>` is picked |\n| `IEnumerable<int>` | `List<byte>` | `[(byte)1, (byte)2]` | `[Implicit Numeric, Implicit Numeric]` | `[Identity, Identity]` | `CE₂ᵢ` is better | `List<byte>` is picked |\n| `int[]` | `List<byte>` | `[1, 2, 3]` | `[Identity, Identity, Identity]` | `[Implicit Constant, Implicit Constant, Implicit Constant]` | `CE₁ᵢ` is better | `int[]` is picked |\n| `ReadOnlySpan<string>` | `ReadOnlySpan<object>` | `[\"\", \"\", \"\"]` | `[Identity, Identity, Identity]` | `[Implicit Reference, Implicit Reference, Implicit Reference]` | `CE₁ᵢ` is better | `ReadOnlySpan<string>` is picked |\n| `ReadOnlySpan<string>` | `ReadOnlySpan<object>` | `[\"\", new object()]` | Not applicable | `[Implicit Reference, Identity]` | `T₁` is not applicable | `ReadOnlySpan<object>` is picked |\n| `ReadOnlySpan<object>` | `Span<string>` | `[\"\", \"\"]` | `[Implicit Reference]` | `[Identity]` | `CE₂ᵢ` is better | `Span<string>` is picked |\n| `ReadOnlySpan<object>` | `Span<string>` | `[new object()]` | `[Identity]` | Not applicable | `T₁` is not applicable | `ReadOnlySpan<object>` is picked |\n| `ReadOnlySpan<InterpolatedStringHandler>` | `ReadOnlySpan<string>` | `[$\"{1}\"]` | `[Interpolated String Handler]` | `[Identity]` | `CE₁ᵢ` is better | `ReadOnlySpan<InterpolatedStringHandler>` is picked |\n| `ReadOnlySpan<InterpolatedStringHandler>` | `ReadOnlySpan<string>` | `[$\"{\"blah\"}\"]` | `[Interpolated String Handler]` | `[Identity]` - But constant | `CE₂ᵢ` is better | `ReadOnlySpan<string>` is picked |\n| `ReadOnlySpan<string>` | `ReadOnlySpan<FormattableString>` | `[$\"{1}\"]` | `[Identity]` | `[Interpolated String]` | `CE₂ᵢ` is better | `ReadOnlySpan<string>` is picked |\n| `ReadOnlySpan<string>` | `ReadOnlySpan<FormattableString>` | `[$\"{1}\", (FormattableString)null]` | Not applicable | `[Interpolated String, Identity]` | `T₁` isn't applicable | `ReadOnlySpan<FormattableString>` is picked |\n| `HashSet<short>` | `Span<long>` | `[1, 2]` | `[Implicit Constant, Implicit Constant]` | `[Implicit Numeric, Implicit Numeric]` | `CE₁ᵢ` is better | `HashSet<short>` is picked |\n| `HashSet<long>` | `Span<short>` | `[1, 2]` | `[Implicit Numeric, Implicit Numeric]` | `[Implicit Constant, Implicit Constant]` | `CE₂ᵢ` is better | `Span<short>` is picked |\n\n## Open questions\n\n### How far should we prioritize `ReadOnlySpan`/`Span` over other types?\n\nAs specified today, the following overloads would be ambiguous:\n\n```cs\nC.M1([\"Hello world\"]); // Ambiguous, no tiebreak between ROS and List\nC.M2([\"Hello world\"]); // Ambiguous, no tiebreak between Span and List\n\nC.M3([\"Hello world\"]); // Ambiguous, no tiebreak between ROS and MyList.\n\nC.M4([\"Hello\", \"Hello\"]); // Ambiguous, no tiebreak between ROS and HashSet. Created collections have different contents\n\nclass C\n{\n    public static void M1(ReadOnlySpan<string> ros) {}\n    public static void M1(List<string> list) {}\n\n    public static void M2(Span<string> ros) {}\n    public static void M2(List<string> list) {}\n\n    public static void M3(ReadOnlySpan<string> ros) {}\n    public static void M3(MyList<string> list) {}\n\n    public static void M4(ReadOnlySpan<string> ros) {}\n    public static void M4(HashSet<string> hashset) {}\n}\n\nclass MyList<T> : List<T> {}\n```\n\nHow far do we want to go here? The `List<T>` variant seems reasonable, and subtypes of `List<T>` exist aplenty. But the `HashSet` version has very different semantics, how sure are we that it's actually \"worse\"\nthan `ReadOnlySpan` in this API?\n"
  },
  {
    "path": "proposals/csharp-13.0/esc-escape-sequence.md",
    "content": "\n# String/Character escape sequence `\\e`\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/8657>\n\n## Summary\nAn addition of the string/character escape sequence `\\e` as a shortcut/short-hand replacement\nfor the character code point `0x1b`, commonly known as the `ESCAPE` (or `ESC`) character.  \nThis character is currently accessible using one of the following escape sequences:\n- `\\u001b`\n- `\\U0000001b`\n- `\\x1b` (not recommended, see the picture attached at the bottom.)\n\nWith the implementation of this proposal, the following assertions should be true:\n```csharp\nchar escape_char = '\\e';\n\nAssert.IsTrue(escape_char == (char)0x1b, \"...\");\nAssert.IsTrue(escape_char == '\\u001b', \"...\");\nAssert.IsTrue(escape_char == '\\U0000001b', \"...\");\nAssert.IsTrue(escape_char == '\\x1b', \"...\");\n```\n\n## Detailed design\nThe language syntax specification is changed as follows in section \n[6.4.5.5](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/lexical-structure.md#6455-character-literals):\n\n```diff\nfragment Simple_Escape_Sequence\n-    : '\\\\\\'' | '\\\\\"' | '\\\\\\\\' | '\\\\0' | '\\\\a' | '\\\\b' | '\\\\f' | '\\\\n' | '\\\\r' | '\\\\t' | '\\\\v'\n+    : '\\\\\\'' | '\\\\\"' | '\\\\\\\\' | '\\\\0' | '\\\\a' | '\\\\b' | '\\\\f' | '\\\\n' | '\\\\r' | '\\\\t' | '\\\\v' | '\\\\e'\n    ;\n```\nAs well as the addition of the **last line** to the following table in the specifications:\n\n> A simple escape sequence represents a Unicode character, as described in the table below.\n> \n> | **Escape sequence** | **Character name** | **Unicode code point** |\n> |---------------------|--------------------|--------------------|\n> | `\\'`                | Single quote       | U+0027             |\n> | ...                 | ...                | ...                |\n> | `\\e`                | Escape character   | U+001B             |\n> \n> The type of a *Character_Literal* is `char`.\n"
  },
  {
    "path": "proposals/csharp-13.0/lock-object.md",
    "content": "# `Lock` object\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/7104>\n\n## Summary\n[summary]: #summary\n\nSpecial-case how `System.Threading.Lock` interacts with the `lock` keyword (calling its `EnterScope` method under the hood).\nAdd static analysis warnings to prevent accidental misuse of the type where possible.\n\n## Motivation\n[motivation]: #motivation\n\n.NET 9 is introducing a new [`System.Threading.Lock` type](https://github.com/dotnet/runtime/issues/34812)\nas a better alternative to existing monitor-based locking.\nThe presence of the `lock` keyword in C# might lead developers to think they can use it with this new type.\nDoing so wouldn't lock according to the semantics of this type but would instead treat it as any other object and would use monitor-based locking.\n\n```cs\nnamespace System.Threading\n{\n    public sealed class Lock\n    {\n        public void Enter();\n        public void Exit();\n        public Scope EnterScope();\n    \n        public ref struct Scope\n        {\n            public void Dispose();\n        }\n    }\n}\n```\n\n## Detailed design\n[design]: #detailed-design\n\nSemantics of the lock statement ([§13.13](https://github.com/dotnet/csharpstandard/blob/9af5bdaa7af535f34fbb7923e5406e01db8489f7/standard/statements.md#1313-the-lock-statement))\nare changed to special-case the `System.Threading.Lock` type:\n\n> A `lock` statement of the form `lock (x) { ... }`\n>\n> 1. **where `x` is an expression of type `System.Threading.Lock`, is precisely equivalent to:**\n>    ```cs\n>    using (x.EnterScope())\n>    {\n>        ...\n>    }\n>    ```\n>    **and `System.Threading.Lock` must have the following shape:**\n>    ```cs\n>    namespace System.Threading\n>    {\n>        public sealed class Lock\n>        {\n>            public Scope EnterScope();\n>    \n>            public ref struct Scope\n>            {\n>                public void Dispose();\n>            }\n>        }\n>    }\n>    ```\n> 2. where `x` is an expression of a *reference_type*, is precisely equivalent to: [...]\n\nNote that the shape might not be fully checked (e.g., there will be no errors nor warnings if the `Lock` type is not `sealed`),\nbut the feature might not work as expected (e.g., there will be no warnings when converting `Lock` to a derived type,\nsince the feature assumes there are no derived types).\n\nAdditionally, new warnings are added to implicit reference conversions ([§10.2.8](https://github.com/dotnet/csharpstandard/blob/9af5bdaa7af535f34fbb7923e5406e01db8489f7/standard/conversions.md#1028-implicit-reference-conversions))\nwhen upcasting the `System.Threading.Lock` type:\n\n> The implicit reference conversions are:\n>\n> - From any *reference_type* to `object` and `dynamic`.\n>   - **A warning is reported when the *reference_type* is known to be `System.Threading.Lock`.**\n> - From any *class_type* `S` to any *class_type* `T`, provided `S` is derived from `T`.\n>   - **A warning is reported when `S` is known to be `System.Threading.Lock`.**\n> - From any *class_type* `S` to any *interface_type* `T`, provided `S` implements `T`.\n>   - **A warning is reported when `S` is known to be `System.Threading.Lock`.**\n> - [...]\n\n```cs\nobject l = new System.Threading.Lock(); // warning\nlock (l) { } // monitor-based locking is used here\n```\n\nNote that this warning occurs even for equivalent explicit conversions.\n\nThe compiler avoids reporting the warning in some cases when the instance cannot be locked after converting to `object`:\n- when the conversion is implicit and part of an object equality operator invocation.\n\n```cs\nvar l = new System.Threading.Lock();\nif (l != null) // no warning even though `l` is implicitly converted to `object` for `operator!=(object, object)`\n    // ...\n```\n\nTo escape out of the warning and force use of monitor-based locking, one can use\n- the usual warning suppression means (`#pragma warning disable`),\n- `Monitor` APIs directly,\n- indirect casting like `object AsObject<T>(T l) => (object)l;`.\n\n## Alternatives\n[alternatives]: #alternatives\n\n- Support a general pattern that other types can also use to interact with the `lock` keyword.\n  This is a future work that might be implemented when `ref struct`s can participate in generics.\n  Discussed in [LDM 2023-12-04](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-12-04.md#lock-statement-pattern).\n\n- To avoid ambiguity between the existing monitor-based locking and the new `Lock` (or pattern in the future), we could:\n  - Introduce a new syntax instead of reusing the existing `lock` statement.\n  - Require the new lock types to be `struct`s (since the existing `lock` disallows value types).\n    There could be problems with default constructors and copying if the structs have lazy initialization.\n\n- The codegen could be hardened against thread aborts (which are themselves obsoleted).\n\n- We could warn also when `Lock` is passed as a type parameter, because locking on a type parameter always uses monitor-based locking:\n\n  ```cs\n  M(new Lock()); // could warn here\n\n  void M<T>(T x) // (specifying `where T : Lock` makes no difference)\n  {\n      lock (x) { } // because this uses Monitor\n  }\n  ```\n\n  However, that would cause warnings when storing `Lock`s in a list which is undesirable:\n\n  ```cs\n  List<Lock> list = new();\n  list.Add(new Lock()); // would warn here\n  ```\n\n- We could include static analysis to prevent usage of `System.Threading.Lock` in `using`s with `await`s.\n  I.e., we could emit either an error or a warning for code like `using (lockVar.EnterScope()) { await ... }`.\n  Currently, this is not needed since `Lock.Scope` is a `ref struct`, so that code is illegal anyway.\n  However, if we ever allowed `ref struct`s in `async` methods or changed `Lock.Scope` to not be a `ref struct`, this analysis would become beneficial.\n  (We would also likely need to consider for this all lock types matching the general pattern if implemented in the future.\n  Although there might need to be an opt-out mechanism as some lock types might be allowed to be used with `await`.)\n  Alternatively, this could be implemented as an analyzer shipped as part of the runtime.\n\n- We could relax the restriction that value types cannot be `lock`ed\n  - for the new `Lock` type (only needed if the API proposal changed it from `class` to `struct`),\n  - for the general pattern where any type can participate when implemented in the future.\n\n- We could allow the new `lock` in `async` methods where `await` is not used inside the `lock`.\n  - Currently, since `lock` is lowered to `using` with a `ref struct` as the resource, this results in a compile-time error.\n    The workaround is to extract the `lock` into a separate non-`async` method.\n  - Instead of using the `ref struct Scope`, we could emit `Lock.Enter` and `Lock.Exit` methods in `try`/`finally`.\n    However, the `Exit` method must throw when it's called from a different thread than `Enter`,\n    hence it contains a thread lookup which is avoided when using the `Scope`.\n  - Best would be to allow compiling `using` on a `ref struct` in `async` methods if there is no `await` inside the `using` body.\n\n## Design meetings\n\n- [LDM 2023-05-01](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-05-01.md#lock-statement-improvements): initial decision to support a `lock` pattern\n- [LDM 2023-10-16](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-10-16.md#lock-statement-pattern): triaged into the working set for .NET 9\n- [LDM 2023-12-04](https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-12-04.md#lock-statement-pattern): rejected the general pattern, accepted only special-casing the `Lock` type + adding static analysis warnings\n"
  },
  {
    "path": "proposals/csharp-13.0/method-group-natural-type-improvements.md",
    "content": "# Method group natural type improvements\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/7429>\n\n## Summary\n[summary]: #summary\n\nThis proposal refines the determination of the natural type of a method group in a few ways:\n1. Consider candidate methods scope-by-scope (instance methods first, then each scope subsequent scope of extension methods)\n2. Prune candidates that have no chance of succeeding, so they don't interfere with determining a unique signature:\n    - Prune generic instance methods when no type arguments are provided (`var x = M;`)\n    - Prune generic extension methods based on being able to reduce the extension and on constraints\n\n## Context on method group natural type\n\nIn C# 10, method groups gained a weak natural type.  \nThat type is a \"weak type\" in that it only comes into play when the method group is not target-typed (ie. it plays no role in `System.Action a = MethodGroup;`).  \nThat weak natural type allows scenarios like `var x = MethodGroup;`.\n\nFor reference:\nhttps://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/lambda-improvements.md#natural-function-type\n\n> A method group has a natural type if all candidate methods in the method group have a common signature. (If the method group may include extension methods, the candidates include the containing type and all extension method scopes.)\n\nIn practice, this means that we:\n1. Construct the set of all candidate methods:\n  - methods on the relevant type are in the set if they are static and the receiver is a type, or if they are non-static and the receiver is a value\n  - extension methods (across all scopes) that can be reduced are in the set\n3. If the signatures of all the candidates do not match, then the method group doesn't have a natural type\n4. If the arity of the resulting signature doesn't match the number of provided type arguments, then the method group doesn't have a natural type\n5. Otherwise, the resulting signature is used as the natural type\n\n## Proposal\n\nThe principle is to go scope-by-scope and prune candidates that we know cannot succeed as early as possible (same principle used in overload resolution).\n\n1. For each scope, we construct the set of all candidate methods:\n  - for the initial scope, methods on the relevant type with arity matching the provided type arguments and satisfying constraints with the provided type arguments are in the set if they are static and the receiver is a type, or if they are non-static and the receiver is a value\n  - for subsequent scopes, extension methods in that scope that can be substituted with the provided type arguments and reduced using the value of the receiver while satisfying contstraints are in the set\n  1. If we have no candidates in the given scope, proceed to the next scope.\n  2. If the signatures of all the candidates do not match, then the method group doesn't have a natural type\n  3. Otherwise, resulting signature is used as the natural type\n2. If the scopes are exhausted, then the method group doesn't have a natural type\n\n----\n\nRelates to scope-by-scope proposal: https://github.com/dotnet/csharplang/issues/7364\nRelates to proposal to better handle generic extension methods: https://github.com/dotnet/roslyn/issues/69222\n\n"
  },
  {
    "path": "proposals/csharp-13.0/overload-resolution-priority.md",
    "content": "# Overload Resolution Priority\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/7706>\n\n## Summary\n[summary]: #summary\n\nWe introduce a new attribute, `System.Runtime.CompilerServices.OverloadResolutionPriority`, that can be used by API authors to adjust the relative priority of\noverloads within a single type as a means of steering API consumers to use specific APIs, even if those APIs would normally be considered ambiguous or otherwise\nnot be chosen by C#'s overload resolution rules.\n\n## Motivation\n[motivation]: #motivation\n\nAPI authors often run into an issue of what to do with a member after it has been obsoleted. For backwards compatibility purposes, many will keep the existing member around\nwith `ObsoleteAttribute` set to error in perpetuity, in order to avoid breaking consumers who upgrade binaries at runtime. This particularly hits plugin systems, where the\nauthor of a plugin does not control the environment in which the plugin runs. The creator of the environment may want to keep an older method present, but block access to it\nfor any newly developed code. However, `ObsoleteAttribute` by itself is not enough. The type or member is still visible in overload resolution, and may cause unwanted overload\nresolution failures when there is a perfectly good alternative, but that alternative is either ambiguous with the obsoleted member, or the presence of the obsoleted member causes\noverload resolution to end early without ever considering the good member. For this purpose, we want to have a way for API authors to guide overload resolution on resolving the\nambiguity, so that they can evolve their API surface areas and steer users towards performant APIs without having to compromise the user experience.\n\nThe Base Class Libraries (BCL) team has several examples of where this can prove useful. Some (hypothetical) examples are:\n* Creating an overload of `Debug.Assert` that uses `CallerArgumentExpression` to get the expression being asserted, so that it can be included in the message, and make it preferred\n  over the existing overload.\n* Making `string.IndexOf(string, StringComparison = Ordinal)` preferred over `string.IndexOf(string)`. This would have to be discussed as a potential breaking change, but there\n  is some thought that it is the better default, and more likely to be what the user intended.\n* A combination of this proposal and [`CallerAssemblyAttribute`](https://github.com/dotnet/csharplang/issues/4984) would allow methods that have an implicit caller identity to\n  avoid expensive stack walks. `Assembly.Load(AssemblyName)` does this today, and it could be much more efficient.\n* `Microsoft.Extensions.Primitives.StringValues` exposes an implicit conversion to both `string` and `string[]`. This means that it is ambiguous when passed to a method with both\n  `params string[]` and `params ReadOnlySpan<string>` overloads. This attribute could be used to prioritize one of the overloads to prevent the ambiguity.\n\n## Detailed Design\n[detailed-design]: #detailed-design\n\n### Overload resolution priority\n\nWe define a new concept, ***overload_resolution_priority***, which is used during the process of resolving a method group. ***overload_resolution_priority*** is a 32-bit integer\nvalue. All methods have an ***overload_resolution_priority*** of 0 by default, and this can be changed by applying\n[`OverloadResolutionPriorityAttribute`](#systemruntimecompilerservicesoverloadresolutionpriorityattribute) to a method. We update section \n[§12.6.4.1](https://github.com/dotnet/csharpstandard/blob/draft-v9/standard/expressions.md#12641-general) of the C# specification as\nfollows (change in **bold**):\n\n> Once the candidate function members and the argument list have been identified, the selection of the best function member is the same in all cases:\n> \n> - First, the set of candidate function members is reduced to those function members that are applicable with respect to the given argument list ([§12.6.4.2](https://github.com/dotnet/csharpstandard/blob/draft-v9/standard/expressions.md#12642-applicable-function-member)). If this reduced set is empty, a compile-time error occurs.\n> - **Then, the reduced set of candidate members is grouped by declaring type. Within each group:**\n>     - **Candidate function members are ordered by ***overload_resolution_priority***. If the member is an override, the ***overload_resolution_priority*** comes from the least-derived declaration of that member.**\n>     - **All members that have a lower ***overload_resolution_priority*** than the highest found within its declaring type group are removed.**\n> - **The reduced groups are then recombined into the final set of applicable candidate function members.**\n> - Then, the best function member from the set of applicable candidate function members is located. If the set contains only one function member, then that function member is the best function member. Otherwise, the best function member is the one function member that is better than all other function members with respect to the given argument list, provided that each function member is compared to all other function members using the rules in [§12.6.4.3](https://github.com/dotnet/csharpstandard/blob/draft-v9/standard/expressions.md#12643-better-function-member). If there is not exactly one function member that is better than all other function members, then the function member invocation is ambiguous and a binding-time error occurs.\n\nAs an example, this feature would cause the following code snippet to print \"Span\", rather than \"Array\":\n\n```cs\nusing System.Runtime.CompilerServices;\n\nvar d = new C1();\nint[] arr = [1, 2, 3];\nd.M(arr); // Prints \"Span\"\n\nclass C1\n{\n    [OverloadResolutionPriority(1)]\n    public void M(ReadOnlySpan<int> s) => Console.WriteLine(\"Span\");\n    // Default overload resolution priority\n    public void M(int[] a) => Console.WriteLine(\"Array\");\n}\n```\n\nThe effect of this change is that, like pruning for most-derived types, we add a final pruning for overload resolution priority. Because this pruning occurs at the very end of the overload resolution\nprocess, it does mean that a base type cannot make its members higher-priority than any derived type. This is intentional, and prevents an arms-race from occuring where a base type may try to always\nbe better than a derived type. For example:\n\n```cs\nusing System.Runtime.CompilerServices;\n\nvar d = new Derived();\nd.M([1, 2, 3]); // Prints \"Derived\", because members from Base are not considered due to finding an applicable member in Derived\n\nclass Base\n{\n    [OverloadResolutionPriority(1)]\n    public void M(ReadOnlySpan<int> s) => Console.WriteLine(\"Base\");\n}\n\nclass Derived : Base\n{\n    public void M(int[] a) => Console.WriteLine(\"Derived\");\n}\n```\n\nNegative numbers are allowed to be used, and can be used to mark a specific overload as worse than all other default overloads.\n\nThe **overload_resolution_priority** of a member comes from the least-derived declaration of that member. **overload_resolution_priority** is not\ninherited or inferred from any interface members a type member may implement, and given a member `Mx` that implements an interface member `Mi`, no\nwarning is issued if `Mx` and `Mi` have different **overload_resolution_priorities**.\n> NB: The intent of this rule is to replicate the behavior of the `params` modifier.\n\n### `System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute`\n\nWe introduce the following attribute to the BCL:\n\n```cs\nnamespace System.Runtime.CompilerServices;\n\n[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]\npublic sealed class OverloadResolutionPriorityAttribute(int priority) : Attribute\n{\n    public int Priority => priority;\n}\n```\n\nAll methods in C# have a default ***overload_resolution_priority*** of 0, unless they are attributed with `OverloadResolutionPriorityAttribute`. If they are\nattributed with that attribute, then their ***overload_resolution_priority*** is the integer value provided to the first argument of the attribute.\n\nIt is an error to apply `OverloadResolutionPriorityAttribute` to the following locations:\n\n* Non-indexer properties\n* Property, indexer, or event accessors\n* Conversion operators\n* Lambdas\n* Local functions\n* Finalizers\n* Static constructors\n\nAttributes encountered on these locations in metadata are ignored by C#.\n\nIt is an error to apply `OverloadResolutionPriorityAttribute` in a location it would be ignored, such as on an override of a base method, as the priority is read\nfrom the least-derived declaration of a member.\n> NB: This intentionally differs from the behavior of the `params` modifier, which allows respecifying or adding when ignored.\n\n### Callability of members\n\nAn important caveat for `OverloadResolutionPriorityAttribute` is that it can make certain members effectively uncallable from source. For example:\n\n```cs\nusing System.Runtime.CompilerServices;\n\nint i = 1;\nvar c = new C3();\nc.M1(i); // Will call C3.M1(long), even though there's an identity conversion for M1(int)\nc.M2(i); // Will call C3.M2(int, string), even though C3.M1(int) has less default parameters\n\nclass C3\n{\n    public void M1(int i) {}\n    [OverloadResolutionPriority(1)]\n    public void M1(long l) {}\n\n    [Conditional(\"DEBUG\")]\n    public void M2(int i) {}\n    [OverloadResolutionPriority(1), Conditional(\"DEBUG\")]\n    public void M2(int i, [CallerArgumentExpression(nameof(i))] string s = \"\") {}\n\n    public void M3(string s) {}\n    [OverloadResolutionPriority(1)]\n    public void M3(object o) {}\n}\n```\n\nFor these examples, the default priority overloads effectively become vestigal, and only callable through a few steps that take some extra effort:\n* Converting the method to a delegate, and then using that delegate.\n    * For some reference type variance scenarios, such as `M3(object)` that is prioritized over `M3(string)`, this strategy will fail.\n    * Conditional methods, such as `M2`, would also not be callable with this strategy, as conditional methods cannot be converted to delegates.\n* Using the `UnsafeAccessor` runtime feature to call it via matching signature.\n* Manually using reflection to obtain a reference to the method and then invoking it.\n* Code that is not recompiled will continue to call old methods.\n* Handwritten IL can specify whatever it chooses.\n\n## Open Questions\n\n### Extension method grouping (answered)\n\nAs currently worded, extension methods are ordered by priority _only within their own type_. For example:\n\n```cs\nnew C2().M([1, 2, 3]); // Will print Ext2 ReadOnlySpan\n\nstatic class Ext1\n{\n    [OverloadResolutionPriority(1)]\n    public static void M(this C2 c, Span<int> s) => Console.WriteLine(\"Ext1 Span\");\n    [OverloadResolutionPriority(0)]\n    public static void M(this C2 c, ReadOnlySpan<int> s) => Console.WriteLine(\"Ext1 ReadOnlySpan\");\n}\n\nstatic class Ext2\n{\n    [OverloadResolutionPriority(0)]\n    public static void M(this C2 c, ReadOnlySpan<int> s) => Console.WriteLine(\"Ext2 ReadOnlySpan\");\n}\n\nclass C2 {}\n```\n\nWhen doing overload resolution for extension members, should we not sort by declaring type, and instead consider all extensions within the same scope?\n\n#### Answer\n\nWe will always group. The above example will print `Ext2 ReadOnlySpan`\n\n### Attribute inheritance on overrides (answered)\n\nShould the attribute be inherited? If not, what is the priority of the overriding member?  \nIf the attribute is specified on a virtual member, should an override of that member be required to repeat the attribute?  \n\n#### Answer\n\nThe attribute will not be marked as inherited. We will look at the least-derived declaration of a member to determine its overload resolution priority.\n\n### Application error or warning on override (answered)\n\n```cs\nclass Base\n{\n    [OverloadResolutionPriority(1)] public virtual void M() {}\n}\nclass Derived\n{\n    [OverloadResolutionPriority(2)] public override void M() {} // Warn or error for the useless and ignored attribute?\n}\n```\n\nWhich should we do on the application of a `OverloadResolutionPriorityAttribute` in a context where it is ignored, such as an override:\n\n1. Do nothing, let it silently be ignored.\n2. Issue a warning that the attribute will be ignored.\n3. Issue an error that the attribute is not allowed.\n\n3 is the most cautious approach, if we think there may be a space in the future where we might want to allow an override to specify this attribute.\n\n#### Answer\n\nWe will go with 3, and block application on locations it would be ignored.\n\n### Implicit interface implementation (answered)\n\nWhat should the behavior of an implicit interface implementation be? Should it be required to specify `OverloadResolutionPriority`? What should the behavior of the compiler be when it encounters\nan implicit implementation without a priority? This will nearly certainly happen, as an interface library may be updated, but not an implementation. Prior art here with `params` is to not specify,\nand not carry over the value:\n\n```cs\nusing System;\n\nvar c = new C();\nc.M(1, 2, 3); // error CS1501: No overload for method 'M' takes 3 arguments\n((I)c).M(1, 2, 3);\n\ninterface I\n{\n    void M(params int[] ints);\n}\n\nclass C : I\n{\n    public void M(int[] ints) { Console.WriteLine(\"params\"); }\n}\n```\n\nOur options are:\n\n1. Follow `params`. `OverloadResolutionPriorityAttribute` will not be implicitly carried over or be required to be specified.\n2. Carry over the attribute implicitly.\n3. Do not carry over the attribute implicitly, require it to be specified at the call site.\n   1. This brings an extra question: what should the behavior be when the compiler encounters this scenario with compiled references?\n\n#### Answer\n\nWe will go with 1.\n\n### Further application errors (Answered)\n\nThere are a few more locations like [this](#application-error-or-warning-on-override-answered) that need to be confirmed. They include:\n\n* Conversion operators - The spec never says that conversion operators go through overload resolution, so the implementation blocks application on these members.\n  Should that be confirmed?\n* Lambdas - Similarly, lambdas are never subject to overload resolution, so the implementation blocks them. Should that be confirmed?\n* Destructors - again, currently blocked.\n* Static constructors - again, currently blocked.\n* Local functions - These are not currently blocked, because they _do_ undergo overload resolution, you just can't overload them. This is similar to how we don't\n  error when the attribute is applied to a member of a type that is not overloaded. Should this behavior be confirmed?\n\n#### Answer\n\nAll of the locations listed above are blocked.\n\n### Langversion Behavior (Answered)\n\nThe implementation currently only issues langversion errors when `OverloadResolutionPriorityAttribute` is applied, _not_ when it actually influences anything. This\ndecision was made because there are APIs that the BCL will add (both now and over time) that will start using this attribute; if the user manually sets their\nlanguage version back to C# 12 or prior, they may see these members and, depending our langversion behavior, either:\n\n* If we ignore the attribute in C# <13, run into an ambiguity error because the API is truly ambiguous without the attribute, or;\n* If we error when the attribute affected the outcome, run into an error that the API is unconsumable. This will be especially bad because `Debug.Assert(bool)`\n  is being de-prioritized in .NET 9, or;\n* If we silently change resolution, encounter potentially different behavior between different compiler versions if one understands the attribute and another doesn't.\n\nThe last behavior was chosen, because it results in the most forward-compatibility, but the changing result could be surprising to some users. Should we confirm\nthis, or should we choose one of the other options?\n\n#### Answer\n\nWe will go with option 1, silently ignoring the attribute in previous language versions.\n\n## Alternatives\n[alternatives]: #alternatives\n\nA [previous](https://github.com/dotnet/csharplang/pull/7707) proposal tried to specify a `BinaryCompatOnlyAttribute` approach, which was very heavy-handed\nin removing things from visibility. However, that has lots of hard implementation problems that either mean the proposal is too strong to be useful (preventing\ntesting old APIs, for example) or so weak that it missed some of the original goals (such as being able have an API that would otherwise be considered ambiguous\ncall a new API). That version is replicated below.\n\n<details>\n\n<summary>BinaryCompatOnlyAttribute Proposal (obsolete)</summary>\n\n### BinaryCompatOnlyAttribute\n\n#### Detailed design\n[design]: #bco-detailed-design\n\n##### `System.BinaryCompatOnlyAttribute`\n\nWe introduce a new reserved attribute:\n\n```cs\nnamespace System;\n\n// Excludes Assembly, GenericParameter, Module, Parameter, ReturnValue\n[AttributeUsage(AttributeTargets.Class\n                | AttributeTargets.Constructor\n                | AttributeTargets.Delegate\n                | AttributeTargets.Enum\n                | AttributeTargets.Event\n                | AttributeTargets.Field\n                | AttributeTargets.Interface\n                | AttributeTargets.Method\n                | AttributeTargets.Property\n                | AttributeTargets.Struct,\n                AllowMultiple = false,\n                Inherited = false)]\npublic class BinaryCompatOnlyAttribute : Attribute {}\n```\n\nWhen applied to a type member, that member is treated as inaccessible in every location by the compiler, meaning that it does not contribute to member\nlookup, overload resolution, or any other similar process.\n\n##### Accessibility Domains\n\nWe update [§7.5.3 Accessibility domains](https://github.com/dotnet/csharpstandard/blob/720d921c5688190ea544682cdbdf8874fa716f2b/standard/basic-concepts.md#753-accessibility-domains)\nas **follows**:\n\n > The ***accessibility domain*** of a member consists of the (possibly disjoint) sections of program text in which access to the member is permitted. For purposes of defining the accessibility domain of a member, a member is said to be ***top-level*** if it is not declared within a type, and a member is said to be ***nested*** if it is declared within another type. Furthermore, the ***program text*** of a program is defined as all text contained in all compilation units of the program, and the program text of a type is defined as all text contained in the *type_declaration*s of that type (including, possibly, types that are nested within the type).\n>\n> The accessibility domain of a predefined type (such as `object`, `int`, or `double`) is unlimited.\n>\n> The accessibility domain of a top-level unbound type `T` ([§8.4.4](https://github.com/dotnet/csharpstandard/blob/draft-v9/standard/types.md#844-bound-and-unbound-types)) that is declared in a program `P` is defined as follows:\n> \n> - **If `T` is marked with `BinaryCompatOnlyAttribute`, the accessibility domain of `T` is completely inaccessible to the program text of `P` and any program that references `P`.**\n> - If the declared accessibility of `T` is public, the accessibility domain of `T` is the program text of `P` and any program that references `P`.\n> - If the declared accessibility of `T` is internal, the accessibility domain of `T` is the program text of `P`.\n> \n> *Note*: From these definitions, it follows that the accessibility domain of a top-level unbound type is always at least the program text of the program in which that type is declared. *end note*\n> \n> The accessibility domain for a constructed type `T<A₁, ..., Aₑ>` is the intersection of the accessibility domain of the unbound generic type `T` and the accessibility domains of the type arguments `A₁, ..., Aₑ`.\n> \n> The accessibility domain of a nested member `M` declared in a type `T` within a program `P`, is defined as follows (noting that `M` itself might possibly be a type):\n> \n> - **If `M` is marked with `BinaryCompatOnlyAttribute`, the accessibility domain of `M` is completely inaccessible to the program text of `P` and any program that references `P`.**\n> - If the declared accessibility of `M` is `public`, the accessibility domain of `M` is the accessibility domain of `T`.\n> - If the declared accessibility of `M` is `protected internal`, let `D` be the union of the program text of `P` and the program text of any type derived from `T`, which is declared outside `P`. The accessibility domain of `M` is the intersection of the accessibility domain of `T` with `D`.\n> - If the declared accessibility of `M` is `private protected`, let `D` be the intersection of the program text of `P` and the program text of `T` and any type derived from `T`. The accessibility domain of `M` is the intersection of the accessibility domain of `T` with `D`.\n> - If the declared accessibility of `M` is `protected`, let `D` be the union of the program text of `T`and the program text of any type derived from `T`. The accessibility domain of `M` is the intersection of the accessibility domain of `T` with `D`.\n> - If the declared accessibility of `M` is `internal`, the accessibility domain of `M` is the intersection of the accessibility domain of `T` with the program text of `P`.\n> - If the declared accessibility of `M` is `private`, the accessibility domain of `M` is the program text of `T`.\n\nThe goal of these additions is to make it so that members marked with `BinaryCompatOnlyAttribute` are completely inaccessible to any location, they will\nnot participate in member lookup, and cannot affect the rest of the program. Consequentely, this means they cannot implement interface members, they cannot\ncall each other, and they cannot be overridden (virtual methods), hidden, or implemented (interface members). Whether this is too strict is the subject of\nseveral open questions below.\n\n#### Unresolved questions\n[unresolved]: #unresolved-questions\n\n##### Virtual methods and overriding\n\nWhat do we do when a virtual method is marked as `BinaryCompatOnly`? Overrides in a derived class may not even be in the current assembly, and it could\nbe that the user is looking to introduce a new version of a method that, for example, only differs by return type, something that C# does not normally\nallow overloading on. What happens to any overrides of that previous method on recompile? Are they allowed to override the `BinaryCompatOnly` member if\nthey're also marked as `BinaryCompatOnly`?\n\n##### Use within the same DLL\n\nThis proposal states that `BinaryCompatOnly` members are not visible anywhere, not even in the assembly currently being compiled. Is that too strict, or\ndo `BinaryCompatAttribute` members need to possibly chain to one another?\n\n##### Implicitly implementing interface members\n\nShould `BinaryCompatOnly` members be able to implement interface members? Or should they be prevented from doing so. This would require that, when a user\nwants to turn an implicit interface implementation into `BinaryCompatOnly`, they would additionally have to provide an explicit interface implementation,\nlikely cloning the same body as the `BinaryCompatOnly` member as the explicit interface implementation would not be able to see the original member anymore.\n\n##### Implementing interface members marked `BinaryCompatOnly`\n\nWhat do we do when an interface member has been marked as `BinaryCompatOnly`? The type still needs to provide an implementation for that member; it may be\nthat we must simply say that interface members cannot be marked as `BinaryCompatOnly`.\n</details>\n"
  },
  {
    "path": "proposals/csharp-13.0/params-collections.md",
    "content": "# `params Collections`\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/7700>\n\n## Summary\n\nIn C# 12 language added support for creating instances of collection types beyond just arrays.\nSee [collection expressions](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md).\nThis proposal extends `params` support to all such collection types.\n\n## Motivation\n\nA `params` array parameter provides a convenient way to call a method that takes an arbitrary length list of arguments.\nToday `params` parameter must be an array type. However, it might be beneficial for a developer to be able to have the same\nconvenience when calling APIs that take other collection types. For example, an `ImmutableArray<T>`, `ReadOnlySpan<T>`, or \nplain `IEnumerable`. Especially in cases when compiler is able to avoid an implicit array allocation for the purpose of\ncreating the collection (`ImmutableArray<T>`, `ReadOnlySpan<T>`, etc).\n\nToday, in situations when an API takes a collection type, developers usually add a `params` overload that takes an array,\nconstruct the target collection and call the original overload with that collection, thus consumers of the API have to\ntrade an extra array allocation for convenience.\n\nAnother motivation is ability to add a params span overload and have it take precedence over the array version,\njust by recompiling existing source code.\n\n## Detailed design\n\n### Method parameters\n\nThe [Method parameters](https://github.com/dotnet/csharpstandard/blob/draft-v9/standard/classes.md#1562-method-parameters) section is adjusted as follows.\n\n```diff ANTLR\nformal_parameter_list\n    : fixed_parameters\n-    | fixed_parameters ',' parameter_array\n+    | fixed_parameters ',' parameter_collection\n-    | parameter_array\n+    | parameter_collection\n    ;\n\n-parameter_array\n+parameter_collection\n-    : attributes? 'params' array_type identifier\n+    : attributes? 'params' 'scoped'? type identifier\n    ;\n```\n\nA *parameter_collection* consists of an optional set of *attributes*, a `params` modifier, an optional `scoped` modifier,\na *type*, and an *identifier*. A parameter collection declares a single parameter of the given type with the given name.\nThe *type* of a parameter collection shall be one of the following valid target types for a collection expression\n(see https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#conversions):\n- A single dimensional *array type* `T[]`, in which case the *element type* is `T`\n- A *span type*\n  - `System.Span<T>`\n  - `System.ReadOnlySpan<T>`  \n  in which cases the *element type* is `T`\n- A *type* with an appropriate *[create method](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#create-methods)* that can be invoked with no additional arguments,\n  which is at least as accessible as the declaring member, and with a corresponding *element type* resulting from that determination\n- A *struct* or *class type* that implements `System.Collections.IEnumerable` where:\n  - The *type* has a constructor that can be invoked with no arguments, and the constructor is at least as accessible as the declaring member.\n  - The *type* has an instance (not an extension) method `Add` where:\n    - The method can be invoked with a single value argument.\n    - If the method is generic, the type arguments can be inferred from the argument.\n    - The method is at least as accessible as the declaring member.\n\n    In which case the *element type* is the [*iteration type*](https://github.com/dotnet/csharpstandard/blob/draft-v9/standard/statements.md#1395-the-foreach-statement) of the *type*.\n- An *interface type*\n  - `System.Collections.Generic.IEnumerable<T>`,\n  - `System.Collections.Generic.IReadOnlyCollection<T>`,\n  - `System.Collections.Generic.IReadOnlyList<T>`,\n  - `System.Collections.Generic.ICollection<T>`,\n  - `System.Collections.Generic.IList<T>`  \n  in which cases the *element type* is `T`\n\nIn a method invocation, a parameter collection permits either a single argument of the given parameter type to be specified, or\nit permits zero or more arguments of the collection's *element type* to be specified. \nParameter collections are described further in *[Parameter collections](#parameter-collections)*.\n\nA *parameter_collection* may occur after an optional parameter, but cannot have a default value – the omission of arguments for a *parameter_collection*\nwould instead result in the creation of an empty collection.\n\n### Parameter collections\n\nThe [Parameter arrays](https://github.com/dotnet/csharpstandard/blob/draft-v9/standard/classes.md#15626-parameter-arrays) section is renamed and adjusted as follows.\n\nA parameter declared with a `params` modifier is a parameter collection. If a formal parameter list includes a parameter collection,\nit shall be the last parameter in the list and it shall be of type specified in *[Method parameters](#method-parameters)* section.\n\n> *Note*: It is not possible to combine the `params` modifier with the modifiers `in`, `out`, or `ref`. *end note*\n\nA parameter collection permits arguments to be specified in one of two ways in a method invocation:\n\n- The argument given for a parameter collection can be a single expression that is implicitly convertible to the parameter collection type.\n  In this case, the parameter collection acts precisely like a value parameter.\n- Alternatively, the invocation can specify zero or more arguments for the parameter collection, where each argument is an expression\n  that is implicitly convertible to the parameter collection's *element type*.\n  In this case, the invocation creates an instance of the parameter collection type according to the rules specified in\n  [Collection expressions](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md)\n  as though the arguments were used as expression elements in a collection expression in the same order,\n  and uses the newly created collection instance as the actual argument.\n  When constructing the collection instance, the original *unconverted* arguments are used.\n\nExcept for allowing a variable number of arguments in an invocation, a parameter collection is precisely equivalent to\na value parameter of the same type.\n\nWhen performing overload resolution, a method with a parameter collection might be applicable, either in its normal form or\nin its expanded form. The expanded form of a method is available only if the normal form of the method is not applicable and\nonly if an applicable method with the same signature as the expanded form is not already declared in the same type.\n\nA potential ambiguity arises between the normal form and the expanded form of the method with a single parameter collection\nargument when it can be used as the parameter collection itself and as the element of the parameter collection at the same time.\nThe ambiguity presents no problem, however, since it can be resolved by inserting a cast or using a collection expression,\nif needed.\n\n### Signatures and overloading\n\nAll the rules around `params` modifier in [Signatures and overloading](https://github.com/dotnet/csharpstandard/blob/draft-v9/standard/basic-concepts.md#76-signatures-and-overloading)\nremain as is.\n\n### Applicable function member\n\nThe [Applicable function member](https://github.com/dotnet/csharpstandard/blob/draft-v9/standard/expressions.md#12642-applicable-function-member) section is adjusted as follows.\n\nIf a function member that includes a parameter collection is not applicable in its normal form, the function member might instead be applicable in its ***expanded form***:\n\n- If parameter collection is not an array, an expanded form is not applicable for language versions C# 12 and below.\n- The expanded form is constructed by replacing the parameter collection in the function member declaration with\n  zero or more value parameters of the parameter collection's *element type*\n  such that the number of arguments in the argument list `A` matches the total number of parameters.\n  If `A` has fewer arguments than the number of fixed parameters in the function member declaration,\n  the expanded form of the function member cannot be constructed and is thus not applicable.\n- Otherwise, the expanded form is applicable if for each argument in `A`, one of the following is true:\n  - the parameter-passing mode of the argument is identical to the parameter-passing mode of the corresponding parameter, and\n    - for a fixed value parameter or a value parameter created by the expansion, an implicit conversion exists from\n      the argument expression to the type of the corresponding parameter, or\n    - for an `in`, `out`, or `ref` parameter, the type of the argument expression is identical to the type of the corresponding parameter.\n  - the parameter-passing mode of the argument is value, and the parameter-passing mode of the corresponding parameter is input,\n    and an implicit conversion exists from the argument expression to the type of the corresponding parameter\n\n### Better function member\n\nThe [Better function member](https://github.com/dotnet/csharpstandard/blob/draft-v9/standard/expressions.md#12643-better-function-member) section is adjusted as follows.\n\nGiven an argument list `A` with a set of argument expressions `{E₁, E₂, ..., Eᵥ}` and two applicable function members `Mᵥ` and `Mₓ` with parameter types `{P₁, P₂, ..., Pᵥ}` and `{Q₁, Q₂, ..., Qᵥ}`, `Mᵥ` is defined to be a ***better function member*** than `Mₓ` if\n\n- for each argument, the implicit conversion from `Eᵥ` to `Qᵥ` is not better than the implicit conversion from `Eᵥ` to `Pᵥ`, and\n- for at least one argument, the conversion from `Eᵥ` to `Pᵥ` is better than the conversion from `Eᵥ` to `Qᵥ`.\n\nIn case the parameter type sequences `{P₁, P₂, ..., Pᵥ}` and `{Q₁, Q₂, ..., Qᵥ}` are equivalent (i.e., each `Pᵢ` has an identity conversion to the corresponding `Qᵢ`), the following tie-breaking rules are applied, in order, to determine the better function member.\n\n- If `Mᵢ` is a non-generic method and `Mₑ` is a generic method, then `Mᵢ` is better than `Mₑ`.\n- Otherwise, if `Mᵢ` is applicable in its normal form and `Mₑ` has a params collection and is applicable only in its expanded form, then `Mᵢ` is better than `Mₑ`.\n- Otherwise, if both methods have params collections and are applicable only in their expanded forms,\n  and if the params collection of `Mᵢ` has fewer elements than the params collection of `Mₑ`,\n  then `Mᵢ` is better than `Mₑ`.\n- Otherwise, if `Mᵥ` has more specific parameter types than `Mₓ`, then `Mᵥ` is better than `Mₓ`. Let `{R1, R2, ..., Rn}` and `{S1, S2, ..., Sn}` represent the uninstantiated and unexpanded parameter types of `Mᵥ` and `Mₓ`. `Mᵥ`’s parameter types are more specific than `Mₓ`s if, for each parameter, `Rx` is not less specific than `Sx`, and, for at least one parameter, `Rx` is more specific than `Sx`:\n  - A type parameter is less specific than a non-type parameter.\n  - Recursively, a constructed type is more specific than another constructed type (with the same number of type arguments) if at least one type argument is more specific and no type argument is less specific than the corresponding type argument in the other.\n  - An array type is more specific than another array type (with the same number of dimensions) if the element type of the first is more specific than the element type of the second.\n- Otherwise if one member is a non-lifted operator and the other is a lifted operator, the non-lifted one is better.\n- If neither function member was found to be better, and all parameters of `Mᵥ` have a corresponding argument whereas default arguments need to be substituted for at least one optional parameter in `Mₓ`, then `Mᵥ` is better than `Mₓ`.\n- If for at least one parameter `Mᵥ` uses the ***better parameter-passing choice*** ([§12.6.4.4](https://github.com/dotnet/csharpstandard/blob/draft-v9/standard/expressions.md#12644-better-parameter-passing-mode)) than the corresponding parameter in `Mₓ` and none of the parameters in `Mₓ` use the better parameter-passing choice than `Mᵥ`, `Mᵥ` is better than `Mₓ`.\n- **Otherwise, if both methods have params collections and are applicable only in their expanded forms then\n   `Mᵢ` is better than `Mₑ` if the same set of arguments corresponds to the collection elements for both methods, and one of the following holds\n   (this corresponds to https://github.com/dotnet/csharplang/blob/main/proposals/csharp-13.0/collection-expressions-better-conversion.md):**\n  - **both params collections are not *span_type*s, and an implicit conversion exists from params collection of `Mᵢ` to params collection of `Mₑ`**  \n  - **params collection of `Mᵢ` is `System.ReadOnlySpan<Eᵢ>`, and params collection of `Mₑ` is `System.Span<Eₑ>`, and an identity conversion exists from `Eᵢ` to `Eₑ`**\n  - **params collection of `Mᵢ` is `System.ReadOnlySpan<Eᵢ>` or `System.Span<Eᵢ>`, and params collection of `Mₑ` is\n    an *[array_or_array_interface__type](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#overload-resolution)*\n    with *element type* `Eₑ`, and an identity conversion exists from `Eᵢ` to `Eₑ`**\n- Otherwise, no function member is better.\n\nThe reason why the new tie-breaking rule is placed at the end of the list is the last sub item\n> - **both params collections are not *span_type*s, and an implicit conversion exists from params collection of `Mᵢ` to params collection of `Mₑ`** \n\nit is applicable to arrays and, therefore, performing the tie-break earlier will introduce a behavior change for existing scenarios.\n\nFor example:\n``` C#\nclass Program\n{\n    static void Main()\n    {\n        Test(1);\n    }\n\n    static void Test(in int x, params C2[] y) {} // There is an implicit conversion from `C2[]` to `C1[]`\n    static void Test(int x, params C1[] y) {} // Better candidate because of \"better parameter-passing choice\"\n}\n\nclass C1 {}\nclass C2 : C1 {}\n```\n\nIf any of the previous tie-breaking rules apply (including the \"better arguments conversions\" rule), the overload resolution result\ncan be different by comparison to the case when an explicit collection expression is used as an argument instead.\n\nFor example:\n``` C#\nclass Program\n{\n    static void Test1()\n    {\n        M1(['1', '2', '3']); // IEnumerable<char> overload is used because `char` is an exact match\n        M1('1', '2', '3');   // IEnumerable<char> overload is used because `char` is an exact match\n    }\n\n    static void M1(params IEnumerable<char> value) {}\n    static void M1(params System.ReadOnlySpan<MyChar> value) {}\n\n    class MyChar\n    {\n        private readonly int _i;\n        public MyChar(int i) { _i = i; }\n        public static implicit operator MyChar(int i) => new MyChar(i);\n        public static implicit operator char(MyChar c) => (char)c._i;\n    }\n\n    static void Test2()\n    {\n        M2([1]); // Span overload is used\n        M2(1);   // Array overload is used, not generic\n    }\n\n    static void M2<T>(params System.Span<T> y){}\n    static void M2(params int[] y){}\n\n    static void Test3()\n    {\n        M3(\"3\", [\"4\"]); // Ambiguity, better-ness of argument conversions goes in opposite directions.\n        M3(\"3\", \"4\");   // Ambiguity, better-ness of argument conversions goes in opposite directions.\n                        // Since parameter types are different (\"object, string\" vs. \"string, object\"), tie-breaking rules do not apply\n    }\n\n    static void M3(object x, params string[] y) {}\n    static void M3(string x, params Span<object> y) {}\n}\n```\n\nHowever, our primary concern are scenarios where overloads differ only by params collection type,\nbut the collection types have the same element type. The behavior should be consistent with \nexplicit collection expressions for these cases.\n\n\nThe \"**if the same set of arguments corresponds to the collection elements for both methods**\" condition is important for scenarios like:\n``` C#\nclass Program\n{\n    static void Main()\n    {\n        Test(x: 1, y: 2); // Ambiguous\n    }\n\n    static void Test(int x, params System.ReadOnlySpan<int> y) {}\n    static void Test(int y, params System.Span<int> x) {}\n}\n```\n\nIt doesn't feel reasonable to \"compare\" collections that are built from different elements.\n\n>This section was reviewed at [LDM](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-01-29.md#better-function-member-changes)\n>and was approved.\n\nOne effect of these rules is that when `params` of different element types are exposed, these will be ambiguous when called with an empty argument list.\nFor example:\n\n```cs\nclass Program\n{\n    static void Main()\n    {\n        // Old scenarios\n        C.M1(); // Ambiguous since params arrays were introduced\n        C.M1([]); // Ambiguous since params arrays were introduced\n\n        // New scenarios\n        C.M2(); // Ambiguous in C# 13\n        C.M2([]); // Ambiguous in C# 13\n        C.M3(); // Ambiguous in C# 13\n        C.M3([]); // Ambiguous in C# 13\n    }\n\n    public static void M1(params int[] a) {\n    }\n    \n    public static void M1(params int?[] a) {\n    }\n    \n    public static void M2(params ReadOnlySpan<int> a) {\n    }\n    \n    public static void M2(params Span<int?> a) {\n    }\n    \n    public static void M3(params ReadOnlySpan<int> a) {\n    }\n    \n    public static void M3(params ReadOnlySpan<int?> a) {\n    }\n}\n```\n\nGiven that we prioritize element type over all else, this seems reasonable; there's nothing to tell the language whether the user would prefer `int?`\nover `int` in this scenario.\n\n### Dynamic Binding\n\nExpanded forms of candidates utilizing non-array params collections won't be considered as valid candidates by the current C# runtime binder.\n\nIf the *primary_expression* does not have compile-time type `dynamic`, then the method invocation undergoes a limited\ncompile-time check as described in [§12.6.5 Compile-time checking of dynamic member invocation](https://github.com/dotnet/csharpstandard/blob/draft-v9/standard/expressions.md#1265-compile-time-checking-of-dynamic-member-invocation).\n\nIf only a single candidate passes the test, the invocation of the candidate is statically bound when all the following conditions are met:\n- the candidate is a local function\n- the candidate is either not generic, or its type arguments are explicitly specified;\n- there is no ambiguity between normal and expanded forms of the candidate that cannot be resolved at compile time. \n\nOtherwise, the *invocation_expression* is dynamically bound.\n\nIf only a single candidate passed the test above:\n- if that candidate is a local function, a compile-time error occurs;\n- if that candidate is applicable only in expanded form utilizing non-array params collections, a compile-time error occurs.\n\nWe also should consider reverting/fixing spec violation that affects local functions today, see https://github.com/dotnet/roslyn/issues/71399. \n\n>[LDM](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-01-29.md#dynamic-and-ref-local-function-bugfixing)\n>confirmed that we want to fix this spec violation. \n\n### Expression trees\n\nCollection expressions are not supported in expression trees. Similarly, expanded forms of non-array params collections\nwill not be supported in expression trees. We will not be changing how the compiler binds lambdas for expression trees\nwith the goal to avoid usage of APIs utilizing expanded forms of non-array params collections.\n\n### Order of evaluation with non-array collections in non-trivial scenarios\n\n> This section was reviewed at [LDM](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-01-31.md#params-collections-evaluation-orders)\n> and was approved. Despite the fact that array cases deviate from other collections, the official language specification\n> doesn't have to specify different rules for arrays. The deviations could simply be treated as an implementation artifact.\n> At the same time we do not intend to change the existing behavior around arrays.\n\n#### Named arguments\n\nA collection instance is created and populated after the lexically previous argument is evaluated, \nbut before the lexically following argument is evaluated.\n\nFor example:\n``` C#\nclass Program\n{\n    static void Main()\n    {\n        Test(b: GetB(), c: GetC(), a: GetA());\n    }\n\n    static void Test(int a, int b, params MyCollection c) {}\n\n    static int GetA() => 0;\n    static int GetB() => 0;\n    static int GetC() => 0;\n}\n```\nThe order of evaluation is the following:\n1. `GetB` is called\n2. `MyCollection` is created and populated, `GetC` is called in the process\n3. `GetA` is called\n4. `Test` is called\n\nNote, in params array case, the array is created right before the target method is invoked, after all\narguments are evaluated in their lexical order.\n\n#### Compound assignment\n\nA collection instance is created and populated after the lexically previous index is evaluated, \nbut before the lexically following index is evaluated. The instance is used to invoke getter\nand setter of the target indexer.\n\nFor example:\n``` C#\nclass Program\n{\n    static void Test(Program p)\n    {\n        p[GetA(), GetC()]++;\n    }\n\n    int this[int a, params MyCollection c] { get => 0; set {} }\n\n    static int GetA() => 0;\n    static int GetC() => 0;\n}\n```\nThe order of evaluation is the following:\n1. `GetA` is called and cached\n2. `MyCollection` is created, populated and cached, `GetC` is called in the process\n3. Indexer's getter is invoked with cached values for indexes\n4. Result is incremented\n5. Indexer's setter is invoked with cached values for indexes and the result of the increment\n\nAn example with an empty collection:\n``` C#\nclass Program\n{\n    static void Test(Program p)\n    {\n        p[GetA()]++;\n    }\n\n    int this[int a, params MyCollection c] { get => 0; set {} }\n\n    static int GetA() => 0;\n}\n```\nThe order of evaluation is the following:\n1. `GetA` is called and cached\n2. An empty `MyCollection` is created and cached\n3. Indexer's getter is invoked with cached values for indexes\n4. Result is incremented\n5. Indexer's setter is invoked with cached values for indexes and the result of the increment\n\n#### Object Initializer\n\nA collection instance is created and populated after the lexically previous index is evaluated, \nbut before the lexically following index is evaluated. The instance is used to invoke indexer's\ngetter as many times as necessary, if any.\n\nFor example:\n``` C#\nclass C1\n{\n    public int F1;\n    public int F2;\n}\n\nclass Program\n{\n    static void Test()\n    {\n        _ = new Program() { [GetA(), GetC()] = { F1 = GetF1(), F2 = GetF2() } };\n    }\n\n    C1 this[int a, params MyCollection c] => new C1();\n\n    static int GetA() => 0;\n    static int GetC() => 0;\n    static int GetF1() => 0;\n    static int GetF2() => 0;\n}\n```\nThe order of evaluation is the following:\n1. `GetA` is called and cached\n2. `MyCollection` is created, populated and cached, `GetC` is called in the process\n3. Indexer's getter is invoked with cached values for indexes\n4. `GetF1` is evaluated and assigned to `F1` field of `C1` retuned on the previous step\n5. Indexer's getter is invoked with cached values for indexes\n6. `GetF2` is evaluated and assigned to `F2` field of `C1` retuned on the previous step\n\nNote, in params array case, its elements are evaluated and cached, but a new instance of an array (with the same values inside)\nis used for each invocation of indexer's getter instead. For the example above, the order of evaluation is the following:\n1. `GetA` is called and cached\n2. `GetC` is called and cached\n3. Indexer's getter is invoked with cached `GetA` and new array populated with cached `GetC`\n4. `GetF1` is evaluated and assigned to `F1` field of `C1` retuned on the previous step\n5. Indexer's getter is invoked with cached `GetA` and new array populated with cached `GetC`\n6. `GetF2` is evaluated and assigned to `F2` field of `C1` retuned on the previous step\n\n\nAn example with an empty collection:\n``` C#\nclass C1\n{\n    public int F1;\n    public int F2;\n}\n\nclass Program\n{\n    static void Test()\n    {\n        _ = new Program() { [GetA()] = { F1 = GetF1(), F2 = GetF2() } };\n    }\n\n    C1 this[int a, params MyCollection c] => new C1();\n\n    static int GetA() => 0;\n    static int GetF1() => 0;\n    static int GetF2() => 0;\n}\n```\nThe order of evaluation is the following:\n1. `GetA` is called and cached\n2. An empty `MyCollection` is created and cached\n3. Indexer's getter is invoked with cached values for indexes\n4. `GetF1` is evaluated and assigned to `F1` field of `C1` retuned on the previous step\n5. Indexer's getter is invoked with cached values for indexes\n6. `GetF2` is evaluated and assigned to `F2` field of `C1` retuned on the previous step\n\n \n### Ref safety\n\nThe [collection expressions ref safety section](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#ref-safety) is applicable to\nthe construction of parameter collections when APIs are invoked in their expanded form.\n\nParams parameters are implicitly `scoped` when their type is a ref struct. UnscopedRefAttribute can be used to override that.\n\n### Metadata\n\nIn metadata we could mark non-array `params` parameters with `System.ParamArrayAttribute`, as `params` arrays are marked today.\nHowever, it looks like we will be much safer to use a different attribute for non-array `params` parameters.\nFor example, the current VB compiler will not be able to consume them decorated with `ParamArrayAttribute` neither in normal, nor in expanded form. Therefore, an addition of 'params' modifier is likely to break VB consumers, and very likely consumers from other languages or tools.\n\nGiven that, non-array `params` parameters are marked with a new `System.Runtime.CompilerServices.ParamCollectionAttribute`.\n``` C#\nnamespace System.Runtime.CompilerServices\n{\n    [AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)]\n    public sealed class ParamCollectionAttribute : Attribute\n    {\n        public ParamCollectionAttribute() { }\n    }\n}\n```\n\n> This section was reviewed at [LDM](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-02-21.md#metadata-format)\n> and was approved.\n\n## Open questions\n\n### Stack allocations \n\nHere is a quote from https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#unresolved-questions:\n\"Stack allocations for huge collections might blow the stack.  Should the compiler have a heuristic for placing this data on the heap?\nShould the language be unspecified to allow for this flexibility?\nWe should follow the spec for [`params Span<T>`](https://github.com/dotnet/csharplang/issues/1757).\" It sounds like we have to answer\nthe questions in context of this proposal.\n\n### [Resolved] Implicitly `scoped` params \n\nThere was a suggestion that, when `params` modifies a `ref struct` parameter, it should be considered as declared `scoped`.\nThe argument is made that number of cases where you want the parameter to be scoped is virtually 100% when looking through\nthe BCL cases. In a few cases that need that, the default could be overwritten with `[UnscopedRef]`.\n\nHowever, it might be undesirable to change the default simply based on presence of `params` modifier. Especially, that\nin overrides/implements scenarios `params` modifier doesn't have to match.\n\n#### Resolution:\nParams parameters are implicitly scoped - https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-11-15.md#params-improvements.\n\n### [Resolved] Consider enforcing `scoped` or `params` across overrides\n\nWe've previously stated that `params` parameters should be `scoped` by default. However, this introduces odd behavior in overriding, due\nto our existing rules around restating `params`:\n\n```cs\nclass Base\n{\n    internal virtual Span<int> M1(scoped Span<int> s1, params Span<int> s2) => throw null!;\n}\n\nclass Derived : Base\n{\n    internal override Span<int> M1(Span<int> s1, // Error, missing `scoped` on override\n                                   Span<int> s2  // Proposal: Error: parameter must include either `params` or `scoped`\n                                  ) => throw null!;\n}\n```\n\nWe have a difference in behavior between carrying the `params` and carrying the `scoped` across overrides here: `params` is inherited implicitly,\nand with it `scoped`, while `scoped` by itself is _not_ inherited implicitly and must be repeated at every level.\n\n**Proposal**: We should enforce that overrides of `params` parameters must explicitly state `params` or `scoped` if the original definition is a\n`scoped` parameter. In other words, `s2` in `Derived` must have `params`, `scoped`, or both.\n\n#### Resolution:\n\nWe will require explicitly stating `scoped` or `params` on override of a `params` parameter when a non-`params` parameter would be required to do so -\nhttps://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-02-21.md#params-and-scoped-across-overrides.\n\n### [Resolved] Should presence of required members prevent declaration of `params` parameter?\n\nConsider the following example:\n``` C#\nusing System.Collections;\nusing System.Collections.Generic;\n\npublic class MyCollection1 : IEnumerable<long>\n{\n    IEnumerator<long> IEnumerable<long>.GetEnumerator() => throw null;\n    IEnumerator IEnumerable.GetEnumerator() => throw null;\n    public void Add(long l) => throw null;\n\n    public required int F; // Collection has required member and constructor doesn't initialize it explicitly\n}\n\nclass Program\n{\n    static void Main()\n    {\n        Test(2, 3); // error CS9035: Required member 'MyCollection1.F' must be set in the object initializer or attribute constructor.\n    }\n\n    // Proposal: An error is reported for the parameter indicating that the constructor that is required\n    // to be available doesn't initialize required members. In other words, one is able\n    // to declare such a parameter under the specified conditions.\n    static void Test(params MyCollection1 a)\n    {\n    }\n}\n```\n#### Resolution:\n\nWe will validate `required` members against the constructor that is used to determine eligibility to be a `params` parameter at the declaration site -\nhttps://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-02-21.md#required-members-and-params-parameters.\n\n## Alternatives \n\nThere is an alternative [proposal](https://github.com/dotnet/csharplang/blob/main/proposals/rejected/params-span.md) that extends\n`params` only for `ReadOnlySpan<T>`.\n\nAlso, one might say, that with [collection expressions](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md)\nnow in the language, there is no need to extend `params` support at all. For any collection type. To consume an API with collection type, a developer\nsimply needs to add two characters, `[` before the expanded list of arguments, and `]` after it. Given that, extending `params` support might be an overkill,\nespecially that other languages are unlikely to support consumption of non-array `params` parameters any time soon.\n\n## Related proposals\n- https://github.com/dotnet/csharplang/issues/1757\n- https://github.com/dotnet/csharplang/blob/main/proposals/rejected/format.md#extending-params\n \n## Related design meetings\n\n- https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-11-15.md#params-improvements\n- https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-01-08.md\n- https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-01-10.md\n- https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-01-29.md\n- https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-01-31.md#params-collections-evaluation-orders\n- https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-02-21.md#params-collections\n- https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-04-22.md#effect-of-language-version-on-overload-resolution-in-presence-of-params-collections\n- https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-04-24.md#adjust-dynamic-binding-rules-for-a-situation-of-a-single-applicable-candidate\n- https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-05-01.md#adjust-binding-rules-in-the-presence-of-a-single-candidate\n- https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-06-03.md#params-collections-and-dynamic\n- https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-06-12.md#params-span-breaks\n- https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-06-17.md#params-span-breaks\n\n"
  },
  {
    "path": "proposals/csharp-13.0/partial-properties.md",
    "content": "# Partial properties\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/6420>\n\n### Grammar\n\nThe *property_declaration* grammar [(§14.7.1)](https://github.com/dotnet/csharpstandard/blob/draft-v7/standard/classes.md#1471-general) is updated as follows:\n\n```diff\nproperty_declaration\n-    : attributes? property_modifier* type member_name property_body\n+    : attributes? property_modifier* 'partial'? type member_name property_body\n    ;  \n```\n\n**Remarks**: This is somewhat similar to how *method_header* [(§15.6.1)](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/classes.md#1561-general) and *class_declaration* [(§15.2.1)](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/classes.md#1521-general) are specified. (Note that [Issue #946](https://github.com/dotnet/csharplang/issues/946) proposes to relax the ordering requirement, and would probably apply to all declarations which allow the `partial` modifier. We intend to specify such an ordering relaxation in the near future, and implement it in the same release that this feature is implemented.)\n\n### Defining and implementing declarations\nWhen a property declaration includes a *partial* modifier, that property is said to be a *partial property*. Partial properties may only be declared as members of partial types.\n\nA *partial property* declaration is said to be a *defining declaration* when its accessors all have semicolon bodies, and it lacks the `extern` modifier. Otherwise, it is an *implementing declaration*.\n\n```cs\npartial class C\n{\n    // Defining declaration\n    public partial string Prop { get; set; }\n\n    // Implementing declaration\n    public partial string Prop { get => field; set => field = value; }\n}\n```\n\nBecause we have reserved the syntactic form with semicolon accessor bodies for the *defining declaration*, a partial property cannot be *automatically implemented*. We therefore adjust [Automatically implemented properties (§15.7.4)](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/classes.md#1574-automatically-implemented-properties) as follows:\n\n> An automatically implemented property (or auto-property for short), is a non-abstract, non-extern, **non-partial,** non-ref-valued property with semicolon-only accessor bodies.\n\n**Remarks**. It is useful for the compiler to be able to look at a single declaration in isolation and know whether it is a defining or an implementing declaration. Therefore we don't want to permit auto-properties by including two identical `partial` property declarations, for example. We don't think that the use cases for this feature involve implementing the partial property with an auto-property, but in cases where a trivial implementation is desired, we think the `field` keyword makes things simple enough.\n\n---\n\nA partial property must have one *defining declaration* and one *implementing declaration*.\n\n**Remarks**. We also don't think it is useful to allow splitting the declaration across more than two parts, to allow different accessors to be implemented in different places, for example. Therefore we simply imitate the scheme established by partial methods.\n\n---\n\nOnly the defining declaration of a partial property participates in lookup, similar to how only the defining declaration of a partial method participates in overload resolution.\n\n**Remarks**. In the compiler, we would expect that only the symbol for the defining declaration appears in the member list, and the symbol for the implementing part can be accessed through the defining symbol. However, some features like nullable analysis might *see through* to the implementing declaration in order to provide more useful behavior.\n\n```cs\npartial class C\n{\n    public partial string Prop { get; set; }\n    public partial string Prop { get => field; set => field = value; }\n\n    public C() // warning CS8618: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.\n    {\n    }\n}\n```\n\n---\n\nA partial property is not permitted to have the `abstract` modifier.\n\nA partial property cannot explicitly implement interface properties.\n\n### Attribute merging\n\nSimilar to partial methods, the attributes in the resulting property are the combined attributes of the parts are concatenated in an unspecified order, and duplicates are not removed.\n\n### Caller-info attributes\nWe adjust the following language from the [standard](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/attributes.md#22551-general):\n\n> It is an error to have the same caller-info attribute on a parameter of both the defining and implementing part of a partial ~~method~~ **member** declaration. Only caller-info attributes in the defining part are applied, whereas caller-info attributes occurring only in the implementing part are ignored.\n\n- The described error falls out from the definitions of these attributes not having `AllowMultiple = true`. Using them multiple times, including across partial declarations, results in an error.\n- When caller-info attributes are applied to a parameter in the implementation part of a partial method, the Roslyn compiler reports a warning. It will also report a warning for the same scenario in a partial property.\n\n### Matching signatures\n\nThe LDM meeting on [14th September 2020](https://github.com/dotnet/csharplang/blob/main/meetings/2020/LDM-2020-09-14.md#partial-method-signature-matching) defined a set of \"strict\" requirements for signature matching of partial methods, which were introduced in a warning wave. Partial properties have analogous requirements to partial methods for signature matching as much as is possible, except that all of the diagnostics for mismatch are reported by default, and are not held behind a warning wave.\n\nSignature matching requirements include:\n1. Type and ref kind differences between partial property declarations which are significant to the runtime result in a compile-time error.\n2. Differences in tuple element names within partial property declarations results in a compile-time error, same as for partial methods.\n3. The property declarations and their accessor declarations must have the same modifiers, though the modifiers may appear in a different order.\n    - Exception: this does not apply to the `extern` modifier, which may only appear on an *implementing declaration*.\n4. All other syntactic differences in the signatures of partial property declarations result in a compile-time warning, with the following exceptions:\n    - Attribute lists on or within partial property declarations do not need to match. Instead, merging of attributes in corresponding positions is performed, per [Attribute merging](#attribute-merging).\n    - Nullable context differences do not cause warnings. In other words, a difference where one of the types is nullable-oblivious and the other type is either nullable-annotated or not-nullable-annotated does not result in any warnings.\n    - Default parameter values do not need to match. A warning is reported when the implementation part of a partial indexer has default parameter values. This is similar to an existing warning which occurs when the implementation part of a partial method has default parameter values.\n5. A warning occurs when parameter names differ across defining and implementing declarations. The parameter names from the definition part are used at use sites and in emit.\n6. Nullability differences which do not involve oblivious nullability result in warnings. When analyzing an accessor body, the implementation part signature is used. The definition part signature is used when analyzing use sites and in emit. This is consistent with partial methods.\n\n```cs\npartial class C1\n{\n    public partial string Prop { get; private set; }\n\n    // Error: accessor modifier mismatch in 'set' accessor of 'Prop'\n    public partial string Prop { get => field; set => field = value; }\n}\n\npartial class C2\n{\n    public partial string Prop { get; init; }\n\n    // Error: implementation of 'Prop' must have an 'init' accessor to match definition\n    public partial string Prop { get => field; set => field = value; }\n}\n\npartial class C3\n{\n    public partial string Prop { get; }\n\n    // Error: implementation of 'Prop' cannot have a 'set' accessor because the definition does not have a 'set' accessor.\n    public partial string Prop { get => field; set => field = value; }\n}\n\npartial class C4\n{\n    public partial string this[string s = \"a\"] { get; set; }\n    public partial string this[string s] { get => s; set { } } // ok\n\n    public partial string this[int i, string s = \"a\"] { get; set; }\n    public partial string this[int i, string s = \"a\"] { get => s; set { } } // CS1066: The default value specified for parameter 's' will have no effect because it applies to a member that is used in contexts that do not allow optional arguments\n}\n```\n\n### Documentation comments\n\nWe want the behavior of doc comments on partial properties to be consistent with what we shipped for partial methods. That behavior is detailed in https://github.com/dotnet/csharplang/issues/5193.\n\nIt is permitted to include doc comments on either the definition or implementation part of a partial property. (Note that doc comments are not supported on property accessors.)\n\nWhen doc comments are present on only one of the parts of the property, those doc comments are used normally (surfaced through `ISymbol.GetDocumentationCommentXml()`, written out to the documentation XML file, etc.).\n\nWhen doc comments are present on both parts, all the doc comments on the definition part are dropped, and only the doc comments on the implementation part are used.\n\nFor example, the following program:\n```cs\n/// <summary>\n/// My type\n/// </summary>\npartial class C\n{\n    /// <summary>Definition part comment</summary>\n    /// <returns>Return value comment</returns>\n    public partial int Prop { get; set; }\n    \n    /// <summary>Implementation part comment</summary>\n    public partial int Prop { get => 1; set { } }\n}\n```\n\nResults in the following XML documentation file:\n```xml\n<?xml version=\"1.0\"?>\n<doc>\n    <assembly>\n        <name>ConsoleApp1</name>\n    </assembly>\n    <members>\n        <member name=\"T:C\">\n            <summary>\n            My type\n            </summary>\n        </member>\n        <member name=\"P:C.Prop\">\n            <summary>\n            Implementation part comment\n            </summary>\n        </member>\n    </members>\n</doc>\n```\n\nWhen parameter names differ between partial declarations, `<paramref>` elements use the parameter names from the declaration associated with the documentation comment in source code. For example, a paramref on a doc comment placed on an implementing declaration refers to the parameter symbols on the implementing declaration using their parameter names. This is consistent with partial methods.\n\n```cs\n/// <summary>\n/// My type\n/// </summary>\npartial class C\n{\n    public partial int this[int x] { get; set; }\n\n    /// <summary>\n    /// <paramref name=\"x\"/> // warning CS1734: XML comment on 'C.this[int]' has a paramref tag for 'x', but there is no parameter by that name\n    /// <paramref name=\"y\"/> // ok. 'Go To Definition' will go to 'int y'.\n    /// </summary>\n    public partial int this[int y] { get => 1; set { } } // warning CS9256: Partial property declarations 'int C.this[int x]' and 'int C.this[int y]' have signature differences.\n}\n```\n\nResults in the following XML documentation file:\n```xml\n<?xml version=\"1.0\"?>\n<doc>\n    <assembly>\n        <name>ConsoleApp1</name>\n    </assembly>\n    <members>\n        <member name=\"T:C\">\n            <summary>\n            My type\n            </summary>\n        </member>\n        <member name=\"P:C.Item(System.Int32)\">\n            <summary>\n            <paramref name=\"x\"/> // warning CS1734: XML comment on 'C.this[int]' has a paramref tag for 'x', but there is no parameter by that name\n            <paramref name=\"y\"/> // ok. 'Go To Definition' will go to 'int y'.\n            </summary>\n        </member>\n    </members>\n</doc>\n```\n\nThis can be confusing, because the metadata signature will use parameter names from the definition part. It is recommended to ensure that parameter names match across parts to avoid this confusion.\n\n### Indexers\n\nPer [LDM meeting on 2nd November 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-11-02.md#partial-properties), indexers will be supported with this feature.\n\nThe indexers grammar is modified as follows:\n```diff\nindexer_declaration\n-    : attributes? indexer_modifier* indexer_declarator indexer_body\n+    : attributes? indexer_modifier* 'partial'? indexer_declarator indexer_body\n-    | attributes? indexer_modifier* ref_kind indexer_declarator ref_indexer_body\n+    | attributes? indexer_modifier* 'partial'? ref_kind indexer_declarator ref_indexer_body\n    ;\n```\n\nPartial indexer parameters must match across declarations per the same rules as [Matching signatures](#matching-signatures). [Attribute merging](#attribute-merging) is performed across partial indexer parameters.\n\n```cs\npartial class C\n{\n    public partial int this[int x] { get; set; }\n    public partial int this[int x]\n    {\n        get => this._store[x];\n        set => this._store[x] = value;\n    }\n}\n\n// attribute merging\npartial class C\n{\n    public partial int this[[Attr1] int x]\n    {\n        [Attr2] get;\n        set;\n    }\n\n    public partial int this[[Attr3] int x]\n    {\n        get => this._store[x];\n        [Attr4] set => this._store[x] = value;\n    }\n\n    // results in a merged member emitted to metadata:\n    public int this[[Attr1, Attr3] int x]\n    {\n        [Attr2] get => this._store[x];\n        [Attr4] set => this._store[x] = value;\n    }\n}\n```\n\n## Open Issues\n\n### Other member kinds\n\nA community member opened a discussion to request support for [partial events](https://github.com/dotnet/csharplang/discussions/8064). In the [LDM meeting on 2nd November 2022](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-11-02.md#partial-properties), we decided to punt on support for events, in part because nobody at the time had requested it. We may want to revisit this question, since this request has now come in, and it has been over a year since we last discussed it.\n\nWe could also go even further in permitting partial declarations of constructors, operators, fields, and so on, but it's unclear if the design burden of these is justified, just because we are already doing partial properties.\n"
  },
  {
    "path": "proposals/csharp-13.0/ref-struct-interfaces.md",
    "content": "# Ref Struct Interfaces\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/7608>\n\n## Summary\n\nThis proposal will expand the capabilities of `ref struct` such that they can implement interfaces and participate as generic type arguments.\n\n## Motivation\n\nThe inability for `ref struct` to implement interfaces means they cannot participate in fairly fundamental abstraction techniques of .NET. A `Span<T>`, even though it has all the attributes of a sequential list cannot participate in methods that take `IReadOnlyList<T>`, `IEnumerable<T>`, etc ... Instead specific methods must be coded for `Span<T>` that have virtually the same implementation. Allowing `ref struct` to implement interfaces will allow operations to be abstracted over them as they are for other types.\n\n## Detailed Design\n\n### ref struct interfaces\n\nThe language will allow for `ref struct` types to implement interfaces. The syntax and rules are the same as for normal `struct` with a few exceptions to account for the limitations of `ref struct` types.\n\nThe ability to implement interfaces does not impact the existing limitations against boxing `ref struct` instances. That means even if a `ref struct` implements a particular interface,  it cannot be directly cast to it as that represents a boxing action.\n\n```csharp\nref struct File : IDisposable\n{\n    private SafeHandle _handle;\n    public void Dispose()\n    {\n        _handle.Dispose();\n    }\n}\n\nFile f = ...;\n// Error: cannot box `ref struct` type `File`\nIDisposable d = f;\n```\n\nThe ability to implement interfaces is only useful when combined with the ability for `ref struct` to participate in generic arguments (as [laid out later][ref-struct-generics]).\n\nTo allow for interfaces to cover the full expressiveness of a `ref struct` and the lifetime issues they can present, the language will allow `[UnscopedRef]` to appear on interface methods and properties. This is necessary as it allows for interfaces that abstract over `struct` to have the same flexibility as using a `struct` directly. Consider the following example:\n\n```csharp\ninterface I1\n{\n    [UnscopedRef]\n    ref int P1 { get; }\n    ref int P2 { get; }\n}\n\nstruct S1\n{\n    [UnscopedRef]\n    internal ref int P1 { get {...} }\n\n    internal ref int P2 { get {...} }\n}\n\nref int M<T>(T t, S1 s)\n    where T : I1, allows ref struct\n{\n    // Error: may return ref to t\n    return ref t.P1;\n\n    // Error: may return ref to t\n    return ref s.P1;\n\n    // Okay\n    return ref t.P2;\n\n    // Okay\n    return ref s.P2;\n}\n```\n\nWhen a `struct` / `ref struct` member implements an interface member with a `[UnscopedRef]` attribute, the implementing member may also be decorated with `[UnscopedRef]` but it is not required. However a member with `[UnscopedRef]` may not be used to implement a member that lacks the attribute ([details][unscoped-ref-impl]).\n\n```csharp\ninterface I1\n{\n    [UnscopedRef]\n    ref int P1 { get; }\n    ref int P2 { get; }\n}\n\nstruct S1\n{\n    internal ref int P1 { get {...} }\n    internal ref int P2 { get {...} }\n}\n\nstruct S2\n{\n    [UnscopedRef]\n    internal ref int P1 { get {...} }\n    internal ref int P2 { get {...} }\n}\n\nstruct S3 : I1\n{\n    internal ref int P1 { get {...} }\n    // Error: P2 is marked with [UnscopedRef] and cannot implement I1.P2 as is not marked \n    // with [UnscopedRef]\n    [UnscopedRef]\n    internal ref int P2 { get {...} }\n}\n\nclass C1 : I1\n{\n    internal ref int P1 { get {...} }\n    internal ref int P2 { get {...} }\n}\n```\n\nDefault interface methods pose a problem for `ref struct` as there are no protections against the default implementation boxing the `this` member.\n\n```csharp\ninterface I1\n{\n    void M()\n    {\n        // Danger: both of these box if I1 is implemented by a ref struct\n        I1 local1 = this;\n        object local2 = this;\n    }\n}\n\n// Error: I1.M cannot implement interface member I1.M() for ref struct S\nref struct S : I1 { }\n```\n\nTo handle this a `ref struct` will be forced to implement all members of an interface, even if they have default implementations.\nThe runtime will also be updated to throw an exception if a default interface member is called on a `ref struct` type.\n\nTo avoid an exception at runtime the compiler will report an error for an invocation of a non-virtual instance method (or property)\non a type parameter that allows ref struct. Here is an example:\n```csharp\npublic interface I1\n{\n    sealed void M3() {}\n}\n\nclass C\n{\n    static void Test2<T>(T x) where T : I1, allows ref struct\n    {\n#line 100\n        x.M3(); // (100,9): error: A non-virtual instance interface member cannot be accessed on a type parameter that allows ref struct.\n    }\n}\n```\n\nThere is also an open design question about reporting a [warning][warn-DIM] for an invocation of a virtual (not abstract) instance method (or property)\non a type parameter that allows ref struct.\n\nDetailed Notes:\n\n- A `ref struct` can implement an interface\n- A `ref struct` cannot participate in default interface members\n- A `ref struct` cannot be cast to interfaces it implements as that is a boxing operation\n\n### ref struct Generic Parameters\n\n```ANTLR\ntype_parameter_constraints_clause\n    : 'where' type_parameter ':' type_parameter_constraints\n    ;\n\ntype_parameter_constraints\n    : restrictive_type_parameter_constraints\n    | allows_type_parameter_constraints_clause\n    | restrictive_type_parameter_constraints ',' allows_type_parameter_constraints_clause\n\nrestrictive_type_parameter_constraints\n    : primary_constraint\n    | secondary_constraints\n    | constructor_constraint\n    | primary_constraint ',' secondary_constraints\n    | primary_constraint ',' constructor_constraint\n    | secondary_constraints ',' constructor_constraint\n    | primary_constraint ',' secondary_constraints ',' constructor_constraint\n    ;\n\nprimary_constraint\n    : class_type\n    | 'class'\n    | 'struct'\n    | 'unmanaged'\n    ;\n\nsecondary_constraints\n    : interface_type\n    | type_parameter\n    | secondary_constraints ',' interface_type\n    | secondary_constraints ',' type_parameter\n    ;\n\nconstructor_constraint\n    : 'new' '(' ')'\n    ;\n\nallows_type_parameter_constraints_clause\n    : 'allows' allows_type_parameter_constraints\n\nallows_type_parameter_constraints\n    : allows_type_parameter_constraint\n    | allows_type_parameter_constraints ',' allows_type_parameter_constraint\n\nallows_type_parameter_constraint\n    : ref_struct_clause\n\nref_struct_clause\n    : 'ref' 'struct'\n```\n\nThe language will allow for generic parameters to opt into supporting `ref struct` as arguments by using the `allows ref struct` syntax inside a `where` clause:\n\n```csharp\nT Identity<T>(T p)\n    where T : allows ref struct\n    => p;\n\n// Okay\nSpan<int> local = Identity(new Span<int>(new int[10]));\n```\n\nThis is similar to other items in a `where` clause in that it specifies the capabilities of the generic parameter. The difference is other syntax items limit the set of types that can fulfill a generic parameter while `allows ref struct` expands the set of types. This is effectively an anti-constraint as it removes the implicit constraint that `ref struct` cannot satisfy a generic parameter. As such this is given a new syntax prefix, `allows`, to make that clearer.\n\nA type parameter bound by `allows ref struct` has all of the behaviors of a `ref struct` type:\n\n1. Instances of it cannot be boxed\n2. Instances participate in lifetime rules like a normal `ref struct`\n3. The type parameter cannot be used in `static` fields, elements of an array, etc ...\n4. Instances can be marked with `scoped`\n\nExamples of these rules in action:\n\n```csharp\ninterface I1 { }\nI1 M1<T>(T p)\n    where T : I1, allows ref struct\n{\n    // Error: cannot box potential ref struct\n    return p;\n}\n\nT M2<T>(T p)\n    where T : allows ref struct\n{\n    Span<int> span = stackalloc int[42];\n\n    // The safe-to-escape of the return is current method because one of the inputs is\n    // current method\n    T t = M3<int, T>(span);\n\n    // Error: the safe-to-escape is current method.\n    return t;\n\n    // Okay\n    return default;\n    return p;\n}\n\nR M3<T, R>(Span<T> span)\n    where R : allows ref struct\n{\n    return default;\n}\n```\n\nThe anti-constraint is not \"inherited\" from a type parameter type constraint.\nFor example, `S` in the code below cannot be substituted with a ref struct:\n```csharp\nclass C<T, S>\n    where T : allows ref struct\n    where S : T\n{}\n```\nDetailed notes:\n\n- A `where T : allows ref struct` generic parameter cannot\n  - Have `where T : U` where `U` is a known reference type\n  - Have `where T : class` constraint\n  - Cannot be used as a generic argument unless the corresponding parameter is also `where T: allows ref struct`\n- The `allows ref struct` must be the last constraint in the `where` clause\n- A type parameter `T` which has `allows ref struct` has all the same limitations as a `ref struct` type.\n\n### Representation in metadata\n\nType parameters allowing ref structs will be encoded in metadata as described in the [byref-like generics doc][byref-like-generics].\nSpecifically by using the `CorGenericParamAttr.gpAllowByRefLike(0x0020)` or `System.Reflection.GenericParameterAttributes.AllowByRefLike(0x0020)` flag value.\nWhether runtime supports the feature can be determined by checking presence of `System.Runtime.CompilerServices.RuntimeFeature.ByRefLikeGenerics` field.\nThe APIs were added in https://github.com/dotnet/runtime/pull/98070.\n\n### `using` statement\n\nA `using` statement will recognize and use implementation of `IDisposable` interface when resource is a ref struct.\n```csharp\nref struct S2 : System.IDisposable\n{\n    void System.IDisposable.Dispose()\n    {\n    }\n}\n\nclass C\n{\n    static void Main()\n    {\n        using (new S2())\n        {\n        } // S2.System.IDisposable.Dispose is called\n    }\n}\n```\n\nNote that preference is given to a `Dispose` method that implements the pattern, and only if one is not found, `IDisposable`\nimplementation is used.\n\nA `using` statement will recognize and use implementation of `IDisposable` interface when resource is a type parameter that \n`allows ref struct` and `IDisposable` is in its effective interfaces set.\n```csharp\nclass C\n{\n    static void Test<T>(T t) where T : System.IDisposable, allows ref struct\n    {\n        using (t)\n        {\n        }\n    }\n}\n```\n\nNote that a pattern `Dispose` method will not be recognized on a type parameter that `allows ref struct` because\nan interface (and this is the only place where we could possibly look for a pattern) is not a ref struct.\n```csharp\ninterface IMyDisposable\n{\n    void Dispose();\n}\nclass C\n{\n    static void Test<T>(T t, IMyDisposable s) where T : IMyDisposable, allows ref struct\n    {\n        using (t) // Error, the pattern is not recognized\n        {\n        }\n\n        using (s) // Error, the pattern is not recognized\n        {\n        }\n    }\n}\n```\n\n### `await using` statement\n\nCurrently language disallows using ref structs as resources in `await using` statement. The same limitation will be\napplied to a type parameter that `allows ref struct`.\n\nThere is a proposal to lift general restrictions around usage of ref structs in async methods - https://github.com/dotnet/csharplang/pull/7994.\nThe remainder of the section describes behavior after the general limitation for `await using` statement will be lifted, if/when that will happen. \n\nAn `await using` statement will recognize and use implementation of `IAsyncDisposable` interface when resource is a ref struct.\n```csharp\nref struct S2 : IAsyncDisposable\n{\n    ValueTask IAsyncDisposable.DisposeAsync()\n    {\n    }\n}\n\nclass C\n{\n    static async Task Main()\n    {\n        await using (new S2())\n        {\n        } // S2.IAsyncDisposable.DisposeAsync\n    }\n}\n```\n\nNote that preference is given to a `DisposeAsync` method that implements the pattern, and only if one is not found, `IAsyncDisposable`\nimplementation is used.\n\nA pattern `DisposeAsync` method will be recognized on a type parameter that `allows ref struct` as it is recognized on\ntype parameters without that constraint today.\n\n```csharp\ninterface IMyAsyncDisposable\n{\n    ValueTask DisposeAsync();\n}\n\nclass C\n{\n    static async Task Test<T>() where T : IMyAsyncDisposable, new(), allows ref struct\n    {\n        await using (new T())\n        {\n        } // IMyAsyncDisposable.DisposeAsync\n    }\n}\n```\n\nA `using` statement will recognize and use implementation of `IAsyncDisposable` interface when resource is a type parameter that \n`allows ref struct`, the process of looking for `DisposeAsync` pattern method failed, and `IAsyncDisposable` is in type parameter's effective interfaces set.\n```csharp\ninterface IMyAsyncDisposable1\n{\n    ValueTask DisposeAsync();\n}\n\ninterface IMyAsyncDisposable2\n{\n    ValueTask DisposeAsync();\n}\n\nclass C\n{\n    static async Task Test<T>() where T : IMyAsyncDisposable1, IMyAsyncDisposable2, IAsyncDisposable, new(), allows ref struct\n    {\n        await using (new T())\n        {\n            System.Console.Write(123);\n        } // IAsyncDisposable.DisposeAsync\n    }\n}\n```\n\n### `foreach` statement\n\nThe https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/statements.md#1295-the-foreach-statement section should be updated accordingly\nto incorporate the following.\n\nA `foreach` statement will recognize and use implementation of ```IEnumerable<T>```/```IEnumerable``` interface when collection is a ref struct.\n```csharp\nref struct S : IEnumerable<int>\n{\n    IEnumerator<int> IEnumerable<int>.GetEnumerator() {...}\n    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {...}\n}\n\nclass C\n{\n    static void Main()\n    {\n        foreach (var i in new S()) // IEnumerable<int>.GetEnumerator\n        {\n        }\n    }\n}\n```\n\nA pattern `GetEnumerator` method will be recognized on a type parameter that `allows ref struct` as it is recognized on\ntype parameters without that constraint today.\n\n```csharp\ninterface IMyEnumerable<T>\n{\n    IEnumerator<T> GetEnumerator();\n}\n\nclass C\n{\n    static void Test<T>(T t) where T : IMyEnumerable<int>, allows ref struct\n    {\n        foreach (var i in t) // IMyEnumerable<int>.GetEnumerator\n        {\n        }\n    }\n}\n```\n\nA `foreach` statement will recognize and use implementation of ```IEnumerable<T>```/```IEnumerable``` interface when collection is a type parameter that \n`allows ref struct`, the process of looking for `GetEnumerator` pattern method failed, and ```IEnumerable<T>```/```IEnumerable``` is in type parameter's effective interfaces set.\n```csharp\ninterface IMyEnumerable1<T>\n{\n    IEnumerator<int> GetEnumerator();\n}\n\ninterface IMyEnumerable2<T>\n{\n    IEnumerator<int> GetEnumerator();\n}\n\nclass C\n{\n    static void Test<T>(T t) where T : IMyEnumerable1<int>, IMyEnumerable2<int>, IEnumerable<int>, allows ref struct\n    {\n        foreach (var i in t) // IEnumerable<int>.GetEnumerator\n        {\n        }\n    }\n}\n```\n\nAn `enumerator` pattern will be recognized on a type parameter that `allows ref struct` as it is recognized on\ntype parameters without that constraint today.\n\n```csharp\ninterface IGetEnumerator<TEnumerator> where TEnumerator : allows ref struct \n{\n    TEnumerator GetEnumerator();\n}\n\nclass C\n{\n    static void Test1<TEnumerable, TEnumerator>(TEnumerable t)\n        where TEnumerable : IGetEnumerator<TEnumerator>, allows ref struct\n        where TEnumerator : IEnumerator, IDisposable, allows ref struct \n    {\n        foreach (var i in t) // IEnumerator.MoveNext/Current\n        {\n        }\n    }\n\n    static void Test2<TEnumerable, TEnumerator>(TEnumerable t)\n        where TEnumerable : IGetEnumerator<TEnumerator>, allows ref struct\n        where TEnumerator : IEnumerator<int>, allows ref struct \n    {\n        foreach (var i in t) // IEnumerator<int>.MoveNext/Current\n        {\n        }\n    }\n\n    static void Test3<TEnumerable, TEnumerator>(TEnumerable t)\n        where TEnumerable : IGetEnumerator<TEnumerator>, allows ref struct\n        where TEnumerator : IMyEnumerator<int>, allows ref struct \n    {\n        foreach (var i in t) // IMyEnumerator<int>.MoveNext/Current\n        {\n        }\n    }\n}\n\ninterface IMyEnumerator<T> : System.IDisposable\n{\n    T Current {get;}\n    bool MoveNext();\n}\n```\n\nA `foreach` statement will recognize and use implementation of `IDisposable` interface when enumerator is a ref struct.\n```csharp\nstruct S1\n{\n    public S2 GetEnumerator()\n    {\n        return new S2();\n    }\n}\n\nref struct S2 : System.IDisposable\n{\n    public int Current {...}\n    public bool MoveNext() {...}\n    void System.IDisposable.Dispose() {...}\n}\n\nclass C\n{\n    static void Main()\n    {\n        foreach (var i in new S1())\n        {\n        } // S2.System.IDisposable.Dispose()\n    }\n}\n```\n\nNote that preference is given to a `Dispose` method that implements the pattern, and only if one is not found, `IDisposable`\nimplementation is used.\n\nA `foreach` statement will recognize and use implementation of `IDisposable` interface when enumerator is a type parameter that \n`allows ref struct` and `IDisposable` is in its effective interfaces set.\n```csharp\ninterface ICustomEnumerator\n{\n    int Current {get;}\n    bool MoveNext();\n}\n\ninterface IGetEnumerator<TEnumerator> where TEnumerator : allows ref struct \n{\n    TEnumerator GetEnumerator();\n}\n\nclass C\n{\n    static void Test<TEnumerable, TEnumerator>(TEnumerable t)\n        where TEnumerable : IGetEnumerator<TEnumerator>\n        where TEnumerator : ICustomEnumerator, System.IDisposable, allows ref struct \n    {\n        foreach (var i in t)\n        {\n        } // System.IDisposable.Dispose()\n    }\n}\n```\n\nNote that a pattern `Dispose` method will not be recognized on a type parameter that `allows ref struct` because\nan interface (and this is the only place where we could possibly look for a pattern) is not a ref struct.\nAlso, since runtime doesn't provide a way to check whether at runtime a type parameter that `allows ref struct`\nimplements `IDisposable` interface, a type parameter enumerator that `allows ref struct` will be disallowed,\nunless `IDisposable` is in its effective interfaces set.\n```csharp\ninterface ICustomEnumerator\n{\n    int Current {get;}\n    bool MoveNext();\n}\n\ninterface IMyDisposable\n{\n    void Dispose();\n}\n\ninterface IGetEnumerator<TEnumerator> where TEnumerator : allows ref struct \n{\n    TEnumerator GetEnumerator();\n}\n\nclass C\n{\n    static void Test<TEnumerable, TEnumerator>(TEnumerable t)\n        where TEnumerable : IGetEnumerator<TEnumerator>\n        where TEnumerator : ICustomEnumerator, IMyDisposable, allows ref struct \n    {\n        // error CS9507: foreach statement cannot operate on enumerators of type 'TEnumerator'\n        //               because it is a type parameter that allows ref struct and\n        //               it is not known at compile time to implement IDisposable.\n        foreach (var i in t)\n        {\n        }\n    }\n}\n```\n\n### `await foreach` statement\n\nThe https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/statements.md#1295-the-foreach-statement section should be updated accordingly\nto incorporate the following.\n\nAn `await foreach` statement will recognize and use implementation of ```IAsyncEnumerable<T>``` interface when collection is a ref struct.\n```csharp\nref struct S : IAsyncEnumerable<int>\n{\n    IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(CancellationToken token) {...}\n}\n\nclass C\n{\n    static async Task Main()\n    {\n        await foreach (var i in new S()) // S.IAsyncEnumerable<int>.GetAsyncEnumerator\n        {\n        }\n    }\n}\n```\n\nA pattern `GetAsyncEnumerator` method will be recognized on a type parameter that `allows ref struct` as it is recognized on\ntype parameters without that constraint today.\n\n```csharp\ninterface IMyAsyncEnumerable<T>\n{\n    IAsyncEnumerator<int> GetAsyncEnumerator(CancellationToken cancellationToken = default);\n}\n\nclass C\n{\n    static async Task Test<T>() where T : IMyAsyncEnumerable<int>, allows ref struct\n    {\n        await foreach (var i in default(T)) // IMyAsyncEnumerable<int>.GetAsyncEnumerator\n        {\n        }\n    }\n}\n```\n\nAn `await foreach` statement will recognize and use implementation of ```IAsyncEnumerable<T>``` interface when collection is a type parameter that \n`allows ref struct`, the process of looking for `GetAsyncEnumerator` pattern method failed, and ```IAsyncEnumerable<T>``` is in type parameter's effective interfaces set.\n```csharp\ninterface IMyAsyncEnumerable1<T>\n{\n    IAsyncEnumerator<int> GetAsyncEnumerator(CancellationToken cancellationToken = default);\n}\n\ninterface IMyAsyncEnumerable2<T>\n{\n    IAsyncEnumerator<int> GetAsyncEnumerator(CancellationToken cancellationToken = default);\n}\n\nclass C\n{\n    static async Task Test<T>() where T : IMyAsyncEnumerable1<int>, IMyAsyncEnumerable2<int>, IAsyncEnumerable<int>, allows ref struct\n    {\n        await foreach (var i in default(T)) // IAsyncEnumerable<int>.GetAsyncEnumerator\n        {\n            System.Console.Write(i);\n        }\n    }\n}\n```\n\nAn `await foreach` statement will continue disallowing a ref struct enumerator and a type parameter enumerator that `allows ref struct`. The reason\nis the fact that the enumerator must be preserved across `await MoveNextAsync()` calls.\n\n### Delegate type for the anonymous function or method group\n\nThe https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/lambda-improvements.md#delegate-types section states:\n>The compiler may allow more signatures to bind to `System.Action<>` and `System.Func<>` types in the future (if `ref struct` types are allowed type arguments for instance).\n\n`Action<>` and `Func<>` types with `allows ref struct` constraints on their type parameters will be used in more scenarios\ninvolving ref struct types in the delegate's signature.\n\nIf target runtime supports `allows ref struct` constraints, generic anonymous delegate types will include `allows ref struct` constraint for\ntheir type parameters. This will enable substitution of those type parameters with ref struct types and other type parameters with\n `allows ref struct` constraint.\n\n### Inline arrays\n\nThe https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/inline-arrays.md#detailed-design section states:\n>Language will provide a type-safe/ref-safe way for accessing elements of inline array types. The access will be span based.\n>This limits support to inline array types with element types that can be used as a type argument.\n\nWhen span types are changed to support spans of ref structs, the limitation should be lifted for inline arrays of ref structs. \n\n## Soundness\n\nWe would like to verify the soundness of both the `ref struct` anti-constraint in particular and the anti-constraint concept in general. To do so we'd like to take advantage of the existing soundness proofs provided for the C# type system. This task is made easier by defining a new language that is similar to C#, but more regular in construction. We will verify the safety of that model, and then specify a sound translation to this language. Because this new language is centered around constraints, we'll call this language \"constraint-C#\".\n\nThe primary ref struct safety invariant that must be preserved is that variables of ref struct type must not appear on the heap. We can encode this restriction via a constraint. Because constraints permit substitution, not forbid it, we will technically define the inverse constraint: `heap`. The `heap` constraint specifies that a type may appear on the heap. In \"constraint-C#\" all types satisfy the `heap` constraint except for ref-structs. Moreover, all existing type parameters in C# will be lowered to type parameters with the `heap` constraint in \"constraint-C#\".\n\nNow, assuming that existing C# is safe, we can transfer the C# ref-struct rules to \"constraint-C#\".\n\n  1. Fields of classes cannot have a ref-struct type.\n  2. Static fields cannot have a ref-struct type.\n  3. Variables of ref-struct type cannot be converted to non-ref structs.\n  4. Variables of ref-struct type cannot be substituted as type arguments.\n  5. Variables of ref-struct type cannot implement interfaces.\n\nThe new rules apply to the `heap` constraint:\n\n  1. Fields of classes must have types that satisfy the `heap` constraint.\n  2. Static fields must have types that satisfy the `heap` constraint.\n  3. Types with the `heap` constraint have only the identity conversion.\n  4. Variables of ref-struct type can only be substituted for type parameters without the `heap` constraint.\n  5. Ref-struct types may only implement interfaces without default-interface-members.\n\nRules (4) and (5) are slightly altered. Note that rule (4) does not need to be transferred exactly because we have a notion of type parameters without the `heap` contraint. Rule (5) is complicated. Implementing interfaces is not universally unsound, but default interface methods imply a receiver of interface type, which is a non-value type and violates rule (3). Thus, default-interface-members are disallowed.\n\nWith these rules, \"constraint-C#\" is ref-struct safe, supports type substitution, and supports interface implementation. The next step is to translate the language defined in this proposal, which we may call \"allow-C#\", into \"constraint-C#\". Fortunately, this is trivial. The lowering is a straightforward syntactic transformation. The syntax `where T : allows ref struct` in \"allow-C#\" is equivalent in \"constraint-C#\" to no constraint and the absence of \"allow clauses\" is equivalent to the `heap` constraint. Since the abstract semantics and typing are equivalent, \"allow-C#\" is also sound.\n\nThere is one last property which we might consider: whether all typed terms in C# are also typed in \"constraint-C#\". In other words, we want to know if, for all terms `t` in C#, whether the corresponding term `t'` after lowering to \"constraint-C#\" is well-typed. This is not a soundness constraint -- making terms ill-typed in our target language would never allow unsafety -- rather, it concerns backwards-compatibility. If we decide to use the typing of \"constraint-C#\" to validate \"allow-C#\", we would like to confirm that we are not making any existing C# code illegal.\n\nSince all C# terms start as valid \"constraint-C#\" terms, we can validate preservation by examining each of our new \"constraint-C#\" restrictions. First, the addition of the `heap` constraint. Since all type parameters in C# would acquire the `heap` constraint, all existing terms must satisfy said constraint. This is true for all concrete types except ref structs, which is appropriate since ref structs may not appear as type arguments today. It is also true for all type parameters, since they would all themselves acquire the `heap` constraint. Moreover, since the `heap` constraint is a valid combination with all other constraints, this would not present any problems. Rules (1-5) would not present any problems since they directly correspond to existing C# rules, or are relaxations thereof. Therefore, all typeable terms in C# should be typeable in \"constraint-C#\" and we should not introduce any typing breaking changes.\n\n## Open Issues\n\n### Anti-Constraint syntax\n\n**Decision**: use `where T: allows ref struct`\n\nThis proposal chose to expose the `ref struct` anti-constraint by augmenting the existing `where` syntax to include `allows ref struct`. This both succinctly describes the feature and is also expandable to include other anti-constraints in the future like pointers. There are other solutions considered that are worth discussing.\n\nThe first is simply picking another syntax to use within the `where` clause. Other proposed options included:\n\n- `~ref struct`: the `~` serves as a marker that the syntax that follows is an anti-constraint.\n- `include ref struct`: using `includes` instead of `allows`\n\n```csharp\nvoid M<T>(T p)\n    where T : IDisposable, ~ref struct\n{\n    p.Dispose();\n}\n```\n\nThe second is to use a new clause entirely to make it clear that what follows is expanding the set of allowed types. Proponents of this feel that using syntax within `where` could lead to confusion when reading. The initial proposal used the following syntax: `allow T: ref struct`:\n\n```csharp\nvoid M<T>(T p)\n    where T : IDisposable\n    allow T : ref struct\n{\n    p.Dispose();\n}\n```\n\nThe `where T: allows ref struct` syntax had a slightly stronger preference in LDM discussions.\n\n### Co and contra variance\n\n**Decision**: no new issues\n\nTo be maximally useful type parameters that are `allows ref struct` must be compatible with generic variance. Specifically it must be legal for a parameter to be both co/contravariant and also `allows ref struct`. Lacking that they would not be usable in many of the most popular `delegate` and `interface` types in .NET like `Func<T>`, `Action<T>`, `IEnumerable<T>`, etc ...\n\nAfter discussion it was concluded this is a non-issue. The `allows ref struct` constraint is just another way that `struct` can be used as generic arguments. Just as a normal `struct` argument removes the variance of an API so will a `ref struct`. \n\n### Auto-applying to delegate members\n\n**Decision**: do not auto-apply\n\nFor many generic `delegate` members the language could automatically apply `allows ref struct` as it's purely an upside change. Consider that for `Func<> / Action<>` style delegates and most interface definitions there is no downside to expanding to allowing `ref struct`. The language can outline rules where it is safe to automatically apply this anti-constraint. This removes the manual process and would speed up the adoption of this feature.\n\nThis auto application of `allows ref struct` poses a few problems though. The first is in multi-targeted scenarios. Code would compile in one target framework but fail in another and there is no syntactic indicator of why the APIs should behave differently.\n\n```csharp\n// Works in net9.0 but fails in all other TF\nFunc<Span<char>> func;\n```\n\nThis is likely to lead to customer confusion and looking at changes in `Func<T>` in the `net9.0` source wouldn't give customers any clue as to what changed.\n\nThe other issue is that very subtle changes in code can cause _spooky action at a distance_ problems. Consider the following code:\n\n```csharp\ninterface I1<T>\n{\n}\n```\n\nThis interface would be eligible for auto-application of `allows ref struct`. If a developer comes around later though and adds a default interface method then suddenly it would not be and it would break any consumers that had already created invocations like `I1<Span<char>>`. This is a very subtle change that would be hard to track down.\n\n### Binary breaking change\n\nAdding `allows ref struct` to an existing API is not a source breaking change. It is purely expanding the set of allowed types for an API. Need to track down if this is a binary breaking change or not. Unclear if updating the attributes of a generic parameter constitute a binary breaking change.\n\n### Warn on DIM invocation\n\nShould the compiler warn on the following invocation of `M` as it creates the opportunity for a runtime exception?\n\n```csharp\ninterface I1\n{\n    // Virtual method with default implementation\n    void M() { }\n}\n\n// Invocation of a virtual instance method with default implementation in a generic method that has the `allows ref struct`\n// anti-constraint\nvoid M<T>(T p)\n    where T : allows ref struct, I1\n{\n    p.M(); // Warn?\n}\n```\n\nThis, however, could be noisy and not very helpful in majority of scenarios. C# will require ref structs to implement all virtual APIs.\nTherefore, assuming that other players follow the same rule, the only situation when this might cause an exception is when the method\nis added after the fact. The author of the consuming code often has no knowledge of all these details and often has no control over \nref structs that will be consumed by the code. Therefore, the only action the author can really take is to suppress the warning.\n\n## Considerations\n\n### Runtime support\n\nThis feature requires several pieces of support from the runtime / libraries team:\n\n- Preventing default interface methods from applying to `ref struct`\n- API in `System.Reflection.Metadata` for encoding the `gpAcceptByRefLike` value\n- Support for generic parameters being a `ref struct`\n\nMost of this support is likely already in place. The general `ref struct` as generic parameter support is already implemented as described [here][byref-like-generics]. It's possible the DIM implementation already account for `ref struct`. But each of these items needs to be tracked down.\n\n### API versioning\n\n#### allows ref struct anti-constraint\n\nThe `allows ref struct` anti-constraint can be safely applied to a large number of generic definitions that do not have implementations. That means most delegates, interfaces and `abstract` methods can safely apply `allows ref struct` to their parameters. These are just API definitions without implementations and hence expanding the set of allowed types is only going to result in errors if they're used as type arguments where `ref struct` are not allowed.\n\nAPI owners can rely on a simple rule of \"if it compiles, it's safe\". The compiler will error on any unsafe uses of `allows ref struct`, just as it does for other `ref struct` uses.\n\nAt the same time though there are versioning considerations API authors should consider. Essentially API owners should avoid adding `allows ref struct` to type parameters where the owning type / member may change in the future to be incompatible with `allows ref struct`. For example:\n\n- An `abstract` method which may later change to a `virtual` method\n- An `abstract` type which may later add implementations\n\nIn such cases an API author should be careful about adding `allows ref struct` unless they are certain the type / member evolution will not using `T` in a way that breaks `ref struct` rules.\n\nRemoving the `allows ref struct` anti-constraint is always a breaking change: source and binary.\n\n#### Default Interface Methods\n\nAPI authors need to be aware that adding DIMS will break `ref struct` implementors until they are recompiled. This is similar to [existing DIM behavior][dim-diamond] where by adding a DIM to an interface will break existing implementations until they are recompiled. That means API authors need to consider the likelihood of `ref struct` implementations when adding DIMs.\n\nThere are three code components that are needed to create this situation:\n\n```csharp\ninterface I1\n{\n    // 1. The addition of a DIM method to an _existing_ interface\n    void M() { }\n}\n\n// 2. A ref struct implementing the interface but not explicitly defining the DIM \n// method\nref struct S : I1 { }\n\n// 3. The invocation of the DIM method in a generic method that has the `allows ref struct`\n// anti-constraint\nvoid M<T>(T p)\n    where T : allows ref struct, I1\n{\n    p.M();\n}\n```\n\nAll of three of these components are needed to create this particular issue. Further at least (1) and (2) must be in different assemblies. If they were in the same assembly then a compilation error would occur.\n\n#### UnscopedRef\n\nAdding or removing `[UnscopedRef]` from `interface` members is a source breaking change (and potentially creating runtime issues). The attribute should be applied when defining an interface member and not added or removed later.\n\n### Span&lt;Span&lt;T&gt;&gt;\n\nThis combination of features does not allow for constructs such as `Span<Span<T>>`. This is made a bit clearer by looking at the definition of `Span<T>`:\n\n```csharp\nreadonly ref struct Span<T>\n{\n    public readonly ref T _data;\n    public readonly int _length;\n\n    public Span(T[] array) { ... }\n\n    public static implicit operator Span<T>(T[]? array) { }\n \n    public static implicit operator Span<T>(ArraySegment<T> segment) { }\n}\n```\n\nIf this type definition were to include `allows ref struct` then all `T` instances in the definition would need be treated as if they were potentially a `ref struct` type. That presents two classes of problems.\n\nThe first is for APIs like `Span(T[] array)` and the implicit operators the `T` cannot be a `ref struct`: it's either used as an array element or as generic parameter which cannot be `allows ref struct`. There are a handful of public APIs on `Span<T>` that have uses of `T` that cannot be compatible with a `ref struct`. These are public API that cannot be deleted and hence must be rationalized by the language. The most likely path forward is the compiler will special case `Span<T>` and issue an error code ever bound to one of these APIs when the argument for `T` is _potentially_ a `ref struct`.\n\nThe second is that the language does not support `ref` fields that are `ref struct`. There is a [design proposal][ref-struct-ref-fields] for allowing that feature. It's unclear if that will be accepted into the language or if it's expressive enough to handle the full set of scenarios around `Span<T>`.\n\nBoth of these issues are beyond the scope of this proposal.\n\n### UnscopedRef Implementation Logic\n\nThe rationale behind the `[UnscopedRef]` rules for interface implementation is easiest to understand when visualizing the `this` parameter as an explicit, rather than implicit, argument to the methods. Consider for example the following `struct` where `this` is visualized as an implicit parameter (similar to how Python handles it):\n\n```csharp\nstruct S\n{\n    public void M(scoped ref S this) { }\n}\n```\n\nThe `[UnscopedRef]` on an interface member is specifying that `this` lacks `scoped` for lifetime purposes at the call site. Allowing `[UnscopedRef]` to be ommitted on the implementing member is effectively allowing a parameter that is `ref T` to be implemented by a parameter that is `scoped ref T`. The language already allows this:\n\n```csharp\ninterface I1\n{\n    void M(ref Span<char> span);\n}\n\nstruct S : I1\n{\n    public void M(scoped ref Span<char> span) { }\n}\n```\n\n## Related Items\n\nRelated Items:\n\n- https://github.com/dotnet/csharplang/issues/7608\n- https://github.com/dotnet/csharplang/pull/7555\n- https://github.com/dotnet/runtime/blob/main/docs/design/features/byreflike-generics.md\n- https://github.com/dotnet/runtime/pull/67783\n- https://github.com/dotnet/runtime/issues/27229#issuecomment-1537274804\n- https://github.com/dotnet/runtime/issues/68002\n\n[ref-struct-ref-fields]: https://github.com/dotnet/csharplang/blob/main/proposals/expand-ref.md\n[ref-struct-generics]: #ref-struct-generic-parameters\n[byref-like-generics]: https://github.com/dotnet/runtime/blob/main/docs/design/features/byreflike-generics.md\n[dim-diamond]: https://github.com/dotnet/csharplang/blob/main/meetings/2018/LDM-2018-10-17.md#diamond-inheritance\n[unscoped-ref-impl]: #unscopedref-implementation-logic\n[warn-DIM]: #warn-on-dim-invocation\n"
  },
  {
    "path": "proposals/csharp-13.0/ref-unsafe-in-iterators-async.md",
    "content": "# Allow ref and unsafe in iterators and async\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/1331>\n\n## Summary\n[summary]: #summary\n\nUnify behavior between iterators and async methods. Specifically:\n\n- Allow `ref`/`ref struct` locals and `unsafe` blocks in iterators and async methods\n  provided they are used in code segments without any `yield` or `await`.\n- Warn about `yield` inside `lock`.\n\n## Motivation\n[motivation]: #motivation\n\nIt is not necessary to disallow `ref`/`ref struct` locals and `unsafe` blocks in async/iterator methods\nif they are not used across `yield` or `await`, because they do not need to be hoisted.\n\n```cs\nasync void M()\n{\n    await ...;\n    ref int x = ...; // error previously, proposed to be allowed\n    x.ToString();\n    await ...;\n    // x.ToString(); // still error\n}\n```\n\n## Breaking changes\n[break]: #breaking-changes\n\nThere are no breaking changes in the language specification,\nbut there is one breaking change in the Roslyn implementation (due to a spec violation).\n\nRoslyn violates the part of the spec which states that iterators introduce a safe context ([§13.3.1][blocks-general]).\nFor example, if there is an `unsafe class` with an iterator method which contains a local function\nthen that local function inherits the unsafe context from the class,\nalthough it should have been in a safe context per the spec due to the iterator method.\nIn fact, the whole iterator method inherited the unsafe context in Roslyn,\nit was just disallowed to use any unsafe constructs in iterators.\nIn `LangVersion >= 13`, iterators will correctly introduce a safe context\nbecause we want to allow unsafe constructs in iterators.\n\n```cs\nunsafe class C // unsafe context\n{\n    System.Collections.Generic.IEnumerable<int> M() // an iterator\n    {\n        yield return 1;\n        local();\n        async void local()\n        {\n            int* p = null; // allowed in C# 12; error in C# 13 (breaking change)\n            await Task.Yield(); // error in C# 12, allowed in C# 13\n        }\n    }\n}\n```\n\nNote:\n- The break can be worked around simply by adding the `unsafe` modifier to the local function.\n- This does not affect lambdas as they \"inherit\" the \"iterator context\"\n  and therefore it was impossible to use unsafe constructs inside them.\n\n## Detailed design\n[design]: #detailed-design\n\nThe following changes are tied to LangVersion, i.e., C# 12 and lower will continue to disallow\nref-like locals and `unsafe` blocks in async methods and iterators,\nand C# 13 will lift these restrictions as described below.\nHowever, spec clarifications which match the existing Roslyn implementation should hold across all LangVersions.\n\n[§13.3.1 Blocks > General][blocks-general]:\n\n> A *block* that contains one or more `yield` statements ([§13.15][yield-statement]) is called an iterator block,\n> **even if those `yield` statements are contained only indirectly in nested blocks (excluding nested lambdas and local functions).**\n>\n> [...]\n>\n> ~~It is a compile-time error for an iterator block to contain an unsafe context ([§23.2][unsafe-contexts]).\n> An iterator block always defines a safe context, even when its declaration is nested in an unsafe context.~~\n> **The iterator block used to implement an iterator ([§15.14][iterators])\n> always defines a safe context, even when the iterator declaration is nested in an unsafe context.**\n\nFrom this spec it also follows:\n- If an iterator declaration is marked with the `unsafe` modifier, the signature is in an unsafe scope\n  but the iterator block used to implement that iterator still defines a safe scope.\n- The `set` accessor of an iterator property or indexer (i.e., its `get` accessor is implemented via an iterator block)\n  \"inherits\" its safe/unsafe scope from the declaration.\n- This does not affect partial declarations without implementation as they are only signatures and cannot have an iterator body.\n\nNote that in C# 12 it is an error to have an iterator method marked with the `unsafe` modifier,\nbut that is allowed in C# 13 due to the spec change.\n\nFor example:\n\n```cs\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\nclass A : System.Attribute { }\nunsafe partial class C1\n{ // unsafe context\n    [/* unsafe context */ A]\n    IEnumerable<int> M1(\n        /* unsafe context */ int*[] x)\n    { // safe context (this is the iterator block implementing the iterator)\n        yield return 1;\n    }\n    IEnumerable<int> M2()\n    { // safe context (this is the iterator block implementing the iterator)\n        unsafe\n        { // unsafe context\n            { // unsafe context (this is *not* the block implementing the iterator)\n                yield return 1; // error: `yield return` in unsafe context\n            }\n        }\n    }\n    [/* unsafe context */ A]\n    unsafe IEnumerable<int> M3(\n        /* unsafe context */ int*[] x)\n    { // safe context\n        yield return 1;\n    }\n    [/* unsafe context */ A]\n    IEnumerable<int> this[\n        /* unsafe context */ int*[] x]\n    { // unsafe context\n        get\n        { // safe context\n            yield return 1;\n        }\n        set { /* unsafe context */ }\n    }\n    [/* unsafe context */ A]\n    unsafe IEnumerable<int> this[\n        /* unsafe context */ long*[] x]\n    { // unsafe context (the iterator declaration is unsafe)\n        get\n        { // safe context\n            yield return 1;\n        }\n        set { /* unsafe context */ }\n    }\n    IEnumerable<int> M4()\n    {\n        yield return 1;\n        var lam1 = async () =>\n        { // safe context\n          // spec violation: in Roslyn, this is an unsafe context in LangVersion 12 and lower\n            await Task.Yield(); // error in C# 12, allowed in C# 13\n            int* p = null; // error in both C# 12 and C# 13 (unsafe in iterator)\n        };\n        unsafe\n        {\n            var lam2 = () =>\n            { // unsafe context, lambda cannot be an iterator\n                yield return 1; // error: yield cannot be used in lambda\n            };\n        }\n        async void local()\n        { // safe context\n          // spec violation: in Roslyn, this is an unsafe context in LangVersion 12 and lower\n            await Task.Yield(); // error in C# 12, allowed in C# 13\n            int* p = null; // allowed in C# 12, error in C# 13 (breaking change in Roslyn)\n        }\n        local();\n    }\n    public partial IEnumerable<int> M5() // unsafe context (inherits from parent)\n    { // safe context\n        yield return 1;\n    }\n}\npartial class C1\n{\n    public partial IEnumerable<int> M5(); // safe context (inherits from parent)\n}\nclass C2\n{ // safe context\n    [/* unsafe context */ A]\n    unsafe IEnumerable<int> M(\n        /* unsafe context */ int*[] x)\n    { // safe context\n        yield return 1;\n    }\n    unsafe IEnumerable<int> this[\n        /* unsafe context */ int*[] x]\n    { // unsafe context\n        get\n        { // safe context\n            yield return 1;\n        }\n        set { /* unsafe context */ }\n    }\n}\n```\n\n[§13.6.2.4 Ref local variable declarations][ref-local]:\n\n> ~~It is a compile-time error to declare a ref local variable, or a variable of a `ref struct` type,\n> within a method declared with the *method_modifier* `async`, or within an iterator ([§15.14][iterators]).~~\n> **It is a compile-time error to declare and use (even implicitly in compiler-synthesized code)\n> a ref local variable, or a variable of a `ref struct` type across `await` expressions or `yield return` statements.\n> More precisely, the error is driven by the following mechanism:\n> after an `await` expression ([§12.9.8][await-expressions]) or a `yield return` statement ([§13.15][yield-statement]),\n> all ref local variables and variables of a `ref struct` type in scope\n> are considered definitely unassigned ([§9.4][definite-assignment]).**\n\nNote that this error is not downgraded to a warning in `unsafe` contexts like [some other ref safety errors][ref-safety-unsafe-warnings].\nThat is because these ref-like locals cannot be manipulated in `unsafe` contexts without relying on implementation details of how the state machine rewrite works,\nhence this error falls outside the boundaries of what we want to downgrade to warnings in `unsafe` contexts.\n\n[§15.14.1 Iterators > General][iterators]:\n\n> When a function member is implemented using an iterator block,\n> it is a compile-time error for the formal parameter list of the function member to specify any\n> `in`, `ref readonly`, `out`, or `ref` parameters, or an parameter of a `ref struct` type **or a pointer type**.\n\nNo change in the spec is needed to allow `unsafe` blocks which do not contain `await`s in async methods,\nbecause the spec has never disallowed `unsafe` blocks in async methods.\nHowever, the spec should have always disallowed `await` inside `unsafe` blocks\n(it had already disallowed `yield` in `unsafe` in [§13.3.1][blocks-general] as cited above),\nso we propose the following change to the spec:\n\n[§15.15.1 Async Functions > General][async-funcs-general]:\n\n> It is a compile-time error for the formal parameter list of an async function to specify\n> any `in`, `out`, or `ref` parameters, or any parameter of a `ref struct` type.\n>\n> **It is a compile-time error for an unsafe context ([§23.2][unsafe-contexts]) to contain\n> an `await` expression ([§12.9.8][await-expressions]) or a `yield return` statement ([§13.15][yield-statement]).**\n\n[§23.6.5 The address-of operator][address-of]:\n\n> **A compile-time error will be reported for taking an address of a local or a parameter in an iterator.**\n\nCurrently, taking an address of a local or a parameter in an async method is [a warning in C# 12 warning wave][async-pointer].\n\n---\n\nNote that more constructs can work thanks to `ref` allowed inside segments without `await` and `yield` in async/iterator methods\neven though no spec change is needed specifically for them as it all falls out from the aforementioned spec changes:\n\n```cs\nusing System.Threading.Tasks;\n\nref struct R\n{\n    public ref int Current { get { ... }};\n    public bool MoveNext() => false;\n    public void Dispose() { }\n}\nclass C\n{\n    public R GetEnumerator() => new R();\n    async void M()\n    {\n        await Task.Yield();\n        using (new R()) { } // allowed under this proposal\n        foreach (var x in new C()) { } // allowed under this proposal\n        foreach (ref int x in new C()) { } // allowed under this proposal\n        lock (new System.Threading.Lock()) { } // allowed under this proposal\n        await Task.Yield();\n    }\n}\n```\n\n## Alternatives\n[alternatives]: #alternatives\n\n- `ref`/`ref struct` locals could be allowed only in blocks ([§13.3.1][blocks-general])\n  which do not contain `await`/`yield`:\n\n  ```cs\n  // error always since `x` is declared/used both before and after `await`\n  {\n      ref int x = ...;\n      await Task.Yield();\n      x.ToString();\n  }\n  // allowed as proposed (`x` does not need to be hoisted as it is not used after `await`)\n  // but alternatively could be an error (`await` in the same block)\n  {\n      ref int x = ...;\n      x.ToString();\n      await Task.Yield();\n  }\n  ```\n\n- `yield return` inside `lock` could be an error (like `await` inside `lock` is) or a warning-wave warning,\n  but that would be a breaking change: https://github.com/dotnet/roslyn/issues/72443.\n  Note that [the new `Lock`-object-based `lock`][lock-object] reports compile-time errors for `yield return`s in its body,\n  because such `lock` statement is equivalent to a `using` on a `ref struct` which disallows `yield return`s in its body.\n\n- Variables inside async or iterator methods should not be \"fixed\" but rather \"moveable\"\n  if they need to be hoisted to fields of the state machine (similarly to captured variables).\n  Note that this is a pre-existing bug in the spec independent of the rest of the proposal\n  because `unsafe` blocks inside `async` methods were always allowed.\n  There is currently [a warning for this in C# 12 warning wave][async-pointer]\n  and making it an error would be a breaking change.\n\n  [§23.4 Fixed and moveable variables][fixed-vars]:\n  \n  > In precise terms, a fixed variable is one of the following:\n  >\n  > - A variable resulting from a *simple_name* ([§12.8.4][simple-names]) that refers to a local variable, value parameter, or parameter array,\n  > unless the variable is captured by an anonymous function ([§12.19.6.2][captured-vars]) **or a local function ([§13.6.4][local-funcs])\n  > or the variable needs to be hoisted as part of an async ([§15.15][async-funcs]) or an iterator ([§15.14][iterators]) method**.\n  > - [...]\n\n  - Currently, we have an existing warning in C# 12 warning wave for address-of in async methods and a proposed error for address-of in iterators\n    reported for LangVersion 13+ (does not need to be reported in earlier versions because it was impossible to use unsafe code in iterators).\n    We could relax both of these to apply only to variables that are actually hoisted, not all locals and parameters. \n\n  - It could be possible to use `fixed` to get the address of a hoisted or captured variable\n    although the fact that those are fields is an implementation detail\n    so in other implementations it might not be possible to use `fixed` on them.\n    Note that we only propose to consider also hoisted variables as \"moveable\",\n    but captured variables were already \"moveable\" and `fixed` was not allowed for them.\n\n- We could allow `await`/`yield` inside `unsafe` except inside `fixed` statements (compiler cannot pin variables across method boundaries).\n  That might result in some unexpected behavior, for example around `stackalloc` as described in the nested bullet point below.\n  Otherwise, hoisting pointers is supported even today in some scenarios (there is an example below related to pointers as arguments),\n  so there should be no other limitations in allowing this.\n\n  - We could disallow the unsafe variant of `stackalloc` in async/iterator methods,\n    because the stack-allocated buffer does not live across `await`/`yield` statements.\n    It does not feel necessary because unsafe code by design does not prevent \"use after free\".\n    Note that we could also allow unsafe `stackalloc` provided it is not used across `await`/`yield`, but\n    that might be difficult to analyze (the resulting pointer can be passed around in any pointer variable).\n    Or we could require it being `fixed` in async/iterator methods. That would *discourage* using it across `await`/`yield`\n    but would not match the semantics of `fixed` because the `stackalloc` expression is not a moveable value.\n    (Note that it would not be *impossible* to use the `stackalloc` result across `await`/`yield` similarly as\n    you can save any `fixed` pointer today into another pointer variable and use it outside the `fixed` block.)\n\n- Iterator and async methods could be allowed to have pointer parameters.\n  They would need to be hoisted, but that should not be a problem as\n  hoisting pointers is supported even today, for example:\n\n  ```cs\n  unsafe public void* M(void* p)\n  {\n      var d = () => p;\n      return d();\n  }\n  ```\n\n- The proposal currently keeps (and extends/clarifies) the pre-existing spec that\n  iterator methods begin a safe context even if they are in an unsafe context.\n  For example, an iterator method is not an unsafe context even if it is defined in a class which has the `unsafe` modifier.\n  Alternatively, we could make iterators \"inherit\" the `unsafe` modifier like other methods do.\n  - Advantage: removes complexity from the spec and implementation.\n  - Advantage: aligns iterators with async methods (one of the motivations of the feature).\n  - Disadvantage: iterators inside unsafe classes could not contain `yield return` statements,\n    such iterators would have to be defined in a separate partial class declaration without the `unsafe` modifier.\n  - Disadvantage: this would be a breaking change in LangVersion=13 (iterators in unsafe classes are allowed in C# 12).\n\n- Instead of an iterator defining a safe context for the body only, the whole signature could be a safe context.\n  That is inconsistent with the rest of the language in that bodies normally do not affect declarations but here\n  a declaration would be either safe or unsafe depending on whether the body is an iterator or not.\n  It would be also a breaking change in LangVersion=13 as in C# 12 iterator signatures are unsafe (they can contain pointer array parameters, for example).\n\n- Applying the `unsafe` modifier to an iterator:\n  - Could affect the body as well as the signature. Such iterators would not be very useful though\n    because their unsafe bodies could not contain `yield return`s, they could have only `yield break`s.\n  - Could be an error in `LangVersion >= 13` as it is in `LangVersion <= 12` because\n    it is not very useful to have an unsafe iterator member as it only allows one to have\n    pointer array parameters or unsafe setters without additional unsafe block.\n    But normal pointer arguments could be allowed in the future.\n\n- Roslyn breaking change:\n  - We could preserve the current behavior (and even modify the spec to match it)\n    for example by introducing the safe context in the iterator method\n    but then reverting to the unsafe context in the local function.\n  - Or we could break all LangVersions, not just 13 and newer.\n  - It is also possible to more drastically simplify the rules by making iterators\n    inherit unsafe context like all other methods do. Discussed above.\n    Could be done across all LangVersions or just for `LangVersion >= 13`.\n\n## Design meetings\n[ldm]: #design-meetings\n\n- [2024-06-03](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-06-03.md): post-implementation review of the speclet\n\n[definite-assignment]: https://github.com/dotnet/csharpstandard/blob/ee38c3fa94375cdac119c9462b604d3a02a5fcd2/standard/variables.md#94-definite-assignment\n[simple-names]: https://github.com/dotnet/csharpstandard/blob/ee38c3fa94375cdac119c9462b604d3a02a5fcd2/standard/expressions.md#1284-simple-names\n[await-expressions]: https://github.com/dotnet/csharpstandard/blob/ee38c3fa94375cdac119c9462b604d3a02a5fcd2/standard/expressions.md#1298-await-expressions\n[captured-vars]: https://github.com/dotnet/csharpstandard/blob/ee38c3fa94375cdac119c9462b604d3a02a5fcd2/standard/expressions.md#121962-captured-outer-variables\n[blocks-general]: https://github.com/dotnet/csharpstandard/blob/ee38c3fa94375cdac119c9462b604d3a02a5fcd2/standard/statements.md#1331-general\n[ref-local]: https://github.com/dotnet/csharpstandard/blob/ee38c3fa94375cdac119c9462b604d3a02a5fcd2/standard/statements.md#13624-ref-local-variable-declarations\n[local-funcs]: https://github.com/dotnet/csharpstandard/blob/d11d5a1a752bff9179f8207e86d63d12782c31ff/standard/statements.md#1364-local-function-declarations\n[lock-statement]: https://github.com/dotnet/csharpstandard/blob/ee38c3fa94375cdac119c9462b604d3a02a5fcd2/standard/statements.md#1313-the-lock-statement\n[using-statement]: https://github.com/dotnet/csharpstandard/blob/ee38c3fa94375cdac119c9462b604d3a02a5fcd2/standard/statements.md#1314-the-using-statement\n[yield-statement]: https://github.com/dotnet/csharpstandard/blob/ee38c3fa94375cdac119c9462b604d3a02a5fcd2/standard/statements.md#1315-the-yield-statement\n[iterators]: https://github.com/dotnet/csharpstandard/blob/ee38c3fa94375cdac119c9462b604d3a02a5fcd2/standard/classes.md#1514-iterators\n[async-funcs]: https://github.com/dotnet/csharpstandard/blob/ee38c3fa94375cdac119c9462b604d3a02a5fcd2/standard/classes.md#1515-async-functions\n[async-funcs-general]: https://github.com/dotnet/csharpstandard/blob/ee38c3fa94375cdac119c9462b604d3a02a5fcd2/standard/classes.md#15151-general\n[unsafe-contexts]: https://github.com/dotnet/csharpstandard/blob/ee38c3fa94375cdac119c9462b604d3a02a5fcd2/standard/unsafe-code.md#232-unsafe-contexts\n[fixed-vars]: https://github.com/dotnet/csharpstandard/blob/ee38c3fa94375cdac119c9462b604d3a02a5fcd2/standard/unsafe-code.md#234-fixed-and-moveable-variables\n[address-of]: https://github.com/dotnet/csharpstandard/blob/ee38c3fa94375cdac119c9462b604d3a02a5fcd2/standard/unsafe-code.md#2365-the-address-of-operator\n[lock-object]: ./lock-object.md\n[ref-safety-unsafe-warnings]: https://github.com/dotnet/csharplang/issues/6476\n[async-pointer]: https://github.com/dotnet/roslyn/pull/66915\n"
  },
  {
    "path": "proposals/csharp-14.0/extension-operators.md",
    "content": "# Extension operators\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\n***Note:*** *Does not cover user-defined implicit and explicit conversion operators, which are not yet designed or planned.*\n\n## Declaration\nLike all extension members, extension operators are declared within an extension block:\n\n``` c#\npublic static class Operators\n{\n    extension<TElement>(TElement[] source) where TElement : INumber<TElement>\n    {\n        public static TElement[] operator *(TElement[] vector, TElement scalar) { ... }\n        public static TElement[] operator *(TElement scalar, TElement[] vector) { ... }\n        public void operator *=(TElement scalar) { ... }\n    }\n}\n```\n\nExtension operator declarations generally follow the rules for non-extension [user-defined operators in the Standard](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/classes.md#1510-operators) as well as the soon-to-be-added [user-defined compound assignment operators](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-14.0/user-defined-compound-assignment.md). \n\nGenerally speaking, the rules pertaining to the *containing type* of the declaration instead apply to the *extended type*. \n\nA static extension operator for the extended type `T` must take at least one parameter of type `S`, where `S` and `T` are identity convertible.\nNote, that, unlike for regular user-defined operators, ```Nullable<T>``` is not a valid type for `S`.\n\nFor operators that require pair-wise declaration, the two declarations are allowed to occur in separate extension blocks for extended types `S` and `T` respectively, as long as `S` and `T` are identity convertible and the extension blocks occur in the same static class.\n\nInstance compound assignment and increment operators are supposed to mutate the instance.\nTherefore, the following restrictions are applied for such extension operators:\n- Receiver type must be known to be either a reference type or a value type. I.e. cannot be an unconstrained type parameter.\n- If receiver type is a value type, the receiver parameter must be a 'ref' parameter.\n- If receiver type is a reference type, the receiver parameter must be a value parameter.\n\nLike other extension members, extension operators cannot use the `abstract`, `virtual`, `override` or `sealed` modifiers.\n\n``` c#\npublic static class Operators\n{\n    extension(int[])\n    {\n        public static int[] operator +(int[] vector, int scalar) { ... }    // OK; parameter and extended type agree\n        public static int operator +(int scalar1, int scalar2) { ... }      // ERROR: extended type not used as parameter type\n        public static bool operator ==(int[] vector1, int[] vector2){ ... } // ERROR: '!=' declaration missing\n        public static bool operator <(int[] vector1, int[] vector2){ ... }  // OK: `>` is declared below\n    }\n    extension(int[])\n    {\n        public static bool operator >(int[] vector1, int[] vector2){ ... }  // OK: `<` is declared above\n    }\n}\n```\n\n## Overload resolution\n\nLike other extension members, extension operators are only considered if no applicable predefined or non-extension user-defined operators were found. The search then proceeds outwards scope by scope, starting with the innermost namespace within which the operator application occurs, until at least one applicable extension operator declaration is found. For compound assignment operators, this involves looking for first user-defined compound assignment operators and then, if none found, non-assignment operators, before moving on to the next scope.\n\nAt each scope, overload resolution works the same as other extension members:\n- The set of operator declarations for the given name (i.e. operator) is determined\n- Type inference is attempted for each, based on operand expressions\n- Declarations that fail type inference are removed\n- Declarations that are not applicable to the operands are removed\n- If there are no remaining candidates, proceed to the enclosing scope (or, if looking for compound-assignment operators, the corresponding simple operator)\n- Applying overload resolution between the candidate, select the unique best candidate, if it exists\n- If no unique best candidate can be found, overload resolution fails with an ambiguity error.\n\nUsing `*` and `*=` declarations above:\n\n``` c#\nint[] numbers = { 1, 2, 3 };\n\nvar i = 2 * 3;       // predefined operator *(int, int)\nvar v = numbers * 4; // extension operator *(int[], int)\nv *= 5;              // extension operator *=(int)\n```\n\n## Extension user-defined conditional logical operators\n\nThe following [restrictions](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12143-user-defined-conditional-)\nare specified for regular user-defined operators:\n\n>When the operands of `&&` or `||` are of types that declare an applicable user-defined `operator &` or `operator |`, both of the following shall be true, where `T` is the type in which the selected operator is declared:\n>\n>- The return type and the type of each parameter of the selected operator shall be `T`. In other words, the operator shall compute the logical AND or the logical OR of two operands of type `T`, and shall return a result of type `T`.\n>- `T` shall contain declarations of `operator true` and `operator false`.\n\nBy analogy, the following restrictions are used for extension operators:\nWhen the operands of `&&` or `||` are of types that declare an applicable user-defined extension `operator &` or\nextension `operator |`, both of the following shall be true:\n\n- The operator shall compute the logical AND or the logical OR of two operands of type `T`, and shall return a result of type `T`.\n- The enclosing static class shall contain declarations of extension `operator true` and extension `operator false` applicable to\n  an instance of type `T`.\n\n For example, these declarations satisfy the restrictions, given that lifted form of `operator &` is used:\n ``` c#\nS1? s11 = new S1();\nS1? s12 = new S1();\n_ = s11 && s12;\n  \npublic static class Extensions\n{\n    extension(S1)\n    {\n        public static S1 operator &(S1 x, S1 y) => x;\n    }\n    extension(S1?)\n    {\n        public static bool operator false(S1? x) => false;\n        public static bool operator true(S1? x) => true;\n    }\n}\n\npublic struct S1\n{}\n```\n\n## Use of extension operators in Linq Expression Trees\n\nWhen an expression utilizing a user-defined operator is used in a lambda that is converted to a Linq Expression tree,\nan expression node that compiler creates includes a `MethodInfo` pointing to the operator method.\n\nFor example:\n``` c#\npublic class C1\n{\n    public static C1 operator +(C1 x, int y) => x;\n}\n\npublic class Program\n{\n    static void Main()\n    {\n        Expression<System.Func<C1, C1>> x = (c1) => c1 + 1;\n    } \n}\n```\n\nuses [Expression.Add(Expression left, Expression right, MethodInfo? method)](https://learn.microsoft.com/dotnet/api/system.linq.expressions.expression.add#system-linq-expressions-expression-add(system-linq-expressions-expression-system-linq-expressions-expression-system-reflection-methodinfo)) factory.\n\nWhen the operator is an extension operator, a MethodInfo referring to the corresponding implementation method in the enclosing class will be used.\n\nNote, `&&`/`||` operators utilizing extension operators will be blocked in Linq Expression trees due to limitations of\nfactory methods. The [issue](https://github.com/dotnet/runtime/issues/115674) illustrates the failure mode for the factory\nmethods.  \n\n## Open design questions\n\n### [Resolved] Should extension operators on Nullable of extended type be disallowed?\n\nIt is allowed to declare a regular user-defined operator on Nullable of containing type.\nSuch operator can be consumed on an instance of containing type, as well as on an \ninstance of Nullable of containing type.\n``` c#\nS1? s1 = new S1();\ns1 = +s1; // Ok\ns1 = +s1.Value; // Ok\n\nstruct S1\n{\n    public static S1? operator +(S1? x) => x;\n}\n```\n\nSimilarly, it is allowed to declare an extension user-defined operator on Nullable of extended type. \nHowever, such operator can be consumed only on an instance of extended type. Consumption on an \ninstance of Nullable of extended type is not allowed because a conversion from ```Nullable<T>``` to \n```T``` is not a valid extension receiver type conversion.\n``` c#\nS1? s1 = new S1();\ns1 = +s1; // Error: no matching operator\ns1 = +s1.Value; // Ok\n\nstruct S1;\n\npublic static class Extensions\n{\n    extension(S1)\n    {\n        public static S1? operator +(S1? x) => x;\n    }\n}\n```\n\nThis makes such operator declarations somewhat useless, they won't ever be consumed on `null` instances,\nand, therefore, no real reason to have nullable parameter types. Should declarations like this be disallowed?\n\n[Resolution:](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-06-04.md#should-extension-operators-on-nullable-of-extended-type-be-disallowed)\n>Restriction accepted: extension operators can only be declared for the type being extended in an extension block, not for the nullable underlying type.\n\n### [Resolved] Applicability of bitwise operators during evaluation of user-defined conditional logical operators\n\nLanguage adds extra [restrictions](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12143-user-defined-conditional-)\nto bitwise operators suitable for evaluation of user-defined conditional logical operators:\n\n>When the operands of `&&` or `||` are of types that declare an applicable user-defined `operator &` or `operator |`, both of the following shall be true, where `T` is the type in which the selected operator is declared:\n>\n>- The return type and the type of each parameter of the selected operator shall be `T`. In other words, the operator shall compute the logical AND or the logical OR of two operands of type `T`, and shall return a result of type `T`.\n>- `T` shall contain declarations of `operator true` and `operator false`.\n\nHowever, the specification isn't clear whether the restriction should eliminate a candidate bitwise operator\nas inapplicable when the requirements are not satisfied, or the requirements should be applied to the best\nbitwise operator after overload resolution among the candidates is complete. Right now, compiler \nimplements the latter, which leads to the following behavior:\n``` c#\n S1 s1 = new S1();\n S2 s2 = new S2();\n        \n // error CS0217: In order to be applicable as a short circuit operator\n //               a user-defined logical operator ('S1.operator &(S1, S2)')\n //               must have the same return type and parameter types\n _ = s1 && s2;\n \nstruct S1\n{\n    // If this operator is removed, candidate from S2 is successfully used\n    public static S2 operator &(S1 x, S2 y) => y;\n}\n\nstruct S2\n{\n    public static S2 operator &(S2 x, S2 y) => y;\n    public static bool operator true(S2 x) => false;\n    public static bool operator false(S2 x) => true;\n    \n    public static implicit operator S2(S1 x) => default;\n}\n```\n\nHere is another example that could benefit from the former approach:\n``` C#\nS1 s1 = new S1();\nS2 s2 = new S2();\n\n// error CS0034: Operator '&&' is ambiguous on operands of type 'S1' and 'S2'\n_ = s1 && s2;\n\nstruct S1\n{\n    // If this operator is removed, candidate from S2 is successfully used\n    public static S1 operator &(S1 x, S1 y) => y;\n    public static implicit operator S1(S2 x) => default;\n}\n\nstruct S2\n{\n    public static S2 operator &(S2 x, S2 y) => y;\n    public static bool operator true(S2 x) => false;\n    public static bool operator false(S2 x) => true;\n    \n    public static implicit operator S2(S1 x) => default;\n}\n```\n\nThe precise applicability rules are even more important for extension operators. Extension operators are considered\nonly when there are no applicable regular user-defined operators. And, only when there are no applicable\nextension operators in the given extension scope, candidates from next extension scope are considered. \n\nHence the question, should the restrictions be part of a candidate applicability check during overload \nresolution rather than a post validation after the overload resolution is complete?\n\n[Resolution:](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-06-04.md#applicability-of-bitwise-operators-during-evaluation-of-user-defined-conditional-logical-operators)\n> We're not doing anything here for now. Rejected until we see use cases.\n\n### [Resolved] Extension user-defined conditional logical operators\n\nThe following [restrictions](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12143-user-defined-conditional-)\nare specified for regular user-defined operators:\n\n>When the operands of `&&` or `||` are of types that declare an applicable user-defined `operator &` or `operator |`, both of the following shall be true, where `T` is the type in which the selected operator is declared:\n>\n>- The return type and the type of each parameter of the selected operator shall be `T`. In other words, the operator shall compute the logical AND or the logical OR of two operands of type `T`, and shall return a result of type `T`.\n>- `T` shall contain declarations of `operator true` and `operator false`.\n\nBy analogy, the following restrictions are proposed for extension operators:\nWhen the operands of `&&` or `||` are of types that declare an applicable user-defined extension `operator &` or\nextension `operator |`, both of the following shall be true:\n\n- The operator shall compute the logical AND or the logical OR of two operands of type `T`, and shall return a result of type `T`.\n- The enclosing static class shall contain declarations of extension `operator true` and extension `operator false` applicable to\n  an instance of type `T`.\n\n For example, these declarations satisfy the restrictions, given that lifted form of `operator &` is used:\n ``` c#\nS1? s11 = new S1();\nS1? s12 = new S1();\n_ = s11 && s12;\n  \npublic static class Extensions\n{\n    extension(S1)\n    {\n        public static S1 operator &(S1 x, S1 y) => x;\n    }\n    extension(S1?)\n    {\n        public static bool operator false(S1? x) => false;\n        public static bool operator true(S1? x) => true;\n    }\n}\n\npublic struct S1\n{}\n``` \n\n[Resolution:](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-06-04.md#extension-user-defined-conditional-logical-operators)\n> Proposal accepted.\n\n### [Resolved] Extension compound assignment operators\n\nCompound assignment operators are instance operators and are supposed to mutate the instance.\nTherefore, the following restrictions are proposed for extension compound assignment operators:\n- Receiver type must be known to be either a reference type or a value type. I.e. cannot be an unconstrained type parameter.\n- If receiver type is a value type, the receiver parameter must be a 'ref' parameter.\n- If receiver type is a reference type, the receiver parameter must be a value parameter.\n\n[Resolution:](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-06-04.md#extension-compound-assignment-operators)\n> Restriction adopted, we can look at it again in the future when there is more bandwidth.\n\n### [Resolved] Dynamic evaluation\n\nExtension operators are not used by dynamic evaluation. This might lead to compile time errors.\nFor example:\n``` c#\ndynamic s1 = new object();\nvar s2 = new object();\n\n// error CS7083: Expression must be implicitly convertible to Boolean or its type 'object' must define operator 'false'.\n_ = s2 && s1;\n\npublic static class Extensions\n{\n    extension(object)\n    {\n        public static object operator &(object x, object y) => x;\n        public static bool operator false(object x) => false;\n        public static bool operator true(object x) => throw null;\n    }\n}\n```\n\nAn attempt to do a compile time optimization using non-dynamic static type of 's2' ignores true/false extensions.\nOne might say this is desirable because runtime binder wouldn't be able to use them as well.\n\n[Resolution:](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-06-11.md#dynamic-resolution-of-operator-truefalse)\nRestriction accepted. Extension operator `true`/`false` are not used for `dynamic` `&&` or `||`.\n\n### [Resolved] Use of extension operators in Linq Expression Trees\n\nWhen an expression utilizing a user-defined operator is used in a lambda that is converted to a Linq Expression tree,\nan expression node that compiler creates includes a `MethodInfo` pointing to the operator method.\n\nFor example:\n``` c#\npublic class C1\n{\n    public static C1 operator +(C1 x, int y) => x;\n}\n\npublic class Program\n{\n    static void Main()\n    {\n        Expression<System.Func<C1, C1>> x = (c1) => c1 + 1;\n    } \n}\n```\n\nuses [Expression.Add(Expression left, Expression right, MethodInfo? method)](https://learn.microsoft.com/dotnet/api/system.linq.expressions.expression.add#system-linq-expressions-expression-add(system-linq-expressions-expression-system-linq-expressions-expression-system-reflection-methodinfo)) factory.\n\nThe question is what should we do when the operator is an extension operator.\nWe cannot use a MethodInfo referencing the extension operator itself because IL is not allowed\nto refer to any declaration from an extension block.\n\nProposal: Use MethodInfo referring to a corresponding implementation method in the enclosing class.\n          A quick smoke test confirmed that an expression tree like that can be compiled, executed,\n          and execution calls the implementation method.\n\n[Resolution:](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-06-11.md#extension-operators-in-linq-expression-trees)\nAccepted.\n\n### [Resolved] Is the rule \"an extension operator may not have the same signature as a predefined operator.\" worth having as specified?\n\nIf our goal is to prevent users from declaring an operator that would be shadowed by a predefined operator,\nthen it doesn't look like the rule as specified achieves it.\nFor example, the rule is going to prevent a user from defining ```operator –(int x)``` and ```operator –(long x)```,\nbut it is not going to prevent declaration of ```operator –(byte x)```. However, in the following code it would be\nshadowed by predefined ```operator –(int x)```.\n``` c#\nbyte x = 0;\nvar y = -x;\n```\n\nPerhaps the rule should be changed to something like the following instead?\n> If operator overload resolution with an argument list consisting of expressions with types\n> matching declared parameters in the same order against the set of predefined operators of\n> the same kind succeeds, then the signature of declared extension operator is considered illegal. \n\nFor ```operator –(byte x)```, we would perform an operator overload resolution with an argument list\n[byte] against predefined unary `-` operators. It would succeed with predefined ```operator –(int x)``` as \nthe result. Therefore, an error would be reported for extension ```operator –(byte x)```.\n\nFor ```operator +(byte x, byte y)```, we would perform an operator overload resolution with an argument list\n[byte, byte] against predefined binary `+` operators. It would succeed with predefined ```operator +(int x, int y)``` as \nthe result. Therefore, an error would be reported for extension ```operator +(byte x, byte y)```.\n\nWhen considering signatures of instance compound assignment operators, the receiver parameter is going to\ncontribute to the argument list. For ```extension(byte).operator+=(short)```, we would perform an operator overload\nresolution with an argument list [byte, short] against predefined binary `+` operators. It would succeed with\npredefined ```operator +(int x, int y)``` as the result. Therefore, an error would be reported for\n```extension(byte).operator+=(short)```.\n\n[Resolution:](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-06-11.md#built-in-operator-protection-rules)\nRule is abandoned. We will not have built-in errors or warnings here.\n\n## Design meetings\n\n- https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-06-04.md\n- https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-06-11.md\n"
  },
  {
    "path": "proposals/csharp-14.0/extensions.md",
    "content": "# Extension members\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: https://github.com/dotnet/csharplang/issues/8697\n\n## Declaration\n\n### Syntax\n\n```antlr\nclass_body\n    : '{' class_member_declaration* '}' ';'?\n    | ';'\n    ;\n\nclass_member_declaration\n    : constant_declaration\n    | field_declaration\n    | method_declaration\n    | property_declaration\n    | event_declaration\n    | indexer_declaration\n    | operator_declaration\n    | constructor_declaration\n    | finalizer_declaration\n    | static_constructor_declaration\n    | type_declaration\n    | extension_declaration // add\n    ;\n\nextension_declaration // add\n    : 'extension' type_parameter_list? '(' receiver_parameter ')' type_parameter_constraints_clause* extension_body\n    ;\n\nextension_body // add\n    : '{' extension_member_declaration* '}' ';'?\n    ;\n\nextension_member_declaration // add\n    : method_declaration\n    | property_declaration\n    | operator_declaration\n    ;\n\nreceiver_parameter // add\n    : attributes? parameter_modifiers? type identifier?\n    ;\n```\n\nExtension declarations shall only be declared in non-generic, non-nested static classes.  \nIt is an error for a type to be named `extension`.  \n\n### Scoping rules\n\nThe type parameters and receiver parameter of an extension declaration are in scope within the body of the extension declaration. It is an error to refer to the receiver parameter from within a static member, except within a `nameof` expression. It is an error for members to declare type parameters or parameters (as well as local variables and local functions directly within the member body) with the same name as a type parameter or receiver parameter of the extension declaration.\n\n``` c#\npublic static class E\n{\n    extension<T>(T[] ts)\n    {\n        public bool M1(T t) => ts.Contains(t);        // `T` and `ts` are in scope\n        public static bool M2(T t) => ts.Contains(t); // Error: Cannot refer to `ts` from static context\n        public void M3(int T, string ts) { }          // Error: Cannot reuse names `T` and `ts`\n        public void M4<T, ts>(string s) { }           // Error: Cannot reuse names `T` and `ts`\n    }\n}\n```\n\nIt is not an error for the members themselves to have the same name as the type parameters or receiver parameter of the enclosing extension declaration. Member names are not directly found in a simple name lookup from within the extension declaration; lookup will thus find the type parameter or receiver parameter of that name, rather than the member. \n\nMembers do give rise to static methods being declared directly on the enclosing static class, and those can be found via simple name lookup; however, an extension declaration type parameter or receiver parameter of the same name will be found first.\n\n``` c#\npublic static class E\n{\n    extension<T>(T[] ts)\n    {\n        public void T() { M(ts); } // Generated static method M<T>(T[]) is found\n        public void M() { T(ts); } // Error: T is a type parameter\n    }\n}\n```\n\n### Static classes as extension containers\n\nExtensions are declared inside top-level non-generic static classes, just like extension methods today, \nand can thus coexist with classic extension methods and non-extension static members:\n\n``` c#\npublic static class Enumerable\n{\n    // New extension declaration\n    extension(IEnumerable source) { ... }\n    \n    // Classic extension method\n    public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source) { ... }\n    \n    // Non-extension member\n    public static IEnumerable<int> Range(int start, int count) { ... } \n}\n```\n\n### Extension declarations\n\nAn extension declaration is anonymous, and provides a _receiver specification_ with any associated type parameters and constraints, \nfollowed by a set of extension member declarations. The receiver specification may be in the form of a parameter, \nor - if only static extension members are declared - a type:\n\n``` c#\npublic static class Enumerable\n{\n    extension(IEnumerable source) // extension members for IEnumerable\n    {\n        public bool IsEmpty { get { ... } }\n    }\n    extension<TSource>(IEnumerable<TSource> source) // extension members for IEnumerable<TSource>\n    {\n        public IEnumerable<T> Where(Func<TSource, bool> predicate) { ... }\n        public IEnumerable<TResult> Select<TResult>(Func<TSource, TResult> selector) { ... }\n    }\n    extension<TElement>(IEnumerable<TElement>) // static extension members for IEnumerable<TElement>\n        where TElement : INumber<TElement>\n    {\n        public static IEnumerable<TElement> operator +(IEnumerable<TElement> first, IEnumerable<TElement> second) { ... }\n    }\n}\n```\n\nThe type in the receiver specification is referred to as the _receiver type_ and the parameter name,\nif present, is referred to as the _receiver parameter_.\n\nIf the _receiver parameter_ is named, the _receiver type_ may not be static.  \nThe _receiver parameter_ is not allowed to have modifiers if it is unnamed, and \nit is only allowed to have the refness modifiers listed below and `scoped` otherwise.  \nThe _receiver parameter_ bears the same restrictions as the first parameter of a classic extension method.  \nThe `[EnumeratorCancellation]` attribute is ignored if it is placed on the _receiver parameter_.  \n\n### Extension members\n\nExtension member declarations are syntactically identical to corresponding instance and static members\nin class and struct declarations (with the exception of constructors). \nInstance members refer to the receiver with the receiver parameter name:\n\n``` c#\npublic static class Enumerable\n{\n    extension(IEnumerable source)\n    {\n        // 'source' refers to receiver\n        public bool IsEmpty => !source.GetEnumerator().MoveNext();\n    }\n}\n```\n\nIt is an error to specify an instance extension member\nif the enclosing extension declaration does not specify a receiver parameter:\n\n``` c#\npublic static class Enumerable\n{\n    extension(IEnumerable) // No parameter name\n    {\n        public bool IsEmpty => true; // Error: instance extension member not allowed\n    }\n}\n```\n\nIt is an error to specify the following modifiers on a member of an extension declaration:\n`abstract`, `virtual`, `override`, `new`, `sealed`, `partial`, and `protected` (and related accessibility modifiers).  \nIt is an error to specify the `readonly` modifier on a member of an extension declaration.  \nProperties in extension declarations may not have `init` accessors.  \nThe instance members are disallowed if the _receiver parameter_ is unnamed.  \n\nAll members shall have names that differ from the name of the static enclosing class and the name of the extended type if it has one.\n\nIt is an error to decorate an extension member with the `[ModuleInitializer]` attribute.\n\n### Refness\n\nBy default the receiver is passed to instance extension members by value, just like other parameters. \nHowever, an extension declaration receiver in parameter form can specify `ref`, `ref readonly` and `in`, \nas long as the receiver type is known to be a value type. \n\n### Nullability and attributes\n\nReceiver types can be or contain nullable reference types, and receiver specifications that are in the form of parameters can specify attributes:\n\n``` c#\npublic static class NullableExtensions\n{\n    extension(string? text)\n    {\n        public string AsNotNull => text is null ? \"\" : text;\n    }\n    extension([NotNullWhen(false)] string? text)\n    {\n        public bool IsNullOrEmpty => text is null or [];\n    }\n    extension<T> ([NotNull] T t) where T : class?\n    {\n        public void ThrowIfNull() => ArgumentNullException.ThrowIfNull(t);\n    }\n}\n```\n\n### Compatibility with classic extension methods\n\nInstance extension methods generate artifacts that match those produced by classic extension methods.\n\nSpecifically the generated static method has the attributes, modifiers and name of the declared extension method, \nas well as type parameter list, parameter list and constraints list concatenated from the extension declaration and the method declaration in that order:\n\n``` c#\npublic static class Enumerable\n{\n    extension<TSource>(IEnumerable<TSource> source) // Generate compatible extension methods\n    {\n        public IEnumerable<TSource> Where(Func<TSource, bool> predicate) { ... }\n        public IEnumerable<TSource> Select<TResult>(Func<TSource, TResult> selector)  { ... }\n    }\n}\n```\n\nGenerates:\n\n``` c#\n[Extension]\npublic static class Enumerable\n{\n    [Extension]\n    public static IEnumerable<TSource> Where<TSource>(IEnumerable<TSource> source, Func<TSource, bool> predicate) { ... }\n\n    [Extension]\n    public static IEnumerable<TSource> Select<TSource, TResult>(IEnumerable<TSource> source, Func<TSource, TResult> selector)  { ... }\n}\n```\n\n### Operators\n\nAlthough extension operators have explicit operand types, they still need to be declared within an extension declaration:\n\n``` c#\npublic static class Enumerable\n{\n    extension<TElement>(IEnumerable<TElement>) where TElement : INumber<TElement>\n    {\n        public static IEnumerable<TElement> operator *(IEnumerable<TElement> vector, TElement scalar) { ... }\n        public static IEnumerable<TElement> operator *(TElement scalar, IEnumerable<TElement> vector) { ... }\n    }\n}\n```\n\nThis allows type parameters to be declared and inferred, and is analogous to how a regular user-defined operator must be declared within one of its operand types.\n\n## Checking\n\n__Inferrability:__ For each non-method extension member, all the type parameters of its extension block must be used in the combined set of parameters\nfrom the extension and the member.\n\n__Uniqueness:__ Within a given enclosing static class, the set of extension member declarations with the same receiver type \n(modulo identity conversion and type parameter name substitution) are treated as a single declaration space \nsimilar to the members within a class or struct declaration, and are subject to the same \n[rules about uniqueness](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/classes.md#153-class-members).\n\n``` c#\npublic static class MyExtensions\n{\n    extension<T1>(IEnumerable<int>) // Error! T1 not inferrable\n    {\n        ...\n    }\n    extension<T2>(IEnumerable<T2>)\n    {\n        public bool IsEmpty { get ... }\n    }\n    extension<T3>(IEnumerable<T3>?)\n    {\n        public bool IsEmpty { get ... } // Error! Duplicate declaration\n    }\n}\n```\n\nThe application of this uniqueness rule includes classic extension methods within the same static class.\nFor the purposes of comparison with methods within extension declarations, the `this` parameter is treated\nas a receiver specification along with any type parameters mentioned in that receiver type,\nand the remaining type parameters and method parameters are used for the method signature:\n\n``` c#\npublic static class Enumerable\n{\n    public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source) { ... }\n    \n    extension(IEnumerable source) \n    {\n        IEnumerable<TResult> Cast<TResult>() { ... } // Error! Duplicate declaration\n    }\n}\n```\n\n## Consumption\n\nWhen an extension member lookup is attempted, all extension declarations within static classes that are `using`-imported contribute their members as candidates,\nregardless of receiver type. Only as part of resolution are candidates with incompatible receiver types discarded.  \nA full generic type inference is attempted between the type of the arguments (including the actual receiver) and any type parameters (combining those in the extension declaration and in the extension member declaration).  \nWhen explicit type arguments are provided, they are used to substitute the type parameters of the extension declaration and the extension member declaration.\n\n``` c#\nstring[] strings = ...;\n\nvar query = strings.Select(s => s.Length); // extension invocation\nvar query2 = strings.Select<string, int>(s => s.Length); // ... with explicit full set of type arguments\n\nvar query3 = Enumerable.Select(strings, s => s.Length); // static method invocation\nvar query4 = Enumerable.Where<string, int>(strings, s => s.Length); // ... with explicit full set of type arguments\n \npublic static class Enumerable\n{\n    extension<TSource>(IEnumerable<TSource> source)\n    {\n        public IEnumerable<TResult> Select<TResult>(Func<T, TResult> predicate) { ... }\n    }\n}\n```\n\nSimilarly to classic extension methods, the emitted implementation methods can be invoked statically.  \nThis allows the compiler to disambiguate between extension members with the same name and arity.  \n\n```csharp\nobject.M(); // ambiguous\nE1.M();\n\nnew object().M2(); // ambiguous\nE1.M2(new object());\n\n_ = _new object().P; // ambiguous\n_ = E1.get_P(new object());\n\nstatic class E1\n{\n    extension(object)\n    {\n        public static void M() { }\n        public void M2() { }\n        public int P => 42;\n    }\n}\n\nstatic class E2\n{\n    extension(object)\n    {\n        public static void M() { }\n        public void M2() { }\n        public int P => 42;\n    }\n}\n```\n\nStatic extension methods will be resolved like instance extension methods (we will consider an extra argument of the receiver type).  \nExtension properties will be resolved like extension methods, with a single parameter (the receiver parameter) and a single argument (the actual receiver value).  \n\n### `using static` directives\n\nA **using_static_directive** makes members of extension blocks in the type declaration available for extension access.  \n\n```cs\nusing static N.E;\n\nnew object().M();\nobject.M2();\n\n_ = new object().Property;\n_ = object.Property2;\n\nC c = null;\n_ = c + c;\nc += 1;\n\nnamespace N\n{\n    static class E\n    {\n        extension(object o)\n        {\n            public void M() { }\n            public static void M2() { }\n            public int Property => 0;\n            public static int Property2 => 0;\n        }\n\n        extension(C c)\n        {\n            public static C operator +(C c1, C c2) => throw null;\n            public void operator +=(int i) => throw null;\n        }\n    }\n}\n\nclass C { } \n```\n\nAs before, the accessible static members (except extension methods) contained directly in the declaration of the given type can be referenced directly.  \nThis means that implementation methods (except those that are extension methods) can be used directly as static methods:\n\n```cs\nusing static E;\n\nM();\nSystem.Console.Write(get_P());\nset_P(43);\n_ = op_Addition(0, 0);\n_ = new object() + new object();\n\nstatic class E\n{\n    extension(object)\n    {\n        public static void M() { }\n        public static int P { get => 42; set { } }\n        public static object operator +(object o1, object o2) { return o1; }\n    }\n}\n```\n\nA **using_static_directive** still does not import extension methods directly as static methods, so the implementation method for non-static extension methods cannot be invoked directly as a static method.  \n```cs\nusing static E;\n\nM(1); // error: The name 'M' does not exist in the current context\n\nstatic class E\n{\n    extension(int i)\n    {\n        public void M() { }\n    }\n}\n```\n\n### OverloadResolutionPriorityAttribute\n\nExtension members within an enclosing static class are subject to prioritization according to ORPA values. The enclosing static\nclass is considered the \"containing type\" which ORPA rules consider.  \nAny ORPA attribute present on an extension property is copied onto the implementation methods for the property's accessors,\nso that the prioritization is respected when those accessors are used via disambiguation syntax.  \n\n### Entry points\n\nMethods of extension blocks do not qualify as entry point candidates (see \"7.1 Application startup\").\nNote: the implementation method may still be a candidate.  \n\n## Lowering\n\nThe lowering strategy for extension declarations is not a language level decision. \nHowever, beyond implementing the language semantics it must satisfy certain requirements:\n\n- The format of generated types, members and metadata should be clearly specified in all cases so that other compilers can consume and generate it.\n- The generated artifacts should be stable, in the sense that reasonable later modifications should not break consumers who compiled against earlier versions.\n\nThese requirements need more refinement as implementation progresses, and may need to be compromised in corner cases in order to allow for a reasonable implementation approach.\n\n### Metadata for declarations\n\n#### Goals\n\nThe design below allows:\n- roundtripping of extension declaration symbols through metadata (full and reference assemblies),\n- stable references to extension members (xml docs), \n- local determination of emitted names (helpful for EnC),\n- public API tracking.  \n\nFor xml docs, the docID for an extension member is the docID for the extension member in metadata. For example, the docID used in `cref=\"Extension.extension(object).M(int)\"`\nis `M:Extension.<>E__ExtensionGroupingTypeNameForObject.M(System.Int32)` and that docID is stable across re-compilations and re-orderings of extension blocks. Ideally, it would also remain\nstable when constraints on the extension block change, but we didn't find a design that would achieve that without detrimental effect on language design for member conflicts.\n\nFor EnC, it is useful to know locally (just by looking at a modified extension member) where the updated extension member is emitted in metadata.  \n\nFor public API tracking, more stable names reduce noise. But technically the extension grouping type names should not come into play in such scenarios. When looking at extension member `M`,\nit doesn't matter what is the name of the extension grouping type, what matters is the signature of the extension block it belongs to. The public API signature should not be seen as\n`Extension.<>E__ExtensionGroupingTypeNameForObject.M(System.Int32)` but rather as `Extension.extension(object).M(int)`. In other words, extension members should be seen as having two sets of\ntype parameters and two sets of parameters.\n\n#### Overview\n\nExtension blocks are grouped by their CLR-level signature. Each CLR equivalency group is emitted as an **extension grouping type** with a content-based name.\nExtension blocks within a CLR equivalency group are then sub-grouped by C# equivalency. Each C# equivalency group is emitted as an **extension marker type** with a content-based name, nested in its corresponding extension grouping type.\nAn extension marker type contains a single **extension marker method** which encodes an extension parameter.\nThe extension marker method with its containing extension marker type encode the signature of an extension block with full fidelity.\nDeclaration of each extension member is emitted in the right extension grouping type, refers back to an extension marker type by its name via an attribute, and is accompanied by a top-level static **implementation method** with a modified signature.    \n\nHere's a schematized overview of metadata encoding:\n```\n[Extension]\nstatic class EnclosingStaticClass\n{\n    [Extension]\n    public sealed class ExtensionGroupingType1 // has type parameters with minimal constraints sufficient to keep extension member declarations below valid\n    {\n        public static class ExtensionMarkerType1 // has re-declared type parameters with full fidelity of C# constraints\n        {\n            public static void <Extension>$(... extension parameter ...) // extension marker method\n        }\n        ... ExtensionMarkerType2, etc ...\n\n        ... extension members for ExtensionGroupingType1, each points to its corresponding extension marker type ...\n    }\n\n    ... ExtensionGroupingType2, etc ...\n\n    ... implementation methods ...\n}\n```\n\nThe enclosing static class is emitted with an `[Extension]` attribute.  \n\n\n### CLR-level signature vs. C#-level signature\n\nThe CLR-level signature of an extension block results from:\n- normalizing type parameter names to `T0`, `T1`, etc ...\n- removing attributes\n- erasing the parameter name\n- erasing parameter modifiers (like `ref`, `in`, `scoped`, ...)\n- erasing tuple names\n- erasing nullability annotations\n- erasing `notnull` constraints\n\nNote: other constraints are preserved, such as `new()`, `struct`, `class`, `allows ref struct`, `unmanaged`, and type constraints.\n\n#### Extension grouping types\n\nAn extension grouping type is emitted to metadata for each set of extension blocks in source with a the same CLR-level signature.  \n- Its name is unspeakable and determined based on the contents of the CLR-level signature. More details below.  \n- Its type parameters have normalized names (`T0`, `T1`, ...) and have no attributes.  \n- It is public and sealed.\n- It is marked with the `specialname` flag and an `[Extension]` attribute.  \n\nThe content-based name of the extension grouping type is based on the CLR-level signature and includes the following:\n- The fully qualified CLR name of the type of the extension parameter.\n    - Referenced type parameter names will be normalized to `T0`, `T1`, etc ... based on the order they appear in the type declaration.\n    - The fully qualified name will not include the containing assembly. It is common for types to be moved between assemblies and that should not break the xml doc references.\n- Constraints of type parameters will be included and sorted such that reordering them in source code does not change the name. Specifically:\n    - Type parameter constraints will be listed in declaration order. The constraints for the Nth type parameter will occur before the Nth+1 type parameter.\n    - Type constraints will be sorted by comparing the full names ordinally.\n    - Non-type constraints are ordered deterministically and are handled so as to avoid any ambiguity or collision with type constraints.\n- Since this does not include attributes, it intentionally ignores C#-isms like tuple names, nullability, etc ...\n\nNote: The name is guaranteed to remain stable across re-compilations, re-orderings and changes of C#-isms (ie. that don't affect the CLR-level signature).   \n\n#### Extension marker types\n\nThe marker type re-declares the type parameters of its containing grouping type (an extension grouping type) to get full fidelity of the C# view of extension blocks.\n\nAn extension marker type is emitted to metadata for each set of extension blocks in source with a the same C#-level signature.  \n- Its name is unspeakable and determined based on the contents of the C#-level signature of the extension block. More details below.  \n- It redeclares the type parameters for its containing grouping type to be those declared in source (including name and attributes).\n- It is public and static.\n- It is marked with the `specialname` flag.  \n\nThe content-based name of the extension marker type is based on the following:\n- The names of type parameters will be included in the order they appear in the extension declaration\n- The attributes of type parameters will be included and sorted such that reordering them in source code does not change the name.\n- Constraints of type parameters will be included and sorted such that reordering them in source code does not change the name.\n- The fully qualified C# name of the extended type\n    - This will include items like nullable annotations, tuple names, etc ... \n    - The fully qualified name will not include the containing assembly\n- The name of the extension parameter\n- The modifiers of the extension parameter (`ref`, `ref readonly`, `scoped`, ...) in a deterministic order\n- The fully qualified name and attribute arguments for any attributes applied to the extension parameter in a deterministic order\n\nNote: The name is guaranteed to remain stable across re-compilation and re-orderings.  \nNote: extension marker types and extension marker methods are emitted as part of reference assemblies.  \n\n#### Extension marker method\n\nThe purpose of the marker method is to encode the extension parameter of the extension block. \nBecause it is a member of the extension marker type, it can refer to the re-declared type parameters of the extension marker type.\n\nEach extension marker type contains a single method, the extension marker method.\n- It is static, non-generic, void-returning, and is called `<Extension>$`.  \n- Its single parameter has the attributes, refness, type and name from the extension parameter.  \n  If the extension parameter doesn't specify a name, then the parameter name is empty.  \n- It is marked with the `specialname` flag.\n\nAccessibility of the marker method will be the least restrictive accessibility among corresponding declared\nextension members, `private` is used if none are declared.\n\n#### Extension members\n\nMethod/property declarations in an extension block in source are represented as members of the extension grouping type in metadata.  \n- The signatures of the original methods are maintained (including attributes), but their bodies are replaced with `throw NotImplementedException()`.  \n- Those should not be referenced in IL.  \n- Methods, properties and their accessors are marked with `[ExtensionMarkerName(\"...\")]` referring to the name of the extension marker type corresponding to the extension block for that member.  \n\n#### Implementation methods\n\nThe method bodies for method/property declarations in an extension block in source are emitted \nas static implementation methods in the top-level static class.  \n- An implementation method has the same name as the original method.  \n- It has type parameters derived from the extension block prepended to the type parameters of the original method (including attributes).  \n- It has the same accessibility and attributes as the original method.  \n- If it implements a static method, it has the same parameters and return type. \n- It if implements an instance method, it has a prepended parameter to the signature of the original method. \n  This parameter's attributes, refness, type, and name are derived from the extension parameter declared in the relevant extension block.\n- The parameters in implementation methods refer to type parameters owned by implementation method, instead of those of an extension block.  \n- If the original member is an instance ordinary method, the implementation method is marked with an `[Extension]` attribute.\n\n#### ExtensionMarkerName attribute\n\nThe `ExtensionMarkerNameAttribute` type is for compiler use only - it is not permitted in source. The type declaration is synthesized by the compiler if not already included in the compilation.\n\n```csharp\nnamespace System.Runtime.CompilerServices;\n\n[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)]\npublic sealed class ExtensionMarkerNameAttribute : Attribute\n{\n    public ExtensionMarkerNameAttribute(string name)\n        => Name = name;\n\n    public string Name { get; }\n}\n```\n\nNote: Although some attribute targets are included for future-proofing (extension nested types, extension fields, extension events), AttributeTargets.Constructor is not included as extension constructors would not be constructors.\n\n#### Example\n\nNote: we use simplified content-based names for the example, for readability.\nNote: since C# cannot represent type parameter re-declaration, the code representing metadata is not valid C# code.\n\nHere's an example illustrating how grouping works, without members:\n\n```\nclass E\n{\n    extension<T>(IEnumerable<T> source)\n    {\n        ... member in extension<T>(IEnumerable<T> source)\n    }\n\n    extension<U>(ref IEnumerable<U?> p)\n    {\n        ... member in extension<U>(ref IEnumerable<U?> p)\n    }\n\n    extension<T>(IEnumerable<U> source)\n        where T : IEquatable<U>\n    {\n        ... member in extension<T>(IEnumerable<U> source) where T : IEquatable<U>\n    }\n}\n```\nis emitted as\n```\n[Extension]\nclass E\n{\n    [Extension, SpecialName]\n    public sealed class <>E__ContentName_For_IEnumerable_T<T0>\n    {\n        [SpecialName]\n        public static class <>E__ContentName1 // note: re-declares type parameter T0 as T\n        {\n            [SpecialName]\n            public static void <Extension>$(IEnumerable<T> source) { }\n        }\n\n        [SpecialName]\n        public static class <>E__ContentName2 // note: re-declares type parameter T0 as U\n        {\n            [SpecialName]\n            public static void <Extension>$(ref IEnumerable<U?> p) { }\n        }\n\n        [ExtensionMarkerName(\"<>E__ContentName1\")]\n        ... member in extension<T>(IEnumerable<T> source)\n\n        [ExtensionMarkerName(\"<>E__ContentName2\")]\n        ... member in extension<U>(ref IEnumerable<U?> p)\n    }\n\n    [Extension, SpecialName]\n    public sealed class <>ContentName_For_IEnumerable_T_With_Constraint<T0>\n       where T0 : IEquatable<T0>\n    {\n        [SpecialName]\n        public static class <>E__ContentName3 // note: re-declares type parameter T0 as U\n        {\n            [SpecialName]\n            public static void <Extension>$(IEnumerable<U> source) { }\n        }\n\n        [ExtensionMarkerName(\"ContentName3\")]\n        public static bool IsPresent(U value) => throw null!;\n    }\n\n    ... implementation methods\n}\n```\n\nHere's an example illustrating how members are emitted:\n```\nstatic class IEnumerableExtensions\n{\n    extension<T>(IEnumerable<T> source) where T : notnull\n    {\n        public void Method() { ... }\n        internal static int Property { get => ...; set => ...; }\n        public int Property2 { get => ...; set => ...; }\n    }\n\n    extension(IAsyncEnumerable<int> values)\n    {\n        public async Task<int> SumAsync() { ... }\n    }\n\n    public static void Method2() { ... }\n}\n```\nis emitted as\n```\n[Extension]\nstatic class IEnumerableExtensions\n{\n    [Extension, SpecialName]\n    public sealed class <>E__ContentName_For_IEnumerable_T<T0>\n    {\n        // Extension marker type is emitted as a nested type and re-declares its type parameters to include C#-isms\n        // In this example, the type parameter `T0` is re-declared as `T` with a `notnull` constraint:\n        // .class <>E__IEnumerableOfT<T>.<>E__ContentName_For_IEnumerable_T_Source\n        // .typeparam T\n        //     .custom instance void NullableAttribute::.ctor(uint8) = (...)\n        [SpecialName]\n        public static class <>E__ContentName_For_IEnumerable_T_Source\n        {\n            [SpecialName]\n            public static <Extension>$(IEnumerable<T> source) => throw null;\n        }\n\n        [ExtensionMarkerName(\"<>E__ContentName_For_IEnumerable_T_Source\")]\n        public void Method() => throw null;\n\n        [ExtensionMarkerName(\"<>E__ContentName_For_IEnumerable_T_Source\")]\n        internal static int Property\n        {\n            [ExtensionMarkerName(\"<>E__ContentName_For_IEnumerable_T_Source\")]\n            get => throw null;\n            [ExtensionMarkerName(\"<>E__ContentName_For_IEnumerable_T_Source\")]\n            set => throw null;\n        }\n\n        [ExtensionMarkerName(\"<>E__ContentName_For_IEnumerable_T_Source\")]\n        public int Property2\n        {\n            [ExtensionMarkerName(\"<>E__ContentName_For_IEnumerable_T_Source\")]\n            get => throw null;\n            [ExtensionMarkerName(\"<>E__ContentName_For_IEnumerable_T_Source\")]\n            set => throw null;\n        }\n    }\n\n    [Extension, SpecialName]\n    public sealed class <>E__ContentName_For_IAsyncEnumerable_Int\n    {\n        [SpecialName]\n        public static class <>E__ContentName_For_IAsyncEnumerable_Int_Values\n        {\n            [SpecialName]\n            public static <Extension>$(IAsyncEnumerable<int> values) => throw null;\n        }\n\n        [ExtensionMarkerName(\"<>E__ContentName_For_IAsyncEnumerable_Int_Values\")]\n        public Task<int> SumAsync() => throw null;\n    }\n\n    // Implementation for Method\n    [Extension]\n    public static void Method<T>(IEnumerable<T> source) { ... }\n\n    // Implementation for Property\n    internal static int get_Property<T>() { ... }\n    internal static void set_Property<T>(int value) { ... }\n\n    // Implementation for Property2\n    public static int get_Property2<T>(IEnumerable<T> source) { ... }\n    public static void set_Property2<T>(IEnumerable<T> source, int value) { ... }\n\n    // Implementation for SumAsync\n    [Extension]\n    public static int SumAsync(IAsyncEnumerable<int> values) { ... }\n\n    public static void Method2() { ... }\n}\n```\n\nWhenever extension members are used in source, we will emit those as reference to implementation methods.\nFor example: an invocation of `enumerableOfInt.Method()` would be emitted as a static call \nto `IEnumerableExtensions.Method<int>(enumerableOfInt)`.  \n\n## XML docs\n\nThe doc comments on the extension block are emitted for the marker type (the DocID for the extension block is `E.<>E__MarkerContentName_For_ExtensionOfT'1` in the example below).  \nThey are allowed to reference the extension parameter and type parameters using `<paramref>` and `<typeparamref>` respectively).  \nNote: you may not document the extension parameter or type parameters (with `<param>` and `<typeparam>`) on an extension member.  \n\nIf two extension blocks are emitted as one marker type, their doc comments are merged as well.\n\nTools consuming the xml docs are responsible for copying the `<param>` and `<typeparam>` from the extension block onto the extension members as appropriate (ie. the parameter information should only be copied for instance members).  \n\nAn `<inheritdoc>` is emitted on implementation methods and it refers to the relevant extension member with a `cref`. For example, the implementation method for a getter refers to the documentation of the extension property. \nIf the extension member has not doc comments, then the `<inheritdoc>` is omitted. \n\nFor extension blocks and extension members, we don't presently warn if:\n- the extension parameter is documented, but the parameters on the extension member aren't\n- or vice-versa\n- or in the equivalent scenarios with undocumented type parameters\n\nFor instance, the following doc comments:\n```\n/// <summary>Summary for E</summary>\nstatic class E\n{\n    /// <summary>Summary for extension block</summary>\n    /// <typeparam name=\"T\">Description for T</typeparam>\n    /// <param name=\"t\">Description for t</param>\n    extension<T>(T t)\n    {\n        /// <summary>Summary for M, which may refer to <paramref name=\"t\"/> and <typeparamref name=\"T\"/></summary>\n        /// <typeparam name=\"U\">Description for U</typeparam>\n        /// <param name=\"u\">Description for u</param>\n        public void M<U>(U u) => throw null!;\n\n        /// <summary>Summary for P</summary>\n        public int P => 0;\n    }\n}\n```\nyield the following xml:\n```\n<?xml version=\"1.0\"?>\n<doc>\n    <assembly>\n        <name>Test</name>\n    </assembly>\n    <members>\n        <member name=\"T:E\">\n            <summary>Summary for E</summary>\n        </member>\n        <member name=\"T:E.&lt;&gt;E__MarkerContentName_For_ExtensionOfT`1\">\n            <summary>Summary for extension block</summary>\n            <typeparam name=\"T\">Description for T</typeparam>\n            <param name=\"t\">Description for t</param>\n        </member>\n        <member name=\"M:E.&lt;&gt;E__MarkerContentName_For_ExtensionOfT`1.M``1(``0)\">\n            <summary>Summary for M, which may refer to <paramref name=\"t\"/> and <typeparamref name=\"T\"/></summary>\n            <typeparam name=\"U\">Description for U</typeparam>\n            <param name=\"u\">Description for u</param>\n        </member>\n        <member name=\"P:E.&lt;&gt;E__MarkerContentName_For_ExtensionOfT`1.P\">\n            <summary>Summary for P</summary>\n        </member>\n        <member name=\"M:E.M``2(``0,``1)\">\n            <inheritdoc cref=\"M:E.&lt;&gt;E__MarkerContentName_For_ExtensionOfT`1.M``1(``0)\"/>\n        </member>\n        <member name=\"M:E.get_P``1(``0)\">\n            <inheritdoc cref=\"P:E.&lt;&gt;E__MarkerContentName_For_ExtensionOfT`1.P\"/>\n        </member>\n    </members>\n</doc>\n```\n\n### CREF references\n\nWe can treat extension blocks like nested types, that can be addressed by their signature (as if it were a method with a single extension parameter).\nExample: `E.extension(ref int).M()`.\n\nBut a cref cannot address an extension block itself. `E.extension(int)` could refer to a method named \"extension\" in type `E`.  \n\n```csharp\nstatic class E\n{\n  extension(ref int i)\n  {\n    void M() { } // can be addressed by cref=\"E.extension(ref int).M()\" or cref=\"extension(ref int).M()\" within E, but not cref=\"M()\"\n  }\n  extension(ref  int i)\n  {\n    void M(int i2) { } // can be addressed by cref=\"E.extension(ref int).M(int)\" or cref=\"extension(ref int).M(int)\" within E\n  }\n}\n```\n\nThe lookup knowns to look in all matching extension blocks.  \nAs we disallow unqualified references to extension members, cref would also disallow them.\n\nThe syntax would be:\n```antlr\nmember_cref\n  : conversion_operator_member_cref\n  | extension_member_cref // added\n  | indexer_member_cref\n  | name_member_cref\n  | operator_member_cref\n  ;\n\nextension_member_cref // added\n : 'extension' type_argument_list? cref_parameter_list '.' member_cref\n ;\n\nqualified_cref\n  : type '.' member_cref\n  ;\n\ncref\n  : member_cref\n  | qualified_cref\n  | type_cref\n  ;\n```\n\nIt's an error to use `extension_member_cref` at top-level (`extension(int).M`) or nested in another extension (`E.extension(int).extension(string).M`).  \n\n## Breaking changes\n\nTypes and aliases may not be named \"extension\".\n\n\n## Open issues\n\n<details>\n<summary>Temporary section of the document related to open issues, including discussion of unfinalized syntax and alternative designs</summary>\n\n- Should we adjust receiver requirements when accessing an extension member? ([comment](https://github.com/dotnet/roslyn/pull/78685#discussion_r2126534632))\n- ~~Confirm `extension` vs. `extensions` as the keyword~~ (answer: `extension`, LDM 2025-03-24)\n- ~~Confirm that we want to disallow `[ModuleInitializer]`~~ (answer: yes, disallow, LDM 2025-06-11)\n- ~~Confirm that we're okay to discard extension blocks as entry point candidates~~ (answer: yes, discard, LDM 2025-06-11)\n- ~~Confirm LangVer logic (skip new extensions, vs. consider and report them when picked)~~ (answer: bind unconditionally and report LangVer error except for instance extension methods, LDM 2025-06-11)\n- ~~Should `partial` be required for extension blocks that merge and have their doc comments merged?~~ (answer: doc comments are merged silently when blocks get merged, no `partial` needed, confirmed by email 2025-09-03)\n- ~~Confirm that members should not be named after the containing or the extended types.~~ (answer: yes, confirmed by email 2025-09-03)\n\n### ~~Revisit grouping/conflict rules in light of portability issue: https://github.com/dotnet/roslyn/issues/79043~~\n\n(answer: this scenario was resolved as part of new metadata design with content-based type names, it is allowed)\n\nThe current logic is to group extension blocks that have the same receiver type. This doesn't account for constraints.\nThis causes a portability issue with this scenario:\n```\nstatic class E\n{\n   extension<T>(ref T) where T : struct\n      void M()\n   extension<T>(T) where T : class\n      void M()\n}\n```\n\nThe proposal is to use the same grouping logic that we're planning for the extension grouping type design, namely to account for CLR-level constraints (ie. ignoring notnull, tuple names, nullability annotations).\n\n### Should refness be encoded in the grouping type name?\n\n- ~~Review proposal that `ref` not be included in extension grouping type name (needs further discussion after WG revisits grouping/conflict rules, LDM 2025-06-23)~~ (answer: confirmed by email 2025-09-03)\n```\npublic static class E\n{\n  extension(ref int)\n  {\n    public static void M()\n  }\n}\n```\nIt is emitted as:\n```\npublic static class E\n{\n  public static class <>ExtensionTypeXYZ\n  {\n    .. marker method ...\n    void M()\n  }\n}\n```\n\nAnd third-party CREF reference for `E.extension(ref int).M` are emitted as `M:E.<>ExtensionGroupingTypeXYZ.M()`\nIf `ref` is removed or added to an extension parameter, we probably don't want the CREF to break.\n\nWe don't much care for this scenario, as any usage as extension would be an ambiguity:\n```\npublic static class E\n{\n  extension(ref int)\n    static void M()\n  extension(int)\n    static void M()\n}\n```\n\nBut we care about this scenario (for portability and usefulness), and this should work with proposed metadata design after we adjust conflict rules:\n```\nstatic class E\n{\n   extension<T>(ref T) where T : struct\n      void M()\n   extension<T>(T) where T : class\n      void M()\n}\n```\n\nNot accounting for refness has a downside, as we loose portability in this scenario:\n```\nstatic class E\n{\n   extension<T>(ref T)\n      void M()\n   extension<T>(T)\n      void M()\n}\n// portability issue: since we're grouping without accounting for refness, the emitted extension members conflict (not implementation members). Mitigation: keep as classic extensions or split to another static class\n```\n\n### nameof\n\n- ~~Should we disallow extension properties in nameof like we do classic and new extension methods?~~ (answer: we'd like to use `nameof(EnclosingStaticClass.ExtensionMember). Needs design, likely punt from .NET 10. LDM 2025-06-11)\n\n### pattern-based constructs\n\n#### Methods\n- ~~Where should new extension methods come into play?~~ (answer: same places where classic extension methods come into play, LDM 2025-05-05)\n\nThis includes:  \n- `GetEnumerator`/`GetAsyncEnumerator` in `foreach`\n- `Deconstruct` in deconstruction, in positional pattern and foreach\n- `Add` in collection initializers\n- `GetPinnableReference` in `fixed`\n- `GetAwaiter` in `await`\n\nThis excludes:  \n- `Dispose`/`DisposeAsync` in `using` and `foreach`\n- `MoveNext`/`MoveNextAsync` in `foreach`\n- `Slice` and `int` indexers in implicit indexers (and possibly list-patterns?)\n- `GetResult` in `await`\n\n#### Properties and indexers\n- ~~Where should extension properties and indexers come into play?~~  (answer: let's start with the four, LDM 2025-05-05)  \n\nWe'd include:  \n- object initializer: `new C() { ExtensionProperty = ... }`\n- dictionary intializer: `new C() { [0] = ... }`\n- `with`: `x with { ExtensionProperty = ... }`\n- property patterns: `x is { ExtensionProperty: ... }`  \n  \nWe'd exclude:  \n- `Current` in `foreach`\n- `IsCompleted` in `await`\n- `Count`/`Length` properties and indexers in list-pattern\n- `Count`/`Length` properties and indexers in implicit indexers\n\n##### Delegate-returning properties\n- ~~Confirm that extension properties of this shape should only come into play in LINQ queries, to match what instance properties do.~~ (answer: makes sense, LDM 2025-04-06)\n\n##### List and spread pattern\n- Confirm that extension `Index`/`Range` indexers should play in list-patterns (answer: not relevant for C# 14)\n\n##### Revisit where `Count`/`Length` extension properties come into play  \n\n#### [Collection expressions](../csharp-12.0/collection-expressions.md)\n\n- Extension `Add` works\n- Extension `GetEnumerator` works for spread\n- Extension `GetEnumerator` does not affect the determination of the element type (must be instance)\n- Static `Create` extension methods should not count as a blessed **create** method\n- Should extension countable properties affect collection expressions?\n\n#### [`params` collections](../csharp-13.0/params-collections.md)\n\n- Extensions `Add` does not affect what types are allowed with `params`\n\n#### [dictionary expressions](https://github.com/dotnet/csharplang/blob/main/proposals/dictionary-expressions.md)\n\n- Confirm that extension indexers don't play in dictionary expressions, as the presence of the indexer is an integral part of what defines a dictionary type. (answer: not relevant for C# 14)\n\n### `extern`\n\n- ~~we're planning to allow `extern` for portability: https://github.com/dotnet/roslyn/issues/78572~~ (answer: approved, LDM 2025-06-23)\n\n### Naming/numbering scheme for extension type\n\n[Issue](https://github.com/dotnet/roslyn/issues/78416)  \nThe current numbering system causes problems with the [validation of public APIs](https://learn.microsoft.com/dotnet/fundamentals/apicompat/package-validation/overview#validator-types)\nwhich ensures that public APIs match between reference-only assemblies and implementation assemblies.\n\n~~Should we make one of the following changes?~~ (answer: we're adopting a content-based naming scheme to increase public API stability, and the tools will still need to be updated to account for marker methods)\n1. adjust the tool\n2. use some content-based naming scheme (TBD)\n3. let the name be controlled via some syntax\n\n### New generic extension Cast method still can't work in LINQ\n\n[Issue](https://github.com/dotnet/roslyn/issues/78415)  \nIn earlier designs of roles/extensions, it was possible to only specify the type arguments of the method explicitly.  \nBut now that we're focusing on seemless transition from classic extension methods, all the type arguments must be given explicitly.  \nThis fails to address a problem with extension Cast method usage in LINQ.\n\n~~Should we make a change to extensions feature to accomodate this scenario?~~ (answer: no, this does not cause us to revisit the extension resolution design, LDM 2025-05-05)\n\n### Constraining the extension parameter on an extension member\n\n~~Should we allow the following?~~ (answer: no, this could be added later)\n\n```csharp\nstatic class E\n{\n    extension<T>(T t)\n    {\n        public void M<U>(U u) where T : C<U>  { } // error: 'E.extension<T>(T).M<U>(U)' does not define type parameter 'T'\n    }\n}\n\npublic class C<T> { }\n```\n\n### Nullability\n\n- ~~Confirm the current design, ie. maximal portability/compatibility~~ (answer: yes, LDM 2025-04-17)\n\n```csharp\n    extension([System.Diagnostics.CodeAnalysis.DoesNotReturnIf(false)] bool b)\n    {\n        public void AssertTrue() => throw null!;\n    }\n```\n```csharp\n    extension([System.Diagnostics.CodeAnalysis.NotNullIfNotNull(\"o\")] ref int? i)\n    {\n        public void M(object? o)  => throw null!;\n    }\n```\n\n### Metadata\n\n- ~~Should skeleton methods throw `NotSupportedException` or some other standard exception (right now we do `throw null;`)?~~ (answer: yes, LDM 2025-04-17)\n- ~~Should we accept more than one parameter in marker method in metadata (in case new versions add more info)?~~ (answer: we can remain strict, LDM 2025-04-17)\n- ~~Should the extension marker or speakable implementation methods be marked with special name?~~ (answer: the marker method should be marked with special name and we should check it, but not implementation methods, LDM 2025-04-17)\n- ~~Should we add `[Extension]` attribute on the static class even when there is no instance extension method inside?~~ (answer: yes, LDM 2025-03-10)\n- ~~Confirm we should add `[Extension]` attribute to implementation getters and setters too.~~ (answer: no, LDM 2025-03-10)\n- ~~Confirm that the extension types should be marked with special name and the compiler will require this flag in metadata (this is a breaking change from preview)~~ (answer: approved, LDM 2025-06-23)\n\n#### static factory scenario\n\n- ~~What are the conflict rules for static methods?~~ (answer: use existing C# rules for the enclosing static type, no relaxation, LDM 2025-03-17)\n\n### Lookup\n\n- ~~How to resolve instance method invocations now that we have speakable implementation names?~~ We prefer the skeleton method to its corresponding implementation method. \n- ~~How to resolve static extension methods?~~ (answer: just like instance extension methods, LDM 2025-03-03)\n- ~~How to resolve properties?~~ (answered in broad strokes LDM 2025-03-03, but needs follow-up for betterness)\n- ~~Scoping and shadowing rules for extension parameter and type parameters~~ (answer: in scope of extension block, shadowing disallowed, LDM 2025-03-10)\n- ~~How should ORPA apply to new extension methods?~~  (answer: treat extension blocks as transparent, the \"containing type\" for ORPA is the enclosing static class, LDM 2025-04-17)\n\n```\npublic static class Extensions\n{\n    extension(Type1)\n    {\n        [OverloadResolutionPriority(1)]\n        public void Overload(...)\n    }\n    extension(Type2)\n    {\n        public void Overload(...)\n    }\n}\n```\n- ~~Should ORPA apply to new extension properties?~~ (answer: yes and ORPA should be copied onto implementation methods, LDM 2025-04-23)\n```\npublic static class Extensions\n{\n    extension(int[] i)\n    {\n        public P { get => }\n    }\n    extension(ReadOnlySpan<int> r)\n    {\n       [OverloadResolutionPriority(1)]\n       public P { get => }\n    }\n}\n```\n- How to retcon the classic extension resolution rules? Do we \n  1. update the standard for classic extension methods, and use that to also describe new extension methods,\n  2. keep the existing language for classic extension methods, use that to also describe new extension methods, but have a known spec deviation for both,\n  3. keep the existing language for classic extension methods, but use different language for new extension methods, and only have a known spec deviation for classic extension methods?\n- ~~Confirm that we want to disallow explicit type arguments on a property access~~ (answer: no property access with explicit type arguments, discussed in WG)\n```csharp\nstring s = \"ran\";\n_ = s.P<object>; // error\n\nstatic class E\n{\n    extension<T>(T t)\n    {\n        public int P => 0;\n    }\n}\n```\n- ~~Confirm that we want betterness rules to apply even when the receiver is a type~~ (answer: a type-only extension parameter should be considered when resolving static extension members, LDM 2025-06-23)\n```csharp\nint.M();\n\nstatic class E1\n{\n    extension(int)\n    {\n        public static void M() { }\n    }\n}\nstatic class E2\n{\n    extension(in int i)\n    {\n        public static void M() => throw null;\n    }\n}\n```\n- ~~Confirm that we're okay with having an ambiguity when both methods and properties are applicable~~ (answer: we should design a proposal to do better than the status quo, punting out of .NET 10, LDM 2025-06-23)\n- ~~Confirm that we don't want some betterness across all members before we determine the winning member kind~~ (answer: punting out of .NET 10, WG 2025-07-02)\n```\nstring s = null;\ns.M(); // error\n\nstatic class E\n{\n    extension(string s)\n    {\n        public System.Action M => throw null;\n    }\n    extension(object o)\n    {\n        public string M() => throw null;\n    }\n}\n```\n- ~~Do we have an implicit receiver within extension declarations?~~ (answer: no, was previously discussed in LDM)\n```csharp\nstatic class E\n{\n    extension(object o)\n    {\n        public void M() \n        {\n            M2();\n        }\n        public void M2() { }\n    }\n}\n```\n- ~~Should we allow lookup on type parameter?~~ ([discussion](https://github.com/dotnet/csharplang/discussions/8696#discussioncomment-12817547)) (answer: no, we're going to wait on feedback, LDM 2025-04-16)\n\n### Accessibility\n\n- ~~What is the meaning of accessibility within an extension declaration?~~ (answer: extension declarations do not count as an accessibility scope, LDM 2025-03-17)\n- ~~Should we apply the \"inconsistent accessibility\" check on the receiver parameter even for static members?~~  (answer: yes, LDM 2025-04-17)\n```csharp\npublic static class Extensions\n{\n    extension(PrivateType p)\n    {\n        // We report inconsistent accessibility error, \n        //   because we generate a `public static void M(PrivateType p)` implementation in enclosing type\n        public void M() { } \n\n        public static void M2() { } // should we also report here, even though not technically necessary?\n    }\n\n    private class PrivateType { }\n}\n```\n\n### Extension declaration validation\n\n- ~~Should we relax the type parameter validation (inferrability: all the type parameters must appear in the type of the extension parameter) where there are only methods?~~ (answer: yes, LDM 2025-04-06) \nThis would allow porting 100% of classic extension methods.  \nIf you have `TResult M<TResult, TSource>(this TSource source)`, you could port it as `extension<TResult, TSource>(TSource source) { TResult M() ... }`. \n\n- ~~Confirm whether init-only accessors should be allowed in extensions~~  (answer: okay to disallow for now, LDM 2025-04-17)\n- ~~Should the only difference in receiver ref-ness be allowed `extension(int receiver) { public void M2() {} }`    `extension(ref int receiver) { public void M2() {} }`?~~ (answer: no, keep spec'ed rule, LDM 2025-03-24)\n- ~~Should we complain about a conflict like this `extension(object receiver) { public int P1 => 1; }`   `extension(object receiver) { public int P1 {set{}} }`?~~ (answer: yes, keep spec'ed rule, LDM 2025-03-24)\n- ~~Should we complain about conflicts between skeleton methods that aren't conflicts between implementation methods?~~ (answer: yes, keep spec'ed rule, LDM 2025-03-24)\n```csharp\nstatic class E\n{\n    extension(object)\n    {\n        public void Method() {  }\n        public static void Method() { }\n    }\n}\n```\nThe current conflict rules are: 1. check no conflict within similar extensions using class/struct rules, 2. check no conflict between implementation methods across various extensions declarations.  \n- ~~Do we stil need the first part of the rules?~~ (answer: yes, we're keeping this structure as it helps with consumption of the APIs, LDM 2025-03-24)\n\n### XML docs\n\n- ~~Is `paramref` to receiver parameter supported on extension members? Even on static? How is it encoded in the output? Probably standard way `<paramref name=\"...\"/>` would work for a human,  but there is a risk that some existing tools won't be happy to not find it among the parameters on the API.~~ (answer: yes paramref to extension parameter is allowed on extension members, LDM 2025-05-05)\n- ~~Are we supposed to copy doc comments to the implementation methods with speakable names?~~ (answer: no copying, LDM 2025-05-05)\n- ~~Should `<param>` element corresponding to receiver parameter be copied from extension container for instance methods? Anything else should be copied from container to implementation methods (`<typeparam>` etc.) ?~~ (answer: no copying, LDM 2025-05-05)\n- ~~Should `<param>` for extension parameter be allowed on extension members as an override?~~ (answer: no, for now, LDM 2025-05-05)\n- Will the summary on extension blocks would appear anywhere?\n\n#### CREF\n\n- ~~Confirm syntax~~  (answer: proposal is good, LDM 2025-06-09)\n- ~~Should it be possible to refer to an extension block (`E.extension(int)`)?~~ (answer: no, LDM 2025-06-09)\n- ~~Should it be possible to refer to a member using an unqualified syntax: `extension(int).Member`?~~ (answer: yes, LDM 2025-06-09)\n- Should we use different characters for unspeakable name, to avoid XML escaping? (answer: defer to WG, LDM 2025-06-09)\n- ~~Confirm it's okay that both references to skeleton and implementation methods are possible: `E.M` vs. `E.extension(int).M`. Both seem necessary (extension properties and portability of classic extension methods).~~ (answer: yes, LDM 2025-06-09)\n- ~~Are extension metadata names problematic for versioning docs?~~ (answer: yes, we're going to move away from ordinals and use a content-based stable naming scheme)\n\n### Add support for more member kinds\n\nWe do not need to implement all of this design at once, but can approach it one or a few member kinds at a time. \nBased on known scenarios in our core libraries, we should work in the following order:\n\n1. Properties and methods (instance and static)\n2. Operators\n3. Indexers (instance and static, may be done opportunistically at an earlier point)\n4. Anything else\n\nHow much do we want to front-load the design for other kinds of members?\n```antlr\nextension_member_declaration // add\n    : constant_declaration\n    | field_declaration\n    | method_declaration\n    | property_declaration\n    | event_declaration\n    | indexer_declaration\n    | operator_declaration\n    | constructor_declaration\n    | finalizer_declaration\n    | static_constructor_declaration\n    | type_declaration\n    ;\n```\n\n#### Nested types\n\nIf we do choose to move forward with extension nested types, here are some notes from previous discussions:\n- There would be a conflict if two extension declarations declared nested extension types with same names and arity.\n  We do not have a solution for representing this in metadata.  \n- The rough approach we discussed for metadata:\n  1. we would emit a skeleton nested type with original type parameters and no members\n  2. we would emit an implementation nested type with prepended type parameters from the extension declaration and \n     all the member implementations as they appear in source (modulo references to type parameters)\n\n#### Constructors\n\nConstructors are generally described as an instance member in C#, since their body has access to the newly created value through the `this` keyword. \nThis does not work well for the parameter-based approach to instance extension members, though, since there is no prior value to pass in as a parameter.\n\nInstead, extension constructors work more like static factory methods. \nThey are considered static members in the sense that they don't depend on a receiver parameter name. \nTheir bodies need to explicitly create and return the construction result. \nThe member itself is still declared with constructor syntax, but cannot have `this` or `base` initializers and does not rely on the receiver type having accessible constructors.\n\nThis also means that extension constructors can be declared for types that have no constructors of their own, such as interfaces and enum types:\n\n``` c#\npublic static class Enumerable\n{\n    extension(IEnumerable<int>)\n    {\n        public static IEnumerable(int start, int count) => Range(start, count);\n    }\n    public static IEnumerable<int> Range(int start, int count) { ... } \n}\n```\n\nAllows:\n\n```\nvar range = new IEnumerable<int>(1, 100);\n```\n\n### Shorter forms\n\nThe proposed design avoids per-member repetition of receiver specifications, but does end up with extension members being nested two-deep in a static class _and_ and extension declaration. It will likely be common for static classes to contain only one extension declaration or for extension declarations to contain only one member, and it seems plausible for us to allow syntactic abbreviation of those cases.\n\n__Merge static class and extension declarations:__\n\n``` c#\npublic static class EmptyExtensions : extension(IEnumerable source)\n{\n    public bool IsEmpty => !source.GetEnumerator().MoveNext();\n}\n```\n\nThis ends up looking more like what we've been calling a \"type-based\" approach, where the container for extension members is itself named.\n\n__Merge extension declaration and extension member:__ \n\n``` c#\npublic static class Bits\n{\n    extension(ref ulong bits) public bool this[int index]\n    {\n        get => (bits & Mask(index)) != 0;\n        set => bits = value ? bits | Mask(index) : bits & ~Mask(index);\n    }\n    static ulong Mask(int index) => 1ul << index;\n}\n \npublic static class Enumerable\n{\n    extension<TSource>(IEnumerable<TSource> source) public IEnumerable<TSource> Where(Func<TSource, bool> predicate) { ... }\n}\n```\n\nThis ends up looking more like what we've been calling a \"member-based\" approach, where each extension member contains its own receiver specification. \n\n</details>\n\n"
  },
  {
    "path": "proposals/csharp-14.0/field-keyword.md",
    "content": "# `field` keyword in properties\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/8635>\n\n## Summary\n\nExtend all properties to allow them to reference an automatically generated backing field using the new contextual keyword `field`. Properties may now also contain an accessor _without_ a body alongside an accessor _with_ a body.\n\n## Motivation\n\nAuto properties only allow for directly setting or getting the backing field, giving some control only by placing access modifiers on the accessors. Sometimes there is a need to have additional control over what happens in one or both accessors, but this confronts users with the overhead of declaring a backing field. The backing field name must then be kept in sync with the property, and the backing field is scoped to the entire class which can result in accidental bypassing of the accessors from within the class.\n\nThere are several common scenarios. Within the getter, there is lazy initialization, or default values when the property has never been given. Within the setter, there is applying a constraint to ensure the validity of a value, or detecting and propagating updates such as by raising the `INotifyPropertyChanged.PropertyChanged` event.\n\nIn these cases by now you always have to create an instance field and write the whole property yourself.  This not only adds a fair amount of code, but it also leaks the backing field into the rest of the type's scope, when it is often desirable to only have it be available to the bodies of the accessors.\n\n## Glossary\n\n- **Auto property**: Short for \"automatically implemented property\" ([§15.7.4](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/classes.md#1574-automatically-implemented-properties)). Accessors on an auto property have no body. The implementation and backing storage are both provided by the compiler. Auto properties have `{ get; }`, `{ get; set; }`, or `{ get; init; }`.\n\n- **Auto accessor**: Short for \"automatically implemented accessor.\" This is an accessor that has no body. The implementation and backing storage are both provided by the compiler. `get;`, `set;` and `init;` are auto accessors.\n\n- **Full accessor**: This is an accessor that has a body. The implementation is not provided by the compiler, though the backing storage may still be (as in the example `set => field = value;`).\n\n- **Field-backed property**: This is either a property using the `field` keyword within an accessor body, or an auto property.\n\n- **Backing field**: This is the variable denoted by the `field` keyword in a property's accessors, which is also implicitly read or written in automatically implemented accessors (`get;`, `set;`, or `init;`).\n\n\n## Detailed design\n\nFor properties with an `init` accessor, everything that applies below to `set` would apply instead to the `init` accessor.\n\nThere are two syntax changes:\n\n1. There is a new contextual keyword, `field`, which may be used within property accessor bodies to access a backing field for the property declaration ([LDM decision](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-05-15.md#should-field-and-value-be-keywords-in-property-or-accessor-signatures-what-about-nameof-in-those-spaces)).\n\n2. Properties may now mix and match auto accessors with full accessors ([LDM decision](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-06-24.md#mixing-auto-accessors)). \"Auto property\" will continue to mean a property whose accessors have no bodies. None of the examples below will be considered auto properties.\n\nExamples:\n\n```cs\n{ get; set => Set(ref field, value); }\n```\n\n```cs\n{ get => field ?? parent.AmbientValue; set; }\n```\n\nBoth accessors may be full accessors with either one or both making use of `field`:\n\n```cs\n{ get => field; set => field = value; }\n```\n\n```cs\n{ get => field; set => throw new InvalidOperationException(); }\n```\n\n```cs\n{ get => overriddenValue; set => field = value; }\n```\n\n```cs\n{\n    get;\n    set\n    {\n        if (field == value) return;\n        field = value;\n        OnXyzChanged();\n    }\n}\n```\n\nExpression-bodied properties and properties with only a `get` accessor may also use `field`:\n\n```cs\npublic string LazilyComputed => field ??= Compute();\n```\n\n```cs\npublic string LazilyComputed { get => field ??= Compute(); }\n```\n\nSet-only properties may also use `field`:\n\n```cs\n{\n    set\n    {\n        if (field == value) return;\n        field = value;\n        OnXyzChanged(new XyzEventArgs(value));\n    }\n}\n```\n\n### Breaking changes\n\nThe existence of the `field` contextual keyword within property accessor bodies is a potentially breaking change.\n\nSince `field` is a keyword and not an identifier, it can only be \"shadowed\" by an identifier using the normal keyword-escaping route: `@field`. All identifiers named `field` declared within property accessor bodies can safeguard against breaks when upgrading from C# versions prior to 14 by adding the initial `@`.\n\nIf a variable named `field` is declared in a property accessor, an error is reported.\n\nIn language version 14 or later, a warning is reported if a *primary expression* `field` refers to the backing field, but would have referred to a different symbol in an earlier language version.\n\n### Field-targeted attributes\n\nAs with auto properties, any property that uses a backing field in one of its accessors will be able to use field-targeted attributes:\n\n```cs\n[field: Xyz]\npublic string Name => field ??= Compute();\n\n[field: Xyz]\npublic string Name { get => field; set => field = value; }\n```\n\nA field-targeted attribute will remain invalid unless an accessor uses a backing field:\n\n```cs\n// ❌ Error, will not compile\n[field: Xyz]\npublic string Name => Compute();\n```\n\n### Property initializers\n\nProperties with initializers may use `field`. The backing field is directly initialized rather than the setter being called ([LDM decision](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-03-02.md#open-questions-in-field)).\n\nCalling a setter for an initializer is not an option; initializers are processed before calling base constructors, and it is illegal to call any instance method before the base constructor is called. This is also important for default initialization/definite assignment of structs.\n\nThis yields flexible control over initialization. If you want to initialize without calling the setter, you use a property initializer. If you want to initialize by calling the setter, you use assign the property an initial value in the constructor.\n\nHere's an example of where this is useful. We believe the `field` keyword will find a lot of its use with view models because of the elegant solution it brings for the `INotifyPropertyChanged` pattern. View model property setters are likely to be databound to UI and likely to cause change tracking or trigger other behaviors. The following code needs to initialize the default value of `IsActive` without setting `HasPendingChanges` to `true`:\n\n```cs\nclass SomeViewModel\n{\n    public bool HasPendingChanges { get; private set; }\n\n    public bool IsActive { get; set => Set(ref field, value); } = true;\n\n    private bool Set<T>(ref T location, T value)\n    {\n        if (EqualityComparer<T>.Default.Equals(location, value))\n            return false;\n\n        location = value;\n        HasPendingChanges = true;\n        return true;\n    }\n}\n```\n\nThis difference in behavior between a property initializer and assigning from the constructor can also be seen with virtual auto properties in previous versions of the language:\n\n```cs\nusing System;\n\n// Nothing is printed; the property initializer is not\n// equivalent to `this.IsActive = true`.\n_ = new Derived();\n\nclass Base\n{\n    public virtual bool IsActive { get; set; } = true;\n}\n\nclass Derived : Base\n{\n    public override bool IsActive\n    {\n        get => base.IsActive;\n        set\n        {\n            base.IsActive = value;\n            Console.WriteLine(\"This will not be reached\");\n        }\n    }\n}\n```\n\n### Constructor assignment\n\nAs with auto properties, assignment in the constructor calls the (potentially virtual) setter if it exists, and if there is no setter it falls back to directly assigning to the backing field.\n\n```cs\nclass C\n{\n    public C()\n    {\n        P1 = 1; // Assigns P1's backing field directly\n        P2 = 2; // Assigns P2's backing field directly\n        P3 = 3; // Calls P3's setter\n        P4 = 4; // Calls P4's setter\n    }\n\n    public int P1 => field;\n    public int P2 { get => field; }\n    public int P4 { get => field; set => field = value; }\n    public int P3 { get => field; set; }\n}\n```\n\n### Definite assignment in structs\n\nEven though they can't be referenced in the constructor, backing fields denoted by the `field` keyword are subject to default-initialization and disabled-by-default warnings under the same conditions as any other struct fields ([LDM decision 1](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-03-02.md#property-assignment-in-structs), [LDM decision 2](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-05-02.md#definite-assignment-of-manually-implemented-setters)).\n\nFor example (these diagnostics are silent by default):\n\n```cs\npublic struct S\n{\n    public S()\n    {\n        // CS9020 The 'this' object is read before all of its fields have been assigned, causing preceding implicit\n        // assignments of 'default' to non-explicitly assigned fields.\n        _ = P1;\n    }\n\n    public int P1 { get => field; }\n}\n```\n\n```cs\npublic struct S\n{\n    public S()\n    {\n        // CS9020 The 'this' object is read before all of its fields have been assigned, causing preceding implicit\n        // assignments of 'default' to non-explicitly assigned fields.\n        P2 = 5;\n    }\n\n    public int P2 { get => field; set => field = value; }\n}\n```\n\n### Ref-returning properties\n\nLike with auto properties, the `field` keyword will not be available for use in ref-returning properties. Ref-returning properties cannot have set accessors, and without a set accessor, the get accessor and the property initializer would be the only things able to access the backing field. Absent use cases for this, now is not the time for ref-returning properties to start to be able to be written as auto properties.\n\n### Nullability\n\nA principle of the the Nullable Reference Types feature was to understand existing idiomatic coding patterns in C# and to require as little ceremony as possible around those patterns. The `field` keyword proposal enables simple, idiomatic patterns to address widely asked-for scenarios, such as lazily initialized properties. It's important for the Nullable Reference Types to mesh well with these new coding patterns.\n\nGoals:\n\n- A reasonable level of null-safety should be ensured for various usage patterns of the `field` keyword feature.\n\n- Patterns that use the `field` keyword should feel as though they've always been part of the language. Avoid making the user jump through hoops to enable Nullable Reference Types in code that is perfectly idiomatic for the `field` keyword feature.\n\nOne of the key scenarios is lazily initialized properties:\n\n```cs\npublic class C\n{\n    public C() { } // It would be undesirable to warn about 'Prop' being uninitialized here\n\n    string Prop => field ??= GetPropValue();\n}\n```\n\nThe following nullability rules will apply not just to properties that use the `field` keyword, but also to existing auto properties.\n\n#### Nullability of the *backing field*\n\nSee [Glossary](#glossary) for definitions of new terms.\n\nThe *backing field* has the same type as the property. However, its nullable annotation may differ from the property. To determine this nullable annotation, we introduce the concept of *null-resilience*. *Null-resilience* intuitively means that the property's `get` accessor preserves null-safety even when the field contains the `default` value for its type.\n\nA *field-backed property* is determined to be *null-resilient* or not by performing a special nullable analysis of its `get` accessor. Note that this analysis is **only** performed when the property may be of reference type and it is *not-annotated*.\n- Two separate nullable analysis passes are performed: one where the `field`'s nullable annotation is *not-annotated*, and one where its nullable annotation is *annotated*. The nullable diagnostics resulting from each analysis are recorded.\n- If there is a nullable diagnostic in the *annotated* pass, which was not present in the *not-annotated* pass, then the property is not null-resilient. Otherwise, it is null-resilient.\n    - The implementation can optimize by first performing the *annotated* pass. If this results in no diagnostics at all, then the property is null-resilient and the *not-annotated* pass can be skipped.\n- If the property does not have a get accessor, it is (vacuously) null-resilient.\n- If the get accessor is auto-implemented, the property is not null-resilient.\n\nNull-forgiving (`!`) operators, directives like `#nullable disable` and `#pragma disable warning`, and conventional project-level settings like `<NoWarn>`, are all respected when deciding if a nullable analysis has diagnostics. [DiagnosticSuppressors](https://github.com/dotnet/roslyn/blob/a91d7700db4a8b5da626d272d371477c6975f10e/docs/analyzers/DiagnosticSuppressorDesign.md) are ignored when deciding if a nullable analysis has diagnostics.\n\nThe nullable annotation of the backing field is determined as follows:\n- If the associated property's nullable annotation is *annotated* or *oblivious*, then the nullable annotation is the same as the nullable annotation of the associated property.\n- If the associated property's nullable annotation is *not-annotated*, then:\n    - If the property is *null-resilient*, the nullable annotation is *annotated*.\n    - If the property is not *null-resilient*, the nullable annotation is *not-annotated*.\n\n#### Constructor analysis\n\nCurrently, an auto property is treated very similarly to an ordinary field in [nullable constructor analysis](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-9.0/nullable-constructor-analysis.md). We extend this treatment to *field-backed properties*, by treating every *field-backed property* as a proxy to its backing field.\n\nWe update the following spec language from the previous [proposed approach](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-9.0/nullable-constructor-analysis.md#proposed-approach) to accomplish this (new language in **bold**):\n\n> At each explicit or implicit 'return' in a constructor, we give a warning for each member whose flow state is incompatible with its annotations and nullability attributes. **If the member is a field-backed property, the nullable annotation of the backing field is used for this check. Otherwise, the nullable annotation of the member itself is used.** A reasonable proxy for this is: if assigning the member to itself at the return point would produce a nullability warning, then a nullability warning will be produced at the return point.\n\n> [!NOTE]\n> A key trait of a *null-resilient* property is that it returns a value with \"correct\" nullability even when the backing field's value is `default`. Given this, we could consider not even tracking a flow state for such properties. However, this seems like a larger change in nullable analysis of properties, which we don't have any motivating scenario for changing at this time.\n\nThis is essentially a constrained interprocedural analysis. We anticipate that in order to analyze a constructor, it will be necessary to do binding and \"null-resilience\" analysis on all potentially applicable get accessors in the same type, which use the `field` contextual keyword and have *not-annotated* nullability. We speculate that this is not prohibitively expensive because getter bodies are usually not very complex, and that the \"null-resilience\" analysis only needs to be performed once regardless of how many constructors are in the type.\n\n#### Setter analysis\n\nFor simplicity, we use the terms \"setter\" and \"set accessor\" to refer to either a `set` or `init` accessor.\n\nThere is a need to check that setters of non-*null-resilient* field-backed properties actually initialize the backing field.\n\n```cs\nclass C\n{\n    string Prop\n    {\n        get => field;\n\n        // getter is not null-resilient, so `field` is not-annotated.\n        // We should warn here that `field` may be null when exiting.\n        set { }\n    }\n\n    public C()\n    {\n        Prop = \"a\"; // ok\n    }\n\n    public static void Main()\n    {\n        new C().Prop.ToString(); // no warning, NRE at runtime\n    }\n}\n```\n\nThe initial flow state of the *backing field* in the setter of a *field-backed property* is determined as follows:\n- If the property has an initializer, then the initial flow state is the same as the flow state after visiting the initializer.\n- Otherwise, the initial flow state is the same as the flow state given by `field = default;`.\n\nAt each explicit or implicit 'return' in the setter, a warning is reported if the flow state of the *backing field* is incompatible with its annotations and nullability attributes.\n\n#### Remarks\n\nThis formulation is intentionally similar to ordinary fields in constructors. Essentially, because only the property accessors can actually refer to the backing field, the setter is treated as a \"mini-constructor\" for the backing field.\n\nMuch like with ordinary fields, we usually know the property was initialized in the constructor because it was set, but not necessarily. Simply returning within a branch where `Prop != null` was true is also good enough for our constructor analysis, since we understand that untracked mechanisms may have been used to set the property.\n\nAlternatives were considered; see the [Nullability alternatives](#nullability-alternatives) section.\n\n### `nameof`\n\nIn places where `field` is a keyword, `nameof(field)` will fail to compile ([LDM decision](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-05-15.md#usage-in-nameof)), like `nameof(nint)`. It is not like `nameof(value)`, which is the thing to use when property setters throw ArgumentException as some do in the .NET core libraries. In contrast, `nameof(field)` has no expected use cases.\n\n### Overrides\n\nOverriding properties may use `field`. Such usages of `field` refer to the backing field for the overriding property, separate from the backing field of the base property if it has one. There is no ABI for exposing the backing field of a base property to overriding classes since this would break encapsulation.\n\nLike with auto properties, properties which use the `field` keyword and override a base property must override all accessors ([LDM decision](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-05-02.md#partial-overrides-of-virtual-properties)).\n\n### Captures\n\n`field` should be able to be captured in local functions and lambdas, and references to `field` from inside local functions and lambdas are allowed even if there are no other references ([LDM decision 1](https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-03-21.md#open-question-in-semi-auto-properties), [LDM decision 2](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-05-15.md#should-field-and-value-be-considered-keywords-in-lambdas-and-local-functions-within-property-accessors)):\n\n```cs\npublic class C\n{\n    public static int P\n    {\n        get\n        {\n            Func<int> f = static () => field;\n            return f();\n        }\n    }\n}\n```\n\n## Field usage warnings\n\nWhen the `field` keyword is used in an accessor, the compiler's existing analysis of unassigned or unread fields will include that field.\n\n- CS0414: The backing field for property 'Xyz' is assigned but its value is never used\n- CS0649: The backing field for property 'Xyz' is never assigned to, and will always have its default value\n\n## Specification changes\n\n### Syntax\n\nWhen compiling with language version 14 or higher, `field` is considered a keyword when used as a *primary expression* ([LDM decision](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-07-15.md)) in the following locations ([LDM decision](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-05-15.md#field-and-value-as-contextual-keywords)):\n- In method bodies of `get`, `set`, and `init` accessors in properties *but not* indexers\n- In attributes applied to those accessors\n- In nested lambda expressions and local functions, and in LINQ expressions in those accessors\n\nIn all other cases, including when compiling with language version 12 or lower, `field` is considered an identifier.\n\n```diff\nprimary_no_array_creation_expression\n    : literal\n+   | 'field'\n    | interpolated_string_expression\n    | ...\n    ;\n```\n\n### Properties\n\n[§15.7.1](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/classes.md#1571-general) *Properties - General*\n\n> A *property_initializer* may only be given for ~~an automatically implemented property, and~~ **a property that has a backing field that will be emitted. The *property_initializer*** causes the initialization of the underlying field of such properties with the value given by the *expression*.\n\n[§15.7.4](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/classes.md#1574-automatically-implemented-properties) *Automatically implemented properties*\n\n> An automatically implemented property (or auto-property for short), is a non-abstract, non-extern, non-ref-valued\n> property with ~~semicolon-only accessor bodies. Auto-properties shall have a get accessor and may optionally have a set accessor.~~ **either or both of:**\n> 1. **an accessor with a semicolon-only body**\n> 2. **usage of the `field` contextual keyword within the accessors or**\n>    **expression body of the property**\n> \n> When a property is specified as an automatically implemented property, a hidden **unnamed** backing field is automatically\n> available for the property ~~, and the accessors are implemented to read from and write to that backing field~~.\n> **For auto-properties, any semicolon-only `get` accessor is implemented to read from, and any semicolon-only**\n> **`set` accessor to write to its backing field.**\n> \n> ~~The hidden backing field is inaccessible, it can be read and written only through the automatically implemented property accessors, even within the containing type.~~\n> **The backing field can be referenced directly using the `field` keyword**\n> **within all accessors and within the property expression body. Because the field is unnamed, it cannot be used in a**\n> **`nameof` expression.**\n> \n> If the auto-property has ~~no set accessor~~ **only a semicolon-only get accessor**, the backing field is considered `readonly` ([§15.5.3](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/classes.md#1553-readonly-fields)).\n> Just like a `readonly` field, a read-only auto-property **(without a set accessor or an init accessor)** may also be assigned to in the body of a constructor\n> of the enclosing class. Such an assignment assigns directly to the ~~read-only~~ backing field of the property.\n> \n> **An auto-property is not allowed to only have a single semicolon-only `set` accessor without a `get` accessor.**\n> \n> An auto-property may optionally have a *property_initializer*, which is applied directly to the backing field as a *variable_initializer* ([§17.7](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/arrays.md#177-array-initializers)).\n\nThe following example:\n```csharp\n// No 'field' symbol in scope.\npublic class Point\n{\n    public int X { get; set; }\n    public int Y { get; set; }\n}\n```\nis equivalent to the following declaration:\n```csharp\n// No 'field' symbol in scope.\npublic class Point\n{\n    public int X { get { return field; } set { field = value; } }\n    public int Y { get { return field; } set { field = value; } }\n}\n```\nwhich is equivalent to:\n```csharp\n// No 'field' symbol in scope.\npublic class Point\n{\n    private int __x;\n    private int __y;\n    public int X { get { return __x; } set { __x = value; } }\n    public int Y { get { return __y; } set { __y = value; } }\n}\n```\n\nThe following example:\n```csharp\n// No 'field' symbol in scope.\npublic class LazyInit\n{\n    public string Value => field ??= ComputeValue();\n    private static string ComputeValue() { /*...*/ }\n}\n```\nis equivalent to the following declaration:\n```csharp\n// No 'field' symbol in scope.\npublic class Point\n{\n    private string __value;\n    public string Value { get { return __value ??= ComputeValue(); } }\n    private static string ComputeValue() { /*...*/ }\n}\n```\n\n## Alternatives\n\n### Nullability alternatives\n\nIn addition to the *null-resilience* approach outlined in the [Nullability](#nullability) section, the working group suggested the following alternatives for the LDM's consideration:\n\n#### Do nothing\n\nWe could introduce no special behavior at all here. In effect:\n- Treat a field-backed property the same way auto-properties are treated today--must be initialized in constructor except when marked required, etc.\n- No special treatment of the field variable when analyzing property accessors. It is simply a variable with the same type and nullability as the property.\n\nNote that this would result in nuisance warnings for \"lazy property\" scenarios, in which case users would likely need to assign `null!` or similar to silence constructor warnings.  \nA \"sub-alternative\" we can consider is to also completely ignore properties using `field` keyword for nullable constructor analysis. In that case, there would be no warnings anywhere about the user needing to initialize anything, but also no nuisance for the user, regardless of what initialization pattern they may be using.\n\nBecause we are only planning to ship the `field` keyword feature under the Preview LangVersion in .NET 9, we expect to have some ability to change the nullable behavior for the feature in .NET 10. Therefore, we could consider adopting a \"lower-cost\" solution like this one in the short term, and growing up to one of the more complex solutions in the long term.\n\n#### `field`-targeted nullability attributes\n\nWe could introduce the following defaults, achieving a reasonable level of null safety, without involving any interprocedural analysis at all:\n1. The `field` variable always has the same nullable annotation as the property.\n2. Nullability attributes `[field: MaybeNull, AllowNull]` etc. can be used to customize the nullability of the backing field.\n3. field-backed properties are checked for initialization in constructors based on the field's nullable annotation and attributes.\n4. setters in field-backed properties check for initialization of `field` similarly to constructors.\n\nThis would mean the \"little-l lazy scenario\" would look like this instead:\n\n```cs\nclass C\n{\n    public C() { } // no need to warn about initializing C.Prop, as the backing field is marked nullable using attributes.\n\n    [field: AllowNull, MaybeNull]\n    public string Prop => field ??= GetPropValue();\n}\n```\n\nOne reason we shied away from using nullability attributes here is that the ones we have are really oriented around describing inputs and outputs of signatures. They are cumbersome to use to describe the nullability of long-lived variables.\n- In practice, `[field: MaybeNull, AllowNull]` is required to make the field behave \"reasonably\" as a nullable variable, which gives maybe-null initial flow state, and allows possible null values to be written to it. This feels cumbersome to ask users to do for relatively common \"little-l lazy\" scenarios.\n- If we pursued this approach, we would consider adding a warning when `[field: AllowNull]` is used, suggesting to also add `MaybeNull`. This is because AllowNull by itself doesn't do what users need out of a nullable variable: it assumes the field is initially not-null when we never saw anything write to it yet.\n- We could also consider adjusting the behavior of `[field: MaybeNull]` on the `field` keyword, or even fields in general, to allow nulls to also be written to the variable, as if `AllowNull` were implicitly also present.\n\n#### Infer the initial flow state of the `field`\n\nInstead of defining the behavior in terms of the `field`'s nullable annotation, we could just define the initial flow state of the `field` in the 'get' accessor. This would reflect the reality that it's ok to assign a possible null value to the `field`. The other forms of analysis we have would succeed in identifying any resulting null safety issues from doing that.\n\nHowever, this came about in a phase of implementation where the churn of making this change was not thought to be worthwhile. This is something we could conceivably adjust under the hood in the future, with very few users perceiving any break--this alternative approach being generally more permissive than the one we actually implemented.\n\n## Answered LDM questions\n\n### Syntax locations for keywords\n\nIn accessors where `field` and `value` could bind to a synthesized backing field or an implicit setter parameter, in which syntax locations should the identifiers be considered keywords?\n1. always\n1. *primary expressions* only\n1. never\n\nThe first two cases are breaking changes.\n\nIf the identifiers are *always* considered keywords, that is a breaking change for the following for instance:\n```csharp\nclass MyClass\n{\n    private int field;\n    public int P => this.field; // error: expected identifier\n\n    private int value;\n    public int Q\n    {\n        set { this.value = value; } // error: expected identifier\n    }\n}\n```\n\nIf the identifiers are keywords when used as *primary expressions* only, the breaking change is smaller. The most common break may be unqualified use of an existing member named `field`.\n```csharp\nclass MyClass\n{\n    private int field;\n    public int P => field; // binds to synthesized backing field rather than 'this.field'\n}\n```\n\nThere is also a break when `field` or `value` is redeclared in a nested function. This may be the only break for `value` for *primary expressions*.\n```csharp\nclass MyClass\n{\n    private IEnumerable<string> _fields;\n    public bool HasNotNullField\n    {\n        get => _fields.Any(field => field is { }); // 'field' binds to synthesized backing field\n    }\n    public IEnumerable<string> Fields\n    {\n        get { return _fields; }\n        set { _fields = value.Where(value => Filter(value)); } // 'value' binds to setter parameter\n    }\n}\n```\n\nIf the identifiers are *never* considered keywords, the identifiers will only bind to a synthesized backing field or the implicit parameter when the identifiers do not bind to other members. There is no breaking change for this case.\n\n#### Answer\n\n`field` is a keyword in appropriate accessors when used as a *primary expression* only; `value` is never considered a keyword.\n\n### Scenarios similar to `{ set; }`\n\n`{ set; }` is currently disallowed and this makes sense: the field which this creates can never be read. There are now new ways to end up in a situation where the setter introduces a backing field that is never read, such as the expansion of `{ set; }` into `{ set => field = value; }`.\n\nWhich of these scenarios should be allowed to compile? Assume that the \"field is never read\" warning would apply just like with a manually declared field.\n\n   1. `{ set; }` - Disallowed today, continue disallowing\n   1. `{ set => field = value; }`\n   1. `{ get => unrelated; set => field = value; }`\n   1. `{ get => unrelated; set; }`\n   1. ```cs\n      {\n          set\n          {\n              if (field == value) return;\n              field = value;\n              SendEvent(nameof(Prop), value);\n          }\n      }\n      ```\n   1. ```cs\n      {\n          get => unrelated;\n          set\n          {\n              if (field == value) return;\n              field = value;\n              SendEvent(nameof(Prop), value);\n          }\n      }\n      ```\n\n#### Answer\n\nOnly disallow what is already disallowed today in auto properties, the bodyless `set;`.\n\n### `field` in event accessor\n\nShould `field` be a keyword in an event accessor, and should the compiler generate a backing field?\n\n```csharp\nclass MyClass\n{\n    public event EventHandler E\n    {\n        add { field += value; }\n        remove { field -= value; }\n    }\n}\n```\n\n**Recommendation**: `field` is *not* a keyword within an event accessor, and no backing field is generated.\n\n#### Answer\n\nRecommendation taken. `field` is *not* a keyword within an event accessor, and no backing field is generated.\n\n### Nullability of `field`\n\nShould the proposed nullability of `field` be accepted? See the [Nullability](#nullability) section, and the open question within.\n\n#### Answer\n\nGeneral proposal is adopted. Specific behavior still needs more review.\n\n### `field` in property initializer\n\nShould `field` be a keyword in a property initializer and bind to the backing field?\n\n```csharp\nclass A\n{\n    const int field = -1;\n\n    object P1 { get; } = field; // bind to const (ok) or backing field (error)?\n}\n```\n\nAre there useful scenarios for referencing the backing field in the initializer?\n\n```csharp\nclass B\n{\n    object P2 { get; } = (field = 2);        // error: initializer cannot reference instance member\n    static object P3 { get; } = (field = 3); // ok, but useful?\n}\n```\n\nIn the example above, binding to the backing field should result in an error: \"initializer cannot reference non-static field\".\n\n#### Answer\n\nWe will bind the initializer as in previous versions of C#. We won't put the backing field in scope, nor will we prevent referencing other members named `field`.\n\n### Interaction with partial properties\n\n#### Initializers\n\nWhen a partial property uses `field`, which parts should be allowed to have an initializer?\n\n```cs\npartial class C\n{\n    public partial int Prop { get; set; } = 1;\n    public partial int Prop { get => field; set => field = value; } = 2;\n}\n```\n\n- It seems clear that an error should occur when both parts have an initializer.\n- We can think of use cases where either the definition or implementation part might want to set the initial value of the `field`.\n- It seems like if we permit the initializer on the definition part, it is effectively forcing the implementer to use `field` in order for the program to be valid. Is that fine?\n- We think it will be common for generators to use `field` whenever a backing field of the same type is needed in the implementation. This is in part because generators often want to enable their users to use `[field: ...]` targeted attributes on the property definition part. Using the `field` keyword saves the generator implementer the trouble of \"forwarding\" such attributes to some generated field and suppressing the warnings on the property. Those same generators are likely to also want to allow the user to specify an initial value for the field.\n\n**Recommendation**: Permit an initializer on either part of a partial property when the implementation part uses `field`. Report an error if both parts have an initializer.\n\n#### Answer\n\nRecommendation accepted. Either declaring or implementing property locations can use an initializer, but not both at the same time.\n\n#### Auto-accessors\n\nAs originally designed, partial property implementation must have bodies for all the accessors. However, recent iterations of the `field` keyword feature have included the notion of \"auto-accessors\". Should partial property implementations be able to use such accessors? If they are used exclusively, it will be indistinguishable from a defining declaration.\n\n```cs\npartial class C\n{\n    public partial int Prop0 { get; set; }\n    public partial int Prop0 { get => field; set => field = value; } // this is equivalent to the two \"semi-auto\" forms below.\n\n    public partial int Prop1 { get; set; }\n    public partial int Prop1 { get => field; set; } // is this a valid implementation part?\n\n    public partial int Prop2 { get; set; }\n    public partial int Prop2 { get; set => field = value; } // what about this? will there be disagreement about which is the \"best\" style?\n\n    public partial int Prop3 { get; }\n    public partial int Prop3 { get => field; } // it will only be valid to use at most 1 auto-accessor, when a second accessor is manually implemented.\n```\n\n**Recommendation**: Disallow auto-accessors in partial property implementations, because the limitations around when they would be usable are more confusing to follow than the benefit of allowing them.\n\n#### Answer\n\nAt least one implementing accessor must be manually implemented, but the other accessor can be automatically implemented.\n\n### Readonly field\n\nWhen should the synthesized backing field be considered *read-only*?\n\n```csharp\nstruct S\n{\n    readonly object P0 { get => field; } = \"\";         // ok\n    object P1          { get => field ??= \"\"; }        // ok\n    readonly object P2 { get => field ??= \"\"; }        // error: 'field' is readonly\n    readonly object P3 { get; set { _ = field; } }     // ok\n    readonly object P4 { get; set { field = value; } } // error: 'field' is readonly\n}\n```\n\nWhen the backing field is considered *read-only*, the field emitted to metadata is marked `initonly`, and an error is reported if `field` is modified other than in an initializer or constructor.\n\n**Recommendation**: The synthesized backing field is *read-only* when the containing type is a `struct` and the property or containing type is declared `readonly`.\n\n#### Answer\n\nRecommendation is accepted.\n\n### Readonly context and `set`\n\nShould a `set` accessor be allowed in a `readonly` context for a property that uses `field`?\n\n```csharp\nreadonly struct S1\n{\n    readonly object _p1;\n    object P1 { get => _p1; set { } }   // ok\n    object P2 { get; set; }             // error: auto-prop in readonly struct must be readonly\n    object P3 { get => field; set { } } // ok?\n}\n\nstruct S2\n{\n    readonly object _p1;\n    readonly object P1 { get => _p1; set { } }   // ok\n    readonly object P2 { get; set; }             // error: auto-prop with set marked readonly\n    readonly object P3 { get => field; set { } } // ok?\n}\n ```\n\n#### Answer\n\nThere could be scenarios for this where you're implementing a `set` accessor on a `readonly` struct and either passing it through, or throwing. We will allow this.\n\n### `[Conditional]` code\n\nShould the synthesized field be generated when `field` is used only in omitted calls to [*conditional methods*](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/attributes.md#22532-conditional-methods)?\n\nFor instance, should a backing field be generated for the following in a non-DEBUG build?\n```csharp\nclass C\n{\n    object P\n    {\n        get\n        {\n            Debug.Assert(field is null);\n            return null;\n        }\n    }\n}\n```\n\nFor reference, fields for *primary constructor parameters* are generated in similar cases - see [sharplab.io](https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA+ABADAAgwRgDoARASwEMBzAOwgGcAXUsOgbgFgAoLjAJhwDCACgjAAVjDAMcAM1IwANgBMAlFwDeXHNrwocAWSFrOOnJpOmdxGMACulQgEE6dGFAZC5ipTlJ0c1LYKCiocFtoAvlxR3JyMULZSOADKIuKS0l7KxuamGHqGxqa5ltrWdg7Oru6e8sq+/oHBoVo6MRFAA).\n\n**Recommendation**: The backing field is generated when `field` is used only in omitted calls to *conditional methods*.\n\n#### Answer\n\n`Conditional` code can have effects on non-conditional code, such as `Debug.Assert` changing nullability. It would be strange if `field` didn't have similar impacts. It is also unlikely to come up in most code, so we'll do the simple thing and accept the recommendation.\n\n### Interface properties and auto-accessors\n\nIs a combination of manually- and auto-implemented accessors recognized for an `interface` property where the auto-implemented accessor refers to a synthesized backing field?\n\nFor an instance property, an error will be reported that instance fields are not supported.\n\n```csharp\ninterface I\n{\n           object P1 { get; set; }                           // ok: not an implementation\n           object P2 { get => field; set { field = value; }} // error: instance field\n\n           object P3 { get; set { } } // error: instance field\n    static object P4 { get; set { } } // ok: equivalent to { get => field; set { } }\n}\n```\n\n**Recommendation**: Auto-accessors are recognized in `interface` properties, and the auto-accessors refer to a synthesized backing field. For an instance property, an error is reported that instance fields are not supported.\n\n#### Answer\n\nStandardizing around the instance field itself being the cause of the error is consistent with partial properties in classes, and we like that outcome. The recommendation is accepted.\n"
  },
  {
    "path": "proposals/csharp-14.0/first-class-span-types.md",
    "content": "# First-class Span Types\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/8714>\n\n## Summary\n\nWe introduce first-class support for `Span<T>` and `ReadOnlySpan<T>` in the language, including new implicit conversion types and consider them in more places,\nallowing more natural programming with these integral types.\n\n## Motivation\n\nSince their introduction in C# 7.2, `Span<T>` and `ReadOnlySpan<T>` have worked their way into the language and base class library (BCL) in many key ways. This is great for\ndevelopers, as their introduction improves performance without costing developer safety. However, the language has held these types at arm's length in a few key ways,\nwhich makes it hard to express the intent of APIs and leads to a significant amount of surface area duplication for new APIs. For example, the BCL has added a number of new\n[tensor primitive APIs](https://github.com/dotnet/runtime/issues/94553) in .NET 9, but these APIs are all offered on `ReadOnlySpan<T>`. C# doesn't recognize the\nrelationship between `ReadOnlySpan<T>`, `Span<T>`, and `T[]`, so even though there are user-defined conversions between these types,\nthey cannot be used for extension method receivers, cannot compose with other user-defined conversions, and don't help with all generic type inference scenarios.\nUsers would need to use explicit conversions or type arguments, which means that IDE tooling is not guiding users to use these APIs, since nothing will indicate to the IDE that it is valid\nto pass these types after conversion. In order to provide maximum usability for this style of API, the BCL will have to\ndefine an entire set of `Span<T>` and `T[]` overloads, which is a lot of duplicate surface area to maintain for no real gain. This proposal seeks to address the problem by\nhaving the language more directly recognize these types and conversions.\n\nFor example, the BCL can add only one overload of any `MemoryExtensions` helper like:\n\n```cs\nint[] arr = [1, 2, 3];\nConsole.WriteLine(\n    arr.StartsWith(1) // CS8773 in C# 13, permitted with this proposal\n    );\n\npublic static class MemoryExtensions\n{\n    public static bool StartsWith<T>(this ReadOnlySpan<T> span, T value) where T : IEquatable<T> => span.Length != 0 && EqualityComparer<T>.Default.Equals(span[0], value);\n}\n```\n\nPreviously, Span and array overloads would be needed to make the extension method usable on Span/array-typed variables\nbecause user-defined conversions (which exist between Span/array/ReadOnlySpan) are not considered for extension receivers.\n\n## Detailed Design\n\nThe changes in this proposal will be tied to `LangVersion >= 14`.\n\n### Span conversions\n\nWe add a new type of implicit conversion to the list in [§10.2.1](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#1021-general), an\n_implicit span conversion_. This conversion is a conversion from type and is defined as follows:\n\n------\n\nAn implicit span conversion permits `array_types`, `System.Span<T>`, `System.ReadOnlySpan<T>`, and `string` to be converted between each other as follows:\n* From any single-dimensional `array_type` with element type `Ei` to `System.Span<Ei>`\n* From any single-dimensional `array_type` with element type `Ei` to `System.ReadOnlySpan<Ui>`, provided that `Ei` is covariance-convertible ([§18.2.3.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/interfaces.md#18233-variance-conversion)) to `Ui`\n* From `System.Span<Ti>` to `System.ReadOnlySpan<Ui>`, provided that `Ti` is covariance-convertible ([§18.2.3.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/interfaces.md#18233-variance-conversion)) to `Ui`\n* From `System.ReadOnlySpan<Ti>` to `System.ReadOnlySpan<Ui>`, provided that `Ti` is covariance-convertible ([§18.2.3.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/interfaces.md#18233-variance-conversion)) to `Ui`\n* From `string` to `System.ReadOnlySpan<char>`\n\n------\n\nAny Span/ReadOnlySpan types are considered applicable for the conversion if they are `ref struct`s and they match by their fully-qualified name\n([LDM 2024-06-24](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-06-24.md#first-class-spans)).\n\nWe also add _implicit span conversion_ to the list of standard implicit conversions\n([§10.4.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#1042-standard-implicit-conversions)). This allows overload resolution to consider\nthem when performing argument resolution, as in the previously-linked API proposal.\n\nThe explicit span conversions are the following:\n- All *implicit span conversions*.\n- From an *array_type* with element type `Ti` to `System.Span<Ui>` or `System.ReadOnlySpan<Ui>` provided an explicit reference conversion exists from `Ti` to `Ui`.\n\nThere is no standard explicit span conversion unlike other *standard explicit conversions* ([§10.4.3][standard-explicit-conversions])\nwhich always exist given the opposite standard implicit conversion.\n\n#### User defined conversions\n[udc]: #user-defined-conversions\n\nUser-defined conversions are not considered when converting between types for which an implicit or an explicit span conversion exists.\n\nThe implicit span conversions are exempted from the rule\nthat it is not possible to define a user-defined operator between types for which a non-user-defined conversion exists\n([§10.5.2 Permitted user-defined conversions][permitted-udcs]).\nThis is needed so the BCL can keep defining the existing Span conversion operators even when they switch to C# 14\n(they are still needed for lower LangVersions and also because these operators are used in codegen of the new standard span conversions).\nBut it can be viewed as an implementation detail (codegen and lower LangVersions are not part of the spec)\nand Roslyn violates this part of the spec anyway (this particular rule about user-defined conversions is not enforced).\n\n#### Extension receiver\n\nWe also add _implicit span conversion_ to the list of acceptable implicit conversions on the first parameter of an extension method when determining applicability\n([12.8.9.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12893-extension-method-invocations)) (change in bold):\n\n> An extension method `Cᵢ.Mₑ` is ***eligible*** if:\n> \n> - `Cᵢ` is a non-generic, non-nested class\n> - The name of `Mₑ` is *identifier*\n> - `Mₑ` is accessible and applicable when applied to the arguments as a static method as shown above\n> - An implicit identity, reference ~~or boxing~~ **, boxing, or span** conversion exists from *expr* to the type of the first parameter of `Mₑ`.\n>   **Span conversion is not considered when overload resolution is performed for a method group conversion.**\n\nNote that implicit span conversion is not considered for extension receiver in method group conversions\n([LDM 2024-07-15](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-07-15.md#first-class-spans-open-question))\nwhich makes the following code continue working as opposed to resulting in a compile-time error\n`CS1113: Extension method 'E.M<int>(Span<int>, int)' defined on value type 'Span<int>' cannot be used to create delegates`:\n\n```cs\nusing System;\nusing System.Collections.Generic;\nAction<int> a = new int[0].M; // binds to M<int>(IEnumerable<int>, int)\nstatic class E\n{\n    public static void M<T>(this Span<T> s, T x) => Console.Write(1);\n    public static void M<T>(this IEnumerable<T> e, T x) => Console.Write(2);\n}\n```\n\nAs possible future work, we could consider removing this condition that span conversion is not considered for extension receiver in method group conversions\nand instead implement changes so the scenario like the one above would end up successfully calling the `Span` overload instead:\n- The compiler could emit a thunk that would take the array as the receiver and perform the span conversion inside\n  (similarly to the user manually creating the delegate like `x => new int[0].M(x)`).\n- Value delegates if implemented could be able to take the `Span` as receiver directly.\n\n#### Variance\n\nThe goal of the variance section in _implicit span conversion_ is to replicate some amount of covariance for `System.ReadOnlySpan<T>`. Runtime changes would be required to fully\nimplement variance through generics here (see ../csharp-13.0/ref-struct-interfaces.md for using `ref struct` types in generics), but we can\nallow a limited amount of covariance through use of a proposed .NET 9 API: https://github.com/dotnet/runtime/issues/96952. This will allow the language to treat `System.ReadOnlySpan<T>`\nas if the `T` was declared as `out T` in some scenarios. We do not, however, plumb this variant conversion through _all_ variance scenarios, and do not add it to the definition of\nvariance-convertible in [§18.2.3.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/interfaces.md#18233-variance-conversion). If in the future, we change the runtime\nto more deeply understand the variance here, we can take the minor breaking change to fully recognize it in the language.\n\n#### Patterns\n\nNote that when `ref struct`s are used as a type in any pattern, only identity conversions are allowed:\n\n```cs\nclass C<T> where T : allows ref struct\n{\n    void M1(T t) { if (t is T x) { } } // ok (T is T)\n    void M2(R r) { if (r is R x) { } } // ok (R is R)\n    void M3(T t) { if (t is R x) { } } // error (T is R)\n    void M4(R r) { if (r is T x) { } } // error (R is T)\n}\nref struct R { }\n```\n\nFrom the specification of *the is-type operator* ([§12.12.12.1][is-type-operator]):\n\n> The result of the operation `E is T` [...] is a Boolean value indicating whether `E` is non-null and can successfully be converted to type `T`\n> by a reference conversion, a boxing conversion, an unboxing conversion, a wrapping conversion, or an unwrapping conversion.\n>\n> [...]\n>\n> If `T` is a non-nullable value type, the result is `true` if `D` and `T` are the same type.\n\nThis behavior does not change with this feature, hence it will not be possible to write patterns for `Span`/`ReadOnlySpan`,\nalthough similar patterns are possible for arrays (including variance):\n\n```cs\nusing System;\n\nM1<object[]>([\"0\"]); // prints\nM1<string[]>([\"1\"]); // prints\n\nvoid M1<T>(T t)\n{\n    if (t is object[] r) Console.WriteLine(r[0]); // ok\n}\n\nvoid M2<T>(T t) where T : allows ref struct\n{\n    if (t is ReadOnlySpan<object> r) Console.WriteLine(r[0]); // error\n}\n```\n\n#### Code generation\n\nThe conversions will always exist, regardless of whether any runtime helpers used to implement them are present\n([LDM 2024-05-13](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-05-13.md#variant-conversion-existence)).\nIf the helpers are not present, attempting to use the conversion will result in a compile-time error that a compiler-required member is missing.\n\nThe compiler expects to use the following helpers or equivalents to implement the conversions:\n\n| Conversion | Helpers |\n|---|---|\n| array to Span | `static implicit operator Span<T>(T[])` (defined in `Span<T>`) |\n| array to ReadOnlySpan | `static implicit operator ReadOnlySpan<T>(T[])` (defined in `ReadOnlySpan<T>`) |\n| Span to ReadOnlySpan | `static implicit operator ReadOnlySpan<T>(Span<T>)` (defined in `Span<T>`) and `static ReadOnlySpan<T>.CastUp<TDerived>(ReadOnlySpan<TDerived>)` |\n| ReadOnlySpan to ReadOnlySpan | `static ReadOnlySpan<T>.CastUp<TDerived>(ReadOnlySpan<TDerived>)` |\n| string to ReadOnlySpan | `static ReadOnlySpan<char> MemoryExtensions.AsSpan(string)` |\n\nNote that `MemoryExtensions.AsSpan` is used instead of the equivalent implicit operator defined on `string`.\nThis means the codegen is different between LangVersions (the implicit operator is used in C# 13; the static method `AsSpan` is used in C# 14).\nOn the other hand, the conversion can be emitted on .NET Framework (the `AsSpan` method exists there whereas the `string` operator does not).\n\nThe explicit array to (ReadOnly)Span conversion first converts explicitly from the source array to an array with the destination element type\nand then to (ReadOnly)Span via the same helper as an implicit conversion would use, i.e., the corresponding `op_Implicit(T[])`.\n\n#### Better conversion from expression\n[betterness-rule]: #better-conversion-from-expression\n\n*Better conversion from expression* ([§12.6.4.5][better-conversion-from-expression]) is updated to prefer implicit span conversions.\nThis is based on [collection expressions overload resolution changes][ce-or].\n\n> Given an implicit conversion `C₁` that converts from an expression `E` to a type `T₁`, and an implicit conversion `C₂` that converts from an expression `E` to a type `T₂`, `C₁` is a *better conversion* than `C₂` if one of the following holds:\n>\n> - `E` is a *collection expression*, and `C₁` is a [*better collection conversion from expression*][better-collection-conversion-from-expression] than `C₂`\n> - `E` is not a *collection expression* and one of the following holds:\n>   - `E` exactly matches `T₁` and `E` does not exactly match `T₂`\n>   - **`E` exactly matches neither of `T₁` and `T₂`,\n>     and `C₁` is an implicit span conversion and `C₂` is not an implicit span conversion**\n>   - `E` exactly matches both or neither of `T₁` and `T₂`,\n>     **both or neither of `C₁` and `C₂` are an implicit span conversion**,\n>     and `T₁` is a *better conversion target* than `T₂`\n> - `E` is a method group, `T₁` is compatible with the single best method from the method group for conversion `C₁`, and `T₂` is not compatible with the single best method from the method group for conversion `C₂`\n\n#### Better conversion target\n[betterness-target]: #better-conversion-target\n\n*Better conversion target* ([§12.6.4.7][better-conversion-target]) is updated to prefer `ReadOnlySpan<T>` over `Span<T>`.\n\n> Given two types `T₁` and `T₂`, `T₁` is a ***better conversion target*** than `T₂` if one of the following holds:\n>\n> - **`T₁` is `System.ReadOnlySpan<E₁>`, `T₂` is `System.Span<E₂>`, and an identity conversion from `E₁` to `E₂` exists**\n> - **`T₁` is `System.ReadOnlySpan<E₁>`, `T₂` is `System.ReadOnlySpan<E₂>`, and an implicit conversion from `T₁` to `T₂` exists and no implicit conversion from `T₂` to `T₁` exists**\n> - **At least one of `T₁` or `T₂` is not `System.ReadOnlySpan<Eᵢ>` and is not `System.Span<Eᵢ>`, and** an implicit conversion from `T₁` to `T₂` exists and no implicit conversion from `T₂` to `T₁` exists\n> - ...\n\nDesign meetings:\n- https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-12-04.md#preferring-readonlyspant-over-spant-conversions\n- https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-12-09.md#first-class-span-open-questions\n\n#### Betterness remarks\n\nThe *better conversion from expression* rule should ensure that whenever an overload becomes applicable due to the new span conversions,\nany potential ambiguity with another overload is avoided because the newly-applicable overload is preferred.\n\nWithout this rule, the following code that successfully compiled in C# 13 would result in an ambiguity error in C# 14\nbecause of the new standard implicit conversion from array to ReadOnlySpan applicable to an extension method receiver:\n\n```cs\nusing System;\nusing System.Collections.Generic;\n\nvar a = new int[] { 1, 2, 3 };\na.M();\n\nstatic class E\n{\n    public static void M(this IEnumerable<int> x) { }\n    public static void M(this ReadOnlySpan<int> x) { }\n}\n```\n\nThe rule also allows introducing new APIs that would previously result in ambiguities, for example:\n\n```cs\nusing System;\nusing System.Collections.Generic;\n\nC.M(new int[] { 1, 2, 3 }); // would be ambiguous before\n\nstatic class C\n{\n    public static void M(IEnumerable<int> x) { }\n    public static void M(ReadOnlySpan<int> x) { } // can be added now\n}\n```\n\n> [!WARNING]\n> Because the betterness rule is defined for the span conversions which only exist in `LangVersion >= 14`,\n> API authors cannot add such new overloads if they want to keep supporting users on `LangVersion <= 13`.\n> For example, if .NET 9 BCL introduces such overloads, users that upgrade to `net9.0` TFM but stay on lower LangVersion\n> will get ambiguity errors for existing code.\n> See also [an open question](#unrestricted-betterness-rule) below.\n\n### Type inference\n\nWe update the type inferences section of the specification as follows (changes in **bold**).\n\n> #### 12.6.3.9 Exact inferences\n> \n> An *exact inference* *from* a type `U` *to* a type `V` is made as follows:\n> \n> - If `V` is one of the *unfixed* `Xᵢ` then `U` is added to the set of exact bounds for `Xᵢ`.\n> - Otherwise, sets `V₁...Vₑ` and `U₁...Uₑ` are determined by checking if any of the following cases apply:\n>   - `V` is an array type `V₁[...]` and `U` is an array type `U₁[...]` of the same rank\n>   - **`V` is a `Span<V₁>` and `U` is an array type `U₁[]` or a `Span<U₁>`**\n>   - **`V` is a `ReadOnlySpan<V₁>` and `U` is an array type `U₁[]` or a `Span<U₁>` or `ReadOnlySpan<U₁>`**\n>   - `V` is the type `V₁?` and `U` is the type `U₁`\n>   - `V` is a constructed type `C<V₁...Vₑ>` and `U` is a constructed type `C<U₁...Uₑ>`  \n>   If any of these cases apply then an *exact inference* is made from each `Uᵢ` to the corresponding `Vᵢ`.\n> - Otherwise, no inferences are made.\n> \n> #### 12.6.3.10 Lower-bound inferences\n> \n> A *lower-bound inference from* a type `U` *to* a type `V` is made as follows:\n> \n> - If `V` is one of the *unfixed* `Xᵢ` then `U` is added to the set of lower bounds for `Xᵢ`.\n> - Otherwise, if `V` is the type `V₁?` and `U` is the type `U₁?` then a lower bound inference is made from `U₁` to `V₁`.\n> - Otherwise, sets `U₁...Uₑ` and `V₁...Vₑ` are determined by checking if any of the following cases apply:\n>   - `V` is an array type `V₁[...]` and `U` is an array type `U₁[...]`of the same rank\n>   - **`V` is a `Span<V₁>` and `U` is an array type `U₁[]` or a `Span<U₁>`**\n>   - **`V` is a `ReadOnlySpan<V₁>` and `U` is an array type `U₁[]` or a `Span<U₁>` or `ReadOnlySpan<U₁>`**\n>   - `V` is one of `IEnumerable<V₁>`, `ICollection<V₁>`, `IReadOnlyList<V₁>>`, `IReadOnlyCollection<V₁>` or `IList<V₁>` and `U` is a single-dimensional array type `U₁[]`\n>   - `V` is a constructed `class`, `struct`, `interface` or `delegate` type `C<V₁...Vₑ>` and there is a unique type `C<U₁...Uₑ>` such that `U` (or, if `U` is a type `parameter`, its effective base class or any member of its effective interface set) is identical to, `inherits` from (directly or indirectly), or implements (directly or indirectly) `C<U₁...Uₑ>`.\n>   - (The “uniqueness” restriction means that in the case interface `C<T>{} class U: C<X>, C<Y>{}`, then no inference is made when inferring from `U` to `C<T>` because `U₁` could be `X` or `Y`.)  \n>   If any of these cases apply then an inference is made from each `Uᵢ` to the corresponding `Vᵢ` as follows:\n>   - If `Uᵢ` is not known to be a reference type then an *exact inference* is made\n>   - Otherwise, if `U` is an array type then ~~a *lower-bound inference* is made~~ **inference depends on the type of `V`**:\n>     - **If `V` is a `Span<Vᵢ>`, then an *exact inference* is made**\n>     - **If `V` is an array type or a `ReadOnlySpan<Vᵢ>`, then a *lower-bound inference* is made**\n>   - **Otherwise, if `U` is a `Span<Uᵢ>` then inference depends on the type of `V`**:\n>     - **If `V` is a `Span<Vᵢ>`, then an *exact inference* is made**\n>     - **If `V` is a `ReadOnlySpan<Vᵢ>`, then a *lower-bound inference* is made**\n>   - **Otherwise, if `U` is a `ReadOnlySpan<Uᵢ>` and `V` is a `ReadOnlySpan<Vᵢ>` a *lower-bound inference* is made**:\n>   - Otherwise, if `V` is `C<V₁...Vₑ>` then inference depends on the `i-th` type parameter of `C`:\n>     - If it is covariant then a *lower-bound inference* is made.\n>     - If it is contravariant then an *upper-bound inference* is made.\n>     - If it is invariant then an *exact inference* is made.\n> - Otherwise, no inferences are made.\n\nThere are no rules for *upper-bound inference* because it would not be possible to hit them.\nType inference never starts as upper-bound, it would have to go through a lower-bound inference and a contravariant type parameter.\nBecause of the rule \"if `Uᵢ` is not known to be a reference type then an *exact inference* is made,\"\nthe source type argument could not be `Span`/`ReadOnlySpan` (those cannot be reference types).\nHowever, the upper-bound span inference would only apply if the source type were a `Span`/`ReadOnlySpan`, since it would have rules like:\n>   - **`U` is a `Span<U₁>` and `V` is an array type `V₁[]` or a `Span<V₁>`**\n>   - **`U` is a `ReadOnlySpan<U₁>` and `V` is an array type `V₁[]` or a `Span<V₁>` or `ReadOnlySpan<V₁>`**\n\n### Breaking changes\n\nAs any proposal that changes conversions of existing scenarios, this proposal does introduce some new breaking changes. Here's a few examples:\n\n#### Calling `Reverse` on an array\n\nCalling `x.Reverse()` where `x` is an instance of type `T[]`\nwould previously bind to `IEnumerable<T> Enumerable.Reverse<T>(this IEnumerable<T>)`,\nwhereas now it binds to `void MemoryExtensions.Reverse<T>(this Span<T>)`.\nUnfortunately these APIs are incompatible (the latter does the reversal in-place and returns `void`).\n\n.NET 10 mitigates this by adding an array-specific overload `IEnumerable<T> Reverse<T>(this T[])`,\nsee https://github.com/dotnet/runtime/issues/107723.\n\n```cs\nvoid M(int[] a)\n{\n    foreach (var x in a.Reverse()) { } // fine previously, an error now (`Reverse` returns `void`)\n    foreach (var x in Enumerable.Reverse(a)) { } // workaround\n}\n```\n\nSee also:\n- https://developercommunity.visualstudio.com/t/Extension-method-SystemLinqEnumerable/10790323\n- https://developercommunity.visualstudio.com/t/Compilation-Error-When-Calling-Reverse/10818048\n- https://developercommunity.visualstudio.com/t/Version-17131-has-an-obvious-defect-th/10858254\n- https://developercommunity.visualstudio.com/t/Visual-Studio-2022-update-breaks-build-w/10856758\n- https://github.com/dotnet/runtime/issues/111532\n- https://developercommunity.visualstudio.com/t/Backward-compatibility-issue-:-IEnumerab/10896189#T-ND10896782\n\nDesign meeting: https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-09-11.md#reverse\n\n#### Ambiguities\n\nThe following examples previously failed type inference for the Span overload,\nbut now type inference from array to Span succeeds, hence these are ambiguous.\nTo work around this, users can use `.AsSpan()` or API authors can use `OverloadResolutionPriorityAttribute`.\n\n```cs\nvar x = new long[] { 1 };\nAssert.Equal([2], x); // previously Assert.Equal<T>(T[], T[]), now ambiguous with Assert.Equal<T>(ReadOnlySpan<T>, Span<T>)\nAssert.Equal([2], x.AsSpan()); // workaround\n```\n\n```cs\nvar x = new int[] { 1, 2 };\nvar s = new ArraySegment<int>(x, 1, 1);\nAssert.Equal(x, s); // previously Assert.Equal<T>(T, T), now ambiguous with Assert.Equal<T>(Span<T>, Span<T>)\nAssert.Equal(x.AsSpan(), s); // workaround\n```\n\nxUnit is adding more overloads to mitigate this: https://github.com/xunit/xunit/discussions/3021.\n\nDesign meeting: https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-09-11.md#new-ambiguities\n\n#### Covariant arrays\n\nOverloads taking `IEnumerable<T>` worked on covariant arrays,\nbut overloads taking `Span<T>` (which we now prefer) don't,\nbecause the span conversion throws an `ArrayTypeMismatchException` for covariant arrays.\nArguably, the `Span<T>` overload should not exist, it should take `ReadOnlySpan<T>` instead.\nTo work around this, users can use `.AsEnumerable()`, or API authors can use `OverloadResolutionPriorityAttribute`\nor add `ReadOnlySpan<T>` overload which is preferred due to [the betterness rule](#better-conversion-target).\n\n```cs\nstring[] s = new[] { \"a\" };\nobject[] o = s;\n\nC.R(o); // wrote 1 previously, now crashes in Span<T> constructor with ArrayTypeMismatchException\nC.R(o.AsEnumerable()); // workaround\n\nstatic class C\n{\n    public static void R<T>(IEnumerable<T> e) => Console.Write(1);\n    public static void R<T>(Span<T> s) => Console.Write(2);\n    // another workaround:\n    public static void R<T>(ReadOnlySpan<T> s) => Console.Write(3);\n}\n```\n\nDesign meeting: https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-09-11.md#covariant-arrays\n\n#### Preferring ReadOnlySpan over Span\n\nThe [betterness rule](#better-conversion-target) causes preference of ReadOnlySpan overloads over Span overloads\nto avoid `ArrayTypeMismatchException`s in [covariant array scenarios](#covariant-arrays).\nThat can lead to compilation breaks in some scenarios, for example when the overloads differ by their return type:\n\n```cs\ndouble[] x = new double[0];\nSpan<ulong> y = MemoryMarshal.Cast<double, ulong>(x); // previously worked, now a compilation error (returns ReadOnlySpan, not Span)\nSpan<ulong> z = MemoryMarshal.Cast<double, ulong>(x.AsSpan()); // workaround\n\nstatic class MemoryMarshal\n{\n    public static ReadOnlySpan<TTo> Cast<TFrom, TTo>(ReadOnlySpan<TFrom> span) => default;\n    public static Span<TTo> Cast<TFrom, TTo>(Span<TFrom> span) => default;\n}\n```\n\nSee https://github.com/dotnet/roslyn/issues/76443.\n\n#### Expression trees\n\nOverloads taking spans like `MemoryExtensions.Contains` are preferred over classic overloads like `Enumerable.Contains`,\neven inside expression trees - but ref structs are not supported by the interpreter engine:\n\n```cs\nExpression<Func<int[], int, bool>> exp = (array, num) => array.Contains(num);\nexp.Compile(preferInterpretation: true); // fails at runtime in C# 14\n\nExpression<Func<int[], int, bool>> exp2 = (array, num) => Enumerable.Contains(array, num); // workaround\nexp2.Compile(preferInterpretation: true); // ok\n```\n\nSimilarly, translation engines like LINQ-to-SQL need to react to this\nif their tree visitors expect `Enumerable.Contains` because they will encounter `MemoryExtensions.Contains` instead.\n\nSee also:\n- https://github.com/dotnet/runtime/issues/109757\n- https://github.com/dotnet/docs/issues/43952\n- https://github.com/dotnet/efcore/issues/35100\n- https://github.com/dotnet/csharplang/discussions/8959\n\nDesign meetings:\n- https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-12-04.md#conversions-in-expression-trees\n- https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-01-06.md#ignoring-ref-structs-in-expressions\n\n#### User-defined conversions through inheritance\n\nBy adding _implicit span conversions_ to the list of standard implicit conversions, we can potentially change behavior when user-defined conversions are involved in a type hierarchy.\nThis example shows that change, in comparison to an integer scenario that already behaves as the new C# 14 behavior will.\n\n```cs\nSpan<string> span = [];\nvar d = new Derived();\nd.M(span); // Base today, Derived tomorrow\nint i = 1;\nd.M(i); // Derived today, demonstrates new behavior\n\nclass Base\n{\n    public void M(Span<string> s)\n    {\n        Console.WriteLine(\"Base\");\n    }\n\n    public void M(int i)\n    {\n        Console.WriteLine(\"Base\");\n    }\n}\n\nclass Derived : Base\n{\n    public static implicit operator Derived(ReadOnlySpan<string> r) => new Derived();\n    public static implicit operator Derived(long l) => new Derived();\n\n    public void M(Derived s)\n    {\n        Console.WriteLine(\"Derived\");\n    }\n}\n```\n\nSee also: https://github.com/dotnet/roslyn/issues/78314\n\n#### Extension method lookup\n\nBy allowing _implicit span conversions_ in extension method lookup, we can potentially change what extension method is resolved by overload resolution.\n\n```cs\nnamespace N1\n{\n    using N2;\n\n    public class C\n    {\n        public static void M()\n        {\n            Span<string> span = new string[0];\n            span.Test(); // Prints N2 today, N1 tomorrow\n        }\n    }\n\n    public static class N1Ext\n    {\n        public static void Test(this ReadOnlySpan<string> span)\n        {\n            Console.WriteLine(\"N1\");\n        }\n    }\n}\n\nnamespace N2\n{\n    public static class N2Ext\n    {\n        public static void Test(this Span<string> span)\n        {\n            Console.WriteLine(\"N2\");\n        }\n    }\n}\n```\n\n## Open questions\n\n### Unrestricted betterness rule\n\nShould we make [the betterness rule][betterness-rule] unconditional on LangVersion?\nThat would allow API authors to add new Span APIs where IEnumerable equivalents exist\nwithout breaking users on older LangVersions or other compilers or languages (e.g., VB).\nHowever, that would mean users could get different behavior after updating the toolset (without changing LangVersion or TargetFramework):\n- Compiler could choose different overloads (technically a breaking change, but hopefully those overloads would have equivalent behavior).\n- Other breaks could arise, unknown at this time.\n\nNote that [`OverloadResolutionPriorityAttribute`][overload-resolution-priority] cannot fully solve this\nbecause it's also ignored on older LangVersions.\nHowever, it should be possible to use it to avoid ambiguities from VB where the attribute should be recognized.\n\n### Ignoring more user-defined conversions\n\nWe defined a set of type pairs for which there are language-defined implicit and explicit span conversions.\nWhenever a language-defined span conversion exists from `T1` to `T2`, any user-defined conversion from `T1` to `T2` is [ignored][udc]\n(regardless of the span and user-defined conversion being implicit or explicit).\n\nNote that this includes all the conditions, so for example there is no span conversion from `Span<object>` to `ReadOnlySpan<string>`\n(there is a span conversion from `Span<T>` to `ReadOnlySpan<U>` but it must hold that `T : U`),\nhence a user-defined conversion would be considered between those types if it existed\n(that would have to be a specialized conversion like `Span<T>` to `ReadOnlySpan<string>` because conversion operators cannot have generic parameters).\n\nShould we ignore user-defined conversions also between other combinations of array/Span/ReadOnlySpan/string types\nwhere no corresponding language-defined span conversion exists?\nFor example, if there is a user-defined conversion from `ReadOnlySpan<T>` to `Span<T>`, should we ignore it?\n\nSpec possibilities to consider:\n\n1. > Whenever a span conversion exists from `T1` to `T2`, ignore any user-defined conversion from `T1` to `T2` *or from `T2` to `T1`*.\n2. > User-defined conversions are not considered when converting between\n   > - any single-dimensional `array_type` and `System.Span<T>`/`System.ReadOnlySpan<T>`,\n   > - any combination of `System.Span<T>`/`System.ReadOnlySpan<T>`,\n   > - `string` and `System.ReadOnlySpan<char>`.\n3. Like above but replacing the last bullet point with:\n   > - `string` and `System.Span<char>`/`System.ReadOnlySpan<char>`.\n4. Like above but replacing the last bullet point with:\n   > - `string` and `System.Span<T>`/`System.ReadOnlySpan<T>`.\n\nTechnically, the spec disallows some of these user-defined conversions to be even defined:\nit is not possible to define a user-defined operator between types for which a non-user-defined conversion exists ([§10.5.2][permitted-udcs]).\nBut Roslyn intentionally violates this part of the spec.\nAnd some conversions like between `Span` and `string` are allowed anyway\n(no language-defined conversion between these types exist).\n\nNevertheless, alternatively to just *ignoring* the conversions, we could *disallow* them to be defined at all\nand perhaps break out of the spec violation at least for these new span conversions,\ni.e., change Roslyn to actually report a compile-time error if these conversions are defined\n(likely except those already defined by the BCL).\n\n## Alternatives\n\nKeep things as they are.\n\n[standard-explicit-conversions]: https://github.com/dotnet/csharpstandard/blob/8c5e008e2fd6057e1bbe802a99f6ce93e5c29f64/standard/conversions.md#1043-standard-explicit-conversions\n[permitted-udcs]: https://github.com/dotnet/csharpstandard/blob/8c5e008e2fd6057e1bbe802a99f6ce93e5c29f64/standard/conversions.md#1052-permitted-user-defined-conversions\n[better-conversion-from-expression]: https://github.com/dotnet/csharpstandard/blob/8c5e008e2fd6057e1bbe802a99f6ce93e5c29f64/standard/expressions.md#12645-better-conversion-from-expression\n[better-conversion-target]: https://github.com/dotnet/csharpstandard/blob/8c5e008e2fd6057e1bbe802a99f6ce93e5c29f64/standard/expressions.md#12647-better-conversion-target\n[is-type-operator]: https://github.com/dotnet/csharpstandard/blob/8c5e008e2fd6057e1bbe802a99f6ce93e5c29f64/standard/expressions.md#1212121-the-is-type-operator\n\n[ce-or]: ../csharp-12.0/collection-expressions.md#overload-resolution\n[overload-resolution-priority]: ../csharp-13.0/overload-resolution-priority.md\n[better-collection-conversion-from-expression]: ../csharp-13.0/collection-expressions-better-conversion.md#detailed-design\n"
  },
  {
    "path": "proposals/csharp-14.0/ignored-directives.md",
    "content": "# Ignored directives for file-based apps\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/8617>\n\n## Summary\n\nAdd `#:` directive prefix to be used by tooling, but ignored by the language.\n\n```cs\n#!/usr/bin/dotnet run\n#:sdk      Microsoft.NET.Sdk.Web\n#:property TargetFramework=net11.0\n#:property LangVersion=preview\n#:package  System.CommandLine@2.0.0-*\n\nConsole.WriteLine(\"Hello, World!\");\n```\n\nSee the [SDK documentation for `dotnet run file.cs`](https://learn.microsoft.com/dotnet/csharp/language-reference/preprocessor-directives#file-based-apps) for more details on directives supported in file-based apps.\n\n## Motivation\n\nWe are adding `dotnet run file.cs` support [in .NET SDK][dotnet-run-file].\nReal-world file-based programs need to reference NuGet packages.\nIt would be also useful if it were possible to execute file-based programs directly like `./file.cs` when they have [the shebang directive][shebang] (`#!`).\n\nThe language should ignore these directives, but compiler implementations and other tooling can recognize them.\nWe already have similar directives in the language:\n- `#region`\n- `#pragma`: details are implementation specific\n- `#error version`: the `version` part is not in the spec, but Roslyn will report its version\n\n## Detailed design\n\nIntroduce new *ignored pre-processing directives* ([§6.5][directives]):\n\n```antlr\nPP_Kind\n    : ... // Existing directive kinds\n    | PP_Ignored\n    ;\n\nPP_Ignored\n    : PP_IgnoredToken Input_Character*\n    ;\n\nPP_IgnoredToken\n    : '!'\n    | ':'\n    ;\n```\n\nThese are parsed regardless of language version.\n\n### Restrictions\n\nIgnored directives must occur before the first token ([§6.4][tokens]) in the compilation unit, just like `#define`/`#undef` directives.\nThis improves readability (all package references and other configuration is in one place), tooling performance (no need to scan long files in full).\nIgnored directives must also occur before any `#if` directives because the tooling might not know the full set of conditional compilation symbols while parsing ignored directives.\n\nFurthermore, the compiler should report a warning if the `#!` directive is not placed at the first line and the first character in the file\n(not even a BOM marker can be in front of it), because otherwise shells won't recognize it.\n\nCompilers are also free to report errors if these directives are used in unsupported scenarios,\ne.g., Roslyn will report an error if these directives are present in a file compiled as part of \"project-based programs\" as opposed to \"file-based programs\"\n(and tooling will remove these directives when migrating file-based programs to project-based programs).\nIf needed, we might consider not reporting that error for the `#!` directive, as it might invoke some other tool than `dotnet run`, so there is no need to restrict it to scripts and file-based programs only.\n\nSimilarly, the compiler or SDK should still error/warn on unrecognized directives to \"reserve\" them for future use by the official .NET tooling.\n\n<!--\n## Drawbacks\n-->\n\n## Alternatives\n\n### Separate directives instead of one ignored prefix\n\nWe could add each ignored directive to the language instead of introducing one ignored prefix.\n- For `dotnet run file.cs` specifically, we might want to add only as few directives as possible,\n  and for anything more advanced, recommend users to eject to project-based programs instead\n  (i.e., avoid having two ways to configure everything).\n- In any case, it might be good if new directives are discussed and approved by the language design team\n  since they are part of the overall C# language experience.\n\n```cs\n#!/usr/bin/dotnet run\n#sdk      Microsoft.NET.Sdk.Web\n#property TargetFramework=net11.0\n#property LangVersion=preview\n#package  System.CommandLine@2.0.0-*\n#something // unrecognized directives would still be required by the language spec to be an error\n\nConsole.WriteLine(\"Hello, World!\");\n```\n\n### Other syntax forms\n\nOther syntax forms could be used except for shebang which shells recognize only by `#!`.\n\n#### Pragma\n\nWe could reuse `#pragma` directive although that's originally meant for compiler options, not SDK (project-wide) options.\n\n```cs\n#pragma package Microsoft.CodeAnalysis 4.14.0\n```\n\n#### Single directive\n\nWe could introduce only a single new directive for everything (packages, sdks, and possibly more in the future).\nFor example, `#r` is already supported by C# scripting and other existing tooling.\nHowever, the naming of the directive is less clear.\n\n```cs\n#r \"nuget: Microsoft.CodeAnalysis, 4.14.0\"\n```\n\n#### Sigil\n\nWe could reserve another sigil prefix (e.g., `#!`/`#@`/`#$`) for any directives that should be ignored by the language.\nNote that `#!` would be interpreted as shebang by shells if it is at the first line of the file.\n\n```cs\n#!/usr/bin/dotnet run\n##package Microsoft.CodeAnalysis 4.14.0\n```\n\n#### Comments\n\nWe could use comments instead of introducing new directives.\nReusing normal comments with `//#` might be confused with directives that have been commented out unless we use some other syntax like `//!` but both of these could be breaking.\nDocumentation XML comments are more verbose and we would need to ensure they do not apply to the class below them when placed at the top of the file.\n\n```cs\n//#package Microsoft.CodeAnalysis 4.14.0\n```\n\n```cs\n/// <package name=\"Microsoft.CodeAnalysis\" version=\"4.14.0\" />\n```\n\n<!--\n## Links\n-->\n\n[dotnet-run-file]: https://github.com/dotnet/sdk/pull/46915\n[shebang]: https://en.wikipedia.org/wiki/Shebang_%28Unix%29\n[tokens]: https://github.com/dotnet/csharpstandard/blob/f885375267570784d8d529d94893555494781abb/standard/lexical-structure.md#64-tokens\n[directives]: https://github.com/dotnet/csharpstandard/blob/f885375267570784d8d529d94893555494781abb/standard/lexical-structure.md#65-pre-processing-directives\n"
  },
  {
    "path": "proposals/csharp-14.0/null-conditional-assignment.md",
    "content": "# Null-conditional assignment\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/8677>\n\n## Summary\n[summary]: #summary\n\nPermits assignment to occur conditionally within a `a?.b` or `a?[b]` expression.\n\n```cs\nusing System;\n\nclass C\n{\n    public object obj;\n}\n\nvoid M(C? c)\n{\n    c?.obj = new object();\n}\n```\n\n```cs\nusing System;\n\nclass C\n{\n    public event Action E;\n}\n\nvoid M(C? c)\n{\n    c?.E += () => { Console.WriteLine(\"handled event E\"); };\n}\n```\n\n```cs\nvoid M(object[]? arr)\n{\n    arr?[42] = new object();\n}\n\n```\n## Motivation\n[motivation]: #motivation\n\nA variety of motivating use cases can be found in the championed issue. Major motivations include:\n1. Parity between properties and `Set()` methods.\n2. Attaching event handlers in UI code.\n\n## Detailed design\n[design]: #detailed-design\n\n- The right side of the assignment is only evaluated when the receiver of the conditional access is non-null.\n```cs\n// M() is only executed if 'a' is non-null.\n// note: the value of 'a.b' doesn't affect whether things are evaluated here.\na?.b = M();\n```\n\n- All forms of compound assignment are allowed.\n```cs\na?.b -= M(); // ok\na?.b += M(); // ok\n// etc.\n```\n\n- If the result of the expression is used, the expression's type must be known to be of a value type or a reference type. This is consistent with existing behaviors on conditional accesses.\n```cs\nclass C<T>\n{\n    public T? field;\n}\n\nvoid M1<T>(C<T>? c, T t)\n{\n    (c?.field = t).ToString(); // error: 'T' cannot be made nullable.\n    c?.field = t; // ok\n}\n```\n\n- Conditional access expressions are still not lvalues, and it's still not allowed to e.g. take a `ref` to them.\n```cs\nM(ref a?.b); // error\n```\n\n- It is not allowed to ref-assign to a conditional access. The main reason for this is that the only way you would conditionally access a ref variable is a ref field, and ref structs are forbidden from being used in nullable value types. If a valid scenario for a conditional ref-assignment came up in the future, we could add support at that time.\n```cs\nref struct RS\n{\n    public ref int b;\n}\n\nvoid M(RS a, ref int x)\n{\n  a?.b = ref x; // error: Operator '?' can't be applied to operand of type 'RS'.\n}\n```\n\n- It's not possible to e.g. assign to conditional accesses through deconstruction assignment. We anticipate it will be rare for people to want to do this, and not a significant drawback to need to do it over multiple separate assignment expressions instead.\n```cs\n(a?.b, c?.d) = (x, y); // error\n```\n\n- Increment/decrement operators are [not supported](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-10-28.md#increment-and-decrement-operators-in-null-conditional-access).\n```cs\na?.b++; // error\n--a?.b; // error\n```\n\n- This feature generally doesn't work when the receiver of the conditional access is a value type. This is because it will fall into one of the following two cases:\n```cs\nvoid Case1(MyStruct a)\n    => a?.b = c; // a?.b is not allowed when 'a' is of non-nullable value type\n\nvoid Case2(MyStruct? a)\n    => a?.b = c; // `a.Value` is not a variable, so there's no reasonable meaning to define for the assignment\n```\n[readonly-setter-calls-on-non-variables.md](https://github.com/dotnet/csharplang/blob/main/proposals/readonly-setter-calls-on-non-variables.md) proposes relaxing this, in which case we could define a reasonable behavior for `a?.b = c`, when `a` is a `System.Nullable<T>` and `b` is a property with a readonly setter.\n\n### Specification\nThe *null conditional assignment* grammar is defined as follows:\n\n```antlr\nnull_conditional_assignment\n    : null_conditional_member_access assignment_operator expression\n    : null_conditional_element_access assignment_operator expression\n```\nSee [§11.7.7](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1177-null-conditional-member-access) and [§11.7.11](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11711-null-conditional-element-access) for reference.\n\nWhen the *null conditional assignment* appears in an expression-statement, its semantics are as follows:\n- `P?.A = B` is equivalent to `if (P is not null) P.A = B;`, except that `P` is only evaluated once.\n- `P?[A] = B` is equivalent to `if (P is not null) P[A] = B`, except that `P` is only evaluated once.\n\nOtherwise, its semantics are as follows:\n- `P?.A = B` is equivalent to `(P is null) ? (T?)null : (P.A = B)`, where `T` is the result type of `P.A = B`, except that `P` is only evaluated once.\n- `P?[A] = B` is equivalent to `(P is null) ? (T?)null : (P[A] = B)`, where `T` is the result type of `P[A] = B`, except that `P` is only evaluated once.\n\n### Implementation\nThe grammar in the standard currently doesn't correspond strongly to the syntax design used in the implementation. We expect that to remain the case after this feature is implemented. The syntax design in the [implementation](https://github.com/dotnet/roslyn/blob/09408ab8a29e03caddfb11f29328c05169ac7cde/src/Compilers/CSharp/Portable/Syntax/Syntax.xml#L583-L607) isn't expected to actually change--only the way it is used will change. For example:\n\n```mermaid\ngraph TD;\nsubgraph ConditionalAccessExpression\n  whole[a?.b = c]\nend\nsubgraph  \n  subgraph WhenNotNull\n    whole-->whenNotNull[\".b = c\"];\n    whenNotNull-->.b;\n    whenNotNull-->eq[=];\n    whenNotNull-->c;\n  end\n  subgraph OperatorToken\n    whole-->?;\n  end\n  subgraph Expression\n    whole-->a;\n  end\nend\n```\n\n### Complex examples\n```cs\nclass C\n{\n    ref int M() => /*...*/;\n}\n\nvoid M1(C? c)\n{\n    c?.M() = 42; // equivalent to:\n    if (c is not null)\n        c.M() = 42;\n}\n\nint? M2(C? c)\n{\n    return c?.M() = 42; // equivalent to:\n    return c is null ? (int?)null : c.M() = 42;\n}\n```\n\n```cs\nM(a?.b?.c = d); // equivalent to:\nM(a is null\n    ? null\n    : (a.b is null\n        ? null\n        : (a.b.c = d)));\n```\n\n```cs\nreturn a?.b = c?.d = e?.f; // equivalent to:\nreturn a?.b = (c?.d = e?.f); // equivalent to:\nreturn a is null\n    ? null\n    : (a.b = c is null\n        ? null\n        : (c.d = e is null\n            ? null\n            : e.f));\n}\n```\n\n```cs\na?.b ??= c; // equivalent to:\nif (a is not null)\n{\n    if (a.b is null)\n    {\n        a.b = c;\n    }\n}\n\nreturn a?.b ??= c; // equivalent to:\nreturn a is null\n    ? null\n    : a.b is null\n        ? a.b = c\n        : a.b;\n```\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nThe choice to keep the assignment within the conditional access introduces some additional work for the IDE, which has many code paths which need to work backwards from an assignment to identifying the thing being assigned.\n\n## Alternatives\n[alternatives]: #alternatives\n\nWe could instead make the `?.` syntactically a child of the `=`. This makes it so any handling of `=` expressions needs to become aware of the conditionality of the right side in the presence of `?.` on the left. It also makes it so the structure of the syntax doesn't correspond as strongly to the semantics.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n## Design meetings\n\n* https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-04-27.md#null-conditional-assignment\n* https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-08-31.md#null-conditional-assignment\n* https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-10-26.md#null-conditional-assignment\n* https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-10-28.md#increment-and-decrement-operators-in-null-conditional-access\n"
  },
  {
    "path": "proposals/csharp-14.0/optional-and-named-parameters-in-expression-trees.md",
    "content": "# Support optional and named arguments in Expression trees\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9246\n\n## Summary\n[summary]: #summary\n\nSupport optional and named arguments in method calls in `Expression` trees\n\n## Motivation\n[motivation]: #motivation\n\nErrors are reported for calls in `Expression` trees when the call is missing an argument for an optional parameter, or when arguments are named.\n\nThis results in unnecessary code and differences for expressions within `Expression` trees. And lack of support for optional arguments can lead to breaking changes when a new overload with an optional parameter is applicable at an existing call site.\n\nThe compiler restrictions should be removed if not needed.\n\nFor example, compiling the following with the .NET 10 preview SDK results in errors currently.\n\n```csharp\nnamespace System\n{\n    public static class MemoryExtensions\n    {\n        public static bool Contains<T>(this ReadOnlySpan<T> span, T value, IEqualityComparer<T>? comparer = null);\n    }\n}\n\nExpression<Func<int?[], int, bool>> e;\n        \ne = (a, i) => a.Contains(i); // error CS0854: expression tree may not contain a call that uses optional arguments\ne = (a, i) => a.Contains(i, comparer: null); // error CS0853: expression tree may not contain a named argument specification\n```\n\n## Detailed design\n[design]: #design\n\nRemove the error reporting for these cases in `Expression` trees, and allow the existing method call rewriting to handle optional and named arguments.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\n## Alternatives\n[alternatives]: #alternatives\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\nIt's unclear why the restrictions were added originally. An initial investigation hasn't revealed an issue supporting these cases.\n\n## Design meetings\n[meetings]: #meetings\n\n*Based on a suggestion from @roji to support optional parameters.*\n"
  },
  {
    "path": "proposals/csharp-14.0/partial-events-and-constructors.md",
    "content": "# Partial Events and Constructors\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/9058>\n\n## Summary\n\nAllow the `partial` modifier on events and constructors to separate declaration and implementation parts,\nsimilar to [partial methods][partial-methods-ext] and [partial properties/indexers][partial-props].\n\n```cs\npartial class C\n{\n    partial C(int x, string y);\n    partial event Action<int, string> MyEvent;\n}\n\npartial class C\n{\n    partial C(int x, string y) { }\n    partial event Action<int, string> MyEvent\n    {\n        add { }\n        remove { }\n    }\n}\n```\n\n## Motivation\n\nC# already supports partial methods, properties, and indexers.\nPartial events and constructors are missing.\n\nPartial events would be useful for [weak event][weak-events] libraries, where the user could write definitions:\n\n```cs\npartial class C\n{\n    [WeakEvent]\n    partial event Action<int, string> MyEvent;\n\n    void M()\n    {\n        RaiseMyEvent(0, \"a\");\n    }\n}\n```\n\nAnd a library-provided source generator would provide implementations:\n\n```cs\npartial class C\n{\n    private readonly WeakEvent _myEvent;\n\n    partial event Action<int, string> MyEvent\n    {\n        add { _myEvent.Add(value); }\n        remove { _myEvent.Remove(value); }\n    }\n\n    protected void RaiseMyEvent(int x, string y)\n    {\n        _myEvent.Invoke(x, y);\n    }\n}\n```\n\nPartial events and partial constructors would be also useful for generating interop code like in [Xamarin][xamarin]\nwhere the user could write partial constructor and event definitions:\n\n```cs\npartial class AVAudioCompressedBuffer : AVAudioBuffer\n{\n    [Export(\"initWithFormat:packetCapacity:\")]\n    public partial AVAudioCompressedBuffer(AVAudioFormat format, uint packetCapacity);\n\n    [Export(\"create:\")]\n    public partial event EventHandler Created;\n}\n```\n\nAnd the source generator would generate the bindings (to Objective-C in this case):\n\n```cs\npartial class AVAudioCompressedBuffer : AVAudioBuffer\n{\n    [BindingImpl(BindingImplOptions.GeneratedCode | BindingImplOptions.Optimizable)]\n    public partial AVAudioCompressedBuffer(AVAudioFormat format, uint packetCapacity) : base(NSObjectFlag.Empty)\n    {\n        // Call Objective-C runtime:\n        InitializeHandle(\n            global::ObjCRuntime.NativeHandle_objc_msgSendSuper_NativeHandle_UInt32(\n                this.SuperHandle,\n                Selector.GetHandle(\"initWithFormat:packetCapacity:\"),\n                format.GetNonNullHandle(nameof(format)),\n                packetCapacity),\n            \"initWithFormat:packetCapacity:\");\n    }\n\n    public partial event EventHandler Created\n    {\n        add { /* ... */ }\n        remove { /* ... */ }\n    }\n}\n```\n\n## Detailed design\n\n### General\n\nEvent declaration syntax ([§15.8.1][event-syntax]) is extended to allow the `partial` modifier:\n\n```diff\n event_declaration\n-    : attributes? event_modifier* 'event' type variable_declarators ';'\n+    : attributes? event_modifier* 'partial'? 'event' type variable_declarators ';'\n-    | attributes? event_modifier* 'event' type member_name\n+    | attributes? event_modifier* 'partial'? 'event' type member_name\n         '{' event_accessor_declarations '}'\n     ;\n```\n\nInstance constructor declaration syntax ([§15.11.1][ctor-syntax]) is extended to allow the `partial` modifier:\n\n```diff\n constructor_declaration\n-    : attributes? constructor_modifier* constructor_declarator constructor_body\n+    : attributes? constructor_modifier* 'partial'? constructor_declarator constructor_body\n     ;\n```\n\nNote that there is [a proposal][partial-ordering] to allow the `partial` modifier anywhere among modifiers,\nrather than only as the last one (also for method, property, and type declarations).\n\nAn event declaration with the `partial` modifier is said to be a *partial event declaration*\nand it is associated with one or more *partial events* with the specified names\n(note that one event declaration without accessors can define multiple events).\n\nA constructor declaration with the `partial` modifier is said to be a *partial constructor declaration*\nand it is associated with a *partial constructor* with the specified signature.\n\nA partial event declaration is said to be an *implementing declaration*\nwhen it specifies the `event_accessor_declarations` or it has the `extern` modifier.\nOtherwise, it is a *defining declaration*.\n\nA partial constructor declaration is said to be a *defining declaration*\nwhen it has a semicolon body and it lacks the `extern` modifier.\nOtherwise, it is an *implementing declaration*.\n\n```cs\npartial class C\n{\n    // defining declarations\n    partial C();\n    partial C(int x);\n    partial event Action E, F;\n\n    // implementing declarations\n    partial C() { }\n    partial C(int x) { }\n    partial event Action E { add { } remove { } }\n    partial event Action F { add { } remove { } }\n}\n```\n\nOnly the defining declaration of a partial member participates in lookup\nand is considered at use sites and for emitting the metadata.\n(Except for documentation comments as detailed [below](#documentation-comments).)\nThe implementing declaration signature is used for nullable analysis of the associated bodies.\n\nA partial event or constructor:\n- May only be declared as a member of a partial type.\n- Must have one defining and one implementing declaration.\n- Is not permitted to have the `abstract` modifier.\n- Cannot explicitly implement an interface member.\n\nA partial event is not field-like ([§15.8.2][event-field-like]), i.e.:\n- It does not have any backing storage or accessors generated by the compiler.\n- It can only be used in `+=` and `-=` operations, not as a value.\n\nA defining partial constructor declaration cannot have a constructor initializer\n(`: this()` or `: base()`; [§15.11.2][ctor-init]).\n\n### Parsing break\n\nAllowing the `partial` modifier in more contexts is a breaking change:\n\n```cs\nclass C\n{\n    partial F() => new partial(); // previously a method, now a constructor\n    @partial F() => new partial(); // workaround to keep it a method\n}\n\nclass partial { }\n```\n\nTo simplify the language parser,\nthe `partial` modifier is accepted at any method-like declaration\n(i.e., local functions and top-level script methods, as well),\neven though we do not specify the grammar changes explicitly above.\n\n### Attributes\n\nThe attributes of the resulting event or constructor are the combined attributes of the partial declarations in the corresponding positions.\nThe combined attributes are concatenated in an unspecified order and duplicates are not removed.\n\nThe `method` *attribute_target* ([§22.3][attribute-spec]) is ignored on partial event declarations.\nAccessor attributes are used only from accessor declarations (which can be present only under the implementing declaration).\nNote that `param` and `return` *attribute_target*s are already ignored on all event declarations.\n\nCaller-info attributes on the implementing declaration are ignored by the compiler as specified\nby the partial properties proposal in section [Caller-info attributes][partial-props-caller-info]\n(notice that it applies to all partial *members* which includes partial events and constructors).\n\n### Signatures\n\nBoth declarations of a partial member must have matching signatures [similar to partial properties][partial-props-signatures]:\n1. Type and ref kind differences between partial declarations which are significant to the runtime result in a compile-time error.\n2. Differences in tuple element names between partial declarations result in a compile-time error.\n3. The declarations must have the same modifiers, though the modifiers may appear in a different order.\n   - Exception: this does not apply to the `extern` modifier which may only appear on the implementing declaration.\n4. All other syntactic differences in the signatures of partial declarations result in a compile-time warning, with the following exceptions:\n   - Attribute lists do not need to match as described [above](#attributes).\n   - Nullable context differences (such as oblivious vs. annotated) do not cause warnings.\n   - Default parameter values do not need to match, but a warning is reported when the implementing constructor declaration has default parameter values\n     (because those would be ignored since only the defining declaration participates in lookup).\n5. A warning occurs when parameter names differ across defining and implementing constructor declarations.\n6. Nullability differences which do not involve oblivious nullability result in warnings.\n\n### Documentation comments\n\nIt is permitted to include doc comments on both the defining and implementing declaration.\nNote that doc comments are not supported on event accessors.\n\nWhen doc comments are present on only one of the declarations of a partial member, those doc comments are used normally\n(surfaced through Roslyn APIs, emitted to the documentation XML file).\n\nWhen doc comments are present on both declarations of a partial member,\nall the doc comments on the defining declaration are dropped,\nand only the doc comments on the implementing declaration are used.\n\nWhen parameter names differ between declarations of a partial member,\n`paramref` elements use the parameter names from the declaration associated with the documentation comment in source code.\nFor example, a `paramref` on a doc comment placed on an implementing declaration\nrefers to the parameter symbols of the implementing declaration using their parameter names.\nThis can be confusing, because the metadata signature will use parameter names from the defining declaration.\nIt is recommended to ensure that parameter names match across the declarations of a partial member to avoid this confusion.\n\n<!-- ## Drawbacks -->\n\n<!-- ## Alternatives -->\n\n## Open questions\n\n### Member kinds\n\nDo we want partial events, constructors, operators, fields?\nWe propose the first two member kinds, but any other subset could be considered.\n\nPartial *primary* constructors could be also considered,\ne.g., permitting the user to have the same parameter list on multiple partial type declarations.\n\n### Attribute locations\n\nShould we recognize the `[method:]` attribute target specifier for partial events (or just the defining declarations)?\nThen the resulting accessor attributes would be the concatenation of `method`-targeting attributes from both (or just the defining) declaration parts\nplus self-targeting and `method`-targeting attributes from the accessors of the implementing declaration.\nCombining attributes from different declaration kinds would be unprecedented and indeed\nthe current implementation of attribute matching in Roslyn does not support that.\n\nWe can also consider recognizing `[param:]` and `[return:]`, not just on partial events, but all field-like and extern events.\nFor more details, see https://github.com/dotnet/roslyn/issues/77254.\n\n<!--------\n## Links\n--------->\n\n[partial-methods-ext]: ../csharp-9.0/extending-partial-methods.md\n[partial-props]: ../csharp-13.0/partial-properties.md\n[partial-props-caller-info]: ../csharp-13.0/partial-properties.md#caller-info-attributes\n[partial-props-signatures]: ../csharp-13.0/partial-properties.md#matching-signatures\n[partial-events-discussion]: https://github.com/dotnet/csharplang/discussions/8064\n[partial-ordering]: https://github.com/dotnet/csharplang/issues/8966\n[xamarin]: https://github.com/xamarin/xamarin-macios/issues/21308#issuecomment-2447535524\n[weak-events]: https://learn.microsoft.com/dotNet/api/system.windows.weakeventmanager\n[event-syntax]: https://github.com/dotnet/csharpstandard/blob/f3c66477dc2d0a76d5c278e457a63c1695ddae08/standard/classes.md#1581-general\n[event-field-like]: https://github.com/dotnet/csharpstandard/blob/f3c66477dc2d0a76d5c278e457a63c1695ddae08/standard/classes.md#1582-field-like-events\n[ctor-syntax]: https://github.com/dotnet/csharpstandard/blob/f3c66477dc2d0a76d5c278e457a63c1695ddae08/standard/classes.md#1511-instance-constructors\n[ctor-init]: https://github.com/dotnet/csharpstandard/blob/f3c66477dc2d0a76d5c278e457a63c1695ddae08/standard/classes.md#15112-constructor-initializers\n[ctor-var-init]: https://github.com/dotnet/csharpstandard/blob/f3c66477dc2d0a76d5c278e457a63c1695ddae08/standard/classes.md#15113-instance-variable-initializers\n[attribute-spec]: https://github.com/dotnet/csharpstandard/blob/f3c66477dc2d0a76d5c278e457a63c1695ddae08/standard/attributes.md#223-attribute-specification\n"
  },
  {
    "path": "proposals/csharp-14.0/simple-lambda-parameters-with-modifiers.md",
    "content": "# Simple lambda parameters with modifiers\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/8637>\n\n## Summary\n\nAllow lambda parameters to be declared with modifiers without requiring their type names. For example, `(ref entry) =>` rather than `(ref FileSystemEntry entry) =>`.\n\nAs another example, given this delegate:\n```cs\ndelegate bool TryParse<T>(string text, out T result);\n```\n\nAllow this simplified parameter declaration:\n```cs\nTryParse<int> parse1 = (text, out result) => Int32.TryParse(text, out result);\n```\n\nCurrently only this is valid:\n```cs\nTryParse<int> parse2 = (string text, out int result) => Int32.TryParse(text, out result);\n```\n\n## Detailed design\n\n### Grammar\n\nNo changes.  The [latest lambda grammar](../csharp-12.0/lambda-method-group-defaults.md#detailed-design) is:\n\n```g4\nlambda_expression\n  : modifier* identifier '=>' (block | expression)\n  | attribute_list* modifier* type? lambda_parameter_list '=>' (block | expression)\n  ;\n\nlambda_parameter_list\n  : lambda_parameters (',' parameter_array)?\n  | parameter_array\n  ;\n\nlambda_parameter\n  : identifier\n  | attribute_list* modifier* type? identifier default_argument?\n  ;\n```\n\nThis grammar already considers `modifiers* identifier` to be syntactically legal.\n\n### Notes\n\n1. This does not apply to a lambda without a parameter list. `ref x => x.ToString()` would not be legal.\n1. A lambda parameter list still cannot mix `implicit_anonymous_function_parameter` and `explicit_anonymous_function_parameter` parameters.\n1. `(ref readonly p) =>`, `(scoped ref p) =>`, and `(scoped ref readonly p) =>` will be allowed, just as they are with explicit parameters, due to:\n   - [Low-level struct improvements](../csharp-11.0/low-level-struct-improvements.md#syntax) in C# 11\n   - [`ref readonly` parameters](../csharp-12.0/ref-readonly-parameters.md#parameter-declarations) in C# 12\n1. The presence/absence of a type has no impact on whether a modifier is required or optional.  In other words, if a modifier was required\n   with a type present, it is still required with the type absent.  Similarly, if a modifier was optional with a type present, it is \n   optional with the type absent.\n\n### Semantics\n\nhttps://learn.microsoft.com/dotnet/csharp/language-reference/language-specification/expressions#12192-anonymous-function-signatures is updated as follows:\n\nIn a `lambda_parameter_list` all `lambda_parameter` elements must either have a `type`\npresent or not have a `type` present.  The former is an \"explicitly\ntyped parameter list\", while the latter is an \"implicitly typed\nparameter list\".\n\nParameters in an implicitly typed parameter list cannot have a `default_argument`.  They\ncan have an `attribute_list`.\n\nThe following change is required to [anonymous function conversions](../csharp-12.0/lambda-method-group-defaults.md#detailed-design):\n\n[...]\n> If F has an explicitly **or implicitly typed parameter list**, each parameter in D has the same type and\n> modifiers as the corresponding parameter in F ignoring params modifiers and default values.\n\n### Notes/Clarifications\n\n`scoped` and `params` are allowed as explicit modifiers in a lambda without an explicit type present. Semantics\nremain the same for both.  Specifically, neither is part of the determination made\n[in](https://learn.microsoft.com/dotnet/csharp/language-reference/language-specification/expressions#12192-anonymous-function-signatures):\n\n> If an anonymous function has an explicit_anonymous_function_signature, then the set of compatible delegate\n> types and expression tree types is restricted to those that have the same parameter types and modifiers in\n> the same order.\n\nThe only modifiers that restrict compatible delegate types are `ref`, `out`, `in` and `ref readonly`. \nFor example, in an explicitly typed lambda, the following is currently ambiguous:\n\n```c#\ndelegate void D<T>(scoped T t) where T : allows ref struct;\ndelegate void E<T>(T t) where T : allows ref struct;\n\nclass C\n{\n    void M<T>() where T : allows ref struct\n    {\n        // error CS0121: The call is ambiguous between the following methods or properties: 'C.M1<T>(D<T>)' and 'C.M1<T>(E<T>)'\n        // despite the presence of the `scoped` keyword.\n        M1<T>((scoped T t) => { });\n    }\n\n    void M1<T>(D<T> d) where T : allows ref struct\n    {\n    }\n\n    void M1<T>(E<T> d) where T : allows ref struct\n    {\n    }\n}\n```\n\nThis remains the case when using implicitly typed lambdas:\n\n```c#\ndelegate void D<T>(scoped T t) where T : allows ref struct;\ndelegate void E<T>(T t) where T : allows ref struct;\n\nclass C\n{\n    void M<T>() where T : allows ref struct\n    {\n        // This will remain ambiguous.  'scoped' will not be used to restrict the set of delegates.\n        M1<T>((scoped t) => { });\n    }\n\n    void M1<T>(D<T> d) where T : allows ref struct\n    {\n    }\n\n    void M1<T>(E<T> d) where T : allows ref struct\n    {\n    }\n}\n```\n\n### Open Questions\n\n1. Should `scoped` *always* be a modifier in a lambda in C# 14?  This matters for a case like:\n\n   ```C#\n   M((scoped s = default) => { });\n   ```\n\n   In this case, this is does *not* fall under the 'simple lambda parameter' spec, as a 'simple lambda'\n   cannot contain a initializer (`= default`).  As such, `scoped` here is treated as a `type` (like it was\n   in C# 13).  Do we want to maintain this?  Or would it just be simpler to have a more blanket rule that\n   `scoped` is always modifier, and thus would still be a modifier here on an invalid simple parameter?\n\n   Recomendation: Make this a modifier.  We already dissuade people from types that are all lowercase,\n   *AND* we've made it illegal to make a type called `scoped` in C# as well.  So this could only be some\n   sort of case of referencing a type from another library.  The workaround is trivial if you did somehow\n   hit this.  Just use `@scoped` to make this a type name instead of a modifier.\n\n2. Allow `params` in a simple lambda parameter? Prior lambda work already added support for `params T[] values`\n   in a lambda.  This modifier is optional, and the lambda and the original delegate are allowed to have a\n   mismatch on this modifier (though we warn if the delegate does not have the modifier and the lambda does).\n   Should we continue allowing this with a simple lambda parameter.  e.g. `M((params values) => { ... })`\n\n   Recomendation: Yes.  Allow this.  The purpose of this spec is to allow just dropping the 'type' from a\n   lambda parameter, while keeping the modifiers.  This is just another case of that.  This also just falls\n   out from the impl (as did supporting attributes on these parameters), so it's more work to try to block\n   this.\n\n   Conclusion 1/15/2025: No. This will always be an error. There do not appear to be any useful cases for this\n   and no one is asking for this.  It is easier and safer to restrict this non-sensical case from the start.\n   If relevant use cases are presented, we can reconsider.\n\n3. Does 'scoped' influence overload resolution?  For example, if there were multiple overloads of a delegate\n   and one had a 'scoped' parameter, while the other did not, would the presense of 'scoped' influencce\n   overload resolution.\n\n   Recomendation: No.  Do not have 'scoped' influence overload resolution.  That is *already* how things\n   work with normal *explicitly typed* lambdas.  For example:\n\n   ```c#\n   delegate void D<T>(scoped T t) where T : allows ref struct;\n   delegate void E<T>(T t) where T : allows ref struct;\n\n   class C\n   {\n       void M<T>() where T : allows ref struct\n       {\n           M1<T>((scoped T t) => { });\n       }\n\n       void M1<T>(D<T> d) where T : allows ref struct\n       {\n       }\n\n       void M1<T>(E<T> d) where T : allows ref struct\n       {\n       }\n   }\n   ```\n\n   This is ambiguous today.  Despite having 'scoped' on `D<T>` and 'scoped' in the lambda parameter, we\n   do not resolve this.  We do not believe this should change with implicitly typed lambdas.\n   \n   Conclusion 1/15/2025: The above will hold true for 'simple lambas' as well.  'scoped' will not influence\n   overload resolution (while `ref` and `out` will continue to do so).\n\n5. Allow '(scoped x) => ...' lambdas?\n\n   Recommendation: Yes.  If we do not allow this then we can end up in scenarios where a user can write\n   the full explicitly typed lambda, but not the implicitly typed version.  For example:\n\n   ```c#\n   delegate ReadOnlySpan<int> D(scoped ReadOnlySpan<int> x);\n\n   class C\n   {\n       static void Main(string[] args)\n       {\n           D d = (scoped ReadOnlySpan<int> x) => throw null!;\n           D d = (ReadOnlySpan<int> x) => throw null!; // error! 'scoped' is required\n       }\n   }\n   ```\n\n   Removing 'scoped' here would cause an error (the language requires the correspondance in this case between\n   the lambda and delegate.  As we want the user to be able to write lambdas like this, without specifying\n   the type explicitly, that then means that `(scoped x) => ...` needs to be allowed. \n\n   Conclusion 1/15/2025: We will allow `(scoped x) => ...` lambdas.\n"
  },
  {
    "path": "proposals/csharp-14.0/unbound-generic-types-in-nameof.md",
    "content": "# Unbound generic types in `nameof`\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/8662>\n\n## Summary\n\nAllows unbound generic types to be used with `nameof`, as in `nameof(List<>)` to obtain the string `\"List\"`,\nrather than having to specify an unused generic type argument in order to obtain the same string.\n\n## Motivation\n\nThis is a small feature that removes a common frustration: \"why do I have to pick a generic type argument when\nthe choice has no effect on the evaluation of the expression?\" It's very odd to require something to be specified\nwithin an operand when it has no impact on the result. Notably, `typeof` does not suffer from this limitation.\n\nThis is also not simply about brevity and simplicity. Once some arbitrary type argument has been chosen in a\n`nameof` expression, such as `object?`, changing a constraint on a type parameter can break uses of `nameof`\nunnecessarily. Insult becomes added to injury in this scenario. Satisfying the type parameter can sometimes\nrequire declaring a dummy class to implement an interface which is constraining the type parameter. Now there's\nunused metadata and a strange name invented, all for the purpose of adding a type argument to the `nameof`\nexpression, a type argument which `nameof` will ultimately ignore even though it requires it.\n\nIn some rarer cases, with a generic class constraint, it's not even _possible_ to use `nameof` because it's not\npossible to inherit from a base class which is used as a generic constraint, due to the base class having an\ninternal constructor or internal abstract member.\n\nA simple tweak allows this to fall out in the language, with minimal implementation complexity in the compiler.\n\n## Description\n\nUnbound type names become available for use with `nameof`:\n\n- `nameof(A<>)` evaluates to `\"A\"`\n- `nameof(Dictionary<,>)` evaluates to `\"Dictionary\"`\n\nAdditionally, chains of members will be able to be accessed on unbound types, just like on bound types:\n\n```cs\nclass A<T>\n{\n    public List<T> B { get; }\n}\n```\n\n- `nameof(A<>.B)` evaluates to `\"B\"`\n- `nameof(A<>.B.Count)` evaluates to `\"Count\"`\n\nEven members of generic type parameters can be accessed, consistent with how `nameof` already works when the\ntype is not unbound. Since the type is unbound, there is no type information on these members beyond what\n`System.Object` or any additional generic constraints provide.\n\n```cs\nclass A<TItem, TCollection> where TCollection : IReadOnlyCollection<TItem>\n{\n    public TCollection B { get; }\n}\n```\n\n- `nameof(A<,>.B)` evaluates to `\"B\"`\n- `nameof(A<,>.B.Count)` evaluates to `\"Count\"`.\n\n### Not supported\n\n1. Support is not included for nesting an unbound type as a type argument to another generic type, such as\n   `A<B<>>` or `A<B<>>.C.D`. Even though this could be logically implemented, such expressions have no precedent\n   in the language, and there is not sufficient motivation to introduce it:\n\n   - `A<B<>>` provides no benefits over `A<>`, and `A<B<>>.C` provides no benefits over `A<>.C`.\n\n   - If `C` returns the `T` of `A<T>`, `A<B<>>.C.D` can be written more directly as `B<>.D`. If it\n     returns some other type, then `A<B<>>.C.D` provides no benefits over `A<>.C.D`.\n\n   - `typeof()` has the same restrictions.\n\n2. Support is not included for partially unbound types, such as `Dictionary<int,>`. Similarly, such expressions\n   have no precedent in the language, and there is not sufficient motivation. That form provides no benefits over\n   `Dictionary<,>`, and accessing members of `T`-returning members can be written more directly without wrapping\n   in a partially unbound type.\n\n## Detailed design\n\n### Grammar changes\n\n```diff\nnameof_expression\n    : 'nameof' '(' named_entity ')'\n    ;\n    \nnamed_entity\n-   : named_entity_target ('.' identifier type_argument_list?)*\n+   : named_entity_target ('.' identifier (type_argument_list | generic_dimension_specifier)?)*\n    ;\n    \nnamed_entity_target\n    : simple_name\n    | 'this'\n    | 'base'\n    | predefined_type \n    | qualified_alias_member\n    ;\n\nsimple_name\n-   : identifier type_argument_list?\n+   : identifier (type_argument_list | generic_dimension_specifier)?\n    ;\n\ngeneric_dimension_specifier\n    : '<' ','* '>'\n```\n\nThis now allows names like `X<>` or `X<,>` to be considered simple names, where they were previously only\nsupported as `unbound_type_name`s within a `typeof` expression.\n\n### Semantic changes\n\nIt is an error to use `generic_dimension_specifier` outside of a `typeof` or `nameof` expression.  Within\neither of those expressions it is an error to use `generic_dimension_specifier` within a `type_argument_list`,\n`array_type`, `pointer_type` or `nullable_type`.  In other words the following are all illegal:\n\n```c#\n// Illegal, not inside `nameof` or `typeof`\nvar v = SomeType<>.StaticMember;\n```\n\n```c#\n// All illegal\nvar v = typeof(List<>[]);\nvar v = typeof(List<>*);\nvar v = typeof((List<> a, int b));\n```\n\nNote: The above rules effectively serve to make it so that `generic_dimension_specifier` cannot show up within\nanother type.  However, at the top level, where the specifier is allowed, it is fine to mix and match with normal\n`type_argument_list`s.  For example, the following are legal:\n\n```c#\nvar v = (nameof(X<>.Y<int>));\nvar v = (nameof(X<int>.Y<>));\n```\n\nMember lookup on an unbound type expression within a `nameof` will be performed the same way as for a `this`\nexpression within that type declaration (modulo performing accessibility checks at the callsite).  In other\nwords lookup off of `List<>` in `nameof(List<>...)` works the same as lookup off of `this` within the `class List<T>`\ntype itself.\n\nNo change is needed for the cases listed in the [Not supported](#not-supported) section. They already provide\nthe same errors for `nameof` expressions as they do for `typeof`.\n\nNo change is needed when the syntax `nameof` binds to a method named 'nameof' rather than being the contextual\nkeyword `nameof`. Passing any type expression to a method results in \"CS0119: '...' is a type, which is not\nvalid in the given context.\" This already covers unbound generic type expressions.\n"
  },
  {
    "path": "proposals/csharp-14.0/user-defined-compound-assignment.md",
    "content": "# User Defined Compound Assignment Operators\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9101\n\n## Summary\n[summary]: #summary\n\nAllow user types to customize behavior of compound assignment operators in a way that the target of the assignment is\nmodified in-place.\n\n## Motivation\n[motivation]: #motivation\n\nC# provides support for the developer overloading operator implementations for user-defined type.\nAdditionally, it provides support for \"compound assignment operators\" which allow the user to write\ncode similarly to `x += y` rather than `x = x + y`. However, the language does not currently allow\nfor the developer to overload these compound assignment operators and while the default behavior\ndoes the right thing, especially as it pertains to immutable value types, it is not always\n\"optimal\".\n\nGiven the following example\n``` C#\nclass C1\n{\n    static void Main()\n    {\n        var c1 = new C1();\n        c1 += 1;\n        System.Console.Write(c1);\n    }\n    \n    public static C1 operator+(C1 x, int y) => new C1();\n}\n```\n\nwith the current language rules, compound assignment operator `c1 += 1` invokes user defined `+` operator\nand then assigns its return value to the local variable `c1`. Note that operator implementation must allocate\nand return a new instance of `C1`, while, from the consumer's perspective, an in-place change to the original\ninstance of `C1` instead would work as good (it is not used after the assignment), with an additional benefit of\navoiding an extra allocation. \n\nWhen a program utilizes a compound assignment operation, the most common effect is that the original value is\n\"lost\" and is no longer available to the program. With types which have large data (such as BigInteger, Tensors, etc.)\nthe cost of producing a net new destination, iterating, and copying the memory tends to be fairly expensive.\nAn in-place mutation would allow skipping this expense in many cases, which can provide significant improvements\nto such scenarios.\n\nTherefore, it may be beneficial for C# to allow user types to\ncustomize behavior of compound assignment operators and optimize scenarios that would otherwise need to allocate\nand copy.\n\n## Detailed design\n[design]: #detailed-design\n\n### Syntax\n\nGrammar at https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#15101-general is adjusted as follows.\n\nOperators are declared using *operator_declaration*s:\n```diff\noperator_declaration\n    : attributes? operator_modifier+ operator_declarator operator_body\n    ;\n\noperator_modifier\n    : 'public'\n    | 'static'\n    | 'extern'\n    | unsafe_modifier   // unsafe code support\n    | 'abstract'\n    | 'virtual'\n    | 'sealed'\n+   | 'override'\n+   | 'new'\n+   | 'readonly'\n    ;\n\noperator_declarator\n    : unary_operator_declarator\n    | binary_operator_declarator\n    | conversion_operator_declarator\n+   | increment_operator_declarator\n+   | compound_assignment_operator_declarator\n    ;\n\nunary_operator_declarator\n    : type 'operator' overloadable_unary_operator '(' fixed_parameter ')'\n    ;\n\nlogical_negation_operator\n    : '!'\n    ;\n\noverloadable_unary_operator\n-   : '+' | 'checked'? '-' | logical_negation_operator | '~' | 'checked'? '++' | 'checked'? '--' | 'true' | 'false'\n+   : '+' | 'checked'? '-' | logical_negation_operator | '~' | 'true' | 'false'\n    ;\n\nbinary_operator_declarator\n    : type 'operator' overloadable_binary_operator\n        '(' fixed_parameter ',' fixed_parameter ')'\n    ;\n\noverloadable_binary_operator\n    : 'checked'? '+'  | 'checked'? '-'  | 'checked'? '*'  | 'checked'? '/'  | '%'  | '&' | '|' | '^'  | '<<'\n    | right_shift | '==' | '!=' | '>' | '<' | '>=' | '<='\n    ;\n\nconversion_operator_declarator\n    : 'implicit' 'operator' type '(' fixed_parameter ')'\n    | 'explicit' 'operator' type '(' fixed_parameter ')'\n    ;\n\n+increment_operator_declarator\n+   : type 'operator' overloadable_increment_operator '(' fixed_parameter ')'\n+   | 'void' 'operator' overloadable_increment_operator '(' ')'\n+   ;\n\n+overloadable_increment_operator\n+   : 'checked'? '++' | 'checked'? '--'\n+    ;\n\n+compound_assignment_operator_declarator\n+   : 'void' 'operator' overloadable_compound_assignment_operator\n+       '(' fixed_parameter ')'\n+   ;\n\n+overloadable_compound_assignment_operator\n+   : 'checked'? '+=' | 'checked'? '-=' | 'checked'? '*=' | 'checked'? '/=' | '%=' | '&=' | '|=' | '^=' | '<<='\n+   | right_shift_assignment\n+   | unsigned_right_shift_assignment\n+   ;\n\noperator_body\n    : block\n    | '=>' expression ';'\n    | ';'\n    ;\n```\n\nThere are five categories of overloadable operators: [unary operators](#unary-operators), [binary operators](#binary-operators),\n[conversion operators](#conversion-operators), [increment operators](#increment-operators), [compound assignment operators](#compound-assignment-operators).\n\n>The following rules apply to all operator declarations:\n>\n>- An operator declaration shall include ~~both~~ a `public` ~~and a `static`~~ modifier.\n\nCompound assignment and instance increment operators can hide operators declared in a base class. Therefore,\nthe following paragraph is no longer accurate and should either be adjusted accordingly, or it can be removed: \n>Because operator declarations always require the class or struct in which the operator is declared to participate in the signature of the operator,\nit is not possible for an operator declared in a derived class to hide an operator declared in a base class. Thus, the `new` modifier is never\nrequired, and therefore never permitted, in an operator declaration.\n\n### Unary operators\n[unary-operators]: #unary-operators\n\nSee https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#15102-unary-operators.\n\nAn operator declaration shall include a `static` modifier and shall not include an `override` modifier.\n\nThe following bullet point is removed:\n>- A unary `++` or `--` operator shall take a single parameter of type `T` or `T?` and shall return that same type or a type derived from it.\n\nThe following paragraph is adjusted to no longer mention `++` and `--` operator tokens:\n> The signature of a unary operator consists of the operator token (`+`, `-`, `!`, `~`, `++`, `--`, `true`, or `false`) and the type of the single parameter. The return type is not part of a unary operator’s signature, nor is the name of the parameter.\n\nAn example in the section should be adjusted to not use a user defined increment operator. \n\n### Binary operators\n[binary-operators]: #binary-operators\n\nSee https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#15103-binary-operators.\n\nAn operator declaration shall include a `static` modifier and shall not include an `override` modifier.\n\n### Conversion operators\n[conversion-operators]: #conversion-operators\n\nSee https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#15104-conversion-operators.\n\nAn operator declaration shall include a `static` modifier and shall not include an `override` modifier.\n\n### Increment operators\n[increment-operators]: #increment-operators\n\nThe following rules apply to static increment operator declarations, where `T` denotes the instance type of the class or struct that contains the operator declaration:\n\n- An operator declaration shall include a `static` modifier and shall not include an `override` modifier.\n- An operator shall take a single parameter of type `T` or `T?` and shall return that same type or a type derived from it.\n\nThe signature of a static increment operator consists of the operator tokens ('checked'? `++`, 'checked'? `--`) and the type of the single parameter.\nThe return type is not part of a static increment operator’s signature, nor is the name of the parameter.\n\nStatic increment operators are very similar to [unary operators](#unary-operators).\n\nThe following rules apply to instance increment operator declarations:\n- An operator declaration shall not include a `static` modifier.\n- An operator shall take no parameters.\n- An operator shall have `void` return type.\n\nEffectively, an instance increment operator is a void returning instance method that has no parameters and\nhas a special name in metadata.\n\nThe signature of an instance increment operator consists of the operator tokens ('checked'? '++' | 'checked'? '--').\n\nA `checked operator` declaration requires a pair-wise declaration of a `regular operator`. A compile-time error occurs otherwise. \nSee also ../csharp-11.0/checked-user-defined-operators.md#semantics.\n\nThe purpose of the method is to adjust the value of the instance to result of the requested increment operation,\nwhatever that means in context of the declaring type.\n\nExample:\n``` C#\nclass C1\n{\n    public int Value;\n\n    public void operator ++()\n    {\n        Value++;\n    }\n}\n```\n\nAn instance increment operator can override an operator with the same signature declared in a base class,\nan `override` modifier can be used for this purpose.\n\nThe following \"reserved\" special names should be added to ECMA-335 to support instance versions of increment/decrement operators:\n| Name | Operator |\n| -----| -------- |\n|op_DecrementAssignment| `--` |\n|op_IncrementAssignment| `++` |\n|op_CheckedDecrementAssignment| checked `--` |\n|op_CheckedIncrementAssignment| checked `++` |\n\n### Compound assignment operators\n[compound-assignment-operators]: #compound-assignment-operators\n\nThe following rules apply to compound assignment operator declarations:\n- An operator declaration shall not include a `static` modifier.\n- An operator shall take one parameter.\n- An operator shall have `void` return type.\n\nEffectively, a compound assignment operator is a void returning instance method that takes one parameter and\nhas a special name in metadata.\n\nThe signature of a compound assignment operator consists of the operator tokens\n('checked'? '+=', 'checked'? '-=', 'checked'? '*=', 'checked'? '/=', '%=', '&=', '|=', '^=', '<<=', right_shift_assignment, unsigned_right_shift_assignment) and\nthe type of the single parameter. The name of the parameter is not part of a compound assignment operator’s signature.\n\nA `checked operator` declaration requires a pair-wise declaration of a `regular operator`. A compile-time error occurs otherwise.\nSee also ../csharp-11.0/checked-user-defined-operators.md#semantics.\n\nThe purpose of the method is to adjust the value of the instance to result of ```<instance> <binary operator token> parameter```.\n\nExample:\n``` C#\nclass C1\n{\n    public int Value;\n\n    public void operator +=(int x)\n    {\n        Value+=x;\n    }\n}\n```\n\nA compound assignment operator can override an operator with the same signature declared in a base class,\nan `override` modifier can be used for this purpose.\n\nECMA-335 already \"reserved\" the following special names for user defined increment operators:\n| Name | Operator |\n| -----| -------- |\n|op_AdditionAssignment|'+=' |\n|op_SubtractionAssignment|'-=' |\n|op_MultiplicationAssignment|'*=' |\n|op_DivisionAssignment|'/=' |\n|op_ModulusAssignment|'%=' |\n|op_BitwiseAndAssignment|'&=' |\n|op_BitwiseOrAssignment|'&#124;=' |\n|op_ExclusiveOrAssignment|'^=' |\n|op_LeftShiftAssignment|'<<='|\n|op_RightShiftAssignment| right_shift_assignment|\n|op_UnsignedRightShiftAssignment|unsigned_right_shift_assignment|\n\nHowever, it states that CLS compliance requires the operator methods to be non-void static methods with two parameters,\ni.e. matches what C# binary operators are. We should consider relaxing the CLS compliance requirements\nto allow the operators to be void returning instance methods with a single parameter.\n\nThe following names should be added to support checked versions of the operators:\n| Name | Operator |\n| -----| -------- |\n|op_CheckedAdditionAssignment| checked '+=' |\n|op_CheckedSubtractionAssignment| checked '-=' |\n|op_CheckedMultiplicationAssignment| checked '*=' |\n|op_CheckedDivisionAssignment| checked '/=' |\n\n### Prefix increment and decrement operators\n\nSee https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1296-prefix-increment-and-decrement-operators\n\nIf `x` in `«op» x` is classified as a variable and a new language version is targeted, then the priority is given to\n[instance increment operators](#increment-operators) as follows.\n\nFirst, an attempt is made to process the operation by applying\n[instance increment operator overload resolution](#instance-increment-operator-overload-resolution).\nIf the process produces no result and no error, then the operation is processed\nby applying unary operator overload resolution as\nhttps://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1296-prefix-increment-and-decrement-operators\ncurrently specifies.\n\nOtherwise, an operation `«op»x` is evaluated as follows.\n\nIf type of `x` is known to be a reference type, the `x` is evaluated to get an instance `x₀`, the operator method is\ninvoked on that instance, and `x₀` is returned as result of the operation.\nIf `x₀` is `null`, the operator method invocation will throw a NullReferenceException.\n\n\nFor example:\n``` C#\nvar a = ++(new C()); // error: not a variable\nvar b = ++a; // var temp = a; temp.op_Increment(); b = temp; \n++b; // b.op_Increment();\nvar d = ++C.P1; // error: setter is missing\n++C.P1; // error: setter is missing\nvar e = ++C.P2; // var temp = C.op_Increment(C.get_P2()); C.set_P2(temp); e = temp;\n++C.P2; // var temp = C.op_Increment(C.get_P2()); C.set_P2(temp);\n\nclass C\n{\n    public static C P1 { get; } = new C();\n    public static C P2 { get; set; } = new C();\n\n    public static C operator ++(C x) => ...;\n    public void operator ++() => ...;\n}\n```\n\nIf type of `x` is not known to be a reference type:\n- If result of increment is used, the `x` is evaluated to get an instance `x₀`, the operator method is\n  invoked on that instance, `x₀` is assigned to `x` and `x₀` is returned as result of\n  the compound assignment.\n- Otherwise, the operator method is invoked on `x`.\n  \nNote that side effects in `x` are evaluated only once in the process.\n\nFor example:\n``` C#\nvar a = ++(new S()); // error: not a variable\nvar b = ++S.P2; // var temp = S.op_Increment(S.get_P2()); S.set_P2(temp); b = temp;\n++S.P2; // var temp = S.op_Increment(S.get_P2()); S.set_P2(temp);\n++b; // b.op_Increment(); \nvar d = ++S.P1; // error: set is missing\n++S.P1; // error: set is missing\nvar e = ++b; // var temp = b; temp.op_Increment(); e = (b = temp); \n\nstruct S\n{\n    public static S P1 { get; } = new S();\n    public static S P2 { get; set; } = new S();\n\n    public static S operator ++(S x) => ...;\n    public void operator ++() => ...;\n}\n```\n\n\n### Postfix increment and decrement operators\n\nSee https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12816-postfix-increment-and-decrement-operators\n\nIf result of the operation is used or `x` in `x «op»` is not classified as a variable\nor an old language version is targeted, the operation is processed by applying unary operator overload resolution as\nhttps://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12816-postfix-increment-and-decrement-operators\ncurrently specifies. \nThe reason why we are not even trying instance increment operators when result is used, is the fact that,\nif we are dealing with a reference type, it is not possible to produce value of `x` before the operation if it is mutated in-place.\nIf we are dealing with a value type, we will have to make copies anyway, etc.\n\nOtherwise, the priority is given to [instance increment operators](#increment-operators) as follows.\n\nFirst, an attempt is made to process the operation by applying\n[instance increment operator overload resolution](#instance-increment-operator-overload-resolution).\nIf the process produces no result and no error, then the operation is processed\nby applying unary operator overload resolution as\nhttps://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12816-postfix-increment-and-decrement-operators\ncurrently specifies.\n\nOtherwise, an operation `x«op»` is evaluated as follows.\n\nIf type of `x` is known to be a reference type, the operator method is invoked on `x`.\nIf `x` is `null`, the operator method invocation will throw a NullReferenceException.\n\n\nFor example:\n``` C#\nvar a = (new C())++; // error: not a variable\nvar b = new C(); \nvar c = b++; // var temp = b; b = C.op_Increment(temp); c = temp; \nb++; // b.op_Increment();\nvar d = C.P1++; // error: missing setter\nC.P1++; // error: missing setter\nvar e = C.P2++; // var temp = C.get_P2(); C.set_P2(C.op_Increment(temp)); e = temp;\nC.P2++; // var temp = C.get_P2(); C.set_P2(C.op_Increment(temp));\n\nclass C\n{\n    public static C P1 { get; } = new C();\n    public static C P2 { get; set; } = new C();\n\n    public static C operator ++(C x) => ...; \n    public void operator ++() => ...;\n}\n```\n\nIf type of `x` is not known to be a reference type, the operator method is invoked on `x`.\n\nFor example:\n``` C#\nvar a = (new S())++; // error: not a variable\nvar b = S.P2++; // var temp = S.get_P2(); S.set_P2(S.op_Increment(temp)); b = temp;\nS.P2++; // var temp = S.get_P2(); S.set_P2(S.op_Increment(temp));\nb++; // b.op_Increment(); \nvar d = S.P1++; // error: set is missing\nS.P1++; // error: missing setter\nvar e = b++; // var temp = b; b = S.op_Increment(temp); e = temp; \n\nstruct S\n{\n    public static S P1 { get; } = new S();\n    public static S P2 { get; set; } = new S();\n\n    public static S operator ++(S x) => ...; \n    public void operator ++() => ...;\n}\n```\n\n### Instance increment operator overload resolution\n[instance-increment-operator-overload-resolution]: #instance-increment-operator-overload-resolution\n\nAn operation of the form `«op» x` or `x «op»`, where «op» is an overloadable instance increment operator,\nand `x` is an expression of type `X`, is processed as follows:\n\n- The set of candidate user-defined operators provided by `X` for the operation `operator «op»(x)` is determined\n  using the rules of [candidate instance increment operators](#candidate-instance-increment-operators).\n- If the set of candidate user-defined operators is not empty, then this becomes the set of candidate operators for the operation.\n  Otherwise, the overload resolution yields no result.\n- The [overload resolution rules](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1264-overload-resolution)\n  are applied to the set of candidate operators to select the best operator,\n  and this operator becomes the result of the overload resolution process. If overload resolution fails to select a single best operator,\n  a binding-time error occurs.\n\n### Candidate instance increment operators\n[candidate-instance-increment-operators]: #candidate-instance-increment-operators\n\nGiven a type `T` and an operation `«op»`, where `«op»` is an overloadable instance increment operator,\nthe set of candidate user-defined operators provided by `T` is determined as follows:\n- In `unchecked` evaluation context, it is a group of operators that would be produced\n  by [Member lookup](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1251-general)\n  process when only instance `operator «op»()` operators were considered matching the target name `N`.\n- In `checked` evaluation context, it is a group of operators that would be produced\n  by [Member lookup](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1251-general)\n  process when only instance `operator «op»()` and instance `operator checked «op»()` operators were considered\n  matching the target name `N`. The `operator «op»()` operators that have pair-wise matching `operator checked «op»()`\n  declarations are excluded from the group.\n\n### Compound assignment\n\nSee https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12214-compound-assignment\n\nThe paragraph at the beginning that deals with `dynamic` is still applicable as is.\n\nOtherwise, if `x` in `x «op»= y` is classified as a variable and a new language version is targeted,\nthen the priority is given to [compound assignment operators](#compound-assignment-operators) as follows.\n\nFirst, an attempt is made to process an operation of the form `x «op»= y` by applying\n[compound assignment operator overload resolution](#compound-assignment-operator-overload-resolution).\nIf the process produces no result and no error, then the operation is processed\nby applying binary operator overload resolution as\nhttps://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12214-compound-assignment\ncurrently specifies.\n\nOtherwise, the operation is evaluated as follows.\n\nIf type of `x` is known to be a reference type, the `x` is evaluated to get an instance `x₀`, the operator method is\ninvoked on that instance with `y` as the argument, and `x₀` is returned as result of the compound assignment.\nIf `x₀` is `null`, the operator method invocation will throw a NullReferenceException.\n\nFor example:\n``` C#\nvar a = (new C())+=10; // error: not a variable\nvar b = a += 100; // var temp = a; temp.op_AdditionAssignment(100); b = temp; \nvar c = b + 1000; // c = C.op_Addition(b, 1000)\nc += 5; // c.op_AdditionAssignment(5);\nvar d = C.P1 += 11; // error: setter is missing\nvar e = C.P2 += 12; // var temp = C.op_Addition(C.get_P2(), 12); C.set_P2(temp); e = temp;\nC.P2 += 13; // var temp = C.op_Addition(C.get_P2(), 13); C.set_P2(temp);\n\nclass C\n{\n    public static C P1 { get; } = new C();\n    public static C P2 { get; set; } = new C();\n\n    // op_Addition\n    public static C operator +(C x, int y) => ...;\n\n    // op_AdditionAssignment\n    public void operator +=(int y) => ...;\n}\n```\n\nIf type of `x` is not known to be a reference type:\n- If result of compound assignment is used, the `x` is evaluated to get an instance `x₀`, the operator method is\n  invoked on that instance with `y` as the argument, `x₀` is assigned to `x` and `x₀` is returned as result of\n  the compound assignment.\n- Otherwise, the operator method is invoked on `x` with `y` as the argument.\n  \nNote that side effects in `x` are evaluated only once in the process.\n\nFor example:\n``` C#\nvar a = (new S())+=10; // error: not a variable\nvar b = S.P2 += 100; // var temp = S.op_Addition(S.get_P2(), 100); S.set_P2(temp); b = temp;\nS.P2 += 100; // var temp = S.op_Addition(S.get_P2(), 100); S.set_P2(temp);\nvar c = b + 1000; // c = S.op_Addition(b, 1000)\nc += 5; // c.op_AdditionAssignment(5); \nvar d = S.P1 += 11; // error: setter is missing\nvar e = c += 12; // var temp = c; temp.op_AdditionAssignment(12); e = (c = temp); \n\nstruct S\n{\n    public static S P1 { get; } = new S();\n    public static S P2 { get; set; } = new S();\n\n    // op_Addition\n    public static S operator +(S x, int y) => ...;\n\n    // op_AdditionAssignment\n    public void operator +=(int y) => ...;\n}\n```\n\n\n### Compound assignment operator overload resolution\n[compound-assignment-operator-overload-resolution]: #compound-assignment-operator-overload-resolution\n\nAn operation of the form `x «op»= y`, where `«op»=` is an overloadable compound assignment operator, `x` is an expression of type `X` is processed as follows:\n\n- The set of candidate user-defined operators provided by `X` for the operation `operator «op»=(y)` is determined\n  using the rules of [candidate compound assignment operators](#candidate-compound-assignment-operators).\n- If at least one candidate user-defined operator in the set is applicable to the argument list `(y)`,\n  then this becomes the set of candidate operators for the operation. Otherwise, the overload resolution yields no result.\n- The [overload resolution rules](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1264-overload-resolution)\n  are applied to the set of candidate operators to select the best operator with respect to the argument list `(y)`,\n  and this operator becomes the result of the overload resolution process. If overload resolution fails to select a single best operator,\n  a binding-time error occurs.\n\n### Candidate compound assignment operators\n[candidate-compound-assignment-operators]: #candidate-compound-assignment-operators\n\nGiven a type `T` and an operation `«op»=`, where `«op»=` is an overloadable compound assignment operator,\nthe set of candidate user-defined operators provided by `T` is determined as follows:\n- In `unchecked` evaluation context, it is a group of operators that would be produced\n  by [Member lookup](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1251-general)\n  process when only instance `operator «op»=(Y)` operators were considered matching the target name `N`.\n- In `checked` evaluation context, it is a group of operators that would be produced\n  by [Member lookup](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1251-general)\n  process when only instance `operator «op»=(Y)` and instance `operator checked «op»=(Y)` operators were considered\n  matching the target name `N`. The `operator «op»=(Y)` operators that have pair-wise matching `operator checked «op»=(Y)`\n  declarations are excluded from the group.\n\n## Open questions\n[open]: #open-questions\n\n### [Resolved] Should `readonly` modifier be allowed in structures?\n\nIt feels like there would be no benefit in allowing to mark a method with `readonly` when the whole\npurpose of the method is to modify the instance.\n\n[Conclusion:](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-04-02.md#conclusion)\nWe will allow `readonly` modifiers, but we will not relax the target requirements at this time.\n\n### [Resolved] Should shadowing be allowed?\n\nIf a derived class declares a 'compound assignment'/'instance increment' operator with the same signature as one in base,\nshould we require an `override` modifier?\n\n[Conclusion:](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-04-02.md#conclusion-1)\nShadowing will be allowed with the same rules as methods.\n\n### [Resolved] Should we have any consistency enforcement between declared `+=` and `+` operators?\n\nDuring [LDM-2025-02-12](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-02-12.md#user-defined-instance-based-operators)\na concern was raised about authors accidentally pushing their users into odd scenarios where a `+=` may work, but\n`+` won't (or vice versa) because one form declares extra operators than the other.\n\n[Conclusion:](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-04-02.md#conclusion-2)\nChecks will not be done on consistency between different forms of operators.\n\n## Alternatives\n[alternatives]: #alternatives\n\n### Keep using static methods\n\nWe could consider using static operator methods where the instance to be mutated\nis passed as the first parameter. In case of a value type, that parameter must be a `ref` parameter.\nOtherwise, the method won't be able to mutate the target variable. At the same time, in case of a class\ntype, that parameter should not be a `ref` parameter. Because in case of a class, the passed in instance\nmust be mutated, not the location where the instance is stored. However, when an operator is declared\nin an interface, it is often not known whether the interface will be implemented only by classes,\nor only by structures. Therefore, it is not clear whether the first parameter should be a `ref` parameter.\n\n## Design meetings\n\n- [LDM-2025-02-12](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-02-12.md#user-defined-instance-based-operators)\n- [LDM-2025-04-02](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-04-02.md#user-defined-compound-assignment-operators)\n"
  },
  {
    "path": "proposals/csharp-6.0/empty-params-array.md",
    "content": "# Empty array for zero arguments passed to params parameter\n\nWe use Array<T>.Empty() to create a zero-element array to pass to a params method when no arguments correspond.\nThe language spec requires a new array, so it is a language change.\nThis is a placeholder for the specification.\n"
  },
  {
    "path": "proposals/csharp-6.0/enum-base-type.md",
    "content": "﻿## Enum Base Type\n\nIn C# 6.0 we relaxed the syntax of an enum base type to be a type syntax, but require that it bind to one of a specified set of types. So `System.Int32` is permitted. But the spec has not been updated; it still requires one of a set of keywords for the base.\n\nThis is a placeholder for a specification of that change.\n"
  },
  {
    "path": "proposals/csharp-6.0/struct-autoprop-init.md",
    "content": "# Relaxed rules for auto-properties in structs \n\nBefore C# 6.0 you could not write code like this: \n\n```csharp\nstruct S \n{ \n    int X { get; set; } \n    int Y { get; set; } \n    public S(int x, int y) \n    { \n        this.X = x; \n        this.Y = y; \n    } \n} \n```\n\n```none\nerror CS0188: The 'this' object cannot be used before all of its fields are assigned to\nerror CS0843: Backing field for automatically implemented property 'S.X' must be fully assigned before control is returned to the caller. Consider calling the default constructor from a constructor initializer. \nerror CS0843: Backing field for automatically implemented property 'S.Y' must be fully assigned before control is returned to the caller. Consider calling the default constructor from a constructor initializer. \n```\n \nA workaround was to invoke the default constructor: \n\n```csharp\nstruct S \n{ \n    int X { get; set; } \n    int Y { get; set; } \n    public S(int x, int y) : this() \n    { \n        this.X = x; \n        this.Y = y; \n    } \n} \n```\n\nor to initialize this to the default value: \n\n```csharp\nstruct S \n{ \n    int X { get; set; } \n    int Y { get; set; } \n    public S(int x, int y) \n    { \n        this = default(S); \n        this.X = x; \n        this.Y = y; \n    } \n} \n```\n\nUnfortunately, both methods effectively disabled definite assignment analysis for instance fields for the given constructor. \n\nC# 6.0 relaxes these rules by tracking assignments to instance auto-properties as if they were assignments to their backing fields, so the code in the beginning of this section is now valid. \n"
  },
  {
    "path": "proposals/csharp-7.0/binary-literals.md",
    "content": "# Binary literals\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/55>\n\nThere’s a relatively common request to add binary literals to C# and VB. For bitmasks (e.g. flag enums) this seems genuinely useful, but it would also be great just for educational purposes.\n\nBinary literals would look like this:\n\n```csharp\nint nineteen = 0b10011;\n```\n\nSyntactically and semantically they are identical to hexadecimal literals, except for using `b`/`B` instead of `x`/`X`, having only digits `0` and `1` and being interpreted in base 2 instead of 16.\n\nThere’s little cost to implementing these, and little conceptual overhead to users of the language.\n\n## Syntax\n\nThe grammar would be as follows:\n\n```antlr\ninteger-literal:\n    : ...\n    | binary-integer-literal\n    ;\nbinary-integer-literal:\n    : `0b` binary-digits integer-type-suffix-opt\n    | `0B` binary-digits integer-type-suffix-opt\n    ;\nbinary-digits:\n    : binary-digit\n    | binary-digits binary-digit\n    ;\nbinary-digit:\n    : `0`\n    | `1`\n    ;\n```\n"
  },
  {
    "path": "proposals/csharp-7.0/digit-separators.md",
    "content": "# Digit separators\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/55>\n\nBeing able to group digits in large numeric literals would have great readability impact and no significant downside. \n\nAdding binary literals (#215) would increase the likelihood of numeric literals being long, so the two features enhance each other. \n\nWe would follow Java and others, and use an underscore `_` as a digit separator. It would be able to occur everywhere in a numeric literal (except as the first and last character), since different groupings may make sense in different scenarios and especially for different numeric bases:\n\n```csharp\nint bin = 0b1001_1010_0001_0100;\nint hex = 0x1b_a0_44_fe;\nint dec = 33_554_432;\nint weird = 1_2__3___4____5_____6______7_______8________9;\ndouble real = 1_000.111_1e-1_000;\n```\n\nAny sequence of digits may be separated by underscores, possibly more than one underscore between two consecutive digits. They are allowed in decimals as well as exponents, but following the previous rule, they may not appear next to the decimal (`10_.0`), next to the exponent character (`1.1e_1`), or next to the type specifier (`10_f`). When used in binary and hexadecimal literals, they may not appear immediately following the `0x` or `0b`.\n\nThe syntax is straightforward, and the separators have no semantic impact - they are simply ignored.\n\nThis has broad value and is easy to implement.\n"
  },
  {
    "path": "proposals/csharp-7.0/expression-bodied-everything.md",
    "content": "﻿## Expression Bodied Everything\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/63>\n\nIn C# 7.0, we added support for expression-bodied constructors, destructors, and accessors.  This is a placeholder for the specification.\n"
  },
  {
    "path": "proposals/csharp-7.0/local-functions.md",
    "content": "# Local functions\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/56>\n\nWe extend C# to support the declaration of functions in block scope. Local functions may use (capture) variables from the enclosing scope.\n\nThe compiler uses flow analysis to detect which variables a local function uses before assigning it a value. Every call of the function requires such variables to be definitely assigned. Similarly the compiler determines which variables are definitely assigned on return. Such variables are considered definitely assigned after the local function is invoked.\n\nLocal functions may be called from a lexical point before its definition. Local function declaration statements do not cause a warning when they are not reachable.\n\nTODO: _WRITE SPEC_\n\n## Syntax grammar\n\nThis grammar is represented as a diff from the current spec grammar.\n\n```diff\ndeclaration-statement\n    : local-variable-declaration ';'\n    | local-constant-declaration ';'\n+   | local-function-declaration\n    ;\n\n+local-function-declaration\n+   : local-function-header local-function-body\n+   ;\n\n+local-function-header\n+   : local-function-modifiers? return-type identifier type-parameter-list?\n+       ( formal-parameter-list? ) type-parameter-constraints-clauses\n+   ;\n\n+local-function-modifiers\n+   : (async | unsafe)\n+   ;\n\n+local-function-body\n+   : block\n+   | arrow-expression-body\n+   ;\n```\n\nLocal functions may use variables defined in the enclosing scope. The current\nimplementation requires that every variable read inside a local function be\ndefinitely assigned, as if executing the local function at its point of\ndefinition. Also, the local function definition must have been \"executed\" at\nany use point.\n\nAfter experimenting with that a bit (for example, it is not possible to define\ntwo mutually recursive local functions), we've since revised how we want the\ndefinite assignment to work. The revision (not yet implemented) is that all\nlocal variables read in a local function must be definitely assigned at each\ninvocation of the local function. That's actually more subtle than it sounds,\nand there is a bunch of work remaining to make it work. Once it is done you'll\nbe able to move your local functions to the end of its enclosing block.\n\nThe new definite assignment rules are incompatible with inferring the return\ntype of a local function, so we'll likely be removing support for inferring the\nreturn type.\n\nUnless you convert a local function to a delegate, capturing is done into\nframes that are value types. That means you don't get any GC pressure from\nusing local functions with capturing.\n\n### Reachability\n\nWe add to the spec\n\n> The body of a statement-bodied lambda expression or local function is considered reachable.\n"
  },
  {
    "path": "proposals/csharp-7.0/out-var.md",
    "content": "# Out variable declarations\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/60>\n\nThe *out variable declaration* feature enables a variable to be declared at the location that it is being passed as an `out` argument.\n\n```antlr\nargument_value\n    : 'out' type identifier\n    | ...\n    ;\n```\n\nA variable declared this way is called an *out variable*. You may use the contextual keyword `var` for the variable's type. The scope will be the same as for a *pattern-variable* introduced via pattern-matching.\n\nAccording to Language Specification (section 7.6.7 Element access) the argument-list of an element-access (indexing expression) does not contain ref or out arguments. However, they are permitted by the compiler for various scenarios, for example indexers declared in metadata that accept `out`.\n\nWithin the scope of a local variable introduced by an argument_value, it is a compile-time error to refer to that local variable in a textual position that precedes its declaration.\n\nIt is also an error to reference an implicitly-typed (§8.5.1) out variable in the same argument list that immediately contains its declaration.\n\nOverload resolution is modified as follows:\n\nWe add a new conversion:\n\n> There is a *conversion from expression* from an implicitly-typed out variable declaration to every type.\n\nAlso\n\n> The type of an explicitly-typed out variable argument is the declared type.\n\nand\n\n> An implicitly-typed out variable argument has no type.\n\nThe *conversion from expression* from an implicitly-typed out variable declaration is not considered better than any other *conversion from expression*.\n\nThe type of an implicitly-typed out variable is the type of the corresponding parameter in the signature of the method selected by overload resolution.\n\nThe new syntax node `DeclarationExpressionSyntax` is added to represent the declaration in an out var argument.\n"
  },
  {
    "path": "proposals/csharp-7.0/pattern-matching.md",
    "content": "# Pattern Matching for C# 7\n\nPattern matching extensions for C# enable many of the benefits of algebraic data types and pattern matching from functional languages, but in a way that smoothly integrates with the feel of the underlying language. The basic features are: [record types](../csharp-9.0/records.md), which are types whose semantic meaning is described by the shape of the data; and pattern matching, which is a new expression form that enables extremely concise multilevel decomposition of these data types. Elements of this approach are inspired by related features in the programming languages [F#](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/p29-syme.pdf \"Extensible Pattern Matching Via a Lightweight Language\") and [Scala](https://infoscience.epfl.ch/record/98468/files/MatchingObjectsWithPatterns-TR.pdf \"Matching Objects With Patterns\").\n\n## Is expression\n\nThe `is` operator is extended to test an expression against a *pattern*.\n\n```antlr\nrelational_expression\n    : relational_expression 'is' pattern\n    ;\n```\n\nThis form of *relational_expression* is in addition to the existing forms in the C# specification. It is a compile-time error if the *relational_expression* to the left of the `is` token does not designate a value or does not have a type.\n\nEvery *identifier* of the pattern introduces a new local variable that is *definitely assigned* after the `is` operator is `true` (i.e. *definitely assigned when true*).\n\n> Note: There is technically an ambiguity between *type* in an `is-expression` and *constant_pattern*, either of which might be a valid parse of a qualified identifier. We try to bind it as a type for compatibility with previous versions of the language; only if that fails do we resolve it as we do in other contexts, to the first thing found (which must be either a constant or a type). This ambiguity is only present on the right-hand-side of an `is` expression.\n\n## Patterns\n\nPatterns are used in the `is` operator and in a *switch_statement* to express the shape of data against which incoming data is to be compared. Patterns may be recursive so that parts of the data may be matched against sub-patterns.\n\n```antlr\npattern\n    : declaration_pattern\n    | constant_pattern\n    | var_pattern\n    ;\n\ndeclaration_pattern\n    : type simple_designation\n    ;\n\nconstant_pattern\n    : shift_expression\n    ;\n\nvar_pattern\n    : 'var' simple_designation\n    ;\n```\n\n> Note: There is technically an ambiguity between *type* in an `is-expression` and *constant_pattern*, either of which might be a valid parse of a qualified identifier. We try to bind it as a type for compatibility with previous versions of the language; only if that fails do we resolve it as we do in other contexts, to the first thing found (which must be either a constant or a type). This ambiguity is only present on the right-hand-side of an `is` expression.\n\n### Declaration pattern\n\nThe *declaration_pattern* both tests that an expression is of a given type and casts it to that type if the test succeeds. If the *simple_designation* is an identifier, it introduces a local variable of the given type named by the given identifier. That local variable is *definitely assigned* when the result of the pattern-matching operation is true.\n\n```antlr\ndeclaration_pattern\n    : type simple_designation\n    ;\n```\n\nThe runtime semantic of this expression is that it tests the runtime type of the left-hand *relational_expression* operand against the *type* in the pattern. If it is of that runtime type (or some subtype), the result of the `is operator` is `true`. It declares a new local variable named by the *identifier* that is assigned the value of the left-hand operand when the result is `true`.\n\nCertain combinations of static type of the left-hand-side and the given type are considered incompatible and result in compile-time error. A value of static type `E` is said to be *pattern compatible* with the type `T` if there exists an identity conversion, an implicit reference conversion, a boxing conversion, an explicit reference conversion, or an unboxing conversion from `E` to `T`. It is a compile-time error if an expression of type `E` is not pattern compatible with the type in a type pattern that it is matched with.\n\n> Note: [In C# 7.1 we extend this](../csharp-7.1/generics-pattern-match.md) to permit a pattern-matching operation if either the input type or the type `T` is an open type. This paragraph is replaced by the following:\n> \n> Certain combinations of static type of the left-hand-side and the given type are considered incompatible and result in compile-time error. A value of static type `E` is said to be *pattern compatible* with the type `T` if there exists an identity conversion, an implicit reference conversion, a boxing conversion, an explicit reference conversion, or an unboxing conversion from `E` to `T`, **or if either `E` or `T` is an open type**. It is a compile-time error if an expression of type `E` is not pattern compatible with the type in a type pattern that it is matched with.\n\nThe declaration pattern is useful for performing run-time type tests of reference types, and replaces the idiom\n\n```csharp\nvar v = expr as Type;\nif (v != null) { // code using v }\n```\n\nWith the slightly more concise\n\n```csharp\nif (expr is Type v) { // code using v }\n```\n\nIt is an error if *type* is a nullable value type.\n\nThe declaration pattern can be used to test values of nullable types: a value of type `Nullable<T>` (or a boxed `T`) matches a type pattern `T2 id` if the value is non-null and the type of `T2` is `T`, or some base type or interface of `T`. For example, in the code fragment\n\n```csharp\nint? x = 3;\nif (x is int v) { // code using v }\n```\n\nThe condition of the `if` statement is `true` at runtime and the variable `v` holds the value `3` of type `int` inside the block.\n\n### Constant pattern\n\n```antlr\nconstant_pattern\n    : shift_expression\n    ;\n```\n\nA constant pattern tests the value of an expression against a constant value. The constant may be any constant expression, such as a literal, the name of a declared `const` variable, or an enumeration constant, or a `typeof` expression.\n\nIf both *e* and *c* are of integral types, the pattern is considered matched if the result of the expression `e == c` is `true`.\n\nOtherwise the pattern is considered matching if `object.Equals(e, c)` returns `true`. In this case it is a compile-time error if the static type of *e* is not *pattern compatible* with the type of the constant.\n\n### Var pattern\n\n```antlr\nvar_pattern\n    : 'var' simple_designation\n    ;\n```\n\nAn expression *e* matches a *var_pattern* always. In other words, a match to a *var pattern* always succeeds. If the *simple_designation* is an identifier, then at runtime the value of *e* is bound to a newly introduced local variable. The type of the local variable is the static type of *e*.\n\nIt is an error if the name `var` binds to a type.\n\n## Switch statement\n\nThe `switch` statement is extended to select for execution the first block having an associated pattern that matches the *switch expression*.\n\n```antlr\nswitch_label\n    : 'case' complex_pattern case_guard? ':'\n    | 'case' constant_expression case_guard? ':'\n    | 'default' ':'\n    ;\n\ncase_guard\n    : 'when' expression\n    ;\n```\n\nThe order in which patterns are matched is not defined. A compiler is permitted to match patterns out of order, and to reuse the results of already matched patterns to compute the result of matching of other patterns.\n\nIf a *case-guard* is present, its expression is of type `bool`. It is evaluated as an additional condition that must be satisfied for the case to be considered satisfied.\n\nIt is an error if a *switch_label* can have no effect at runtime because its pattern is subsumed by previous cases. [TODO: We should be more precise about the techniques the compiler is required to use to reach this judgment.]\n\nA pattern variable declared in a *switch_label* is definitely assigned in its case block if and only if that case block contains precisely one *switch_label*.\n\n[TODO: We should specify when a *switch block* is reachable.]\n\n### Scope of pattern variables\n\nThe scope of a variable declared in a pattern is as follows:\n\n- If the pattern is a case label, then the scope of the variable is the *case block*.\n\nOtherwise the variable is declared in an *is_pattern* expression, and its scope is based on the construct immediately enclosing the expression containing the *is_pattern* expression as follows:\n\n- If the expression is in an expression-bodied lambda, its scope is the body of the lambda.\n- If the expression is in an expression-bodied method or property, its scope is the body of the method or property.\n- If the expression is in a `when` clause of a `catch` clause, its scope is that `catch` clause.\n- If the expression is in an *iteration_statement*, its scope is just that statement.\n- Otherwise if the expression is in some other statement form, its scope is the scope containing the statement.\n\nFor the purpose of determining the scope, an *embedded_statement* is considered to be in its own scope. For example, the grammar for an *if_statement* is\n\n``` antlr\nif_statement\n    : 'if' '(' boolean_expression ')' embedded_statement\n    | 'if' '(' boolean_expression ')' embedded_statement 'else' embedded_statement\n    ;\n```\n\nSo if the controlled statement of an *if_statement* declares a pattern variable, its scope is restricted to that *embedded_statement*:\n\n```csharp\nif (x) M(y is var z);\n```\n\nIn this case the scope of `z` is the embedded statement `M(y is var z);`.\n\nOther cases are errors for other reasons (e.g. in a parameter's default value or an attribute, both of which are an error because those contexts require a constant expression).\n\n> [In C# 7.3 we added the following contexts](../csharp-7.3/expression-variables-in-initializers.md) in which a pattern variable may be declared:\n> - If the expression is in a *constructor initializer*, its scope is the *constructor initializer* and the constructor's body.\n> - If the expression is in a field initializer, its scope is the *equals_value_clause* in which it appears.\n> - If the expression is in a query clause that is specified to be translated into the body of a lambda, its scope is just that expression.\n\n## Changes to syntactic disambiguation\n\nThere are situations involving generics where the C# grammar is ambiguous, and the language spec says how to resolve those ambiguities:\n\n> #### 7.6.5.2 Grammar ambiguities\n> The productions for *simple-name* (§7.6.3) and *member-access* (§7.6.5) can give rise to ambiguities in the grammar for expressions. For example, the statement:\n> ```csharp\n> F(G<A,B>(7));\n> ```\n> could be interpreted as a call to `F` with two arguments, `G < A` and `B > (7)`. Alternatively, it could be interpreted as a call to `F` with one argument, which is a call to a generic method `G` with two type arguments and one regular argument.\n\n> If a sequence of tokens can be parsed (in context) as a *simple-name* (§7.6.3), *member-access* (§7.6.5), or *pointer-member-access* (§18.5.2) ending with a *type-argument-list* (§4.4.1), the token immediately following the closing `>` token is examined. If it is one of\n> ```none\n> (  )  ]  }  :  ;  ,  .  ?  ==  !=  |  ^\n> ```\n> then the *type-argument-list* is retained as part of the *simple-name*, *member-access* or *pointer-member-access* and any other possible parse of the sequence of tokens is discarded. Otherwise, the *type-argument-list* is not considered to be part of the *simple-name*, *member-access* or > *pointer-member-access*, even if there is no other possible parse of the sequence of tokens. Note that these rules are not applied when parsing a *type-argument-list* in a *namespace-or-type-name* (§3.8). The statement\n> ```csharp\n> F(G<A,B>(7));\n> ```\n> will, according to this rule, be interpreted as a call to `F` with one argument, which is a call to a generic method `G` with two type arguments and one regular argument. The statements\n> ```csharp\n> F(G < A, B > 7);\n> F(G < A, B >> 7);\n> ```\n> will each be interpreted as a call to `F` with two arguments. The statement\n> ```csharp\n> x = F < A > +y;\n> ```\n> will be interpreted as a less than operator, greater than operator, and unary plus operator, as if the statement had been written `x = (F < A) > (+y)`, instead of as a *simple-name* with a *type-argument-list* followed by a binary plus operator. In the statement\n> ```csharp\n> x = y is C<T> + z;\n> ```\n> the tokens `C<T>` are interpreted as a *namespace-or-type-name* with a *type-argument-list*.\n\nThere are a number of changes being introduced in C# 7 that make these disambiguation rules no longer sufficient to handle the complexity of the language.\n\n### Out variable declarations\n\nIt is now possible to declare a variable in an out argument:\n\n```csharp\nM(out Type name);\n```\n\nHowever, the type may be generic: \n\n```csharp\nM(out A<B> name);\n```\n\nSince the language grammar for the argument uses *expression*, this context is subject to the disambiguation rule. In this case the closing `>` is followed by an *identifier*, which is not one of the tokens that permits it to be treated as a *type-argument-list*. I therefore propose to **add *identifier* to the set of tokens that triggers the disambiguation to a *type-argument-list*.**\n\n### Tuples and deconstruction declarations\n\nA tuple literal runs into exactly the same issue. Consider the tuple expression\n\n```csharp\n(A < B, C > D, E < F, G > H)\n```\n\nUnder the old C# 6 rules for parsing an argument list, this would parse as a tuple with four elements, starting with `A < B` as the first. However, when this appears on the left of a deconstruction, we want the disambiguation triggered by the *identifier* token as described above:\n\n```csharp\n(A<B,C> D, E<F,G> H) = e;\n```\n\nThis is a deconstruction declaration which declares two variables, the first of which is of type `A<B,C>` and named `D`. In other words, the tuple literal contains two expressions, each of which is a declaration expression.\n\nFor simplicity of the specification and compiler, I propose that this tuple literal be parsed as a two-element tuple wherever it appears (whether or not it appears on the left-hand-side of an assignment). That would be a natural result of the disambiguation described in the previous section.\n\n### Pattern-matching\n\nPattern matching introduces a new context where the expression-type ambiguity arises. Previously the right-hand-side of an `is` operator was a type. Now it can be a type or expression, and if it is a type it may be followed by an identifier. This can, technically, change the meaning of existing code:\n\n```csharp\nvar x = e is T < A > B;\n```\n\nThis could be parsed under C#6 rules as\n\n```csharp\nvar x = ((e is T) < A) > B;\n```\n\nbut under under C#7 rules (with the disambiguation proposed above) would be parsed as\n\n```csharp\nvar x = e is T<A> B;\n```\n\nwhich declares a variable `B` of type `T<A>`. Fortunately, the native and Roslyn compilers have a bug whereby they give a syntax error on the C#6 code. Therefore this particular breaking change is not a concern.\n\nPattern-matching introduces additional tokens that should drive the ambiguity resolution toward selecting a type. The following examples of existing valid C#6 code would be broken without additional disambiguation rules:\n\n```csharp\nvar x = e is A<B> && f;            // &&\nvar x = e is A<B> || f;            // ||\nvar x = e is A<B> & f;             // &\nvar x = e is A<B>[];               // [\n```\n\n### Proposed change to the disambiguation rule\n\nI propose to revise the specification to change the list of disambiguating tokens from\n\n>\n```none\n(  )  ]  }  :  ;  ,  .  ?  ==  !=  |  ^\n```\n\nto\n\n>\n```none\n(  )  ]  }  :  ;  ,  .  ?  ==  !=  |  ^  &&  ||  &  [\n```\n\nAnd, in certain contexts, we treat *identifier* as a disambiguating token. Those contexts are where the sequence of tokens being disambiguated is immediately preceded by one of the keywords `is`, `case`, or `out`, or arises while parsing the first element of a tuple literal (in which case the tokens are preceded by `(` or `:` and the identifier is followed by a `,`) or a subsequent element of a tuple literal.\n\n### Modified disambiguation rule\n\nThe revised disambiguation rule would be something like this\n\n> If a sequence of tokens can be parsed (in context) as a *simple-name* (§7.6.3), *member-access* (§7.6.5), or *pointer-member-access* (§18.5.2) ending with a *type-argument-list* (§4.4.1), the token immediately following the closing `>` token is examined, to see if it is\n> - One of `(  )  ]  }  :  ;  ,  .  ?  ==  !=  |  ^  &&  ||  &  [`; or\n> - One of the relational operators `<  >  <=  >=  is as`; or\n> - A contextual query keyword appearing inside a query expression; or\n> - In certain contexts, we treat *identifier* as a disambiguating token. Those contexts are where the sequence of tokens being disambiguated is immediately preceded by one of the keywords `is`, `case` or `out`, or arises while parsing the first element of a tuple literal (in which case the tokens are preceded by `(` or `:` and the identifier is followed by a `,`) or a subsequent element of a tuple literal.\n> \n> If the following token is among this list, or an identifier in such a context, then the *type-argument-list* is retained as part of the *simple-name*, *member-access* or  *pointer-member-access* and any other possible parse of the sequence of tokens is discarded.  Otherwise, the *type-argument-list* is not considered to be part of the *simple-name*, *member-access* or *pointer-member-access*, even if there is no other possible parse of the sequence of tokens. Note that these rules are not applied when parsing a *type-argument-list* in a *namespace-or-type-name* (§3.8).\n\n### Breaking changes due to this proposal\n\nNo breaking changes are known due to this proposed disambiguation rule.\n\n### Interesting examples\n\nHere are some interesting results of these disambiguation rules:\n\nThe expression `(A < B, C > D)` is a tuple with two elements, each a comparison.\n\nThe expression `(A<B,C> D, E)` is a tuple with two elements, the first of which is a declaration expression.\n\nThe invocation `M(A < B, C > D, E)` has three arguments.\n\nThe invocation `M(out A<B,C> D, E)` has two arguments, the first of which is an `out` declaration.\n\nThe expression `e is A<B> C` uses a declaration expression.\n\nThe case label `case A<B> C:` uses a declaration expression.\n\n## Some examples of pattern matching\n\n### Is-As\n\nWe can replace the idiom\n\n```csharp\nvar v = expr as Type;\t\nif (v != null) {\n    // code using v\n}\n```\n\nWith the slightly more concise and direct\n\n```csharp\nif (expr is Type v) {\n    // code using v\n}\n```\n\n### Testing nullable\n\nWe can replace the idiom\n\n```csharp\nType? v = x?.y?.z;\nif (v.HasValue) {\n    var value = v.GetValueOrDefault();\n    // code using value\n}\n```\n\nWith the slightly more concise and direct\n\n```csharp\nif (x?.y?.z is Type value) {\n    // code using value\n}\n```\n\n### Arithmetic simplification\n\nSuppose we define a set of recursive types to represent expressions (per a separate proposal):\n\n```csharp\nabstract class Expr;\nclass X() : Expr;\nclass Const(double Value) : Expr;\nclass Add(Expr Left, Expr Right) : Expr;\nclass Mult(Expr Left, Expr Right) : Expr;\nclass Neg(Expr Value) : Expr;\n```\n\nNow we can define a function to compute the (unreduced) derivative of an expression:\n\n```csharp\nExpr Deriv(Expr e)\n{\n  switch (e) {\n    case X(): return Const(1);\n    case Const(*): return Const(0);\n    case Add(var Left, var Right):\n      return Add(Deriv(Left), Deriv(Right));\n    case Mult(var Left, var Right):\n      return Add(Mult(Deriv(Left), Right), Mult(Left, Deriv(Right)));\n    case Neg(var Value):\n      return Neg(Deriv(Value));\n  }\n}\n```\n\nAn expression simplifier demonstrates positional patterns:\n\n```csharp\nExpr Simplify(Expr e)\n{\n  switch (e) {\n    case Mult(Const(0), *): return Const(0);\n    case Mult(*, Const(0)): return Const(0);\n    case Mult(Const(1), var x): return Simplify(x);\n    case Mult(var x, Const(1)): return Simplify(x);\n    case Mult(Const(var l), Const(var r)): return Const(l*r);\n    case Add(Const(0), var x): return Simplify(x);\n    case Add(var x, Const(0)): return Simplify(x);\n    case Add(Const(var l), Const(var r)): return Const(l+r);\n    case Neg(Const(var k)): return Const(-k);\n    default: return e;\n  }\n}\n```\n"
  },
  {
    "path": "proposals/csharp-7.0/ref-locals-returns.md",
    "content": "﻿## Ref Locals and Returns\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/58>\n\nIn C# 7.0 we added support for *ref locals and ref returns*.  This is a placeholder for its specification.\n"
  },
  {
    "path": "proposals/csharp-7.0/task-types.md",
    "content": "# Async Task Types in C# #\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/61>\n\nExtend `async` to support _task types_ that match a specific pattern, in addition to the well known types\n`System.Threading.Tasks.Task` and `System.Threading.Tasks.Task<T>`.\n\n## Task Type\nA _task type_ is a `class` or `struct` with an associated _builder type_ identified\nwith `System.Runtime.CompilerServices.AsyncMethodBuilderAttribute`.\nThe _task type_ may be non-generic, for async methods that do not return a value, or generic, for methods that return a value.\n\nTo support `await`, the _task type_ must have a corresponding, accessible `GetAwaiter()` method\nthat returns an instance of an _awaiter type_ (see _C# 7.7.7.1 Awaitable expressions_).\n```cs\n[AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))]\nclass MyTask<T>\n{\n    public Awaiter<T> GetAwaiter();\n}\n\nclass Awaiter<T> : INotifyCompletion\n{\n    public bool IsCompleted { get; }\n    public T GetResult();\n    public void OnCompleted(Action completion);\n}\n```\n## Builder Type\nThe _builder type_ is a `class` or `struct` that corresponds to the specific _task type_.\nThe _builder type_ can have at most 1 type parameter and must not be nested in a generic type.\nThe _builder type_ has the following `public` methods.\nFor non-generic _builder types_, `SetResult()` has no parameters.\n```cs\nclass MyTaskMethodBuilder<T>\n{\n    public static MyTaskMethodBuilder<T> Create();\n\n    public void Start<TStateMachine>(ref TStateMachine stateMachine)\n        where TStateMachine : IAsyncStateMachine;\n\n    public void SetStateMachine(IAsyncStateMachine stateMachine);\n    public void SetException(Exception exception);\n    public void SetResult(T result);\n\n    public void AwaitOnCompleted<TAwaiter, TStateMachine>(\n        ref TAwaiter awaiter, ref TStateMachine stateMachine)\n        where TAwaiter : INotifyCompletion\n        where TStateMachine : IAsyncStateMachine;\n    public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(\n        ref TAwaiter awaiter, ref TStateMachine stateMachine)\n        where TAwaiter : ICriticalNotifyCompletion\n        where TStateMachine : IAsyncStateMachine;\n\n    public MyTask<T> Task { get; }\n}\n```\n## Execution\nThe types above are used by the compiler to generate the code for the state machine of an `async` method.\n(The generated code is equivalent to the code generated for async methods that return `Task`, `Task<T>`, or `void`.\nThe difference is, for those well known types, the _builder types_ are also known to the compiler.)\n\n`Builder.Create()` is invoked to create an instance of the _builder type_.\n\n`builder.Start(ref stateMachine)` is invoked to associate the builder with compiler-generated state machine instance.\nThe builder must call `stateMachine.MoveNext()` either in `Start()` or after `Start()` has returned to advance the state machine.\nAfter `Start()` returns, the `async` method calls `builder.Task` for the task to return from the async method.\n\nEach call to `stateMachine.MoveNext()` will advance the state machine.\nIf the state machine completes successfully, `builder.SetResult()` is called, with  the method return value if any.\nIf an exception is thrown in the state machine, `builder.SetException(exception)` is called.\n\nIf the state machine reaches an `await expr` expression, `expr.GetAwaiter()` is invoked.\nIf the awaiter implements `ICriticalNotifyCompletion` and `IsCompleted` is false,\nthe state machine invokes `builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine)`.\n`AwaitUnsafeOnCompleted()` should call `awaiter.UnsafeOnCompleted(action)` with an `Action` that calls `stateMachine.MoveNext()`\nwhen the awaiter completes. Similarly for `INotifyCompletion` and `builder.AwaitOnCompleted()`.\n\n`SetStateMachine(IAsyncStateMachine)` is called by the compiler-generated `IAsyncStateMachine` implementation.\nThat can be used to identify the instance of the builder associated with a state machine instance, particularly for cases where the state machine is implemented as a value type:\nif the builder calls `stateMachine.SetStateMachine(stateMachine)`, the `stateMachine` will call `builder.SetStateMachine(stateMachine)` on the _builder instance associated with `stateMachine`_.\n\n## Overload Resolution\nOverload resolution is extended to recognize _task types_ in addition to `Task` and `Task<T>`.\n\nAn `async` lambda with no return value is an exact match for an overload candidate parameter of non-generic _task type_,\nand an `async` lambda with return type `T` is an exact match for an overload candidate parameter of generic _task type_. \n\nOtherwise if an `async` lambda is not an exact match for either of two candidate parameters of _task types_, or an exact match for both, and there\nis an implicit conversion from one candidate type to the other, the from candidate wins. Otherwise recursively evaluate\nthe types `A` and `B` within `Task1<A>` and `Task2<B>` for better match.\n\nOtherwise if an `async` lambda is not an exact match for either of two candidate parameters of _task types_,\nbut one candidate is a more specialized type than the other, the more specialized candidate wins.\n"
  },
  {
    "path": "proposals/csharp-7.0/throw-expression.md",
    "content": "# Throw expression\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/62>\n\nWe extend the set of expression forms to include\n\n```antlr\nthrow_expression\n    : 'throw' null_coalescing_expression\n    ;\n\nnull_coalescing_expression\n    : throw_expression\n    ;\n```\n\nThe type rules are as follows:\n\n- A *throw_expression* has no type.\n- A *throw_expression* is convertible to every type by an implicit conversion.\n\nA *throw expression* throws the value produced by evaluating the *null_coalescing_expression*, which must denote a value of the class type `System.Exception`, of a class type that derives from `System.Exception` or of a type parameter type that has `System.Exception` (or a subclass thereof) as its effective base class. If evaluation of the expression produces `null`, a `System.NullReferenceException` is thrown instead.\n\nThe behavior at runtime of the evaluation of a *throw expression* is the same as specified for a *throw statement* ([§12.10.6](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#12106-the-throw-statement)).\n\nThe flow-analysis rules are as follows:\n\n- For every variable *v*, *v* is definitely assigned before the *null_coalescing_expression* of a *throw_expression* iff it is definitely assigned before the *throw_expression*.\n- For every variable *v*, *v* is definitely assigned after *throw_expression*.\n\nA *throw expression* is permitted in only the following syntactic contexts:\n- As the second or third operand of a ternary conditional operator `?:`\n- As the second operand of a null coalescing operator `??`\n- As the body of an expression-bodied lambda or method.\n"
  },
  {
    "path": "proposals/csharp-7.0/tuples.md",
    "content": "﻿## Tuples\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/59>\n\nIn C# 7.0 we added support for *tuples*.  This is a placeholder for its specification.\n"
  },
  {
    "path": "proposals/csharp-7.1/README.md",
    "content": "\n# C# 7.1\n\n- [Async Main](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/async-main.md)\n- [Default Expressions](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/target-typed-default.md)\n- [Infer tuple names](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/infer-tuple-names.md)\n- [Pattern-matching with generics](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/generics-pattern-match.md)\n\n"
  },
  {
    "path": "proposals/csharp-7.1/async-main.md",
    "content": "# Async Main\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/97>\n\n## Summary\n[summary]: #summary\n\nAllow `await` to be used in an application's Main / entrypoint method by allowing the entrypoint to return `Task` / `Task<int>` and be marked `async`.\n\n## Motivation\n[motivation]: #motivation\n\nIt is very common when learning C#, when writing console-based utilities, and when writing small test apps to want\nto call and `await` `async` methods from Main.  Today we add a level of complexity here by forcing such `await`'ing to be\ndone in a separate async method, which causes developers to need to write boilerplate like the following just to get\nstarted:\n\n```csharp\npublic static void Main()\n{\n    MainAsync().GetAwaiter().GetResult();\n}\n\nprivate static async Task MainAsync()\n{\n    ... // Main body here\n}\n```\n\nWe can remove the need for this boilerplate and make it easier to get started simply by allowing Main itself to be\n`async` such that `await`s can be used in it.\n\n## Detailed design\n[design]: #detailed-design\n\nThe following signatures are currently allowed entrypoints:\n\n```csharp\nstatic void Main()\nstatic void Main(string[])\nstatic int Main()\nstatic int Main(string[])\n```\n\nWe extend the list of allowed entrypoints to include:\n\n```csharp\nstatic Task Main()\nstatic Task<int> Main()\nstatic Task Main(string[])\nstatic Task<int> Main(string[])\n```\n\nTo avoid compatibility risks, these new signatures will only be considered as valid entrypoints if no overloads of the previous set are present.\nThe language / compiler will not require that the entrypoint be marked as `async`, though we expect the vast majority of uses will be marked as such.\n\nWhen one of these is identified as the entrypoint, the compiler will synthesize an actual entrypoint method that calls one of these coded methods:\n- ```static Task Main()``` will result in the compiler emitting the equivalent of ```private static void $GeneratedMain() => Main().GetAwaiter().GetResult();```\n- ```static Task Main(string[])``` will result in the compiler emitting the equivalent of ```private static void $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();```\n- ```static Task<int> Main()``` will result in the compiler emitting the equivalent of ```private static int $GeneratedMain() => Main().GetAwaiter().GetResult();```\n- ```static Task<int> Main(string[])``` will result in the compiler emitting the equivalent of ```private static int $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();```\n\nExample usage:\n\n```csharp\nusing System;\nusing System.Net.Http;\n\nclass Test\n{\n    static async Task Main(string[] args) =>\n\t    Console.WriteLine(await new HttpClient().GetStringAsync(args[0]));\n}\n```\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nThe main drawback is simply the additional complexity of supporting additional entrypoint signatures.\n\n## Alternatives\n[alternatives]: #alternatives\n\nOther variants considered:\n\nAllowing `async void`.  We need to keep the semantics the same for code calling it directly, which would then make it difficult for a generated entrypoint to call it (no Task returned).  We could solve this by generating two other methods, e.g.\n\n```csharp\npublic static async void Main()\n{\n   ... // await code\n}\n```\n\nbecomes\n\n```csharp\npublic static async void Main() => await $MainTask();\n\nprivate static void $EntrypointMain() => Main().GetAwaiter().GetResult();\n\nprivate static async Task $MainTask()\n{\n    ... // await code\n}\n```\n\nThere are also concerns around encouraging usage of `async void`.\n\nUsing \"MainAsync\" instead of \"Main\" as the name.  While the async suffix is recommended for Task-returning methods, that's primarily about library functionality, which Main is not, and supporting additional entrypoint names beyond \"Main\" is not worth it.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\nn/a\n\n## Design meetings\n\nn/a\n"
  },
  {
    "path": "proposals/csharp-7.1/generics-pattern-match.md",
    "content": "# pattern-matching with generics\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/154>\n\n## Summary\n[summary]: #summary\n\nThe specification for the existing C# as operator ([§11.11.12](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#111112-the-as-operator)) permits there to be no conversion between the type of the operand and the specified type when either is an open type. However, in C# 7 the `Type identifier` pattern requires there be a conversion between the type of the input and the given type.\n\nWe propose to relax this and change `expression is Type identifier`, in addition to being permitted in the conditions when it is permitted in C# 7, to also be permitted when `expression as Type` would be allowed. Specifically, the new cases are cases where the type of the expression or the specified type is an open type. \n\n## Motivation\n[motivation]: #motivation\n\nCases where pattern-matching should \"obviously\" be permitted currently fail to compile. See, for example, https://github.com/dotnet/roslyn/issues/16195.\n\n## Detailed design\n[design]: #detailed-design\n\nWe change the paragraph in the pattern-matching specification (the proposed addition is shown in bold):\n\n> Certain combinations of static type of the left-hand-side and the given type are considered incompatible and result in compile-time error. A value of static type `E` is said to be *pattern compatible* with the type `T` if there exists an identity conversion, an implicit reference conversion, a boxing conversion, an explicit reference conversion, or an unboxing conversion from `E` to `T`**, or if either `E` or `T` is an open type**. It is a compile-time error if an expression of type `E` is not pattern compatible with the type in a type pattern that it is matched with.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nNone.\n\n## Alternatives\n[alternatives]: #alternatives\n\nNone.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\nNone.\n\n## Design meetings\n\nLDM considered this question and felt it was a bug-fix level change. We are treating it as a separate language feature because just making the change after the language has been released would introduce a forward incompatibility. Using the proposed change requires that the programmer specify language version 7.1.\n"
  },
  {
    "path": "proposals/csharp-7.1/infer-tuple-names.md",
    "content": "# Infer tuple names (aka. tuple projection initializers)\n\n## Summary\n[summary]: #summary\n\nIn a number of common cases, this feature allows the tuple element names to be omitted and instead be inferred. For instance, instead of typing `(f1: x.f1, f2: x?.f2)`, the element names \"f1\" and \"f2\" can be inferred from `(x.f1, x?.f2)`.\n\nThis parallels the behavior of  anonymous types, which allow inferring member names during creation. For instance, `new { x.f1, y?.f2 }` declares members \"f1\" and \"f2\".\n\nThis is particularly handy when using tuples in LINQ:\n\n```csharp\n// \"c\" and \"result\" have element names \"f1\" and \"f2\"\nvar result = list.Select(c => (c.f1, c.f2)).Where(t => t.f2 == 1); \n```\n\n## Detailed design\n[design]: #detailed-design\n\nThere are two parts to the change:\n\n1.\tTry to infer a candidate name for each tuple element which does not have an explicit name:\n    -\tUsing same rules as name inference for anonymous types.\n        - In C#, this allows three cases: `y` (identifier), `x.y` (simple member access) and `x?.y` (conditional access).\n        - In VB, this allows for additional cases, such as `x.y()`.\n    -\tRejecting reserved tuple names (case-sensitive in C#, case-insensitive in VB), as they are either forbidden or already implicit. For instance, such as `ItemN`, `Rest`, and `ToString`.\n    -\tIf any candidate names are duplicates (case-sensitive in C#, case-insensitive in VB) within the entire tuple, we drop those candidates,\n2.\tDuring conversions (which check and warn about dropping names from tuple literals), inferred names would not produce any warnings. This avoids breaking existing tuple code.\n\nNote that the rule for handling duplicates is different than that for anonymous types. For instance, `new { x.f1, x.f1 }` produces an error, but `(x.f1, x.f1)` would still be allowed (just without any inferred names). This avoids breaking existing tuple code.\n\nFor consistency, the same would apply to tuples produced by deconstruction-assignments (in C#):\n\n```csharp\n// tuple has element names \"f1\" and \"f2\" \nvar tuple = ((x.f1, x?.f2) = (1, 2));\n```\n\nThe same would also apply to VB tuples, using the VB-specific rules for inferring name from expression and case-insensitive name comparisons.\n\nWhen using the C# 7.1 compiler (or later) with language version \"7.0\", the element names will be inferred (despite the feature not being available), but there will be a use-site error for trying to access them. This will limit additions of new code that would later face the compatibility issue (described below).\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nThe main drawback is that this introduces a compatibility break from C# 7.0:\n\n```csharp\nAction y = () => M();\nvar t = (x: x, y);\nt.y(); // this might have previously picked up an extension method called “y”, but would now call the lambda.\n```\n\nThe compatibility council found this break acceptable, given that it is limited and the time window since tuples shipped (in C# 7.0) is short.\n\n## References\n- [LDM April 4th 2017](https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-05.md#tuple-names)\n- [Github discussion](https://github.com/dotnet/csharplang/issues/370) (thanks @alrz for bringing this issue up)\n- [Tuples design](https://github.com/dotnet/roslyn/blob/master/docs/features/tuples.md)\n"
  },
  {
    "path": "proposals/csharp-7.1/target-typed-default.md",
    "content": "# Target-typed \"default\" literal\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/102>\n\n## Summary\n[summary]: #summary\n\nThe target-typed `default` feature is a shorter form variation of the `default(T)` operator, which allows the type to be omitted. Its type is inferred by target-typing instead. Aside from that, it behaves like `default(T)`.\n\n## Motivation\n[motivation]: #motivation\n\nThe main motivation is to avoid typing redundant information.\n\nFor instance, when invoking `void Method(ImmutableArray<SomeType> array)`, the *default* literal allows `M(default)` in place of `M(default(ImmutableArray<SomeType>))`.\n\nThis is applicable in a number of scenarios, such as:\n\n- declaring locals (`ImmutableArray<SomeType> x = default;`)\n- ternary operations (`var x = flag ? default : ImmutableArray<SomeType>.Empty;`)\n- returning in methods and lambdas (`return default;`)\n- declaring default values for optional parameters (`void Method(ImmutableArray<SomeType> arrayOpt = default)`)\n- including default values in array creation expressions (`var x = new[] { default, ImmutableArray.Create(y) };`)\n\n\n## Detailed design\n[design]: #detailed-design\n\nA new expression is introduced, the *default* literal. An expression with this classification can be implicitly converted to any type, by a *default literal conversion*. \n\nThe inference of the type for the *default* literal works the same as that for the *null* literal, except that any type is allowed (not just reference types).\n\nThis conversion produces the default value of the inferred type.\n\nThe *default* literal may have a constant value, depending on the inferred type. So `const int x = default;` is legal, but `const int? y = default;` is not.\n\nThe *default* literal can be the operand of equality operators, as long as the other operand has a type. So `default == x` and `x == default` are valid expressions, but `default == default` is illegal.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nA minor drawback is that *default* literal can be used in place of *null* literal in most contexts. Two of the exceptions are `throw null;` and `null == null`, which are allowed for the *null* literal, but not the *default* literal.\n\n## Alternatives\n[alternatives]: #alternatives\n\nThere are a couple of alternatives to consider:\n\n- The status quo:  The feature is not justified on its own merits and developers continue to use the default operator with an explicit type.\n- Extending the null literal: This is the VB approach with `Nothing`. We could allow `int x = null;`.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n- [x] Should *default* be allowed as the operand of the *is* or *as* operators? Answer:  disallow `default is T`, allow `x is default`, allow `default as RefType` (with always-null warning)\n\n## Design meetings\n\n- [LDM 3/7/2017](https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-03-07.md)\n- [LDM 3/28/2017](https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-03-28.md)\n- [LDM 5/31/2017](https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-05-31.md#default-in-operators)\n"
  },
  {
    "path": "proposals/csharp-7.2/conditional-ref.md",
    "content": "# Conditional ref expressions\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/223>\n\nThe pattern of binding a ref variable to one or another expression conditionally is not currently expressible in C#.\n\nThe typical workaround is to introduce a method like:\n\n```csharp\nref T Choice(bool condition, ref T consequence, ref T alternative)\n{\n    if (condition)\n    {\n         return ref consequence;\n    }\n    else\n    {\n         return ref alternative;\n    }\n}\n```\n\nNote that this is not an exact replacement of a ternary since all arguments must be evaluated at the call site.\n\nThe following will not work as expected:\n\n```csharp\n       // will crash with NRE because 'arr[0]' will be executed unconditionally\n      ref var r = ref Choice(arr != null, ref arr[0], ref otherArr[0]);\n```\n\nThe proposed syntax would look like:\n\n```csharp\n     <condition> ? ref <consequence> : ref <alternative>;\n```\n\nThe above attempt with \"Choice\" can be _correctly_ written using ref ternary as:\n\n```csharp\n     ref var r = ref (arr != null ? ref arr[0]: ref otherArr[0]);\n```\n\nThe difference from Choice is that consequence and alternative expressions are accessed in a _truly_ conditional manner, so we do not see a crash if ```arr == null```\n\nThe ternary ref is just a ternary where both alternative and consequence are refs. It will naturally require that consequence/alternative operands are LValues. \nIt will also require that consequence and alternative have types that are identity convertible to each other.\n\nThe type of the expression will be computed similarly to the one for the regular ternary. I.E. in a case if consequence and alternative have identity convertible, but different types, the existing type-merging rules will apply.\n\nSafe-to-return will be assumed conservatively from the conditional operands. If either is unsafe to return the whole thing is unsafe to return.\n\nRef ternary is an LValue and as such it can be passed/assigned/returned by reference;\n\n```csharp\n     // pass by reference\n     foo(ref (arr != null ? ref arr[0]: ref otherArr[0]));\n\n     // return by reference\n     return ref (arr != null ? ref arr[0]: ref otherArr[0]);\n```\n\nBeing an LValue, it can also be assigned to. \n\n```csharp\n    // assign to\n    (arr != null ? ref arr[0]: ref otherArr[0]) = 1;\n```\n\nRef ternary can be used in a regular (not ref) context as well. Although it would not be common since you could as well just use a regular ternary.\n\n```csharp\n     int x = (arr != null ? ref arr[0]: ref otherArr[0]);\n```\n\n\n___\n\nImplementation notes: \n\nThe complexity of the implementation would seem to be the size of a moderate-to-large bug fix. - I.E not very expensive.\nI do not think we need any changes to the syntax or parsing.\nThere is no effect on metadata or interop. The feature is completely expression based.\nNo effect on debugging/PDB either\n"
  },
  {
    "path": "proposals/csharp-7.2/leading-separator.md",
    "content": "# Allow digit separator after 0b or 0x\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/65>\n\nIn C# 7.2, we extend the set of places that digit separators (the underscore character) can appear in integral literals. [Beginning in C# 7.0, separators are permitted between the digits of a literal](../csharp-7.0/digit-separators.md). Now, in C# 7.2, we also permit digit separators before the first significant digit of a binary or hexadecimal literal, after the prefix.\n\n```csharp\n    123      // permitted in C# 1.0 and later\n    1_2_3    // permitted in C# 7.0 and later\n    0x1_2_3  // permitted in C# 7.0 and later\n    0b101    // binary literals added in C# 7.0\n    0b1_0_1  // permitted in C# 7.0 and later\n\n    // in C# 7.2, _ is permitted after the `0x` or `0b`\n    0x_1_2   // permitted in C# 7.2 and later\n    0b_1_0_1 // permitted in C# 7.2 and later\n```\n\nWe do not permit a decimal integer literal to have a leading underscore. A token such as `_123` is an identifier.\n"
  },
  {
    "path": "proposals/csharp-7.2/non-trailing-named-arguments.md",
    "content": "# Non-trailing named arguments\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/570>\n\n## Summary\n[summary]: #summary\nAllow named arguments to be used in non-trailing position, as long as they are used in their correct position. For example: `DoSomething(isEmployed:true, name, age);`.\n\n## Motivation\n[motivation]: #motivation\n\nThe main motivation is to avoid typing redundant information. It is common to name an argument that is a literal (such as `null`, `true`) for the purpose of clarifying the code, rather than of passing arguments out-of-order.\nThat is currently disallowed (`CS1738`) unless all the following arguments are also named.\n\n```csharp\nDoSomething(isEmployed:true, name, age); // currently disallowed, even though all arguments are in position\n// CS1738 \"Named argument specifications must appear after all fixed arguments have been specified\"\n```\n\nSome additional examples:\n```csharp\npublic void DoSomething(bool isEmployed, string personName, int personAge) { ... }\n\nDoSomething(isEmployed:true, name, age); // currently CS1738, but would become legal\nDoSomething(true, personName:name, age); // currently CS1738, but would become legal\nDoSomething(name, isEmployed:true, age); // remains illegal\nDoSomething(name, age, isEmployed:true); // remains illegal\nDoSomething(true, personAge:age, personName:name); // already legal\n```\n\nThis would also work with params:\n```csharp\npublic class Task\n{\n    public static Task When(TaskStatus all, TaskStatus any, params Task[] tasks);\n}\nTask.When(all: TaskStatus.RanToCompletion, any: TaskStatus.Faulted, task1, task2)\n```\n\n## Detailed design\n[design]: #detailed-design\n\nIn §7.5.1 (Argument lists), the spec currently says:\n> An *argument* with an *argument-name* is referred to as a __named argument__, whereas an *argument* without an *argument-name* is a __positional argument__. It is an error for a positional argument to appear after a named argument in an *argument-list*.\n\nThe proposal is to remove this error and update the rules for finding the corresponding parameter for an argument (§7.5.1.1):\n\nArguments in the argument-list of instance constructors, methods, indexers and delegates:\n- [existing rules]\n- An unnamed argument corresponds to no parameter when it is after an out-of-position named argument or a named params argument.\n\nIn particular, this prevents invoking `void M(bool a = true, bool b = true, bool c = true, );` with `M(c: false, valueB);`. The first argument is used out-of-position (the argument is used in first position, but the parameter named \"c\" is in third position), so the following arguments should be named.\n\nIn other words, non-trailing named arguments are only allowed when the name and the position result in finding the same corresponding parameter.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nThis proposal exacerbates existing subtleties with named arguments in overload resolution. For instance:\n\n```csharp\nvoid M(int x, int y) { }\nvoid M<T>(T y, int x) { }\n\nvoid M2()\n{\n    M(3, 4);\n    M(y: 3, x: 4); // Invokes M(int, int)\n    M(y: 3, 4); // Invokes M<T>(T, int)\n}\n```\n\nYou could get this situation today by swapping the parameters:\n\n```csharp\nvoid M(int y, int x) { }\nvoid M<T>(int x, T y) { }\n\nvoid M2()\n{\n    M(3, 4);\n    M(x: 3, y: 4); // Invokes M(int, int)\n    M(3, y: 4); // Invokes M<T>(int, T)\n}\n```\n\nSimilarly, if you have two methods `void M(int a, int b)` and `void M(int x, string y)`, the mistaken invocation `M(x: 1, 2)` will produce a diagnostic based on the second overload (\"cannot convert from 'int' to 'string'\"). This problem already exists when the named argument is used in a trailing position.\n\n## Alternatives\n[alternatives]: #alternatives\n\nThere are a couple of alternatives to consider:\n\n- The status quo\n- Providing IDE assistance to fill-in all the names of trailing arguments when you type specific a name in the middle.\n\nBoth of those suffer from more verbosity, as they introduce multiple named arguments even if you just need one name of a literal at the beginning of the argument list.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n## Design meetings\n[ldm]: #ldm\nThe feature was briefly discussed in LDM on May 16th 2017, with approval in principle (ok to move to proposal/prototype). It was also briefly discussed on June 28th 2017.\n\nRelates to initial discussion https://github.com/dotnet/csharplang/issues/518\nRelates to championed issue https://github.com/dotnet/csharplang/issues/570\n"
  },
  {
    "path": "proposals/csharp-7.2/private-protected.md",
    "content": "# private protected\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/37>\n\n## Summary\n[summary]: #summary\n\nExpose the CLR `protectedAndInternal` accessibility level in C# as `private protected`.\n\n## Motivation\n[motivation]: #motivation\n\nThere are many circumstances in which an API contains members that are only intended to be implemented and used by subclasses contained in the assembly that provides the type. While the CLR provides an accessibility level for that purpose, it is not available in C#. Consequently API owners are forced to either use `internal` protection and self-discipline or a custom analyzer, or to use `protected` with additional documentation explaining that, while the member appears in the public documentation for the type, it is not intended to be part of the public API.  For examples of the latter, see members of Roslyn's `CSharpCompilationOptions` whose names start with `Common`.\n\nDirectly providing support for this access level in C# enables these circumstances to be expressed naturally in the language.\n\n## Detailed design\n[design]: #detailed-design\n\n### `private protected` access modifier\n\nWe propose to add a new access modifier combination `private protected` (which can appear in any order among the modifiers). This maps to the CLR notion of protectedAndInternal, and borrows the same syntax currently used in [C++/CLI](https://docs.microsoft.com/cpp/dotnet/how-to-define-and-consume-classes-and-structs-cpp-cli#BKMK_Member_visibility).\n\nA member declared `private protected` can be accessed within a subclass of its container if that subclass is in the same assembly as the member.\n\nWe modify the language specification as follows (additions in bold). Section numbers are not shown below as they may vary depending on which version of the specification it is integrated into.\n\n-----\n\n> The declared accessibility of a member can be one of the following:\n- Public, which is selected by including a public modifier in the member declaration. The intuitive meaning of public is “access not limited”.\n- Protected, which is selected by including a protected modifier in the member declaration. The intuitive meaning of protected is “access limited to the containing class or types derived from the containing class”.\n- Internal, which is selected by including an internal modifier in the member declaration. The intuitive meaning of internal is “access limited to this assembly”.\n- Protected internal, which is selected by including both a protected and an internal modifier in the member declaration. The intuitive meaning of protected internal is “accessible within this assembly as well as types derived from the containing class”.\n- **Private protected, which is selected by including both a private and a protected modifier in the member declaration. The intuitive meaning of private protected is “accessible within this assembly by types derived from the containing class”.**\n\n-----\n\n> Depending on the context in which a member declaration takes place, only certain types of declared accessibility are permitted. Furthermore, when a member declaration does not include any access modifiers, the context in which the declaration takes place determines the default declared accessibility. \n- Namespaces implicitly have public declared accessibility. No access modifiers are allowed on namespace declarations.\n- Types declared directly in compilation units or namespaces (as opposed to within other types) can have public or internal declared accessibility and default to internal declared accessibility.\n- Class members can have any of the five kinds of declared accessibility and default to private declared accessibility. [Note: A type declared as a member of a class can have any of the five kinds of declared accessibility, whereas a type declared as a member of a namespace can have only public or internal declared accessibility. end note]\n- Struct members can have public, internal, or private declared accessibility and default to private declared accessibility because structs are implicitly sealed. Struct members introduced in a struct (that is, not inherited by that struct) cannot have protected*,* ~~or~~ protected internal**, or private protected** declared accessibility. [Note: A type declared as a member of a struct can have public, internal, or private declared accessibility, whereas a type declared as a member of a namespace can have only public or internal declared accessibility. end note]\n- Interface members implicitly have public declared accessibility. No access modifiers are allowed on interface member declarations.\n- Enumeration members implicitly have public declared accessibility. No access modifiers are allowed on enumeration member declarations.\n\n-----\n\n> The accessibility domain of a nested member M declared in a type T within a program P, is defined as follows (noting that M itself might possibly be a type):\n- If the declared accessibility of M is public, the accessibility domain of M is the accessibility domain of T.\n- If the declared accessibility of M is protected internal, let D be the union of the program text of P and the program text of any type derived from T, which is declared outside P. The accessibility domain of M is the intersection of the accessibility domain of T with D.\n- **If the declared accessibility of M is private protected, let D be the intersection of the program text of P and the program text of any type derived from T. The accessibility domain of M is the intersection of the accessibility domain of T with D.**\n- If the declared accessibility of M is protected, let D be the union of the program text of T and the program text of any type derived from T. The accessibility domain of M is the intersection of the accessibility domain of T with D.\n- If the declared accessibility of M is internal, the accessibility domain of M is the intersection of the accessibility domain of T with the program text of P.\n- If the declared accessibility of M is private, the accessibility domain of M is the program text of T.\n\n-----\n\n> When a protected **or private protected** instance member is accessed outside the program text of the class in which it is declared, and when a protected internal instance member is accessed outside the program text of the program in which it is declared, the access shall take place within a class declaration that derives from the class in which it is declared. Furthermore, the access is required to take place through an instance of that derived class type or a class type constructed from it. This restriction prevents one derived class from accessing protected members of other derived classes, even when the members are inherited from the same base class.\n\n-----\n\n> The permitted access modifiers and the default access for a type declaration depend on the context in which the declaration takes place (§9.5.2):\n- Types declared in compilation units or namespaces can have public or internal access. The default is internal access.\n- Types declared in classes can have public, protected internal, **private protected**, protected, internal, or private access. The default is private access.\n- Types declared in structs can have public, internal, or private access. The default is private access.\n\n-----\n\n> A static class declaration is subject to the following restrictions:\n- A static class shall not include a sealed or abstract modifier. (However, since a static class cannot be instantiated or derived from, it behaves as if it was both sealed and abstract.)\n- A static class shall not include a class-base specification (§16.2.5) and cannot explicitly specify a base class or a list of implemented interfaces. A static class implicitly inherits from type object.\n- A static class shall only contain static members (§16.4.8). [Note: All constants and nested types are classified as static members. end note]\n- A static class shall not have members with protected**, private protected** or protected internal declared accessibility.\n\n> It is a compile-time error to violate any of these restrictions. \n\n-----\n\n> A class-member-declaration can have any one of the ~~five~~**six** possible kinds of declared accessibility (§9.5.2): public, **private protected**, protected internal, protected, internal, or private. Except for the protected internal **and private protected** combination**s**, it is a compile-time error to specify more than one access modifier. When a class-member-declaration does not include any access modifiers, private is assumed.\n\n-----\n\n> Non-nested types can have public or internal declared accessibility and have internal declared accessibility by default. Nested types can have these forms of declared accessibility too, plus one or more additional forms of declared accessibility, depending on whether the containing type is a class or struct:\n- A nested type that is declared in a class can have any of ~~five~~**six** forms of declared accessibility (public, **private protected**, protected internal, protected, internal, or private) and, like other class members, defaults to private declared accessibility.\n- A nested type that is declared in a struct can have any of three forms of declared accessibility (public, internal, or private) and, like other struct members, defaults to private declared accessibility.\n\n-----\n\n> The method overridden by an override declaration is known as the overridden base method For an override method M declared in a class C, the overridden base method is determined by examining each base class type of C, starting with the direct base class type of C and continuing with each successive direct base class type, until in a given base class type at least one accessible method is located which has the same signature as M after substitution of type arguments. For the purposes of locating the overridden base method, a method is considered accessible if it is public, if it is protected, if it is protected internal, or if it is **either** internal **or private protected** and declared in the same program as C.\n\n-----\n\n> The use of accessor-modifiers is governed by the following restrictions:\n- An accessor-modifier shall not be used in an interface or in an explicit interface member implementation.\n- For a property or indexer that has no override modifier, an accessor-modifier is permitted only if the property or indexer has both a get and set accessor, and then is permitted only on one of those accessors.\n- For a property or indexer that includes an override modifier, an accessor shall match the accessor-modifier, if any, of the accessor being overridden.\n- The accessor-modifier shall declare an accessibility that is strictly more restrictive than the declared accessibility of the property or indexer itself. To be precise:\n  - If the property or indexer has a declared accessibility of public, the accessor-modifier may be either **private protected**, , protected internal, internal, protected, or private.\n  - If the property or indexer has a declared accessibility of protected internal, the accessor-modifier may be either **private protected**, internal, protected, or private.\n  - If the property or indexer has a declared accessibility of internal or protected, the accessor-modifier shall be **either private protected or** private.\n  - **If the property or indexer has a declared accessibility of private protected, the accessor-modifier shall be private.**\n  - If the property or indexer has a declared accessibility of private, no accessor-modifier may be used.\n\n-----\n\n> Since inheritance isn’t supported for structs, the declared accessibility of a struct member cannot be protected, **private protected**, or protected internal.\n\n-----\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nAs with any language feature, we must question whether the additional complexity to the language is repaid in the additional clarity offered to the body of C# programs that would benefit from the feature.\n\n## Alternatives\n[alternatives]: #alternatives\n\nAn alternative would be the provision of an API combining an attribute and an analyzer. The attribute is placed by the programmer on an `internal` member to indicates that the member is intended to be used only in subclasses, and the analyzer checks that those restrictions are obeyed. \n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\nThe implementation is largely complete. The only open work item is drafting a corresponding specification for VB.\n\n## Design meetings\n\nTBD\n"
  },
  {
    "path": "proposals/csharp-7.2/readonly-ref.md",
    "content": "# Readonly references\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/38>\n\n## Summary\n[summary]: #summary\n\nThe \"readonly references\" feature is actually a group of features that leverage the efficiency of passing variables by reference, but without exposing the data to modifications:  \n- `in` parameters\n- `ref readonly` returns\n- `readonly` structs\n- `ref`/`in` extension methods\n- `ref readonly` locals\n- `ref` conditional expressions\n\n## Passing arguments as readonly references.\n\nThere is an existing proposal that touches this topic https://github.com/dotnet/roslyn/issues/115 as a special case of readonly parameters without going into many details.\nHere I just want to acknowledge that the idea by itself is not very new.\n\n### Motivation\n\nPrior to this feature C# did not have an efficient way of expressing a desire to pass struct variables into method calls for readonly purposes with no intention of modifying. Regular by-value argument passing implies copying, which adds unnecessary costs.  That drives users to use by-ref argument passing and rely on comments/documentation to indicate that the data is not supposed to be mutated by the callee. It is not a good solution for many reasons.  \nThe examples are numerous - vector/matrix math operators in graphics libraries like [XNA](https://msdn.microsoft.com/library/bb194944.aspx) are known to have ref operands purely because of performance considerations. There is code in Roslyn compiler itself that uses structs to avoid allocations and then passes them by reference to avoid copying costs.\n\n### Solution (`in` parameters)\n\nSimilarly to the `out` parameters, `in` parameters are passed as managed references with additional guarantees from the callee.  \nUnlike `out` parameters which _must_ be assigned by the callee before any other use, `in` parameters cannot be assigned by the callee at all.\n\nAs a result `in` parameters allow for effectiveness of indirect argument passing without exposing arguments to mutations by the callee.\n\n### Declaring `in` parameters\n\n`in` parameters are declared by using `in` keyword as a modifier in the parameter signature.\n\nFor all purposes the `in` parameter is treated as a `readonly` variable. Most of the restrictions on the use of `in` parameters inside the method are the same as with `readonly` fields.\n\n> Indeed an `in` parameter may represent a `readonly` field. Similarity of restrictions is not a coincidence.\n\nFor example fields of an `in` parameter which has a struct type are all recursively classified as `readonly` variables .\n\n```csharp\nstatic Vector3 Add (in Vector3 v1, in Vector3 v2)\n{\n    // not OK!!\n    v1 = default(Vector3);\n\n    // not OK!!\n    v1.X = 0;\n\n    // not OK!!\n    foo(ref v1.X);\n\n    // OK\n    return new Vector3(v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z);\n}\n```\n\n- `in` parameters are allowed anywhere where ordinary byval parameters are allowed. This includes indexers, operators (including conversions), delegates, lambdas, local functions.\n\n> ```csharp\n>  (in int x) => x                                                     // lambda expression  \n>  TValue this[in TKey index];                                         // indexer\n>  public static Vector3 operator +(in Vector3 x, in Vector3 y) => ... // operator\n>  ```\n\n- `in` is not allowed in combination with `out` or with anything that `out` does not combine with.\n\n- It is not permitted to overload on `ref`/`out`/`in` differences.\n\n- It is permitted to overload on ordinary byval and `in` differences.\n\n- For the purpose of OHI (Overloading, Hiding, Implementing), `in` behaves similarly to an `out` parameter.\nAll the same rules apply.\nFor example the overriding method will have to match `in` parameters with `in` parameters of an identity-convertible type.\n\n- For the purpose of delegate/lambda/method group conversions, `in` behaves similarly to an `out` parameter.\nLambdas and applicable method group conversion candidates will have to match `in` parameters of the target delegate with `in` parameters of an identity-convertible type.\n\n- For the purpose of generic variance, `in` parameters are nonvariant.\n\n> NOTE: There are no warnings on `in` parameters that have reference or primitives types.\nIt may be pointless in general, but in some cases user must/want to pass primitives as `in`. Examples - overriding a generic method like `Method(in T param)` when `T` was substituted to be `int`, or when having methods like `Volatile.Read(in int location)`\n>\n> It is conceivable to have an analyzer that warns in cases of inefficient use of `in` parameters, but the rules for such analysis would be too fuzzy to be a part of a language specification.\n\n### Use of `in` at call sites. (`in` arguments)\n\nThere are two ways to pass arguments to `in` parameters.\n\n#### `in` arguments can match `in` parameters:\n\nAn argument with an `in` modifier at the call site can match `in` parameters.\n\n```csharp\nint x = 1;\n\nvoid M1<T>(in T x)\n{\n  // . . .\n}\n\nvar x = M1(in x);  // in argument to a method\n\nclass D\n{\n    public string this[in Guid index];\n}\n\nD dictionary = . . . ;\nvar y = dictionary[in Guid.Empty]; // in argument to an indexer\n```\n\n- `in` argument must be a _readable_ LValue(*).\nExample: `M1(in 42)` is invalid\n\n> (*) The notion of [LValue/RValue](https://en.wikipedia.org/wiki/Value_(computer_science)#lrvalue) vary between languages.  \nHere, by LValue I mean an expression that represent a location that can be referred to directly.\nAnd RValue means an expression that yields a temporary result which does not persist on its own.  \n\n- In particular it is valid to pass `readonly` fields, `in` parameters or other formally `readonly` variables as `in` arguments.\nExample: `dictionary[in Guid.Empty]` is legal. `Guid.Empty` is a static readonly field.\n\n- `in` argument must have type _identity-convertible_ to the type of the parameter.\nExample: `M1<object>(in Guid.Empty)` is invalid. `Guid.Empty` is not _identity-convertible_ to `object`\n\nThe motivation for the above rules is that `in` arguments guarantee _aliasing_ of the argument variable. The callee always receives a direct reference to the same location as represented by the argument.\n\n- in rare situations when `in` arguments must be stack-spilled due to `await` expressions used as operands of the same call, the behavior is the same as with `out` and `ref` arguments - if the variable cannot be spilled in referentially-transparent manner, an error is reported.\n\nExamples:\n1. `M1(in staticField, await SomethingAsync())`  is valid.\n`staticField` is a static field which can be accessed more than once without observable side effects. Therefore both the order of side effects and aliasing requirements can be provided.\n2. `M1(in RefReturningMethod(), await SomethingAsync())`  will produce an error.\n`RefReturningMethod()` is a `ref` returning method. A method call may have observable side effects, therefore it must be evaluated before the `SomethingAsync()` operand. However the result of the invocation is a reference that cannot be preserved across the `await` suspension point which make the direct reference requirement impossible.\n\n> NOTE: the stack spilling errors are considered to be implementation-specific limitations. Therefore they do not have effect on overload resolution or lambda inference.\n\n#### Ordinary byval arguments can match `in` parameters:\n\nRegular arguments without modifiers can match `in` parameters. In such case the arguments have the same relaxed constraints as an ordinary byval arguments would have.\n\nThe motivation for this scenario is that `in` parameters in APIs may result in inconveniences for the user when arguments cannot be passed as a direct reference - ex: literals, computed or `await`-ed results or arguments that happen to have more specific types.  \nAll these cases have a trivial solution of storing the argument value in a temporary local of appropriate type and passing that local as an `in` argument.  \nTo reduce the need for such boilerplate code compiler can perform the same transformation, if needed, when `in` modifier is not present at the call site.  \n\nIn addition, in some cases, such as invocation of operators, or `in` extension methods, there is no syntactical way to specify `in` at all. That alone requires specifying the behavior of ordinary byval arguments when they match `in` parameters.\n\nIn particular:\n\n- it is valid to pass RValues.\nA reference to a temporary is passed in such case.\nExample:\n```csharp\nPrint(\"hello\");      // not an error.\n\nvoid Print<T>(in T x)\n{\n  //. . .\n}\n```\n\n- implicit conversions are allowed.\n\n> This is actually a special case of passing an RValue  \n\nA reference to a temporary holding converted value is passed in such case.\nExample:\n```csharp\nPrint<int>(Short.MaxValue)     // not an error.\n```\n\n- in a case of a receiver of an `in` extension method (as opposed to `ref` extension methods), RValues or implicit _this-argument-conversions_ are allowed.\nA reference to a temporary holding converted value is passed in such case.\nExample:\n```csharp\npublic static IEnumerable<T> Concat<T>(in this (IEnumerable<T>, IEnumerable<T>) arg)  => . . .;\n\n(\"aa\", \"bb\").Concat<char>()    // not an error.\n```\nMore information on `ref`/`in` extension methods is provided further in this document.\n\n- argument spilling due to `await` operands could spill \"by-value\", if necessary.\nIn scenarios where providing a direct reference to the argument is not possible due to intervening `await` a copy of the argument's value is spilled instead.  \nExample:\n```csharp\nM1(RefReturningMethod(), await SomethingAsync())   // not an error.\n```\nSince the result of a side-effecting invocation is a reference that cannot be preserved across `await` suspension, a temporary containing the actual value will be preserved instead (as it would in an ordinary byval parameter case).\n\n#### Omitted optional arguments\n\nIt is permitted for an `in` parameter to specify a default value. That makes the corresponding argument optional.\n\nOmitting optional argument at the call site results in passing the default value via a temporary.\n\n```csharp\nPrint(\"hello\");      // not an error, same as\nPrint(\"hello\", c: Color.Black);\n\nvoid Print(string s, in Color c = Color.Black)\n{\n    // . . .\n}\n```\n\n### Aliasing behavior in general\n\nJust like `ref` and `out` variables, `in` variables are references/aliases to existing locations.\n\nWhile callee is not allowed to write into them, reading an `in` parameter can observe different values as a side effect of other evaluations.\n\nExample:\n\n```C#\nstatic Vector3 v = Vector3.UnitY;\n\nstatic void Main()\n{\n    Test(v);\n}\n\nstatic void Test(in Vector3 v1)\n{\n    Debug.Assert(v1 == Vector3.UnitY);\n    // changes v1 deterministically (no races required)\n    ChangeV();\n    Debug.Assert(v1 == Vector3.UnitX);\n}\n\nstatic void ChangeV()\n{\n    v = Vector3.UnitX;\n}\n```\n\n### `in` parameters and capturing of local variables.  \nFor the purpose of lambda/async capturing `in` parameters behave the same as `out` and `ref` parameters.\n\n- `in` parameters cannot be captured in a closure\n- `in` parameters are not allowed in iterator methods\n- `in` parameters are not allowed in async methods\n\n### Temporary variables.  \nSome uses of `in` parameter passing may require indirect use of a temporary local variable:  \n- `in` arguments are always passed as direct aliases when call-site uses `in`. Temporary is never used in such case.\n- `in` arguments are not required to be direct aliases when call-site does not use `in`. When argument is not an LValue, a temporary may be used.\n- `in` parameter may have default value. When corresponding argument is omitted at the call site, the default value are passed via a temporary.\n- `in` arguments may have implicit conversions, including those that do not preserve identity. A temporary is used in those cases.\n- receivers of ordinary struct calls may not be writeable LValues (**existing case!**). A temporary is used in those cases.\n\nThe life time of the argument temporaries matches the closest encompassing scope of the call-site.\n\nThe formal life time of temporary variables is semantically significant in scenarios involving escape analysis of variables returned by reference.\n\n### Metadata representation of `in` parameters.\nWhen `System.Runtime.CompilerServices.IsReadOnlyAttribute` is applied to a byref parameter, it means that the parameter is an `in` parameter.\n\nIn addition, if the method is *abstract* or *virtual*, then the signature of such parameters (and only such parameters) must have `modreq[System.Runtime.InteropServices.InAttribute]`.\n\n**Motivation**: this is done to ensure that in a case of method overriding/implementing the `in` parameters match.\n\nSame requirements apply to `Invoke` methods in delegates.\n\n**Motivation**: this is to ensure that existing compilers cannot simply ignore `readonly` when creating or assigning delegates.\n\n**Warning**: this is currently not implemented. See https://github.com/dotnet/roslyn/issues/69079.\n\n## Returning by readonly reference.\n\n### Motivation\nThe motivation for this sub-feature is roughly symmetrical to the reasons for the `in` parameters - avoiding copying, but on the returning side. Prior to this feature, a method or an indexer had two options: 1) return by reference and be exposed to possible mutations or 2) return by value which results in copying.\n\n### Solution (`ref readonly` returns)  \nThe feature allows a member to return variables by reference without exposing them to mutations.\n\n### Declaring `ref readonly` returning members\n\nA combination of modifiers `ref readonly` on the return signature is used to to indicate that the member returns a readonly reference.\n\nFor all purposes a `ref readonly` member is treated as a `readonly` variable - similar to `readonly` fields and `in` parameters.\n\nFor example fields of `ref readonly` member which has a struct type are all recursively classified as `readonly` variables. - It is permitted to pass them as `in` arguments, but not as `ref` or `out` arguments.\n\n```csharp\nref readonly Guid Method1()\n{\n}\n\nMethod2(in Method1()); // valid. Can pass as `in` argument.\n\nMethod3(ref Method1()); // not valid. Cannot pass as `ref` argument\n```\n\n- `ref readonly` returns are allowed in the same places were `ref` returns are allowed.\nThis includes indexers, delegates, lambdas, local functions.\n\n- It is not permitted to overload on `ref`/`ref readonly` /  differences.\n\n- It is permitted to overload on ordinary byval and `ref readonly` return differences.\n\n- For the purpose of OHI (Overloading, Hiding, Implementing), `ref readonly` is similar but distinct from `ref`.\nFor example the a method that overrides `ref readonly` one, must itself be `ref readonly` and have identity-convertible type.\n\n- For the purpose of delegate/lambda/method group conversions, `ref readonly` is similar but distinct from `ref`.\nLambdas and applicable method group conversion candidates have to match `ref readonly` return of the target delegate with `ref readonly` return of the type that is identity-convertible.\n\n- For the purpose of generic variance, `ref readonly` returns are nonvariant.\n\n> NOTE: There are no warnings on `ref readonly` returns that have reference or primitives types.\nIt may be pointless in general, but in some cases user must/want to pass primitives as `in`. Examples - overriding a generic method like `ref readonly T Method()` when `T` was substituted to be `int`.\n>\n>It is conceivable to have an analyzer that warns in cases of inefficient use of `ref readonly` returns, but the rules for such analysis would be too fuzzy to be a part of a language specification.\n\n### Returning from `ref readonly` members\nInside the method body the syntax is the same as with regular ref returns. The `readonly` will be inferred from the containing method.\n\nThe motivation is that `return ref readonly <expression>` is unnecessary long and only allows for mismatches on the `readonly` part that would always result in errors.\nThe `ref` is, however, required for consistency with other scenarios where something is passed via strict aliasing vs. by value.\n\n> Unlike the case with `in` parameters, `ref readonly` returns never return via a local copy. Considering that the copy would cease to exist immediately upon returning such practice would be pointless and dangerous. Therefore `ref readonly` returns are always direct references.\n\nExample:\n\n```csharp\nstruct ImmutableArray<T>\n{\n    private readonly T[] array;\n\n    public ref readonly T ItemRef(int i)\n    {\n        // returning a readonly reference to an array element\n        return ref this.array[i];\n    }\n}\n\n```\n\n- An argument of `return ref` must be an LValue (**existing rule**)\n- An argument of `return ref` must be \"safe to return\" (**existing rule**)\n- In a `ref readonly` member an argument of `return ref` is _not required to be writeable_ .\nFor example such member can ref-return a readonly field or one of its `in` parameters.\n\n### Safe to Return rules.\nNormal safe to return rules for references will apply to readonly references as well.\n\nNote that a `ref readonly` can be obtained from a regular `ref` local/parameter/return, but not the other way around. Otherwise the safety of `ref readonly` returns is inferred the same way as for regular `ref` returns.\n\nConsidering that RValues can be passed as `in` parameter and returned as `ref readonly` we need one more rule - **RValues are not safe-to-return by reference**.\n\n> Consider the situation when an RValue is passed to an `in` parameter via a copy and then returned back in a form of a `ref readonly`. In the context of the caller the result of such invocation is a reference to local data and as such is unsafe to return.\n> Once RValues are not safe to return, the existing rule `#6` already handles this case.\n\nExample:\n```csharp\nref readonly Vector3 Test1()\n{\n    // can pass an RValue as \"in\" (via a temp copy)\n    // but the result is not safe to return\n    // because the RValue argument was not safe to return by reference\n    return ref Test2(default(Vector3));\n}\n\nref readonly Vector3 Test2(in Vector3 r)\n{\n    // this is ok, r is returnable\n    return ref r;\n}\n```\n\nUpdated `safe to return` rules:\n\n1.\t**refs to variables on the heap are safe to return**\n2.\t**ref/in parameters are safe to return**\n`in` parameters naturally can only be returned as readonly.\n3.\t**out parameters are safe to return** (but must be definitely assigned, as is already the case today)\n4.\t**instance struct fields are safe to return as long as the receiver is safe to return**\n5.\t**'this' is not safe to return from struct members**\n6.\t**a ref, returned from another method is safe to return if all refs/outs passed to that method as formal parameters were safe to return.**\n*Specifically it is irrelevant if receiver is safe to return, regardless whether receiver is a struct, class or typed as a generic type parameter.*\n7.\t**RValues are not safe to return by reference.**\n*Specifically RValues are safe to pass as in parameters.*\n\n> NOTE: There are additional rules regarding safety of returns that come into play when ref-like types and ref-reassignments are involved.\n> The rules equally apply to `ref` and `ref readonly` members and therefore are not mentioned here.\n\n### Aliasing behavior.\n`ref readonly` members provide the same aliasing behavior as ordinary `ref` members (except for being readonly).\nTherefore for the purpose of capturing in lambdas, async, iterators, stack spilling etc... the same restrictions apply. - I.E. due to inability to capture the actual references and due to side-effecting nature of member evaluation such scenarios are disallowed.\n\n> It is permitted and required to make a copy when `ref readonly` return is a receiver of regular struct methods, which take `this` as an ordinary writeable reference. Historically in all cases where such invocations are applied to readonly variable a local copy is made.\n\n### Metadata representation.\nWhen `System.Runtime.CompilerServices.IsReadOnlyAttribute` is applied to the return of a byref returning method, it means that the method returns a readonly reference.\n\nIn addition, the result signature of such methods (and only those methods) must have `modreq[System.Runtime.InteropServices.InAttribute]`.\n\n**Motivation**: this is to ensure that existing compilers cannot simply ignore `readonly` when invoking methods with `ref readonly` returns\n\n## Readonly structs\nIn short - a feature that makes `this` parameter of all instance members of a struct, except for constructors, an `in` parameter.\n\n### Motivation\nCompiler must assume that any method call on a struct instance may modify the instance. Indeed a writeable reference is passed to the method as `this` parameter and fully enables this behavior. To allow such invocations on `readonly` variables, the invocations are applied to temp copies. That could be unintuitive and sometimes forces people to abandon `readonly` for performance reasons.  \nExample: https://codeblog.jonskeet.uk/2014/07/16/micro-optimization-the-surprising-inefficiency-of-readonly-fields/\n\nAfter adding support for `in` parameters and `ref readonly` returns the problem of defensive copying will get worse since readonly variables will become more common.\n\n### Solution\nAllow `readonly` modifier on struct declarations which would result in `this` being treated as `in` parameter on all struct instance methods except for constructors.\n\n```csharp\nstatic void Test(in Vector3 v1)\n{\n    // no need to make a copy of v1 since Vector3 is a readonly struct\n    System.Console.WriteLine(v1.ToString());\n}\n\nreadonly struct Vector3\n{\n    . . .\n\n    public override string ToString()\n    {\n        // not OK!!  `this` is an `in` parameter\n        foo(ref this.X);\n\n        // OK\n        return $\"X: {X}, Y: {Y}, Z: {Z}\";\n    }\n}\n```\n\n### Restrictions on members of readonly struct\n- Instance fields of a readonly struct must be readonly.  \n**Motivation:** can only be written to externally, but not through members.\n- Instance autoproperties of a readonly struct must be get-only.  \n**Motivation:** consequence of restriction on instance fields.\n- Readonly struct may not declare field-like events.  \n**Motivation:** consequence of restriction on instance fields.\n\n### Metadata representation.\nWhen `System.Runtime.CompilerServices.IsReadOnlyAttribute` is applied to a value type, it means that the type is a `readonly struct`.\n\nIn particular:\n-  The identity of the `IsReadOnlyAttribute` type is unimportant. In fact it can be embedded by the compiler in the containing assembly if needed.\n\n## `ref`/`in` extension methods\nThere is actually an existing proposal (https://github.com/dotnet/roslyn/issues/165) and corresponding prototype PR (https://github.com/dotnet/roslyn/pull/15650).\nI just want to acknowledge that this idea is not entirely new. It is, however, relevant here since `ref readonly` elegantly removes the most contentious issue about such methods - what to do with RValue receivers.\n\nThe general idea is allowing extension methods to take the `this` parameter by reference, as long as the type is known to be a struct type.\n\n```csharp\npublic static void Extension(ref this Guid self)\n{\n    // do something\n}\n```\n\nThe reasons for writing such extension methods are primarily:  \n1.\tAvoid copying when receiver is a large struct\n2.\tAllow mutating extension methods on structs\n\nThe reasons why we do not want to allow this on classes  \n1.\tIt would be of very limited purpose.\n2.\tIt would break long standing invariant that a method call cannot turn non-`null` receiver to become `null` after invocation.\n> In fact, currently a non-`null` variable cannot become `null` unless _explicitly_ assigned or passed by `ref` or `out`.\n> That greatly aids readability or other forms of \"can this be a null here\" analysis.\n3.\tIt would be hard to reconcile with \"evaluate once\" semantics of null-conditional accesses.\nExample:\n`obj.stringField?.RefExtension(...)` - need to capture a copy of `stringField` to make the null check meaningful, but then assignments to `this` inside RefExtension would not be reflected back to the field.\n\nAn ability to declare extension methods on **structs** that take the first argument by reference was a long-standing request. One of the blocking consideration was \"what happens if receiver is not an LValue?\".\n\n- There is a precedent that any extension method could also be called as a static method (sometimes it is the only way to resolve ambiguity). It would dictate that RValue receivers should be disallowed.\n- On the other hand there is a practice of making invocation on a copy in similar situations when struct instance methods are involved.\n\nThe reason why the \"implicit copying\" exists is because the majority of struct methods do not actually modify the struct while not being able to indicate that. Therefore the most practical solution was to just make the invocation on a copy, but this practice is known for harming performance and causing bugs.\n\nNow, with availability of `in` parameters, it is possible for an extension to signal the intent. Therefore the conundrum can be resolved by requiring `ref` extensions to be called with writeable receivers while `in` extensions permit implicit copying if necessary.\n\n```csharp\n// this can be called on either RValue or an LValue\npublic static void Reader(in this Guid self)\n{\n    // do something nonmutating.\n    WriteLine(self == default(Guid));\n}\n\n// this can be called only on an LValue\npublic static void Mutator(ref this Guid self)\n{\n    // can mutate self\n    self = new Guid();\n}\n```\n\n### `in` extensions and generics.\nThe purpose of `ref` extension methods is to mutate the receiver directly or by invoking mutating members. Therefore `ref this T` extensions are allowed as long as `T` is constrained to be a struct.\n\nOn the other hand `in` extension methods exist specifically to reduce implicit copying. However any use of an `in T` parameter will have to be done through an interface member. Since all interface members are considered mutating, any such use would require a copy. - Instead of reducing copying, the effect would be the opposite. Therefore `in this T` is not allowed when `T` is a generic type parameter regardless of constraints.\n\n### Valid kinds of extension methods (recap):\nThe following forms of `this` declaration in an extension method are now allowed:\n1) `this T arg` - regular byval extension. (**existing case**)\n- T can be any type, including reference types or type parameters.\nInstance will be the same variable after the call.\nAllows implicit conversions of _this-argument-conversion_ kind.\nCan be called on RValues.\n\n- `in this T self` - `in` extension.\nT must be an actual struct type.\nInstance will be the same variable after the call.\nAllows implicit conversions of _this-argument-conversion_ kind.\nCan be called on RValues (may be invoked on a temp if needed).\n\n- `ref this T self` - `ref` extension.\nT must be a struct type or a generic type parameter constrained to be a struct.\nInstance may be written to by the invocation.\nAllows only identity conversions.\nMust be called on writeable LValue. (never invoked via a temp).\n\n## Readonly ref locals.\n\n### Motivation.\nOnce `ref readonly` members were introduced, it was clear from the use that they need to be paired with appropriate kind of local. Evaluation of a member may produce or observe side effects, therefore if the result must be used more than once, it needs to be stored. Ordinary `ref` locals do not help here since they cannot be assigned a `readonly` reference.   \n\n### Solution.\nAllow declaring `ref readonly` locals. This is a new kind of `ref` locals that is not writeable. As a result `ref readonly` locals can accept references to readonly variables without exposing these variables to writes.\n\n### Declaring and using `ref readonly` locals.\n\nThe syntax of such locals uses `ref readonly` modifiers at declaration site (in that specific order). Similarly to ordinary `ref` locals, `ref readonly` locals must be ref-initialized at declaration. Unlike regular `ref` locals, `ref readonly` locals can refer to `readonly` LValues like `in` parameters, `readonly` fields, `ref readonly` methods.\n\nFor all purposes a `ref readonly` local is treated as a `readonly` variable. Most of the restrictions on the use are the same as with `readonly` fields or `in` parameters.\n\nFor example fields of an `in` parameter which has a struct type are all recursively classified as `readonly` variables .   \n\n```csharp\nstatic readonly ref Vector3 M1() => . . .\n\nstatic readonly ref Vector3 M1_Trace()\n{\n    // OK\n    ref readonly var r1 = ref M1();\n\n    // Not valid. Need an LValue\n    ref readonly Vector3 r2 = ref default(Vector3);\n\n    // Not valid. r1 is readonly.\n    Mutate(ref r1);\n\n    // OK.\n    Print(in r1);\n\n    // OK.\n    return ref r1;\n}\n```\n\n### Restrictions on use of `ref readonly` locals\nExcept for their `readonly` nature, `ref readonly` locals behave like ordinary `ref` locals and are subject to exactly same restrictions.  \nFor example restrictions related to capturing in closures, declaring in `async` methods or the `safe-to-return` analysis equally applies to `ref readonly` locals.\n\n## Ternary `ref` expressions. (aka \"Conditional LValues\")\n\n### Motivation\nUse of `ref` and `ref readonly` locals exposed a need to ref-initialize such locals with one or another target variable based on a condition.\n\nA typical workaround is to introduce a method like:\n\n```csharp\nref T Choice(bool condition, ref T consequence, ref T alternative)\n{\n    if (condition)\n    {\n         return ref consequence;\n    }\n    else\n    {\n         return ref alternative;\n    }\n}\n```\n\nNote that `Choice` is not an exact replacement of a ternary since _all_ arguments must be evaluated at the call site, which was leading to unintuitive behavior and bugs.\n\nThe following will not work as expected:\n\n```csharp\n    // will crash with NRE because 'arr[0]' will be executed unconditionally\n    ref var r = ref Choice(arr != null, ref arr[0], ref otherArr[0]);\n```\n\n### Solution\nAllow special kind of conditional expression that evaluates to a reference to one of LValue argument based on a condition.\n\n### Using `ref` ternary expression.\n\nThe syntax for the `ref` flavor of a conditional expression is `<condition> ? ref <consequence> : ref <alternative>;`\n\nJust like with the ordinary conditional expression only `<consequence>` or `<alternative>` is evaluated depending on result of the boolean condition expression.\n\nUnlike ordinary conditional expression, `ref` conditional expression:\n- requires that `<consequence>` and `<alternative>` are LValues.\n- `ref` conditional expression itself is an LValue and\n- `ref` conditional expression is writeable if both `<consequence>` and `<alternative>` are writeable LValues\n\nExamples:  \n`ref` ternary is an LValue and as such it can be passed/assigned/returned by reference;\n```csharp\n     // pass by reference\n     foo(ref (arr != null ? ref arr[0]: ref otherArr[0]));\n\n     // return by reference\n     return ref (arr != null ? ref arr[0]: ref otherArr[0]);\n```\n\nBeing an LValue, it can also be assigned to.\n```csharp\n     // assign to\n     (arr != null ? ref arr[0]: ref otherArr[0]) = 1;\n\n     // error. readOnlyField is readonly and thus conditional expression is readonly\n     (arr != null ? ref arr[0]: ref obj.readOnlyField) = 1;\n```\n\nCan be used as a receiver of a method call and skip copying if necessary.\n```csharp\n     // no copies\n     (arr != null ? ref arr[0]: ref otherArr[0]).StructMethod();\n\n     // invoked on a copy.\n     // The receiver is `readonly` because readOnlyField is readonly.\n     (arr != null ? ref arr[0]: ref obj.readOnlyField).StructMethod();\n\n     // no copies. `ReadonlyStructMethod` is a method on a `readonly` struct\n     // and can be invoked directly on a readonly receiver\n     (arr != null ? ref arr[0]: ref obj.readOnlyField).ReadonlyStructMethod();\n```\n\n`ref` ternary can be used in a regular (not ref) context as well.\n```csharp\n     // only an example\n     // a regular ternary could work here just the same\n     int x = (arr != null ? ref arr[0]: ref otherArr[0]);\n```\n\n### Drawbacks\n[drawbacks]: #drawbacks\n\nI can see two major arguments against enhanced support for references and readonly references:\n\n1) The problems that are solved here are very old. Why suddenly solve them now, especially since it would not help existing code?\n\nAs we find C# and .Net used in new domains, some problems become more prominent.  \nAs examples of environments that are more critical than average about computation overheads, I can list\n\n* cloud/datacenter scenarios where computation is billed for and responsiveness is a competitive advantage.\n* Games/VR/AR with soft-realtime requirements on latencies     \n\nThis feature does not sacrifice any of the existing strengths such as type-safety, while allowing to lower overheads in some common scenarios.\n\n2) Can we reasonably guarantee that the callee will play by the rules when it opts into `readonly` contracts?\n\nWe have similar trust when using `out`. Incorrect implementation of `out` can cause unspecified behavior, but in reality it rarely happens.  \n\nMaking the formal verification rules familiar with `ref readonly` would further mitigate the trust issue.\n\n### Alternatives\n[alternatives]: #alternatives\n\nThe main competing design is really \"do nothing\".\n\n### Unresolved questions\n[unresolved]: #unresolved-questions\n\n### Design meetings\n\nhttps://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-02-22.md\nhttps://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-03-01.md\nhttps://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-08-28.md\nhttps://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-09-25.md\nhttps://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-09-27.md\n"
  },
  {
    "path": "proposals/csharp-7.2/readonly-struct.md",
    "content": "﻿## Readonly structs\n\nIn C# 7.2, we added a feature permitting a struct declaration to have the `readonly` modifier.  This is a placeholder for that feature's specification.\n"
  },
  {
    "path": "proposals/csharp-7.2/ref-extension-methods.md",
    "content": "﻿## Ref Extension Methods\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/186>\n\nIn C# 7.2, we added support for *ref extension methods*.  This is a placeholder for the feature's specification.\n"
  },
  {
    "path": "proposals/csharp-7.2/ref-struct-and-span.md",
    "content": "﻿## Ref Structs and Span\n\nIn C# 7.2 we added support for *ref struct* types.  This is a placeholder for the specification.\n"
  },
  {
    "path": "proposals/csharp-7.2/span-safety.md",
    "content": "# Compile time enforcement of safety for ref-like types\n\n## Introduction\n\nThe main reason for the additional safety rules when dealing with types like `Span<T>` and `ReadOnlySpan<T>` is that such types must be confined to the execution stack.\n \nThere are two reasons why `Span<T>` and similar types must be a stack-only types.\n\n1. `Span<T>` is semantically a struct containing a reference and a range - `(ref T data, int length)`. Regardless of actual implementation, writes to such struct would not be atomic. Concurrent \"tearing\" of such struct would lead to the possibility of `length` not matching the `data`, causing out-of-range accesses and type-safety violations, which ultimately could result in GC heap corruption in seemingly \"safe\" code.\n2. Some implementations of `Span<T>` literally contain a managed pointer in one of its fields. Managed pointers are not supported as fields of heap objects and code that manages to put a managed pointer on the GC heap typically crashes at JIT time.\n\nAll the above problems would be alleviated if instances of `Span<T>` are constrained to exist only on the execution stack. \n\nAn additional problem arises due to composition. It would be generally desirable to build more complex data types that would embed `Span<T>` and `ReadOnlySpan<T>` instances. Such composite types would have to be structs and would share all the hazards and requirements of `Span<T>`. As a result the safety rules described here should be viewed as applicable to the whole range of **_ref-like types_**.\n\nThe [draft language specification](#draft-language-specification) is intended to ensure that values of a ref-like type occur only on the stack.\n\n## Generalized `ref-like` types in source code\n\n`ref-like` structs are explicitly marked in the source code using `ref` modifier:\n\n```csharp\nref struct TwoSpans<T>\n{\n\t// can have ref-like instance fields\n\tpublic Span<T> first;\n\tpublic Span<T> second;\n} \n\n// error: arrays of ref-like types are not allowed. \nTwoSpans<T>[] arr = null;\n\n```\n\nDesignating a struct as ref-like will allow the struct to have ref-like instance fields and will also make all the requirements of ref-like types applicable to the struct. \n\n## Metadata representation of ref-like structs\n\nRef-like structs will be marked with **System.Runtime.CompilerServices.IsRefLikeAttribute** attribute.\n\nThe attribute will be added to common base libraries such as `mscorlib`. In a case if the attribute is not available, compiler will generate an internal one similarly to other embedded-on-demand attributes such as `IsReadOnlyAttribute`.\n\nAn additional measure will be taken to prevent the use of ref-like structs in compilers not familiar with the safety rules (this includes C# compilers prior to the one in which this feature is implemented). \n\nHaving no other good alternatives that work in old compilers without servicing, an `Obsolete` attribute with a known string will be added to all ref-like structs. Compilers that know how to use ref-like types will ignore this particular form of `Obsolete`.\n\nA typical metadata representation:\n\n```csharp\n    [IsRefLike]\n    [Obsolete(\"Types with embedded references are not supported in this version of your compiler.\")]\n    public struct TwoSpans<T>\n    {\n       // . . . .\n    }\n```\n\nNOTE: it is not the goal to make it so that any use of ref-like types on old compilers fails 100%. That is hard to achieve and is not strictly necessary. For example there would always be a way to get around the `Obsolete` using dynamic code or, for example, creating an array of ref-like types through reflection.\n\nIn particular, if user wants to actually put an `Obsolete` or `Deprecated` attribute on a ref-like type, we will have no choice other than not emitting the predefined one since `Obsolete` attribute cannot be applied more than once..  \n\n## Examples:\n\n```csharp\nSpanLikeType M1(ref SpanLikeType x, Span<byte> y)\n{\n    // this is all valid, unconcerned with stack-referring stuff\n    var local = new SpanLikeType(y);\n    x = local;\n    return x;\n}\n\nvoid Test1(ref SpanLikeType param1, Span<byte> param2)\n{\n    Span<byte> stackReferring1 = stackalloc byte[10];\n    var stackReferring2 = new SpanLikeType(stackReferring1);\n\n    // this is allowed\n    stackReferring2 = M1(ref stackReferring2, stackReferring1);\n\n    // this is NOT allowed\n    stackReferring2 = M1(ref param1, stackReferring1);\n\n    // this is NOT allowed\n    param1 = M1(ref stackReferring2, stackReferring1);\n\n    // this is NOT allowed\n    param2 = stackReferring1.Slice(10);\n\n    // this is allowed\n    param1 = new SpanLikeType(param2);\n\n    // this is allowed\n    stackReferring2 = param1;\n}\n\nref SpanLikeType M2(ref SpanLikeType x)\n{\n    return ref x;\n}\n\nref SpanLikeType Test2(ref SpanLikeType param1, Span<byte> param2)\n{\n    Span<byte> stackReferring1 = stackalloc byte[10];\n    var stackReferring2 = new SpanLikeType(stackReferring1);\n\n    ref var stackReferring3 = M2(ref stackReferring2);\n\n    // this is allowed\n    stackReferring3 = M1(ref stackReferring2, stackReferring1);\n\n    // this is allowed\n    M2(ref stackReferring3) = stackReferring2;\n\n    // this is NOT allowed\n    M1(ref param1) = stackReferring2;\n\n    // this is NOT allowed\n    param1 = stackReferring3;\n\n    // this is NOT allowed\n    return ref stackReferring3;\n\n    // this is allowed\n    return ref param1;\n}\n\n```\n\n----------------\n\n## Draft language specification\n\nBelow we describe a set of safety rules for ref-like types (`ref struct`s) to ensure that values of these types occur only on the stack. A different, simpler set of safety rules would be possible if locals cannot be passed by reference. This specification would also permit the safe reassignment of ref locals.\n\n### Overview\n\nWe associate with each expression at compile-time the concept of what scope that expression is permitted to escape to, \"safe-to-escape\". Similarly, for each lvalue we maintain a concept of what scope a reference to it is permitted to escape to, \"ref-safe-to-escape\". For a given lvalue expression, these may be different.\n\nThese are analogous to the \"safe to return\" of the ref locals feature, but it is more fine-grained. Where the \"safe-to-return\" of an expression records only whether (or not) it may escape the enclosing method as a whole, the safe-to-escape records which scope it may escape to (which scope it may not escape beyond). The basic safety mechanism is enforced as follows. Given an assignment from an expression E1 with a safe-to-escape scope S1, to an (lvalue) expression E2 with safe-to-escape scope S2, it is an error if S2 is a wider scope than S1. By construction, the two scopes S1 and S2 are in a nesting relationship, because a legal expression is always safe-to-return from some scope enclosing the expression.\n\nFor the time being it is sufficient, for the purpose of the analysis, to support just two scopes - external to the method, and top-level scope of the method. That is because ref-like values with inner scopes cannot be created and ref locals do not support re-assignment. The rules, however, can support more than two scope levels.\n\nThe precise rules for computing the *safe-to-return* status of an expression, and the rules governing the legality of expressions, follow.\n\n### ref-safe-to-escape\n\nThe *ref-safe-to-escape* is a scope, enclosing an lvalue expression, to which it is safe for a ref to the lvalue to escape to. If that scope is the entire method, we say that a ref to the lvalue is *safe to return* from the method.\n\nThe *ref-safe-to-escape* scope for an lvalue expression can never be to a greater scope than the *safe-to-escape* for the same value. That means when the spec limits the *safe-to-escape* of a value it is implicitly also limiting the *ref-safe-to-escape*. However *ref-safe-to-escape* scope can be to a smaller scope than *safe-to-escape*. Consider that non-ref locals have *safe-to-escape* scope outside method but *ref-safe-to-escape* inside the method.\n\n### safe-to-escape\n\nThe *safe-to-escape* is a scope, enclosing an expression, to which it is safe for the value to escape to. If that scope is the entire method, we say that the value is *safe to return* from the method.\n\nAn expression whose type is not a `ref struct` type is always *safe-to-return* from the entire enclosing method. Otherwise we refer to the rules below.\n\n#### Parameters\n\nAn lvalue designating a formal parameter is *ref-safe-to-escape* (by reference) as follows:\n- If the parameter is a `ref`, `out`, or `in` parameter, it is *ref-safe-to-escape* from the entire method (e.g. by a `return ref` statement); otherwise\n- If the parameter is the `this` parameter of a struct type, it is *ref-safe-to-escape* to the top-level scope of the method (but not from the entire method itself); [Sample](#struct-this-escape)\n- Otherwise the parameter is a value parameter, and it is *ref-safe-to-escape* to the top-level scope of the method (but not from the method itself).\n\nAn expression that is an rvalue designating the use of a formal parameter is *safe-to-escape* (by value) from the entire method (e.g. by a `return` statement). This applies to the `this` parameter as well.\n\n#### Locals\n\nAn lvalue designating a local variable is *ref-safe-to-escape* (by reference) as follows:\n- If the variable is a `ref` variable, then its *ref-safe-to-escape* is taken from the *ref-safe-to-escape* of its initializing expression; otherwise\n- The variable is *ref-safe-to-escape* the scope in which it was declared.\n\nAn expression that is an rvalue designating the use of a local variable is *safe-to-escape* (by value) as follows:\n- But the general rule above, a local whose type is not a `ref struct` type is *safe-to-return* from the entire enclosing method.\n- If the variable is an iteration variable of a `foreach` loop, then the variable's *safe-to-escape* scope is the same as the *safe-to-escape* of the `foreach` loop's expression.\n- A local of `ref struct` type and uninitialized at the point of declaration is *safe-to-return* from the entire enclosing method.\n- Otherwise the variable's type is a `ref struct` type, and the variable's declaration requires an initializer. The variable's *safe-to-escape* scope is the same as the *safe-to-escape* of its initializer.\n\n#### Field reference\n\nAn lvalue designating a reference to a field, `e.F`, is *ref-safe-to-escape* (by reference) as follows:\n- If `e` is of a reference type, it is *ref-safe-to-escape* from the entire method; otherwise\n- If `e` is of a value type, its *ref-safe-to-escape* is taken from the *ref-safe-to-escape* of `e`.\n\nAn rvalue designating a reference to a field, `e.F`, has a *safe-to-escape* scope that is the same as the *safe-to-escape* of `e`.\n\n#### Operators including `?:`\n\nThe application of a user-defined operator is treated as a method invocation.\n\nFor an operator that yields an rvalue, such as `e1 + e2` or `c ? e1 : e2`, the *safe-to-escape* of the result is the narrowest scope among the *safe-to-escape* of the operands of the operator.  As a consequence, for a unary operator that yields an rvalue, such as `+e`, the *safe-to-escape* of the result is the *safe-to-escape* of the operand.\n\nFor an operator that yields an lvalue, such as `c ? ref e1 : ref e2`\n- the *ref-safe-to-escape* of the result is the narrowest scope among the *ref-safe-to-escape* of the operands of the operator.\n- the *safe-to-escape* of the operands must agree, and that is the *safe-to-escape* of the resulting lvalue.\n\n#### Method invocation\n\nAn lvalue resulting from a ref-returning method invocation `e1.M(e2, ...)` is *ref-safe-to-escape* the smallest of the following scopes:\n- The entire enclosing method\n- the *ref-safe-to-escape* of all `ref` and `out` argument expressions (excluding the receiver)\n- For each `in` parameter of the method, if there is a corresponding expression that is an lvalue, its *ref-safe-to-escape*, otherwise the nearest enclosing scope\n- the *safe-to-escape* of all argument expressions (including the receiver)\n\n> Note: the last bullet is necessary to handle code such as\n> ```csharp\n> var sp = new Span(...)\n> return ref sp[0];\n> ```\n> or\n> ```csharp\n> return ref M(sp, 0);\n> ```\n\nAn rvalue resulting from a method invocation `e1.M(e2, ...)` is *safe-to-escape* from the smallest of the following scopes:\n- The entire enclosing method\n- the *safe-to-escape* of all argument expressions (including the receiver)\n\n#### An Rvalue\nAn rvalue is *ref-safe-to-escape* from the nearest enclosing scope. This occurs for example in an invocation such as `M(ref d.Length)` where `d` is of type `dynamic`. It is also consistent with (and perhaps subsumes) our handling of arguments corresponding to `in` parameters.\n\n#### Property invocations\n\nA property invocation (either `get` or `set`) it treated as a method invocation of the underlying method by the above rules.\n\n#### `stackalloc`\n\nA stackalloc expression is an rvalue that is *safe-to-escape* to the top-level scope of the method (but not from the entire method itself).\n\n#### Constructor invocations\n\nA `new` expression that invokes a constructor obeys the same rules as a method invocation that is considered to return the type being constructed.\n\nIn addition *safe-to-escape* is no wider than the smallest of the *safe-to-escape* of all arguments/operands of the object initializer expressions, recursively, if initializer is present. \n\n#### Span constructor\nThe language relies on `Span<T>` not having a constructor of the following form:\n\n```csharp\nvoid Example(ref int x)\n{\n    // Create a span of length one\n    var span = new Span<int>(ref x); \n}\n```\n\nSuch a constructor makes `Span<T>` which are used as fields indistinguishable from a `ref` field. The safety rules described in this document\ndepend on `ref` fields not being a valid construct in C# or .NET.\n\n#### `default` expressions\n\nA `default` expression is *safe-to-escape* from the entire enclosing method.\n\n## Language Constraints\n\nWe wish to ensure that no `ref` local variable, and no variable of `ref struct` type, refers to stack memory or variables that are no longer alive. We therefore have the following language constraints:\n\n- Neither a ref parameter, nor a ref local, nor a parameter or local of a `ref struct` type can be lifted into a lambda or local function.\n\n- Neither a ref parameter nor a parameter of a `ref struct` type may be an argument on an iterator method or an `async` method.\n\n- Neither a ref local, nor a local of a `ref struct` type may be in scope at the point of a `yield return` statement or an `await` expression.\n\n- A `ref struct` type may not be used as a type argument, or as an element type in a tuple type.\n\n- A `ref struct` type may not be the declared type of a field, except that it may be the declared type of an instance field of another `ref struct`.\n\n- A `ref struct` type may not be the element type of an array.\n\n- A value of a `ref struct` type may not be boxed:\n  - There is no conversion from a `ref struct` type to the type `object` or the type `System.ValueType`.\n  - A `ref struct` type may not be declared to implement any interface\n  - No instance method declared in `object` or in `System.ValueType` but not overridden in a `ref struct` type may be called with a receiver of that `ref struct` type.\n  - No instance method of a `ref struct` type may be captured by method conversion to a delegate type.\n\n- For a ref reassignment `e1 = ref e2`, the *ref-safe-to-escape* of `e2` must be at least as wide a scope as the *ref-safe-to-escape* of `e1`.\n\n- For a ref return statement `return ref e1`, the *ref-safe-to-escape* of `e1` must be *ref-safe-to-escape* from the entire method. (TODO: Do we also need a rule that `e1` must be *safe-to-escape* from the entire method, or is that redundant?)\n\n- For a return statement `return e1`, the *safe-to-escape* of `e1` must be *safe-to-escape* from the entire method.\n\n- For an assignment `e1 = e2`, if the type of `e1` is a `ref struct` type, then the *safe-to-escape* of `e2` must be at least as wide a scope as the *safe-to-escape* of `e1`.\n\n- For a method invocation if there is a `ref` or `out` argument of a `ref struct` type (including the receiver unless the type is `readonly`), with *safe-to-escape* E1, then no argument (including the receiver) may have a narrower *safe-to-escape* than E1. [Sample](#method-arguments-must-match)\n\n- A local function or anonymous function may not refer to a local or parameter of `ref struct` type declared in an enclosing scope.\n\n> ***Open Issue:*** We need some rule that permits us to produce an error when needing to spill a stack value of a `ref struct` type at an await expression, for example in the code\n> ```csharp\n> Foo(new Span<int>(...), await e2);\n> ```\n\n## Explanations\nThese explanations and samples help explain why many of the safety rules above exist\n\n### Method Arguments Must Match\n<a name=\"method-arguments-must-match\"></a>\n\nWhen invoking a method where there is an `out` or `ref` parameter that is a `ref struct` then all of the `ref struct` parameters need to have the same lifetime. This is necessary because C# must make all of its decisions around lifetime safety based on the information available in the signature of the method and the lifetime of the values at the call site. \n\nWhen there are `ref` parameters that are `ref struct` then there is the potential that they could swap around their contents. Hence at the call site we must ensure all of these **potential** swaps are compatible. If the language didn't enforce that then it will allow for bad code like the following.\n\n```csharp\nvoid M1(ref Span<int> s1)\n{\n    Span<int> s2 = stackalloc int[1];\n    Swap(ref s1, ref s2);\n}\n\nvoid Swap(ref Span<int> x, ref Span<int> y)\n{\n    // This will effectively assign the stackalloc to the s1 parameter and allow it\n    // to escape to the caller of M1\n    ref x = ref y; \n}\n```\n\nThis analysis of `ref` parameters includes the receiver in instance methods. This is necessary because it can be used to store values passed in as parameters, just as a `ref` parameter could`. This means with mismatched lifetimes you could create a type safety hole in the following way:\n\n```csharp\nref struct S\n{\n    public Span<int> Span;\n\n    public void Set(Span<int> span)\n    {\n        Span = span;\n    }\n}\n\nvoid Broken(ref S s)\n{\n    Span<int> span = stackalloc int[1];\n\n    // The result of a stackalloc is now stored in s.Span and escaped to the caller\n    // of Broken\n    s.Set(span); \n}\n```\n\nFor the purpose of this analysis the receiver is considered an `in`, not a `ref`, if the type is a `readonly struct`. In that case the receiver cannot be used to store values from other parameters, it is effectively an `in` parameter for analysis purposes. Hence the same example above is legal when `S` is `readonly` because the `span` cannot be stored anywhere.\n\n### Struct This Escape\nWhen it comes to span safety rules, the `this` value in an instance member is modeled as a parameter to the member. Now for a `struct` the type of `this` is actually `ref S` where in a `class` it's simply `S` (for members of a `class / struct` named S). \n\nYet `this` has different escaping rules than other `ref` parameters. Specifically it is not ref-safe-to-escape while other parameters are:\n\n```csharp\nref struct S\n{ \n    int Field;\n\n    // Illegal because `this` isn't safe to escape as ref\n    ref int Get() => ref Field;\n\n    // Legal\n    ref int GetParam(ref int p) => ref p;\n}\n```\n\nThe reason for this restriction actually has little to do with `struct` member invocation. There are some rules that need to be worked out with respect to member invocation on `struct` members where the receiver is an rvalue. But that is very approachable. \n\nThe reason for this restriction is actually about interface invocation. Specifically it comes down to whether or not the following sample should or should not compile;\n\n```csharp\ninterface I1\n{\n    ref int Get();\n}\n\nref int Use<T>(T p)\n    where T : I1\n{\n    return ref p.Get();\n}\n```\n\nConsider the case where `T` is instantiated as a `struct`. If the `this` parameter is ref-safe-to-escape then the return of `p.Get` could point to the stack (specifically it could be a field inside of the instantiated type of `T`). That means the language could not allow this sample to compile as it could be returning a `ref` to a stack location. On the other hand if `this` is not ref-safe-to-escape then `p.Get` cannot refer to the stack and hence it's safe to return. \n\nThis is why the escapability of `this` in a `struct` is really all about interfaces. It can absolutely be made to work but it has a trade off. The design eventually came down in favor of making interfaces more flexible. \n\nThere is potential for us to relax this in the future though. \n\n## Future Considerations\n\n### Length one Span\\<T> over ref values\nThough not legal today there are cases where creating a length one `Span<T>` instance over a value would be beneficial:\n\n```csharp\nvoid RefExample()\n{\n    int x = ...;\n\n    // Today creating a length one Span<int> requires a stackalloc and a new \n    // local\n    Span<int> span1 = stackalloc [] { x };\n    Use(span1);\n    x = span1[0]; \n\n    // Simpler to just allow length one span\n    var span2 = new Span<int>(ref x);\n    Use(span2);\n}\n```\n\nThis feature gets more compelling if we lift the restrictions on [fixed sized buffers](https://github.com/dotnet/csharplang/blob/master/proposals/fixed-sized-buffers.md) as it would\nallow for `Span<T>` instances of even greater length. \n\nIf there is ever a need to go down this path then the language could accommodate this by ensuring such `Span<T>` instances\nwere downward facing only. That is they were only ever *safe-to-escape* to the scope in which they were created. This ensure\nthe language never had to consider a `ref` value escaping a method via a `ref struct` return or field of `ref struct`. This\nwould likely also require further changes to recognize such constructors as capturing a `ref` parameter in this way though.\n"
  },
  {
    "path": "proposals/csharp-7.3/auto-prop-field-attrs.md",
    "content": "# Auto-Implemented Property Field-Targeted Attributes\n\nChampion issu: https://github.com/dotnet/csharplang/issues/42\n\n## Summary\n[summary]: #summary\n\nThis feature intends to allow developers to apply attributes directly to the backing fields of auto-implemented properties.\n\n## Motivation\n[motivation]: #motivation\n\nCurrently it is not possible to apply attributes to the backing fields of auto-implemented properties.  In those cases where the developer must use a field-targeting attribute they are forced to declare the field manually and use the more verbose property syntax.  Given that C# has always supported field-targeted attributes on the generated backing field for events it makes sense to extend the same functionality to their property kin.\n\n## Detailed design\n[design]: #detailed-design\n\nIn short, the following would be legal C# and not produce a warning:\n\n```csharp\n[Serializable]\npublic class Foo \n{\n    [field: NonSerialized]\n    public string MySecret { get; set; }\n}\n```\n\nThis would result in the field-targeted attributes being applied to the compiler-generated backing field:\n\n```csharp\n[Serializable]\npublic class Foo \n{\n    [NonSerialized]\n    private string _mySecretBackingField;\n    \n    public string MySecret\n    {\n        get { return _mySecretBackingField; }\n        set { _mySecretBackingField = value; }\n    }\n}\n```\n\nAs mentioned, this brings parity with event syntax from C# 1.0 as the following is already legal and behaves as expected:\n\n```csharp\n[Serializable]\npublic class Foo\n{\n    [field: NonSerialized]\n    public event EventHandler MyEvent;\n}\n```\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nThere are two potential drawbacks to implementing this change:\n\n1. Attempting to apply an attribute to the field of an auto-implemented property produces a compiler warning that the attributes in that block will be ignored.  If the compiler were changed to support those attributes they would be applied to the backing field on a subsequent recompilation which could alter the behavior of the program at runtime.\n1. The compiler does not currently validate the AttributeUsage targets of the attributes when attempting to apply them to the field of the auto-implemented property.  If the compiler were changed to support field-targeted attributes and the attribute in question cannot be applied to a field the compiler would emit an error instead of a warning, breaking the build.\n\n## Alternatives\n[alternatives]: #alternatives\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n## Design meetings\n"
  },
  {
    "path": "proposals/csharp-7.3/blittable.md",
    "content": "# Unmanaged type constraint\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/187>\n\n## Summary\n[summary]: #summary\n\nThe unmanaged constraint feature will give language enforcement to the class of types known as \"unmanaged types\" in the C# language spec.  This is defined in section 18.2 as a type which is not a reference type and doesn't contain reference type fields at any level of nesting.  \n\n## Motivation\n[motivation]: #motivation\n\nThe primary motivation is to make it easier to author low level interop code in C#. Unmanaged types are one of the core building blocks for interop code, yet the lack of support in generics makes it impossible to create re-usable routines across all unmanaged types. Instead developers are forced to author the same boiler plate code for every unmanaged type in their library:\n\n```csharp\nint Hash(Point point) { ... } \nint Hash(TimeSpan timeSpan) { ... } \n```\n\nTo enable this type of scenario the language will be introducing a new constraint: unmanaged:\n\n```csharp\nvoid Hash<T>(T value) where T : unmanaged\n{\n    ...\n}\n```\n\nThis constraint can only be met by types which fit into the unmanaged type definition in the C# language spec. Another way of looking at it is that a type satisfies the unmanaged constraint if it can also be used as a pointer. \n\n```csharp\nHash(new Point()); // Okay \nHash(42); // Okay\nHash(\"hello\") // Error: Type string does not satisfy the unmanaged constraint\n```\n\nType parameters with the unmanaged constraint can use all the features available to unmanaged types: pointers, fixed, etc ... \n\n```csharp\nvoid Hash<T>(T value) where T : unmanaged\n{\n    // Okay\n    fixed (T* p = &value) \n    { \n        ...\n    }\n}\n```\n\nThis constraint will also make it possible to have efficient conversions between structured data and streams of bytes. This is an operation that is common in networking stacks and serialization layers:\n\n```csharp\nSpan<byte> Convert<T>(ref T value) where T : unmanaged \n{\n    ...\n}\n```\n\nSuch routines are advantageous because they are provably safe at compile time and allocation free.  Interop authors today can not do this (even though it's at a layer where perf is critical).  Instead they need to rely on allocating routines that have expensive runtime checks to verify values are correctly unmanaged.\n\n## Detailed design\n[design]: #detailed-design\n\nThe language will introduce a new constraint named `unmanaged`. In order to satisfy this constraint a type must be a struct and all the fields of the type must fall into one of the following categories:\n\n- Have the type `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `char`, `float`, `double`, `decimal`, `bool`, `IntPtr` or `UIntPtr`.\n- Be any `enum` type.\n- Be a pointer type.\n- Be a user defined struct that satisfies the `unmanaged` constraint.\n\nCompiler generated instance fields, such as those backing auto-implemented properties, must also meet these constraints. \n\nFor example:\n\n```csharp\n// Unmanaged type\nstruct Point \n{ \n    int X;\n    int Y {get; set;}\n}\n\n// Not an unmanaged type\nstruct Student \n{ \n    string FirstName;\n    string LastName;\n}\n``` \n\nThe `unmanaged` constraint cannot be combined with `struct`, `class` or `new()`. This restriction derives from the fact that `unmanaged` implies `struct` hence the other constraints do not make sense.\n\nThe `unmanaged` constraint is not enforced by CLR, only by the language. To prevent mis-use by other languages, methods which have this constraint will be protected by a mod-req. This will \nprevent other languages from using type arguments which are not unmanaged types.\n\nThe token `unmanaged` in the constraint is not a keyword, nor a contextual keyword. Instead it is like `var` in that it is evaluated at that location and will either:\n\n- Bind to user defined or referenced type named `unmanaged`: This will be treated just as any other named type constraint is treated. \n- Bind to no type: This will be interpreted as the `unmanaged` constraint.\n\nIn the case there is a type named `unmanaged` and it is available without qualification in the current context, then there will be no way to use the `unmanaged` constraint. This parallels the rules surrounding the feature `var` and user defined types of the same name. \n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nThe primary drawback of this feature is that it serves a small number of developers: typically low level library authors or frameworks.  Hence it's spending precious language time for a small number of developers. \n\nYet these frameworks are often the basis for the majority of .NET applications out there.  Hence performance / correctness wins at this level can have a ripple effect on the .NET ecosystem.  This makes the feature worth considering even with the limited audience.\n\n## Alternatives\n[alternatives]: #alternatives\n\nThere are a couple of alternatives to consider:\n\n- The status quo:  The feature is not justified on its own merits and developers continue to use the implicit opt in behavior.\n\n## Questions\n[quesions]: #questions\n\n### Metadata Representation\n\nThe F# language encodes the constraint in the signature file which means C# cannot re-use their representation. A new attribute will need to be chosen for this constraint. Additionally a method which has this constraint must be protected by a mod-req.\n\n### Blittable vs. Unmanaged\nThe F# language has a very [similar feature](https://docs.microsoft.com/dotnet/articles/fsharp/language-reference/generics/constraints) which uses the keyword unmanaged. The blittable name comes from the use in Midori.  May want to look to precedence here and use unmanaged instead. \n\n**Resolution** The language decide to use unmanaged \n\n### Verifier\n\nDoes the verifier / runtime need to be updated to understand the use of pointers to generic type parameters?  Or can it simply work as is without changes?\n\n**Resolution** No changes needed. All pointer types are simply unverifiable. \n\n## Design meetings\n\nn/a\n"
  },
  {
    "path": "proposals/csharp-7.3/enum-delegate-constraints.md",
    "content": "﻿## Enum and Delegate type parameter constraint\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/104>\n\nIn C# 7.3, we added support for type parameter constraint keywords `enum` and `delegate`.  This is a placeholder for their specification.\n"
  },
  {
    "path": "proposals/csharp-7.3/expression-variables-in-initializers.md",
    "content": "# Expression variables in initializers\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/32>\n\n## Summary\n[summary]: #summary\n\nWe extend the features introduced in C# 7 to permit expressions containing expression variables (out variable declarations and declaration patterns) in field initializers, property initializers, ctor-initializers, and query clauses.\n\n## Motivation\n[motivation]: #motivation\n\nThis completes a couple of the rough edges left in the C# language due to lack of time.\n\n## Detailed design\n[design]: #detailed-design\n\nWe remove the restriction preventing the declaration of expression variables (out variable declarations and declaration patterns) in a ctor-initializer. Such a declared variable is in scope throughout the body of the constructor.\n\nWe remove the restriction preventing the declaration of expression variables (out variable declarations and declaration patterns) in a field or property initializer. Such a declared variable is in scope throughout the initializing expression.\n\nWe remove the restriction preventing the declaration of expression variables (out variable declarations and declaration patterns) in a query expression clause that is translated into the body of a lambda. Such a declared variable is in scope throughout that expression of the query clause.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nNone.\n\n## Alternatives\n[alternatives]: #alternatives\n\nThe appropriate scope for expression variables declared in these contexts is not obvious, and deserves further LDM discussion.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n- [ ] What is the appropriate scope for these variables?\n\n## Design meetings\n\nNone.\n"
  },
  {
    "path": "proposals/csharp-7.3/improved-overload-candidates.md",
    "content": "# Improved overload candidates\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/98>\n\n## Summary\n[summary]: #summary\n\nThe overload resolution rules have been updated in nearly every C# language update to improve the experience for programmers, making ambiguous invocations select the \"obvious\" choice. This has to be done carefully to preserve backward compatibility, but since we are usually resolving what would otherwise be error cases, these enhancements usually work out nicely.\n\n1. When a method group contains both instance and static members, we discard the instance members if invoked without an instance receiver or context, and discard the static members if invoked with an instance receiver. When there is no receiver, we include only static members in a static context, otherwise both static and instance members. When the receiver is ambiguously an instance or type due to a color-color situation, we include both. A static context, where an implicit this instance receiver cannot be used, includes the body of members where no this is defined, such as static members, as well as places where this cannot be used, such as field initializers and constructor-initializers.\n2. When a method group contains some generic methods whose type arguments do not satisfy their constraints, these members are removed from the candidate set.\n3. For a method group conversion, candidate methods whose return type doesn't match up with the delegate's return type are removed from the set.\n"
  },
  {
    "path": "proposals/csharp-7.3/indexing-movable-fixed-fields.md",
    "content": "# Indexing `fixed` fields should not require pinning regardless of the movable/unmovable context. #\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/1351>\n\nThe change has the size of a bug fix. It can be in 7.3 and does not conflict with whatever direction we take further.\nThis change is only about allowing the following scenario to work even though `s` is moveable. It is already valid when `s` is not moveable. \n\nNOTE: in either case, it still requires `unsafe` context. It is possible to read uninitialized data or even out of range. That is not changing.\n\n```csharp\nunsafe struct S\n{\n    public fixed int myFixedField[10];\n}\n\nclass Program\n{\n    static S s;\n\n    unsafe static void Main()\n    {\n        int p = s.myFixedField[5]; // indexing fixed-size array fields would be ok\n    }\n}\n```\n\nThe main “challenge” that I see here is how to explain the relaxation in the spec. \nIn particular, since the following would still need pinning. \n(because `s` is moveable and we explicitly use the field as a pointer)\n\n```csharp\nunsafe struct S\n{\n    public fixed int myFixedField[10];\n}\n\nclass Program\n{\n    static S s;\n\n    unsafe static void Main()\n    {\n        int* ptr = s.myFixedField; // taking a pointer explicitly still requires pinning.\n        int p = ptr[5];\n    }\n}\n```\n\nOne reason why we require pinning of the target when it is movable is the artifact of our code generation strategy, - we always convert to an unmanaged pointer and thus force the user to pin via `fixed` statement. However, conversion to unmanaged is unnecessary when doing indexing. The same unsafe pointer math is equally applicable when we have the receiver in the form of a managed pointer. If we do that, then the intermediate ref is managed (GC-tracked) and the pinning is unnecessary.\n\nThe change https://github.com/dotnet/roslyn/pull/24966 is a prototype PR that relaxes this requirement.\n"
  },
  {
    "path": "proposals/csharp-7.3/pattern-based-fixed.md",
    "content": "# Pattern-based `fixed` statement\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/1287>\n\n## Summary\n[summary]: #summary\n\nIntroduce a pattern that would allow types to participate in `fixed` statements. \n\n## Motivation\n[motivation]: #motivation\n\nThe language provides a mechanism for pinning managed data and obtain a native pointer to the underlying buffer.\n\n```csharp\nfixed(byte* ptr = byteArray)\n{\n   // ptr is a native pointer to the first element of the array\n   // byteArray is protected from being moved/collected by the GC for the duration of this block \n}\n\n```\n\nThe set of types that can participate in `fixed` is hardcoded and limited to arrays and `System.String`. Hardcoding \"special\" types does not scale when new primitives such as `ImmutableArray<T>`, `Span<T>`, `Utf8String` are introduced. \n\nIn addition, the current solution for `System.String` relies on a fairly rigid API. The shape of the API implies that `System.String` is a contiguous object that embeds UTF16 encoded data at a fixed offset from the object header. Such approach has been found problematic in several proposals that could require changes to the underlying layout. \nIt would be desirable to be able to switch to something more flexible that decouples `System.String` object from its internal representation for the purpose of unmanaged interop. \n\n## Detailed design\n[design]: #detailed-design\n\n## *Pattern* ##\nA viable pattern-based “fixed” need to:\n-\tProvide the managed references to pin the instance and to initialize the pointer (preferably this is the same reference)\n-\tConvey unambiguously the type of the unmanaged element   (i.e. “char” for “string”)\n-\tPrescribe the behavior in \"empty\" case when there is nothing to refer to. \n-\tShould not push API authors toward design decisions that hurt the use of the type outside of `fixed`.\n\nI think the above could be satisfied by recognizing a specially named ref-returning member:\n `ref [readonly] T GetPinnableReference()`.\n\nIn order to be used by the `fixed` statement the following conditions must be met:\n\n1. There is only one such member provided for a type.\n1. Returns by `ref` or `ref readonly`. \n(`readonly` is permitted so that authors of immutable/readonly types could implement the pattern without adding writeable API that could be used in safe code)\n1. T is an unmanaged type.\n(since `T*` becomes the pointer type. The restriction will naturally expand if/when the notion of \"unmanaged\" is expanded)\n1. Returns managed `nullptr` when there is no data to pin – probably the cheapest way to convey emptiness.\n(note that “” string returns a ref to '\\0' since strings are null-terminated)\n\nAlternatively for the `#3` we can allow the result in empty cases be undefined or implementation-specific. \nThat, however, may make the API more dangerous and prone to abuse and unintended compatibility burdens. \n\n## *Translation* ##\n\n```csharp\nfixed(byte* ptr = thing)\n{ \n    // <BODY>\n}\n```\n\nbecomes the following pseudocode (not all expressible in C#)\n\n```csharp\nbyte* ptr;\n// specially decorated \"pinned\" IL local slot, not visible to user code.\npinned ref byte _pinned;\n\ntry\n{\n    // NOTE: null check is omitted for value types \n    // NOTE: `thing` is evaluated only once (temporary is introduced if necessary) \n    if (thing != null)\n    {\n        // obtain and \"pin\" the reference\n        _pinned = ref thing.GetPinnableReference();\n\n        // unsafe cast in IL\n        ptr = (byte*)_pinned;\n    }\n    else\n    {\n        ptr = default(byte*);\n    }\n\n    // <BODY> \n}\nfinally   // finally can be omitted when not observable\n{\n    // \"unpin\" the object\n    _pinned = nullptr;\n}\n```\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\n- GetPinnableReference is intended to be used only in `fixed`, but nothing prevents its use in safe code, so implementor must keep that in mind.\n\n## Alternatives\n[alternatives]: #alternatives\n\nUsers can introduce GetPinnableReference or similar member and use it as\n \n```csharp\nfixed(byte* ptr = thing.GetPinnableReference())\n{ \n    // <BODY>\n}\n```\n\nThere is no solution for `System.String` if alternative solution is desired.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n- [ ] Behavior in \"empty\" state. - `nullptr` or `undefined` ? \n- [ ] Should the extension methods be considered ? \n- [ ] If a pattern is detected on `System.String`, should it win over ? \n\n## Design meetings\n\nNone yet. \n"
  },
  {
    "path": "proposals/csharp-7.3/ref-local-reassignment.md",
    "content": "# Ref Local Reassignment\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/933>\n\nIn C# 7.3, we add support for rebinding the referent of a ref local variable or a ref parameter.\n\nWe add the following to the set of `assignment_operator`s.\n\n```antlr\nassignment_operator\n    : '=' 'ref'\n    ;\n```\n\nThe `=ref` operator is called the ***ref assignment operator***. It is not a *compound assignment operator*. The left operand must be an expression that binds to a ref local variable, a ref parameter (other than `this`), or an out parameter. The right operand must be an expression that yields an lvalue designating a value of the same type as the left operand.\n\nThe right operand must be definitely assigned at the point of the ref assignment.\n\nWhen the left operand binds to an `out` parameter, it is an error if that `out` parameter has not been definitely assigned at the beginning of the ref assignment operator.\n\nIf the left operand is a writeable ref (i.e. it designates anything other than a `ref readonly` local or  `in` parameter), then the right operand must be a writeable lvalue.\n\nThe ref assignment operator yields an lvalue of the assigned type. It is writeable if the left operand is writeable (i.e. not `ref readonly` or `in`).\n\nThe safety rules for this operator are:\n\n- For a ref reassignment `e1 = ref e2`, the *ref-safe-to-escape* of `e2` must be at least as wide a scope as the *ref-safe-to-escape* of `e1`.\n\nWhere *ref-safe-to-escape* is defined in [Safety for ref-like types](../csharp-7.2/span-safety.md)\n"
  },
  {
    "path": "proposals/csharp-7.3/ref-loops.md",
    "content": "﻿## Ref loops\n\nIn C# 7.3, we added support for *ref for loops* and *ref foreach loops*.  This is a placeholder for their specifications.\n"
  },
  {
    "path": "proposals/csharp-7.3/stackalloc-array-initializers.md",
    "content": "# Stackalloc array initializers\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/1286>\n\n## Summary\n[summary]: #summary\n\nAllow array initializer syntax to be used with `stackalloc`.\n\n## Motivation\n[motivation]: #motivation\n\nOrdinary arrays can have their elements initialized at creation time. It seems reasonable to allow that in `stackalloc` case.\n\nThe question of why such syntax is not allowed with `stackalloc` arises fairly frequently.  \nSee, for example, [#1112](https://github.com/dotnet/csharplang/issues/1112)\n\n## Detailed design\n\nOrdinary arrays can be created through the following syntax:\n\n```csharp\nnew int[3]\nnew int[3] { 1, 2, 3 }\nnew int[] { 1, 2, 3 }\nnew[] { 1, 2, 3 }\n```\n\nWe should allow stack allocated arrays be created through:  \n\n```csharp\nstackalloc int[3]\t\t\t\t// currently allowed\nstackalloc int[3] { 1, 2, 3 }\nstackalloc int[] { 1, 2, 3 }\nstackalloc[] { 1, 2, 3 }\n```\n\nThe semantics of all cases is roughly the same as with arrays.  \nFor example: in the last case the element type is inferred from the initializer and must be an \"unmanaged\" type.\n\nNOTE: the feature is not dependent on the target being a `Span<T>`. It is just as applicable in `T*` case, so it does not seem reasonable to predicate it on `Span<T>` case.  \n\n## Translation\n\nThe naive implementation could just initialize the array right after creation through a series of element-wise assignments.  \n\nSimilarly to the case with arrays, it might be possible and desirable to detect cases where all or most of the elements are blittable types and use more efficient techniques by copying over the pre-created state of all the constant elements. \n\n## Drawbacks\n[drawbacks]: #drawbacks\n\n## Alternatives\n[alternatives]: #alternatives\n\nThis is a convenience feature. It is possible to just do nothing.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n## Design meetings\n\nNone yet. \n"
  },
  {
    "path": "proposals/csharp-7.3/tuple-equality.md",
    "content": "# Support for == and != on tuple types\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/190>\n\nAllow expressions `t1 == t2` where `t1` and `t2` are tuple or nullable tuple types of same cardinality, and evaluate them roughly as `temp1.Item1 == temp2.Item1 && temp1.Item2 == temp2.Item2` (assuming `var temp1 = t1; var temp2 = t2;`).\n\nConversely it would allow `t1 != t2` and evaluate it as `temp1.Item1 != temp2.Item1 || temp1.Item2 != temp2.Item2`.\n\nIn the nullable case, additional checks for `temp1.HasValue` and `temp2.HasValue` are used. For instance, `nullableT1 == nullableT2` evaluates as `temp1.HasValue == temp2.HasValue ? (temp1.HasValue ? ... : true) : false`.\n\nWhen an element-wise comparison returns a non-bool result (for instance, when a non-bool user-defined `operator ==` or `operator !=` is used, or in a dynamic comparison), then that result will be either converted to `bool` or run through `operator true` or `operator false` to get a `bool`. The tuple comparison always ends up returning a `bool`.\n\nAs of C# 7.2, such code produces an error (`error CS0019: Operator '==' cannot be applied to operands of type '(...)' and '(...)'`), unless there is a user-defined `operator==`.\n\n## Details\n\nWhen binding the `==` (or `!=`) operator, the existing rules are: (1) dynamic case, (2) overload resolution, and (3) fail.\nThis proposal adds a tuple case between (1) and (2): if both operands of a comparison operator are tuples (have tuple types or are tuple literals) and have matching cardinality, then the comparison is performed element-wise. This tuple equality is also lifted onto nullable tuples.\n\nBoth operands (and, in the case of tuple literals, their elements) are evaluated in order from left to right. Each pair of elements is then used as operands to bind the operator `==` (or `!=`), recursively. Any elements with compile-time type `dynamic` cause an error. The results of those element-wise comparisons are used as operands in a chain of conditional AND (or OR) operators.\n\nFor instance, in the context of `(int, (int, int)) t1, t2;`, `t1 == (1, (2, 3))` would evaluate as `temp1.Item1 == temp2.Item1 && temp1.Item2.Item1 == temp2.Item2.Item1 && temp1.Item2.Item2 == temp2.Item2.Item2`.\n\nWhen a tuple literal is used as operand (on either side), it receives a converted tuple type formed by the element-wise conversions which are introduced when binding the operator `==` (or `!=`) element-wise. \n\nFor instance, in `(1L, 2, \"hello\") == (1, 2L, null)`, the converted type for both tuple literals is `(long, long, string)` and the second literal has no natural type.\n\n\n### Deconstruction and conversions to tuple\nIn `(a, b) == x`, the fact that `x` can deconstruct into two elements does not play a role. That could conceivably be in a future proposal, although it would raise questions about `x == y` (is this a simple comparison or an element-wise comparison, and if so using what cardinality?).\nSimilarly, conversions to tuple play no role.\n\n### Tuple element names\n\nWhen converting a tuple literal, we warn when an explicit tuple element name was provided in the literal, but it doesn't match the target tuple element name.\nWe use the same rule in tuple comparison, so that assuming `(int a, int b) t` we warn on `d` in `t == (c, d: 0)`.\n\n### Non-bool element-wise comparison results\n\nIf an element-wise comparison is dynamic in a tuple equality, we use a dynamic invocation of the operator `false` and negate that to get a `bool` and continue with further element-wise comparisons. \n\nIf an element-wise comparison returns some other non-bool type in a tuple equality, there are two cases:\n- if the non-bool type converts to `bool`, we apply that conversion,\n- if there is no such conversion, but the type has an operator `false`, we'll use that and negate the result.\n\nIn a tuple inequality, the same rules apply except that we'll use the operator `true` (without negation) instead of the operator `false`.\n\nThose rules are similar to the rules involved for using a non-bool type in an `if` statement and some other existing contexts.\n\n## Evaluation order and special cases\nThe left-hand-side value is evaluated first, then the right-hand-side value, then the element-wise comparisons from left to right (including conversions, and with early exit based on existing rules for conditional AND/OR operators).\n\nFor instance, if there is a conversion from type `A` to type `B` and a method `(A, A) GetTuple()`, evaluating `(new A(1), (new B(2), new B(3))) == (new B(4), GetTuple())` means:\n- `new A(1)`\n- `new B(2)`\n- `new B(3)`\n- `new B(4)`\n- `GetTuple()`\n- then the element-wise conversions and comparisons and conditional logic is evaluated (convert `new A(1)` to type `B`, then compare it with `new B(4)`, and so on).\n\n### Comparing `null` to `null`\n\nThis is a special case from regular comparisons, that carries over to tuple comparisons. The `null == null` comparison is allowed, and the `null` literals do not get any type.\nIn tuple equality, this means, `(0, null) == (0, null)` is also allowed and the `null` and tuple literals don't get a type either.\n\n### Comparing a nullable struct to `null` without `operator==`\n\nThis is another special case from regular comparisons, that carries over to tuple comparisons.\nIf you have a `struct S` without `operator==`, the `(S?)x == null` comparison is allowed, and it is interpreted as `((S?).x).HasValue`.\nIn tuple equality, the same rule is applied, so `(0, (S?)x) == (0, null)` is allowed.\n\n## Compatibility\n\nIf someone wrote their own `ValueTuple` types with  an implementation of the comparison operator, it would have previously been picked up by overload resolution. But since the new tuple case comes before overload resolution, we would handle this case with tuple comparison instead of relying on the user-defined comparison.\n\n----\n\nRelates to relational and type testing operators ([§11.11](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1111-relational-and-type-testing-operators))\nRelates to [#190](https://github.com/dotnet/csharplang/issues/190)\n"
  },
  {
    "path": "proposals/csharp-8.0/README.md",
    "content": ""
  },
  {
    "path": "proposals/csharp-8.0/alternative-interpolated-verbatim.md",
    "content": "﻿## Alternative interpolated verbatim strings\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/1630>\n\nIn C# 8.0 we added a feature that permits an interpolated verbatim string to be introduced with the characters `@$\"` or the characters `$@\"`.  This is a placeholder for its specification.\n"
  },
  {
    "path": "proposals/csharp-8.0/async-streams.md",
    "content": "﻿# Async Streams\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/43>\n\n## Summary\n[summary]: #summary\n\nC# has support for iterator methods and async methods, but no support for a method that is both an iterator and an async method.  We should rectify this by allowing for `await` to be used in a new form of `async` iterator, one that returns an `IAsyncEnumerable<T>` or `IAsyncEnumerator<T>` rather than an `IEnumerable<T>` or `IEnumerator<T>`, with `IAsyncEnumerable<T>` consumable in a new `await foreach`.  An `IAsyncDisposable` interface is also used to enable asynchronous cleanup.\n\n## Related discussion\n- https://github.com/dotnet/roslyn/issues/261\n- https://github.com/dotnet/roslyn/issues/114\n\n## Detailed design\n[design]: #detailed-design\n\n## Interfaces\n\n### IAsyncDisposable\n\nThere has been much discussion of `IAsyncDisposable` (e.g. https://github.com/dotnet/roslyn/issues/114) and whether it's a good idea.  However, it's a required concept to add in support of async iterators.  Since `finally` blocks may contain `await`s, and since `finally` blocks need to be run as part of disposing of iterators, we need async disposal.  It's also just generally useful any time cleaning up of resources might take any period of time, e.g. closing files (requiring flushes), deregistering callbacks and providing a way to know when deregistration has completed, etc.\n\nThe following interface is added to the core .NET libraries (e.g. System.Private.CoreLib / System.Runtime):\n```csharp\nnamespace System\n{\n    public interface IAsyncDisposable\n    {\n        ValueTask DisposeAsync();\n    }\n}\n```\nAs with `Dispose`, invoking `DisposeAsync` multiple times is acceptable, and subsequent invocations after the first should be treated as no-ops, returning a synchronously completed successful task (`DisposeAsync` need not be thread-safe, though, and need not support concurrent invocation).  Further, types may implement both `IDisposable` and `IAsyncDisposable`, and if they do, it's similarly acceptable to invoke `Dispose` and then `DisposeAsync` or vice versa, but only the first should be meaningful and subsequent invocations of either should be a nop.  As such, if a type does implement both, consumers are encouraged to call once and only once the more relevant method based on the context, `Dispose` in synchronous contexts and `DisposeAsync` in asynchronous ones.\n\n(How `IAsyncDisposable` interacts with `using` is a separate discussion.  And coverage of how it interacts with `foreach` is handled later in this proposal.)\n\nAlternatives considered:\n- _`DisposeAsync` accepting a `CancellationToken`_: while in theory it makes sense that anything async can be canceled, disposal is about cleanup, closing things out, free'ing resources, etc., which is generally not something that should be canceled; cleanup is still important for work that's canceled.  The same `CancellationToken` that caused the actual work to be canceled would typically be the same token passed to `DisposeAsync`, making `DisposeAsync` worthless because cancellation of the work would cause `DisposeAsync` to be a no-op.  If someone wants to avoid being blocked waiting for disposal, they can avoid waiting on the resulting `ValueTask`, or wait on it only for some period of time.\n- _`DisposeAsync` returning a `Task`_: Now that a non-generic `ValueTask` exists and can be constructed from an `IValueTaskSource`, returning `ValueTask` from `DisposeAsync` allows an existing object to be reused as the promise representing the eventual async completion of `DisposeAsync`, saving a `Task` allocation in the case where `DisposeAsync` completes asynchronously.\n- _Configuring `DisposeAsync` with a `bool continueOnCapturedContext` (`ConfigureAwait`)_: While there may be issues related to how such a concept is exposed to `using`, `foreach`, and other language constructs that consume this, from an interface perspective it's not actually doing any `await`'ing and there's nothing to configure... consumers of the `ValueTask` can consume it however they wish.\n- _`IAsyncDisposable` inheriting `IDisposable`_:  Since only one or the other should be used, it doesn't make sense to force types to implement both.\n- _`IDisposableAsync` instead of `IAsyncDisposable`_: We've been following the naming that things/types are an \"async something\" whereas operations are \"done async\", so types have \"Async\" as a prefix and methods have \"Async\" as a suffix.\n\n### IAsyncEnumerable / IAsyncEnumerator\n\nTwo interfaces are added to the core .NET libraries:\n\n```csharp\nnamespace System.Collections.Generic\n{\n    public interface IAsyncEnumerable<out T>\n    {\n        IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default);\n    }\n\n    public interface IAsyncEnumerator<out T> : IAsyncDisposable\n    {\n        ValueTask<bool> MoveNextAsync();\n        T Current { get; }\n    }\n}\n```\n\nTypical consumption (without additional language features) would look like:\n\n```csharp\nIAsyncEnumerator<T> enumerator = enumerable.GetAsyncEnumerator();\ntry\n{\n    while (await enumerator.MoveNextAsync())\n    {\n        Use(enumerator.Current);\n    }\n}\nfinally { await enumerator.DisposeAsync(); }\n```\n\nDiscarded options considered:\n- _`Task<bool> MoveNextAsync(); T current { get; }`_: Using `Task<bool>` would support using a cached task object to represent synchronous, successful `MoveNextAsync` calls, but an allocation would still be required for asynchronous completion.  By returning `ValueTask<bool>`, we enable the enumerator object to itself implement `IValueTaskSource<bool>` and be used as the backing for the `ValueTask<bool>` returned from `MoveNextAsync`, which in turn allows for significantly reduced overheads.\n- _`ValueTask<(bool, T)> MoveNextAsync();`_: It's not only harder to consume, but it means that `T` can no longer be covariant.\n- _`ValueTask<T?> TryMoveNextAsync();`_: Not covariant.\n- _`Task<T?> TryMoveNextAsync();`_: Not covariant, allocations on every call, etc.\n- _`ITask<T?> TryMoveNextAsync();`_: Not covariant, allocations on every call, etc.\n- _`ITask<(bool,T)> TryMoveNextAsync();`_: Not covariant, allocations on every call, etc.\n- _`Task<bool> TryMoveNextAsync(out T result);`_: The `out` result would need to be set when the operation returns synchronously, not when it asynchronously completes the task potentially sometime long in the future, at which point there'd be no way to communicate the result.\n- _`IAsyncEnumerator<T>` not implementing `IAsyncDisposable`_: We could choose to separate these.  However, doing so complicates certain other areas of the proposal, as code must then be able to deal with the possibility that an enumerator doesn't provide disposal, which makes it difficult to write pattern-based helpers.  Further, it will be common for enumerators to have a need for disposal (e.g. any C# async iterator that has a finally block, most things enumerating data from a network connection, etc.), and if one doesn't, it is simple to implement the method purely as `public ValueTask DisposeAsync() => default(ValueTask);` with minimal additional overhead.\n- _ `IAsyncEnumerator<T> GetAsyncEnumerator()`: No cancellation token parameter.\n\nThe following subsection discuss alternatives that weren't chosen.\n\n<details>\n\n#### Viable alternative:\n\n```csharp\nnamespace System.Collections.Generic\n{\n    public interface IAsyncEnumerable<out T>\n    {\n        IAsyncEnumerator<T> GetAsyncEnumerator();\n    }\n\n    public interface IAsyncEnumerator<out T> : IAsyncDisposable\n    {\n        ValueTask<bool> WaitForNextAsync();\n        T TryGetNext(out bool success);\n    }\n}\n```\n\n`TryGetNext` is used in an inner loop to consume items with a single interface call as long as they're available synchronously.  When the next item can't be retrieved synchronously, it returns false, and any time it returns false, a caller must subsequently invoke `WaitForNextAsync` to either wait for the next item to be available or to determine that there will never be another item. Typical consumption (without additional language features) would look like:\n\n```csharp\nIAsyncEnumerator<T> enumerator = enumerable.GetAsyncEnumerator();\ntry\n{\n    while (await enumerator.WaitForNextAsync())\n    {\n        while (true)\n        {\n            int item = enumerator.TryGetNext(out bool success);\n            if (!success) break;\n            Use(item);\n        }\n    }\n}\nfinally { await enumerator.DisposeAsync(); }\n```\n\nThe advantage of this is two-fold, one minor and one major:\n- _Minor: Allows for an enumerator to support multiple consumers_. There may be scenarios where it's valuable for an enumerator to support multiple concurrent consumers.  That can't be achieved when `MoveNextAsync` and `Current` are separate such that an implementation can't make their usage atomic.  In contrast, this approach provides a single method `TryGetNext` that supports pushing the enumerator forward and getting the next item, so the enumerator can enable atomicity if desired.  However, it's likely that such scenarios could also be enabled by giving each consumer its own enumerator from a shared enumerable.  Further, we don't want to enforce that every enumerator support concurrent usage, as that would add non-trivial overheads to the majority case that doesn't require it, which means a consumer of the interface generally couldn't rely on this any way.\n- _Major: Performance_. The `MoveNextAsync`/`Current` approach requires two interface calls per operation, whereas the best case for `WaitForNextAsync`/`TryGetNext` is that most iterations complete synchronously, enabling a tight inner loop with `TryGetNext`, such that we only have one interface call per operation.  This can have a measurable impact in situations where the interface calls dominate the computation.\n\nHowever, there are non-trivial downsides, including significantly increased complexity when consuming these manually, and an increased chance of introducing bugs when using them.  And while the performance benefits show up in microbenchmarks, we don't believe they'll be impactful in the vast majority of real usage.  If it turns out they are, we can introduce a second set of interfaces in a light-up fashion.\n\nDiscarded options considered:\n- `ValueTask<bool> WaitForNextAsync(); bool TryGetNext(out T result);`: `out` parameters can't be covariant.  There's also a small impact here (an issue with the try pattern in general) that this likely incurs a runtime write barrier for reference type results.\n\n</details>\n\n#### Cancellation\n\nThere are several possible approaches to supporting cancellation:\n1. `IAsyncEnumerable<T>`/`IAsyncEnumerator<T>` are cancellation-agnostic: `CancellationToken` doesn't appear anywhere.  Cancellation is achieved by logically baking the `CancellationToken` into the enumerable and/or enumerator in whatever manner is appropriate, e.g. when calling an iterator, passing the `CancellationToken` as an argument to the iterator method and using it in the body of the iterator, as is done with any other parameter.\n2. `IAsyncEnumerator<T>.GetAsyncEnumerator(CancellationToken)`: You pass a `CancellationToken` to `GetAsyncEnumerator`, and subsequent `MoveNextAsync` operations respect it however it can.\n3. `IAsyncEnumerator<T>.MoveNextAsync(CancellationToken)`: You pass a `CancellationToken` to each individual `MoveNextAsync` call.\n4. 1 && 2: You both embed `CancellationToken`s into your enumerable/enumerator and pass `CancellationToken`s into `GetAsyncEnumerator`.\n5. 1 && 3: You both embed `CancellationToken`s into your enumerable/enumerator and pass `CancellationToken`s into `MoveNextAsync`.\n\nFrom a purely theoretical perspective, (5) is the most robust, in that (a) `MoveNextAsync` accepting a `CancellationToken` enables the most fine-grained control over what's canceled, and (b) `CancellationToken` is just any other type that can passed as an argument into iterators, embedded in arbitrary types, etc.\n\nHowever, there are multiple problems with that approach:\n- How does a `CancellationToken` passed to `GetAsyncEnumerator` make it into the body of the iterator?  We could expose a new `iterator` keyword that you could dot off of to get access to the `CancellationToken` passed to `GetEnumerator`, but a) that's a lot of additional machinery, b) we're making it a very first-class citizen, and c) the 99% case would seem to be the same code both calling an iterator and calling `GetAsyncEnumerator` on it, in which case it can just pass the `CancellationToken` as an argument into the method.\n- How does a `CancellationToken` passed to `MoveNextAsync` get into the body of the method?  This is even worse, as if it's exposed off of an `iterator` local object, its value could change across awaits, which means any code that registered with the token would need to unregister from it prior to awaits and then re-register after; it's also potentially quite expensive to need to do such registering and unregistering in every `MoveNextAsync` call, regardless of whether implemented by the compiler in an iterator or by a developer manually.\n- How does a developer cancel a `foreach` loop?  If it's done by giving a `CancellationToken` to an enumerable/enumerator, then either a) we need to support `foreach`'ing over enumerators, which raises them to being first-class citizens, and now you need to start thinking about an ecosystem built up around enumerators (e.g. LINQ methods) or b) we need to embed the `CancellationToken` in the enumerable anyway by having some `WithCancellation` extension method off of `IAsyncEnumerable<T>` that would store the provided token and then pass it into  the wrapped enumerable's `GetAsyncEnumerator` when the `GetAsyncEnumerator` on the returned struct is invoked (ignoring that token).  Or, you can just use the `CancellationToken` you have in the body of the foreach.\n- If/when query comprehensions are supported, how would the `CancellationToken` supplied to `GetEnumerator` or `MoveNextAsync` be passed into each clause?  The easiest way would simply be for the clause to capture it, at which point whatever token is passed to `GetAsyncEnumerator`/`MoveNextAsync` is ignored.\n\nAn earlier version of this document recommended (1), but we since switched to (4).\n\nThe two main problems with (1):\n- producers of cancellable enumerables have to implement some boilerplate, and can only leverage the compiler's support for async-iterators to implement a `IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken)` method.\n- it is likely that many producers would be tempted to just add a `CancellationToken` parameter to their async-enumerable signature instead, which will prevent consumers from passing the cancellation token they want when they are given an `IAsyncEnumerable` type.\n\nThere are two main consumption scenarios:\n1. `await foreach (var i in GetData(token)) ...` where the consumer calls the async-iterator method,\n2. `await foreach (var i in givenIAsyncEnumerable.WithCancellation(token)) ...` where the consumer deals with a given `IAsyncEnumerable` instance.\n\nWe find that a reasonable compromise to support both scenarios in a way that is convenient for both producers and consumers of async-streams is to use a specially annotated parameter in the async-iterator method. The `[EnumeratorCancellation]` attribute is used for this purpose. Placing this attribute on a parameter tells the compiler that if a token is passed to the `GetAsyncEnumerator` method, that token should be used instead of the value originally passed for the parameter.\n\nConsider `IAsyncEnumerable<int> GetData([EnumeratorCancellation] CancellationToken token = default)`. \nThe implementer of this method can simply use the parameter in the method body. \nThe consumer can use either consumption patterns above:\n1. if you use `GetData(token)`, then the token is saved into the async-enumerable and will be used in iteration,\n2. if you use `givenIAsyncEnumerable.WithCancellation(token)`, then the token passed to `GetAsyncEnumerator` will supersede any token saved in the async-enumerable.\n\n## foreach\n\n`foreach` will be augmented to support `IAsyncEnumerable<T>` in addition to its existing support for `IEnumerable<T>`.  And it will support the equivalent of `IAsyncEnumerable<T>` as a pattern if the relevant members are exposed publicly, falling back to using the interface directly if not, in order to enable struct-based extensions that avoid allocating as well as using alternative awaitables as the return type of `MoveNextAsync` and `DisposeAsync`.\n\n### Syntax\n\nUsing the syntax:\n\n```csharp\nforeach (var i in enumerable)\n```\n\nC# will continue to treat `enumerable` as a synchronous enumerable, such that even if it exposes the relevant APIs for async enumerables (exposing the pattern or implementing the interface), it will only consider the synchronous APIs.\n\nTo force `foreach` to instead only consider the asynchronous APIs, `await` is inserted as follows:\n\n```csharp\nawait foreach (var i in enumerable)\n```\n\nNo syntax would be provided that would support using either the async or the sync APIs; the developer must choose based on the syntax used.\n\n### Semantics\n\nThe compile-time processing of an `await foreach` statement first determines the ***collection type***, ***enumerator type*** and ***iteration type*** of the expression (very similar to https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md#1395-the-foreach-statement). This determination proceeds as follows:\n\n- If the type `X` of *expression* is `dynamic` or an array type, then an error is produced and no further steps are taken.\n- Otherwise, determine whether the type `X` has an appropriate `GetAsyncEnumerator` method:\n  - Perform member lookup on the type `X` with identifier `GetAsyncEnumerator` and no type arguments. If the member lookup does not produce a match, or it produces an ambiguity, or produces a match that is not a method group, check for an enumerable interface as described below.\n  - Perform overload resolution using the resulting method group and an empty argument list. If overload resolution results in no applicable methods, results in an ambiguity, or results in a single best method but that method is either static or not public, check for an enumerable interface as described below.\n  - If the return type `E` of the `GetAsyncEnumerator` method is not a class, struct or interface type, an error is produced and no further steps are taken.\n  - Member lookup is performed on `E` with the identifier `Current` and no type arguments. If the member lookup produces no match, the result is an error, or the result is anything except a public instance property that permits reading, an error is produced and no further steps are taken.\n  - Member lookup is performed on `E` with the identifier `MoveNextAsync` and no type arguments. If the member lookup produces no match, the result is an error, or the result is anything except a method group, an error is produced and no further steps are taken.\n  - Overload resolution is performed on the method group with an empty argument list. If overload resolution results in no applicable methods, results in an ambiguity, or results in a single best method but that method is either static or not public, or its return type is not awaitable into `bool`, an error is produced and no further steps are taken.\n  - The collection type is `X`, the enumerator type is `E`, and the iteration type is the type of the `Current` property.\n- Otherwise, check for an enumerable interface:\n  - If among all the types `Tᵢ` for which there is an implicit conversion from `X` to `IAsyncEnumerable<ᵢ>`, there is a unique type `T` such that `T` is not dynamic and for all the other `Tᵢ` there is an implicit conversion from `IAsyncEnumerable<T>` to `IAsyncEnumerable<Tᵢ>`, then the collection type is the interface `IAsyncEnumerable<T>`, the enumerator type is the interface `IAsyncEnumerator<T>`, and the iteration type is `T`.\n  - Otherwise, if there is more than one such type `T`, then an error is produced and no further steps are taken.\n- Otherwise, an error is produced and no further steps are taken.\n\nThe above steps, if successful, unambiguously produce a collection type `C`, enumerator type `E` and iteration type `T`.\n\n```csharp\nawait foreach (V v in x) «embedded_statement»\n```\n\nis then expanded to:\n\n```csharp\n{\n    E e = ((C)(x)).GetAsyncEnumerator();\n    try {\n        while (await e.MoveNextAsync()) {\n            V v = (V)(T)e.Current;\n            «embedded_statement»\n        }\n    }\n    finally {\n        ... // Dispose e\n    }\n}\n```\n\nThe body of the `finally` block is constructed according to the following steps:\n- If the type `E` has an appropriate `DisposeAsync` method:\n  - Perform member lookup on the type `E` with identifier `DisposeAsync` and no type arguments. If the member lookup does not produce a match, or it produces an ambiguity, or produces a match that is not a method group, check for the disposal interface as described below.\n  - Perform overload resolution using the resulting method group and an empty argument list. If overload resolution results in no applicable methods, results in an ambiguity, or results in a single best method but that method is either static or not public, check for the disposal interface as described below.\n  - If the return type of the `DisposeAsync` method is not awaitable, an error is produced and no further steps are taken.\n  - The `finally` clause is expanded to the semantic equivalent of:\n  ```csharp\n    finally {\n        await e.DisposeAsync();\n    }\n    ```\n- Otherwise, if there is an implicit conversion from `E` to the `System.IAsyncDisposable` interface, then\n  - If `E` is a non-nullable value type then the `finally` clause is expanded to the semantic equivalent of:\n  ```csharp\n    finally {\n        await ((System.IAsyncDisposable)e).DisposeAsync();\n    }\n    ```\n  - Otherwise the `finally` clause is expanded to the semantic equivalent of:\n    ```csharp\n    finally {\n        System.IAsyncDisposable d = e as System.IAsyncDisposable;\n        if (d != null) await d.DisposeAsync();\n    }\n    ```\n    except that if `E` is a value type, or a type parameter instantiated to a value type, then the conversion of `e` to `System.IAsyncDisposable` shall not cause boxing to occur.\n- Otherwise, the `finally` clause is expanded to an empty block:\n  ```csharp\n  finally {\n  }\n  ```\n\n### ConfigureAwait\n\nThis pattern-based compilation will allow `ConfigureAwait` to be used on all of the awaits, via a `ConfigureAwait` extension method:\n\n```csharp\nawait foreach (T item in enumerable.ConfigureAwait(false))\n{\n   ...\n}\n```\n\nThis will be based on types we'll add to .NET as well, likely to System.Threading.Tasks.Extensions.dll:\n\n```csharp\n// Approximate implementation, omitting arg validation and the like\nnamespace System.Threading.Tasks\n{\n    public static class AsyncEnumerableExtensions\n    {\n        public static ConfiguredAsyncEnumerable<T> ConfigureAwait<T>(this IAsyncEnumerable<T> enumerable, bool continueOnCapturedContext) =>\n            new ConfiguredAsyncEnumerable<T>(enumerable, continueOnCapturedContext);\n\n        public struct ConfiguredAsyncEnumerable<T>\n        {\n            private readonly IAsyncEnumerable<T> _enumerable;\n            private readonly bool _continueOnCapturedContext;\n\n            internal ConfiguredAsyncEnumerable(IAsyncEnumerable<T> enumerable, bool continueOnCapturedContext)\n            {\n                _enumerable = enumerable;\n                _continueOnCapturedContext = continueOnCapturedContext;\n            }\n\n            public ConfiguredAsyncEnumerator<T> GetAsyncEnumerator() =>\n                new ConfiguredAsyncEnumerator<T>(_enumerable.GetAsyncEnumerator(), _continueOnCapturedContext);\n\n            public struct ConfiguredAsyncEnumerator<T>\n            {\n                private readonly IAsyncEnumerator<T> _enumerator;\n                private readonly bool _continueOnCapturedContext;\n\n                internal ConfiguredAsyncEnumerator(IAsyncEnumerator<T> enumerator, bool continueOnCapturedContext)\n                {\n                    _enumerator = enumerator;\n                    _continueOnCapturedContext = continueOnCapturedContext;\n                }\n\n                public ConfiguredValueTaskAwaitable<bool> MoveNextAsync() =>\n                    _enumerator.MoveNextAsync().ConfigureAwait(_continueOnCapturedContext);\n\n                public T Current => _enumerator.Current;\n\n                public ConfiguredValueTaskAwaitable DisposeAsync() =>\n                    _enumerator.DisposeAsync().ConfigureAwait(_continueOnCapturedContext);\n            }\n        }\n    }\n}\n```\n\nNote that this approach will not enable `ConfigureAwait` to be used with pattern-based enumerables, but then again it's already the case that the `ConfigureAwait` is only exposed as an extension on `Task`/`Task<T>`/`ValueTask`/`ValueTask<T>` and can't be applied to arbitrary awaitable things, as it only makes sense when applied to Tasks (it controls a behavior implemented in Task's continuation support), and thus doesn't make sense when using a pattern where the awaitable things may not be tasks.  Anyone returning awaitable things can provide their own custom behavior in such advanced scenarios.\n\n(If we can come up with some way to support a scope- or assembly-level `ConfigureAwait` solution, then this won't be necessary.)\n\n## Async Iterators\n\nThe language / compiler will support producing `IAsyncEnumerable<T>`s and `IAsyncEnumerator<T>`s in addition to consuming them. Today the language supports writing an iterator like:\n\n```csharp\nstatic IEnumerable<int> MyIterator()\n{\n    try\n    {\n        for (int i = 0; i < 100; i++)\n        {\n            Thread.Sleep(1000);\n            yield return i;\n        }\n    }\n    finally\n    {\n        Thread.Sleep(200);\n        Console.WriteLine(\"finally\");\n    }\n}\n```\n\nbut `await` can't be used in the body of these iterators.  We will add that support.\n\n### Syntax\n\nThe existing language support for iterators infers the iterator nature of the method based on whether it contains any `yield`s.  The same will be true for async iterators.  Such async iterators will be demarcated and differentiated from synchronous iterators via adding `async` to the signature, and must then also have either `IAsyncEnumerable<T>` or `IAsyncEnumerator<T>` as its return type.  For example, the above example could be written as an async iterator as follows:\n\n```csharp\nstatic async IAsyncEnumerable<int> MyIterator()\n{\n    try\n    {\n        for (int i = 0; i < 100; i++)\n        {\n            await Task.Delay(1000);\n            yield return i;\n        }\n    }\n    finally\n    {\n        await Task.Delay(200);\n        Console.WriteLine(\"finally\");\n    }\n}\n```\n\nAlternatives considered:\n- _Not using `async` in the signature_: Using `async` is likely technically required by the compiler, as it uses it to determine whether `await` is valid in that context.  But even if it's not required, we've established that `await` may only be used in methods marked as `async`, and it seems important to keep the consistency.\n- _Enabling custom builders for `IAsyncEnumerable<T>`_:  That's something we could look at for the future, but the machinery is complicated and we don't support that for the synchronous counterparts.\n- _Having an `iterator` keyword in the signature_: Async iterators would use `async iterator` in the signature, and `yield` could only be used in `async` methods that included `iterator`; `iterator` would then be made optional on synchronous iterators.  Depending on your perspective, this has the benefit of making it very clear by the signature of the method whether `yield` is allowed and whether the method is actually meant to return instances of type `IAsyncEnumerable<T>` rather than the compiler manufacturing one based on whether the code uses `yield` or not.  But it is different from synchronous iterators, which don't and can't be made to require one.  Plus some developers don't like the extra syntax.  If we were designing it from scratch, we'd probably make this required, but at this point there's much more value in keeping async iterators close to sync iterators.\n\n## LINQ\n\nThere are over ~200 overloads of methods on the `System.Linq.Enumerable` class, all of which work in terms of `IEnumerable<T>`; some of these accept `IEnumerable<T>`, some of them produce `IEnumerable<T>`, and many do both.  Adding LINQ support for `IAsyncEnumerable<T>` would likely entail duplicating all of these overloads for it, for another ~200.  And since `IAsyncEnumerator<T>` is likely to be more common as a standalone entity in the asynchronous world than `IEnumerator<T>` is in the synchronous world, we could potentially need another ~200 overloads that work with `IAsyncEnumerator<T>`.  Plus, a large number of the overloads deal with predicates (e.g. `Where` that takes a `Func<T, bool>`), and it may be desirable to have `IAsyncEnumerable<T>`-based overloads that deal with both synchronous and asynchronous predicates (e.g. `Func<T, ValueTask<bool>>` in addition to `Func<T, bool>`).  While this isn't applicable to all of the now ~400 new overloads, a rough calculation is that it'd be applicable to half, which means another ~200 overloads, for a total of ~600 new methods.\n\nThat is a staggering number of APIs, with the potential for even more when extension libraries like Interactive Extensions (Ix) are considered.  But Ix already has an implementation of many of these, and there doesn't seem to be a great reason to duplicate that work; we should instead help the community improve Ix and recommend it for when developers want to use LINQ with `IAsyncEnumerable<T>`.\n\nThere is also the issue of query comprehension syntax.  The pattern-based nature of query comprehensions would allow them to \"just work\" with some operators, e.g. if Ix provides the following methods:\n\n```csharp\npublic static IAsyncEnumerable<TResult> Select<TSource, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, TResult> func);\npublic static IAsyncEnumerable<T> Where(this IAsyncEnumerable<T> source, Func<T, bool> func);\n```\n\nthen this C# code will \"just work\":\n\n```csharp\nIAsyncEnumerable<int> enumerable = ...;\nIAsyncEnumerable<int> result = from item in enumerable\n                               where item % 2 == 0\n                               select item * 2;\n```\n\nHowever, there is no query comprehension syntax that supports using `await` in the clauses, so if Ix added, for example:\n\n```csharp\npublic static IAsyncEnumerable<TResult> Select<TSource, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TResult>> func);\n```\n\nthen this would \"just work\":\n\n```csharp\nIAsyncEnumerable<string> result = from url in urls\n                                  where item % 2 == 0\n                                  select SomeAsyncMethod(item);\n\nasync ValueTask<int> SomeAsyncMethod(int item)\n{\n    await Task.Yield();\n    return item * 2;\n}\n```\n\nbut there'd be no way to write it with the `await` inline in the `select` clause.  As a separate effort, we could look into adding `async { ... }` expressions to the language, at which point we could allow them to be used in query comprehensions and the above could instead be written as:\n\n```csharp\nIAsyncEnumerable<int> result = from item in enumerable\n                               where item % 2 == 0\n                               select async\n                               {\n                                   await Task.Yield();\n                                   return item * 2;\n                               };\n```\n\nor to enabling `await` to be used directly in expressions, such as by supporting `async from`.  However, it's unlikely a design here would impact the rest of the feature set one way or the other, and this isn't a particularly high-value thing to invest in right now, so the proposal is to do nothing additional here right now.\n\n## Integration with other asynchronous frameworks\n\nIntegration with `IObservable<T>` and other asynchronous frameworks (e.g. reactive streams) would be done at the library level rather than at the language level.  For example, all of the data from an `IAsyncEnumerator<T>` can be published to an `IObserver<T>` simply by `await foreach`'ing over the enumerator and `OnNext`'ing the data to the observer, so an `AsObservable<T>` extension method is possible.  Consuming an `IObservable<T>` in a `await foreach` requires buffering the data (in case another item is pushed while the previous item is still being processing), but such a push-pull adapter can easily be implemented to enable an `IObservable<T>` to be pulled from with an `IAsyncEnumerator<T>`.  Etc.  Rx/Ix already provide prototypes of such implementations, and libraries like https://github.com/dotnet/corefx/tree/master/src/System.Threading.Channels provide various kinds of buffering data structures.  The language need not be involved at this stage.\n"
  },
  {
    "path": "proposals/csharp-8.0/async-using.md",
    "content": "﻿## Async using declaration\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/43>\n\nIn C# 8.0 we added support for an *async using* statements. There are two forms. One has a block body that is the scope of the using declaratation. The other declares a local and is implicitly scoped to the end of the block. This is a placeholder for their specification.\n"
  },
  {
    "path": "proposals/csharp-8.0/constraints-in-overrides.md",
    "content": "﻿## Override with constraints\n\nIn C# 8.0, we added a feature to permit the specification of certain type parameter constraints in an `override` method declaration. This is a placeholder for its specification.\n"
  },
  {
    "path": "proposals/csharp-8.0/constructed-unmanaged.md",
    "content": "﻿## Unmanaged constructed types\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/1937>\n\nIn C# 8.0, we extended the concept of an *unmanaged* type to include constructed (generic) types. This is a placeholder for its specification.\n"
  },
  {
    "path": "proposals/csharp-8.0/default-interface-methods.md",
    "content": "# default interface methods\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/52>\n\n## Summary\n[summary]: #summary\n\nAdd support for _virtual extension methods_ - methods in interfaces with concrete implementations. A class or struct that implements such an interface is required to have a single _most specific_ implementation for the interface method, either implemented by the class or struct, or inherited from its base classes or interfaces. Virtual extension methods enable an API author to add methods to an interface in future versions without breaking source or binary compatibility with existing implementations of that interface.\n\nThese are similar to Java's [\"Default Methods\"](http://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html).\n\n(Based on the likely implementation technique) this feature requires corresponding support in the CLI/CLR. Programs that take advantage of this feature cannot run on earlier versions of the platform.\n\n## Motivation\n[motivation]: #motivation\n\nThe principal motivations for this feature are\n\n- Default interface methods enable an API author to add methods to an interface in future versions without breaking source or binary compatibility with existing implementations of that interface.\n- The feature enables C# to interoperate with APIs targeting [Android (Java)](http://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html) and [iOS (Swift)](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID267), which support similar features.\n- As it turns out, adding default interface implementations provides the elements of the \"traits\" language feature (<https://en.wikipedia.org/wiki/Trait_(computer_programming)>). Traits have proven to be a powerful programming technique (<http://scg.unibe.ch/archive/papers/Scha03aTraits.pdf>).\n\n## Detailed design\n[design]: #detailed-design\n\nThe syntax for an interface is extended to permit\n\n- member declarations that declare constants, operators, static constructors, and nested types;\n- a *body* for a method or indexer, property, or event accessor (that is, a \"default\" implementation);\n- member declarations that declare static fields, methods, properties, indexers, and events;\n- member declarations using the explicit interface implementation syntax; and\n- Explicit access modifiers (the default access is `public`).\n\nMembers with bodies permit the interface to provide a \"default\" implementation for the method in classes and structs that do not provide their own implementation.\n\nInterfaces may not contain instance state. While static fields are now permitted, instance fields are not permitted in interfaces. Instance auto-properties are not supported in interfaces, as they would implicitly declare a hidden field.\n\nStatic and private methods permit useful refactoring and organization of code used to implement the interface's public API.\n\nA method override in an interface must use the explicit interface implementation syntax.\n\nIt is an error to declare a class type, struct type, or enum type within the scope of a type parameter that was declared with a *variance_annotation*.  For example, the declaration of `C` below is an error.\n\n```csharp\ninterface IOuter<out T>\n{\n    class C { } // error: class declaration within the scope of variant type parameter 'T'\n}\n```\n\n### Concrete methods in interfaces\n\nThe simplest form of this feature is the ability to declare a *concrete method* in an interface, which is a method with a body.\n\n```csharp\ninterface IA\n{\n    void M() { WriteLine(\"IA.M\"); }\n}\n```\n\nA class that implements this interface need not implement its concrete method.\n\n```csharp\nclass C : IA { } // OK\n\nIA i = new C();\ni.M(); // prints \"IA.M\"\n```\n\nThe final override for `IA.M` in class `C` is the concrete method `M` declared in `IA`. Note that a class does not inherit members from its interfaces; that is not changed by this feature:\n\n```csharp\nnew C().M(); // error: class 'C' does not contain a member 'M'\n```\n\nWithin an instance member of an interface, `this` has the type of the enclosing interface.\n\n### Modifiers in interfaces\n\nThe syntax for an interface is relaxed to permit modifiers on its members. The following are permitted: `private`, `protected`, `internal`, `public`, `virtual`, `abstract`, `sealed`, `static`, `extern`, and `partial`.\n\nAn interface member whose declaration includes a body is a `virtual` member unless the `sealed` or `private` modifier is used. The `virtual` modifier may be used on a function member that would otherwise be implicitly `virtual`. Similarly, although `abstract` is the default on interface members without bodies, that modifier may be given explicitly. A non-virtual member may be declared using the `sealed` keyword.\n\nIt is an error for a `private` or `sealed` function member of an interface to have no body. A `private` function member may not have the modifier `sealed`.\n\nAccess modifiers may be used on interface members of all kinds of members that are permitted. The access level `public` is the default but it may be given explicitly.\n\n> ***Open Issue:*** We need to specify the precise meaning of the access modifiers such as `protected` and `internal`, and which declarations do and do not override them (in a derived interface) or implement them (in a class that implements the interface).\n\nInterfaces may declare `static` members, including nested types, methods, indexers, properties, events, and static constructors. The default access level for all interface members is `public`.\n\nInterfaces may not declare instance constructors, destructors, or fields.\n\n> ***Closed Issue:*** Should operator declarations be permitted in an interface? Probably not conversion operators, but what about others? ***Decision***: Operators are permitted *except* for conversion, equality, and inequality operators.\n\n> ***Closed Issue:*** Should `new` be permitted on interface member declarations that hide members from base interfaces? ***Decision***: Yes.\n\n> ***Closed Issue:*** We do not currently permit `partial` on an interface or its members. That would require a separate proposal. ***Decision***: Yes. <https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#permit-partial-in-interface>\n\n### Explicit implementation in interfaces\n\nExplicit implementations allow the programmer to provide a most specific implementation of a virtual member in an interface where the compiler or runtime would not otherwise find one. An implementation declaration is permitted to *explicitly* implement a particular base interface method by qualifying the declaration with the interface name (no access modifier is permitted in this case). Implicit implementations are not permitted.\n\n```csharp\ninterface IA\n{\n    void M() { WriteLine(\"IA.M\"); }\n}\ninterface IB : IA\n{\n    void IA.M() { WriteLine(\"IB.M\"); } // Explicit implementation\n}\ninterface IC : IA\n{\n    void M() { WriteLine(\"IC.M\"); } // Creates a new M, unrelated to `IA.M`. Warning\n}\n```\n\nExplicit implementations in interfaces may not be declared `sealed`.\n\nPublic `virtual` function members in an interface may only be implemented in a derived interface explicitly (by qualifying the name in the declaration with the interface type that originally declared the method, and omitting an access modifier). The member must be *accessible* where it is implemented.\n\n### Reabstraction\n\nA virtual (concrete) method declared in an interface may be reabstracted in a derived interface\n\n```csharp\ninterface IA\n{\n    void M() { WriteLine(\"IA.M\"); }\n}\ninterface IB : IA\n{\n    abstract void IA.M();\n}\nclass C : IB { } // error: class 'C' does not implement 'IA.M'.\n```\n\nThe `abstract` modifier is required in the declaration of `IB.M`, to indicate that `IA.M` is being reabstracted.\n\nThis is useful in derived interfaces where the default implementation of a method is inappropriate and a more appropriate implementation should be provided by implementing classes.\n\n### The most specific implementation rule\n\nWe require that every interface and class have a *most specific implementation* for every virtual member among the implementations appearing in the type or its direct and indirect interfaces. The *most specific implementation* is a unique implementation that is more specific than every other implementation. If there is no implementation, the member itself is considered the most specific implementation.\n\nOne implementation `M1` is considered *more specific* than another implementation `M2` if `M1` is declared on type `T1`, `M2` is declared on type `T2`, and either\n\n1. `T1` contains `T2` among its direct or indirect interfaces, or\n2. `T2` is an interface type but `T1` is not an interface type.\n\nFor example:\n\n```csharp\ninterface IA\n{\n    void M() { WriteLine(\"IA.M\"); }\n}\ninterface IB : IA\n{\n    void IA.M() { WriteLine(\"IB.M\"); }\n}\ninterface IC : IA\n{\n    void IA.M() { WriteLine(\"IC.M\"); }\n}\ninterface ID : IB, IC { } // compiles, but error when a class implements 'ID'\nabstract class C : IB, IC { } // error: no most specific implementation for 'IA.M'\nabstract class D : IA, IB, IC // ok\n{\n    public abstract void M();\n}\npublic class E : ID { } // Error. No most specific implementation for 'IA.M'\n```\n\nThe most specific implementation rule ensures that a conflict (i.e. an ambiguity arising from diamond inheritance) is resolved explicitly by the programmer at the point where the conflict arises.\n\nBecause we support explicit reabstractions in interfaces, we could do so in classes as well\n\n```csharp\nabstract class E : IA, IB, IC // ok\n{\n    abstract void IA.M();\n}\n```\n\n> ***Closed issue***: should we support explicit interface abstract implementations in classes? **Decision: NO**\n\nIn addition, it is an error if in a class declaration the most specific implementation of some interface method is an abstract implementation that was declared in an interface. This is an existing rule restated using the new terminology.\n\n```csharp\ninterface IF\n{\n    void M();\n}\nabstract class F : IF { } // error: 'F' does not implement 'IF.M'\n```\n\nIt is possible for a virtual property declared in an interface to have a most specific implementation for its `get` accessor in one interface and a most specific implementation for its `set` accessor in a different interface. This is considered a violation of the *most specific implementation* rule, and generates a compiler error.\n\n### `static` and `private` methods\n\nBecause interfaces may now contain executable code, it is useful to abstract common code into private and static methods. We now permit these in interfaces.\n\n> ***Closed issue***: Should we support private methods? Should we support static methods? **Decision: YES**\n\n> ***Open issue***: should we permit interface methods to be `protected` or `internal` or other access? If so, what are the semantics? Are they `virtual` by default? If so, is there a way to make them non-virtual?\n\n> ***Closed issue***: If we support static methods, should we support (static) operators? **Decision: YES**\n\n### Base interface invocations\n\nThe syntax in this section hasn't been implemented. It remains an active proposal.\n\n<details>\n\nCode in a type that derives from an interface with a default method can explicitly invoke that interface's \"base\" implementation.\n\n```csharp\ninterface I0\n{\n   void M() { Console.WriteLine(\"I0\"); }\n}\ninterface I1 : I0\n{\n   override void M() { Console.WriteLine(\"I1\"); }\n}\ninterface I2 : I0\n{\n   override void M() { Console.WriteLine(\"I2\"); }\n}\ninterface I3 : I1, I2\n{\n   // an explicit override that invoke's a base interface's default method\n   void I0.M() { I2.base.M(); }\n}\n```\n\nAn instance (nonstatic) method is permitted to invoke the implementation of an accessible instance method in a direct base interface nonvirtually by naming it using the syntax `base(Type).M`. This is useful when an override that is required to be provided due to diamond inheritance is resolved by delegating to one particular base implementation.\n\n```csharp\ninterface IA\n{\n    void M() { WriteLine(\"IA.M\"); }\n}\ninterface IB : IA\n{\n    override void IA.M() { WriteLine(\"IB.M\"); }\n}\ninterface IC : IA\n{\n    override void IA.M() { WriteLine(\"IC.M\"); }\n}\n\nclass D : IA, IB, IC\n{\n    void IA.M() { base(IB).M(); }\n}\n```\n\nWhen a `virtual` or `abstract` member is accessed using the syntax `base(Type).M`, it is required that `Type` contains a unique *most specific override* for `M`.\n\n</details>\n\n### Binding base clauses\n\nInterfaces now contain types.  These types may be used in the base clause as base interfaces.  When binding a base clause, we may need to know the set of base interfaces to bind those types (e.g. to lookup in them and to resolve protected access).  The meaning of an interface's base clause is thus circularly defined.  To break the cycle, we add a new language rules corresponding to a similar rule already in place for classes.\n\nWhile determining the meaning of the *interface_base* of an interface, the base interfaces are temporarily assumed to be empty. Intuitively this ensures that the meaning of a base clause cannot recursively depend on itself. \n\n**We used to have the following rules:**\n\n\"When a class B derives from a class A, it is a compile-time error for A to depend on B. A class **directly depends on** its direct base class (if any) and **directly depends on** the ~~**class**~~ within which it is immediately nested (if any). Given this definition, the complete set of ~~**classes**~~ upon which a class depends is the reflexive and transitive closure of the **directly depends on** relationship.\"\n\nIt is a compile-time error for an interface to directly or indirectly inherit from itself.\nThe **base interfaces** of an interface are the explicit base interfaces and their base interfaces. In other words, the set of base interfaces is the complete transitive closure of the explicit base interfaces, their explicit base interfaces, and so on.\n\n**We are adjusting them as follows:**\n\nWhen a class B derives from a class A, it is a compile-time error for A to depend on B. A class **directly depends on** its direct base class (if any) and **directly depends on** the _**type**_ within which it is immediately nested (if any).\n\nWhen an interface IB extends an interface IA, it is a compile-time error for IA to depend on IB. An interface **directly depends on** its direct base interfaces (if any) and **directly depends on** the type within which it is immediately nested (if any).\n\nGiven these definitions, the complete set of **types** upon which a type depends is the reflexive and transitive closure of the **directly depends on** relationship.\n\n### Effect on existing programs\n\nThe rules presented here are intended to have no effect on the meaning of existing programs.\n\nExample 1:\n\n```csharp\ninterface IA\n{\n    void M();\n}\nclass C: IA // Error: IA.M has no concrete most specific override in C\n{\n    public static void M() { } // method unrelated to 'IA.M' because static\n}\n```\n\nExample 2:\n\n```csharp\ninterface IA\n{\n    void M();\n}\nclass Base: IA\n{\n    void IA.M() { }\n}\nclass Derived: Base, IA // OK, all interface members have a concrete most specific override\n{\n    private void M() { } // method unrelated to 'IA.M' because private\n}\n```\n\nThe same rules give similar results to the analogous situation involving default interface methods:\n\n```csharp\ninterface IA\n{\n    void M() { }\n}\nclass Derived: IA // OK, all interface members have a concrete most specific override\n{\n    private void M() { } // method unrelated to 'IA.M' because private\n}\n```\n\n> ***Closed issue***: confirm that this is an intended consequence of the specification. **Decision: YES**\n\n### Runtime method resolution\n\n> ***Closed Issue:*** The spec should describe the runtime method resolution algorithm in the face of interface default methods. We need to ensure that the semantics are consistent with the language semantics, e.g. which declared methods do and do not override or implement an `internal` method.\n\n### CLR support API\n\nIn order for compilers to detect when they are compiling for a runtime that supports this feature, libraries for such runtimes are modified to advertise that fact through the API discussed in <https://github.com/dotnet/corefx/issues/17116>. We add\n\n```csharp\nnamespace System.Runtime.CompilerServices\n{\n    public static class RuntimeFeature\n    {\n        // Presence of the field indicates runtime support\n        public const string DefaultInterfaceImplementation = nameof(DefaultInterfaceImplementation);\n    }\n}\n```\n\n> ***Open issue***: Is that the best name for the *CLR* feature? The CLR feature does much more than just that (e.g. relaxes protection constraints, supports overrides in interfaces, etc). Perhaps it should be called something like \"concrete methods in interfaces\", or \"traits\"?\n\n### Further areas to be specified\n\n- [ ] It would be useful to catalog the kinds of source and binary compatibility effects caused by adding default interface methods and overrides to existing interfaces.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nThis proposal requires a coordinated update to the CLR specification (to support concrete methods in interfaces and method resolution). It is therefore fairly \"expensive\" and it may be worth doing in combination with other features that we also anticipate would require CLR changes.\n\n## Alternatives\n[alternatives]: #alternatives\n\nNone.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n- Open questions are called out throughout the proposal, above.\n- See also <https://github.com/dotnet/csharplang/issues/406> for a list of open questions.\n- The detailed specification must describe the resolution mechanism used at runtime to select the precise method to be invoked.\n- The interaction of metadata produced by new compilers and consumed by older compilers needs to be worked out in detail. For example, we need to ensure that the metadata representation that we use does not cause the addition of a default implementation in an interface to break an existing class that implements that interface when compiled by an older compiler. This may affect the metadata representation that we can use.\n- The design must consider interoperation with other languages and existing compilers for other languages.\n\n## Resolved Questions\n\n### Abstract Override\n\nThe earlier draft spec contained the ability to \"reabstract\" an inherited method:\n\n```csharp\ninterface IA\n{\n    void M();\n}\ninterface IB : IA\n{\n    override void M() { }\n}\ninterface IC : IB\n{\n    override void M(); // make it abstract again\n}\n```\n\nMy notes for 2017-03-20 showed that we decided not to allow this. However, there are at least two use cases for it:\n\n1. The Java APIs, with which some users of this feature hope to interoperate, depend on this facility.\n2. Programming with *traits* benefits from this. Reabstraction is one of the elements of the \"traits\" language feature (https://en.wikipedia.org/wiki/Trait_(computer_programming)). The following is permitted with classes:\n\n```csharp\npublic abstract class Base\n{\n    public abstract void M();\n}\npublic abstract class A : Base\n{\n    public override void M() { }\n}\npublic abstract class B : A\n{\n    public override abstract void M(); // reabstract Base.M\n}\n```\n\nUnfortunately this code cannot be refactored as a set of interfaces (traits) unless this is permitted. By the *Jared principle of greed*, it should be permitted.\n\n> ***Closed issue:*** Should reabstraction be permitted? [YES] My notes were wrong. The [LDM notes](https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-03-21.md) say that reabstraction is permitted in an interface. Not in a class.\n\n### Virtual Modifier vs Sealed Modifier\n\nFrom [Aleksey Tsingauz](https://github.com/AlekseyTs):\n\n> We decided to allow modifiers explicitly stated on interface members, unless there is a reason to disallow some of them. This brings an interesting question around virtual modifier. Should it be required on members with default implementation?\n>\n> We could say that:\n>\n> - if there is no implementation and neither virtual, nor sealed are specified, we assume the member is abstract.\n> - if there is an implementation and neither abstract, nor sealed are specified, we assume the member is virtual.\n> - sealed modifier is required to make a method neither virtual, nor abstract.\n>\n> Alternatively, we could say that virtual modifier is required for a virtual member. I.e, if there is a member with implementation not explicitly marked with virtual modifier, it is neither virtual, nor abstract. This approach might provide better experience when a method is moved from a class to an interface:\n>\n> - an abstract method stays abstract.\n> - a virtual method stays virtual.\n> - a method without any modifier stays neither virtual, nor abstract.\n> - sealed modifier cannot be applied to a method that is not an override.\n>\n> What do you think?\n\n> ***Closed Issue:*** Should a concrete method (with implementation) be implicitly `virtual`? [YES]\n\n***Decisions:*** Made in the LDM 2017-04-05:\n\n1. non-virtual should be explicitly expressed through `sealed` or `private`.\n2. `sealed` is the keyword to make interface instance members with bodies non-virtual\n3. We want to allow all modifiers in interfaces  \n4. Default accessibility for interface members is public, including nested types\n5. private function members in interfaces are implicitly sealed, and `sealed` is not permitted on them.\n6. Private classes (in interfaces) are permitted and can be sealed, and that means sealed in the class sense of sealed.\n7. Absent a good proposal, partial is still not allowed on interfaces or their members.\n\n### Binary Compatibility 1\n\nWhen a library provides a default implementation\n\n```csharp\ninterface I1\n{\n    void M() { Impl1 }\n}\ninterface I2 : I1\n{\n}\nclass C : I2\n{\n}\n```\n\nWe understand that the implementation of `I1.M` in `C` is `I1.M`. What if the assembly containing `I2` is changed as follows and recompiled\n\n```csharp\ninterface I2 : I1\n{\n    override void M() { Impl2 }\n}\n```\n\nbut `C` is not recompiled. What happens when the program is run? An invocation of `(C as I1).M()`\n\n1. Runs `I1.M`\n2. Runs `I2.M`\n3. Throws some kind of runtime error\n\n***Decision:*** Made 2017-04-11: Runs `I2.M`, which is the unambiguously most specific override at runtime.\n\n### Event accessors (closed)\n\n> ***Closed Issue:*** Can an event be overridden \"piecewise\"?\n\nConsider this case:\n\n```csharp\npublic interface I1\n{\n    event T e1;\n}\npublic interface I2 : I1\n{\n    override event T\n    {\n        add { }\n        // error: \"remove\" accessor missing\n    }\n}\n```\n\nThis \"partial\" implementation of the event is not permitted because, as in a class, the syntax for an event declaration does not permit only one accessor; both (or neither) must be provided. You could accomplish the same thing by permitting the abstract remove accessor in the syntax to be implicitly abstract by the absence of a body:\n\n```csharp\npublic interface I1\n{\n    event T e1;\n}\npublic interface I2 : I1\n{\n    override event T\n    {\n        add { }\n        remove; // implicitly abstract\n    }\n}\n```\n\nNote that *this is a new (proposed) syntax*. In the current grammar, event accessors have a mandatory body.\n\n> ***Closed Issue:*** Can an event accessor be (implicitly) abstract by the omission of a body, similarly to the way that methods in interfaces and property accessors are (implicitly) abstract by the omission of a body?\n\n***Decision:*** (2017-04-18) No, event declarations require both concrete accessors (or neither).\n\n### Reabstraction in a Class (closed)\n\n***Closed Issue:*** We should confirm that this is permitted (otherwise adding a default implementation would be a breaking change):\n\n```csharp\ninterface I1\n{\n    void M() { }\n}\nabstract class C : I1\n{\n    public abstract void M(); // implement I1.M with an abstract method in C\n}\n```\n\n***Decision:*** (2017-04-18) Yes, adding a body to an interface member declaration shouldn't break C.\n\n### Sealed Override (closed)\n\nThe previous question implicitly assumes that the `sealed` modifier can be applied to an `override` in an interface. This contradicts the draft specification. Do we want to permit sealing an override? Source and binary compatibility effects of sealing should be considered.\n\n> ***Closed Issue:*** Should we permit sealing an override?\n\n***Decision:*** (2017-04-18) Let's not allow `sealed` on overrides in interfaces. The only use of `sealed` on interface members is to make them non-virtual in their initial declaration.\n\n### Diamond inheritance and classes (closed)\n\nThe draft of the proposal prefers class overrides to interface overrides in diamond inheritance scenarios:\n\n> We require that every interface and class have a *most specific override* for every interface method among the overrides appearing in the type or its direct and indirect interfaces. The *most specific override* is a unique override that is more specific than every other override. If there is no override, the method itself is considered the most specific override.\n>\n> One override `M1` is considered *more specific* than another override `M2` if `M1` is declared on type `T1`, `M2` is declared on type `T2`, and either\n>\n> 1. `T1` contains `T2` among its direct or indirect interfaces, or\n> 2. `T2` is an interface type but `T1` is not an interface type.\n\nThe scenario is this\n\n```csharp\ninterface IA\n{\n    void M();\n}\ninterface IB : IA\n{\n    override void M() { WriteLine(\"IB\"); }\n}\nclass Base : IA\n{\n    void IA.M() { WriteLine(\"Base\"); }\n}\nclass Derived : Base, IB // allowed?\n{\n    static void Main()\n    {\n        IA a = new Derived();\n        a.M();           // what does it do?\n    }\n}\n```\n\nWe should confirm this behavior (or decide otherwise)\n\n> ***Closed Issue:*** Confirm the draft spec, above, for *most specific override* as it applies to mixed classes and interfaces (a class takes priority over an interface). See <https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-19.md#diamonds-with-classes>.\n\n### Interface methods vs structs (closed)\n\nThere are some unfortunate interactions between default interface methods and structs.\n\n```csharp\ninterface IA\n{\n    public void M() { }\n}\nstruct S : IA\n{\n}\n```\n\nNote that interface members are not inherited:\n\n```csharp\nvar s = default(S);\ns.M(); // error: 'S' does not contain a member 'M'\n```\n\nConsequently, the client must box the struct to invoke interface methods\n\n```csharp\nIA s = default(S); // an S, boxed\ns.M(); // ok\n```\n\nBoxing in this way defeats the principal benefits of a `struct` type. Moreover, any mutation methods will have no apparent effect, because they are operating on a *boxed copy* of the struct:\n\n```csharp\ninterface IB\n{\n    public void Increment() { P += 1; }\n    public int P { get; set; }\n}\nstruct T : IB\n{\n    public int P { get; set; } // auto-property\n}\n\nT t = default(T);\nConsole.WriteLine(t.P); // prints 0\n(t as IB).Increment();\nConsole.WriteLine(t.P); // prints 0\n```\n\n> ***Closed Issue:*** What can we do about this:\n>\n> 1. Forbid a `struct` from inheriting a default implementation. All interface methods would be treated as abstract in a `struct`. Then we may take time later to decide how to make it work better.\n> 2. Come up with some kind of code generation strategy that avoids boxing. Inside a method like `IB.Increment`, the type of `this` would perhaps be akin to a type parameter constrained to `IB`. In conjunction with that, to avoid boxing in the caller, non-abstract methods would be inherited from interfaces. This may increase compiler and CLR implementation work substantially.\n> 3. Not worry about it and just leave it as a wart.\n> 4. Other ideas?\n\n***Decision:*** Not worry about it and just leave it as a wart. See <https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-19.md#structs-and-default-implementations>.\n\n### Base interface invocations (closed)\n\nThis decision was not implemented in C# 8. The `base(Interface).M()` syntax is not implemented.\n\n<details>\n\nThe draft spec suggests a syntax for base interface invocations inspired by Java: `Interface.base.M()`. We need to select a syntax, at least for the initial prototype. My favorite is `base<Interface>.M()`.\n\n> ***Closed Issue:*** What is the syntax for a base member invocation?\n\n***Decision:*** The syntax is `base(Interface).M()`. See <https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-19.md#base-invocation>. The interface so named must be a base interface, but does not need to be a direct base interface.\n\n> ***Open Issue:*** Should base interface invocations be permitted in class members?\n\n***Decision***: Yes. <https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-19.md#base-invocation>\n\n</details>\n\n### Overriding non-public interface members (closed)\n\nIn an interface, non-public members from base interfaces are overridden using the `override` modifier. If it is an \"explicit\" override that names the interface containing the member, the access modifier is omitted.\n\n> ***Closed Issue:*** If it is an \"implicit\" override that does not name the interface, does the access modifier have to match?\n\n***Decision:*** Only public members may be implicitly overridden, and the access must match. See <https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-18.md#dim-implementing-a-non-public-interface-member-not-in-list>.\n\n> ***Open Issue:*** Is the access modifier required, optional, or omitted on an explicit override such as `override void IB.M() {}`?\n\n> ***Open Issue:*** Is `override` required, optional, or omitted on an explicit override such as `void IB.M() {}`?\n\nHow does one implement a non-public interface member in a class? Perhaps it must be done explicitly?\n\n```csharp\ninterface IA\n{\n    internal void MI();\n    protected void MP();\n}\nclass C : IA\n{\n    // are these implementations?  Decision: NO\n    internal void MI() {}\n    protected void MP() {}\n}\n```\n\n> ***Closed Issue:*** How does one implement a non-public interface member in a class?\n\n***Decision:*** You can only implement non-public interface members explicitly. See <https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-18.md#dim-implementing-a-non-public-interface-member-not-in-list>.\n\n***Decision***: No `override` keyword permitted on interface members. <https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#does-an-override-in-an-interface-introduce-a-new-member>\n\n### Binary Compatibility 2 (closed)\n\nConsider the following code in which each type is in a separate assembly\n\n```csharp\ninterface I1\n{\n    void M() { Impl1 }\n}\ninterface I2 : I1\n{\n    override void M() { Impl2 }\n}\ninterface I3 : I1\n{\n}\nclass C : I2, I3\n{\n}\n```\n\nWe understand that the implementation of `I1.M` in `C` is `I2.M`. What if the assembly containing `I3` is changed as follows and recompiled\n\n```csharp\ninterface I3 : I1\n{\n    override void M() { Impl3 }\n}\n```\n\nbut `C` is not recompiled. What happens when the program is run? An invocation of `(C as I1).M()`\n\n1. Runs `I1.M`\n2. Runs `I2.M`\n3. Runs `I3.M`\n4. Either 2 or 3, deterministically\n5. Throws some kind of runtime exception\n\n***Decision***: Throw an exception (5). See <https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#issues-in-default-interface-methods>.\n\n### Permit `partial` in interface? (closed)\n\nGiven that interfaces may be used in ways analogous to the way abstract classes are used, it may be useful to declare them `partial`. This would be particularly useful in the face of generators.\n\n> ***Proposal:*** Remove the language restriction that interfaces and members of interfaces may not be declared `partial`.\n\n***Decision***: Yes. See <https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#permit-partial-in-interface>.\n\n### `Main` in an interface? (closed)\n\n> ***Open Issue:*** Is a `static Main` method in an interface a candidate to be the program's entry point?\n\n***Decision***: Yes. See <https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#main-in-an-interface>.\n\n### Confirm intent to support public non-virtual methods (closed)\n\nCan we please confirm (or reverse) our decision to permit non-virtual public methods in an interface?\n\n```csharp\ninterface IA\n{\n    public sealed void M() { }\n}\n```\n\n> ***Semi-Closed Issue:*** (2017-04-18) We think it is going to be useful, but will come back to it. This is a mental model tripping block.\n\n***Decision***: Yes. <https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#confirm-that-we-support-public-non-virtual-methods>.\n\n### Does an `override` in an interface introduce a new member? (closed)\n\nThere are a few ways to observe whether an override declaration introduces a new member or not.\n\n```csharp\ninterface IA\n{\n    void M(int x) { }\n}\ninterface IB : IA\n{\n    override void M(int y) { } // 'override' not permitted\n}\ninterface IC : IB\n{\n    static void M2()\n    {\n        M(y: 3); // permitted? Decision: No.\n    }\n    override void IB.M(int z) { } // permitted? What does it override? Decision: No.\n}\n```\n\n> ***Open Issue:*** Does an override declaration in an interface introduce a new member? (closed)\n\nIn a class, an overriding method is \"visible\" in some senses. For example, the names of its parameters take precedence over the names of parameters in the overridden method. It may be possible to duplicate that behavior in interfaces, as there is always a most specific override. But do we want to duplicate that behavior?\n\nAlso, it is possible to \"override\" an override method? [Moot]\n\n***Decision***: No `override` keyword permitted on interface members. <https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#does-an-override-in-an-interface-introduce-a-new-member>.\n\n### Properties with a private accessor (closed)\n\nWe say that private members are not virtual, and the combination of virtual and private is disallowed. But what about a property with a private accessor?\n\n```csharp\ninterface IA\n{\n    public virtual int P\n    {\n        get => 3;\n        private set { }\n    }\n}\n```\n\nIs this allowed? Is the `set` accessor here `virtual` or not? Can it be overridden where it is accessible? Does the following implicitly implement only the `get` accessor?\n\n```csharp\nclass C : IA\n{\n    public int P\n    {\n        get => 4;\n        set { }\n    }\n}\n```\n\nIs the following presumably an error because IA.P.set isn't virtual and also because it isn't accessible?\n\n```csharp\nclass C : IA\n{\n    int IA.P\n    {\n        get => 4;\n        set { } // Decision: Not valid\n    }\n}\n```\n\n***Decision***: The first example looks valid, while the last does not. This is resolved analogously to how it already works in C#. <https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#properties-with-a-private-accessor>\n\n### Base Interface Invocations, round 2 (closed)\n\nThis was not implemented in C# 8.\n\n<details>\n\nOur previous \"resolution\" to how to handle base invocations doesn't actually provide sufficient expressiveness. It turns out that in C# and the CLR, unlike Java, you need to specify both the interface containing the method declaration and the location of the implementation you want to invoke.\n\nI propose the following syntax for base calls in interfaces. I’m not in love with it, but it illustrates what any syntax must be able to express:\n\n```csharp\ninterface I1 { void M(); }\ninterface I2 { void M(); }\ninterface I3 : I1, I2 { void I1.M() { } void I2.M() { } }\ninterface I4 : I1, I2 { void I1.M() { } void I2.M() { } }\ninterface I5 : I3, I4\n{\n    void I1.M()\n    {\n        base<I3>(I1).M(); // calls I3's implementation of I1.M\n        base<I4>(I1).M(); // calls I4's implementation of I1.M\n    }\n    void I2.M()\n    {\n        base<I3>(I2).M(); // calls I3's implementation of I2.M\n        base<I4>(I2).M(); // calls I4's implementation of I2.M\n    }\n}\n```\n\nIf there is no ambiguity, you can write it more simply\n\n```csharp\ninterface I1 { void M(); }\ninterface I3 : I1 { void I1.M() { } }\ninterface I4 : I1 { void I1.M() { } }\ninterface I5 : I3, I4\n{\n    void I1.M()\n    {\n        base<I3>.M(); // calls I3's implementation of I1.M\n        base<I4>.M(); // calls I4's implementation of I1.M\n    }\n}\n```\n\nOr\n\n```csharp\ninterface I1 { void M(); }\ninterface I2 { void M(); }\ninterface I3 : I1, I2 { void I1.M() { } void I2.M() { } }\ninterface I5 : I3\n{\n    void I1.M()\n    {\n        base(I1).M(); // calls I3's implementation of I1.M\n    }\n    void I2.M()\n    {\n        base(I2).M(); // calls I3's implementation of I2.M\n    }\n}\n```\n\nOr\n\n```csharp\ninterface I1 { void M(); }\ninterface I3 : I1 { void I1.M() { } }\ninterface I5 : I3\n{\n    void I1.M()\n    {\n        base.M(); // calls I3's implementation of I1.M\n    }\n}\n```\n\n***Decision***: Decided on `base(N.I1<T>).M(s)`, conceding that if we have an invocation binding there may be problem here later on. <https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-11-14.md#default-interface-implementations>\n\n<details>\n\n### Warning for struct not implementing default method? (closed)\n\n@vancem asserts that we should seriously consider producing a warning if a value type declaration fails to override some interface method, even if it would inherit an implementation of that method from an interface. Because it causes boxing and undermines constrained calls.\n\n***Decision***: This seems like something more suited for an analyzer. It also seems like this warning could be noisy, since it would fire even if the default interface method is never called and no boxing will ever occur. <https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#warning-for-struct-not-implementing-default-method>\n\n### Interface static constructors (closed)\n\nWhen are interface static constructors run?  The current CLI draft proposes that it occurs when the first static method or field is accessed. If there are neither of those then it might never be run??\n\n[2018-10-09 The CLR team proposes \"Going to mirror what we do for valuetypes (cctor check on access to each instance method)\"]\n\n***Decision***: Static constructors are also run on entry to instance methods, if the static constructor was not `beforefieldinit`, in which case static constructors are run before access to the first static field. <https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md#when-are-interface-static-constructors-run>\n\n## Design meetings\n\n[2017-03-08 LDM Meeting Notes](https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-03-08.md)\n[2017-03-21 LDM Meeting Notes](https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-03-21.md)\n[2017-03-23 meeting \"CLR Behavior for Default Interface Methods\"](https://github.com/dotnet/csharplang/blob/master/meetings/2017/CLR-2017-03-23.md)\n[2017-04-05 LDM Meeting Notes](https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-05.md)\n[2017-04-11 LDM Meeting Notes](https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-11.md)\n[2017-04-18 LDM Meeting Notes](https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-18.md)\n[2017-04-19 LDM Meeting Notes](https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-04-19.md)\n[2017-05-17 LDM Meeting Notes](https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-05-17.md)\n[2017-05-31 LDM Meeting Notes](https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-05-31.md)\n[2017-06-14 LDM Meeting Notes](https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-06-14.md)\n[2018-10-17 LDM Meeting Notes](https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md)\n[2018-11-14 LDM Meeting Notes](https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-11-14.md)\n"
  },
  {
    "path": "proposals/csharp-8.0/nested-stackalloc.md",
    "content": "﻿# Permit `stackalloc` in nested contexts\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/1412>\n\n## Stack allocation\n\nWe modify the section *Stack allocation* ([§12.8.22 Stack allocation](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12822-stack-allocation)) of the C# language specification to relax the places when a `stackalloc` expression may appear. We delete\n\n``` antlr\nlocal_variable_initializer_unsafe\n    : stackalloc_initializer\n    ;\n\nstackalloc_initializer\n    : 'stackalloc' unmanaged_type '[' expression ']'\n    ;\n```\n\nand replace them with\n\n``` antlr\nprimary_no_array_creation_expression\n    : stackalloc_initializer\n    ;\n\nstackalloc_initializer\n    : 'stackalloc' unmanaged_type '[' expression? ']' array_initializer?\n    | 'stackalloc' '[' expression? ']' array_initializer\n    ;\n```\n\nNote that the addition of an *array_initializer* to *stackalloc_initializer* (and making the index expression optional) was an extension in C# 7.3 and is not described here.\n\nThe *element type* of the `stackalloc` expression is the *unmanaged_type* named in the stackalloc expression, if any, or the common type among the elements of the *array_initializer* otherwise.\n\nThe type of the *stackalloc_initializer* with *element type* `K` depends on its syntactic context:\n- If the *stackalloc_initializer* appears directly as the *local_variable_initializer* of a *local_variable_declaration* statement or a *for_initializer*, then its type is `K*`.\n- Otherwise its type is `System.Span<K>`.\n\n## Stackalloc Conversion\n\nThe *stackalloc conversion* is a new built-in implicit conversion from expression. When the type of a *stackalloc_initializer* is `K*`, there is an implicit *stackalloc conversion* from the *stackalloc_initializer* to the type `System.Span<K>`.\n"
  },
  {
    "path": "proposals/csharp-8.0/notnull-constraint.md",
    "content": "﻿## Notnull constraint\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/36>\n\nIn C# 8.0, we added a language feature that permits the specification of a new type parameter constraint `notnull`. This is a placeholder for its specification.\n"
  },
  {
    "path": "proposals/csharp-8.0/null-coalescing-assignment.md",
    "content": "# Null coalescing assignment\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/34>\n\n## Summary\n[summary]: #summary\n\nSimplifies a common coding pattern where a variable is assigned a value if it is null.\n\nAs part of this proposal, we will also loosen the type requirements on `??` to allow an expression whose type is an unconstrained type parameter to be used on the left-hand side.\n\n## Motivation\n[motivation]: #motivation\n\nIt is common to see code of the form\n\n```csharp\nif (variable == null)\n{\n    variable = expression;\n}\n```\n\nThis proposal adds a non-overloadable binary operator to the language that performs this function.\n\nThere have been at least eight separate community requests for this feature.\n\n## Detailed design\n[design]: #detailed-design\n\nWe add a new form of assignment operator\n\n``` antlr\nassignment_operator\n    : '??='\n    ;\n```\n\nWhich follows the existing semantic rules for compound assignment operators ([§12.21.4](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12214-compound-assignment)), except that we elide the assignment if the left-hand side is non-null. The rules for this feature are as follows.\n\nGiven `a ??= b`, where `A` is the type of `a`, `B` is the type of `b`, and `A0` is the underlying type of `A` if `A` is a nullable value type:\n\n1. If `A` does not exist or is a non-nullable value type, a compile-time error occurs.\n2. If `B` is not implicitly convertible to `A` or `A0` (if `A0` exists), a compile-time error occurs.\n3. If `A0` exists and `B` is implicitly convertible to `A0`, and `B` is not dynamic, then the type of `a ??= b` is `A0`. `a ??= b` is evaluated at runtime as:\n   ```C#\n   var tmp = a.GetValueOrDefault();\n   if (!a.HasValue) { tmp = b; a = tmp; }\n   tmp\n   ```\n   Except that `a` is only evaluated once.\n4. Otherwise, the type of `a ??= b` is `A`. `a ??= b` is evaluated at runtime as `a ?? (a = b)`, except that `a` is only evaluated once.\n\n\nFor the relaxation of the type requirements of `??`, we update the spec where it currently states that, given `a ?? b`, where `A` is the type of `a`:\n\n> 1. If A exists and is not a nullable type or a reference type, a compile-time error occurs.\n\nWe relax this requirement to:\n\n1. If A exists and is a non-nullable value type, a compile-time error occurs.\n\nThis allows the null coalescing operator to work on unconstrained type parameters, as the unconstrained type parameter `T` exists, is not a nullable type, and is not a reference type.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nAs with any language feature, we must question whether the additional complexity to the language is repaid in the additional clarity offered to the body of C# programs that would benefit from the feature.\n\n## Alternatives\n[alternatives]: #alternatives\n\nThe programmer can write `(x = x ?? y)`, `if (x == null) x = y;`, or `x ?? (x = y)` by hand.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n- [ ] Should we also support `&&=` and `||=` operators?\n\n## Design meetings\n\nNone.\n"
  },
  {
    "path": "proposals/csharp-8.0/nullable-reference-types-specification.md",
    "content": "﻿# Nullable Reference Types Specification\n\n***This is a work in progress - several parts are missing or incomplete. An updated version of this document can be found in the C# 9 folder. ***\n\n## Syntax\n\n### Nullable reference types\n\nNullable reference types have the same syntax `T?` as the short form of nullable value types, but do not have a corresponding long form.\n\nFor the purposes of the specification, the current `nullable_type` production is renamed to `nullable_value_type`, and a `nullable_reference_type` production is added:\n\n```antlr\nreference_type\n    : ...\n    | nullable_reference_type\n    ;\n    \nnullable_reference_type\n    : non_nullable_reference_type '?'\n    ;\n    \nnon_nullable_reference_type\n    : type\n    ;\n```\n\nThe `non_nullable_reference_type` in a `nullable_reference_type` must be a non-nullable reference type (class, interface, delegate or array), or a type parameter that is constrained to be a non-nullable reference type (through the `class` constraint, or a class other than `object`).\n\nNullable reference types cannot occur in the following positions:\n\n- as a base class or interface\n- as the receiver of a `member_access`\n- as the `type` in an `object_creation_expression`\n- as the `delegate_type` in a `delegate_creation_expression`\n- as the `type` in an `is_expression`, a `catch_clause` or a `type_pattern`\n- as the `interface` in a fully qualified interface member name\n\nA warning is given on a `nullable_reference_type` where the nullable annotation context is disabled.\n\n### Nullable class constraint\n\nThe `class` constraint has a nullable counterpart `class?`:\n\n```antlr\nprimary_constraint\n    : ...\n    | 'class' '?'\n    ;\n```\n\n### The null-forgiving operator\n\nThe post-fix `!` operator is called the null-forgiving operator.\n\n```antlr\nprimary_expression\n    : ...\n    | null_forgiving_expression\n    ;\n    \nnull_forgiving_expression\n    : primary_expression '!'\n    ;\n```\n\nThe `primary_expression` must be of a reference type.  \n\nThe postfix `!` operator has no runtime effect - it evaluates to the result of the underlying expression. Its only role is to change the null state of the expression, and to limit warnings given on its use.\n\n### nullable implicitly typed local variables\n\n`var` infers an annotated type for reference types.\nFor instance, in `var s = \"\";` the `var` is inferred as `string?`.\n\n### Nullable compiler directives\n\n`#nullable` directives control the nullable annotation and warning contexts.\n\n```antlr\npp_directive\n    : ...\n    | pp_nullable\n    ;\n    \npp_nullable\n    : whitespace? '#' whitespace? 'nullable' whitespace nullable_action pp_new_line\n    ;\n    \nnullable_action\n    : 'disable'\n    | 'enable'\n    | 'restore'\n    ;\n```\n\n`#pragma warning` directives are expanded to allow changing the nullable warning context, and to allow individual warnings to be enabled on even when they're disabled by default:\n\n```antlr\npragma_warning_body\n    : ...\n    | 'warning' whitespace nullable_action whitespace 'nullable'\n    ;\n\nwarning_action\n    : ...\n    | 'enable'\n    ;\n```\n\nNote that the new form of `pragma_warning_body` uses `nullable_action`, not `warning_action`.\n\n## Nullable contexts\n\nEvery line of source code has a *nullable annotation context* and a *nullable warning context*. These control whether nullable annotations have effect, and whether nullability warnings are given. The annotation context of a given line is either *disabled* or *enabled*. The warning context of a given line is either *disabled* or *enabled*.\n\nBoth contexts can be specified at the project level (outside of C# source code), or anywhere within a source file via `#nullable` pre-processor directives. If no project level settings are provided the default is for both contexts to be *disabled*.\n\nThe `#nullable` directive controls the annotation and warning contexts within the source text, and take precedence over the project-level settings.\n\nA directive sets the context(s) it controls for subsequent lines of code, until another directive overrides it, or until the end of the source file.\n\nThe effect of the directives is as follows:\n\n- `#nullable disable`: Sets the nullable annotation and warning contexts to *disabled*\n- `#nullable enable`: Sets the nullable annotation and warning contexts to *enabled*\n- `#nullable restore`: Restores the nullable annotation and warning contexts to project settings\n- `#nullable disable annotations`: Sets the nullable annotation context to *disabled*\n- `#nullable enable annotations`: Sets the nullable annotation context to *enabled*\n- `#nullable restore annotations`: Restores the nullable annotation context to project settings\n- `#nullable disable warnings`: Sets the nullable warning context to *disabled*\n- `#nullable enable warnings`: Sets the nullable warning context to *enabled*\n- `#nullable restore warnings`: Restores the nullable warning context to project settings\n\n## Nullability of types\n\nA given type can have one of four nullabilities: *Oblivious*, *nonnullable*, *nullable* and *unknown*. \n\n*Nonnullable* and *unknown* types may cause warnings if a potential `null` value is assigned to them. *Oblivious* and *nullable* types, however, are \"*null-assignable*\" and can have `null` values assigned to them without warnings. \n\n*Oblivious* and *nonnullable* types can be dereferenced or assigned without warnings. Values of *nullable* and *unknown* types, however, are \"*null-yielding*\" and may cause warnings when dereferenced or assigned without proper null checking. \n\nThe *default null state* of a null-yielding type is \"maybe null\". The default null state of a non-null-yielding type is \"not null\".\n\nThe kind of type and the nullable annotation context it occurs in determine its nullability:\n\n- A nonnullable value type `S` is always *nonnullable*\n- A nullable value type `S?` is always *nullable*\n- An unannotated reference type `C` in a *disabled* annotation context is *oblivious*\n- An unannotated reference type `C` in an *enabled* annotation context is *nonnullable*\n- A nullable reference type `C?` is *nullable* (but a warning may be yielded in a *disabled* annotation context)\n\nType parameters additionally take their constraints into account:\n\n- A type parameter `T` where all constraints (if any) are either null-yielding types (*nullable* and *unknown*) or the `class?` constraint is *unknown*\n- A type parameter `T` where at least one constraint is either *oblivious* or *nonnullable* or one of the `struct` or `class` constraints is\n    - *oblivious* in a *disabled* annotation context\n    - *nonnullable* in an *enabled* annotation context\n- A nullable type parameter `T?` where at least one of `T`'s constraints is *oblivious* or *nonnullable* or one of the `struct` or `class` constraints, is\n    - *nullable* in a *disabled* annotation context (but a warning is yielded)\n    - *nullable* in an *enabled* annotation context\n\nFor a type parameter `T`, `T?` is only allowed if `T` is known to be a value type or known to be a reference type.\n\n### Nested functions\n\nNested functions (lambdas and local functions) are treated like methods, except in regards to their captured variables.\nThe default state of a captured variable inside a lambda or local function is the intersection of the nullable state\nof the variable at all the \"uses\" of that nested function. A use of a function is either a call to that function, or\nwhere it is converted to a delegate.\n\n### Oblivious vs nonnullable\n\nA `type` is deemed to occur in a given annotation context when the last token of the type is within that context.\n\nWhether a given reference type `C` in source code is interpreted as oblivious or nonnullable depends on the annotation context of that source code. But once established, it is considered part of that type, and \"travels with it\" e.g. during substitution of generic type arguments. It is as if there is an annotation like `?` on the type, but invisible.\n\n## Constraints\n\nNullable reference types can be used as generic constraints. Furthermore `object` is now valid as an explicit constraint. Absence of a constraint is now equivalent to an `object?` constraint (instead of `object`), but (unlike `object` before) `object?` is not prohibited as an explicit constraint.\n\n`class?` is a new constraint denoting \"possibly nullable reference type\", whereas `class` denotes \"nonnullable reference type\".\n\nThe nullability of a type argument or of a constraint does not impact whether the type satisfies the constraint, except where that is already the case today (nullable value types do not satisfy the `struct` constraint). However, if the type argument does not satisfy the nullability requirements of the constraint, a warning may be given.\n\n## Null state and null tracking\n\nEvery expression in a given source location has a *null state*, which indicated whether it is believed to potentially evaluate to null. The null state is either \"not null\" or \"maybe null\". The null state is used to determine whether a warning should be given about null-unsafe conversions and dereferences.\n\n### Null tracking for variables\n\nFor certain expressions denoting variables or properties, the null state is tracked between occurrences, based on assignments to them, tests performed on them and the control flow between them. This is similar to how definite assignment is tracked for variables. The tracked expressions are the ones of the following form:\n\n```antlr\ntracked_expression\n    : simple_name\n    | this\n    | base\n    | tracked_expression '.' identifier\n    ;\n```\n\nWhere the identifiers denote fields or properties.\n\n***Describe null state transitions similar to definite assignment***\n\n### Null state for expressions\n\nThe null state of an expression is derived from its form and type, and from the null state of variables involved in it.\n\n### Literals\n\nThe null state of a `null` literal is \"maybe null\". The null state of a `default` literal that is being converted to a type that is known not to be a nonnullable value type is \"maybe null\". The null state of any other literal is \"not null\".\n\n### Simple names\n\nIf a `simple_name` is not classified as a value, its null state is \"not null\". Otherwise it is a tracked expression, and its null state is its tracked null state at this source location.\n\n### Member access\n\nIf a `member_access` is not classified as a value, its null state is \"not null\". Otherwise, if it is a tracked expression, its null state is its tracked null state at this source location. Otherwise its null state is the default null state of its type.\n\n### Invocation expressions\n\nIf an `invocation_expression` invokes a member that is declared with one or more attributes for special null behavior, the null state is determined by those attributes. Otherwise the null state of the expression is the default null state of its type.\n\n### Element access\n\nIf an `element_access` invokes an indexer that is declared with one or more attributes for special null behavior, the null state is determined by those attributes. Otherwise the null state of the expression is the default null state of its type.\n\n### Base access\n\nIf `B` denotes the base type of the enclosing type, `base.I` has the same null state as `((B)this).I` and `base[E]` has the same null state as `((B)this)[E]`.\n\n### Default expressions\n\n`default(T)` has the null state \"non-null\" if `T` is known to be a nonnullable value type. Otherwise it has the null state \"maybe null\".\n\n### Null-conditional expressions\n\nA `null_conditional_expression` has the null state \"maybe null\".\n\n### Cast expressions\n\nIf a cast expression `(T)E` invokes a user-defined conversion, then the null state of the expression is the default null state for its type. Otherwise, if `T` is null-yielding (*nullable* or *unknown*) then the null state is \"maybe null\". Otherwise the null state is the same as the null state of `E`.\n\n### Await expressions\n\nThe null state of `await E` is the default null state of its type.\n\n### The `as` operator\n\nAn `as` expression has the null state \"maybe null\".\n\n### The null-coalescing operator\n\n`E1 ?? E2` has the same null state as `E2`\n\n### The conditional operator\n\nThe null state of `E1 ? E2 : E3` is \"not null\" if the null state of both `E2` and `E3` are \"not null\". Otherwise it is \"maybe null\".\n\n### Query expressions\n\nThe null state of a query expression is the default null state of its type.\n\n### Assignment operators\n\n`E1 = E2` and `E1 op= E2` have the same null state as `E2` after any implicit conversions have been applied.\n\n### Unary and binary operators\n\nIf a unary or binary operator invokes an user-defined operator that is declared with one or more attributes for special null behavior, the null state is determined by those attributes. Otherwise the null state of the expression is the default null state of its type.\n\n***Something special to do for binary `+` over strings and delegates?***\n\n### Expressions that propagate null state\n\n`(E)`, `checked(E)` and `unchecked(E)` all have the same null state as `E`.\n\n### Expressions that are never null\n\nThe null state of the following expression forms is always \"not null\":\n\n- `this` access\n- interpolated strings\n- `new` expressions (object, delegate, anonymous object and array creation expressions)\n- `typeof` expressions\n- `nameof` expressions\n- anonymous functions (anonymous methods and lambda expressions)\n- null-forgiving expressions\n- `is` expressions\n\n## Type inference\n\n### Type inference for `var`\n\nThe type inferred for local variables declared with `var` is informed by the null state of the initializing expression.\n\n```csharp\nvar x = E;\n```\n\nIf the type of `E` is a nullable reference type `C?` and the null state of `E` is \"not null\" then the type inferred for `x` is `C`. Otherwise, the inferred type is the type of `E`.\n\nThe nullability of the type inferred for `x` is determined as described above, based on the annotation context of the `var`, just as if the type had been given explicitly in that position.\n\n### Type inference for `var?`\n\nThe type inferred for local variables declared with `var?` is independent of the null state of the initializing expression.\n\n```csharp\nvar? x = E;\n```\n\nIf the type `T` of `E` is a nullable value type or a nullable reference type then the type inferred for `x` is `T`. Otherwise, if `T` is a nonnullable value type `S` the type inferred is `S?`. Otherwise, if `T` is a nonnullable reference type `C` the type inferred is `C?`. Otherwise, the declaration is illegal.\n\nThe nullability of the type inferred for `x` is always *nullable*.\n\n### Generic type inference\n\nGeneric type inference is enhanced to help decide whether inferred reference types should be nullable or not. This is a best effort, and does not in and of itself yield warnings, but may lead to nullable warnings when the inferred types of the selected overload are applied to the arguments.\n\nThe type inference does not rely on the annotation context of incoming types. Instead a `type` is inferred which acquires its own annotation context from where it \"would have been\" if it had been expressed explicitly. This underscores the role of type inference as a convenience for what you could have written yourself.\n\nMore precisely, the annotation context for an inferred type argument is the context of the token that would have been followed by the `<...>` type parameter list, had there been one; i.e. the name of the generic method being called. For query expressions that translate to such calls, the context is taken from the initial contextual keyword of the query clause from which the call is generated.\n\n### The first phase\n\nNullable reference types flow into the bounds from the initial expressions, as described below. In addition, two new kinds of bounds, namely `null` and `default` are introduced. Their purpose is to carry through occurrences of `null` or `default` in the input expressions, which may cause an inferred type to be nullable, even when it otherwise wouldn't. This works even for nullable *value* types, which are enhanced to pick up \"nullness\" in the inference process.\n\nThe determination of what bounds to add in the first phase are enhanced as follows:\n\nIf an argument `Ei` has a reference type, the type `U` used for inference depends on the null state of `Ei` as well as its declared type:\n- If the declared type is a nonnullable reference type `U0` or a nullable reference type `U0?` then\n    - if the null state of `Ei` is \"not null\" then `U` is `U0`\n    - if the null state of `Ei` is \"maybe null\" then `U` is `U0?`\n- Otherwise if `Ei` has a declared type, `U` is that type\n- Otherwise if `Ei` is `null` then `U` is the special bound `null`\n- Otherwise if `Ei` is `default` then `U` is the special bound `default`\n- Otherwise no inference is made.\n\n### Exact, upper-bound and lower-bound inferences\n\nIn inferences *from* the type `U` *to* the type `V`, if `V` is a nullable reference type `V0?`, then `V0` is used instead of `V` in the following clauses.\n- If `V` is one of the unfixed type variables, `U` is added as an exact, upper or lower bound as before\n- Otherwise, if `U` is `null` or `default`, no inference is made\n- Otherwise, if `U` is a nullable reference type `U0?`, then `U0` is used instead of `U` in the subsequent clauses.\n\nThe essence is that nullability that pertains directly to one of the unfixed type variables is preserved into its bounds. For the inferences that recurse further into the source and target types, on the other hand, nullability is ignored. It may or may not match, but if it doesn't, a warning will be issued later if the overload is chosen and applied.\n\n### Fixing\n\nThe spec currently does not do a good job of describing what happens when multiple bounds are identity convertible to each other, but are different. This may happen between `object` and `dynamic`, between tuple types that differ only in element names, between types constructed thereof and now also between `C` and `C?` for reference types.\n\nIn addition we need to propagate \"nullness\" from the input expressions to the result type. \n\nTo handle these we add more phases to fixing, which is now:\n\n1. Gather all the types in all the bounds as candidates, removing `?` from all that are nullable reference types\n2. Eliminate candidates based on requirements of exact, lower and upper bounds (keeping `null` and `default` bounds)\n3. Eliminate candidates that do not have an implicit conversion to all the other candidates\n4. If the remaining candidates do not all have identity conversions to one another, then type inference fails\n5. *Merge* the remaining candidates as described below\n6. If the resulting candidate is a reference type or a nonnullable value type and *all* of the exact bounds or *any* of the lower bounds are nullable value types, nullable reference types, `null` or `default`, then `?` is added to the resulting candidate, making it a nullable value type or reference type.\n\n*Merging* is described between two candidate types. It is transitive and commutative, so the candidates can be merged in any order with the same ultimate result. It is undefined if the two candidate types are not identity convertible to each other.\n\nThe *Merge* function takes two candidate types and a direction (*+* or *-*):\n\n- *Merge*(`T`, `T`, *d*) = T\n- *Merge*(`S`, `T?`, *+*) = *Merge*(`S?`, `T`, *+*) = *Merge*(`S`, `T`, *+*)`?`\n- *Merge*(`S`, `T?`, *-*) = *Merge*(`S?`, `T`, *-*) = *Merge*(`S`, `T`, *-*)\n- *Merge*(`C<S1,...,Sn>`, `C<T1,...,Tn>`, *+*) = `C<`*Merge*(`S1`, `T1`, *d1*)`,...,`*Merge*(`Sn`, `Tn`, *dn*)`>`, *where*\n    - `di` = *+* if the `i`'th type parameter of `C<...>` is covariant\n    - `di` = *-* if the `i`'th type parameter of `C<...>` is contra- or invariant\n- *Merge*(`C<S1,...,Sn>`, `C<T1,...,Tn>`, *-*) = `C<`*Merge*(`S1`, `T1`, *d1*)`,...,`*Merge*(`Sn`, `Tn`, *dn*)`>`, *where*\n    - `di` = *-* if the `i`'th type parameter of `C<...>` is covariant\n    - `di` = *+* if the `i`'th type parameter of `C<...>` is contra- or invariant\n- *Merge*(`(S1 s1,..., Sn sn)`, `(T1 t1,..., Tn tn)`, *d*) = `(`*Merge*(`S1`, `T1`, *d*)`n1,...,`*Merge*(`Sn`, `Tn`, *d*) `nn)`, *where*\n    - `ni` is absent if `si` and `ti` differ, or if both are absent\n    - `ni` is `si` if `si` and `ti` are the same\n- *Merge*(`object`, `dynamic`) = *Merge*(`dynamic`, `object`) = `dynamic`\n\n## Warnings\n\n### Potential null assignment\n\n### Potential null dereference\n\n### Constraint nullability mismatch\n\n### Nullable types in disabled annotation context\n\n## Attributes for special null behavior\n\n\n"
  },
  {
    "path": "proposals/csharp-8.0/nullable-reference-types.md",
    "content": "# Nullable reference types in C# #\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/36>\n\nThe goal of this feature is to:\n\n* Allow developers to express whether a variable, parameter or result of a reference type is intended to be null or not.\n* Provide warnings when such variables, parameters and results are not used according to that intent.\n\n## Expression of intent\n\nThe language already contains the `T?` syntax for value types. It is straightforward to extend this syntax to reference types.\n\nIt is assumed that the intent of an unadorned reference type `T` is for it to be non-null.\n\n## Checking of nullable references\n\nA flow analysis tracks nullable reference variables. Where the analysis deems that they would not be null (e.g. after a check or an assignment), their value will be considered a non-null reference.\n\nA nullable reference can also explicitly be treated as non-null with the postfix `x!` operator (the \"damnit\" operator), for when flow analysis cannot establish a non-null situation that the developer knows is there.\n\nOtherwise, a warning is given if a nullable reference is dereferenced, or is converted to a non-null type.\n\nA warning is given when converting from `S[]` to `T?[]` and from `S?[]` to `T[]`.\n\nA warning is given when converting from `C<S>` to `C<T?>` except when the type parameter is covariant (`out`), and when converting from `C<S?>` to `C<T>` except when the type parameter is contravariant (`in`).\n\nA warning is given on `C<T?>` if the type parameter has non-null constraints.\n\n## Checking of non-null references\n\nA warning is given if a null literal is assigned to a non-null variable or passed as a non-null parameter.\n\nA warning is also given if a constructor does not explicitly initialize non-null reference fields.\n\nWe cannot adequately track that all elements of an array of non-null references are initialized. However, we could issue a warning if no element of a newly created array is assigned to before the array is read from or passed on. That might handle the common case without being too noisy.\n\nWe need to decide whether `default(T)` generates a warning, or is simply treated as being of the type `T?`.\n\n## Metadata representation\n\nNullability adornments should be represented in metadata as attributes. This means that downlevel compilers will ignore them.\n\nWe need to decide if only nullable annotations are included, or there's also some indication of whether non-null was \"on\" in the assembly.\n\n## Generics\n\nIf a type parameter `T` has non-nullable constraints, it is treated as non-nullable within its scope.\n\nIf a type parameter is unconstrained or has only nullable constraints, the situation is a little more complex: this means that the corresponding type argument could be *either* nullable or non-nullable. The safe thing to do in that situation is to treat the type parameter as *both* nullable and non-nullable, giving warnings when either is violated. \n\nIt is worth considering whether explicit nullable reference constraints should be allowed. Note, however, that we cannot avoid having nullable reference types *implicitly* be constraints in certain cases (inherited constraints).\n\nThe `class` constraint is non-null. We can consider whether `class?` should be a valid nullable constraint denoting \"nullable reference type\".\n\n## Type inference\n\nIn type inference, if a contributing type is a nullable reference type, the resulting type should be nullable. In other words, nullness is propagated.\n\nWe should consider whether the `null` literal as a participating expression should contribute nullness. It doesn't today: for value types it leads to an error, whereas for reference types the null successfully converts to the plain type.\n\n```csharp\nstring? n = \"world\";\nvar x = b ? \"Hello\" : n; // string?\nvar y = b ? \"Hello\" : null; // string? or error\nvar z = b ? 7 : null; // Error today, could be int?\n```\n\n## Null guard guidance\n\nAs a feature, nullable reference types allow developers to express their intent, and provide warnings through flow analysis if that intent is contradicted. There is a common question as to whether or not null guards are necessary.\n\n### Example of null guard\n\n```csharp\npublic void DoWork(Worker worker)\n{\n    // Guard against worker being null\n    if (worker is null)\n    {\n        throw new ArgumentNullException(nameof(worker));\n    }\n\n    // Otherwise use worker argument\n}\n```\n\nIn the previous example, the `DoWork` function accepts a `Worker` and guards against it potentially being `null`. If the `worker` argument is `null`, the `DoWork` function will `throw`. With nullable reference types, the code in the previous example makes the intent that the `Worker` parameter would *not* be `null`. If the `DoWork` function was a public API, such as a NuGet package or a shared library - as guidance you should leave null guards in place. As a public API, the only guarantee that a caller isn't passing `null` is to guard against it.\n\n### Express intent\n\nA more compelling use of the previous example is to express that the `Worker` parameter could be `null`, thus making the null guard more appropriate. If you remove the null guard in the following example, the compiler warns that you may be dereferencing null. Regardless, both null guards are still valid.\n\n```csharp\npublic void DoWork(Worker? worker)\n{\n    // Guard against worker being null\n    if (worker is null)\n    {\n        throw new ArgumentNullException(nameof(worker));\n    }\n\n    // Otherwise use worker argument\n}\n```\n\nFor non-public APIs, such as source code entirely in control by a developer or dev team - the nullable reference types could allow for the safe removal of null guards where the developers can guarantee it is not necessary. The feature can help with warnings, but it cannot guarantee that at runtime code execution could result in a `NullReferenceException`.\n\n## Breaking changes\n\nNon-null warnings are an obvious breaking change on existing code, and should be accompanied with an opt-in mechanism.\n\nLess obviously, warnings from nullable types (as described above) are a breaking change on existing code in certain scenarios where the nullability is implicit:\n\n* Unconstrained type parameters will be treated as implicitly nullable, so assigning them to `object` or accessing e.g. `ToString` will yield warnings.\n* if type inference infers nullness from `null` expressions, then existing code will sometimes yield nullable rather than non-nullable types, which can lead to new warnings.\n\nSo nullable warnings also need to be optional\n\nFinally, adding annotations to an existing API will be a breaking change to users who have opted in to warnings, when they upgrade the library. This, too, merits the ability to opt in or out. \"I want the bug fixes, but I am not ready to deal with their new annotations\"\n\nIn summary, you need to be able to opt in/out of:\n* Nullable warnings\n* Non-null warnings\n* Warnings from annotations in other files\n\nThe granularity of the opt-in suggests an analyzer-like model, where swaths of code can opt in and out with pragmas and severity levels can be chosen by the user. Additionally, per-library options (\"ignore the annotations from JSON.NET until I'm ready to deal with the fall out\") may be expressible in code as attributes.\n\nThe design of the opt-in/transition experience is crucial to the success and usefulness of this feature. We need to make sure that:\n\n* Users can adopt nullability checking gradually as they want to\n* Library authors can add nullability annotations without fear of breaking customers\n* Despite these, there is not a sense of \"configuration nightmare\"\n\n## Tweaks\n\nWe could consider not using the `?` annotations on locals, but just observing whether they are used in accordance with what gets assigned to them. I don't favor this; I think we should uniformly let people express their intent.\n\nWe could consider a shorthand `T! x` on parameters, that auto-generates a runtime null check.\n\nCertain patterns on generic types, such as `FirstOrDefault` or `TryGet`, have slightly weird behavior with non-nullable type arguments, because they explicitly yield default values in certain situations. We could try to nuance the type system to accommodate these better. For instance, we could allow `?` on unconstrained type parameters, even though the type argument could already be nullable. I doubt that it is worth it, and it leads to weirdness related to interaction with nullable *value* types. \n\n## Nullable value types\n\nWe could consider adopting some of the above semantics for nullable value types as well.\n\nWe already mentioned type inference, where we could infer `int?` from `(7, null)`, instead of just giving an error.\n\nAnother opportunity is to apply the flow analysis to nullable value types. When they are deemed non-null, we could actually allow using as the non-nullable type in certain ways (e.g. member access). We just have to be careful that the things that you can *already* do on a nullable value type will be preferred, for back compat reasons.\n"
  },
  {
    "path": "proposals/csharp-8.0/obsolete-accessor.md",
    "content": "﻿## Obsolete on property accessor\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/2152>\n\nIn C# 8.0, we added support for declaring a property accessor `[Obsolete]`. This is a placeholder for the specification.\n"
  },
  {
    "path": "proposals/csharp-8.0/patterns.md",
    "content": "# Recursive Pattern Matching\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/45>\n\n## Summary\n[summary]: #summary\n\nPattern matching extensions for C# enable many of the benefits of algebraic data types and pattern matching from functional languages, but in a way that smoothly integrates with the feel of the underlying language. Elements of this approach are inspired by related features in the programming languages [F#](https://www.microsoft.com/research/wp-content/uploads/2016/02/p29-syme.pdf \"Extensible Pattern Matching Via a Lightweight Language\") and [Scala](https://link.springer.com/content/pdf/10.1007%2F978-3-540-73589-2.pdf \"Matching Objects With Patterns, page 273\").\n\n## Detailed design\n[design]: #detailed-design\n\n### Is Expression\n\nThe `is` operator is extended to test an expression against a *pattern*.\n\n```antlr\nrelational_expression\n    : is_pattern_expression\n    ;\nis_pattern_expression\n    : relational_expression 'is' pattern\n    ;\n```\n\nThis form of *relational_expression* is in addition to the existing forms in the C# specification. It is a compile-time error if the *relational_expression* to the left of the `is` token does not designate a value or does not have a type.\n\nEvery *identifier* of the pattern introduces a new local variable that is *definitely assigned* after the `is` operator is `true` (i.e. *definitely assigned when true*).\n\n> Note: There is technically an ambiguity between *type* in an `is-expression` and *constant_pattern*, either of which might be a valid parse of a qualified identifier. We try to bind it as a type for compatibility with previous versions of the language; only if that fails do we resolve it as we do an expression in other contexts, to the first thing found (which must be either a constant or a type). This ambiguity is only present on the right-hand-side of an `is` expression.\n\n### Patterns\n\nPatterns are used in the *is_pattern* operator, in a *switch_statement*, and in a *switch_expression* to express the shape of data against which incoming data  (which we call the input value) is to be compared. Patterns may be recursive so that parts of the data may be matched against sub-patterns.\n\n```antlr\npattern\n    : declaration_pattern\n    | constant_pattern\n    | var_pattern\n    | positional_pattern\n    | property_pattern\n    | discard_pattern\n    ;\ndeclaration_pattern\n    : type simple_designation\n    ;\nconstant_pattern\n    : constant_expression\n    ;\nvar_pattern\n    : 'var' designation\n    ;\npositional_pattern\n    : type? '(' subpatterns? ')' property_subpattern? simple_designation?\n    ;\nsubpatterns\n    : subpattern\n    | subpattern ',' subpatterns\n    ;\nsubpattern\n    : pattern\n    | identifier ':' pattern\n    ;\nproperty_subpattern\n    : '{' '}'\n    | '{' subpatterns ','? '}'\n    ;\nproperty_pattern\n    : type? property_subpattern simple_designation?\n    ;\nsimple_designation\n    : single_variable_designation\n    | discard_designation\n    ;\ndiscard_pattern\n    : '_'\n    ;\n```\n\n#### Declaration Pattern\n\n```antlr\ndeclaration_pattern\n    : type simple_designation\n    ;\n```\n\nThe *declaration_pattern* both tests that an expression is of a given type and casts it to that type if the test succeeds. This may introduce a local variable of the given type named by the given identifier, if the designation is a *single_variable_designation*. That local variable is *definitely assigned* when the result of the pattern-matching operation is `true`.\n\nThe runtime semantic of this expression is that it tests the runtime type of the left-hand *relational_expression* operand against the *type* in the pattern.  If it is of that runtime type (or some subtype) and not `null`, the result of the `is operator` is `true`.\n\nCertain combinations of static type of the left-hand-side and the given type are considered incompatible and result in compile-time error. A value of static type `E` is said to be *pattern-compatible* with a type `T` if there exists an identity conversion, an implicit reference conversion, a boxing conversion, an explicit reference conversion, or an unboxing conversion from `E` to `T`, or if one of those types is an open type. It is a compile-time error if an input of type `E` is not *pattern-compatible* with the *type* in a type pattern that it is matched with.\n\nThe type pattern is useful for performing run-time type tests of reference types, and replaces the idiom\n\n```csharp\nvar v = expr as Type;\nif (v != null) { // code using v\n```\n\nWith the slightly more concise\n\n```csharp\nif (expr is Type v) { // code using v\n```\n\nIt is an error if *type* is a nullable value type.\n\nThe type pattern can be used to test values of nullable types: a value of type `Nullable<T>` (or a boxed `T`) matches a type pattern `T2 id` if the value is non-null and the type of `T2` is `T`, or some base type or interface of `T`. For example, in the code fragment\n\n```csharp\nint? x = 3;\nif (x is int v) { // code using v\n```\n\nThe condition of the `if` statement is `true` at runtime and the variable `v` holds the value `3` of type `int` inside the block. After the block the variable `v` is in scope but not definitely assigned.\n\n#### Constant Pattern\n\n```antlr\nconstant_pattern\n    : constant_expression\n    ;\n```\n\nA constant pattern tests the value of an expression against a constant value. The constant may be any constant expression, such as a literal, the name of a declared `const` variable, or an enumeration constant. When the input value is not an open type, the constant expression is implicitly converted to the type of the matched expression; if the type of the input value is not *pattern-compatible* with the type of the constant expression, the pattern-matching operation is an error.\n\nThe pattern *c* is considered matching the converted input value *e* if `object.Equals(c, e)` would return `true`.\n\nWe expect to see `e is null` as the most common way to test for `null` in newly written code, as it cannot invoke a user-defined `operator==`.\n\n#### Var Pattern\n\n```antlr\nvar_pattern\n    : 'var' designation\n    ;\ndesignation\n    : simple_designation\n    | tuple_designation\n    ;\nsimple_designation\n    : single_variable_designation\n    | discard_designation\n    ;\nsingle_variable_designation\n    : identifier\n    ;\ndiscard_designation\n    : _\n    ;\ntuple_designation\n    : '(' designations? ')'\n    ;\ndesignations\n    : designation\n    | designations ',' designation\n    ;\n```\n\nIf the *designation* is a *simple_designation*, an expression *e* matches the pattern. In other words, a match to a *var pattern* always succeeds with a *simple_designation*. If the *simple_designation* is a *single_variable_designation*, the value of *e* is bound to a newly introduced local variable. The type of the local variable is the static type of *e*.\n\nIf the *designation* is a *tuple_designation*, then the pattern is equivalent to a *positional_pattern* of the form `(var` *designation*, ... `)` where the *designation*s are those found within the *tuple_designation*.  For example, the pattern `var (x, (y, z))` is equivalent to `(var x, (var y, var z))`.\n\nIt is an error if the name `var` binds to a type.\n\n#### Discard Pattern\n\n```antlr\ndiscard_pattern\n    : '_'\n    ;\n```\n\nAn expression *e* matches the pattern `_` always. In other words, every expression matches the discard pattern.\n\nA discard pattern may not be used as the pattern of an *is_pattern_expression*.\n\n#### Positional Pattern\n\nA positional pattern checks that the input value is not `null`, invokes an appropriate `Deconstruct` method, and performs further pattern matching on the resulting values.  It also supports a tuple-like pattern syntax (without the type being provided) when the type of the input value is the same as the type containing `Deconstruct`, or if the type of the input value is a tuple type, or if the type of the input value is `object` or `ITuple` and the runtime type of the expression implements `ITuple`.\n\n```antlr\npositional_pattern\n    : type? '(' subpatterns? ')' property_subpattern? simple_designation?\n    ;\nsubpatterns\n    : subpattern\n    | subpattern ',' subpatterns\n    ;\nsubpattern\n    : pattern\n    | identifier ':' pattern\n    ;\n```\n\nIf the *type* is omitted, we take it to be the static type of the input value.\n\nGiven a match of an input value to the pattern *type* `(` *subpattern_list* `)`, a method is selected by searching in *type* for accessible declarations of `Deconstruct` and selecting one among them using the same rules as for the deconstruction declaration.\n\nIt is an error if a *positional_pattern* omits the type, has a single *subpattern* without an *identifier*, has no *property_subpattern* and has no *simple_designation*. This disambiguates between a *constant_pattern* that is parenthesized and a *positional_pattern*.\n\nIn order to extract the values to match against the patterns in the list,\n- If *type* was omitted and the input value's type is a tuple type, then the number of subpatterns is required to be the same as the cardinality of the tuple. Each tuple element is matched against the corresponding *subpattern*, and the match succeeds if all of these succeed. If any *subpattern* has an *identifier*, then that must name a tuple element at the corresponding position in the tuple type.\n- Otherwise, if a suitable `Deconstruct` exists as a member of *type*, it is a compile-time error if the type of the input value is not *pattern-compatible* with *type*. At runtime the input value is tested against *type*. If this fails then the positional pattern match fails. If it succeeds,  the input value is converted to this type and `Deconstruct` is invoked with fresh compiler-generated variables to receive the `out` parameters. Each value that was received is matched against the corresponding *subpattern*, and the match succeeds if all of these succeed. If any *subpattern* has an *identifier*, then that must name a parameter at the corresponding position of `Deconstruct`.\n- Otherwise if *type* was omitted, and the input value is of type `object` or `ITuple` or some type that can be converted to `ITuple` by an implicit reference conversion, and no *identifier* appears among the subpatterns, then we match using `ITuple`.\n- Otherwise the pattern is a compile-time error.\n\nThe order in which subpatterns are matched at runtime is unspecified, and a failed match may not attempt to match all subpatterns.\n\n##### Example\n\nThis example uses many of the features described in this specification\n\n``` c#\n    var newState = (GetState(), action, hasKey) switch {\n        (DoorState.Closed, Action.Open, _) => DoorState.Opened,\n        (DoorState.Opened, Action.Close, _) => DoorState.Closed,\n        (DoorState.Closed, Action.Lock, true) => DoorState.Locked,\n        (DoorState.Locked, Action.Unlock, true) => DoorState.Closed,\n        (var state, _, _) => state };\n```\n\n#### Property Pattern\n\nA property pattern checks that the input value is not `null` and recursively matches values extracted by the use of accessible properties or fields.\n\n```antlr\nproperty_pattern\n    : type? property_subpattern simple_designation?\n    ;\nproperty_subpattern\n    : '{' '}'\n    | '{' subpatterns ','? '}'\n    ;\n```\n\nIt is an error if any _subpattern_ of a _property_pattern_ does not contain an _identifier_ (it must be of the second form, which has an _identifier_).  A trailing comma after the last subpattern is optional.\n\nNote that a null-checking pattern falls out of a trivial property pattern. To check if the string `s` is non-null, you can write any of the following forms\n\n```csharp\nif (s is object o) ... // o is of type object\nif (s is string x) ... // x is of type string\nif (s is {} x) ... // x is of type string\nif (s is {}) ...\n```\n\nGiven a match of an expression *e* to the pattern *type* `{` *property_pattern_list* `}`, it is a compile-time error if the expression *e* is not *pattern-compatible* with the type *T* designated by *type*. If the type is absent, we take it to be the static type of *e*. If the *identifier* is present, it declares a pattern variable of type *type*. Each of the identifiers appearing on the left-hand-side of its *property_pattern_list* must designate an accessible readable property or field of *T*. If the *simple_designation* of the *property_pattern* is present, it defines a pattern variable of type *T*.\n\nAt runtime, the expression is tested against *T*. If this fails then the property pattern match fails and the result is `false`. If it succeeds, then each *property_subpattern* field or property is read and its value matched against its corresponding pattern. The result of the whole match is `false` only if the result of any of these is `false`. The order in which subpatterns are matched is not specified, and a failed match may not match all subpatterns at runtime. If the match succeeds and the *simple_designation* of the *property_pattern* is a *single_variable_designation*, it defines a variable of type *T* that is assigned the matched value.\n\n> Note: The property pattern can be used to pattern-match with anonymous types.\n\n##### Example\n\n```csharp\nif (o is string { Length: 5 } s)\n```\n\n### Switch Expression\n\nA *switch_expression* is added to support `switch`-like semantics for an expression context.\n\nThe C# language syntax is augmented with the following syntactic productions:\n\n```antlr\nmultiplicative_expression\n    : switch_expression\n    | multiplicative_expression '*' switch_expression\n    | multiplicative_expression '/' switch_expression\n    | multiplicative_expression '%' switch_expression\n    ;\nswitch_expression\n    : range_expression 'switch' '{' '}'\n    | range_expression 'switch' '{' switch_expression_arms ','? '}'\n    ;\nswitch_expression_arms\n    : switch_expression_arm\n    | switch_expression_arms ',' switch_expression_arm\n    ;\nswitch_expression_arm\n    : pattern case_guard? '=>' expression\n    ;\ncase_guard\n    : 'when' null_coalescing_expression\n    ;\n```\n\nThe *switch_expression* is not permitted as an *expression_statement*.\n\n> We are looking at relaxing this in a future revision.\n\nThe type of the *switch_expression* is the *best common type* ([§12.6.3.15](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#126315-finding-the-best-common-type-of-a-set-of-expressions)) of the expressions appearing to the right of the `=>` tokens of the *switch_expression_arm*s if such a type exists and the expression in every arm of the switch expression can be implicitly converted to that type.  In addition, we add a new *switch expression conversion*, which is a predefined implicit conversion from a switch expression to every type `T` for which there exists an implicit conversion from each arm's expression to `T`.\n\nIt is an error if some *switch_expression_arm*'s pattern cannot affect the result because some previous pattern and guard will always match.\n\nA switch expression is said to be *exhaustive* if some arm of the switch expression handles every value of its input.  The compiler shall produce a warning if a switch expression is not *exhaustive*.\n\nAt runtime, the result of the *switch_expression* is the value of the *expression* of the first *switch_expression_arm* for which the expression on the left-hand-side of the *switch_expression* matches the *switch_expression_arm*'s pattern, and for which the *case_guard* of the *switch_expression_arm*, if present, evaluates to `true`. If there is no such *switch_expression_arm*, the *switch_expression* throws an instance of the exception `System.Runtime.CompilerServices.SwitchExpressionException`.\n\n### Optional parens when switching on a tuple literal\n\nIn order to switch on a tuple literal using the *switch_statement*, you have to write what appear to be redundant parens\n\n```csharp\nswitch ((a, b))\n{\n```\n\nTo permit\n\n```csharp\nswitch (a, b)\n{\n```\n\nthe parentheses of the switch statement are optional when the expression being switched on is a tuple literal.\n\n### Order of evaluation in pattern-matching\n\nGiving the compiler flexibility in reordering the operations executed during pattern-matching can permit flexibility that can be used to improve the efficiency of pattern-matching. The (unenforced) requirement would be that properties accessed in a pattern, and the Deconstruct methods, are required to be \"pure\" (side-effect free, idempotent, etc). That doesn't mean that we would add purity as a language concept, only that we would allow the compiler flexibility in reordering operations.\n\n**Resolution 2018-04-04 LDM**: confirmed: the compiler is permitted to reorder calls to `Deconstruct`, property accesses, and invocations of methods in `ITuple`, and may assume that returned values are the same from multiple calls. The compiler should not invoke functions that cannot affect the result, and we will be very careful before making any changes to the compiler-generated order of evaluation in the future.\n\n### Some Possible Optimizations\n\nThe compilation of pattern matching can take advantage of common parts of patterns. For example, if the top-level type test of two successive patterns in a *switch_statement* is the same type, the generated code can skip the type test for the second pattern.\n\nWhen some of the patterns are integers or strings, the compiler can generate the same kind of code it generates for a switch-statement in earlier versions of the language.\n\nFor more on these kinds of optimizations, see [[Scott and Ramsey (2000)]](https://www.cs.tufts.edu/~nr/cs257/archive/norman-ramsey/match.pdf \"When Do Match-Compilation Heuristics Matter?\").\n"
  },
  {
    "path": "proposals/csharp-8.0/ranges.cs",
    "content": "namespace System\n{\n    public readonly struct Index\n    {\n        private readonly int _value;\n\n        public int Value => _value < 0 ? ~_value : _value;\n        public bool FromEnd => _value < 0;\n\n        public Index(int value, bool fromEnd)\n        {\n            if (value < 0) throw new ArgumentException(\"Index must not be negative.\", nameof(value));\n\n            _value = fromEnd ? ~value : value;\n        }\n\n        public static implicit operator Index(int value)\n            => new Index(value, fromEnd: false);\n    }\n\n    public readonly struct Range\n    {\n        public Index Start { get; }\n        public Index End { get; }\n\n        private Range(Index start, Index end)\n        {\n            this.Start = start;\n            this.End = end;\n        }\n\n        public static Range Create(Index start, Index end) => new Range(start, end);\n        public static Range FromStart(Index start) => new Range(start, new Index(0, fromEnd: true));\n        public static Range ToEnd(Index end) => new Range(new Index(0, fromEnd: false), end);\n        public static Range All() => new Range(new Index(0, fromEnd: false), new Index(0, fromEnd: true));\n    }\n\n    static class Extensions\n    {\n        public static int get_IndexerExtension(this int[] array, Index index) =>\n            index.FromEnd ? array[array.Length - index.Value] : array[index.Value];\n\n        public static int get_IndexerExtension(this Span<int> span, Index index) =>\n            index.FromEnd ? span[span.Length - index.Value] : span[index.Value];\n\n        public static char get_IndexerExtension(this string s, Index index) =>\n            index.FromEnd ? s[s.Length - index.Value] : s[index.Value];\n\n        public static Span<int> get_IndexerExtension(this int[] array, Range range) =>\n            array.Slice(range);\n\n        public static Span<int> get_IndexerExtension(this Span<int> span, Range range) =>\n            span.Slice(range);\n\n        public static string get_IndexerExtension(this string s, Range range) =>\n            s.Substring(range);\n\n        public static Span<T> Slice<T>(this T[] array, Range range)\n            => array.AsSpan().Slice(range);\n\n        public static Span<T> Slice<T>(this Span<T> span, Range range)\n        {\n            var (start, length) = GetStartAndLength(range, span.Length);\n            return span.Slice(start, length);\n        }\n\n        public static string Substring(this string s, Range range)\n        {\n            var (start, length) = GetStartAndLength(range, s.Length);\n            return s.Substring(start, length);\n        }\n\n        private static (int start, int length) GetStartAndLength(Range range, int entityLength)\n        {\n            var start = range.Start.FromEnd ? entityLength - range.Start.Value : range.Start.Value;\n            var end = range.End.FromEnd ? entityLength - range.End.Value : range.End.Value;\n            var length = end - start;\n\n            return (start, length);\n        }\n    }\n}\n"
  },
  {
    "path": "proposals/csharp-8.0/ranges.md",
    "content": "# Ranges\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/185>\n\n## Summary\n\nThis feature is about delivering two new operators that allow constructing `System.Index` and `System.Range` objects, and using them to index/slice collections at runtime.\n\n## Overview\n\n### Well-known types and members\n\nTo use the new syntactic forms for `System.Index` and `System.Range`, new well-known\ntypes and members may be necessary, depending on which syntactic forms are used.\n\nTo use the \"hat\" operator (`^`), the following is required\n\n```csharp\nnamespace System\n{\n    public readonly struct Index\n    {\n        public Index(int value, bool fromEnd);\n    }\n}\n```\n\nTo use the `System.Index` type as an argument in an array element access, the following\nmember is required:\n\n```csharp\nint System.Index.GetOffset(int length);\n```\n\nThe `..` syntax for `System.Range` will require the `System.Range` type, as well as one\nor more of the following members:\n\n```csharp\nnamespace System\n{\n    public readonly struct Range\n    {\n        public Range(System.Index start, System.Index end);\n        public static Range StartAt(System.Index start);\n        public static Range EndAt(System.Index end);\n        public static Range All { get; }\n    }\n}\n```\n\nThe `..` syntax allows for either, both, or none of its arguments to be absent. Regardless\nof the number of arguments, the `Range` constructor is always sufficient for using the\n`Range` syntax. However, if any of the other members are present and one or more of the\n`..` arguments are missing, the appropriate member may be substituted.\n\nFinally, for a value of type `System.Range` to be used in an array element access expression,\nthe following member must be present:\n\n```csharp\nnamespace System.Runtime.CompilerServices\n{\n    public static class RuntimeHelpers\n    {\n        public static T[] GetSubArray<T>(T[] array, System.Range range);\n    }\n}\n```\n\n### System.Index\n\nC# has no way of indexing a collection from the end, but rather most indexers use the \"from start\" notion, or do a \"length - i\" expression. We introduce a new Index expression that means \"from the end\". The feature will introduce a new unary prefix \"hat\" operator. Its single operand must be convertible to `System.Int32`. It will be lowered into the appropriate `System.Index` factory method call.\n\nWe augment the grammar for *unary_expression* with the following additional syntax form:\n\n```antlr\nunary_expression\n    : '^' unary_expression\n    ;\n```\n\nWe call this the *index from end* operator. The predefined *index from end* operators are as follows:\n\n```csharp\nSystem.Index operator ^(int fromEnd);\n```\n\nThe behavior of this operator is only defined for input values greater than or equal to zero.\n\nExamples:\n\n```csharp\nvar array = new int[] { 1, 2, 3, 4, 5 };\nvar thirdItem = array[2];    // array[2]\nvar lastItem = array[^1];    // array[new Index(1, fromEnd: true)]\n```\n\n#### System.Range\n\nC# has no syntactic way to access \"ranges\" or \"slices\" of collections. Usually users are forced to implement complex structures to filter/operate on slices of memory, or resort to LINQ methods like `list.Skip(5).Take(2)`. With the addition of `System.Span<T>` and other similar types, it becomes more important to have this kind of operation supported on a deeper level in the language/runtime, and have the interface unified.\n\nThe language will introduce a new range operator `x..y`. It is a binary infix operator that accepts two expressions. Either operand can be omitted (examples below), and they have to be convertible to `System.Index`. It will be lowered to the appropriate `System.Range` factory method call.\n\nWe replace the C# grammar rules for *multiplicative_expression* with the following (in order to introduce a new precedence level):\n\n```antlr\nrange_expression\n    : unary_expression\n    | range_expression? '..' range_expression?\n    ;\n\nmultiplicative_expression\n    : range_expression\n    | multiplicative_expression '*' range_expression\n    | multiplicative_expression '/' range_expression\n    | multiplicative_expression '%' range_expression\n    ;\n```\n\nAll forms of the *range operator* have the same precedence. This new precedence group is lower than the *unary operators* and higher than the *multiplicative arithmetic operators*.\n\nWe call the `..` operator the *range operator*. The built-in range operator can roughly be understood to correspond to the invocation of a built-in operator of this form:\n\n```csharp\nSystem.Range operator ..(Index start = 0, Index end = ^0);\n```\n\nExamples:\n\n```csharp\nvar array = new int[] { 1, 2, 3, 4, 5 };\nvar slice1 = array[2..^3];    // array[new Range(2, new Index(3, fromEnd: true))]\nvar slice2 = array[..^3];     // array[Range.EndAt(new Index(3, fromEnd: true))]\nvar slice3 = array[2..];      // array[Range.StartAt(2)]\nvar slice4 = array[..];       // array[Range.All]\n```\n\nMoreover, `System.Index` should have an implicit conversion from `System.Int32`, in order to avoid the need to overload mixing integers and indexes over multi-dimensional signatures.\n\n## Adding Index and Range support to existing library types\n\n### Implicit Index support\n\nThe language will provide an instance indexer member with a single parameter of type `Index` for types which meet the following criteria:\n\n- The type is Countable.\n- The type has an accessible instance indexer which takes a single `int` as the argument.\n- The type does not have an accessible instance indexer which takes an `Index` as the first parameter. The `Index` must be the only parameter or the remaining parameters must be optional.\n\nA type is ***Countable*** if it  has a property named `Length` or `Count` with an accessible getter and a return type of `int`. The language can make use of this property to convert an expression of type `Index` into an `int` at the point of the expression without the need to use the type `Index` at all. In case both `Length` and `Count`\nare present, `Length` will be preferred. For simplicity going forward, the proposal will use the name `Length` to represent `Count` or `Length`.\n\nFor such types, the language will act as if there is an indexer member of the form `T this[Index index]` where `T` is the return type of the `int` based indexer including any `ref` style annotations. The new member will have the same `get` and `set` members with matching accessibility as the `int` indexer.\n\nThe new indexer will be implemented by converting the argument of type `Index` into an `int` and emitting a call to the `int` based indexer. For discussion purposes, let's use the example of `receiver[expr]`. The conversion of `expr` to `int` will occur as follows:\n\n- When the argument is of the form `^expr2` and the type of `expr2` is `int`, it will be translated to `receiver.Length - expr2`.\n- Otherwise, it will be translated as `expr.GetOffset(receiver.Length)`.\n\nRegardless of the specific conversion strategy, the order of evaluation should be equivalent to the following:\n1. `receiver` is evaluated;\n2. `expr` is evaluated;\n3. `length` is evaluated, if needed;\n4. the `int` based indexer is invoked. \n\nThis allows for developers to use the `Index` feature on existing types without the need for modification. For example:\n\n``` csharp\nList<char> list = ...;\nvar value = list[^1];\n\n// Gets translated to\nvar value = list[list.Count - 1];\n```\n\nThe `receiver` and `Length` expressions will be spilled as appropriate to ensure any side effects are only executed once. For example:\n\n``` csharp\nclass Collection {\n    private int[] _array = new[] { 1, 2, 3 };\n\n    public int Length {\n        get {\n            Console.Write(\"Length \");\n            return _array.Length;\n        }\n    }\n\n    public int this[int index] => _array[index];\n}\n\nclass SideEffect {\n    Collection Get() {\n        Console.Write(\"Get \");\n        return new Collection();\n    }\n\n    void Use() {\n        int i = Get()[^1];\n        Console.WriteLine(i);\n    }\n}\n```\n\nThis code will print \"Get Length 3\".\n\n### Implicit Range support\n\nThe language will provide an instance indexer member with a single parameter of type `Range` for types which meet the following criteria:\n\n- The type is Countable.\n- The type has an accessible member named `Slice` which has two parameters of type `int`.\n- The type does not have an instance indexer which takes a single `Range` as the first parameter. The `Range` must be the only parameter or the remaining parameters must be optional.\n\nFor such types, the language will bind as if there is an indexer member of the form `T this[Range range]` where `T` is the return type of the `Slice` method including any `ref` style annotations. The new member will also have matching accessibility with `Slice`.\n\nWhen the `Range` based indexer is bound on an expression named `receiver`, it will be lowered by converting the `Range` expression into two values that are then passed to the `Slice` method. For discussion purposes, let's use the example of `receiver[expr]`.\n\nThe first argument of `Slice` will be obtained by converting the range typed expression in the following way:\n\n- When `expr` is of the form `expr1..expr2` (where `expr2` can be omitted) and `expr1` has type `int`, then it will be emitted as `expr1`.\n- When `expr` is of the form `^expr1..expr2` (where `expr2` can be omitted), then it will be emitted as `receiver.Length - expr1`.\n- When `expr` is of the form `..expr2` (where `expr2` can be omitted), then it will be emitted as `0`.\n- Otherwise, it will be emitted as `expr.Start.GetOffset(receiver.Length)`.\n\nThis value will be re-used in the calculation of the second `Slice` argument. When doing so it will be referred to as `start`. The second argument of `Slice` will be obtained by converting the range typed expression in the following way:\n\n- When `expr` is of the form `expr1..expr2` (where `expr1` can be omitted) and `expr2` has type `int`, then it will be emitted as `expr2 - start`.\n- When `expr` is of the form `expr1..^expr2` (where `expr1` can be omitted), then it will be emitted as `(receiver.Length - expr2) - start`.\n- When `expr` is of the form `expr1..` (where `expr1` can be omitted), then it will be emitted as `receiver.Length - start`.\n- Otherwise, it will be emitted as `expr.End.GetOffset(receiver.Length) - start`.\n\nRegardless of the specific conversion strategy, the order of evaluation should be equivalent to the following:\n1. `receiver` is evaluated;\n2. `expr` is evaluated;\n3. `length` is evaluated, if needed;\n4. the `Slice` method is invoked. \n\nThe `receiver`, `expr`, and `length` expressions will be spilled as appropriate to ensure any side effects are only executed once. For example:\n\n``` csharp\nclass Collection {\n    private int[] _array = new[] { 1, 2, 3 };\n\n    public int Length {\n        get {\n            Console.Write(\"Length \");\n            return _array.Length;\n        }\n    }\n\n    public int[] Slice(int start, int length) {\n        var slice = new int[length];\n        Array.Copy(_array, start, slice, 0, length);\n        return slice;\n    }\n}\n\nclass SideEffect {\n    Collection Get() {\n        Console.Write(\"Get \");\n        return new Collection();\n    }\n\n    void Use() {\n        var array = Get()[0..2];\n        Console.WriteLine(array.Length);\n    }\n}\n```\n\nThis code will print \"Get Length 2\".\n\nThe language will special case the following known types:\n\n- `string`: the method `Substring` will be used instead of `Slice`.\n- `array`: the method `System.Runtime.CompilerServices.RuntimeHelpers.GetSubArray` will be used instead of `Slice`.\n\n## Alternatives\n\nThe new operators (`^` and `..`) are syntactic sugar. The functionality can be implemented by explicit calls to `System.Index` and `System.Range` factory methods, but it will result in a lot more boilerplate code, and the experience will be unintuitive.\n\n## IL Representation\n\nThese two operators will be lowered to regular indexer/method calls, with no change in subsequent compiler layers.\n\n## Runtime behavior\n\n- Compiler can optimize indexers for built-in types like arrays and strings, and lower the indexing to the appropriate existing methods.\n- `System.Index` will throw if constructed with a negative value.\n- `^0` does not throw, but it translates to the length of the collection/enumerable it is supplied to.\n- `Range.All` is semantically equivalent to `0..^0`, and can be deconstructed to these indices.\n\n## Considerations\n\n### Detect Indexable based on ICollection\n\nThe inspiration for this behavior was collection initializers. Using the structure of a type to convey that it had opted into a feature. In the case of collection initializers types can opt into the feature by implementing the interface `IEnumerable` (non generic).\n\nThis proposal initially required that types implement `ICollection` in order to qualify as Indexable. That required a number of special cases though:\n\n- `ref struct`: these cannot implement interfaces yet types like `Span<T>` are ideal for index / range support.\n- `string`: does not implement `ICollection` and adding that interface has a large cost.\n\nThis means to support key types special casing is already needed. The special casing of `string` is less interesting as the language does this in other areas (`foreach` lowering, constants, etc ...). The special casing of `ref struct` is more concerning as it's special casing an entire class of types. They get labeled as Indexable if they simply have a property named `Count` with a return type of `int`.\n\nAfter consideration the design was normalized to say that any type which has a property `Count` / `Length` with a return type of `int` is Indexable. That removes all special casing, even for `string` and arrays.\n\n### Detect just Count\n\nDetecting on the property names `Count` or `Length` does complicate the design a bit. Picking just one to standardize though is not sufficient as it ends up excluding a large number of types:\n\n- Use `Length`: excludes pretty much every collection in System.Collections and sub-namespaces. Those tend to derive from `ICollection` and hence prefer `Count` over length.\n- Use `Count`: excludes `string`, arrays, `Span<T>` and most `ref struct` based types\n\nThe extra complication on the initial detection of Indexable types is outweighed by its simplification in other aspects.\n\n### Choice of Slice as a name\n\nThe name `Slice` was chosen as it's the de-facto standard name for slice style operations in .NET. Starting with netcoreapp2.1 all span style types use the name `Slice` for slicing operations. Prior to netcoreapp2.1 there really aren't any examples of slicing to look to for an example. Types like `List<T>`, `ArraySegment<T>`, `SortedList<T>` would've been ideal for slicing but the concept didn't exist when types were added.\n\nThus, `Slice` being the sole example, it was chosen as the name.\n\n### Index target type conversion\n\nAnother way to view the `Index` transformation in an indexer expression is as a target type conversion. Instead of binding as if there is a member of the form `return_type this[Index]`, the language instead assigns a target typed conversion to `int`.\n\nThis concept could be generalized to all member access on Countable types. Whenever an expression with type `Index` is used as an argument to an instance member invocation and the receiver is Countable then the expression will have a target type conversion to `int`. The member invocations applicable for this conversion include methods, indexers, properties, extension methods, etc ... Only constructors are excluded as they have no receiver.\n\nThe target type conversion will be implemented as follows for any expression which has a type of `Index`. For discussion purposes lets use the example of `receiver[expr]`:\n\n- When `expr` is of the form `^expr2` and the type of `expr2` is `int`, it will be translated to `receiver.Length - expr2`.\n- Otherwise, it will be translated as `expr.GetOffset(receiver.Length)`.\n\nThe `receiver` and `Length` expressions will be spilled as appropriate to ensure any side effects are only executed once. For example:\n\n``` csharp\nclass Collection {\n    private int[] _array = new[] { 1, 2, 3 };\n\n    public int Length {\n        get {\n            Console.Write(\"Length \");\n            return _array.Length;\n        }\n    }\n\n    public int GetAt(int index) => _array[index];\n}\n\nclass SideEffect {\n    Collection Get() {\n        Console.Write(\"Get \");\n        return new Collection();\n    }\n\n    void Use() {\n        int i = Get().GetAt(^1);\n        Console.WriteLine(i);\n    }\n}\n```\n\nThis code will print \"Get Length 3\".\n\nThis feature would be beneficial to any member which had a parameter that represented an index. For example `List<T>.InsertAt`. This also has the potential for confusion as the language can't give any guidance as to whether or not an expression is meant for indexing. All it can do is convert any `Index` expression to `int` when invoking a member on a Countable type.\n\nRestrictions:\n\n- This conversion is only applicable when the expression with type `Index` is directly an argument to the member. It would not apply to any nested expressions.\n\n## Decisions made during implementation\n\n- All members in the pattern must be instance members\n- If a Length method is found but it has the wrong return type, continue looking for Count\n- The indexer used for the Index pattern must have exactly one int parameter\n- The `Slice` method used for the Range pattern must have exactly two int parameters\n- When looking for the pattern members, we look for original definitions, not constructed members\n\n## Design meetings\n\n- [Jan 10, 2018](https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-01-10.md)\n- [Jan 18, 2018](https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-01-18.md)\n- [Jan 22, 2018](https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-01-22.md)\n- [Dec 3, 2018](https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-12-03.md)\n- [Mar 25, 2019](https://github.com/dotnet/csharplang/blob/master/meetings/2019/LDM-2019-03-25.md#pattern-based-indexing-with-index-and-range)\n- [April 1st, 2019](https://github.com/dotnet/csharplang/blob/master/meetings/2019/LDM-2019-04-01.md)\n- [April 15, 2019](https://github.com/dotnet/csharplang/blob/master/meetings/2019/LDM-2019-04-15.md#follow-up-decisions-for-pattern-based-indexrange)\n"
  },
  {
    "path": "proposals/csharp-8.0/readonly-instance-members.md",
    "content": "# Readonly Instance Members\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <<https://github.com/dotnet/csharplang/issues/1710>>\n\n## Summary\n[summary]: #summary\n\nProvide a way to specify individual instance members on a struct do not modify state, in the same way that `readonly struct` specifies no instance members modify state.\n\nIt is worth noting that *readonly instance member* != *pure instance member*. A *pure* instance member guarantees no state will be modified. A `readonly` instance member only guarantees that instance state will not be modified.\n\nAll instance members on a `readonly struct` could be considered implicitly *readonly instance members* Explicit *readonly instance members* declared on non-readonly structs would behave in the same manner. For example, they would still create hidden copies if you called an instance member (on the current instance or on a field of the instance) which was itself not-readonly.\n\n## Motivation\n[motivation]: #motivation\n\nBefore C# 8.0, users have the ability to create `readonly struct` types which the compiler enforces that all fields are readonly (and by extension, that no instance members modify the state). However, there are some scenarios where you have an existing API that exposes accessible fields or that has a mix of mutating and non-mutating members. Under these circumstances, you cannot mark the type as `readonly` (it would be a breaking change).\n\nThis normally doesn't have much impact, except in the case of `in` parameters. With `in` parameters for non-readonly structs, the compiler will make a copy of the parameter for each instance member invocation, since it cannot guarantee that the invocation does not modify internal state. This can lead to a multitude of copies and worse overall performance than if you had just passed the struct directly by value. For an example, see this code on [sharplab](https://sharplab.io/#v2:CYLg1APgAgDABFAjAbgLACgNQMxwM4AuATgK4DGBcAagKYUD2RATBgN4ZycK4BmANvQCGlAB5p0XbnH5DKAT3GSOXHNIHC4AGRoA7AOYEAFgGUAjiUFEawZZ3YTJXPTQK3H9x54QB2OAAoROAAqOBEASjgwNy8YvzlguDkwxS8AXzd09EysXCgmOABhOA8VXnVKAFk/AEsdajoCRnyAN0E+EhoIks8oX1b2mgA6bX0jMwsrYEi4fo7h3QMTc0trFM5M1KA==)\n\nSome other scenarios where hidden copies can occur include *`static readonly` fields* and *literals*. If they are supported in the future, *blittable constants* would end up in the same boat; that is they all currently necessitate a full copy (on instance member invocation) if the struct is not marked `readonly`.\n\n## Design\n[design]: #design\n\nAllow a user to specify that an instance member is, itself, `readonly` and does not modify the state of the instance (with all the appropriate verification done by the compiler, of course). For example:\n\n```csharp\npublic struct Vector2\n{\n    public float x;\n    public float y;\n\n    public readonly float GetLengthReadonly()\n    {\n        return MathF.Sqrt(LengthSquared);\n    }\n\n    public float GetLength()\n    {\n        return MathF.Sqrt(LengthSquared);\n    }\n\n    public readonly float GetLengthIllegal()\n    {\n        var tmp = MathF.Sqrt(LengthSquared);\n\n        x = tmp;    // Compiler error, cannot write x\n        y = tmp;    // Compiler error, cannot write y\n\n        return tmp;\n    }\n\n    public readonly float LengthSquared\n    {\n        get\n        {\n            return (x * x) +\n                   (y * y);\n        }\n    }\n}\n\npublic static class MyClass\n{\n    public static float ExistingBehavior(in Vector2 vector)\n    {\n        // This code causes a hidden copy, the compiler effectively emits:\n        //    var tmpVector = vector;\n        //    return tmpVector.GetLength();\n        //\n        // This is done because the compiler doesn't know that `GetLength()`\n        // won't mutate `vector`.\n\n        return vector.GetLength();\n    }\n\n    public static float ReadonlyBehavior(in Vector2 vector)\n    {\n        // This code is emitted exactly as listed. There are no hidden\n        // copies as the `readonly` modifier indicates that the method\n        // won't mutate `vector`.\n\n        return vector.GetLengthReadonly();\n    }\n}\n```\n\nReadonly can be applied to property accessors to indicate that `this` will not be mutated in the accessor. The following examples have readonly setters because those accessors modify the state of member field, but do not modify the value of that member field.\n\n```csharp\npublic readonly int Prop1\n{\n    get\n    {\n        return this._store[\"Prop1\"];\n    }\n    set\n    {\n        this._store[\"Prop1\"] = value;\n    }\n}\n```\n\nWhen `readonly` is applied to the property syntax, it means that all accessors are `readonly`.\n\n```csharp\npublic readonly int Prop2\n{\n    get\n    {\n        return this._store[\"Prop2\"];\n    }\n    set\n    {\n        this._store[\"Prop2\"] = value;\n    }\n}\n```\n\nReadonly can only be applied to accessors which do not mutate the containing type.\n\n```csharp\npublic int Prop3\n{\n    readonly get\n    {\n        return this._prop3;\n    }\n    set\n    {\n        this._prop3 = value;\n    }\n}\n```\n\nReadonly can be applied to some auto-implemented properties, but it won't have a meaningful effect. The compiler will treat all auto-implemented getters as readonly whether or not the `readonly` keyword is present.\n\n```csharp\n// Allowed\npublic readonly int Prop4 { get; }\npublic int Prop5 { readonly get; set; }\n\n// Not allowed\npublic int Prop6 { readonly get; }\npublic readonly int Prop7 { get; set; }\npublic int Prop8 { get; readonly set; }\n```\n\nReadonly can be applied to manually-implemented events, but not field-like events. Readonly cannot be applied to individual event accessors (add/remove).\n\n```csharp\n// Allowed\npublic readonly event Action<EventArgs> Event1\n{\n    add { }\n    remove { }\n}\n\n// Not allowed\npublic readonly event Action<EventArgs> Event2;\npublic event Action<EventArgs> Event3\n{\n    readonly add { }\n    readonly remove { }\n}\npublic static readonly event Event4\n{\n    add { }\n    remove { }\n}\n```\n\nSome other syntax examples:\n\n* Expression bodied members: `public readonly float ExpressionBodiedMember => (x * x) + (y * y);`\n* Generic constraints: `public readonly void GenericMethod<T>(T value) where T : struct { }`\n\nThe compiler would emit the instance member, as usual, and would additionally emit a compiler recognized attribute indicating that the instance member does not modify state. This effectively causes the hidden `this` parameter to become `in T` instead of `ref T`.\n\nThis would allow the user to safely call said instance method without the compiler needing to make a copy.\n\nThe restrictions would include:\n\n* The `readonly` modifier cannot be applied to static methods, constructors or destructors.\n* The `readonly` modifier cannot be applied to delegates.\n* The `readonly` modifier cannot be applied to members of class or interface.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nSame drawbacks as exist with `readonly struct` methods today. Certain code may still cause hidden copies.\n\n## Notes\n[notes]: #notes\n\nUsing an attribute or another keyword may also be possible.\n\nThis proposal is somewhat related to (but is more a subset of) `functional purity` and/or `constant expressions`, both of which have had some existing proposals.\n"
  },
  {
    "path": "proposals/csharp-8.0/shadowing-in-nested-functions.md",
    "content": "﻿# Name shadowing in nested functions\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/2777>\n\n## Summary\n\nPermit variable names in lambdas and local functions to reuse (and shadow) names from the enclosing method or function.\n\n## Detailed design\n\nWith `-langversion:8`, names of locals, local functions, parameters, type parameters, and range variables within a lambda or local function can reuse names of locals, local functions, parameters, type parameters, and range variables from an enclosing method or function. The name in the nested function hides the symbol of the same name from the enclosing function within the nested function.\n\nShadowing is supported for `static` and non-`static` local functions and lambdas.\n\nThere is no change in behavior using `-langversion:7.3` or earlier: names in nested functions that shadow names from the enclosing method or function are reported as errors in those cases.\n\nAny shadowing previously permitted is still supported with `-langversion:8`. For instance: variable names may shadow type and member names; and variable names may shadow enclosing method or local function names.\n\nShadowing a name declared in an enclosing scope in the same lambda or local function is still reported as an error.\n\nA warning is reported for a type parameter in a local function that shadows a type parameter in the enclosing type, method, or function.\n\n## Design meetings\n\n- https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-09-10.md#static-local-functions\n- https://github.com/dotnet/csharplang/blob/master/meetings/2019/LDM-2019-01-16.md#shadowing-in-nested-functions\n"
  },
  {
    "path": "proposals/csharp-8.0/static-local-functions.md",
    "content": "# Static local functions\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/1565>\n\n## Summary\n\nSupport local functions that disallow capturing state from the enclosing scope.\n\n## Motivation\n\nAvoid unintentionally capturing state from the enclosing context.\nAllow local functions to be used in scenarios where a `static` method is required.\n\n## Detailed design\n\nA local function declared `static` cannot capture state from the enclosing scope.\nAs a result, locals, parameters, and `this` from the enclosing scope are not available within a `static` local function.\n\nA `static` local function cannot reference instance members from an implicit or explicit `this` or `base` reference.\n\nA `static` local function may reference `static` members from the enclosing scope.\n\nA `static` local function may reference `constant` definitions from the enclosing scope.\n\n`nameof()` in a `static` local function may reference locals, parameters, or `this` or `base` from the enclosing scope.\n\nAccessibility rules for `private` members in the enclosing scope are the same for `static` and non-`static` local functions.\n\nA `static` local function definition is emitted as a `static` method in metadata, even if only used in a delegate.\n\nA non-`static` local function or lambda can capture state from an enclosing `static` local function but cannot capture state outside the enclosing `static` local function.\n\nA `static` local function cannot be invoked in an expression tree.\n\nA call to a local function is emitted as `call` rather than `callvirt`, regardless of whether the local function is `static`.\n\nOverload resolution of a call within a local function not affected by whether the local function is `static`.\n\nRemoving the `static` modifier from a local function in a valid program does not change the meaning of the program.\n\n## Design meetings\n\nhttps://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-09-10.md#static-local-functions\n"
  },
  {
    "path": "proposals/csharp-8.0/unconstrained-null-coalescing.md",
    "content": "﻿## Unconstrained type parameter in null coalescing operator\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/1284>\n\nIn C# 8.0 we introduced a feature that permits a null coalescing operator to have a left operand that is not known to be either a reference or value type (i.e. an unconstrained type parameter). This is a placeholder for its specification.\n"
  },
  {
    "path": "proposals/csharp-8.0/using.md",
    "content": "# \"pattern-based using\" and \"using declarations\"\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/114>\n\n## Summary\n\nThe language will add two new capabilities around the `using` statement in order to make resource\nmanagement simpler: `using` should recognize a disposable pattern in addition to `IDisposable` and add a `using`\ndeclaration to the language.\n\n## Motivation\n\nThe `using` statement is an effective tool for resource management today but it requires quite a \nbit of ceremony. Methods that have a number of resources to manage can get syntactically bogged \ndown with a series of `using` statements. This syntax burden is enough that most coding style \nguidelines explicitly have an exception around braces for this scenario. \n\nThe `using` declaration removes much of the ceremony here and gets C# on par with other languages\nthat include resource management blocks. Additionally the pattern-based `using` lets developers expand\nthe set of types that can participate here. In many cases removing the need to create wrapper types \nthat only exist to allow for a values use in a `using` statement. \n\nTogether these features allow developers to simplify and expand the scenarios where `using` can\nbe applied.\n\n## Detailed Design \n\n### using declaration\n\nThe language will allow for `using` to be added to a local variable declaration. Such a declaration\nwill have the same effect as declaring the variable in a `using` statement at the same location.\n\n```csharp\nif (...) \n{ \n   using FileStream f = new FileStream(@\"C:\\source\\using.md\");\n   // statements\n}\n\n// Equivalent to \nif (...) \n{ \n   using (FileStream f = new FileStream(@\"C:\\source\\using.md\")) \n   {\n    // statements\n   }\n}\n```\n\nThe lifetime of a `using` local will extend to the end of the scope in which it is declared. The \n`using` locals will then be disposed in the reverse order in which they are declared. \n\n```csharp\n{ \n    using var f1 = new FileStream(\"...\");\n    using var f2 = new FileStream(\"...\");\n    using var f3 = new FileStream(\"...\");\n    ...\n    // Dispose f3\n    // Dispose f2 \n    // Dispose f1\n}\n```\n\nThere are no restrictions around `goto`, or any other control flow construct in the face of \na `using` declaration. Instead the code acts just as it would for the equivalent `using` statement:\n\n```csharp\n{\n    using var f1 = new FileStream(\"...\");\n  target:\n    using var f2 = new FileStream(\"...\");\n    if (someCondition) \n    {\n        // Causes f2 to be disposed but has no effect on f1\n        goto target;\n    }\n}\n```\n\nA local declared in a `using` local declaration will be implicitly read-only. This matches the \nbehavior of locals declared in a `using` statement. \n\nThe language grammar for `using` declarations will be the following:\n\n```antlr\nlocal-using-declaration:\n  'using' type using-declarators\n\nusing-declarators:\n  using-declarator\n  using-declarators , using-declarator\n  \nusing-declarator:\n  identifier = expression\n```\n\nRestrictions around `using` declaration:\n\n- May not appear directly inside a `case` label but instead must be within a block inside the\n `case` label.\n- May not appear as part of an `out` variable declaration. \n- Must have an initializer for each declarator.\n- The local type must be implicitly convertible to `IDisposable` or fulfill the `using` pattern.\n\n### pattern-based using\n\nThe language will add the notion of a disposable pattern for `ref struct` types: that is a `ref struct` which has an accessible \n`Dispose` instance method. Types which fit the disposable pattern can participate in a `using` \nstatement or declaration without being required to implement `IDisposable`. \n\n```csharp\nref struct Resource\n{ \n    public void Dispose() { ... }\n}\n\nusing (var r = new Resource())\n{\n    // statements\n}\n```\n\nThis will allow developers to leverage `using` for `ref struct` types. These types can't implement interfaces in C# 8 and hence can't participate in `using`\nstatements.\n\nThe same restrictions from a traditional `using` statement apply here as well: local variables \ndeclared in the `using` are read-only, a `null` value will not cause an exception to be thrown, \netc ... The code generation will be different only in that there will not be a cast to \n`IDisposable` before calling Dispose:\n\n```csharp\n{\n\t  Resource r = new Resource();\n\t  try {\n\t\t    // statements\n\t  }\n\t  finally {\n\t\t    if (r != null) r.Dispose();\n\t  }\n}\n```\n\nIn order to fit the disposable pattern the `Dispose` method must be an accessible instance member, parameterless and have \na `void` return type. It cannot be an extension method.\n\n## Considerations\n\nNeither of these considerations were implemented in C# 8\n\n<details>\n\n### case labels without blocks\n\nA `using declaration` is illegal directly inside a `case` label due to complications around its \nactual lifetime. One potential solution is to simply give it the same lifetime as an `out var` \nin the same location. It was deemed the extra complexity to the feature implementation and the \nease of the work around (just add a block to the `case` label) didn't justify taking this route.\n\n## Future Expansions\n\n### fixed locals\n\nA `fixed` statement has all of the properties of `using` statements that motivated the ability\nto have `using` locals. Consideration should be given to extending this feature to `fixed` locals\nas well. The lifetime and ordering rules should apply equally well for `using` and `fixed` here.\n\n</details>\n"
  },
  {
    "path": "proposals/csharp-9.0/covariant-returns.md",
    "content": "# Covariant returns\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/49>\n\n## Summary\n[summary]: #summary\n\nSupport _covariant return types_. Specifically, permit the override of a method to declare a more derived return type than the method it overrides, and similarly to permit the override of a read-only property to declare a more derived type. Override declarations appearing in more derived types would be required to provide a return type at least as specific as that appearing in overrides in its base types. Callers of the method or property would statically receive the more refined return type from an invocation.\n\n## Motivation\n[motivation]: #motivation\n\nIt is a common pattern in code that different method names have to be invented to work around the language constraint that overrides must return the same type as the overridden method.\n\nThis would be useful in the factory pattern. For example, in the Roslyn code base we would have\n\n``` cs\nclass Compilation ...\n{\n    public virtual Compilation WithOptions(Options options)...\n}\n```\n\n``` cs\nclass CSharpCompilation : Compilation\n{\n    public override CSharpCompilation WithOptions(Options options)...\n}\n```\n\n## Detailed design\n[design]: #detailed-design\n\nThis is a specification for [covariant return types](https://github.com/dotnet/csharplang/issues/49) in C#.  Our intent is to permit the override of a method to return a more derived return type than the method it overrides, and similarly to permit the override of a read-only property to return a more derived return type.  Callers of the method or property would statically receive the more refined return type from an invocation, and overrides appearing in more derived types would be required to provide a return type at least as specific as that appearing in overrides in its base types.\n\n--------------\n\n### Class Method Override\n\nThe existing constraint on class override ([§15.6.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#1565-override-methods)) methods\n\n> - The override method and the overridden base method have the same return type.\n\nis modified to\n\n> - The override method must have a return type that is convertible by an identity conversion or (if the method has a value return - not a [ref return](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/ref-locals-returns.md) see [§13.1.0.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md#13105-the-return-statement) implicit reference conversion to the return type of the overridden base method.\n\nAnd the following additional requirements are appended to that list:\n\n> - The override method must have a return type that is convertible by an identity conversion or (if the method has a value return - not a [ref return](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/ref-locals-returns.md), [§13.1.0.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md#13105-the-return-statement)) implicit reference conversion to the return type of every override of the overridden base method that is declared in a (direct or indirect) base type of the override method.\n> - The override method's return type must be at least as accessible as the override method  (Accessibility domains - [§7.5.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/basic-concepts.md#753-accessibility-domains)).\n\nThis constraint permits an override method in a `private` class to have a `private` return type.  However it requires a `public` override method in a `public` type to have a `public` return type.\n\n### Class Property and Indexer Override\n\nThe existing constraint on class override ([§15.7.6](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#1576-virtual-sealed-override-and-abstract-accessors)) properties\n\n> An overriding property declaration shall specify the exact same accessibility modifiers and name as the inherited property, and there shall be an identity conversion ~~between the type of the overriding and the inherited property~~. If the inherited property has only a single accessor (i.e., if the inherited property is read-only or write-only), the overriding property shall include only that accessor. If the inherited property includes both accessors (i.e., if the inherited property is read-write), the overriding property can include either a single accessor or both accessors.\n\nis modified to\n\n> An overriding property declaration shall specify the exact same accessibility modifiers and name as the inherited property, and there shall be an identity conversion **or (if the inherited property is read-only and has a value return - not a [ref return](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/ref-locals-returns.md) [§13.1.0.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md#13105-the-return-statement)) implicit reference conversion from the type of the overriding property to the type of the inherited property**. If the inherited property has only a single accessor (i.e., if the inherited property is read-only or write-only), the overriding property shall include only that accessor. If the inherited property includes both accessors (i.e., if the inherited property is read-write), the overriding property can include either a single accessor or both accessors. **The overriding property's type must be at least as accessible as the overriding property (Accessibility domains - [§7.5.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/basic-concepts.md#753-accessibility-domains)).**\n\n-----------------\n\n***The remainder of the draft specification below proposes a further extension to covariant returns of interface methods to be considered later.***\n\n### Interface Method, Property, and Indexer Override\n\nAdding to the kinds of members that are permitted in an interface with the addition of the DIM feature in C# 8.0, we further add support for `override` members along with covariant returns.  These follow the rules of `override` members as specified for classes, with the following differences:\n\nThe following text in classes:\n\n> The method overridden by an override declaration is known as the ***overridden base method***. For an override method `M` declared in a class `C`, the overridden base method is determined by examining each base class of `C`, starting with the direct base class of `C` and continuing with each successive direct base class, until in a given base class type at least one accessible method is located which has the same signature as `M` after substitution of type arguments.\n\nis given the corresponding specification for interfaces:\n\n> The method overridden by an override declaration is known as the ***overridden base method***. For an override method `M` declared in an interface `I`, the overridden base method is determined by examining each direct or indirect base interface of `I`, collecting the set of interfaces declaring an accessible method which has the same signature as `M` after substitution of type arguments.  If this set of interfaces has a *most derived type*, to which there is an identity or implicit reference conversion from every type in this set, and that type contains a unique such method declaration, then that is the *overridden base method*.\n\nWe similarly permit `override` properties and indexers in interfaces as specified for classes in [§15.7.6 Virtual, sealed, override, and abstract accessors](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#1576-virtual-sealed-override-and-abstract-accessors).\n\n### Name Lookup\n\nName lookup in the presence of class `override` declarations currently modify the result of name lookup by imposing on the found member details from the most derived `override` declaration in the class hierarchy starting from the type of the identifier's qualifier (or `this` when there is no qualifier).  For example, in [§12.6.2.2 Corresponding parameters](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12622-corresponding-parameters) we have\n\n> For virtual methods and indexers defined in classes, the parameter list is picked from the first  declaration or override of the function member found when starting with the static type of the receiver, and searching through its base classes.\n\nto this we add\n\n> For virtual methods and indexers defined in interfaces, the parameter list is picked from the declaration or override of the function member found in the most derived type among those types containing the declaration of override of the function member.  It is a compile-time error if no unique such type exists.\n\nFor the result type of a property or indexer access, the existing text\n\n> - If `I` identifies an instance property, then the result is a property access with an associated instance expression of `E` and an associated type that is the type of the property. If `T` is a class type, the associated type is picked from the first declaration or override of the property found when starting with `T`, and searching through its base classes.\n\nis augmented with\n\n> If `T` is an interface type, the associated type is picked from the declaration or override of the property found in the most derived of `T` or its direct or indirect base interfaces.  It is a compile-time error if no unique such type exists.\n\nA similar change should be made in [§12.8.12.3 Indexer access](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#128123-indexer-access)\n\nIn [§12.8.10 Invocation expressions](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12810-invocation-expressions) we augment the existing text\n\n> - Otherwise, the result is a value, with an associated type of the return type of the method or delegate. If the invocation is of an instance method, and the receiver is of a class type `T`, the associated type is picked from the first declaration or override of the method found when starting with `T` and searching through its base classes.\n\nwith\n\n> If the invocation is of an instance method, and the receiver is of an interface type `T`, the associated type is picked from the declaration or override of the method found in the most derived interface from among `T` and its direct and indirect base interfaces.  It is a compile-time error if no unique such type exists.\n\n### Implicit Interface Implementations\n\nThis section of the specification\n\n> For purposes of interface mapping, a class member `A` matches an interface member `B` when:\n> \n> - `A` and `B` are methods, and the name, type, and formal parameter lists of `A` and `B` are identical.\n> - `A` and `B` are properties, the name and type of `A` and `B` are identical, and `A` has the same accessors as `B` (`A` is permitted to have additional accessors if it is not an explicit interface member implementation).\n> - `A` and `B` are events, and the name and type of `A` and `B` are identical.\n> - `A` and `B` are indexers, the type and formal parameter lists of `A` and `B` are identical, and `A` has the same accessors as `B` (`A` is permitted to have additional accessors if it is not an explicit interface member implementation).\n\nis modified as follows:\n\n> For purposes of interface mapping, a class member `A` matches an interface member `B` when:\n> \n> - `A` and `B` are methods, and the name and formal parameter lists of `A` and `B` are identical, and the return type of `A` is convertible to the return type of `B` via an identity of implicit reference convertion to the return type of `B`.\n> - `A` and `B` are properties, the name of `A` and `B` are identical, `A` has the same accessors as `B` (`A` is permitted to have additional accessors if it is not an explicit interface member implementation), and the type of `A` is convertible to the return type of `B` via an identity conversion or, if `A` is a readonly property, an implicit reference conversion.\n> - `A` and `B` are events, and the name and type of `A` and `B` are identical.\n> - `A` and `B` are indexers, the formal parameter lists of `A` and `B` are identical, `A` has the same accessors as `B` (`A` is permitted to have additional accessors if it is not an explicit interface member implementation), and the type of `A` is convertible to the return type of `B` via an identity conversion or, if `A` is a readonly indexer, an implicit reference conversion.\n\nThis is technically a breaking change, as the program below prints \"C1.M\" today, but would print \"C2.M\" under the proposed revision.\n\n``` c#\nusing System;\n\ninterface I1 { object M(); }\nclass C1 : I1 { public object M() { return \"C1.M\"; } }\nclass C2 : C1, I1 { public new string M() { return \"C2.M\"; } }\nclass Program\n{\n    static void Main()\n    {\n        I1 i = new C2();\n        Console.WriteLine(i.M());\n    }\n}\n```\n\nDue to this breaking change, we might consider not supporting covariant return types on implicit implementations.\n\n### Constraints on Interface Implementation\n\n**We will need a rule that an explicit interface implementation must declare a return type no less derived than the return type declared in any override in its base interfaces.**\n\n### API Compatibility Implications\n\n*TBD*\n\n### Open Issues\n\nThe specification does not say how the caller gets the more refined return type. Presumably that would be done in a way similar to the way that callers get the most derived override's parameter specifications.\n\n--------------\n\nIf we have the following interfaces:\n\n```csharp\ninterface I1 { I1 M(); }\ninterface I2 { I2 M(); }\ninterface I3: I1, I2 { override I3 M(); }\n```\n\nNote that in `I3`, the methods `I1.M()` and `I2.M()` have been “merged”.  When implementing `I3`, it is necessary to implement them both together.\n\nGenerally, we require an explicit implementation to refer to the original method.  The question is, in a class\n\n```csharp\nclass C : I1, I2, I3\n{\n    C IN.M();\n}\n```\n\nWhat does that mean here?  What should *N* be?\n\nI suggest that we permit implementing either `I1.M` or `I2.M` (but not both), and treat that as an implementation of both.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\n- [ ] Every language change must pay for itself.\n- [ ] We should ensure that the performance is reasonable, even in the case of deep inheritance hierarchies\n- [ ] We should ensure that artifacts of the translation strategy do not affect language semantics, even when consuming new IL from old compilers.\n\n## Alternatives\n[alternatives]: #alternatives\n\nWe could relax the language rules slightly to allow, in source,\n\n```csharp\n// Possible alternative. This was not implemented.\nabstract class Cloneable\n{\n    public abstract Cloneable Clone();\n}\n\nclass Digit : Cloneable\n{\n    public override Cloneable Clone()\n    {\n        return this.Clone();\n    }\n\n    public new Digit Clone() // Error: 'Digit' already defines a member called 'Clone' with the same parameter types\n    {\n        return this;\n    }\n}\n```\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n- [ ] How will APIs that have been compiled to use this feature work in older versions of the language?\n\n## Design meetings\n\n- some discussion at <https://github.com/dotnet/roslyn/issues/357>.\n- https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-01-08.md\n- Offline discussion toward a decision to support overriding of class methods only in C# 9.0.\n"
  },
  {
    "path": "proposals/csharp-9.0/extending-partial-methods.md",
    "content": "# Extending Partial Methods\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/3301>\n\n## Summary\nThis proposal aims to remove all restrictions around the signatures of `partial`\nmethods in C#. The goal being to expand the set of scenarios in which these\nmethods can work with source generators as well as being a more general \ndeclaration form for C# methods.\n\nSee also the original partial methods specification ([§15.6.9](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#1569-partial-methods)).\n\n## Motivation\nC# has limited support for developers splitting methods into declarations and \ndefinitions / implementations. \n\n```cs \npartial class C\n{\n    // The declaration of C.M\n    partial void M(string message);\n}\n\npartial class C\n{\n    // The definition of C.M\n    partial void M(string message) => Console.WriteLine(message);\n}\n```\n\nOne behavior of `partial` methods is that when the definition is absent then\nthe language will simply erase any calls to the `partial` method. Essentially \nit behaves like a call to a `[Conditional]` method where the condition was \nevaluated to false. \n\n```cs\npartial class D\n{\n    partial void M(string message);\n\n    void Example()\n    {\n        M(GetIt()); // Call to M and GetIt erased at compile time\n    }\n\n    string GetIt() => \"Hello World\";\n}\n```\n\nThe original motivation for this feature was source generation in the form of \ndesigner generated code. Users were constantly editing the generated code \nbecause they wanted to hook some aspect of the generated code. Most notably \nparts of the Windows Forms startup process, after components were initialized.\n\nEditing the generated code was error prone because any action which caused the\ndesigner to regenerate the code would cause the user edit to be erased. The \n`partial` method feature eased this tension because it allowed designers to\nemit hooks in the form of `partial` methods. \n\nDesigners could emit hooks like `partial void OnComponentInit()` and developers\ncould define declarations for them or not define them. In either case though \nthe generated code would compile and developers who were interested in the \nprocess could hook in as needed. \n\nThis does mean that partial methods have several restrictions:\n\n1. Must have a `void` return type.\n1. Cannot have `out` parameters. \n1. Cannot have any accessibility (implicitly `private`).\n\nThese restrictions exist because the language must be able to emit code when\nthe call site is erased. Given they can be erased `private` is the only possible\naccessibility because the member can't be exposed in assembly metadata. These \nrestrictions also serve to limit the set of scenarios in which `partial` methods\ncan be applied.\n\nThe proposal here is to remove all of the existing restrictions around `partial`\nmethods. Essentially let them have `out` parameters, non-void return types or any \ntype of accessibility. Such `partial` declarations would then have the added\nrequirement that a definition must exist. That means the language does not\nhave to consider the impact of erasing the call sites. \n\nThis would expand the set of generator scenarios that `partial` methods could\nparticipate in and hence link in nicely with our source generators feature. For\nexample a regex could be defined using the following pattern:\n\n```cs\n[RegexGenerated(\"(dog|cat|fish)\")]\npartial bool IsPetMatch(string input);\n```\n\nThis gives both the developer a simple declarative way of opting into generators\nas well as giving generators a very easy set of declarations to look through \nin the source code to drive their generated output. \n\nCompare that with the difficulty that a generator would have hooking up the \nfollowing snippet of code. \n\n```cs\nvar regex = new RegularExpression(\"(dog|cat|fish)\");\nif (regex.IsMatch(someInput))\n{\n\n}\n```\n\nGiven that the compiler doesn't allow generators to modify code hooking up this\npattern would be pretty much impossible for generators. They would need to\nresort to reflection in the `IsMatch` implementation, or asking users to change\ntheir call sites to a new method + refactor the regex to pass the string literal\nas an argument. It's pretty messy.\n\n## Detailed Design\nThe language will change to allow `partial` methods to be annotated with an \nexplicit accessibility modifier. This means they can be labeled as `private`, \n`public`, etc ... \n\nWhen a `partial` method has an explicit accessibility modifier \nthe language will require that the declaration has a matching\ndefinition even when the accessibility is `private`:\n\n```cs\npartial class C\n{\n    // Okay because no definition is required here\n    partial void M1();\n\n    // Okay because M2 has a definition\n    private partial void M2();\n\n    // Error: partial method M3 must have a definition\n    private partial void M3();\n}\n\npartial class C\n{\n    private partial void M2() { }\n}\n```\n\nFurther the language will remove all restrictions on what can appear on a \n`partial` method which has an explicit accessibility. Such declarations can \ncontain non-void return types, `out` parameters, `extern` modifier, \netc ... These signatures will have the full expressivity of the C# language.\n\n```cs\npartial class D\n{\n    // Okay\n    internal partial bool TryParse(string s, out int i); \n}\n\npartial class D\n{\n    internal partial bool TryParse(string s, out int i) { ... }\n}\n```\n\nThis explicitly allows for `partial` methods to participate in `overrides` and \n`interface` implementations:\n\n```cs\ninterface IStudent\n{\n    string GetName();\n}\n\npartial class C : IStudent\n{\n    public virtual partial string GetName(); \n}\n\npartial class C\n{\n    public virtual partial string GetName() => \"Jarde\";\n}\n```\n\nThe compiler will change the error it emits when a `partial` method contains\nan illegal element to essentially say:\n\n> Cannot use `ref` on a `partial` method that lacks explicit accessibility \n\nThis will help point developers in the right direction when using this feature.\n\nRestrictions:\n- `partial` declarations with explicit accessibility must have a definition\n- `partial` declarations and definition signatures must match on all method\nand parameter modifiers. The only aspects which can differ are parameter names\nand attribute lists (this is not new but rather an existing requirement of\n`partial` methods).\n\n## Questions\n\n### partial on all members\nGiven that we're expanding `partial` to be more friendly to source generators\nshould we also expand it to work on all class members? For example should we \nbe able to declare `partial` constructors, operators, etc ...\n\n**Resolution**\nThe idea is sound but at this point in the C# 9 schedule we're trying to avoid\nunnecessary feature creep. Want to solve the immediate problem of expanding\nthe feature to work with modern source generators. \n\nExtending `partial` to support other members will be considered for the C# 10\nrelease. Seems likely that we will consider this extension. This remains an\nactive proposal, but it has not yet been implemented.\n\n### Use abstract instead of partial\nThe crux of this proposal is essentially ensuring that a declaration has a\ncorresponding definition / implementation. Given that should we use `abstract`\nsince it's already a language keyword that forces the developer to think about\nhaving an implementation?\n\n**Resolution**\nThere was a healthy discussion about this but eventually it was decided against.\nYes the requirements are familiar but the concepts are significantly different.\nCould easily lead the developer to believe they were creating virtual slots when\nthey were not doing so.\n"
  },
  {
    "path": "proposals/csharp-9.0/extension-getenumerator.md",
    "content": "# Extension `GetEnumerator` support for `foreach` loops.\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/3194>\n\n## Summary\n[summary]: #summary\n\nAllow `foreach` loops to recognize an extension method `GetEnumerator` method that otherwise satisfies the foreach pattern, and loop over the expression when it would otherwise be an error.\n\n## Motivation\n[motivation]: #motivation\n\nThis will bring `foreach` inline with how other features in C# are implemented, including async and pattern-based deconstruction.\n\n## Detailed design\n[design]: #detailed-design\n\nThe spec change is relatively straightforward. We modify `The foreach statement` [§13.9.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md#1395-the-foreach-statement) section to this text:\n\n>The compile-time processing of a foreach statement first determines the ***collection type***, ***enumerator type*** and ***element type*** of the expression. This determination proceeds as follows:\n>\n>*  If the type `X` of *expression* is an array type then there is an implicit reference conversion from `X` to the `IEnumerable` interface (since `System.Array` implements this interface). The ***collection type*** is the `IEnumerable` interface, the ***enumerator type*** is the `IEnumerator` interface and the ***element type*** is the element type of the array type `X`.\n>*  If the type `X` of *expression* is `dynamic` then there is an implicit conversion from *expression* to the `IEnumerable` interface ([§10.2.10](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#10210-implicit-dynamic-conversions)). The ***collection type*** is the `IEnumerable` interface and the ***enumerator type*** is the `IEnumerator` interface. If the `var` identifier is given as the *local_variable_type* then the ***element type*** is `dynamic`, otherwise it is `object`.\n>*  Otherwise, determine whether the type `X` has an appropriate `GetEnumerator` method:\n>    * Perform member lookup on the type `X` with identifier `GetEnumerator` and no type arguments. If the member lookup does not produce a match, or it produces an ambiguity, or produces a match that is not a method group, check for an enumerable interface as described below. It is recommended that a warning be issued if member lookup produces anything except a method group or no match.\n>    * Perform overload resolution using the resulting method group and an empty argument list. If overload resolution results in no applicable methods, results in an ambiguity, or results in a single best method but that method is either static or not public, check for an enumerable interface as described below. It is recommended that a warning be issued if overload resolution produces anything except an unambiguous public instance method or no applicable methods.\n>    * If the return type `E` of the `GetEnumerator` method is not a class, struct or interface type, an error is produced and no further steps are taken.\n>    * Member lookup is performed on `E` with the identifier `Current` and no type arguments. If the member lookup produces no match, the result is an error, or the result is anything except a public instance property that permits reading, an error is produced and no further steps are taken.\n>    * Member lookup is performed on `E` with the identifier `MoveNext` and no type arguments. If the member lookup produces no match, the result is an error, or the result is anything except a method group, an error is produced and no further steps are taken.\n>    * Overload resolution is performed on the method group with an empty argument list. If overload resolution results in no applicable methods, results in an ambiguity, or results in a single best method but that method is either static or not public, or its return type is not `bool`, an error is produced and no further steps are taken.\n>    * The ***collection type*** is `X`, the ***enumerator type*** is `E`, and the ***element type*** is the type of the `Current` property.\n>\n>*  Otherwise, check for an enumerable interface:\n>    * If among all the types `Ti` for which there is an implicit conversion from `X` to `IEnumerable<Ti>`, there is a unique type `T` such that `T` is not `dynamic` and for all the other `Ti` there is an implicit conversion from `IEnumerable<T>` to `IEnumerable<Ti>`, then the ***collection type*** is the interface `IEnumerable<T>`, the ***enumerator type*** is the interface `IEnumerator<T>`, and the ***element type*** is `T`.\n>    * Otherwise, if there is more than one such type `T`, then an error is produced and no further steps are taken.\n>    * Otherwise, if there is an implicit conversion from `X` to the `System.Collections.IEnumerable` interface, then the ***collection type*** is this interface, the ***enumerator type*** is the interface `System.Collections.IEnumerator`, and the ***element type*** is `object`.\n>*  Otherwise, determine whether the type 'X' has an appropriate `GetEnumerator` extension method:\n>    * Perform extension method lookup on the type `X` with identifier `GetEnumerator`. If the member lookup does not produce a match, or it produces an ambiguity, or produces a match which is not a method group, an error is produced and no further steps are taken. It is recommended that a warning be issues if member lookup produces anything except a method group or no match.\n>    * Perform overload resolution using the resulting method group and a single argument of type `X`. If overload resolution produces no applicable methods, results in an ambiguity, or results in a single best method but that method is not accessible, an error is produced an no further steps are taken.\n>        * This resolution permits the first argument to be passed by ref if `X` is a struct type, and the ref kind is `in`.\n>    * If the return type `E` of the `GetEnumerator` method is not a class, struct or interface type, an error is produced and no further steps are taken.\n>    * Member lookup is performed on `E` with the identifier `Current` and no type arguments. If the member lookup produces no match, the result is an error, or the result is anything except a public instance property that permits reading, an error is produced and no further steps are taken.\n>    * Member lookup is performed on `E` with the identifier `MoveNext` and no type arguments. If the member lookup produces no match, the result is an error, or the result is anything except a method group, an error is produced and no further steps are taken.\n>    * Overload resolution is performed on the method group with an empty argument list. If overload resolution results in no applicable methods, results in an ambiguity, or results in a single best method but that method is either static or not public, or its return type is not `bool`, an error is produced and no further steps are taken.\n>    * The ***collection type*** is `X`, the ***enumerator type*** is `E`, and the ***element type*** is the type of the `Current` property.\n>*  Otherwise, an error is produced and no further steps are taken.\n\nFor `await foreach`, the rules are similarly modified. The only change that is required to that spec is removing the `Extension methods do not contribute.` line from the description, as the rest of that spec is based on the above rules with different names substituted for the pattern methods.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nEvery change adds additional complexity to the language, and this potentially allows things that weren't designed to be `foreach`ed to be `foreach`ed, like `Range`.\n\n## Alternatives\n[alternatives]: #alternatives\n\nDoing nothing.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\nNone at this point.\n"
  },
  {
    "path": "proposals/csharp-9.0/function-pointers.md",
    "content": "# Function Pointers\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\n## Summary\n\nThis proposal provides language constructs that expose IL opcodes that cannot currently be accessed efficiently,\nor at all, in C# today: `ldftn` and `calli`. These IL opcodes can be important in high performance code and developers\nneed an efficient way to access them.\n\n## Motivation\n\nThe motivations and background for this feature are described in the following issue (as is a\npotential implementation of the feature):\n\n[dotnet/csharplang#191](https://github.com/dotnet/csharplang/issues/191)\n\nThis is an alternate design proposal to [compiler intrinsics](https://github.com/dotnet/csharplang/blob/main/proposals/rejected/intrinsics.md)\n\n## Detailed Design\n\n### Function pointers\n\nThe language will allow for the declaration of function pointers using the `delegate*` syntax. The full syntax is described\nin detail in the next section but it is meant to resemble the syntax used by `Func` and `Action` type declarations.\n\n``` csharp\nunsafe class Example\n{\n    void M(Action<int> a, delegate*<int, void> f)\n    {\n        a(42);\n        f(42);\n    }\n}\n```\n\nThese types are represented using the function pointer type as outlined in ECMA-335. This means invocation\nof a `delegate*` will use `calli` where invocation of a `delegate` will use `callvirt` on the `Invoke` method.\nSyntactically though invocation is identical for both constructs.\n\nThe ECMA-335 definition of method pointers includes the calling convention as part of the type signature (section 7.1).\nThe default calling convention will be `managed`. Unmanaged calling conventions can be specified by putting an `unmanaged`\nkeyword afer the `delegate*` syntax, which will use the runtime platform default. Specific unmanaged conventions can then\nbe specified in brackets to the `unmanaged` keyword by specifying any type starting with `CallConv` in the\n`System.Runtime.CompilerServices` namespace, leaving off the `CallConv` prefix. These types must come from the program's\ncore library, and the set of valid combinations is platform-dependent.\n\n``` csharp\n//This method has a managed calling convention. This is the same as leaving the managed keyword off.\ndelegate* managed<int, int>;\n\n// This method will be invoked using whatever the default unmanaged calling convention on the runtime\n// platform is. This is platform and architecture dependent and is determined by the CLR at runtime.\ndelegate* unmanaged<int, int>;\n\n// This method will be invoked using the cdecl calling convention\n// Cdecl maps to System.Runtime.CompilerServices.CallConvCdecl\ndelegate* unmanaged[Cdecl] <int, int>;\n\n// This method will be invoked using the stdcall calling convention, and suppresses GC transition\n// Stdcall maps to System.Runtime.CompilerServices.CallConvStdcall\n// SuppressGCTransition maps to System.Runtime.CompilerServices.CallConvSuppressGCTransition\ndelegate* unmanaged[Stdcall, SuppressGCTransition] <int, int>;\n```\n\nConversions between `delegate*` types is done based on their signature including the calling convention.\n\n``` csharp\nunsafe class Example {\n    void Conversions() {\n        delegate*<int, int, int> p1 = ...;\n        delegate* managed<int, int, int> p2 = ...;\n        delegate* unmanaged<int, int, int> p3 = ...;\n\n        p1 = p2; // okay p1 and p2 have compatible signatures\n        Console.WriteLine(p2 == p1); // True\n        p2 = p3; // error: calling conventions are incompatible\n    }\n}\n```\n\nA `delegate*` type is a pointer type which means it has all of the capabilities and restrictions of a standard pointer\ntype:\n\n- Only valid in an `unsafe` context.\n- Methods which contain a `delegate*` parameter or return type can only be called from an `unsafe` context.\n- Cannot be converted to `object`.\n- Cannot be used as a generic argument.\n- Can implicitly convert `delegate*` to `void*`.\n- Can explicitly convert from `void*` to `delegate*`.\n\nRestrictions:\n\n- Custom attributes cannot be applied to a `delegate*` or any of its elements.\n- A `delegate*` parameter cannot be marked as `params`\n- A `delegate*` type has all of the restrictions of a normal pointer type.\n- Pointer arithmetic cannot be performed directly on function pointer types.\n\n### Function pointer syntax\n\nThe full function pointer syntax is represented by the following grammar:\n\n```antlr\npointer_type\n    : ...\n    | funcptr_type\n    ;\n\nfuncptr_type\n    : 'delegate' '*' calling_convention_specifier? '<' funcptr_parameter_list funcptr_return_type '>'\n    ;\n\ncalling_convention_specifier\n    : 'managed'\n    | 'unmanaged' ('[' unmanaged_calling_convention ']')?\n    ;\n\nunmanaged_calling_convention\n    : 'Cdecl'\n    | 'Stdcall'\n    | 'Thiscall'\n    | 'Fastcall'\n    | identifier (',' identifier)*\n    ;\n\nfunptr_parameter_list\n    : (funcptr_parameter ',')*\n    ;\n\nfuncptr_parameter\n    : funcptr_parameter_modifier? type\n    ;\n\nfuncptr_return_type\n    : funcptr_return_modifier? return_type\n    ;\n\nfuncptr_parameter_modifier\n    : 'ref'\n    | 'out'\n    | 'in'\n    ;\n\nfuncptr_return_modifier\n    : 'ref'\n    | 'ref readonly'\n    ;\n```\n\nIf no `calling_convention_specifier` is provided, the default is `managed`. The precise metadata encoding\nof the `calling_convention_specifier` and what `identifier`s are valid in the `unmanaged_calling_convention` is\ncovered in [Metadata Representation of Calling Conventions](#metadata-representation-of-calling-conventions).\n\n``` csharp\ndelegate int Func1(string s);\ndelegate Func1 Func2(Func1 f);\n\n// Function pointer equivalent without calling convention\ndelegate*<string, int>;\ndelegate*<delegate*<string, int>, delegate*<string, int>>;\n\n// Function pointer equivalent with calling convention\ndelegate* managed<string, int>;\ndelegate*<delegate* managed<string, int>, delegate*<string, int>>;\n```\n\n### Function pointer conversions\n\nIn an unsafe context, the set of available implicit conversions (Implicit conversions) is extended to include the following implicit pointer conversions:\n- _Existing conversions_ - ([§23.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#235-pointer-conversions))\n- From _funcptr\\_type_ `F0` to another _funcptr\\_type_ `F1`, provided all of the following are true:\n    - `F0` and `F1` have the same number of parameters, and each parameter `D0n` in `F0` has the same `ref`, `out`, or `in` modifiers as the corresponding parameter `D1n` in `F1`.\n    - For each value parameter (a parameter with no `ref`, `out`, or `in` modifier), an identity conversion, implicit reference conversion, or implicit pointer conversion exists from the parameter type in `F0` to the corresponding parameter type in `F1`.\n    - For each `ref`, `out`, or `in` parameter, the parameter type in `F0` is the same as the corresponding parameter type in `F1`.\n    - If the return type is by value (no `ref` or `ref readonly`), an identity, implicit reference, or implicit pointer conversion exists from the return type of `F1` to the return type of `F0`.\n    - If the return type is by reference (`ref` or `ref readonly`), the return type and `ref` modifiers of `F1` are the same as the return type and `ref` modifiers of `F0`.\n    - The calling convention of `F0` is the same as the calling convention of `F1`.\n\n### Allow address-of to target methods\n\nMethod groups will now be allowed as arguments to an address-of expression. The type of such an\nexpression will be a `delegate*` which has the equivalent signature of the target method and a managed\ncalling convention:\n\n``` csharp\nunsafe class Util {\n    public static void Log() { }\n\n    void Use() {\n        delegate*<void> ptr1 = &Util.Log;\n\n        // Error: type \"delegate*<void>\" not compatible with \"delegate*<int>\";\n        delegate*<int> ptr2 = &Util.Log;\n   }\n}\n```\n\nIn an unsafe context, a method `M` is compatible with a function pointer type `F` if all of the following are true:\n- `M` and `F` have the same number of parameters, and each parameter in `M` has the same `ref`, `out`, or `in` modifiers as the corresponding parameter in `F`.\n- For each value parameter (a parameter with no `ref`, `out`, or `in` modifier), an identity conversion, implicit reference conversion, or implicit pointer conversion exists from the parameter type in `M` to the corresponding parameter type in `F`.\n- For each `ref`, `out`, or `in` parameter, the parameter type in `M` is the same as the corresponding parameter type in `F`.\n- If the return type is by value (no `ref` or `ref readonly`), an identity, implicit reference, or implicit pointer conversion exists from the return type of `F` to the return type of `M`.\n- If the return type is by reference (`ref` or `ref readonly`), the return type and `ref` modifiers of `F` are the same as the return type and `ref` modifiers of `M`.\n- The calling convention of `M` is the same as the calling convention of `F`. This includes both the calling convention bit, as well as any calling convention flags specified in the unmanaged identifier.\n- `M` is a static method.\n\nIn an unsafe context, an implicit conversion exists from an address-of expression whose target is a method group `E` to a compatible function pointer type `F` if `E` contains at least one method that is applicable in its normal form to an argument list constructed by use of the parameter types and modifiers of `F`, as described in the following.\n- A single method `M` is selected corresponding to a method invocation of the form `E(A)` with the following modifications:\n   - The arguments list `A` is a list of expressions, each classified as a variable and with the type and modifier (`ref`, `out`, or `in`) of the corresponding _funcptr\\_parameter\\_list_ of `F`.\n   - The candidate methods are only those methods that are applicable in their normal form, not those applicable in their expanded form.\n   - The candidate methods are only those methods that are static.\n- If the algorithm of overload resolution produces an error, then a compile-time error occurs. Otherwise, the algorithm produces a single best method `M` having the same number of parameters as `F` and the conversion is considered to exist.\n- The selected method `M` must be compatible (as defined above) with the function pointer type `F`. Otherwise, a compile-time error occurs.\n- The result of the conversion is a function pointer of type `F`.\n\nThis means developers can depend on overload resolution rules to work in conjunction with the\naddress-of operator:\n\n``` csharp\nunsafe class Util {\n    public static void Log() { }\n    public static void Log(string p1) { }\n    public static void Log(int i) { }\n\n    void Use() {\n        delegate*<void> a1 = &Log; // Log()\n        delegate*<int, void> a2 = &Log; // Log(int i)\n\n        // Error: ambiguous conversion from method group Log to \"void*\"\n        void* v = &Log;\n    }\n}\n```\n\nThe address-of operator will be implemented using the `ldftn` instruction.\n\nRestrictions of this feature:\n\n- Only applies to methods marked as `static`.\n- Non-`static` local functions cannot be used in `&`. The implementation details of these methods are\n  deliberately not specified by the language. This includes whether they are static vs. instance or\n  exactly what signature they are emitted with.\n\n\n### Operators on Function Pointer Types\n\nThe section in unsafe code on expressions is modified as such:\n\n> In an unsafe context, several constructs are available for operating on all _pointer\\_type_s that are not _funcptr\\_type_s:\n>\n> *  The `*` operator may be used to perform pointer indirection ([§23.6.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#2362-pointer-indirection)).\n> *  The `->` operator may be used to access a member of a struct through a pointer ([§23.6.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#2363-pointer-member-access)).\n> *  The `[]` operator may be used to index a pointer ([§23.6.4](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#2364-pointer-element-access)).\n> *  The `&` operator may be used to obtain the address of a variable ([§23.6.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#2365-the-address-of-operator)).\n> *  The `++` and `--` operators may be used to increment and decrement pointers ([§23.6.6](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#2366-pointer-increment-and-decrement)).\n> *  The `+` and `-` operators may be used to perform pointer arithmetic ([§23.6.7](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#2367-pointer-arithmetic)).\n> *  The `==`, `!=`, `<`, `>`, `<=`, and `=>` operators may be used to compare pointers ([§23.6.8](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#2368-pointer-comparison)).\n> *  The `stackalloc` operator may be used to allocate memory from the call stack ([§23.8](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#238-fixed-size-buffers)).\n> *  The `fixed` statement may be used to temporarily fix a variable so its address can be obtained ([§23.7](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#237-the-fixed-statement)).\n> \n> In an unsafe context, several constructs are available for operating on all _funcptr\\_type_s:\n> *  The `&` operator may be used to obtain the address of static methods ([Allow address-of to target methods](#allow-address-of-to-target-methods))\n> *  The `==`, `!=`, `<`, `>`, `<=`, and `=>` operators may be used to compare pointers ([§23.6.8](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#2368-pointer-comparison)).\n\nAdditionally, we modify all the sections in `Pointers in expressions` to forbid function pointer types, except `Pointer comparison` and `The sizeof operator`.\n\n### Better function member\n\n[§12.6.4.3 Better function member](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12643-better-function-member)  will be changed to include the following line:\n\n> A `delegate*` is more specific than `void*`\n\nThis means that it is possible to overload on `void*` and a `delegate*` and still sensibly use the address-of operator.\n\n### Type Inference\n\nIn unsafe code, the following changes are made to the type inference algorithms:\n\n#### Input types\n\n[§12.6.3.4](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12634-input-types)\n\nThe following is added:\n\n> If `E` is an address-of method group and `T` is a function pointer type then all the parameter types of `T` are input types of `E` with type `T`.\n\n#### Output types\n\n[§12.6.3.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12635-output-types)\n\nThe following is added:\n\n> If `E` is an address-of method group and `T` is a function pointer type then the return type of `T` is an output type of `E` with type `T`.\n\n#### Output type inferences\n\n[§12.6.3.7](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12637-output-type-inferences)\n\nThe following bullet is added between bullets 2 and 3:\n\n> * If `E` is an address-of method group and `T` is a function pointer type with parameter types `T1...Tk` and return type `Tb`, and overload resolution\nof `E` with the types `T1..Tk` yields a single method with return type `U`, then a _lower-bound inference_ is made from `U` to `Tb`.\n\n#### Better conversion from expression\n\n[§12.6.4.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12645-better-conversion-from-expression)\n\nThe following sub-bullet is added as a case to bullet 2:\n\n> * `V` is a function pointer type `delegate*<V2..Vk, V1>` and `U` is a function pointer type `delegate*<U2..Uk, U1>`, and the calling convention of `V`\nis identical to `U`, and the refness of `Vi` is identical to `Ui`.\n\n#### Lower-bound inferences\n\n[§12.6.3.10](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#126310-lower-bound-inferences)\n\nThe following case is added to bullet 3:\n\n> * `V` is a function pointer type `delegate*<V2..Vk, V1>` and there is a function pointer type `delegate*<U2..Uk, U1>` such that `U` is identical to\n`delegate*<U2..Uk, U1>`, and the calling convention of `V` is identical to `U`, and the refness of `Vi` is identical to `Ui`.\n\nThe first bullet of inference from `Ui` to `Vi` is modified to:\n\n> * If `U` is not a function pointer type and `Ui` is not known to be a reference type, or if `U` is a function pointer type and `Ui` is not known to be\n>   a function pointer type or a reference type, then an _exact inference_ is made\n\nThen, added after the 3rd bullet of inference from `Ui` to `Vi`:\n\n> * Otherwise, if `V` is `delegate*<V2..Vk, V1>` then inference depends on the i-th parameter of `delegate*<V2..Vk, V1>`:\n>    * If V1:\n>        * If the return is by value, then a _lower-bound inference_ is made.\n>        * If the return is by reference, then an _exact inference_ is made.\n>    * If V2..Vk:\n>        * If the parameter is by value, then an _upper-bound inference_ is made.\n>        * If the parameter is by reference, then an _exact inference_ is made.\n\n#### Upper-bound inferences\n\n[§12.6.3.11](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#126311-upper-bound-inferences)\n\nThe following case is added to bullet 2:\n\n> * `U` is a function pointer type `delegate*<U2..Uk, U1>` and `V` is a function pointer type which is identical to `delegate*<V2..Vk, V1>`, and the\ncalling convention of `U` is identical to `V`, and the refness of `Ui` is identical to `Vi`.\n\nThe first bullet of inference from `Ui` to `Vi` is modified to:\n\n> * If `U` is not a function pointer type and `Ui` is not known to be a reference type, or if `U` is a function pointer type and `Ui` is not known to be\n>   a function pointer type or a reference type, then an _exact inference_ is made\n\nThen added after the 3rd bullet of inference from `Ui` to `Vi`:\n\n> * Otherwise, if `U` is `delegate*<U2..Uk, U1>` then inference depends on the i-th parameter of `delegate*<U2..Uk, U1>`:\n>    * If U1:\n>        * If the return is by value, then an _upper-bound inference_ is made.\n>        * If the return is by reference, then an _exact inference_ is made.\n>    * If U2..Uk:\n>        * If the parameter is by value, then a _lower-bound inference_ is made.\n>        * If the parameter is by reference, then an _exact inference_ is made.\n\n## Metadata representation of `in`, `out`, and `ref readonly` parameters and return types\n\nFunction pointer signatures have no parameter flags location, so we must encode whether parameters and the return type are `in`, `out`, or `ref readonly` by using modreqs.\n\n### `in`\n\nWe reuse `System.Runtime.InteropServices.InAttribute`, applied as a `modreq` to the ref specifier on a parameter or return type, to mean the following:\n* If applied to a parameter ref specifier, this parameter is treated as `in`.\n* If applied to the return type ref specifier, the return type is treated as `ref readonly`.\n\n### `out`\n\nWe use `System.Runtime.InteropServices.OutAttribute`, applied as a `modreq` to the ref specifier on a parameter type, to mean that the parameter is an `out` parameter.\n\n### Errors\n\n* It is an error to apply `OutAttribute` as a modreq to a return type.\n* It is an error to apply both `InAttribute` and `OutAttribute` as a modreq to a parameter type.\n* If either are specified via modopt, they are ignored.\n\n### Metadata Representation of Calling Conventions\n\nCalling conventions are encoded in a method signature in metadata by a combination of the `CallKind` flag in the signature\nand zero or more `modopt`s at the start of the signature. ECMA-335 currently declares the following elements in the\n`CallKind` flag:\n\n```antlr\nCallKind\n   : default\n   | unmanaged cdecl\n   | unmanaged fastcall\n   | unmanaged thiscall\n   | unmanaged stdcall\n   | varargs\n   ;\n```\n\nOf these, function pointers in C# will support all but `varargs`.\n\nIn addition, the runtime (and eventually 335) will be updated to include a new `CallKind` on new platforms. This does\nnot have a formal name currently, but this document will use `unmanaged ext` as a placeholder to stand for the new\nextensible calling convention format. With no `modopt`s, `unmanaged ext` is the platform default calling convention,\n`unmanaged` without the square brackets.\n\n#### Mapping the `calling_convention_specifier` to a `CallKind`\n\nA `calling_convention_specifier` that is omitted, or specified as `managed`, maps to the `default` `CallKind`. This is\ndefault `CallKind` of any method not attributed with `UnmanagedCallersOnly`.\n\nC# recognizes 4 special identifiers that map to specific existing unmanaged `CallKind`s from ECMA 335. In order for this\nmapping to occur, these identifiers must be specified on their own, with no other identifiers, and this requirement is\nencoded into the spec for `unmanaged_calling_convention`s. These identifiers are `Cdecl`, `Thiscall`, `Stdcall`, and\n`Fastcall`, which correspond to `unmanaged cdecl`, `unmanaged thiscall`, `unmanaged stdcall`, and `unmanaged fastcall`,\nrespectively. If more than one `identifer` is specified, or the single `identifier` is not of the specially recognized\nidentifiers, we perform special name lookup on the identifier with the following rules:\n\n* We prepend the `identifier` with the string `CallConv`\n* We look only at types defined in the `System.Runtime.CompilerServices` namespace.\n* We look only at types defined in the core library of the application, which is the library that defines `System.Object`\nand has no dependencies.\n* We look only at public types.\n\nIf lookup succeeds on all of the `identifier`s specified in an `unmanaged_calling_convention`, we encode the `CallKind` as\n`unmanaged ext`, and encode each of the resolved types in the set of `modopt`s at the beginning of the function pointer\nsignature. As a note, these rules mean that users cannot prefix these `identifier`s with `CallConv`, as that will result\nin looking up `CallConvCallConvVectorCall`.\n\nWhen interpreting metadata, we first look at the `CallKind`. If it is anything other than `unmanaged ext`, we ignore all\n`modopt`s on the return type for the purposes of determining the calling convention, and use only the `CallKind`. If the\n`CallKind` is `unmanaged ext`, we look at the modopts at the start of the function pointer type, taking the union of all\ntypes that meet the following requirements:\n\n* The is defined in the core library, which is the library that references no other libraries and defines `System.Object`.\n* The type is defined in the `System.Runtime.CompilerServices` namespace.\n* The type starts with the prefix `CallConv`.\n* The type is public.\n\n These represent the types that must be found when performing lookup on the `identifier`s in an\n`unmanaged_calling_convention` when defining a function pointer type in source.\n\nIt is an error to attempt to use a function pointer with a `CallKind` of `unmanaged ext` if the target runtime does not\nsupport the feature. This will be determined by looking for the presence of the\n`System.Runtime.CompilerServices.RuntimeFeature.UnmanagedCallKind` constant. If this constant is present, the runtime is\nconsidered to support the feature.\n\n### `System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute`\n\n`System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute` is an attribute used by the CLR to indicate that a method\nshould be called with a specific calling convention. Because of this, we introduce the following support for working with\nthe attribute:\n\n* It is an error to directly call a method annotated with this attribute from C#. Users must obtain a function pointer to\nthe method and then invoke that pointer.\n* It is an error to apply the attribute to anything other than an ordinary static method or ordinary static local function.\nThe C# compiler will mark any non-static or static non-ordinary methods imported from metadata with this attribute as\nunsupported by the language.\n* It is an error for a method marked with the attribute to have a parameter or return type that is not an `unmanaged_type`.\n* It is an error for a method marked with the attribute to have type parameters, even if those type parameters are\nconstrained to `unmanaged`.\n* It is an error for a method in a generic type to be marked with the attribute.\n* It is an error to convert a method marked with the attribute to a delegate type.\n* It is an error to specify any types for `UnmanagedCallersOnly.CallConvs` that do not meet the requirements for calling\nconvention `modopt`s in metadata.\n\nWhen determining the calling convention of a method marked with a valid `UnmanagedCallersOnly` attribute, the compiler\nperforms the following checks on the types specified in the `CallConvs` property to determine the effective `CallKind`\nand `modopt`s that should be used to determine the calling convention:\n\n* If no types are specified, the `CallKind` is treated as `unmanaged ext`, with no calling convention `modopt`s at the start\nof the function pointer type.\n* If there is one type specified, and that type is named `CallConvCdecl`, `CallConvThiscall`, `CallConvStdcall`, or\n`CallConvFastcall`, the `CallKind` is treated as `unmanaged cdecl`, `unmanaged thiscall`, `unmanaged stdcall`, or\n`unmanaged fastcall`, respectively, with no calling convention `modopt`s at the start of the function pointer type.\n* If multiple types are specified or the single type is not named one of the specially called out types above, the `CallKind`\nis treated as `unmanaged ext`, with the union of the types specified treated as `modopt`s at the start of the function pointer\ntype.\n\nThe compiler then looks at this effective `CallKind` and `modopt` collection and uses normal metadata rules to determine the\nfinal calling convention of the function pointer type.\n\n## Open Questions\n\n### Detecting runtime support for `unmanaged ext`\n\nhttps://github.com/dotnet/runtime/issues/38135 tracks adding this flag. Depending on the feedback from review, we will either\nuse the property specified in the issue, or use the presence of `UnmanagedCallersOnlyAttribute` as the flag that determines\nwhether the runtimes supports `unmanaged ext`.\n\n## Considerations\n\n### Allow instance methods\n\nThe proposal could be extended to support instance methods by taking advantage of the `EXPLICITTHIS` CLI calling\nconvention (named `instance` in C# code). This form of CLI function pointers puts the `this` parameter as an explicit\nfirst parameter of the function pointer syntax.\n\n``` csharp\nunsafe class Instance {\n    void Use() {\n        delegate* instance<Instance, string> f = &ToString;\n        f(this);\n    }\n}\n```\n\nThis is sound but adds some complication to the proposal. Particularly because function pointers which differed by the\ncalling convention `instance` and `managed` would be incompatible even though both cases are used to invoke managed\nmethods with the same C# signature. Also in every case considered where this would be valuable to have there was a\nsimple work around: use a `static` local function.\n\n``` csharp\nunsafe class Instance {\n    void Use() {\n        static string toString(Instance i) => i.ToString();\n        delegate*<Instance, string> f = &toString;\n        f(this);\n    }\n}\n```\n\n### Don't require unsafe at declaration\n\nInstead of requiring `unsafe` at every use of a `delegate*`, only require it at the point where a method group is\nconverted to a `delegate*`. This is where the core safety issues come into play (knowing that the containing assembly\ncannot be unloaded while the value is alive). Requiring `unsafe` on the other locations can be seen as excessive.\n\nThis is how the design was originally intended. But the resulting language rules felt very awkward. It's impossible to\nhide the fact that this is a pointer value and it kept peeking through even without the `unsafe` keyword. For example\nthe conversion to `object` can't be allowed, it can't be a member of a `class`, etc ... The C# design is to require\n`unsafe` for all pointer uses and hence this design follows that.\n\nDevelopers will still be capable of presenting a _safe_ wrapper on top of `delegate*` values the same way that they do\nfor normal pointer types today. Consider:\n\n``` csharp\nunsafe struct Action {\n    delegate*<void> _ptr;\n\n    Action(delegate*<void> ptr) => _ptr = ptr;\n    public void Invoke() => _ptr();\n}\n```\n\n### Using delegates\n\nInstead of using a new syntax element, `delegate*`, simply use existing `delegate` types with a `*` following the type:\n\n``` csharp\nFunc<object, object, bool>* ptr = &object.ReferenceEquals;\n```\n\nHandling calling convention can be done by annotating the `delegate` types with an attribute that specifies\na `CallingConvention` value. The lack of an attribute would signify the managed calling convention.\n\nEncoding this in IL is problematic. The underlying value needs to be represented as a pointer yet it also must:\n\n1. Have a unique type to allow for overloads with different function pointer types.\n1. Be equivalent for OHI purposes across assembly boundaries.\n\nThe last point is particularly problematic. This mean that every assembly which uses `Func<int>*` must encode\nan equivalent type in metadata even though `Func<int>*` is defined in an assembly though don't control.\nAdditionally any other type which is defined with the name `System.Func<T>` in an assembly that is not mscorlib\nmust be different than the version defined in mscorlib.\n\nOne option that was explored was emitting such a pointer as `mod_req(Func<int>) void*`. This doesn't\nwork though as a `mod_req` cannot bind to a `TypeSpec` and hence cannot target generic instantiations.\n\n### Named function pointers\n\nThe function pointer syntax can be cumbersome, particularly in complex cases like nested function pointers. Rather than\nhave developers type out the signature every time the language could allow for named declarations of function pointers\nas is done with `delegate`.\n\n``` csharp\nfunc* void Action();\n\nunsafe class NamedExample {\n    void M(Action a) {\n        a();\n    }\n}\n```\n\nPart of the problem here is the underlying CLI primitive doesn't have names hence this would be purely a C# invention\nand require a bit of metadata work to enable. That is doable but is a significant about of work. It essentially requires\nC# to have a companion to the type def table purely for these names.\n\nAlso when the arguments for named function pointers were examined we found they could apply equally well to a number of\nother scenarios. For example it would be just as convenient to declare named tuples to reduce the need to type out\nthe full signature in all cases.\n\n``` csharp\n(int x, int y) Point;\n\nclass NamedTupleExample {\n    void M(Point p) {\n        Console.WriteLine(p.x);\n    }\n}\n```\n\nAfter discussion we decided to not allow named declaration of `delegate*` types. If we find there is significant need for\nthis based on customer usage feedback then we will investigate a naming solution that works for function pointers,\ntuples, generics, etc. This is likely to be similar in form to other suggestions like full `typedef` support in\nthe language.\n\n## Future Considerations\n\n### static delegates\n\nThis refers to [the proposal](https://github.com/dotnet/csharplang/issues/302) to allow for the declaration of\n`delegate` types which can only refer to `static` members. The advantage being that such `delegate` instances can be\nallocation free and better in performance sensitive scenarios.\n\nIf the function pointer feature is implemented the `static delegate` proposal will likely be closed out. The proposed\nadvantage of that feature is the allocation free nature. However recent investigations have found that is not possible\nto achieve due to assembly unloading. There must be a strong handle from the `static delegate` to the method it refers\nto in order to keep the assembly from being unloaded out from under it.\n\nTo maintain every `static delegate` instance would be required to allocate a new handle which runs counter to the goals\nof the proposal. There were some designs where the allocation could be amortized to a single allocation per call-site\nbut that was a bit complex and didn't seem worth the trade off.\n\nThat means developers essentially have to decide between the following trade offs:\n\n1. Safety in the face of assembly unloading: this requires allocations and hence `delegate` is already a sufficient\noption.\n1. No safety in face of assembly unloading: use a `delegate*`. This can be wrapped in a `struct` to allow usage outside\nan `unsafe` context in the rest of the code.\n"
  },
  {
    "path": "proposals/csharp-9.0/init.md",
    "content": "# Init Only Setters\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/39>\n\n## Summary\nThis proposal adds the concept of init only properties and indexers to C#. \nThese properties and indexers can be set at the point of object creation \nbut become effectively `get` only once object creation has completed.\nThis allows for a much more flexible immutable model in C#. \n\n## Motivation\nThe underlying mechanisms for building immutable data in C# haven't changed\nsince 1.0. They remain:\n\n1. Declaring fields as `readonly`.\n1. Declaring properties that contain only a `get` accessor.\n\nThese mechanisms are effective at allowing the construction of immutable data\nbut they do so by adding cost to the boilerplate code of types and opting\nsuch types out of features like object and collection initializers. This means\ndevelopers must choose between ease of use and immutability.\n\nA simple immutable object like `Point` requires twice as much boiler plate code\nto support construction as it does to declare the type. The bigger the type \nthe bigger the cost of this boiler plate:\n\n```cs\nstruct Point\n{\n    public int X { get; }\n    public int Y { get; }\n\n    public Point(int x, int y)\n    {\n        this.X = x;\n        this.Y = y;\n    }\n}\n```\n\nThe `init` accessor makes immutable objects more flexible by allowing the\ncaller to mutate the members during the act of construction. That means the\nobject's immutable properties can participate in object initializers and thus\nremoves the need for all constructor boilerplate in the type. The `Point`\ntype is now simply:\n\n```cs\nstruct Point\n{\n    public int X { get; init; }\n    public int Y { get; init; }\n}\n```\n\nThe consumer can then use object initializers to create the object\n\n```cs\nvar p = new Point() { X = 42, Y = 13 };\n```\n\n## Detailed Design\n\n### init accessors\nAn init only property (or indexer) is declared by using the `init` accessor in place of the \n`set` accessor:\n\n```cs\nclass Student\n{\n    public string FirstName { get; init; }\n    public string LastName { get; init; }\n}\n```\n\nAn instance property containing an `init` accessor is considered settable in\nthe following circumstances, except when in a local function or lambda:\n\n- During an object initializer\n- During a `with` expression initializer\n- Inside an instance constructor of the containing or derived type, on `this` or `base`\n- Inside the `init` accessor of any property, on `this` or `base`\n- Inside attribute usages with named parameters\n\nThe times above in which the `init` accessors are settable are collectively\nreferred to in this document as the construction phase of the object.\n\nThis means the `Student` class can be used in the following ways:\n\n```cs\nvar s = new Student()\n{\n    FirstName = \"Jared\",\n    LastName = \"Parosns\",\n};\ns.LastName = \"Parsons\"; // Error: LastName is not settable\n```\n\nThe rules around when `init` accessors are settable extend across type\nhierarchies. If the member is accessible and the object is known to be in the\nconstruction phase then the member is settable. That specifically allows for\nthe following:\n\n```cs\nclass Base\n{\n    public bool Value { get; init; }\n}\n\nclass Derived : Base\n{\n    public Derived()\n    {\n        // Not allowed with get only properties but allowed with init\n        Value = true;\n    }\n}\n\nclass Consumption\n{\n    void Example()\n    {\n        var d = new Derived() { Value = true };\n    }\n}\n\n```\n\nAt the point an `init` accessor is invoked, the instance is known to be \nin the open construction phase. Hence an `init` accessor is allowed to take \nthe following actions in addition to what a normal `set` accessor can do:\n\n1. Call other `init` accessors available through `this` or `base`\n1. Assign `readonly` fields declared on the same type through `this`\n\n```cs\nclass Complex\n{\n    readonly int Field1;\n    int Field2;\n    int Prop1 { get; init; }\n    int Prop2\n    {\n        get => 42;\n        init\n        {\n            Field1 = 13; // okay\n            Field2 = 13; // okay\n            Prop1 = 13; // okay\n        }\n    }\n}\n```\n\nThe ability to assign `readonly` fields from an `init` accessor is limited to \nthose fields declared on the same type as the accessor. It cannot be used to \nassign `readonly` fields in a base type. This rule ensures that type authors\nremain in control over the mutability behavior of their type. Developers who do\nnot wish to utilize `init` cannot be impacted from other types choosing to\ndo so:\n\n```cs\nclass Base\n{\n    internal readonly int Field;\n    internal int Property\n    {\n        get => Field;\n        init => Field = value; // Okay\n    }\n\n    internal int OtherProperty { get; init; }\n}\n\nclass Derived : Base\n{\n    internal readonly int DerivedField;\n    internal int DerivedProperty\n    {\n        get => DerivedField;\n        init\n        {\n            DerivedField = 42;  // Okay\n            Property = 0;       // Okay\n            Field = 13;         // Error Field is readonly\n        }\n    }\n\n    public Derived()\n    {\n        Property = 42;  // Okay \n        Field = 13;     // Error Field is readonly\n    }\n}\n```\n\nWhen `init` is used in a virtual property then all the overrides must also\nbe marked as `init`. Likewise it is not possible to override a simple \n`set` with `init`.\n\n```cs\nclass Base\n{\n    public virtual int Property { get; init; }\n}\n\nclass C1 : Base\n{\n    public override int Property { get; init; }\n}\n\nclass C2 : Base\n{\n    // Error: Property must have init to override Base.Property\n    public override int Property { get; set; }\n}\n```\n\nAn `interface` declaration can also participate in `init` style initialization \nvia the following pattern:\n\n```cs\ninterface IPerson\n{\n    string Name { get; init; }\n}\n\nclass Init\n{\n    void M<T>() where T : IPerson, new()\n    {\n        var local = new T()\n        {\n            Name = \"Jared\"\n        };\n        local.Name = \"Jraed\"; // Error\n    }\n}\n```\n\nRestrictions of this feature:\n- The `init` accessor can only be used on instance properties\n- A property cannot contain both an `init` and `set` accessor\n- All overrides of a property must have `init` if the base had `init`. This rule\nalso applies to interface implementation.\n\n### Readonly structs\n\n`init` accessors (both auto-implemented accessors and manually-implemented\naccessors) are permitted on properties of `readonly struct`s, as well as\n`readonly` properties. `init` accessors are not permitted to be marked\n`readonly` themselves, in both `readonly` and non-`readonly` `struct` types.\n\n```cs\nreadonly struct ReadonlyStruct1\n{\n    public int Prop1 { get; init; } // Allowed\n}\n\nstruct ReadonlyStruct2\n{\n    public readonly int Prop2 { get; init; } // Allowed\n\n    public int Prop3 { get; readonly init; } // Error\n}\n```\n\n### Metadata encoding \nProperty `init` accessors will be emitted as a standard `set` accessor with\nthe return type marked with a modreq of `IsExternalInit`. This is a new type\nwhich will have the following definition:\n\n```cs\nnamespace System.Runtime.CompilerServices\n{\n    public sealed class IsExternalInit\n    {\n    }\n}\n```\n\nThe compiler will match the type by full name. There is no requirement\nthat it appear in the core library. If there are multiple types by this name\nthen the compiler will tie break in the following order:\n\n1. The one defined in the project being compiled\n1. The one defined in corelib\n\nIf neither of these exist then a type ambiguity error will be issued.\n\nThe design for `IsExternalInit` is futher covered in [this issue](https://github.com/dotnet/runtime/issues/34978)\n\n## Questions\n\n### Breaking changes\nOne of the main pivot points in how this feature is encoded will come down to\nthe following question: \n\n> Is it a binary breaking change to replace `init` with `set`?\n\nReplacing `init` with `set` and thus making a property fully writable is never\na source breaking change on a non-virtual property. It simply expands the set\nof scenarios where the property can be written. The only behavior in question is\nwhether or not this remains a binary breaking change.\n\nIf we want to make the change of `init` to `set` a source and binary compatible\nchange then it will force our hand on the modreq vs. attributes decision\nbelow because it will rule out modreqs as a solution. If on the other hand\nthis is seen as a non-interesting then this will make the modreq vs. attribute\ndecision less impactful.\n\n**Resolution**\nThis scenario is not seen as compelling by LDM.\n\n### Modreqs vs. attributes\nThe emit strategy for `init` property accessors must choose between using \nattributes or modreqs when emitting during metadata. These have different \ntrade offs that need to be considered.\n\nAnnotating a property set accessor with a modreq declaration means CLI compliant\ncompilers will ignore the accessor unless it understands the modreq. That means\nonly compilers aware of `init` will read the member. Compilers unaware of \n`init` will ignore the `set` accessor and hence will not accidentally treat the\nproperty as read / write. \n\nThe downside of modreq is `init` becomes a part of the binary signature of \nthe `set` accessor. Adding or removing `init` will break binary compatbility \nof the application.\n\nUsing attributes to annotate the `set` accessor means that only compilers which\nunderstand the attribute will know to limit access to it. A compiler unaware \nof `init` will see it as a simple read / write property and allow access.\n\nThis would seemingly mean this decision is a choice between extra safety at \nthe expense of binary compatibility. Digging in a bit the extra safety is not\nexactly what it seems. It will not protect against the following circumstances:\n\n1. Reflection over `public` members\n1. The use of `dynamic` \n1. Compilers that don't recognize modreqs\n\nIt should also be considered that, when we complete the IL verification rules \nfor .NET 5, `init` will be one of those rules. That means extra enforcement \nwill be gained from simply verifying compilers emitting verifiable IL.\n\nThe primary languages for .NET (C#, F# and VB) will all be updated to \nrecognize these `init` accessors. Hence the only realistic scenario here is \nwhen a C# 9 compiler emits `init` properties and they are seen by an older \ntoolset such as C# 8, VB 15, etc ... C# 8. That is the trade off to consider\nand weigh against binary compatibility.\n\n**Note**\nThis discussion primarily applies to members only, not to fields. While `init`\nfields were rejected by LDM they are still interesting to consider for the \nmodreq vs. attribute discussion. The `init` feature for fields is a relaxation\nof the existing restriction of `readonly`. That means if we emit the fields as\n`readonly` + an attribute there is no risk of older compilers mis-using the \nfield because they would already recognize `readonly`. Hence using a modreq here\ndoesn't add any extra protection.\n\n**Resolution**\nThe feature will use a modreq to encode the property `init` setter. The\ncompelling factors were (in no particular order):\n\n* Desire to discourage older compilers from violating `init` semantics\n* Desire to make adding or removing `init` in a `virtual` declaration or \n`interface` both a source and binary breaking change.\n\nGiven there was also no significant support for removing `init` to be a \nbinary compatible change it made the choice of using modreq straight forward.\n\n### init vs. initonly\nThere were three syntax forms which got significant consideration during our\nLDM meeting:\n\n```cs\n// 1. Use init \nint Option1 { get; init; }\n// 2. Use init set\nint Option2 { get; init set; }\n// 3. Use initonly\nint Option3 { get; initonly; }\n```\n\n**Resolution**\nThere was no syntax which was overwhelmingly favored in LDM.\n\nOne point which got significant attention was how the choice of syntax would\nimpact our ability to do `init` members as a general feature in the future.\nChoosing option 1 would mean that it would be difficult to define a property\nwhich had an `init` style `get` method in the future. Eventually it was decided\nthat if we decided to go forward with general `init` members in future, we could\nallow `init` to be a modifier in the property accessor list as well as a short\nhand for `init set`. Essentially the following two declarations would be\nidentical.\n\n```cs\nint Property1 { get; init; }\nint Property1 { get; init set; }\n```\n\nThe decision was made to move forward with `init` as a standalone accessor in\nthe property accessor list.\n\n### Warn on failed init\nConsider the following scenario. A type declares an `init` only member which\nis not set in the constructor. Should the code which constructs the object \nget a warning if they failed to initialize the value?\n\nAt that point it is clear the field will never be set and hence has a lot of\nsimilarities with the warning around failing to initialize `private` data. \nHence a warning would seemingly have some value here?\n\nThere are significant downsides to this warning though:\n1. It complicates the compatibility story of changing `readonly` to `init`. \n1. It requires carrying additional metadata around to denote the members\nwhich are required to be initialized by the caller.\n\nFurther if we believe there is value here in the overall scenario of forcing\nobject creators to be warned / error'd about specific fields then this \nlikely makes sense as a general feature. There is no reason it should be \nlimited to just `init` members.\n\n**Resolution**\nThere will be no warning on consumption of `init` fields and properties.\n\nLDM wants to have a broader discussion on the idea of required fields and\nproperties. That may cause us to come back and reconsider our position on\n`init` members and validation.\n\n## Allow init as a field modifier\nIn the same way `init` can serve as a property accessor it could also serve as\na designation on fields to give them similar behaviors as `init` properties.\nThat would allow for the field to be assigned before construction was complete\nby the type, derived types, or object initializers.\n\n```cs\nclass Student\n{\n    public init string FirstName;\n    public init string LastName;\n}\n\nvar s = new Student()\n{\n    FirstName = \"Jarde\",\n    LastName = \"Parsons\",\n}\n\ns.FirstName = \"Jared\"; // Error FirstName is readonly\n```\n\nIn metadata these fields would be marked in the same way as `readonly` fields \nbut with an additional attribute or modreq to indicate they are `init` style\nfields. \n\n**Resolution**\nLDM agrees this proposal is sound but overall the scenario felt disjoint from \nproperties. The decision was to proceed only with `init` properties for now. \nThis has a suitable level of flexibility as an `init` property can mutate a \n`readonly` field on the declaring type of the property. This will be\nreconsidered if there is significant customer feedback that justifies the \nscenario.\n\n### Allow init as a type modifier\nIn the same way the `readonly` modifier can be applied to a `struct` to \nautomatically declare all fields as `readonly`, the `init` only modifier can\nbe declared on a `struct` or `class` to automatically mark all fields as `init`.\nThis means the following two type declarations are equivalent:\n\n```cs\nstruct Point\n{\n    public init int X;\n    public init int Y;\n}\n\n// vs. \n\ninit struct Point\n{\n    public int X;\n    public int Y;\n}\n```\n\n**Resolution** \nThis feature is too *cute* here and conflicts with the `readonly struct` \nfeature on which it is based. The `readonly struct` feature is simple in that \nit applies `readonly` to all members: fields, methods, etc ... The \n`init struct` feature would only apply to properties. This actually ends up making\nit confusing for users. \n\nGiven that `init` is only valid on certain aspects of a type, we rejected the \nidea of having it as a type modifier.\n\n## Considerations\n\n### Compatibility\nThe `init` feature is designed to be compatible with existing `get` only \nproperties. Specifically it is meant to be a completely additive change for \na property which is `get` only today but desires more flexbile object creation\nsemantics.\n\nFor example consider the following type:\n\n```cs\nclass Name\n{\n    public string First { get; }\n    public string Last { get; }\n\n    public Name(string first, string last)\n    {\n        First = first;\n        Last = last;\n    }\n}\n```\n\nAdding `init` to these properties is a non-breaking change:\n\n```cs\nclass Name\n{\n    public string First { get; init; }\n    public string Last { get; init; }\n\n    public Name(string first, string last)\n    {\n        First = first;\n        Last = last;\n    }\n}\n```\n\n### IL verification\nWhen .NET Core decides to re-implement IL verification, the rules will need to be \nadjusted to account for `init` members. This will need to be included in the \nrule changes for non-mutating access to `readonly` data.\n\nThe IL verification rules will need to be broken into two parts: \n\n1. Allowing `init` members to set a `readonly` field.\n1. Determining when an `init` member can be legally called.\n\nThe first is a simple adjustment to the existing rules. The IL verifier can \nbe taught to recognize `init` members and from there it just needs to consider\na `readonly` field to be settable on `this` in such a member.\n\nThe second rule is more complicated. In the simple case of object initializers\nthe rule is straight forward. It should be legal to call `init` members when \nthe result of a `new` expression is still on the stack. That is until the \nvalue has been stored in a local, array element or field or passed as an\nargument to another method it will still be legal to call `init` members. This\nensures that once the result of the `new` expression is published to a named\nidentifier (other than `this`) then it will no longer be legal to call `init`\nmembers. \n\nThe more complicated case though is when we mix `init` members, object\ninitializers and `await`. That can cause the newly created object to be\ntemporarily hoisted into a state machine and hence put into a field.\n\n```cs\nvar student = new Student() \n{\n    Name = await SomeMethod()\n};\n```\n\nHere the result of `new Student()` will be hoisted into a state machine as a \nfield before the set of `Name` occurs. The compiler will need to mark such\nhoisted fields in a way that the IL verifier understands they're not user \naccessible and hence doesn't violate the intended semantics of `init`.\n\n### init members\nThe `init` modifier could be extended to apply to all instance members. This \nwould generalize the concept of `init` during object construction and allow\ntypes to declare helper methods that could participate in the construction \nprocess to initialize `init` fields and properties.\n\nSuch members would have all the restrictions that an `init` accessor does\nin this design. The need is questionable though and this can be safely added\nin a future version of the language in a compatible manner.\n\n### Generate three accessors\nOne potential implementation of `init` properties is to make `init` completely\nseparate from `set`. That means that a property can potentially have three \ndifferent accessors: `get`, `set`, and `init`.\n\nThis has the potential advantage of allowing the use of modreq to enforce \ncorrectness while maintaining binary compatibility. The implementation would\nroughly be the following:\n\n1. An `init` accessor is always emitted if there is a `set`. When not defined \nby the developer it is simply a reference to `set`. \n1. The set of a property in an object initializer will always use `init` if \npresent but fall back to `set` if it's missing.\n\nThis means that a developer can always safely delete `init` from a property. \n\nThe downside of this design is that is only useful if `init` is **always** \nemitted when there is a `set`. The language can't know if `init` was deleted\nin the past, it has to assume it was and hence the `init` must always be\nemitted. That would cause a significant metadata expansion and is simply not\nworth the cost of the compatibility here.\n"
  },
  {
    "path": "proposals/csharp-9.0/lambda-discard-parameters.md",
    "content": "# Lambda discard parameters\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/111>\n\n## Summary\n\nAllow discards (`_`) to be used as parameters of lambdas and anonymous methods.\nFor example:\n- lambdas: `(_, _) => 0`, `(int _, int _) => 0`\n- anonymous methods: `delegate(int _, int _) { return 0; }`\n\n## Motivation\n\nUnused parameters do not need to be named. The intent of discards is clear, i.e. they are unused/discarded.\n\n## Detailed design\n\nMethod parameters - [§15.6.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#1562-method-parameters)\nIn the parameter list of a lambda or anonymous method with more than one parameter named `_`, such parameters are discard parameters.\nNote: if a single parameter is named `_` then it is a regular parameter for backwards compatibility reasons.\n\nDiscard parameters do not introduce any names to any scopes.\nNote this implies they do not cause any `_` (underscore) names to be hidden.\n\nSimple names ([§12.8.4](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1284-simple-names))\nIf `K` is zero and the *simple_name* appears within a *block* and if the *block*'s (or an enclosing *block*'s) local variable declaration space (Declarations - [§7.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/basic-concepts.md#73-declarations)) contains a local variable, parameter (with the exception of discard parameters) or constant with name `I`, then the *simple_name* refers to that local variable, parameter or constant and is classified as a variable or value.\n\nScopes - [§7.7](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/basic-concepts.md#77-scopes)\nWith the exception of discard parameters, the scope of a parameter declared in a *lambda_expression* ([§12.19](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1219-anonymous-function-expressions)) is the *anonymous_function_body* of that *lambda_expression*\nWith the exception of discard parameters, the scope of a parameter declared in an *anonymous_method_expression* ([§12.19](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1219-anonymous-function-expressions)) is the *block* of that *anonymous_method_expression*.\n\n## Related spec sections\n- Corresponding parameters - [§12.6.2.2](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12622-corresponding-parameters)\n"
  },
  {
    "path": "proposals/csharp-9.0/local-function-attributes.md",
    "content": "# Attributes on local functions\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/1888>\n\n## Attributes\n\nLocal function declarations are now permitted to have attributes ([§22](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/attributes.md#22-attributes)). Parameters and type parameters on local functions are also allowed to have attributes.\n\nAttributes with a specified meaning when applied to a method, its parameters, or its type parameters will have the same meaning when applied to a local function, its parameters, or its type parameters, respectively.\n\nA local function can be made conditional in the same sense as a conditional method ([§22.5.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/attributes.md#2253-the-conditional-attribute)) by decorating it with a `[ConditionalAttribute]`. A conditional local function must also be `static`. All restrictions on conditional methods also apply to conditional local functions, including that the return type must be `void`.\n\n## Extern\n\nThe `extern` modifier is now permitted on local functions. This makes the local function external in the same sense as an external method ([§15.6.8](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#1468-external-methods)).\n\nSimilarly to an external method, the *local-function-body* of an external local function must be a semicolon. A semicolon *local-function-body* is only permitted on an external local function. \n\nAn external local function must also be `static`.\n\n## Syntax\n\nThe [§13.6.4](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md#1364-local-function-declarations), or [local functions grammar](../csharp-7.0/local-functions.md#syntax-grammar) is modified as follows:\n\n```\nlocal-function-header\n    : attributes? local-function-modifiers? return-type identifier type-parameter-list?\n        ( formal-parameter-list? ) type-parameter-constraints-clauses\n    ;\n\nlocal-function-modifiers\n    : (async | unsafe | static | extern)*\n    ;\n\nlocal-function-body\n    : block\n    | arrow-expression-body\n    | ';'\n    ;\n```\n"
  },
  {
    "path": "proposals/csharp-9.0/module-initializers.md",
    "content": "# Module Initializers\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/2608>\n\n## Summary\n[summary]: #summary\n\nAlthough the .NET platform has a [feature](https://github.com/dotnet/runtime/blob/master/docs/design/specs/Ecma-335-Augments.md#module-initializer) that directly supports writing initialization code for the assembly (technically, the module), it is not exposed in C#.  This is a rather niche scenario, but once you run into it the solutions appear to be pretty painful.  There are reports of [a number of customers](https://www.google.com/search?q=.net+module+constructor+c%23&oq=.net+module+constructor) (inside and outside Microsoft) struggling with the problem, and there are no doubt more undocumented cases.\n\n## Motivation\n[motivation]: #motivation\n\n- Enable libraries to do eager, one-time initialization when loaded, with minimal overhead and without the user needing to explicitly call anything\n- One particular pain point of current `static` constructor approaches is that the runtime must do additional checks on usage of a type with a static constructor, in order to decide whether the static constructor needs to be run or not. This adds measurable overhead.\n- Enable source generators to run some global initialization logic without the user needing to explicitly call anything\n\n## Detailed design\n[design]: #detailed-design\n\nA method can be designated as a module initializer by decorating it with a `[ModuleInitializer]` attribute.\n\n```cs\nusing System;\nnamespace System.Runtime.CompilerServices\n{\n    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]\n    public sealed class ModuleInitializerAttribute : Attribute { }\n}\n```\n\nThe attribute can be used like this:\n\n```cs\nusing System.Runtime.CompilerServices;\nclass C\n{\n    [ModuleInitializer]\n    internal static void M1()\n    {\n        // ...\n    }\n}\n```\n\nSome requirements are imposed on the method targeted with this attribute:\n1. The method must be `static`.\n1. The method must be parameterless.\n1. The method must return `void`.\n1. The method must not be generic or be contained in a generic type.\n1. The method must be accessible from the containing module.\n    - This means the method's effective accessibility must be `internal` or `public`.\n    - This also means the method cannot be a local function.\n    \nWhen one or more valid methods with this attribute are found in a compilation, the compiler will emit a module initializer which calls each of the attributed methods. The calls will be emitted in a reserved, but deterministic order.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nWhy should we *not* do this?\n\n- Perhaps the existing third-party tooling for \"injecting\" module initializers is sufficient for users who have been asking for this feature.\n\n## Design meetings\n\n### [April 8th, 2020](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-04-08.md#module-initializers)\n"
  },
  {
    "path": "proposals/csharp-9.0/native-integers.md",
    "content": "# Native-sized integers\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/435>\n\n## Summary\n[summary]: #summary\n\nLanguage support for a native-sized signed and unsigned integer types.\n\nThe motivation is for interop scenarios and for low-level libraries.\n\n## Design\n[design]: #design\n\nThe identifiers `nint` and `nuint` are new contextual keywords that represent native signed and unsigned integer types.\nThe identifiers are only treated as keywords when name lookup does not find a viable result at that program location.\n```C#\nnint x = 3;\n_ = nint.Equals(x, 3);\n```\n\nThe types `nint` and `nuint` are represented by the underlying types `System.IntPtr` and `System.UIntPtr` with compiler surfacing additional conversions and operations for those types as native ints.\n\n### Constants\n\nConstant expressions may be of type `nint` or `nuint`.\nThere is no direct syntax for native int literals. Implicit or explicit casts of other integral constant values can be used instead: `const nint i = (nint)42;`.\n\n`nint` constants are in the range [ `int.MinValue`, `int.MaxValue` ].\n\n`nuint` constants are in the range [ `uint.MinValue`, `uint.MaxValue` ].\n\nThere are no `MinValue` or `MaxValue` fields on `nint` or `nuint` because, other than `nuint.MinValue`, those values cannot be emitted as constants.\n\nConstant folding is supported for all unary operators { `+`, `-`, `~` } and binary operators { `+`, `-`, `*`, `/`, `%`, `==`, `!=`, `<`, `<=`, `>`, `>=`, `&`, `|`, `^`, `<<`, `>>` }.\nConstant folding operations are evaluated with `Int32` and `UInt32` operands rather than native ints for consistent behavior regardless of compiler platform.\nIf the operation results in a constant value in 32-bits, constant folding is performed at compile-time.\nOtherwise the operation is executed at runtime and not considered a constant.\n\n### Conversions\nThere is an identity conversion between `nint` and `IntPtr`, and between `nuint` and `UIntPtr`.\nThere is an identity conversion between compound types that differ by native ints and underlying types only: arrays, `Nullable<>`, constructed types, and tuples.\n\nThe tables below cover the conversions between special types.\n(The IL for each conversion includes the variants for `unchecked` and `checked` contexts if different.)\n\nGeneral notes on the table below:\n- `conv.u` is a zero-extending conversion to native integer and `conv.i` is sign-extending conversion to native integer.\n- `checked` contexts for both **widening** and **narrowing** are:\n  - `conv.ovf.*` for `signed to *`\n  - `conv.ovf.*.un` for `unsigned to *`\n- `unchecked` contexts for **widening** are:\n  - `conv.i*` for `signed to *` (where * is the target width)\n  - `conv.u*` for `unsigned to *` (where * is the target width)\n- `unchecked` contexts for **narrowing** are:\n  - `conv.i*` for `any to signed *` (where * is the target width)\n  - `conv.u*` for `any to unsigned *` (where * is the target width)\n\nTaking a few examples:\n- `sbyte to nint` and `sbyte to nuint` use `conv.i` while `byte to nint` and `byte to nuint` use `conv.u` because they are all **widening**.\n- `nint to byte` and `nuint to byte` use `conv.u1` while `nint to sbyte` and `nuint to sbyte` use `conv.i1`. For `byte`, `sbyte`, `short`, and `ushort` the \"stack type\" is `int32`. So `conv.i1` is effectively \"downcast to a signed byte and then sign-extend up to int32\" while `conv.u1` is effectively \"downcast to an unsigned byte and then zero-extend up to int32\".\n- `checked void* to nint` uses `conv.ovf.i.un` the same way that `checked void* to long` uses `conv.ovf.i8.un`.\n\n| Operand | Target | Conversion | IL |\n|:---:|:---:|:---:|:---:|\n| `object` | `nint` | Unboxing | `unbox` |\n| `void*` | `nint` | PointerToVoid | nop / `conv.ovf.i.un` |\n| `sbyte` | `nint` | ImplicitNumeric | `conv.i` |\n| `byte` | `nint` | ImplicitNumeric | `conv.u` |\n| `short` | `nint` | ImplicitNumeric | `conv.i` |\n| `ushort` | `nint` | ImplicitNumeric | `conv.u` |\n| `int` | `nint` | ImplicitNumeric | `conv.i` |\n| `uint` | `nint` | ExplicitNumeric | `conv.u` / `conv.ovf.i.un` |\n| `long` | `nint` | ExplicitNumeric | `conv.i` / `conv.ovf.i` |\n| `ulong` | `nint` | ExplicitNumeric | `conv.i` / `conv.ovf.i.un` |\n| `char` | `nint` | ImplicitNumeric | `conv.u` |\n| `float` | `nint` | ExplicitNumeric | `conv.i` / `conv.ovf.i` |\n| `double` | `nint` | ExplicitNumeric | `conv.i` / `conv.ovf.i` |\n| `decimal` | `nint` | ExplicitNumeric | `long decimal.op_Explicit(decimal) conv.i` / `... conv.ovf.i` |\n| `IntPtr` | `nint` | Identity | |\n| `UIntPtr` | `nint` | None | |\n| | | | |\n| `object` | `nuint` | Unboxing | `unbox` |\n| `void*` | `nuint` | PointerToVoid | nop |\n| `sbyte` | `nuint` | ExplicitNumeric | `conv.i` / `conv.ovf.u` |\n| `byte` | `nuint` | ImplicitNumeric | `conv.u` |\n| `short` | `nuint` | ExplicitNumeric | `conv.i` / `conv.ovf.u` |\n| `ushort` | `nuint` | ImplicitNumeric | `conv.u` |\n| `int` | `nuint` | ExplicitNumeric | `conv.i` / `conv.ovf.u` |\n| `uint` | `nuint` | ImplicitNumeric | `conv.u` |\n| `long` | `nuint` | ExplicitNumeric | `conv.u` / `conv.ovf.u` |\n| `ulong` | `nuint` | ExplicitNumeric | `conv.u` / `conv.ovf.u.un` |\n| `char` | `nuint` | ImplicitNumeric | `conv.u` |\n| `float` | `nuint` | ExplicitNumeric | `conv.u` / `conv.ovf.u` |\n| `double` | `nuint` | ExplicitNumeric | `conv.u` / `conv.ovf.u` |\n| `decimal` | `nuint` | ExplicitNumeric | `ulong decimal.op_Explicit(decimal) conv.u` / `... conv.ovf.u.un`  |\n| `IntPtr` | `nuint` | None | |\n| `UIntPtr` | `nuint` | Identity | |\n|Enumeration|`nint`|ExplicitEnumeration||\n|Enumeration|`nuint`|ExplicitEnumeration||\n\n| Operand | Target | Conversion | IL |\n|:---:|:---:|:---:|:---:|\n| `nint` | `object` | Boxing | `box` |\n| `nint` | `void*` | PointerToVoid | nop / `conv.ovf.u` |\n| `nint` | `nuint` | ExplicitNumeric | `conv.u` (can be omitted) / `conv.ovf.u` |\n| `nint` | `sbyte` | ExplicitNumeric | `conv.i1` / `conv.ovf.i1` |\n| `nint` | `byte` | ExplicitNumeric | `conv.u1` / `conv.ovf.u1` |\n| `nint` | `short` | ExplicitNumeric | `conv.i2` / `conv.ovf.i2` |\n| `nint` | `ushort` | ExplicitNumeric | `conv.u2` / `conv.ovf.u2` |\n| `nint` | `int` | ExplicitNumeric | `conv.i4` / `conv.ovf.i4` |\n| `nint` | `uint` | ExplicitNumeric | `conv.u4` / `conv.ovf.u4` |\n| `nint` | `long` | ImplicitNumeric | `conv.i8` |\n| `nint` | `ulong` | ExplicitNumeric | `conv.i8` / `conv.ovf.u8` |\n| `nint` | `char` | ExplicitNumeric | `conv.u2` / `conv.ovf.u2` |\n| `nint` | `float` | ImplicitNumeric | `conv.r4` |\n| `nint` | `double` | ImplicitNumeric | `conv.r8` |\n| `nint` | `decimal` | ImplicitNumeric | `conv.i8 decimal decimal.op_Implicit(long)` |\n| `nint` | `IntPtr` | Identity | |\n| `nint` | `UIntPtr` | None | |\n| `nint` |Enumeration|ExplicitEnumeration||\n| | | | |\n| `nuint` | `object` | Boxing | `box` |\n| `nuint` | `void*` | PointerToVoid | nop |\n| `nuint` | `nint` | ExplicitNumeric | `conv.i`(can be omitted) / `conv.ovf.i.un` |\n| `nuint` | `sbyte` | ExplicitNumeric | `conv.i1` / `conv.ovf.i1.un` |\n| `nuint` | `byte` | ExplicitNumeric | `conv.u1` / `conv.ovf.u1.un` |\n| `nuint` | `short` | ExplicitNumeric | `conv.i2` / `conv.ovf.i2.un` |\n| `nuint` | `ushort` | ExplicitNumeric | `conv.u2` / `conv.ovf.u2.un` |\n| `nuint` | `int` | ExplicitNumeric | `conv.i4` / `conv.ovf.i4.un` |\n| `nuint` | `uint` | ExplicitNumeric | `conv.u4` / `conv.ovf.u4.un` |\n| `nuint` | `long` | ExplicitNumeric | `conv.u8` / `conv.ovf.i8.un` |\n| `nuint` | `ulong` | ImplicitNumeric | `conv.u8` |\n| `nuint` | `char` | ExplicitNumeric | `conv.u2` / `conv.ovf.u2.un` |\n| `nuint` | `float` | ImplicitNumeric | `conv.r.un conv.r4` |\n| `nuint` | `double` | ImplicitNumeric | `conv.r.un conv.r8` |\n| `nuint` | `decimal` | ImplicitNumeric | `conv.u8 decimal decimal.op_Implicit(ulong)` |\n| `nuint` | `IntPtr` | None | |\n| `nuint` | `UIntPtr` | Identity | |\n| `nuint` |Enumeration|ExplicitEnumeration||\n\nConversion from `A` to `Nullable<B>` is:\n- an implicit nullable conversion if there is an identity conversion or implicit conversion from `A` to `B`;\n- an explicit nullable conversion if there is an explicit conversion from `A` to `B`;\n- otherwise invalid.\n\nConversion from `Nullable<A>` to `B` is:\n- an explicit nullable conversion if there is an identity conversion or implicit or explicit numeric conversion from `A` to `B`;\n- otherwise invalid.\n\nConversion from `Nullable<A>` to `Nullable<B>` is:\n- an identity conversion if there is an identity conversion from `A` to `B`;\n- an explicit nullable conversion if there is an implicit or explicit numeric conversion from `A` to `B`;\n- otherwise invalid.\n\n### Operators\n\nThe predefined operators are as follows.\nThese operators are considered during overload resolution based on normal rules for implicit conversions _if at least one of the operands is of type `nint` or `nuint`_.\n\n(The IL for each operator includes the variants for `unchecked` and `checked` contexts if different.)\n\n| Unary | Operator Signature | IL |\n|:---:|:---:|:---:|\n| `+` | `nint operator +(nint value)` | `nop` |\n| `+` | `nuint operator +(nuint value)` | `nop` |\n| `-` | `nint operator -(nint value)` | `neg` |\n| `~` | `nint operator ~(nint value)` | `not` |\n| `~` | `nuint operator ~(nuint value)` | `not` |\n\n| Binary | Operator Signature | IL |\n|:---:|:---:|:---:|\n| `+` | `nint operator +(nint left, nint right)` | `add` / `add.ovf` |\n| `+` | `nuint operator +(nuint left, nuint right)` | `add` / `add.ovf.un` |\n| `-` | `nint operator -(nint left, nint right)` | `sub` / `sub.ovf` |\n| `-` | `nuint operator -(nuint left, nuint right)` | `sub` / `sub.ovf.un` |\n| `*` | `nint operator *(nint left, nint right)` | `mul` / `mul.ovf` |\n| `*` | `nuint operator *(nuint left, nuint right)` | `mul` / `mul.ovf.un` |\n| `/` | `nint operator /(nint left, nint right)` | `div` |\n| `/` | `nuint operator /(nuint left, nuint right)` | `div.un` |\n| `%` | `nint operator %(nint left, nint right)` | `rem` |\n| `%` | `nuint operator %(nuint left, nuint right)` | `rem.un` |\n| `==` | `bool operator ==(nint left, nint right)` | `beq` / `ceq` |\n| `==` | `bool operator ==(nuint left, nuint right)` | `beq` / `ceq` |\n| `!=` | `bool operator !=(nint left, nint right)` | `bne` |\n| `!=` | `bool operator !=(nuint left, nuint right)` | `bne` |\n| `<` | `bool operator <(nint left, nint right)` | `blt` / `clt` |\n| `<` | `bool operator <(nuint left, nuint right)` | `blt.un` / `clt.un` |\n| `<=` | `bool operator <=(nint left, nint right)` | `ble` |\n| `<=` | `bool operator <=(nuint left, nuint right)` | `ble.un` |\n| `>` | `bool operator >(nint left, nint right)` | `bgt` / `cgt` |\n| `>` | `bool operator >(nuint left, nuint right)` | `bgt.un` / `cgt.un` |\n| `>=` | `bool operator >=(nint left, nint right)` | `bge` |\n| `>=` | `bool operator >=(nuint left, nuint right)` | `bge.un` |\n| `&` | `nint operator &(nint left, nint right)` | `and` |\n| `&` | `nuint operator &(nuint left, nuint right)` | `and` |\n| <code>&#124;</code> | <code>nint operator &#124;(nint left, nint right)</code> | `or` |\n| <code>&#124;</code> | <code>nuint operator &#124;(nuint left, nuint right)</code> | `or` |\n| `^` | `nint operator ^(nint left, nint right)` | `xor` |\n| `^` | `nuint operator ^(nuint left, nuint right)` | `xor` |\n| `<<` | `nint operator <<(nint left, int right)` | `shl` |\n| `<<` | `nuint operator <<(nuint left, int right)` | `shl` |\n| `>>` | `nint operator >>(nint left, int right)` | `shr` |\n| `>>` | `nuint operator >>(nuint left, int right)` | `shr.un` |\n\nFor some binary operators, the IL operators support additional operand types\n(see [ECMA-335](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/) III.1.5 Operand type table).\nBut the set of operand types supported by C# is limited for simplicity and for consistency with existing operators in the language.\n\nLifted versions of the operators, where the arguments and return types are `nint?` and `nuint?`, are supported.\n\nCompound assignment operations `x op= y` where `x` or `y` are native ints follow the same rules as with other primitive types with pre-defined operators.\nSpecifically the expression is bound as `x = (T)(x op y)` where `T` is the type of `x` and where `x` is only evaluated once.\n\nThe shift operators should mask the number of bits to shift - to 5 bits if `sizeof(nint)` is 4, and to 6 bits if `sizeof(nint)` is 8.\n(see [§12.11](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1211-shift-operators)) in C# spec).\n\nThe C#9 compiler will report errors binding to predefined native integer operators when compiling with an earlier language version,\nbut will allow use of predefined conversions to and from native integers.\n\n`csc -langversion:9 -t:library A.cs`\n```C#\npublic class A\n{\n    public static nint F;\n}\n```\n\n`csc -langversion:8 -r:A.dll B.cs`\n```C#\nclass B : A\n{\n    static void Main()\n    {\n        F = F + 1; // error: nint operator+ not available with -langversion:8\n        F = (System.IntPtr)F + 1; // ok\n    }\n}\n```\n\n### Pointer arithmetic\nThere are no predefined operators in C# for pointer addition or subtraction with native integer offsets.\nInstead, `nint` and `nuint` values are promoted to `long` and `ulong` and pointer arithmetic uses predefined operators for those types.\n```C#\nstatic T* AddLeftS(nint x, T* y) => x + y;   // T* operator +(long left, T* right)\nstatic T* AddLeftU(nuint x, T* y) => x + y;  // T* operator +(ulong left, T* right)\nstatic T* AddRightS(T* x, nint y) => x + y;  // T* operator +(T* left, long right)\nstatic T* AddRightU(T* x, nuint y) => x + y; // T* operator +(T* left, ulong right)\nstatic T* SubRightS(T* x, nint y) => x - y;  // T* operator -(T* left, long right)\nstatic T* SubRightU(T* x, nuint y) => x - y; // T* operator -(T* left, ulong right)\n```\n\n### Binary numeric promotions\nThe _binary numeric promotions_ informative text (see [§12.4.7.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12473-binary-numeric-promotions)) in C# spec) is updated as follows:\n\n> -   …\n> -   Otherwise, if either operand is of type `ulong`, the other operand is converted to type `ulong`, or a binding-time error occurs if the other operand is of type `sbyte`, `short`, `int`, **`nint`**, or `long`.\n> -   **Otherwise, if either operand is of type `nuint`, the other operand is converted to type `nuint`, or a binding-time error occurs if the other operand is of type `sbyte`, `short`, `int`, `nint`, or `long`.**\n> -   Otherwise, if either operand is of type `long`, the other operand is converted to type `long`.\n> -   Otherwise, if either operand is of type `uint` and the other operand is of type `sbyte`, `short`, **`nint`,** or `int`, both operands are converted to type `long`.\n> -   Otherwise, if either operand is of type `uint`, the other operand is converted to type `uint`.\n> -   **Otherwise, if either operand is of type `nint`, the other operand is converted to type `nint`.**\n> -   Otherwise, both operands are converted to type `int`.\n\n### Dynamic\n\nThe conversions and operators are synthesized by the compiler and are not part of the underlying `IntPtr` and `UIntPtr` types.\nAs a result those conversions and operators _are not available_ from the runtime binder for `dynamic`. \n\n```C#\nnint x = 2;\nnint y = x + x; // ok\ndynamic d = x;\nnint z = d + x; // RuntimeBinderException: '+' cannot be applied 'System.IntPtr' and 'System.IntPtr'\n```\n\n### Type members\n\nThe only constructor for `nint` or `nuint` is the parameter-less constructor.\n\nThe following members of `System.IntPtr` and `System.UIntPtr` _are explicitly excluded_ from `nint` or `nuint`:\n```C#\n// constructors\n// arithmetic operators\n// implicit and explicit conversions\npublic static readonly IntPtr Zero; // use 0 instead\npublic static int Size { get; }     // use sizeof() instead\npublic static IntPtr Add(IntPtr pointer, int offset);\npublic static IntPtr Subtract(IntPtr pointer, int offset);\npublic int ToInt32();\npublic long ToInt64();\npublic void* ToPointer();\n```\n\nThe remaining members of `System.IntPtr` and `System.UIntPtr` _are implicitly included_ in `nint` and `nuint`. For .NET Framework 4.7.2:\n```C#\npublic override bool Equals(object obj);\npublic override int GetHashCode();\npublic override string ToString();\npublic string ToString(string format);\n```\n\nInterfaces implemented by `System.IntPtr` and `System.UIntPtr` _are implicitly included_ in `nint` and `nuint`,\nwith occurrences of the underlying types replaced by the corresponding native integer types.\nFor instance if `IntPtr` implements `ISerializable, IEquatable<IntPtr>, IComparable<IntPtr>`,\nthen `nint` implements `ISerializable, IEquatable<nint>, IComparable<nint>`.\n\n### Overriding, hiding, and implementing\n\n`nint` and `System.IntPtr`, and `nuint` and `System.UIntPtr`, are considered equivalent for overriding, hiding, and implementing.\n\nOverloads cannot differ by `nint` and `System.IntPtr`, and `nuint` and `System.UIntPtr`, alone.\nOverrides and implementations may differ by `nint` and `System.IntPtr`, or `nuint` and `System.UIntPtr`, alone.\nMethods hide other methods that differ by `nint` and `System.IntPtr`, or `nuint` and `System.UIntPtr`, alone.\n\n### Miscellaneous\n\n`nint` and `nuint` expressions used as array indices are emitted without conversion.\n```C#\nstatic object GetItem(object[] array, nint index)\n{\n    return array[index]; // ok\n}\n```\n\n`nint` and `nuint` cannot be used as an `enum` base type from C#.\n```C#\nenum E : nint // error: byte, sbyte, short, ushort, int, uint, long, or ulong expected\n{\n}\n```\n\nReads and writes are atomic for `nint` and `nuint`.\n\nFields may be marked `volatile` for types `nint` and `nuint`.\n[ECMA-334](https://www.ecma-international.org/publications-and-standards/standards/ecma-334/) 15.5.4 does not include `enum` with base type `System.IntPtr` or `System.UIntPtr` however.\n\n`default(nint)` and `new nint()` are equivalent to `(nint)0`; `default(nuint)` and `new nuint()` are equivalent to `(nuint)0`.\n\n`typeof(nint)` is `typeof(IntPtr)`; `typeof(nuint)` is `typeof(UIntPtr)`.\n\n`sizeof(nint)` and `sizeof(nuint)` are supported but require compiling in an unsafe context (as required for `sizeof(IntPtr)` and `sizeof(UIntPtr)`).\nThe values are not compile-time constants.\n`sizeof(nint)` is implemented as `sizeof(IntPtr)` rather than `IntPtr.Size`; `sizeof(nuint)` is implemented as `sizeof(UIntPtr)` rather than `UIntPtr.Size`.\n\nCompiler diagnostics for type references involving `nint` or `nuint` report `nint` or `nuint` rather than `IntPtr` or `UIntPtr`.\n\n### Metadata\n\n`nint` and `nuint` are represented in metadata as `System.IntPtr` and `System.UIntPtr`.\n\nType references that include `nint` or `nuint` are emitted with a `System.Runtime.CompilerServices.NativeIntegerAttribute` to indicate which parts of the type reference are native ints.\n\n```C#\nnamespace System.Runtime.CompilerServices\n{\n    [AttributeUsage(\n        AttributeTargets.Class |\n        AttributeTargets.Event |\n        AttributeTargets.Field |\n        AttributeTargets.GenericParameter |\n        AttributeTargets.Parameter |\n        AttributeTargets.Property |\n        AttributeTargets.ReturnValue,\n        AllowMultiple = false,\n        Inherited = false)]\n    public sealed class NativeIntegerAttribute : Attribute\n    {\n        public NativeIntegerAttribute()\n        {\n            TransformFlags = new[] { true };\n        }\n        public NativeIntegerAttribute(bool[] flags)\n        {\n            TransformFlags = flags;\n        }\n        public readonly bool[] TransformFlags;\n    }\n}\n```\n\nThe encoding of type references with `NativeIntegerAttribute` is covered in [NativeIntegerAttribute.md](https://github.com/dotnet/roslyn/blob/master/docs/features/NativeIntegerAttribute.md).\n\n## Alternatives\n[alternatives]: #alternatives\n\nAn alternative to the \"type erasure\" approach above is to introduce new types: `System.NativeInt` and `System.NativeUInt`.\n```C#\npublic readonly struct NativeInt\n{\n    public IntPtr Value;\n}\n```\nDistinct types would allow overloading distinct from `IntPtr` and would allow distinct parsing and `ToString()`.\nBut there would be more work for the CLR to handle these types efficiently which defeats the primary purpose of the feature - efficiency.\nAnd interop with existing native int code that uses `IntPtr` would be more difficult. \n\nAnother alternative is to add more native int support for `IntPtr` in the framework but without any specific compiler support.\nAny new conversions and arithmetic operations would be supported by the compiler automatically.\nBut the language would not provide keywords, constants, or `checked` operations.\n\n## Design meetings\n\n- https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-05-26.md\n- https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-06-13.md\n- https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-07-05.md#native-int-and-intptr-operators\n- https://github.com/dotnet/csharplang/blob/master/meetings/2019/LDM-2019-10-23.md\n- https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-03-25.md\n"
  },
  {
    "path": "proposals/csharp-9.0/nullable-constructor-analysis.md",
    "content": "# Nullable constructor analysis\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/3297>\n\nThis proposal is intended to resolve a few of the outstanding problems with nullable constructor analysis.\n\nThis proposal was accepted on [2020-07-27](https://github.com/dotnet/csharplang/blob/main/meetings/2020/LDM-2020-07-27.md#improved-nullable-analysis-in-constructors).\n\n## Problems with the definite-assignment based approach\n\nNullable analysis of constructors works by essentially running a definite assignment pass and reporting a warning if a constructor does not initialize a non-nullable reference type member (for example: a field, auto-property, or field-like event) in all code paths. The constructor is otherwise treated like an ordinary method for analysis purposes. This approach comes with a few problems.\n\nFirst is that the initial flow state of members is not accurate:\n\n```cs\npublic class C\n{\n    public string Prop { get; set; }\n    public C() // we get no \"uninitialized member\" warning, as expected\n    {\n        Prop.ToString(); // unexpectedly, there is no \"possible null receiver\" warning here\n        Prop = \"\";\n    }\n}\n```\n\nAnother is that assertions/'throw' statements do not prevent field initialization warnings:\n\n```cs\npublic class C\n{\n    public string Prop { get; set; }\n    public C() // unexpected warning: 'Prop' is not initialized\n    {\n        Init();\n\n        if (Prop is null)\n        {\n            throw new Exception();\n        }\n    }\n\n    void Init()\n    {\n        Prop = \"some default\";\n    }\n}\n```\n\n## Proposed approach\n\nWe can address this by instead taking an approach similar to `[MemberNotNull]` analysis, where fields are marked maybe-null and a warning is given if we ever exit the method when a field is still in a maybe-null state. We can do this by introducing the following rules:\n\n**A constructor on a reference type with no initializer** *or*  \n**A constructor on a reference type with a `: base(...)` initializer** has an initial nullable flow state determined by:\n- Initializing base type members to their declared state, since we expect the base constructor to initialize the base members.\n- Then initializing all *applicable members* in the type to the state given by assigning a `default` literal to the member. A member is applicable if:\n  - It does not have oblivious nullability, *and*\n  - It is instance and the constructor being analyzed is instance, or the member is static and the constructor being analyzed is static.\n  - We expect the `default` literal to yield a `NotNull` state for non-nullable value types, a `MaybeNull` state for reference types or nullable value types, and a `MaybeDefault` state for unconstrained generics.\n- Then visiting the initializers for the applicable members, updating the flow state accordingly.\n  - This allows some non-nullable reference members to be initialized using a field/property initializer, and others to be initialized within the constructor.\n  - The expectation is that the compiler will flow-analyze and report diagnostics on the initializers once, then copy the resulting flow state as the initial state for each constructor which does not have a `: this(...)` initializer.\n\n**A constructor on a value type with a `: this()` initializer referencing the default value type constructor** has an initial flow state given by initializing all applicable members to the state given by assigning a `default` literal to the member.\n\n**A constructor on a reference type with a `: this(...)` initializer** *or*  \n**A constructor on a value type with an initializer not referencing the default value type constructor** *or*  \n**A constructor on a value type with no initializer** has the same initial nullable flow state as an ordinary method.  \nMembers have an initial state based on the declared annotations and nullability attributes. In the case of value types, we expect definite assignment analysis to provide the desired level of safety when there is no `: this(...)` initializer. This is the same as the existing behavior.\n\n**At each explicit or implicit 'return' in a constructor**, we give a warning for each *applicable member* whose flow state is incompatible with its annotations and nullability attributes. A reasonable proxy for this is: if assigning the member to itself at the return point would produce a nullability warning, then a nullability warning will be produced at the return point.\n\nIt's possible this could result in a lot of warnings for the same members in some scenarios. As a \"stretch goal\" I think we should consider the following \"optimizations\":\n- If a member has an incompatible flow state at all return points in an applicable constructor, we warn on the constructor's name syntax instead of on each return point individually.\n- If a member has an incompatible flow state at all return points in all applicable constructors, we warn on the member declaration itself.\n\n## Consequences of this approach\n\n```cs\npublic class C\n{\n    public string Prop { get; set; }\n    public C()\n    {\n        Prop = null; // Warning: cannot assign null to 'Prop'\n    } // Warning: Prop may be null when exiting 'C.C()'\n    \n    // This is consistent with currently shipped behavior:\n    [MemberNotNull(nameof(Prop))]\n    void M()\n    {\n        Prop = null; // Warning: cannot assign null to 'Prop'\n    } // Warning: Prop may be null when exiting 'C.M()'\n}\n```\n\nThe above scenario produces multiple warnings corresponding to the same property. If there are more return points in the method, indefinitely many warnings could be produced depending on the number of return points in which a member has a bad flow state.\n\nHowever, this is consistent with the behavior we have shipped for `[MemberNotNull]` and `[NotNull]` attributes: we warn when a bad value goes in, and we warn again when you return where the variable could contain a bad value.\n\n---\n\n```cs\npublic class C\n{\n    public string Prop { get; set; }\n    public C()\n    {\n        Prop.ToString(); // Warning: dereference of a possible null reference.\n    } // No warning: Prop's flow state was 'promoted' to NotNull after dereference\n    \n    // This is also consistent with currently shipped behavior:\n    [MemberNotNull(nameof(Prop))]\n    void M()\n    {\n        Prop.ToString(); // Warning: dereference of a possible null reference.\n    } // No warning: Prop's flow state was 'promoted' to NotNull after dereference\n}\n```\n\nIn this scenario we never really initialize `Prop`, but we know that if we return normally from this constructor then Prop must have somehow gotten initialized. Thus this warning, while not ideal, does seem to be adequate for pointing the user toward where their problem lies.\n\nSimilarly, this is consistent with the shipped behavior of `[MemberNotNull]` and `[NotNull]`.\n\n---\n\n```cs\nclass C\n{\n    string Prop1 { get; set; }\n    string Prop2 { get; set; }\n\n    public C(bool a)\n    {\n        if (a)\n        {\n            Prop1 = \"hello\";\n            return; // warning for Prop2\n        }\n        else\n        {\n            return; // warning for Prop1 and for Prop2\n        }\n    }\n}\n```\n\nThis scenario demonstrates the independence of warnings at each return point, as well as the way warnings can multiply for a single member within a single constructor. It feels like there might be methods of reducing redundancy of the warnings, but this refinement could come later and improve `[MemberNotNull]`/`[NotNull]` analysis at the same time. For constructors with complex conditional logic, it does seem to be an improvement to say \"at this return, you haven't initialized something yet\" versus simply saying \"somewhere in here, you didn't initialize something\".\n"
  },
  {
    "path": "proposals/csharp-9.0/nullable-parameter-default-value-analysis.md",
    "content": "# Nullable Parameter Default Value Analysis\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/3297>\n\n## Analysis of declarations\n\nIn a method declaration it's desirable for the compiler to give warnings for parameter default values which are incompatible with the parameter's type.\n\n```cs\nvoid M(string s = null) // warning CS8600: Converting null literal or possible null value to non-nullable type.\n{\n}\n```\n\nHowever, unconstrained generics present a problem where a bad value can go in but we don't warn about it for compat reasons. Therefore we adopted a strategy of simulating a assignment of the default value to the parameter in the method body, then joining in the resulting state, giving us the desired warnings in the method signature as well as the desired initial nullable state for the parameter.\n\n```cs\nclass C<T>\n{\n    void M0(T t) { }\n\n    void M1(T t = default) // no warning here\n    {\n        M0(t); // warning CS8604: Possible null reference argument for parameter 't' in 'void C<T>.M0(T t)'.\n    }\n}\n```\n\nIt's difficult to update the parameter initial state appropriately in all scenarios. Here are some scenarios where the approach falls over:\n\n### [Overriding methods with optional parameters](https://github.com/dotnet/roslyn/issues/48848)\n```cs\nBase<string> obj = new Override();\nobj.M(); // throws NRE at runtime\n\npublic class Base<T>\n{\n    public virtual void M(T t = default) { } // no warning\n}\n\npublic class Override : Base<string>\n{\n    public override void M(string s)\n    {\n        s.ToString(); // no warning today, but something in this sample ought to warn. :)\n    }\n}\n```\nIn the above sample we may call the method `Base<string>.M()` and dispatch to `Override.M()`. We need to account for the possibility that the caller implicitly provided `null` as an argument for `s` via the base, but currently we do not do so.\n\n---\n\n### [Lambda conversion to delegates which have optional parameters](https://github.com/dotnet/roslyn/issues/48844)\n```cs\npublic delegate void Del<T>(T t = default);\n\npublic class C\n{\n    public static void Main()\n    {\n        Del<string> del = str => str.ToString(); // expected warning, but didn't get one\n        del(); // throws NRE at runtime\n    }\n}\n```\nIn the above sample we expect that a lambda converted to the type `Del<string>` will have a `MaybeNull` initial state for its parameter because of the default value. Currently we don't handle this case properly.\n\n---\n\n### [Abstract methods and delegate declarations which have optional parameters](https://github.com/dotnet/roslyn/issues/48847)\n```cs\npublic abstract class C\n{\n    public abstract void M1(string s = null); // expected warning, but didn't get one\n}\n\ninterface I\n{\n    void M1(string s = null); // expected warning, but didn't get one\n}\n\npublic delegate void Del1(string s = null); // expected warning, but didn't get one\n```\nIn the above sample, we want warnings on these parameters which aren't directly associated with any method implementation. However, since these parameter lists don't have any methods with bodies that we want to flow analyze, we never hit the EnterParameters method in NullableWalker which simulates the assignments and produces the warnings.\n\n---\n\n### Indexers with get and set accessors\n```cs\npublic class C\n{\n    public int this[int i, string s = null] // no warning here\n    {\n        get // entire accessor syntax has warning CS8600: Converting null literal or possible null value to non-nullable type.\n        {\n            return i;\n        }\n\n        set // entire accessor syntax has warning CS8600: Converting null literal or possible null value to non-nullable type.\n        {\n        }\n    }\n}\n```\nThis last sample is just an annoyance. Here we synthesize a distinct parameter symbol for each accessor, whose location is the entire accessor syntax. We simulate the default value assignment in each accessor and give a warning on the parameter, which ends up giving duplicate warnings that don't really show where the problem is.\n\n## Suggested change to declaration analysis\n\n**We shouldn't update the parameter's initial state in flow analysis based on the default value.** It introduces strange complexity and missing warnings around overriding, delegate conversions, etc. that is not worth accounting for, and would cause user confusion if we did account for them. Revisiting the overriding sample from above:\n\n```cs\npublic class Base<T>\n{\n    public virtual void M(T t = default) { } // let's start warning here\n}\n\npublic class Override : Base<string>\n{\n    public override void M(string s)\n    {\n        s.ToString(); // let's not warn here\n    }\n}\n```\nAs a user you'd probably find a warning on `s.ToString()` confusing and useless--the thing that's broken here is the incompatibility of the type and default value in `T t = default`, and that's where user's fix needs to go.\n\n**Instead, we should enforce that the default value is compatible with the parameter in all scenarios, including unconstrained generics.** I am certain that this is how we should do it in `/langversion:9` in VS 16.9. I also believe that we should do this in `/langversion:8` under the \"bug fix\" umbrella. `[AllowNull]` can be applied to unconstrained generic parameters to allow `default` as a default value, so C# 8 users are not blocked. I could be convinced otherwise about doing it in `/langversion:8` depending on the impact.\n\nAs far as implementation strategy: we should just do this in SourceComplexParameterSymbol at the same time we bind the parameter's default value. We can ensure sufficient amount of consistency, as well as reasonable handling of suppression, perhaps by creating a NullableWalker and doing a \"mini-analysis\" of the assignment of the default value whose final state is discarded.\n\n"
  },
  {
    "path": "proposals/csharp-9.0/nullable-reference-types-specification.md",
    "content": "﻿# Nullable Reference Types Specification\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\n> ***The portions of this feature that were part of C# 8 have been incorporated into the standard. See:***\n>\n> - [§6.5.9 Nullable directive](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/lexical-structure.md#659-nullable-directive)\n> - [§8.4.5 Satisfying constraints](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/types.md#845-satisfying-constraints)\n> - [§8.9 Reference Types and nullability](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/types.md#89-reference-types-and-nullability)\n> - [§10.2.6 Implicit nullable conversions](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#1026-implicit-nullable-conversions)\n> - [§10.3.4 Explicit nullable conversions](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#1034-explicit-nullable-conversions)\n> - [§12.8.9 Null-forgiving expressions](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1289-null-forgiving-expressions)\n> - [§15.2.5 Type parameter constraints](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#1525-type-parameter-constraints)\n> - [§22.5.7 Code analysis attributes](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/attributes.md#2257-code-analysis-attributes)\n>\n> Those areas include the majority of this feature. The notable exception is the [`default` constraint](#default-constraint). This document contains much more detail on the implementation of nullable analysis provided by the roslyn compiler.\n\nThis feature adds two new kinds of nullable types (nullable reference types and nullable generic types) to the existing nullable value types, and introduces a static flow analysis for purpose of null-safety.\n\n## Syntax\n\n### Nullable reference types and nullable type parameters\n\nNullable reference types and nullable type parameters have the same syntax `T?` as the short form of nullable value types, but do not have a corresponding long form.\n\nFor the purposes of the specification, the current `nullable_type` production is renamed to `nullable_value_type`, and `nullable_reference_type` and `nullable_type_parameter` productions are added:\n\n```antlr\ntype\n    : value_type\n    | reference_type\n    | nullable_type_parameter\n    | type_parameter\n    | type_unsafe\n    ;\n\nreference_type\n    : ...\n    | nullable_reference_type\n    ;\n\nnullable_reference_type\n    : non_nullable_reference_type '?'\n    ;\n\nnon_nullable_reference_type\n    : reference_type\n    ;\n\nnullable_type_parameter\n    : non_nullable_non_value_type_parameter '?'\n    ;\n\nnon_nullable_non_value_type_parameter\n    : type_parameter\n    ;\n```\n\nThe `non_nullable_reference_type` in a `nullable_reference_type` must be a nonnullable reference type (class, interface, delegate or array).\n\nThe `non_nullable_non_value_type_parameter` in `nullable_type_parameter` must be a type parameter that isn't constrained to be a value type.\n\nNullable reference types and nullable type parameters cannot occur in the following positions:\n\n- as a base class or interface\n- as the receiver of a `member_access`\n- as the `type` in an `object_creation_expression`\n- as the `delegate_type` in a `delegate_creation_expression`\n- as the `type` in an `is_expression`, a `catch_clause` or a `type_pattern`\n- as the `interface` in a fully qualified interface member name\n\nA warning is given on a `nullable_reference_type` and `nullable_type_parameter` in a *disabled* nullable annotation context.\n\n### `class` and `class?` constraint\n\nThe `class` constraint has a nullable counterpart `class?`:\n\n```antlr\nprimary_constraint\n    : ...\n    | 'class' '?'\n    ;\n```\n\nA type parameter constrained with `class` (in an *enabled* annotation context) must be instantiated with a nonnullable reference type.\n\nA type parameter constrained with `class?` (or `class` in a *disabled* annotation context) may either be instantiated with a nullable or nonnullable reference type.\n\nA warning is given on a `class?` constraint in a *disabled* annotation context.\n\nThe behavior of `?` annotations on type parameters that aren't constrained to be either a `struct` or `class` is covered in [Unconstrained type parameter annotations](unconstrained-type-parameter-annotations.md#-annotation).\n\n### `notnull` constraint\n\nA type parameter constrained with `notnull` may not be a nullable type (nullable value type, nullable reference type or nullable type parameter).\n\n```antlr\nprimary_constraint\n    : ...\n    | 'notnull'\n    ;\n```\n\n### `default` constraint\n\nThe `default` constraint can be used on a method override or explicit implementation to disambiguate `T?` meaning \"nullable type parameter\" from \"nullable value type\" (`Nullable<T>`). Lacking the `default` constraint a `T?` syntax in an override or explicit implementation will be interpreted as `Nullable<T>`\n\nSee [Unconstrained type parameter annotations](unconstrained-type-parameter-annotations.md#default-constraint).\n\n### The null-forgiving operator\n\nThe post-fix `!` operator is called the null-forgiving operator. It can be applied on a *primary_expression* or within a *null_conditional_expression*:\n\n```antlr\nprimary_expression\n    : ...\n    | null_forgiving_expression\n    ;\n\nnull_forgiving_expression\n    : primary_expression '!'\n    ;\n\nnull_conditional_expression\n    : primary_expression null_conditional_operations_no_suppression suppression?\n    ;\n\nnull_conditional_operations_no_suppression\n    : null_conditional_operations? '?' '.' identifier type_argument_list?\n    | null_conditional_operations? '?' '[' argument_list ']'\n    | null_conditional_operations '.' identifier type_argument_list?\n    | null_conditional_operations '[' argument_list ']'\n    | null_conditional_operations '(' argument_list? ')'\n    ;\n\nnull_conditional_operations\n    : null_conditional_operations_no_suppression suppression?\n    ;\n\nsuppression\n    : '!'\n    ;\n```\n\nFor example:\n\n```csharp\nvar v = expr!;\nexpr!.M();\n_ = a?.b!.c;\n```\n\nThe postfix `!` operator has no runtime effect - it evaluates to the result of the underlying expression. Its only role is to change the null state of the expression to \"not null\", and to limit warnings given on its use.\n\n### Nullable compiler directives\n\n`#nullable` directives control the nullable annotation and warning contexts.\n\n```antlr\npp_directive\n    : ...\n    | pp_nullable\n    ;\n\npp_nullable\n    : whitespace? '#' whitespace? 'nullable' whitespace nullable_action (whitespace nullable_target)? pp_new_line\n    ;\n\nnullable_action\n    : 'disable'\n    | 'enable'\n    | 'restore'\n    ;\n\nnullable_target\n    : 'warnings'\n    | 'annotations'\n    ;\n```\n\n`#pragma warning` directives are expanded to allow changing the nullable warning context:\n\n```antlr\npragma_warning_body\n    : ...\n    | 'warning' whitespace warning_action whitespace 'nullable'\n    ;\n```\n\nFor example:\n\n```csharp\n#pragma warning disable nullable\n```\n\n## Nullable contexts\n\nEvery line of source code has a *nullable annotation context* and a *nullable warning context*. These control whether nullable annotations have effect, and whether nullability warnings are given. The annotation context of a given line is either *disabled* or *enabled*. The warning context of a given line is either *disabled* or *enabled*.\n\nBoth contexts can be specified at the project level (outside of C# source code), or anywhere within a source file via `#nullable` pre-processor directives. If no project level settings are provided the default is for both contexts to be *disabled*.\n\nThe `#nullable` directive controls the annotation and warning contexts within the source text, and take precedence over the project-level settings.\n\nA directive sets the context(s) it controls for subsequent lines of code, until another directive overrides it, or until the end of the source file.\n\nThe effect of the directives is as follows:\n\n- `#nullable disable`: Sets the nullable annotation and warning contexts to *disabled*\n- `#nullable enable`: Sets the nullable annotation and warning contexts to *enabled*\n- `#nullable restore`: Restores the nullable annotation and warning contexts to project settings\n- `#nullable disable annotations`: Sets the nullable annotation context to *disabled*\n- `#nullable enable annotations`: Sets the nullable annotation context to *enabled*\n- `#nullable restore annotations`: Restores the nullable annotation context to project settings\n- `#nullable disable warnings`: Sets the nullable warning context to *disabled*\n- `#nullable enable warnings`: Sets the nullable warning context to *enabled*\n- `#nullable restore warnings`: Restores the nullable warning context to project settings\n\n## Nullability of types\n\nA given type can have one of three nullabilities: *oblivious*, *nonnullable*, and *nullable*.\n\n*Nonnullable* types may cause warnings if a potential `null` value is assigned to them. *Oblivious* and *nullable* types, however, are \"*null-assignable*\" and can have `null` values assigned to them without warnings.\n\nValues of *oblivious* and *nonnullable* types can be dereferenced or assigned without warnings. Values of *nullable* types, however, are \"*null-yielding*\" and may cause warnings when dereferenced or assigned without proper null checking.\n\nThe *default null state* of a null-yielding type is \"maybe null\" or \"maybe default\". The default null state of a non-null-yielding type is \"not null\".\n\nThe kind of type and the nullable annotation context it occurs in determine its nullability:\n\n- A nonnullable value type `S` is always *nonnullable*\n- A nullable value type `S?` is always *nullable*\n- An unannotated reference type `C` in a *disabled* annotation context is *oblivious*\n- An unannotated reference type `C` in an *enabled* annotation context is *nonnullable*\n- A nullable reference type `C?` is *nullable* (but a warning may be yielded in a *disabled* annotation context)\n\nType parameters additionally take their constraints into account:\n\n- A type parameter `T` where all constraints (if any) are either nullable types or the `class?` constraint is *nullable*\n- A type parameter `T` where at least one constraint is either *oblivious* or *nonnullable* or one of the `struct` or `class` or `notnull` constraints is\n    - *oblivious* in a *disabled* annotation context\n    - *nonnullable* in an *enabled* annotation context\n- A nullable type parameter `T?` is *nullable*, but a warning is yielded in a *disabled* annotation context if `T` isn't a value type\n\n### Oblivious vs nonnullable\n\nA `type` is deemed to occur in a given annotation context when the last token of the type is within that context.\n\nWhether a given reference type `C` in source code is interpreted as oblivious or nonnullable depends on the annotation context of that source code. But once established, it is considered part of that type, and \"travels with it\" e.g. during substitution of generic type arguments. It is as if there is an annotation like `?` on the type, but invisible.\n\n## Constraints\n\nNullable reference types can be used as generic constraints.\n\n`class?` is a new constraint denoting \"possibly nullable reference type\", whereas `class` in an *enabled* annotation context denotes \"nonnullable reference type\".\n\n`default` is a new constraint denoting a type parameter that isn't known to be a reference or value type. It can only be used on overridden and explicitly implemented methods. With this constraint, `T?` means a nullable type parameter, as opposed to being a shorthand for `Nullable<T>`.\n\n`notnull` is a new constraint denoting a type parameter that is nonnullable.\n\nThe nullability of a type argument or of a constraint does not impact whether the type satisfies the constraint, except where that is already the case today (nullable value types do not satisfy the `struct` constraint). However, if the type argument does not satisfy the nullability requirements of the constraint, a warning may be given.\n\n## Null state and null tracking\n\nEvery expression in a given source location has a *null state*, which indicated whether it is believed to potentially evaluate to null. The null state is either \"not null\", \"maybe null\", or \"maybe default\". The null state is used to determine whether a warning should be given about null-unsafe conversions and dereferences.\n\nThe distinction between \"maybe null\" and \"maybe default\" is subtle and applies to type parameters. The distinction is that a type parameter `T` which has the state \"maybe null\" means the value is in the domain of legal values for `T` however that legal value may include `null`. Where as a \"maybe default\" means that the value may be outside the legal domain of values for `T`. \n\nExample: \n\n```c#\n// The value `t` here has the state \"maybe null\". It's possible for `T` to be instantiated\n// with `string?` in which case `null` would be within the domain of legal values here. The \n// assumption though is the value provided here is within the legal values of `T`. Hence \n// if `T` is `string` then `null` will not be a value, just as we assume that `null` is not\n// provided for a normal `string` parameter\nvoid M<T>(T t)\n{\n    // There is no guarantee that default(T) is within the legal values for T hence the \n    // state *must* be \"maybe-default\" and hence `local` must be `T?`\n    T? local = default(T);\n}\n```\n\n### Null tracking for variables\n\nFor certain expressions denoting variables, fields or properties, the null state is tracked between occurrences, based on assignments to them, tests performed on them and the control flow between them. This is similar to how definite assignment is tracked for variables. The tracked expressions are the ones of the following form:\n\n```antlr\ntracked_expression\n    : simple_name\n    | this\n    | base\n    | tracked_expression '.' identifier\n    ;\n```\n\nWhere the identifiers denote fields or properties.\n\nThe null state for tracked variables is \"not null\" in unreachable code. This follows other decisions around unreachable code like considering all locals to be definitely assigned.\n\n***Describe null state transitions similar to definite assignment***\n\n### Null state for expressions\n\nThe null state of an expression is derived from its form and type, and from the null state of variables involved in it.\n\n### Literals\n\nThe null state of a `null` literal depends on the target type of the expression. If the target type is a type parameter constrained to a reference type then it's \"maybe default\". Otherwise it is \"maybe null\".\n\nThe null state of a `default` literal depends on the target type of the `default` literal. A `default` literal with target type `T` has the same null state as the `default(T)` expression.\n\nThe null state of any other literal is \"not null\".\n\n### Simple names\n\nIf a `simple_name` is not classified as a value, its null state is \"not null\". Otherwise it is a tracked expression, and its null state is its tracked null state at this source location.\n\n### Member access\n\nIf a `member_access` is not classified as a value, its null state is \"not null\". Otherwise, if it is a tracked expression, its null state is its tracked null state at this source location. Otherwise its null state is the default null state of its type.\n\n```c#\nvar person = new Person();\n\n// The receiver is a tracked expression hence the member_access of the property \n// is tracked as well \nif (person.FirstName is not null)\n{\n    Use(person.FirstName);\n}\n\n// The return of an invocation is not a tracked expression hence the member_access\n// of the return is also not tracked\nif (GetAnonymous().FirstName is not null)\n{\n    // Warning: Cannot convert null literal to non-nullable reference type.\n    Use(GetAnonymous().FirstName);\n}\n\nvoid Use(string s) \n{ \n    // ...\n}\n\npublic class Person\n{\n    public string? FirstName { get; set; }\n    public string? LastName { get; set; }\n\n    private static Person s_anonymous = new Person();\n    public static Person GetAnonymous() => s_anonymous;\n}\n```\n\n### Invocation expressions\n\nIf an `invocation_expression` invokes a member that is declared with one or more attributes for special null behavior, the null state is determined by those attributes. Otherwise the null state of the expression is the default null state of its type.\n\nThe null state of an `invocation_expression` is not tracked by the compiler.\n\n```c#\n\n// The result of an invocation_expression is not tracked\nif (GetText() is not null)\n{\n    // Warning: Converting null literal or possible null value to non-nullable type.\n    string s = GetText();\n    // Warning: Dereference of a possibly null reference.\n    Use(s);\n}\n\n// Nullable friendly pattern\nif (GetText() is string s)\n{\n    Use(s);\n}\n\nstring? GetText() => ... \nUse(string s) {  }\n```\n\n### Element access\n\nIf an `element_access` invokes an indexer that is declared with one or more attributes for special null behavior, the null state is determined by those attributes. Otherwise the null state of the expression is the default null state of its type.\n\n```c#\nobject?[] array = ...;\nif (array[0] != null)\n{\n    // Warning: Converting null literal or possible null value to non-nullable type.\n    object o = array[0];\n    // Warning: Dereference of a possibly null reference.\n    Console.WriteLine(o.ToString());\n}\n\n// Nullable friendly pattern\nif (array[0] is {} o)\n{\n    Console.WriteLine(o.ToString());\n}\n```\n\n### Base access\n\nIf `B` denotes the base type of the enclosing type, `base.I` has the same null state as `((B)this).I` and `base[E]` has the same null state as `((B)this)[E]`.\n\n### Default expressions\n\n`default(T)` has the null state based on the properties of the type `T`:\n\n- If the type is a *nonnullable* type then it has the null state \"not null\"\n- Else if the type is a type parameter then it has the null state \"maybe default\"\n- Else it has the null state \"maybe null\"\n\n### Null-conditional expressions ?.\n\nA `null_conditional_expression` has the null state based on the expression type. Note that this refers to the type of the `null_conditional_expression`, not the original type of the member being invoked:\n\n- If the type is a *nullable* value type then it has the null state \"maybe null\"\n- Else if the type is a *nullable* type parameter then it has the null state \"maybe default\"\n- Else it has the null state \"maybe null\"\n\n### Cast expressions\n\nIf a cast expression `(T)E` invokes a user-defined conversion, then the null state of the expression is the default null state for the type of the user-defined conversion. Otherwise:\n\n- If `T` is a *nonnullable* value type then `T` has the null state \"not null\"\n- Else if `T` is a *nullable* value type then `T` has the null state \"maybe null\"\n- Else if `T` is a *nullable* type in the form `U?` where `U` is a type parameter then `T` has the null state \"maybe default\"\n- Else if `T` is a *nullable* type, and `E` has null state \"maybe null\" or \"maybe default\", then `T` has the null state \"maybe null\"\n- Else if `T` is a type parameter, and `E` has null state \"maybe null\" or \"maybe default\", then `T` has the null state \"maybe default\"\n- Else `T` has the same null state as `E`\n\n### Unary and binary operators\n\nIf a unary or binary operator invokes an user-defined operator then the null state of the expression is the default null state for the type of the user-defined operator. Otherwise it is the null state of the expression.\n\n***Something special to do for binary `+` over strings and delegates?***\n\n### Await expressions\n\nThe null state of `await E` is the default null state of its type.\n\n### The `as` operator\n\nThe null state of an `E as T` expression depends first on properties of the type `T`. If the type of `T` is *nonnullable* then the null state is \"not null\". Otherwise the null state depends on the conversion from the type of `E` to type `T`:\n\n- If the conversion is an identity, boxing, implicit reference, or implicit nullable conversion, then the null state is the null state of `E`\n- Else if `T` is a type parameter then it has the null state \"maybe default\"\n- Else it has the null state \"maybe null\"\n\n### The null-coalescing operator\n\nThe null state of `E1 ?? E2` is the null state of `E2`\n\n### The conditional operator\n\nThe null state of `E1 ? E2 : E3` is based on the null state of `E2` and `E3`:\n\n- If both are \"not null\" then the null state is \"not null\"\n- Else if either is \"maybe default\" then the null state is \"maybe default\"\n- Else the null state is \"not null\"\n\n### Query expressions\n\nThe null state of a query expression is the default null state of its type.\n\n*Additional work needed here*\n\n### Assignment operators\n\n`E1 = E2` and `E1 op= E2` have the same null state as `E2` after any implicit conversions have been applied.\n\n### Expressions that propagate null state\n\n`(E)`, `checked(E)` and `unchecked(E)` all have the same null state as `E`.\n\n### Expressions that are never null\n\nThe null state of the following expression forms is always \"not null\":\n\n- `this` access\n- interpolated strings\n- `new` expressions (object, delegate, anonymous object and array creation expressions)\n- `typeof` expressions\n- `nameof` expressions\n- anonymous functions (anonymous methods and lambda expressions)\n- null-forgiving expressions\n- `is` expressions\n\n### Nested functions\n\nNested functions (lambdas and local functions) are treated like methods, except in regards to their captured variables.\nThe initial state of a captured variable inside a lambda or local function is the intersection of the nullable state\nof the variable at all the \"uses\" of that nested function or lambda. A use of a local function is either a call to that \nfunction, or where it is converted to a delegate. A use of a lambda is the point at which it is defined in source.\n\n## Type inference\n\n### nullable implicitly typed local variables\n\n`var` infers an annotated type for reference types, and type parameters that aren't constrained to be a value type.\nFor instance:\n- in `var s = \"\";` the `var` is inferred as `string?`.\n- in `var t = new T();` with an unconstrained `T` the `var` is inferred as `T?`.\n\n### Generic type inference\n\nGeneric type inference is enhanced to help decide whether inferred reference types should be nullable or not. This is a best effort. It may yield warnings regarding nullability constraints, and may lead to nullable warnings when the inferred types of the selected overload are applied to the arguments.\n\n### The first phase\n\nNullable reference types flow into the bounds from the initial expressions, as described below. In addition, two new kinds of bounds, namely `null` and `default` are introduced. Their purpose is to carry through occurrences of `null` or `default` in the input expressions, which may cause an inferred type to be nullable, even when it otherwise wouldn't.\n\nThe determination of what bounds to add in the first phase are enhanced as follows:\n\nIf an argument `Ei` has a reference type, the type `U` used for inference depends on the null state of `Ei` as well as its declared type:\n- If the declared type is a nonnullable reference type `U0` or a nullable reference type `U0?` then\n    - if the null state of `Ei` is \"not null\" then `U` is `U0`\n    - if the null state of `Ei` is \"maybe null\" then `U` is `U0?`\n- Otherwise if `Ei` has a declared type, `U` is that type\n- Otherwise if `Ei` is `null` then `U` is the special bound `null`\n- Otherwise if `Ei` is `default` then `U` is the special bound `default`\n- Otherwise no inference is made.\n\n### Exact, upper-bound and lower-bound inferences\n\nIn inferences *from* the type `U` *to* the type `V`, if `V` is a nullable reference type `V0?`, then `V0` is used instead of `V` in the following clauses.\n- If `V` is one of the unfixed type variables, `U` is added as an exact, upper or lower bound as before\n- Otherwise, if `U` is `null` or `default`, no inference is made\n- Otherwise, if `U` is a nullable reference type `U0?`, then `U0` is used instead of `U` in the subsequent clauses.\n\nThe essence is that nullability that pertains directly to one of the unfixed type variables is preserved into its bounds. For the inferences that recurse further into the source and target types, on the other hand, nullability is ignored. It may or may not match, but if it doesn't, a warning will be issued later if the overload is chosen and applied.\n\n### Fixing\n\nThe spec currently does not do a good job of describing what happens when multiple bounds are identity convertible to each other, but are different. This may happen between `object` and `dynamic`, between tuple types that differ only in element names, between types constructed thereof and now also between `C` and `C?` for reference types.\n\nIn addition we need to propagate \"nullness\" from the input expressions to the result type.\n\nTo handle these we add more phases to fixing, which is now:\n\n1. Gather all the types in all the bounds as candidates, removing `?` from all that are nullable reference types\n2. Eliminate candidates based on requirements of exact, lower and upper bounds (keeping `null` and `default` bounds)\n3. Eliminate candidates that do not have an implicit conversion to all the other candidates\n4. If the remaining candidates do not all have identity conversions to one another, then type inference fails\n5. *Merge* the remaining candidates as described below\n6. If the resulting candidate is a reference type and *all* of the exact bounds or *any* of the lower bounds are nullable reference types, `null` or `default`, then `?` is added to the resulting candidate, making it a nullable reference type.\n\n*Merging* is described between two candidate types. It is transitive and commutative, so the candidates can be merged in any order with the same ultimate result. It is undefined if the two candidate types are not identity convertible to each other.\n\nThe *Merge* function takes two candidate types and a direction (*+* or *-*):\n\n- *Merge*(`T`, `T`, *d*) = T\n- *Merge*(`S`, `T?`, *+*) = *Merge*(`S?`, `T`, *+*) = *Merge*(`S`, `T`, *+*)`?`\n- *Merge*(`S`, `T?`, *-*) = *Merge*(`S?`, `T`, *-*) = *Merge*(`S`, `T`, *-*)\n- *Merge*(`C<S1,...,Sn>`, `C<T1,...,Tn>`, *+*) = `C<`*Merge*(`S1`, `T1`, *d1*)`,...,`*Merge*(`Sn`, `Tn`, *dn*)`>`, *where*\n    - `di` = *+* if the `i`'th type parameter of `C<...>` is covariant\n    - `di` = *-* if the `i`'th type parameter of `C<...>` is contra- or invariant\n- *Merge*(`C<S1,...,Sn>`, `C<T1,...,Tn>`, *-*) = `C<`*Merge*(`S1`, `T1`, *d1*)`,...,`*Merge*(`Sn`, `Tn`, *dn*)`>`, *where*\n    - `di` = *-* if the `i`'th type parameter of `C<...>` is covariant\n    - `di` = *+* if the `i`'th type parameter of `C<...>` is contra- or invariant\n- *Merge*(`(S1 s1,..., Sn sn)`, `(T1 t1,..., Tn tn)`, *d*) = `(`*Merge*(`S1`, `T1`, *d*)`n1,...,`*Merge*(`Sn`, `Tn`, *d*) `nn)`, *where*\n    - `ni` is absent if `si` and `ti` differ, or if both are absent\n    - `ni` is `si` if `si` and `ti` are the same\n- *Merge*(`object`, `dynamic`) = *Merge*(`dynamic`, `object`) = `dynamic`\n\n## Warnings\n\n### Potential null assignment\n\n### Potential null dereference\n\n### Constraint nullability mismatch\n\n### Nullable types in disabled annotation context\n\n### Override and implementation nullability mismatch\n\n## Attributes for special null behavior\n\n"
  },
  {
    "path": "proposals/csharp-9.0/patterns3.md",
    "content": "﻿# Pattern-matching changes for C# 9.0\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nWe are considering a small handful of enhancements to pattern-matching for C# 9.0 that have natural synergy and work well to address a number of common programming problems:\n- https://github.com/dotnet/csharplang/issues/2925 Type patterns\n- https://github.com/dotnet/csharplang/issues/1350 Parenthesized patterns to enforce or emphasize precedence of the new combinators\n- https://github.com/dotnet/csharplang/issues/1350 Conjunctive `and` patterns that require both of two different patterns to match;\n- https://github.com/dotnet/csharplang/issues/1350 Disjunctive `or` patterns that require either of two different patterns to match;\n- https://github.com/dotnet/csharplang/issues/1350 Negated `not` patterns that require a given pattern *not* to match; and\n- https://github.com/dotnet/csharplang/issues/812 Relational patterns that require the input value to be less than, less than or equal to, etc a given constant.\n\n## Parenthesized Patterns\n\nParenthesized patterns permit the programmer to put parentheses around any pattern.  This is not so useful with the existing patterns in C# 8.0, however the new pattern combinators introduce a precedence that the programmer may want to override.\n\n```antlr\nprimary_pattern\n    : parenthesized_pattern\n    | // all of the existing forms\n    ;\nparenthesized_pattern\n    : '(' pattern ')'\n    ;\n```\n\n## Type Patterns\n\nWe permit a type as a pattern:\n\n``` antlr\nprimary_pattern\n    : type-pattern\n    | // all of the existing forms\n    ;\ntype_pattern\n    : type\n    ;\n```\n\nThis retcons the existing *is-type-expression* to be an *is-pattern-expression* in which the pattern is a *type-pattern*, though we would not change the syntax tree produced by the compiler.\n\nOne subtle implementation issue is that this grammar is ambiguous.  A string such as `a.b` can be parsed either as a qualified name (in a type context) or a dotted expression (in an expression context).  The compiler is already capable of treating a qualified name the same as a dotted expression in order to handle something like `e is Color.Red`.  The compiler's semantic analysis would be further extended to be capable of binding a (syntactic) constant pattern (e.g. a dotted expression) as a type in order to treat it as a bound type pattern in order to support this construct.\n\nAfter this change, you would be able to write\n```csharp\nvoid M(object o1, object o2)\n{\n    var t = (o1, o2);\n    if (t is (int, string)) {} // test if o1 is an int and o2 is a string\n    switch (o1) {\n        case int: break; // test if o1 is an int\n        case System.String: break; // test if o1 is a string\n    }\n}\n```\n\n## Relational Patterns\n\nRelational patterns permit the programmer to express that an input value must satisfy a relational constraint when compared to a constant value:\n\n``` C#\n    public static LifeStage LifeStageAtAge(int age) => age switch\n    {\n        < 0 =>  LifeStage.Prenatal,\n        < 2 =>  LifeStage.Infant,\n        < 4 =>  LifeStage.Toddler,\n        < 6 =>  LifeStage.EarlyChild,\n        < 12 => LifeStage.MiddleChild,\n        < 20 => LifeStage.Adolescent,\n        < 40 => LifeStage.EarlyAdult,\n        < 65 => LifeStage.MiddleAdult,\n        _ =>    LifeStage.LateAdult,\n    };\n```\n\nRelational patterns support the relational operators `<`, `<=`, `>`, and `>=` on all of the built-in types that support such binary relational operators with two operands of the same type in an expression. Specifically, we support all of these relational patterns for `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `char`, `float`, `double`, `decimal`, `nint`, and `nuint`.\n\n```antlr\nprimary_pattern\n    : relational_pattern\n    ;\nrelational_pattern\n    : '<' relational_expression\n    | '<=' relational_expression\n    | '>' relational_expression\n    | '>=' relational_expression\n    ;\n```\n\nThe expression is required to evaluate to a constant value.  It is an error if that constant value is `double.NaN` or `float.NaN`.  It is an error if the expression is a null constant.\n\nWhen the input is a type for which a suitable built-in binary relational operator is defined that is applicable with the input as its left operand and the given constant as its right operand, the evaluation of that operator is taken as the meaning of the relational pattern.  Otherwise we convert the input to the type of the expression using an explicit nullable or unboxing conversion.  It is a compile-time error if no such conversion exists.  The pattern is considered not to match if the conversion fails.  If the conversion succeeds then the result of the pattern-matching operation is the result of evaluating the expression `e OP v` where `e` is the converted input, `OP` is the relational operator, and `v` is the constant expression.\n\n## Pattern Combinators\n\nPattern *combinators* permit matching both of two different patterns using `and` (this can be extended to any number of patterns by the repeated use of `and`), either of two different patterns using `or` (ditto), or the *negation* of a pattern using `not`.\n\nA common use of a combinator will be the idiom\n\n``` c#\nif (e is not null) ...\n```\n\nMore readable than the current idiom `e is object`, this pattern clearly expresses that one is checking for a non-null value.\n\nThe `and` and `or` combinators will be useful for testing ranges of values\n\n``` c#\nbool IsLetter(char c) => c is >= 'a' and <= 'z' or >= 'A' and <= 'Z';\n```\n\nThis example illustrates that `and` will have a higher parsing priority (i.e. will bind more closely) than `or`.  The programmer can use the *parenthesized pattern* to make the precedence explicit:\n\n``` c#\nbool IsLetter(char c) => c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z');\n```\n\nLike all patterns, these combinators can be used in any context in which a pattern is expected, including nested patterns, the *is-pattern-expression*, the *switch-expression*, and the pattern of a switch statement's case label.\n\n```antlr\npattern\n    : disjunctive_pattern\n    ;\ndisjunctive_pattern\n    : disjunctive_pattern 'or' conjunctive_pattern\n    | conjunctive_pattern\n    ;\nconjunctive_pattern\n    : conjunctive_pattern 'and' negated_pattern\n    | negated_pattern\n    ;\nnegated_pattern\n    : 'not' negated_pattern\n    | primary_pattern\n    ;\nprimary_pattern\n    : // all of the patterns forms previously defined\n    ;\n```\n\n## Change to 6.2.5 Grammar Ambiguities\n\nDue to the introduction of the *type pattern*, it is possible for a generic type to appear before the token `=>`.  We therefore add `=>` to the set of tokens listed in [§6.2.5 Grammar ambiguities](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/lexical-structure.md#625-grammar-ambiguities) to permit disambiguation of the `<` that begins the type argument list.  See also https://github.com/dotnet/roslyn/issues/47614.\n\n## Open Issues with Proposed Changes\n\n### Syntax for relational operators\n\nAre `and`, `or`, and `not` some kind of contextual keyword?  If so, is there a breaking change (e.g. compared to their use as a designator in a *declaration-pattern*).\n\n### Semantics (e.g. type) for relational operators\n\nWe expect to support all of the primitive types that can be compared in an expression using a relational operator.  The meaning in simple cases is clear\n\n``` c#\nbool IsValidPercentage(int x) => x is >= 0 and <= 100;\n```\n\nBut when the input is not such a primitive type, what type do we attempt to convert it to?\n\n``` c#\nbool IsValidPercentage(object x) => x is >= 0 and <= 100;\n```\n\nWe have proposed that when the input type is already a comparable primitive, that is the type of the comparison. However, when the input is not a comparable primitive, we treat the relational as including an implicit type test to the type of the constant on the right-hand-side of the relational.  If the programmer intends to support more than one input type, that must be done explicitly:\n\n``` c#\nbool IsValidPercentage(object x) => x is\n    >= 0 and <= 100 or    // integer tests\n    >= 0F and <= 100F or  // float tests\n    >= 0D and <= 100D;    // double tests\n```\n\nResult: The relational does include an implicit type test to the type of the constant on the right-hand-side of the relational.\n\n### Flowing type information from the left to the right of `and`\n\nIt has been suggested that when you write an `and` combinator, type information learned on the left about the top-level type could flow to the right.  For example\n\n```csharp\nbool isSmallByte(object o) => o is byte and < 100;\n```\n\nHere, the *input type* to the second pattern is narrowed by the *type narrowing* requirements of left of the `and`.  We would define type narrowing semantics for all patterns as follows.  The *narrowed type* of a pattern `P` is defined as follows:\n1. If `P` is a type pattern, the *narrowed type* is the type of the type pattern's type.\n2. If `P` is a declaration pattern, the *narrowed type* is the type of the declaration pattern's type.\n3. If `P` is a recursive pattern that gives an explicit type, the *narrowed type* is that type.\n4. If `P` is [matched via the rules for](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-8.0/patterns.md#positional-pattern) `ITuple`, the *narrowed type* is the type `System.Runtime.CompilerServices.ITuple`.\n5. If `P` is a constant pattern where the constant is not the null constant and where the expression has no *constant expression conversion* to the *input type*, the *narrowed type* is the type of the constant.\n6. If `P` is a relational pattern where the constant expression has no *constant expression conversion* to the *input type*, the *narrowed type* is the type of the constant.\n7. If `P` is an `or` pattern, the *narrowed type* is the common type of the *narrowed type* of the subpatterns if such a common type exists. For this purpose, the common type algorithm considers only identity, boxing, and implicit reference conversions, and it considers all subpatterns of a sequence of `or` patterns (ignoring parenthesized patterns).\n8. If `P` is an `and` pattern, the *narrowed type* is the *narrowed type* of the right pattern. Moreover, the *narrowed type* of the left pattern is the *input type* of the right pattern.\n9. Otherwise the *narrowed type* of `P` is `P`'s input type.\n\nResult: The above narrowing semantics have been implemented.\n\n### Variable definitions and definite assignment\n\nThe addition of `or` and `not` patterns creates some interesting new problems around pattern variables and definite assignment.  Since variables can normally be declared at most once, it would seem any pattern variable declared on one side of an `or` pattern would not be definitely assigned when the pattern matches.  Similarly, a variable declared inside a `not` pattern would not be expected to be definitely assigned when the pattern matches.  The simplest way to address this is to forbid declaring pattern variables in these contexts.  However, this may be too restrictive.  There are other approaches to consider.\n\nOne scenario that is worth considering is this\n\n``` csharp\nif (e is not int i) return;\nM(i); // is i definitely assigned here?\n```\n\nThis does not work today because, for an *is-pattern-expression*, the pattern variables are considered *definitely assigned* only where the *is-pattern-expression* is true (\"definitely assigned when true\").\n\nSupporting this would be simpler (from the programmer's perspective) than also adding support for a negated-condition `if` statement.  Even if we add such support, programmers would wonder why the above snippet does not work.  On the other hand, the same scenario in a `switch` makes less sense, as there is no corresponding point in the program where *definitely assigned when false* would be meaningful.  Would we permit this in an *is-pattern-expression* but not in other contexts where patterns are permitted?  That seems irregular.\n\nRelated to this is the problem of definite assignment in a *disjunctive-pattern*.\n\n```csharp\nif (e is 0 or int i)\n{\n    M(i); // is i definitely assigned here?\n}\n```\n\nWe would only expect `i` to be definitely assigned when the input is not zero.  But since we don't know whether the input is zero or not inside the block, `i` is not definitely assigned.  However, what if we permit `i` to be declared in different mutually exclusive patterns?\n\n```csharp\nif ((e1, e2) is (0, int i) or (int i, 0))\n{\n    M(i);\n}\n```\n\nHere, the variable `i` is definitely assigned inside the block, and takes it value from the other element of the tuple when a zero element is found.\n\nIt has also been suggested to permit variables to be (multiply) defined in every case of a case block:\n\n```csharp\n    case (0, int x):\n    case (int x, 0):\n        Console.WriteLine(x);\n```\n\nTo make any of this work, we would have to carefully define where such multiple definitions are permitted and under what conditions such a variable is considered definitely assigned.\n\nShould we elect to defer such work until later (which I advise), we could say in C# 9\n- beneath a `not` or `or`, pattern variables may not be declared.\n\nThen, we would have time to develop some experience that would provide insight into the possible value of relaxing that later.\n\nResult: Pattern variables can't be declared beneath a `not` or `or` pattern.\n\n### Diagnostics, subsumption, and exhaustiveness\n\nThese new pattern forms introduce many new opportunities for diagnosable programmer error.  We will need to decide what kinds of errors we will diagnose, and how to do so.  Here are some examples:\n\n``` csharp\ncase >= 0 and <= 100D:\n```\n\nThis case can never match (because the input cannot be both an `int` and a `double`).  We already have an error when we detect a case that can never match, but its wording (\"The switch case has already been handled by a previous case\" and \"The pattern has already been handled by a previous arm of the switch expression\") may be misleading in new scenarios.  We may have to modify the wording to just say that the pattern will never match the input.\n\n``` csharp\ncase 1 and 2:\n```\n\nSimilarly, this would be an error because a value cannot be both `1` and `2`.\n\n``` csharp\ncase 1 or 2 or 3 or 1:\n```\n\nThis case is possible to match, but the `or 1` at the end adds no meaning to the pattern.  I suggest we should aim to produce an error whenever some conjunct or disjunct of a compound pattern does not either define a pattern variable or affect the set of matched values.\n\n``` csharp\ncase < 2: break;\ncase 0 or 1 or 2 or 3 or 4 or 5: break;\n```\n\nHere, `0 or 1 or` adds nothing to the second case, as those values would have been handled by the first case.  This too deserves an error.\n\n``` csharp\nbyte b = ...;\nint x = b switch { <100 => 0, 100 => 1, 101 => 2, >101 => 3 };\n```\n\nA switch expression such as this should be considered *exhaustive* (it handles all possible input values).\n\nIn C# 8.0, a switch expression with an input of type `byte` is only considered exhaustive if it contains a final arm whose pattern matches everything (a *discard-pattern* or *var-pattern*).  Even a switch expression that has an arm for every distinct `byte` value is not considered exhaustive in C# 8.  In order to properly handle exhaustiveness of relational patterns, we will have to handle this case too.  This will technically be a breaking change, but no user is likely to notice.\n"
  },
  {
    "path": "proposals/csharp-9.0/records.md",
    "content": "# Records\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/39>\n\nThis proposal tracks the specification for the C# 9 records feature, as agreed to by the C#\nlanguage design team.\n\nThe syntax for a record is as follows:\n\n```antlr\nrecord_declaration\n    : attributes? class_modifier* 'partial'? 'record' identifier type_parameter_list?\n      parameter_list? record_base? type_parameter_constraints_clause* record_body\n    ;\n\nrecord_base\n    : ':' class_type argument_list?\n    | ':' interface_type_list\n    | ':' class_type argument_list? ',' interface_type_list\n    ;\n\nrecord_body\n    : '{' class_member_declaration* '}' ';'?\n    | ';'\n    ;\n```\n\nRecord types are reference types, similar to a class declaration. It is an error for a record to provide\na `record_base` `argument_list` if the `record_declaration` does not contain a `parameter_list`.\nAt most one partial type declaration of a partial record may provide a `parameter_list`.\n\nRecord parameters cannot use `ref`, `out` or `this` modifiers (but `in` and `params` are allowed).\n\n## Inheritance\n\nRecords cannot inherit from classes, unless the class is `object`, and classes cannot inherit from records. Records can inherit from other records.\n\n## Members of a record type\n\nIn addition to the members declared in the record body, a record type has additional synthesized members.\nMembers are synthesized unless a member with a \"matching\" signature is declared in the record body or\nan accessible concrete non-virtual member with a \"matching\" signature is inherited. A matching member prevents the compiler from generating that member, not any other synthesized members.\nTwo members are considered matching if they have the same\nsignature or would be considered \"hiding\" in an inheritance scenario.\nIt is an error for a member of a record to be named \"Clone\".\nIt is an error for an instance field of a record to have a top-level pointer type. A nested pointer type, such as an array of pointers, is allowed.\n\nThe synthesized members are as follows:\n\n### Equality members\n\nIf the record is derived from `object`, the record type includes a synthesized readonly property equivalent to a property declared as follows:\n```C#\nType EqualityContract { get; }\n```\nThe property is `private` if the record type is `sealed`. Otherwise, the property is `virtual` and `protected`.\nThe property can be declared explicitly. It is an error if the explicit declaration does not match the expected signature or accessibility, or if the explicit declaration doesn't allow overriding it in a derived type and the record type is not `sealed`.\n\nIf the record type is derived from a base record type `Base`, the record type includes a synthesized readonly property equivalent to a property declared as follows:\n```C#\nprotected override Type EqualityContract { get; }\n```\n\nThe property can be declared explicitly. It is an error if the explicit declaration does not match the expected signature or accessibility, or if the explicit declaration doesn't allow overriding it in a derived type and the record type is not `sealed`. It is an error if either synthesized, or explicitly declared property doesn't override a property with this signature in the record type `Base` (for example, if the property is missing in the `Base`, or sealed, or not virtual, etc.).\nThe synthesized property returns `typeof(R)` where `R` is the record type.\n\nThe record type implements `System.IEquatable<R>` and includes a synthesized strongly-typed overload of `Equals(R? other)` where `R` is the record type.\nThe method is `public`, and the method is `virtual` unless the record type is `sealed`.\nThe method can be declared explicitly. It is an error if the explicit declaration does not match the expected signature or accessibility, or the explicit declaration doesn't allow overriding it in a derived type and the record type is not `sealed`.\n\nIf `Equals(R? other)` is user-defined (not synthesized) but `GetHashCode` is not, a warning is produced.\n\n```C#\npublic virtual bool Equals(R? other);\n```\nThe synthesized `Equals(R?)` returns `true` if and only if each of the following are `true`:\n- `other` is not `null`, and\n- For each instance field `fieldN` in the record type that is not inherited, the value of\n`System.Collections.Generic.EqualityComparer<TN>.Default.Equals(fieldN, other.fieldN)` where `TN` is the field type, and\n- If there is a base record type, the value of `base.Equals(other)` (a non-virtual call to `public virtual bool Equals(Base? other)`); otherwise\nthe value of `EqualityContract == other.EqualityContract`.\n\nThe record type includes synthesized `==` and `!=` operators equivalent to operators declared as follows:\n```C#\npublic static bool operator==(R? left, R? right)\n    => (object)left == right || (left?.Equals(right) ?? false);\npublic static bool operator!=(R? left, R? right)\n    => !(left == right);\n```\nThe `Equals` method called by the `==` operator is the `Equals(R? other)` method specified above. The `!=` operator delegates to the `==` operator. It is an error if the operators are declared explicitly.\n    \nIf the record type is derived from a base record type `Base`, the record type includes a synthesized override equivalent to a method declared as follows:\n```C#\npublic sealed override bool Equals(Base? other);\n```\nIt is an error if the override is declared explicitly. It is an error if the method doesn't override a method with same signature in record type `Base` (for example, if the method is missing in the `Base`, or sealed, or not virtual, etc.).\nThe synthesized override returns `Equals((object?)other)`.\n\nThe record type includes a synthesized override equivalent to a method declared as follows:\n```C#\npublic override bool Equals(object? obj);\n```\nIt is an error if the override is declared explicitly. It is an error if the method doesn't override `object.Equals(object? obj)` (for example, due to shadowing in intermediate base types, etc.).\nThe synthesized override returns `Equals(other as R)` where `R` is the record type.\n\nThe record type includes a synthesized override equivalent to a method declared as follows:\n```C#\npublic override int GetHashCode();\n```\nThe method can be declared explicitly.\nIt is an error if the explicit declaration doesn't allow overriding it in a derived type and the record type is not `sealed`. It is an error if either synthesized, or explicitly declared method doesn't override `object.GetHashCode()` (for example, due to shadowing in intermediate base types, etc.).\n \nA warning is reported if one of `Equals(R?)` and `GetHashCode()` is explicitly declared but the other method is not explicit.\n\nThe synthesized override of `GetHashCode()` returns an `int` result of combining the following values:\n- For each instance field `fieldN` in the record type that is not inherited, the value of\n`System.Collections.Generic.EqualityComparer<TN>.Default.GetHashCode(fieldN)` where `TN` is the field type, and\n- If there is a base record type, the value of `base.GetHashCode()`; otherwise\nthe value of `System.Collections.Generic.EqualityComparer<System.Type>.Default.GetHashCode(EqualityContract)`.\n\nFor example, consider the following record types:\n```C#\nrecord R1(T1 P1);\nrecord R2(T1 P1, T2 P2) : R1(P1);\nrecord R3(T1 P1, T2 P2, T3 P3) : R2(P1, P2);\n```\n\nFor those record types, the synthesized equality members would be something like:\n```C#\nclass R1 : IEquatable<R1>\n{\n    public T1 P1 { get; init; }\n    protected virtual Type EqualityContract => typeof(R1);\n    public override bool Equals(object? obj) => Equals(obj as R1);\n    public virtual bool Equals(R1? other)\n    {\n        return !(other is null) &&\n            EqualityContract == other.EqualityContract &&\n            EqualityComparer<T1>.Default.Equals(P1, other.P1);\n    }\n    public static bool operator==(R1? left, R1? right)\n        => (object)left == right || (left?.Equals(right) ?? false);\n    public static bool operator!=(R1? left, R1? right)\n        => !(left == right);\n    public override int GetHashCode()\n    {\n        return HashCode.Combine(EqualityComparer<Type>.Default.GetHashCode(EqualityContract),\n            EqualityComparer<T1>.Default.GetHashCode(P1));\n    }\n}\n\nclass R2 : R1, IEquatable<R2>\n{\n    public T2 P2 { get; init; }\n    protected override Type EqualityContract => typeof(R2);\n    public override bool Equals(object? obj) => Equals(obj as R2);\n    public sealed override bool Equals(R1? other) => Equals((object?)other);\n    public virtual bool Equals(R2? other)\n    {\n        return base.Equals((R1?)other) &&\n            EqualityComparer<T2>.Default.Equals(P2, other.P2);\n    }\n    public static bool operator==(R2? left, R2? right)\n        => (object)left == right || (left?.Equals(right) ?? false);\n    public static bool operator!=(R2? left, R2? right)\n        => !(left == right);\n    public override int GetHashCode()\n    {\n        return HashCode.Combine(base.GetHashCode(),\n            EqualityComparer<T2>.Default.GetHashCode(P2));\n    }\n}\n\nclass R3 : R2, IEquatable<R3>\n{\n    public T3 P3 { get; init; }\n    protected override Type EqualityContract => typeof(R3);\n    public override bool Equals(object? obj) => Equals(obj as R3);\n    public sealed override bool Equals(R2? other) => Equals((object?)other);\n    public virtual bool Equals(R3? other)\n    {\n        return base.Equals((R2?)other) &&\n            EqualityComparer<T3>.Default.Equals(P3, other.P3);\n    }\n    public static bool operator==(R3? left, R3? right)\n        => (object)left == right || (left?.Equals(right) ?? false);\n    public static bool operator!=(R3? left, R3? right)\n        => !(left == right);\n    public override int GetHashCode()\n    {\n        return HashCode.Combine(base.GetHashCode(),\n            EqualityComparer<T3>.Default.GetHashCode(P3));\n    }\n}\n```\n\n### Copy and Clone members\n\nA record type contains two copying members:\n\n* A constructor taking a single argument of the record type. It is referred to as a \"copy constructor\".\n* A synthesized public parameterless instance \"clone\" method with a compiler-reserved name\n\nThe purpose of the copy constructor is to copy the state from the parameter to the new instance being\ncreated. This constructor doesn't run any instance field/property initializers present in the record\ndeclaration. If the constructor is not explicitly declared, a constructor will be synthesized\nby the compiler. If the record is sealed, the constructor will be private, otherwise it will be protected.\nAn explicitly declared copy constructor must be either public or protected, unless the\nrecord is sealed.\nThe first thing the constructor must do, is to call a copy constructor of the base, or a parameter-less\nobject constructor if the record inherits from object. An error is reported if a user-defined copy\nconstructor uses an implicit or explicit constructor initializer that doesn't fulfill this requirement.\nAfter a base copy constructor is invoked, a synthesized copy constructor copies values for all instance\nfields implicitly or explicitly declared within the record type. \nThe sole presence of a copy constructor, whether explicit or implicit, doesn't prevent an automatic\naddition of a default instance constructor.\n\nIf a virtual \"clone\" method is present in the base record, the synthesized \"clone\" method overrides it and\nthe return type of the method is the current containing type. An error is produced if the base record clone method is sealed.\nIf a virtual \"clone\" method is not present in the base record, the return type of the clone method\nis the containing type and the method is virtual, unless the record is sealed or abstract.\nIf the containing record is abstract, the synthesized clone method is also abstract.\nIf the \"clone\" method is not abstract, it returns the result of a call to a copy constructor. \n\n\n### Printing members: PrintMembers and ToString methods\n\nIf the record is derived from `object`, the record includes a synthesized method equivalent to a method declared as follows:\n```C#\nbool PrintMembers(System.Text.StringBuilder builder);\n```\nThe method is `private` if the record type is `sealed`. Otherwise, the method is `virtual` and `protected`.\n\nThe method:\n1. calls the method `System.Runtime.CompilerServices.RuntimeHelpers.EnsureSufficientExecutionStack()` if the method is present and the record has printable members.\n2. for each of the record's printable members (non-static public field and readable property members), appends that member's name followed by \" = \" followed by the member's value separated with \", \",\n3. return true if the record has printable members.\n\nFor a member that has a value type, we will convert its value to a string representation using the most efficient method available to the target platform. At present that means calling `ToString` before passing to `StringBuilder.Append`.\n\nIf the record type is derived from a base record `Base`, the record includes a synthesized override equivalent to a method declared as follows:\n```C#\nprotected override bool PrintMembers(StringBuilder builder);\n```\n\nIf the record has no printable members, the method calls the base `PrintMembers` method with one argument (its `builder` parameter) and returns the result.\n\nOtherwise, the method:\n1. calls the base `PrintMembers` method with one argument (its `builder` parameter),\n2. if the `PrintMembers` method returned true, append \", \" to the builder,\n3. for each of the record's printable members, appends that member's name followed by \" = \" followed by the member's value: `this.member` (or `this.member.ToString()` for value types), separated with \", \",\n4. return true.\n\nThe `PrintMembers` method can be declared explicitly.\nIt is an error if the explicit declaration does not match the expected signature or accessibility, or if the explicit declaration doesn't allow overriding it in a derived type and the record type is not `sealed`.\n\nThe record includes a synthesized method equivalent to a method declared as follows:\n```C#\npublic override string ToString();\n```\n\nThe method can be declared explicitly. It is an error if the explicit declaration does not match the expected signature or accessibility, or if the explicit declaration doesn't allow overriding it in a derived type and the record type is not `sealed`. It is an error if either synthesized, or explicitly declared method doesn't override `object.ToString()` (for example, due to shadowing in intermediate base types, etc.).\n\nThe synthesized method:\n1. creates a `StringBuilder` instance,\n2. appends the record name to the builder, followed by \" { \",\n3. invokes the record's `PrintMembers` method giving it the builder, followed by \" \" if it returned true,\n4. appends \"}\",\n3. returns the builder's contents with `builder.ToString()`.\n\nFor example, consider the following record types:\n\n``` csharp\nrecord R1(T1 P1);\nrecord R2(T1 P1, T2 P2, T3 P3) : R1(P1);\n```\n\nFor those record types, the synthesized printing members would be something like:\n\n```C#\nclass R1 : IEquatable<R1>\n{\n    public T1 P1 { get; init; }\n    \n    protected virtual bool PrintMembers(StringBuilder builder)\n    {\n        builder.Append(nameof(P1));\n        builder.Append(\" = \");\n        builder.Append(this.P1); // or builder.Append(this.P1.ToString()); if T1 is a value type\n        \n        return true;\n    }\n    \n    public override string ToString()\n    {\n        var builder = new StringBuilder();\n        builder.Append(nameof(R1));\n        builder.Append(\" { \");\n\n        if (PrintMembers(builder))\n            builder.Append(\" \");\n\n        builder.Append(\"}\");\n        return builder.ToString();\n    }\n}\n\nclass R2 : R1, IEquatable<R2>\n{\n    public T2 P2 { get; init; }\n    public T3 P3 { get; init; }\n    \n    protected override bool PrintMembers(StringBuilder builder)\n    {\n        if (base.PrintMembers(builder))\n            builder.Append(\", \");\n            \n        builder.Append(nameof(P2));\n        builder.Append(\" = \");\n        builder.Append(this.P2); // or builder.Append(this.P2); if T2 is a value type\n        \n        builder.Append(\", \");\n        \n        builder.Append(nameof(P3));\n        builder.Append(\" = \");\n        builder.Append(this.P3); // or builder.Append(this.P3); if T3 is a value type\n        \n        return true;\n    }\n    \n    public override string ToString()\n    {\n        var builder = new StringBuilder();\n        builder.Append(nameof(R2));\n        builder.Append(\" { \");\n\n        if (PrintMembers(builder))\n            builder.Append(\" \");\n\n        builder.Append(\"}\");\n        return builder.ToString();\n    }\n}\n```\n\n## Positional record members\n\nIn addition to the above members, records with a parameter list (\"positional records\") synthesize\nadditional members with the same conditions as the members above.\n\n### Primary Constructor\n\nA record type has a public constructor whose signature corresponds to the value parameters of the\ntype declaration. This is called the primary constructor for the type, and causes the implicitly\ndeclared default class constructor, if present, to be suppressed. It is an error to have a primary\nconstructor and a constructor with the same signature already present in the class.\n\nAt runtime the primary constructor\n\n1. executes the instance initializers appearing in the class-body\n\n1. invokes the base class constructor with the arguments provided in the `record_base` clause, if present\n\nIf a record has a primary constructor, any user-defined constructor, except \"copy constructor\" must have an\nexplicit `this` constructor initializer. \n\nParameters of the primary constructor as well as members of the record are in scope within the `argument_list`\nof the `record_base` clause and within initializers of instance fields or properties. Instance members would\nbe an error in these locations (similar to how instance members are in scope in regular constructor initializers\ntoday, but an error to use), but the parameters of the primary constructor would be in scope and useable and\nwould shadow members. Static members would also be useable, similar to how base calls and initializers work in\nordinary constructors today.\n\nA warning is produced if a parameter of the primary constructor is not read.\n\nExpression variables declared in the `argument_list` are in scope within the `argument_list`. The same shadowing\nrules as within an argument list of a regular constructor initializer apply.\n\n### Properties\n\nFor each record parameter of a record type declaration there is a corresponding public property\nmember whose name and type are taken from the value parameter declaration.\n\nFor a record:\n\n* A public `get` and `init` auto-property is created (see separate `init` accessor specification).\n  An inherited `abstract` property with matching type is overridden.\n  It is an error if the inherited property does not have `public` overridable `get` and `init` accessors.\n  It is an error if the inherited property is hidden.  \n  The auto-property is initialized to the value of the corresponding primary constructor parameter.\n  Attributes can be applied to the synthesized auto-property and its backing field by using `property:` or `field:`\n  targets for attributes syntactically applied to the corresponding record parameter.  \n\n### Deconstruct\n\nA positional record with at least one parameter synthesizes a public void-returning instance method called Deconstruct with an out\nparameter declaration for each parameter of the primary constructor declaration. Each parameter\nof the `Deconstruct` method has the same type as the corresponding parameter of the primary\nconstructor declaration. The body of the method assigns to each parameter of the `Deconstruct` method, \nthe value of the instance property of the same name.\nThe method can be declared explicitly. It is an error if the explicit declaration does not match\nthe expected signature or accessibility, or is static.\n\nThe following example shows a positional record `R` with its compiler synthesized `Deconstruct` method, along with its usage:\n\n```csharp\npublic record R(int P1, string P2 = \"xyz\")\n{\n    public void Deconstruct(out int P1, out string P2)\n    {\n        P1 = this.P1;\n        P2 = this.P2;\n    }\n}\n\nclass Program\n{\n    static void Main()\n    {\n        R r = new R(12);\n        (int p1, string p2) = r;\n        Console.WriteLine($\"p1: {p1}, p2: {p2}\");\n    }\n}\n```\n\n## `with` expression\n\nA `with` expression is a new expression using the following syntax.\n\n```antlr\nwith_expression\n    : switch_expression\n    | switch_expression 'with' '{' member_initializer_list? '}'\n    ;\n\nmember_initializer_list\n    : member_initializer (',' member_initializer)*\n    ;\n\nmember_initializer\n    : identifier '=' expression\n    ;\n```\nA `with` expression is not permitted as a statement.\n\nA `with` expression allows for \"non-destructive mutation\", designed to\nproduce a copy of the receiver expression with modifications in assignments\nin the `member_initializer_list`.\n\nA valid `with` expression has a receiver with a non-void type. The receiver type must be a record.\n\nOn the right hand side of the `with` expression is a `member_initializer_list` with a sequence\nof assignments to *identifier*, which must be an accessible instance field or property of the receiver's\ntype.\n\nFirst, receiver's \"clone\" method (specified above) is invoked and its result is converted to the\nreceiver's type. Then, each `member_initializer` is processed the same way as an assignment to\na field or property access of the result of the conversion. Assignments are processed in lexical order.\n"
  },
  {
    "path": "proposals/csharp-9.0/skip-localsinit.md",
    "content": "# Suppress emitting of `localsinit` flag.\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/1738>\n\n## Summary\n[summary]: #summary\n\nAllow suppressing emit of `localsinit` flag via `SkipLocalsInitAttribute` attribute. \n\n## Motivation\n[motivation]: #motivation\n\n\n### Background\nPer CLR spec local variables that do not contain references are not initialized to a particular value by the VM/JIT. Reading from such variables without initialization is type-safe, but otherwise the behavior is undefined and implementation specific. Typically uninitialized locals contain whatever values were left in the memory that is now occupied by the stack frame. That could lead to nondeterministic behavior and hard to reproduce bugs. \n\nThere are two ways to \"assign\" a local variable: \n- by storing a value or \n- by specifying `localsinit` flag which forces everything that is allocated from the local memory pool to be zero-initialized\nNOTE: this includes both local variables and `stackalloc` data.    \n\nUse of uninitialized data is discouraged and is not allowed in verifiable code. While it might be possible to prove that by the means of flow analysis, it is permitted for the verification algorithm to be conservative and simply require that `localsinit` is set.\n\nHistorically C# compiler emits `localsinit` flag on all methods that declare locals.\n\nWhile C# employs definite-assignment analysis which is more strict than what CLR spec would require (C# also needs to consider scoping of locals), it is not strictly guaranteed that the resulting code would be formally verifiable:\n- CLR and C# rules may not agree on whether passing a local as `out` argument is a `use`.\n- CLR and C# rules may not agree on treatment of conditional branches when conditions are known (constant propagation).\n- CLR could as well simply require `localinits`, since that is permitted.  \n\n### Problem\nIn high-performance application the cost of forced zero-initialization could be noticeable. It is particularly noticeable when `stackalloc` is used.\n\nIn some cases JIT can elide initial zero-initialization of individual locals when such initialization is \"killed\" by subsequent assignments. Not all JITs do this and such optimization has limits. It does not help with `stackalloc`.\n\nTo illustrate that the problem is real - there is a known bug where a method not containing any `IL` locals would not have `localsinit` flag. The bug is already being exploited by users by putting `stackalloc` into such methods - intentionally to avoid initialization costs. That is despite the fact that absence of `IL` locals is an unstable metric and may vary depending on changes in codegen strategy. \nThe bug should be fixed and users should get a more documented and reliable way of suppressing the flag. \n\n## Detailed design\n\nAllow specifying `System.Runtime.CompilerServices.SkipLocalsInitAttribute` as a way to tell the compiler to not emit `localsinit` flag.\n \nThe end result of this will be that the locals may not be zero-initialized by the JIT, which is in most cases unobservable in C#.  \nIn addition to that `stackalloc` data will not be zero-initialized. That is definitely observable, but also is the most motivating scenario.\n\nPermitted and recognized attribute targets are: `Method`, `Property`, `Module`, `Class`, `Struct`, `Interface`, `Constructor`. However compiler will not require that attribute is defined with the listed targets nor it will care in which assembly the attribute is defined. \n\nWhen attribute is specified on a container (`class`, `module`, containing method for a nested method, ...), the flag affects all methods contained within the container.\n\nSynthesized methods \"inherit\" the flag from the logical container/owner. \n\nThe flag affects only codegen strategy for actual method bodies. I.E. the flag has no effect on abstract methods and is not propagated to overriding/implementing methods.\n\nThis is explicitly a **_compiler feature_** and **_not a language feature_**.  \nSimilarly to compiler command line switches the feature controls implementation details of a particular codegen strategy and does not need to be required by the C# spec.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\n- Old/other compilers may not honor the attribute.\nIgnoring the attribute is compatible behavior. Only may result in a slight perf hit.\n\n- The code without `localinits` flag may trigger verification failures.\nUsers that ask for this feature are generally unconcerned with verifiability. \n \n- Applying the attribute at higher levels than an individual method has nonlocal effect, which is observable when `stackalloc` is used. \nYet, this is the most requested scenario.\n\n## Alternatives\n[alternatives]: #alternatives\n\n- omit `localinits` flag when method is declared in `unsafe` context. \nThat could cause silent and dangerous behavior change from deterministic to nondeterministic in a case of `stackalloc`.\n\n- omit `localinits` flag always.\nEven worse than above.\n\n- omit `localinits` flag unless `stackalloc` is used in the method body.\nDoes not address the most requested scenario and may turn code unverifiable with no option to revert that back.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n- Should the attribute be actually emitted to metadata? \n\n## Design meetings\n\nNone yet. \n"
  },
  {
    "path": "proposals/csharp-9.0/static-anonymous-functions.md",
    "content": "# Static anonymous functions\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/275>\n\n## Summary\n\nAllow a 'static' modifier on lambdas and anonymous methods, which disallows capture of locals or instance state from containing scopes.\n\n## Motivation\n\nAvoid unintentionally capturing state from the enclosing context, which can result in unexpected retention of captured objects or unexpected additional allocations.\n\n## Detailed design\n\nA lambda or anonymous method may have a `static` modifier. The `static` modifier indicates that the lambda or anonymous method is a *static anonymous function*.\n\nA *static anonymous function* cannot capture state from the enclosing scope.\nAs a result, locals, parameters, and `this` from the enclosing scope are not available within a *static anonymous function*.\n\nA *static anonymous function* cannot reference instance members from an implicit or explicit `this` or `base` reference.\n\nA *static anonymous function* may reference `static` members from the enclosing scope.\n\nA *static anonymous function* may reference `constant` definitions from the enclosing scope.\n\n`nameof()` in a *static anonymous function* may reference locals, parameters, or `this` or `base` from the enclosing scope.\n\nAccessibility rules for `private` members in the enclosing scope are the same for `static` and non-`static` anonymous functions.\n\nNo guarantee is made as to whether a *static anonymous function* definition is emitted as a `static` method in metadata. This is left up to the compiler implementation to optimize.\n\nA non-`static` local function or anonymous function can capture state from an enclosing *static anonymous function* but cannot capture state outside the enclosing *static anonymous function*.\n\nRemoving the `static` modifier from an anonymous function in a valid program does not change the meaning of the program.\n"
  },
  {
    "path": "proposals/csharp-9.0/target-typed-conditional-expression.md",
    "content": "# Target-Typed Conditional Expression\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/2460>\n\n## Conditional Expression Conversion\n\nFor a conditional expression `c ? e1 : e2`, when\n\n1. there is no common type for `e1` and `e2`, or\n2. for which a common type exists but one of the expressions `e1` or `e2` has no implicit conversion to that type\n\nwe define a new implicit *conditional expression conversion* that permits an implicit conversion from the conditional expression to any type `T` for which there is a conversion-from-expression from `e1` to `T` and also from `e2` to `T`.  It is an error if a conditional expression neither has a common type between `e1` and `e2` nor is subject to a *conditional expression conversion*.\n\n## Better Conversion from Expression\n\nWe change\n\n> #### Better conversion from expression\n> \n> Given an implicit conversion `C1` that converts from an expression `E` to a type `T1`, and an implicit conversion `C2` that converts from an expression `E` to a type `T2`, `C1` is a ***better conversion*** than `C2` if `E` does not exactly match `T2` and at least one of the following holds:\n> \n> * `E` exactly matches `T1` ([§12.6.4.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12645-better-conversion-from-expression))\n> * `T1` is a better conversion target than `T2` ([§12.6.4.7](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1264-better-conversion-target))\n\nto\n\n> #### Better conversion from expression\n> \n> Given an implicit conversion `C1` that converts from an expression `E` to a type `T1`, and an implicit conversion `C2` that converts from an expression `E` to a type `T2`, `C1` is a ***better conversion*** than `C2` if `E` does not exactly match `T2` and at least one of the following holds:\n> \n> * `E` exactly matches `T1` ([§12.6.4.5](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12645-better-conversion-from-expression))\n> * **`C1` is not a *conditional expression conversion* and `C2` is a *conditional expression conversion***.\n> * `T1` is a better conversion target than `T2` ([§12.6.4.7](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12647-better-conversion-target)) **and either `C1` and `C2` are both *conditional expression conversions* or neither is a *conditional expression conversion***.\n\n## Cast Expression\n\nThe current C# language specification says\n\n> A *cast_expression* of the form `(T)E`, where `T` is a *type* and `E` is a *unary_expression*, performs an explicit conversion ([§10.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#103-explicit-conversions)) of the value of `E` to type `T`.\n\nIn the presence of the *conditional expression conversion* there may be more than one possible conversion from `E` to `T`. With the addition of *conditional expression conversion*, we prefer any other conversion to a *conditional expression conversion*, and use the *conditional expression conversion* only as a last resort.\n\n## Design Notes\n\nThe reason for the change to *Better conversion from expression* is to handle a case such as this:\n\n```csharp\nM(b ? 1 : 2);\n\nvoid M(short);\nvoid M(long);\n```\n\nThis approach does have two small downsides.  First, it is not quite the same as the switch expression:\n\n```csharp\nM(b ? 1 : 2); // calls M(long)\nM(b switch { true => 1, false => 2 }); // calls M(short)\n```\n\nThis is still a breaking change, but its scope is less likely to affect real programs:\n\n```csharp\nM(b ? 1 : 2, 1); // calls M(long, long) without this feature; ambiguous with this feature.\n\nM(short, short);\nM(long, long);\n```\n\nThis becomes ambiguous because the conversion to `long` is better for the first argument (because it does not use the *conditional expression conversion*), but the conversion to `short` is better for the second argument (because `short` is a *better conversion target* than `long`). This breaking change seems less serious because it does not silently change the behavior of an existing program.\n\nThe reason for the notes on the cast expression is to handle a case such as this:\n\n```csharp\n_ = (short)(b ? 1 : 2);\n```\n\nThis program currently uses the explicit conversion from `int` to `short`, and we want to preserve the current language meaning of this program.  The change would be unobservable at runtime, but with the following program the change would be observable:\n\n```csharp\n_ = (A)(b ? c : d);\n```\n\nwhere `c` is of type `C`, `d` is of type `D`, and there is an implicit user-defined conversion from `C` to `D`, and an implicit user-defined conversion from `D` to `A`, and an implicit user-defined conversion from `C` to `A`. If this code is compiled before C# 9.0, when `b` is true we convert from `c` to `D` then to `A`. If we use the *conditional expression conversion*, then when `b` is true we convert from `c` to `A` directly, which executes a different sequence of user code. Therefore we treat the *conditional expression conversion* as a last resort in a cast, to preserve existing behavior.\n"
  },
  {
    "path": "proposals/csharp-9.0/target-typed-new.md",
    "content": "# Target-typed `new` expressions\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/100>\n\n## Summary\n[summary]: #summary\n\nDo not require type specification for constructors when the type is known. \n\n## Motivation\n[motivation]: #motivation\n\nAllow field initialization without duplicating the type.\n```cs\nDictionary<string, List<int>> field = new() {\n    { \"item1\", new() { 1, 2, 3 } }\n};\n```\n\nAllow omitting the type when it can be inferred from usage.\n```cs\nXmlReader.Create(reader, new() { IgnoreWhitespace = true });\n```\n\nInstantiate an object without spelling out the type.\n```cs\nprivate readonly static object s_syncObj = new();\n```\n\n## Specification\n[design]: #detailed-design\n\nA new syntactic form, *target_typed_new* of the *object_creation_expression* is accepted in which the *type* is optional.\n\n```antlr\nobject_creation_expression\n    : 'new' type '(' argument_list? ')' object_or_collection_initializer?\n    | 'new' type object_or_collection_initializer\n    | target_typed_new\n    ;\ntarget_typed_new\n    : 'new' '(' argument_list? ')' object_or_collection_initializer?\n    ;\n```\n\nA *target_typed_new* expression does not have a type. However, there is a new *object creation conversion* that is an implicit conversion from expression, that exists from a *target_typed_new* to every type.\n\nGiven a target type `T`, the type `T0` is `T`'s underlying type if `T` is an instance of `System.Nullable`. Otherwise `T0` is `T`. The meaning of a *target_typed_new* expression that is converted to the type `T` is the same as the meaning of a corresponding *object_creation_expression* that specifies `T0` as the type.\n\nIt is a compile-time error if a *target_typed_new* is used as an operand of a unary or binary operator, or if it is used where it is not subject to an *object creation conversion*.\n\n> **Open Issue:** should we allow delegates and tuples as the target-type?\n\nThe above rules include delegates (a reference type) and tuples (a struct type). Although both types are constructible, if the type is inferable, an anonymous function or a tuple literal can already be used.\n```cs\n(int a, int b) t = new(1, 2); // \"new\" is redundant\nAction a = new(() => {}); // \"new\" is redundant\n\n(int a, int b) t = new(); // OK; same as (0, 0)\nAction a = new(); // no constructor found\n```\n\n### Miscellaneous\n\nThe following are consequences of the specification:\n\n- `throw new()` is allowed (the target type is `System.Exception`)\n- Target-typed `new` is not allowed with binary operators.\n- It is disallowed when there is no type to target: unary operators, collection of a `foreach`, in a `using`, in a deconstruction, in an `await` expression, as an anonymous type property (`new { Prop = new() }`), in a `lock` statement, in a `sizeof`, in a `fixed` statement, in a member access (`new().field`), in a dynamically dispatched operation (`someDynamic.Method(new())`), in a LINQ query, as the operand of the `is` operator, as the left operand of the `??` operator,  ...\n- It is also disallowed as a `ref`.\n- The following kinds of types are not permitted as targets of the conversion\n  - **Enum types:** `new()` will work (as `new Enum()` works to give the default value), but `new(1)` will not work as enum types do not have a constructor.\n  - **Interface types:** This would work the same as the corresponding creation expression for COM types.\n  - **Array types:** arrays need a special syntax to provide the length.\t\n  - **dynamic:** we don't allow `new dynamic()`, so we don't allow `new()` with `dynamic` as a target type.\n  - **tuples:** These have the same meaning as an object creation using the underlying type.\n  - All the other types that are not permitted in the *object_creation_expression* are excluded as well, for instance, pointer types.\t\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nThere were some concerns with target-typed `new` creating new categories of breaking changes, but we already have that with `null` and `default`, and that has not been a significant problem.\n\n## Alternatives\n[alternatives]: #alternatives\n\nMost of complaints about types being too long to duplicate in field initialization is about *type arguments* not the type itself, we could infer only type arguments like `new Dictionary(...)` (or similar) and infer type arguments locally from arguments or the collection initializer.\n\n## Questions\n[questions]: #questions\n\n- Should we forbid usages in expression trees? (no)\n- How the feature interacts with `dynamic` arguments? (no special treatment)\n- How IntelliSense should work with `new()`? (only when there is a single target-type)\n\n## Design meetings\n\n- [LDM-2017-10-18](https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-10-18.md#100)\n- [LDM-2018-05-21](https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-05-21.md)\n- [LDM-2018-06-25](https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-06-25.md)\n- [LDM-2018-08-22](https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-08-22.md#target-typed-new)\n- [LDM-2018-10-17](https://github.com/dotnet/csharplang/blob/master/meetings/2018/LDM-2018-10-17.md)\n- [LDM-2020-03-25](https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-03-25.md)\n"
  },
  {
    "path": "proposals/csharp-9.0/top-level-statements.md",
    "content": "# Top-level statements\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/2765>\n\n## Summary\n[summary]: #summary\n\nAllow a sequence of *statements* to occur right before the *namespace_member_declaration*s of a *compilation_unit* (i.e. source file).\n\nThe semantics are that if such a sequence of *statements* is present, the following type declaration, modulo the actual method name, would be emitted:\n\n``` c#\npartial class Program\n{\n    static async Task Main(string[] args)\n    {\n        // statements\n    }\n}\n```\n\nSee also https://github.com/dotnet/csharplang/issues/3117.\n\n## Motivation\n[motivation]: #motivation\n\nThere's a certain amount of boilerplate surrounding even the simplest of programs,\nbecause of the need for an explicit `Main` method. This seems to get in the way of\nlanguage learning and program clarity. The primary goal of the feature therefore is\nto allow C# programs without unnecessary boilerplate around them, for the sake of\nlearners and the clarity of code.\n\n## Detailed design\n[design]: #detailed-design\n\n### Syntax\n\nThe only additional syntax is allowing a sequence of *statement*s in a compilation unit,\njust before the *namespace_member_declaration*s:\n\n``` antlr\ncompilation_unit\n    : extern_alias_directive* using_directive* global_attributes? statement* namespace_member_declaration*\n    ;\n```\n\nOnly one *compilation_unit* is allowed to have *statement*s. \n\nExample:\n\n``` c#\nif (args.Length == 0\n    || !int.TryParse(args[0], out int n)\n    || n < 0) return;\nConsole.WriteLine(Fib(n).curr);\n\n(int curr, int prev) Fib(int i)\n{\n    if (i == 0) return (1, 0);\n    var (curr, prev) = Fib(i - 1);\n    return (curr + prev, curr);\n}\n```\n\n### Semantics\n\nIf any top-level statements are present in any compilation unit of the program, the meaning is as if\nthey were combined in the block body of a `Main` method of a `Program` class in the global namespace,\nas follows:\n\n``` c#\npartial class Program\n{\n    static async Task Main(string[] args)\n    {\n        // statements\n    }\n}\n```\n\nThe type is named \"Program\", so can be referenced by name from source code. It is \na partial type, so a type named \"Program\" in source code must also be declared as partial.  \nBut the method name \"Main\" is used only for illustration purposes, the actual name used by\nthe compiler is implementation dependent and the method cannot be referenced by name from\nsource code.\n\nThe method is designated as the entry point of the program. Explicitly declared methods that by convention \ncould be considered as an entry point candidates are ignored. A warning is reported when that happens. It is\npossible to specify a different entry point via the `-main:<type>` compiler switch.\n\nThe entry point method always has one formal parameter, `string[] args`. The execution environment creates and passes a `string[]` argument containing the command-line arguments that were specified when the application was started. The `string[]` argument is never null, but it may have a length of zero if no command-line arguments were specified. The ‘args’ parameter is in scope  within top-level statements and is not in scope outside of them. Regular name conflict/shadowing rules apply.\n\nAsync operations are allowed in top-level statements to the degree they are allowed in statements within\na regular async entry point method. However, they are not required, if `await` expressions and other async\noperations are omitted, no warning is produced.\n\nThe signature of the generated entry point method is determined based on operations used by the top level\nstatements as follows:\n\n| **Async-operations\\Return-with-expression** | **Present** | **Absent** |\n|----------------------------------------|-------------|-------------|\n| **Present** | `static Task<int> Main(string[] args)`| `static Task Main(string[] args)` |\n| **Absent**  | `static int Main(string[] args)` | `static void Main(string[] args)` |\n\nThe example above would yield the following `$Main` method declaration:\n\n``` c#\npartial class Program\n{\n    static void $Main(string[] args)\n    {\n        if (args.Length == 0\n            || !int.TryParse(args[0], out int n)\n            || n < 0) return;\n        Console.WriteLine(Fib(n).curr);\n        \n        (int curr, int prev) Fib(int i)\n        {\n            if (i == 0) return (1, 0);\n            var (curr, prev) = Fib(i - 1);\n            return (curr + prev, curr);\n        }\n    }\n}\n```\n\nAt the same time an example like this:\n``` c#\nawait System.Threading.Tasks.Task.Delay(1000);\nSystem.Console.WriteLine(\"Hi!\");\n```\n\nwould  yield:\n``` c#\npartial class Program\n{\n    static async Task $Main(string[] args)\n    {\n        await System.Threading.Tasks.Task.Delay(1000);\n        System.Console.WriteLine(\"Hi!\");\n    }\n}\n```\n\nAn example like this:\n``` c#\nawait System.Threading.Tasks.Task.Delay(1000);\nSystem.Console.WriteLine(\"Hi!\");\nreturn 0;\n```\n\nwould  yield:\n``` c#\npartial class Program\n{\n    static async Task<int> $Main(string[] args)\n    {\n        await System.Threading.Tasks.Task.Delay(1000);\n        System.Console.WriteLine(\"Hi!\");\n        return 0;\n    }\n}\n```\n\nAnd an example like this:\n``` c#\nSystem.Console.WriteLine(\"Hi!\");\nreturn 2;\n```\n\nwould  yield:\n``` c#\npartial class Program\n{\n    static int $Main(string[] args)\n    {\n        System.Console.WriteLine(\"Hi!\");\n        return 2;\n    }\n}\n```\n\n### Scope of top-level local variables and local functions\n\nEven though top-level local variables and functions are \"wrapped\" \ninto the generated entry point method, they should still be in scope throughout the program in\nevery compilation unit.\nFor the purpose of simple-name evaluation, once the global namespace is reached:\n- First, an attempt is made to evaluate the name within the generated entry point method and \n  only if this attempt fails \n- The \"regular\" evaluation within the global namespace declaration is performed. \n\nThis could lead to name shadowing of namespaces and types declared within the global namespace\nas well as to shadowing of imported names.\n\nIf the simple name evaluation occurs outside of the top-level statements and the evaluation\nyields a top-level local variable or function, that should lead to an error.\n\nIn this way we protect our future ability to better address \"Top-level functions\" (scenario 2 \nin https://github.com/dotnet/csharplang/issues/3117), and are able to give useful diagnostics \nto users who mistakenly believe them to be supported.\n\n"
  },
  {
    "path": "proposals/csharp-9.0/unconstrained-type-parameter-annotations.md",
    "content": "﻿# Unconstrained type parameter annotations\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/3297>\n\n## Summary\n\nAllow nullable annotations for type parameters that are not constrained to value types or reference types: `T?`.\n```C#\nstatic T? FirstOrDefault<T>(this IEnumerable<T> collection) { ... }\n```\n\n## `?` annotation\n\nIn C#8, `?` annotations could only be applied to type parameters that were explicitly constrained to value types or reference types.\nIn C#9, `?` annotations can be applied to any type parameter, regardless of constraints.\n\nUnless a type parameter is explicitly constrained to value types, annotations can only be applied within a `#nullable enable` context.\n\nIf a type parameter `T` is substituted with a reference type, then `T?` represents a nullable instance of that reference type.\n```C#\nvar s1 = new string[0].FirstOrDefault();  // string? s1\nvar s2 = new string?[0].FirstOrDefault(); // string? s2\n```\n\nIf `T` is substituted with a value type, then `T?` represents an instance of `T`.\n```C#\nvar i1 = new int[0].FirstOrDefault();  // int i1\nvar i2 = new int?[0].FirstOrDefault(); // int? i2\n```\n\nIf `T` is substituted with an annotated type `U?`, then `T?` represents the annotated type `U?` rather than `U??`.\n```C#\nvar u1 = new U[0].FirstOrDefault();  // U? u1\nvar u2 = new U?[0].FirstOrDefault(); // U? u2\n```\n\nIf `T` is substituted with a type `U`, then `T?` represents `U?`, even within a `#nullable disable` context.\n```C#\n#nullable disable\nvar u3 = new U[0].FirstOrDefault();  // U? u3\n```\n\nFor return values, `T?` is equivalent to `[MaybeNull]T`;\nfor argument values, `T?` is equivalent to `[AllowNull]T`.\nThe equivalence is important when overriding or implementing interfaces from an assembly compiled with C#8.\n```C#\npublic abstract class A\n{\n    [return: MaybeNull] public abstract T F1<T>();\n    public abstract void F2<T>([AllowNull] T t);\n}\n\npublic class B : A\n{\n    public override T? F1<T>() where T : default { ... }       // matches A.F1<T>()\n    public override void F2<T>(T? t) where T : default { ... } // matches A.F2<T>()\n}\n```\n\n## `default` constraint\n\nFor compatibility with existing code where overridden and explicitly implemented generic methods could not include explicit constraint clauses, `T?` in an overridden or explicitly implemented method is treated as `Nullable<T>` where `T` is a value type.\n\nTo allow annotations for type parameters constrained to reference types, C#8 allowed explicit `where T : class` and `where T : struct` constraints on the overridden or explicitly implemented method.\n```C#\nclass A1\n{\n    public virtual void F1<T>(T? t) where T : struct { }\n    public virtual void F1<T>(T? t) where T : class { }\n}\n\nclass B1 : A1\n{\n    public override void F1<T>(T? t) /*where T : struct*/ { }\n    public override void F1<T>(T? t) where T : class { }\n}\n```\n\nTo allow annotations for type parameters that are not constrained to reference types or value types, C#9 allows a new `where T : default` constraint.\n```C#\nclass A2\n{\n    public virtual void F2<T>(T? t) where T : struct { }\n    public virtual void F2<T>(T? t) { }\n}\n\nclass B2 : A2\n{\n    public override void F2<T>(T? t) /*where T : struct*/ { }\n    public override void F2<T>(T? t) where T : default { }\n}\n```\n\nIt is an error to use a `default` constraint other than on a method override or explicit implementation.\nIt is an error to use a `default` constraint when the corresponding type parameter in the overridden or interface method is constrained to a reference type or value type.\n\n## Design meetings\n\n- https://github.com/dotnet/csharplang/blob/master/meetings/2019/LDM-2019-11-25.md\n- https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-06-17.md#t\n"
  },
  {
    "path": "proposals/csharp-9.0/variance-safety-for-static-interface-members.md",
    "content": "﻿# Variance Safety for static interface members\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/3275>\n\n## Summary\n\nAllow static, non-virtual members in interfaces to treat type parameters in their declarations as invariant, regardless of their declared variance.\n\n## Motivation\n\n\n- https://github.com/dotnet/csharplang/issues/3275\n- https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-06-24.md#interface-static-member-variance\n\nWe considered variance in `static` interface members. Today, for co/contravariant type parameters\nused in these members, they must follow the full standard rules of variance, leading to some\ninconsistency with the way that `static` fields are treated vs `static` properties or methods:\n\n```cs\npublic interface I<out T>\n{\n    static Task<T> F = Task.FromResult(default(T)); // No problem\n    static Task<T> P => Task.FromResult(default(T));   //CS1961\n    static Task<T> M() => Task.FromResult(default(T));    //CS1961\n    static event EventHandler<T> E; // CS1961\n}\n```\n\nBecause these members are `static` and non-virtual, there aren't any safety issues here: you can't\nderive a looser/more restricted member in some fashion by subtyping the interface and overriding\nthe member.\n\n## Detailed Design\n\nHere is the proposed content for Vaiance Safety section of the language specification\n[§17.2.3.2](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#17232-variance-safety).\nThe change is the addition of \"*These restrictions do not apply to occurrences of types\nwithin declarations of static members.*\" sentence at the beginning of the section. \n\n### Variance safety\n\nThe occurrence of variance annotations in the type parameter list of a type restricts the places where types can occur within the type declaration.\n*These restrictions do not apply to ocurrances of types within declarations of static members.*\n\nA type `T` is ***output-unsafe*** if one of the following holds:\n\n*  `T` is a contravariant type parameter\n*  `T` is an array type with an output-unsafe element type\n*  `T` is an interface or delegate type `S<A1,...,Ak>` constructed from a generic type `S<X1,...,Xk>` where for at least one `Ai` one of the following holds:\n   * `Xi` is covariant or invariant and `Ai` is output-unsafe.\n   * `Xi` is contravariant or invariant and `Ai` is input-safe.\n   \nA type `T` is ***input-unsafe*** if one of the following holds:\n\n*  `T` is a covariant type parameter\n*  `T` is an array type with an input-unsafe element type\n*  `T` is an interface or delegate type `S<A1,...,Ak>` constructed from a generic type `S<X1,...,Xk>` where for at least one `Ai` one of the following holds:\n   * `Xi` is covariant or invariant and `Ai` is input-unsafe.\n   * `Xi` is contravariant or invariant and `Ai` is output-unsafe.\n\nIntuitively, an output-unsafe type is prohibited in an output position, and an input-unsafe type is prohibited in an input position.\n\nA type is ***output-safe*** if it is not output-unsafe, and ***input-safe*** if it is not input-unsafe.\n\n\n## Other Considerations\n\nWe also considered whether this could potentially interfere with some of the other\nenhancements we hope to make regarding roles, type classes, and extensions. These should all be\nfine: we won't be able to retcon the existing static members to be virtual-by-default for interfaces,\nas that would end up being a breaking change on multiple levels, even without changing the variance\nbehavior here.\n"
  },
  {
    "path": "proposals/deconstruction-in-lambda-parameters.md",
    "content": "# Deconstruction in lambda parameters\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/9848>\n\n## Summary\n\nLambda parameters may be deconstructed within the parameter list of the lambda expression:\n\n```cs\nAction<(int, int)> action = ((a, b)) => { };\n\nAction<(int, int)> action = ((int a, int _)) => { };\n\nAction<(int, SomeRecord)> action = ((a, (b, _))) => { };\n```\n\n## Motivation\n\nThere has been steady interest in this feature since tuple deconstruction debuted in C# 7. When using LINQ methods, it is natural to bundle multiple variables into a tuple to be used in later stages. Here is one illustration provided by the community for the desired workflow:\n\n```cs\nvar item = Enumerable\n    .Range(1, 10)\n    .Select(i => (i + 1, i * i))\n    .Where(((a, b)) => 2 * a < b)\n    .OrderBy(((a, b)) => b)\n    .Last();\n```\n\nAnother use case is when passing multiple variables through generic arguments which are provided in order to avoid allocations. Examples are the `TLocal` parameter on [`Parallel.For`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.parallel.for) and [`Parallel.ForEach`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.parallel.foreach), as well as [`ThreadPool.QueueUserWorkItem<TState>`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.threadpool.queueuserworkitem?view=net-10.0#system-threading-threadpool-queueuserworkitem-1(system-action((-0))-0-system-boolean)). The usage pattern would look like:\n\n```cs\nThreadPool.QueueUserWorkItem(\n    static ((varA, varB, varC)) => { ... },\n    (varA, varB, varC),\n    preferLocal: false);\n```\n\nIn the prior examples, the introduction of tuples was a user decision. However, some APIs (including LINQ's `Zip` method) may always introduce tuples, and sometimes in a nested fashion. The user then has two options. One option is to dot into deeply nested tuples as in `tuple.Left.Right` below, where the tuple names are chosen by the API rather than by the user and are often less than meaningful. The other option is to add a deconstruction statement to the lambda which may entail converting to a block body:\n\n```cs\nvar finalProvider = compilationAndGroupedNodesProvider.SelectMany((tuple, cancellationToken) =>\n{\n    // Then either:\n    var ((syntaxTree, syntaxNodes), compilation) = tuple;\n\n    // or:\n    ProcessNodes(tuple.Left.Right);\n```\n\nWhile the deconstruction assignment works, it takes the user out of the realm of being able to simply use expression-bodied lambdas.\n\nOverall, this is a small feature aimed at expanding the goodness started in v7 with deconstructible types, and at reducing recurring papercuts when using tuples.\n\n## Detailed design\n\nAny lambda parameter may be deconstructed if its type is deconstructible. A deconstructed lambda parameter consists entirely of tuple syntax with either implicitly-typed or explicitly-typed tuple elements, corresponding to whether the lambda is implicitly-typed or explicitly-typed. The tuple syntax must have at least two elements. Parameter modifiers and attributes are not permitted inside or outside the tuple.\n\nA deconstructing tuple element may be one of three operations: variable declaration, discard, or recursive deconstruction. Each of the three operations works the same as it does in a deconstructing assignment or `foreach` iteration variable deconstruction; however, the syntaxes for these operations have some differences in lambda parameter deconstruction.\n\n(Examples of deconstructible types are tuples, positional records, and types with user-defined `Deconstruct` instance or extension methods. This proposal does not change the set of types that the language considers deconstructible.)\n\n### Semantics\n\nA compile-time error is produced in the same way as in a deconstructing assignment or deconstructing `foreach` if the type is not deconstructible with the given arity and any given explicit types.\n\nCode within the body of the lambda may use the declared variable names to access the deconstructed values. Deconstruction is performed before the lambda method body runs. It is performed the same way as in a deconstructing assignment or deconstructing `foreach`, to the extent needed to populate the declared variables, regardless of whether the variables are used in the body of the lambda.\n\nCode within the body of the lambda may assign to the declared variables and take writable references to them. As with by-value lambda parameters, changes may be written to these declared variables, and such changes are not observable outside the lambda.\n\nIt is an error if a declared variable name is the same as a lambda parameter name or the same as another declared variable name.\n\n### Implicit and explicit typing\n\nAn implicitly-typed lambda does not specify parameter types (`(a, b) =>`), whereas an explicitly-typed lambda does (`(int a, int b) =>`). Variable declarations and discards in lambda parameters must follow suit, including nested deconstructions.\n\nIn an implicitly-typed lambda, types are never specified for variable declarations and discards:\n\n```cs\nAction<int, (int, (int, int))> action = (a, (b, (c, _))) => { };\n```\n\nWhereas in an explicitly-typed lambda, types are always specified for variable declarations and discards:\n\n```cs\nAction<int, (int, (int, int))> action = (int a, (int b, (int c, int _))) => { };\n```\n\n`var` is not permitted as a variable declaration type or discard type within the parameter list of either implicitly-typed or explicitly-typed lambdas.\n\n### Discards\n\nWhen exactly one lambda parameter is named `_`, it is considered a parameter name rather than a discard for backwards compatibility reasons. However, if there is any deconstruction in the lambda parameters, `_` becomes a discard at the top level.\n\nThis avoids the confusion that would occur if `_` was able to be referenced in the lambda body, despite there being two discards in the lambda parameter list (one top-level, one nested):\n\n```cs\nAction<int, (int, int)> action = (_, (a, _)) => { /* _ is not an identifier here */ };\n```\n\nThis mirrors the effect of a second top-level discard as in the following example:\n\n```cs\nAction<int, (int, int)> action = (_, _) => { /* _ is not an identifier here */ };/\n```\n\nWe go even further and cause `_` at the top level to be a discard if there is any deconstruction, even without a second discard, because this is not a breaking change for the language and it avoids spreading the dichotomy of `_`-as-discard-or-parameter-name any further:\n\n```cs\nAction<int, (int, int)> action = (_, (a, b)) => { /* _ is not an identifier here */ };\n```\n\n### Parameter list parentheses\n\nA lambda's parameter list parentheses may not be omitted if any parameter in a lambda expression is deconstructed:\n\n```cs\nAction<(int, int)> action = (a, b) => { }; // ❌ INVALID\nAction<(int, int)> action = ((a, b)) => { }; // Valid\n\nAction<(int, int)> action = (int a, int b) => { }; // ❌ INVALID\nAction<(int, int)> action = ((int a, int b)) => { }; // Valid\n```\n\n### Method type inference\n\nA deconstructed lambda parameter can be used to infer a tuple type (see [inferred tuple type](#inferred-tuple-type)) for a method type parameter:\n\n```cs\nM(((int a, string b)) => { });          // Success: T is (int a, string b)\n\nM(((int a, (string _, byte _))) => { }); // Success: T is (int a, (string, byte))\n\nvoid M<T>(Action<T> action) { }\n```\n\nA deconstructed lambda parameter may also be used to infer individual element types for the tuple:\n\n```cs\nM(((int a, string b)) => { });         // Success: T1 is int, T2 is string\n\nvoid M<T1, T2>(Action<(T1, T2)> action) { }\n```\n\n```cs\nM(((int a, (string b, byte c))) => { }); // Success: T1 is int, T2 is string, T3 is byte\n\nvoid M<T1, T2, T3>(Action<(T1, (T2, T3))> action) { }\n```\n\nHere is an example that combines inferring individual element types for a tuple from the method signature with inferring an additional type type for a method type parameter:\n\n```cs\nM(((int a, (string b, byte c))) => { }); // Success: T1 is int, T2 is (string b, byte c)\n\nvoid M<T1, T2>(Action<(T1, T2)> action) { }\n```\n\nA deconstructed lambda parameter may not be used to infer type parameters of types besides tuples. This would require mapping Deconstruct methods back to type parameters and is not expected to be an essential scenario.\n\n```cs\nM(((int a, int b)) => { }); // ❌ INVALID\n\nvoid M<T1, T2>(Action<R<T1, T2>> action) { }\n\nrecord R<T1, T2>(T1 Prop1, T2 Prop2);\n```\n\n### Overload resolution\n\nDeconstructed lambda parameters can resolve ambiguities in overload resolution if there is exactly one candidate that allows the deconstructed lambda parameters to all map to tuple types:\n\n```cs\nM(((int a, int b)) => { }); // Succeeds: calls M(Action<(int A, int B)>)\n\nvoid M(Action<(int A, int B)> action) { }\nvoid M(Action<R> action) { }\n\nrecord R(int Prop1, int Prop2);\n```\n\nThis may combine with [method type inference](#method-type-inference). If the deconstructed lambda parameter maps to a type parameter for which a tuple type may be inferred, and no other overload maps the deconstructed lambda parameter to a tuple type, overload resolution succeeds:\n\n```cs\nM2(((int a, int b)) => { }); // Succeeds: calls M<(int a, int b)>(Action<T>)\n\nvoid M2<T>(Action<T> action) { }\nvoid M2(Action<R> action) { }\n\nrecord R(int Prop1, int Prop2);\n```\n\nHowever, no attempt is made to resolve ambiguities between non-tuple types. A deconstructed lambda parameter may become valid on any parameter type if that type declares a new Deconstruct instance method or if a Deconstruct extension method is imported. This takes a page from target-typed new: `new(...)` expressions also contribute no information to overload resolution for similar reasons.\n\n```cs\nM(((int a, int b)) => { }); // ❌ INVALID: Ambiguous invocation\n\nvoid M(Action<object> action) { }\nvoid M(Action<R> action) { }\n\nrecord R(int Prop1, int Prop2);\n```\n\n### Lambda natural types\n\nAn explicitly typed lambda with a deconstructed lambda parameter has a natural type. The deconstructed lambda parameter contributes a tuple type for the corresponding parameter in the lambda natural type as described by [inferred tuple type](#inferred-tuple-type).\n\nLambda natural types do not make use of lambda parameter names, so the lack of a specified parameter name in a deconstructed lambda parameter is of no consequence.\n\n### Inferred tuple type\n\nA tuple type may be inferred from a deconstructed lambda parameter for [method type inference](#method-type-inference) or [lambda natural types](#lambda-natural-types).\n\nA tuple type is determined for a given deconstructed lambda parameter as follows:\n\n1. Its arity is the arity of the deconstructing tuple syntax.\n1. For each deconstructing tuple element:\n   1. If the element is a variable declaration, the corresponding tuple type element is of the same type as the variable declaration and has the same name as the variable declaration.\n   1. If the element is a discard, the corresponding tuple type element is of the same type as the discard and has no name.\n   1. If the element is a nested deconstruction, a nested tuple type is formed from the nested deconstruction using the same containing algorithm as for the top level. The corresponding tuple type element is of the resulting nested tuple type and has no name.\n\nThe rationale for using the deconstructed variable name as the tuple element name is the same as the rationale for inferring the variable names as tuple element names in the following example:\n\n```cs\nvar a = 1;\nvar b = 2;\nvar x = (a, b);\nx.a++;\nx.b++;\n```\n\n## Specification\n\nTODO\n\n## Expansions\n\nDeconstruction could be allowed in LINQ clauses. Deconstruction in `from` and `let` is tracked by <https://github.com/dotnet/csharplang/issues/8875>.\n"
  },
  {
    "path": "proposals/dictionary-expressions.md",
    "content": "# Dictionary Expressions\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/8659>\n\n## Summary\n\n*Dictionary Expressions* are a continuation of the C# 12 *Collection Expressions* feature.  They extend that system with a new terse syntax, `[\"mads\": 21, \"dustin\": 22]`, for creating common dictionary values.  Like with collection expressions, merging other dictionaries into these values is possible using the existing spread operator `..` like so: `[.. currentStudents, \"mads\": 21, \"dustin\": 22]`\n\nSeveral dictionary-like types can be created without external BCL support.  These types are:\n\n1. Concrete dictionary-like types, containing an read/write indexer `TValue this[TKey] { get; set; }`, like `Dictionary<TKey, TValue>` and `ConcurrentDictionary<TKey, TValue>`.\n1. The well-known generic BCL dictionary interface types: `IDictionary<TKey, TValue>` and `IReadOnlyDictionary<TKey, TValue>`.\n\nFurther support is present for dictionary-like types not covered above through the `CollectionBuilderAttribute` and a similar API pattern to the corresponding *create method* pattern introduced for collection expressions.  Types like `ImmutableDictionary<TKey, TValue>` and `FrozenDictionary<TKey, TValue>` will be updated to support this pattern.\n\n## Motivation\n\nWhile dictionaries are similar to standard sequential collections in that they can be interpreted as a sequence of key/value pairs, they differ in that they are often used for their more fundamental capability of efficient looking up of values based on a provided key.  In an analysis of the BCL and the NuGet package ecosystem, sequential collection types and values make up the lion's share of collections used.  However, dictionary types were still used a significant amount, with appearances in APIs occurring at between 5% and 10% the amount of sequential collections, and with dictionary values appearing universally in all programs.\n\nCurrently, all C# programs must use many different and unfortunately verbose approaches to create instances of such values. Some approaches also have performance drawbacks. Here are some common examples:\n\n1. Collection-initializer types, which require syntax like `new Dictionary<X, Y> { ... }` (lacking inference of possibly verbose TKey and TValue) prior to their values, and which can cause multiple reallocations of memory because they use `N` `.Add` invocations without supplying an initial capacity.\n1. Immutable collections, which require syntax like `ImmutableDictionary.CreateRange(...)`, but which are also unpleasant due to the need to provide values as an `IEnumerable<KeyValuePair>`.  Builders are even more unwieldy.\n1. Read-only dictionaries, which require first making a normal dictionary, then wrapping it.\n1. Concurrent dictionaries, which lack an `.Add` method, and thus cannot easily be used with collection initializers.\n\nLooking at the surrounding ecosystem, we also find examples everywhere of dictionary creation being more convenient and pleasant to use. Swift, TypeScript, Dart, Ruby, Python, and more, opt for a succinct syntax for this purpose, with widespread usage, and to great effect. Cursory investigations have revealed no substantive problems arising in those ecosystems with having these built-in syntax forms.\n\nUnlike with *collection expressions*, C# does not have an existing pattern serving as the corresponding deconstruction form.  Designs here should be made with a consideration for being complementary with future deconstruction work. \n\nAn inclusive solution is needed for C#. It should meet the vast majority of case for customers in terms of the dictionary-like types and values they already have. It should also feel pleasant in the language, complement the work done with collection expressions, and naturally extend to pattern matching in the future.\n\n## Detailed Design\n\nThe following grammar productions are added:\n\n```diff\n\ncollection_element\n  : expression_element\n  | spread_element\n+ | key_value_pair_element\n  ;\n\n+ key_value_pair_element\n+  : expression ':' expression\n+  ;\n```\n\nAlternative syntaxes are available for consideration, but should be considered later due to the bike-shedding cost involved.  Picking the above syntax allows the compiler team to move quickly at implementing the semantic side of the feature, allowing earlier previews to be made available.  These syntaxes include, but are not limited to:\n\n1. Using braces instead of brackets.  `{ k1: v1, k2: v2 }`.\n2. Using brackets for keys: `[k1] = v1, [k2] = v2`\n3. Using arrows for elements: `k1 => v1, k2 => v2`.\n\nChoices here would have implications regarding potential syntactic ambiguities, collisions with potential future language features, and concerns around corresponding pattern forms.  However, all of those should not generally affect the semantics of the feature and can be considered at a later point dedicated to determining the most desirable syntax.\n\n## Design Intuition\n\nThere are three core aspects to the design of dictionary expressions. \n\n1. Collection expressions containing `KeyValuePair<,>` (coming from `expression_element`, `spread_element`, or `key_value_pair_element` elements) can now instantiate a normal *collection type* *or* a *dictionary type*.\n\n    So, if the target type for a collection expression is some *collection type* (that is *not* a *dictionary type*) with an element of `KeyValuePair<,>` then it can be instantiated like so:\n\n    ```c#\n    List<KeyValuePair<string, int>> nameToAge = [\"mads\": 21];\n    ```\n\n    This is just a simple augmentation on top of the existing collection expression rules.  In the above example, the code will be emitted as:\n\n    ```c#\n    __result.Add(new KeyValuePair<string, int>(\"mads\", 21));\n    ```\n\n2. Introduction of the *dictionary type*. *Dictionary types* are types that are similar to the existing *collection types*, with the additional requirements that they have an *element type* of some `KeyValuePair<TKey, TValue>` *and* have an indexer `TValue this[TKey] { ... }`. The former requirement ensures that `List<T>` is not considered a dictionary type, as its element type is `T` not `KeyValuePair<,>`. The latter requirement ensures that `List<KeyValuePair<int, string>>` is also not considered a dictionary type, with its `int`-to-`KeyValuePair<int, string>` indexer (instead of an `int`-to-`string` indexer). `Dictionary<TKey, TValue>` passes both requirements.\n\n    As such, if the target type for the collection expression *is* a *dictionary* type, then all `KeyValuePair<,>` produced by `expression_element` or `spread_element` elements will be changed to use the indexer\\* to assign into the resultant dictionary. Any `key_value_pair_element` will use that indexer\\* directly as well.  For example:\n\n    ```c#\n    Dictionary<string, int> nameToAge = [\"mads\": 21, existingDict.MaxPair(), .. otherDict];\n\n    // would be rewritten similar to:\n\n    Dictionary<string, int> __result = new();\n    __result[\"mads\"] = 21;\n\n    // Note: the below casts must be legal for the dictionary\n    // expression to be legal\n    var __t1 = existingDict.MaxPair();\n    __result[(string)__t1.Key] = (int)__t1.Value;\n\n    foreach (var __t2 in otherDict)\n        __result[(string)__t2.Key] = (int)__t2.Value;\n    ```\n\n    \\* The above holds for types with an available `set` accessor in their indexer. Similar semantics are provided for dictionary types without a writable indexer (like immutable dictionary types, or `IReadOnlyDictionary<,>`), and are explained later in the spec.\n\n3. Alignment of the rules for assigning to *dictionary types* with the rules for assigning to *collection types*, just requiring aspects such as *element* and *iteration types* to be some `KeyValuePair<,>`.  *However*, with the rules extended such that the `KeyValuePair<,>` type itself is relatively transparent, and instead the rule is updated to work on the underlying `TKey` and `TValue` types.\n\n    This view allows for very natural processing of what would otherwise be thought of as disparate `KeyValuePair<,>` types.  For example:\n\n    ```c#\n    Dictionary<string, int> d1 = ...;\n\n    // Assignment possible, even though KeyValuePair<string, int>` is not itself assignable to KeyValuePair<object, long>\n    Dictionary<object, long> d2 = [.. d1]; \n    ```\n\nNote: Many rules in this spec will refer to types needing to be the same `KeyValuePair<,>` type.  This is an informal way of saying the types must have an identity conversion between them.  As such, `KeyValuePair<(int X, int Y), object>` would be considered the same type a `KeyValuePair<(int, int), object?>` for the purpose of these rules.\n\nWith a broad interpretation of these rules, all of the following would be legal:\n\n```c#\n// Assigning to dictionary types:\nDictionary<string, int> nameToAge1 = [\"mads\": 21, existingKvp];     // as would\nDictionary<string, int> nameToAge2 = [\"mads\": 21, .. existingDict]; // as would\nDictionary<string, int> nameToAge3 = [\"mads\": 21, .. existingListOfKVPS];\n\n// Assigning to collection types:\nList<string, int> nameToAge1 = [\"mads\": 21, existingKvp];     // as would\nList<string, int> nameToAge2 = [\"mads\": 21, .. existingDict]; // as would\nList<string, int> nameToAge3 = [\"mads\": 21, .. existingListOfKVPS];\n```\n\n## Comparer support\n\nA dictionary expression can also provide a custom *comparer* to control its behavior just by including such a value as the first `expression_element` in the expression. For example:\n\n```c#\nDictionary<string, int> caseInsensitiveMap = [StringComparer.CaseInsensitive, .. existingMap];\n\n// Or even:\nDictionary<string, int> caseInsensitiveMap = [StringComparer.CaseInsensitive];\n```\n\nWhile this approach does reuse `expression_element` both for specifying individual `KeyValuePair<,>` as well as a comparer for the dictionary, there is no ambiguity here as no type could satisfy both types.  \n\nThe motivation for this is due to the high number of cases of dictionaries found in real world code with custom comparers.  Support for any further customization is not provided.  This is in line with the lack of support for customization for normal collection expressions (like setting initial capacity). Other designs were explored which attempted to generalize this concept (for example, passing arbitrary arguments along).  These designs never landed on a satisfactory syntax.  And the concept of passing an arbitrary argument along doesn't supply a satisfactory answer on how that would control instantiating an `IDictionary<,>` or `IReadOnlyDictionary<,>`.\n\n### Question: Comparers for *collection types*\n\nShould support for the key comparer be available for normal *collection types*, not just *dictionary types*.  This would be useful for set-like types like `HashSet<>`.  For example:\n\n```c#\nHashSet<string> values = [StringComparer.CaseInsensitive, .. names];\n```\n\n### Question: Specialized comparer syntax.\n\nShould there be more distinctive syntax for the comparer?  Simply starting with a comparer could be difficult to tease out.  Having a syntax like so could make things clearer:\n\n```c#\n// `comparer: ...` to indicate the purpose of this value\nDictionary<string, int> caseInsensitiveMap = [comparer: StringComparer.CaseInsensitive, .. existingMap];\n\n// Semicolon to more clearly delineate the comparer\nDictionary<string, int> caseInsensitiveMap = [StringComparer.CaseInsensitive; .. existingMap];\n\n// Both?\nDictionary<string, int> caseInsensitiveMap = [comparer : StringComparer.CaseInsensitive; .. existingMap];\n```\n\n### Question: Types of comparers supported.\n\n`IEqualityComparer<T>` is not the only comparer type used in collections.  `SortedDictionary<,>` and `SortedSet<,>` both use an `IComparer<T>` instead (as they have ordering, not hashing semantics).  It seems unfortunate to leave out `SortedDictionary<,>` if we are supporting the rest.  As such, perhaps the rules should just be that the special value in the collection be typed as some `IComparer<T>` or some `IEqualityComparer<T>`.  \n\n## Conversions\n\n[*Collection expression conversions*](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#conversions) are **updated** to include conversions to *dictionary types*.\n\nAn implicit *collection expression conversion* exists from a collection expression to the following types:\n* A single dimensional *array type* `T[]`, in which case the *element type* is `T`\n* A *span type*:\n  * `System.Span<T>`\n  * `System.ReadOnlySpan<T>`  \n  In which case the *element type* is `T`\n* A *type* with an appropriate *[create method](#create-methods)*, in which case the *element type* is the [*iteration type*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/statements.md#1295-the-foreach-statement) determined from a `GetEnumerator` instance method or enumerable interface, not from an extension method\n* A *struct* or *class type* that implements `System.Collections.IEnumerable` where:\n  * The *type* has an *[applicable](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/expressions.md#11642-applicable-function-member)* constructor that can be invoked with no arguments, and the constructor is accessible at the location of the collection expression.\n  * **One of the following holds:**\n    * **The [*iteration type*](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md#1395-the-foreach-statement) of the *type* is `KeyValuePair<K, V>`, and the *type* has an instance *indexer*, with `get` and `set` accessors where:**\n      * **The indexer has a single parameter passed by value or with `in`.**\n      * **There is an identity conversion from the parameter type to `K` and an identity conversion from the indexer type to `V`.** *Identity conversions rather than exact matches allow type differences that are ignored by the runtime: `object` vs. `dynamic`; tuple element names; nullable reference types; etc.*\n      * **The `get` accessor returns by value.**\n      * **The `get` and `set` accessors are declared `public`.**\n      * **The indexer is not [*hidden*](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/basic-concepts.md#7723-hiding-through-inheritance).**\n    * If the collection expression has any elements, the *type* has an instance or extension method `Add` where:\n      * The method can be invoked with a single value argument.\n      * If the method is generic, the type arguments can be inferred from the collection and argument.\n      * The method is accessible at the location of the collection expression.\n\n    In which case the *element type* is the [*iteration type*](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md#1395-the-foreach-statement) of the *type*.\n* An *interface type*:\n  * `System.Collections.Generic.IEnumerable<T>`\n  * `System.Collections.Generic.IReadOnlyCollection<T>`\n  * `System.Collections.Generic.IReadOnlyList<T>`\n  * `System.Collections.Generic.ICollection<T>`\n  * `System.Collections.Generic.IList<T>`  \n    In which case the *element type* is `T`\n* **An *interface type*:**\n  * **`System.Collections.Generic.IDictionary<TKey, TValue>`**\n  * **`System.Collections.Generic.IReadOnlyDictionary<TKey, TValue>`**  \n  **In which case the *element type* is `KeyValuePair<TKey, TValue>`**\n\n*Collection expression conversions* require implicit conversions for each element.\nThe element conversion rules are **updated** as follows.\n\nThe implicit conversion exists if the type has an *element type* `T` where for each *element* `Eᵢ` in the collection expression:\n* If `Eᵢ` is an *expression element* then:\n  * There is an implicit conversion from `Eᵢ` to `T`, **or**\n  * **There is no implicit conversion from `Eᵢ` to `T`, and `T` is a type `KeyValuePair<K, V>`, and `Eᵢ` has a type `KeyValuePair<Kᵢ, Vᵢ>`, and there is an implicit conversion from `Kᵢ` to `K` and an implicit conversion from `Vᵢ` to `V`.**\n* If `Eᵢ` is a *spread element* `..Sᵢ` then:\n  * There is an implicit conversion from the *iteration type* of `Sᵢ` to `T`, **or**\n  * **There is no implicit conversion from the *iteration type* of `Sᵢ` to `T`, and `T` is a type `KeyValuePair<K, V>`, and `Sᵢ` has an *iteration type* `KeyValuePair<Kᵢ, Vᵢ>`, and there is an implicit conversion from `Kᵢ` to `K` and an implicit conversion from `Vᵢ` to `V`.**\n* **If `Eᵢ` is a *key-value pair element* `Kᵢ:Vᵢ`, then `T` is a type `KeyValuePair<K, V>`, and there is an implicit conversion from `Kᵢ` to `K` and an implicit conversion from `Vᵢ` to `V`.**\n\n> Allowing implicit key and value conversions is useful for *expression elements* and *spread elements* where the key or value types do not match the collection element type exactly.\n> \n> ```csharp\n> Dictionary<int, string>  x = ...;\n> Dictionary<long, object> y = [..x]; // key-value pair conversion from KVP<int, string> to KVP<long, object>\n> ```\n\nCollection arguments are *not* considered when determining *collection expression* conversions.\n\n## Create methods\n\n> A *create method* is indicated with a `[CollectionBuilder(...)]` attribute on the *collection type*.\n> The attribute specifies the *builder type* and *method name* of a method to be invoked to construct an instance of the collection type.\n\n> **A create method need not be called `Create`.  Instead, it may commonly use the name `CreateRange` in the dictionary domain.**\n>\n> For the create method:\n>   - The method must have a single parameter of type System.ReadOnlySpan<E>, passed by value, and there is an identity conversion from E to the *iteration type* of the collection type. \n>\n>    - **The method has two parameters, where the first is a [*comparer*](#Comparer-support) and the other follows the rules of the *single parameter* rule above. This method will be called if the collection expression's first element is an [*comparer*](#Comparer-support) that is convertible to that parameter type.**\n\n*Dictionary type* authors who use `CollectionBuilderAttribute` should have the method that is pointed to have `overwrite` not `throw` semantics when encountering the same `.Key` multiple times in the span of `KeyValuePair<,>` they are processing.\n\nThe runtime has committed to supplying these new CollectionBuilder methods that take `ReadOnlySpan<>` for their immutable collections.\n\n## Construction\n\n[*Collection construction*](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#construction) is **updated** as follows.\n\nThe elements of a collection expression are evaluated in order, left to right. Each element is evaluated exactly once, and any further references to the elements refer to the results of this initial evaluation.  \n...\n\nIf the target type is a *struct* or *class type* that implements `System.Collections.IEnumerable`, and the target type does not have a *[create method](#create-methods)*, the construction of the collection instance is as follows:\n\n* The elements are evaluated in order. Some or all elements may be evaluated *during* the steps below rather than before.\n\n* The compiler *may* determine the *known length* of the collection expression by invoking [*countable*](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-8.0/ranges.md#adding-index-and-range-support-to-existing-library-types) properties &mdash; or equivalent properties from well-known interfaces or types &mdash; on each *spread element expression*.\n\n* The constructor that is applicable with no arguments is invoked.\n\n* **If the *iteration type* is a type `KeyValuePair<K, V>` and the [*collection expression conversion*](#conversions) involves an instance *indexer*, then:**\n  * **For each element in order:**\n    * **If the element is a *key value pair element* `Kᵢ:Vᵢ` then:**\n      * **First `Kᵢ` is evaluated, then `Vᵢ` is evaluated.**\n      * **The indexer is invoked on the collection instance with the converted values of `Kᵢ` and `Vᵢ`.**\n    * **If the element is an *expression element* `Eᵢ`, then:**\n      * **If `Eᵢ` is implicitly convertible to `KeyValuePair<K, V>`, then:**\n        * **`Eᵢ` is evaluated and converted to a `KeyValuePair<K, V>`.**\n        * **The indexer is invoked on the collection instance with `Key` and `Value` of the converted value.**\n      * **Otherwise, `Eᵢ` has a type `KeyValuePair<Kᵢ, Vᵢ>`, in which case:**\n        * **`Eᵢ` is evaluated.**\n        * **The indexer is invoked on the collection instance with `Key` and `Value` of the value, converted to `K` and `V`.**\n    * **If the element is a *spread element* where the spread element *expression* has an [*iteration type*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/statements.md#1295-the-foreach-statement) `Tᵢ` then:**\n      * **An applicable `GetEnumerator` instance or extension method is invoked on the spread element *expression***.\n      * **For each item from the enumerator:**\n        * **If `Tᵢ` is implicitly convertible to `KeyValuePair<K, V>` then:**\n          * **The item is converted to a `KeyValuePair<K, V>`.**\n          * **The indexer is invoked on the collection instance with `Key` and `Value` of the converted item.**\n        * **Otherwise, `Tᵢ` is a type `KeyValuePair<Kᵢ, Vᵢ>`, in which case:**\n          * **The indexer is invoked on the collection instance with `Key` and `Value` of the item, converted to `K` and `V`.**\n      * **If the enumerator implements `IDisposable`, then `Dispose` will be called after enumeration, regardless of exceptions.**\n\n* **If the *iteration type* is a type `KeyValuePair<K, V>` and the [*collection expression conversion*](#conversions) involves an applicable `Add` method, then:**\n  * **For each element in order:**\n    * **If the element is a *key value pair element* `Kᵢ:Vᵢ` then:**\n      * **First `Kᵢ` is evaluated, then `Vᵢ` is evaluated.**\n      * **A `KeyValuePair<K, V>` instance is constructed from the values of `Kᵢ` and `Vᵢ` converted to `K` and `V`.**\n      * **The applicable `Add` instance or extension method is invoked with the `KeyValuePair<K, V>` instance as the argument.**\n    * **If the element is an *expression element* `Eᵢ`, then:**\n      * **If `Eᵢ` is implicitly convertible to `KeyValuePair<K, V>`, then the applicable `Add` instance or extension method is invoked with `Eᵢ` as the argument.**\n      * **Otherwise, `Eᵢ` has a type `KeyValuePair<Kᵢ, Vᵢ>`, in which case:**\n        * **`Eᵢ` is evaluated.**\n        * **A `KeyValuePair<K, V>` instance is constructed from the `Key` and `Value` of the value, converted to `K` and `V`.**\n        * **The applicable `Add` instance or extension method is invoked with the `KeyValuePair<K, V>` instance as the argument.**\n    * **If the element is a *spread element* where the spread element *expression* has an [*iteration type*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/statements.md#1295-the-foreach-statement) `Tᵢ` then:**\n      * **An applicable `GetEnumerator` instance or extension method is invoked on the spread element *expression***.\n      * **For each item from the enumerator:**\n        * **If `Tᵢ` is implicitly convertible to `KeyValuePair<K, V>` then the applicable `Add` instance or extension method is invoked with item as the argument.**\n        * **Otherwise, `Tᵢ` is a type `KeyValuePair<Kᵢ, Vᵢ>`, in which case:**\n          * **A `KeyValuePair<K, V>` instance is constructed from the `Key` and `Value` of the item, converted to `K` and `V`.**\n          * **The applicable `Add` instance or extension method is invoked with the `KeyValuePair<K, V>` instance as the argument.**\n      * **If the enumerator implements `IDisposable`, then `Dispose` will be called after enumeration, regardless of exceptions.**\n\n* Otherwise, the *iteration type* is *not* a `KeyValuePair<K, V>` type, in which case:\n  * For each element in order:\n    * If the element is an *expression element*, the applicable `Add` instance or extension method is invoked with the element *expression* as the argument.\n    * If the element is a *spread element* then ...:\n      * An applicable `GetEnumerator` instance or extension method is invoked on the *spread element expression*.\n      * For each item from the enumerator:\n        * The applicable `Add` instance or extension method is invoked on the *collection instance* with the item as the argument.\n      * If the enumerator implements `IDisposable`, then `Dispose` will be called after enumeration, regardless of exceptions.\n      * ...\n\nIf the target type is an *array*, a *span*, a type with a *[create method](#create-methods)*, or an *interface*, the construction of the collection instance is as follows:\n\n* The elements are evaluated in order. Some or all elements may be evaluated *during* the steps below rather than before.\n\n* The compiler *may* determine the *known length* of the collection expression by invoking [*countable*](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-8.0/ranges.md#adding-index-and-range-support-to-existing-library-types) properties &mdash; or equivalent properties from well-known interfaces or types &mdash; on each *spread element expression*.\n\n* An *initialization instance* is created as follows:\n  * If the target type is an *array* and the collection expression has a *known length*, an array is allocated with the expected length.\n  * If the target type is a *span* or a type with a *create method*, and the collection has a *known length*, a span with the expected length is created referring to contiguous storage.\n  * Otherwise intermediate storage is allocated. The intermediate storage has an indexer for element assignment.\n\n* **If the *iteration type* is a type `KeyValuePair<K, V>`, then:**\n  * **For each element in order:**\n    * **If the element is a *key value pair element* `Kᵢ:Vᵢ` then:**\n      * **First `Kᵢ` is evaluated, then `Vᵢ` is evaluated.**\n      * **The initialization instance *indexer* is invoked on the collection instance with the converted values of `Kᵢ` and `Vᵢ`.**\n    * **If the element is an *expression element* `Eᵢ`, then:**\n      * **If `Eᵢ` is implicitly convertible to `KeyValuePair<K, V>`, then:**\n        * **`Eᵢ` is evaluated and converted to a `KeyValuePair<K, V>`.**\n        * **The initialization instance *indexer* is invoked on the collection instance with `Key` and `Value` of the converted value.**\n      * **Otherwise, `Eᵢ` has a type `KeyValuePair<Kᵢ, Vᵢ>`, in which case:**\n        * **`Eᵢ` is evaluated.**\n        * **The initialization instance *indexer* is invoked on the collection instance with `Key` and `Value` of the value, converted to `K` and `V`.**\n    * **If the element is a *spread element* where the spread element *expression* has an [*iteration type*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/statements.md#1295-the-foreach-statement) `Tᵢ` then:**\n      * **An applicable `GetEnumerator` instance or extension method is invoked on the spread element *expression***.\n      * **For each item from the enumerator:**\n        * **If `Tᵢ` is implicitly convertible to `KeyValuePair<K, V>` then:**\n          * **The item is converted to a `KeyValuePair<K, V>`.**\n          * **The initialization instance *indexer* is invoked on the collection instance with `Key` and `Value` of the converted item.**\n        * **Otherwise, `Tᵢ` is a type `KeyValuePair<Kᵢ, Vᵢ>`, in which case:**\n          * **The initialization instance *indexer* is invoked on the collection instance with `Key` and `Value` of the item, converted to `K` and `V`.**\n      * **If the enumerator implements `IDisposable`, then `Dispose` will be called after enumeration, regardless of exceptions.**\n\n* Otherwise, the *iteration type* is *not* a `KeyValuePair<K, V>` type, in which case:\n  * For each element in order:\n    * If the element is an *expression element*, the initialization instance *indexer* is invoked to assign the evaluated expression at the current index.\n    * If the element is a *spread element* then ...:\n      * An applicable `GetEnumerator` instance or extension method is invoked on the *spread element expression*.\n      * For each item from the enumerator:\n        * The initialization instance *indexer* is invoked to assign the item at the current index.\n        * If the enumerator implements `IDisposable`, then `Dispose` will be called after enumeration, regardless of exceptions.\n\n* If intermediate storage was allocated for the collection, a collection instance is allocated with the actual collection length and the values from the initialization instance are copied to the collection instance, or if a span is required the compiler *may* use a span of the actual collection length from the intermediate storage. Otherwise the initialization instance is the collection instance.\n\n* If the target type has a *create method*, the create method is invoked with the span instance.\n\n## Type inference\n\n`k:v` elements contribute input and output inferences respectively to those types.  Normal expression elements and spread elements must have associated `KeyValuePair<K_n, V_n>` types, where the `K_n` and `V_n` then contribute as well.\n\nFor example:\n\n```c#\nKeyValuePair<object, long> kvp = ...;\nvar a = AsDictionary([\"mads\": 21, \"dustin\": 22, kvp]); // AsDictionary<object, long>(Dictionary<object, long> arg)\n\nstatic Dictionary<TKey, TValue> AsDictionary<TKey, TValue>(Dictionary<TKey, TValue> arg) => arg;\n```\n\nThe [*type inference*](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#type-inference) rules are updated as follows.\n\n> 11.6.3.2 The first phase\n>\n> For each of the method arguments `Eᵢ`:\n>\n> * An *input type inference* is made *from* `Eᵢ` *to* the corresponding *parameter type* `Tᵢ`.\n>\n> An *input type inference* is made *from* an expression `E` *to* a type `T` in the following way:\n>\n> * If `E` is a *collection expression* with elements `Eᵢ`:\n>   * **If `T` has an *element type* `KeyValuePair<Kₑ, Vₑ>`, or `T` is a *nullable value type* `T0?` and `T0` has an *element type* `KeyValuePair<Kₑ, Vₑ>`, then for each `Eᵢ`**:\n>     * **If `Eᵢ` is a *key value pair element* `Kᵢ:Vᵢ`, then an *input type inference* is made *from* `Kᵢ` *to* `Kₑ` and an *input type inference* is made *from* `Vᵢ` *to* `Vₑ`.**\n>     * **If `Eᵢ` is an *expression element* with type `KeyValuePair<Kᵢ, Vᵢ>`, then a [*lower-bound inference*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/expressions.md#116310-lower-bound-inferences) is made *from* `Kᵢ` *to* `Kₑ` and a [*lower-bound inference*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/expressions.md#116310-lower-bound-inferences) is made *from* `Vᵢ` *to* `Vₑ`.**\n>     * **If `Eᵢ` is a *spread element* with an [*iteration type*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/statements.md#1295-the-foreach-statement) `KeyValuePair<Kᵢ, Vᵢ>`, then a [*lower-bound inference*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/expressions.md#116310-lower-bound-inferences) is made *from* `Kᵢ` *to* `Kₑ` and a [*lower-bound inference*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/expressions.md#116310-lower-bound-inferences) is made *from* `Vᵢ` *to* `Vₑ`.**\n>   * If `T` has an *element type* `Tₑ`, or `T` is a *nullable value type* `T0?` and `T0` has an *element type* `Tₑ`, then for each `Eᵢ`:\n>     * If `Eᵢ` is an *expression element*, then an *input type inference* is made *from* `Eᵢ` *to* `Tₑ`.\n>     * If `Eᵢ` is a *spread element* with an [*iteration type*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/statements.md#1295-the-foreach-statement) `Sᵢ`, then a [*lower-bound inference*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/expressions.md#116310-lower-bound-inferences) is made *from* `Sᵢ` *to* `Tₑ`.\n> * *[existing rules from first phase]* ...\n\n> 11.6.3.7 Output type inferences\n>\n> An *output type inference* is made *from* an expression `E` *to* a type `T` in the following way:\n>\n> * If `E` is a *collection expression* with elements `Eᵢ`:\n>   * **If `T` has an *element type* `KeyValuePair<Kₑ, Vₑ>`, or `T` is a *nullable value type* `T0?` and `T0` has an *element type* `KeyValuePair<Kₑ, Vₑ>`, then for each `Eᵢ`**:\n>     * **If `Eᵢ` is a *key value pair element* `Kᵢ:Vᵢ`, then an *output type inference* is made *from* `Kᵢ` *to* `Kₑ` and an *output type inference* is made *from* `Vᵢ` *to* `Vₑ`.**\n>     * **If `Eᵢ` is an *expression element*, no inference is made from `Eᵢ`.**\n>     * **If `Eᵢ` is a *spread element*, no inference is made from `Eᵢ`.**\n>   * If `T` has an *element type* `Tₑ` or `T` is a *nullable value type* `T0?` and `T0` has an *element type* `Tₑ`, then for each `Eᵢ`:\n>     * If `Eᵢ` is an *expression element*, then an *output type inference* is made *from* `Eᵢ` *to* `Tₑ`.\n>     * If `Eᵢ` is a *spread element*, no inference is made from `Eᵢ`.\n> * *[existing rules from output type inferences]* ...\n\nThe *input type inference* change is necessary to infer `T` in `InputType<T>()` in the following; the *output type inference* change is necessary to infer `T` in `OutputType<T>()`.\n\n```csharp\nstatic void InputType<T>(Dictionary<string, T> d);\nstatic void OutputType<T>(Dictionary<string, Func<T>> d);\n\nInputType([\"a\":1]);\nOutputType([\"b\":() => 2)]);\n```\n\n## Extension methods\n\nNo changes here.  Like with collection expressions, dictionary expressions do not have a natural type, so the existing conversions from type are not applicable. As a result, a dictionary expression cannot be used directly as the first parameter for an extension method invocation. \n\n## Overload resolution\n\nFor example, given:\n\n```c#\nvoid X(IDictionary<A, B> dict);\nvoid X(Dictionary<A, B> dict);\n```\n\nIn this case, standard betterness would pick the latter method.\n\nSimilarly for:\n\n```c#\nvoid X(IEnumerable<KeyValuePair<A, B>> dict);\nvoid X(Dictionary<A, B> dict);\n```\n\nSimilar to *collection expressions*, there is no betterness between disparate concrete dictionary types.  For example:\n\n```c#\nvoid X(Dictionary<A, B> dict);\nvoid X(ImmutableDictionary<A, B> dict);\n\nX([a, b]); // ambiguous\n```\n\n[*Better collection conversion from expression*](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-13.0/collection-expressions-better-conversion.md) is updated as follows.\n\n> If there is an identity conversion from `E₁` to `E₂`, then the element conversions are as good as each other. Otherwise, the element conversions to `E₁` are ***better than the element conversions*** to `E₂` if:\n> - For every `ELᵢ`, `CE₁ᵢ` is at least as good as `CE₂ᵢ`, and\n> - There is at least one i where `CE₁ᵢ` is better than `CE₂ᵢ`\n> Otherwise, neither set of element conversions is better than the other, and they are also not as good as each other.\n>\n> Conversion comparisons are made as follows:\n> - **If the target is a type with an *element type* `KeyValuePair<Kₑ, Vₑ>`:**\n>   - **If `ELᵢ` is a *key value pair element* `Kᵢ:Vᵢ`, conversion comparison uses better conversion from expression from `Kᵢ` to `Kₑ` and better conversion from expression from `Vᵢ` to `Vₑ`.**\n>   - **If `ELᵢ` is an *expression element* with *element type* `KeyValuePair<Kᵢ, Vᵢ>`, conversion comparison uses better conversion from type `Kᵢ` to `Kₑ` and better conversion from type `Vᵢ` to `Vₑ`.**\n>   - **If `ELᵢ` is an *spread element* with an expression with *element type* `KeyValuePair<Kᵢ, Vᵢ>`, conversion comparison uses better conversion from type `Kᵢ` to `Kₑ` and better conversion from type `Vᵢ` to `Vₑ`.**\n> - **If the target is a type with an *element type* other than `KeyValuePair<,>`:**\n>   - **If `ELᵢ` is a *key value pair element*, there is no conversion to the *element type*.**\n>   - If `ELᵢ` is an *expression element*, conversion comparison uses better conversion from expression.\n>   - If `ELᵢ` is a *spread element*, conversion conversion uses better conversion from the spread collection *element type*.\n>\n> `C₁` is a ***better collection conversion from expression*** than `C₂` if:\n> - Both `T₁` and `T₂` are not *span types*, and `T₁` is implicitly convertible to `T₂`, and `T₂` is not implicitly convertible to `T₁`, or\n> - **Both or neither of `T₁` and `T₂` have *element type* `KeyValuePair<,>`, and** `E₁` does not have an identity conversion to `E₂`, and both  and the element conversions to `E₁` are ***better than the element conversions*** to `E₂`, or\n> - `E₁` has an identity conversion to `E₂`, and one of the following holds:\n>    - `T₁` is `System.ReadOnlySpan<E₁>`, and `T₂` is `System.Span<E₂>`, or\n>    - `T₁` is `System.ReadOnlySpan<E₁>` or `System.Span<E₁>`, and `T₂` is an *array_or_array_interface* with *element type* `E₂`\n>\n> Otherwise, neither collection type is better, and the result is ambiguous.\n\n## Interface translation\n\n### Non-mutable interface translation\n\nGiven a target type `IReadOnlyDictionary<TKey, TValue>`, a compliant implementation is required to produce a value that implements that interface. If a type is synthesized, it is recommended the synthesized type implements `IDictionary<TKey, TValue>` as well. This ensures maximal compatibility with existing libraries, including those that introspect the interfaces implemented by a value in order to light up performance optimizations.\n\nIn addition, the value must implement the nongeneric `IDictionary` interface. This enables collection expressions to support dynamic introspection in scenarios such as data binding.\n\nA compliant implementation is free to:\n\n1. Use an existing type that implements the required interfaces.\n2. Synthesize a type that implements the required interfaces.\n\nIn either case, the type used is allowed to implement a larger set of interfaces than those strictly required.\n\nSynthesized types are free to employ any strategy they want to implement the required interfaces properly. For example, returning a cached singleton for empty collections, or a synthesized type which inlines the keys/values directly within itself, avoiding the need for additional internal collection allocations.\n\n1. The value must return `true` when queried for `ICollection<T>.IsReadOnly`. This ensures consumers can appropriately tell that the collection is non-mutable, despite implementing the mutable views.\n1. The value must throw on any call to a mutation method (like `IDictionary<TKey, TValue>.Add`). This ensures safety, preventing a non-mutable collection from being accidentally mutated.\n\nThis follows the originating intuition around the `IEnumerable<T> / IReadOnlyCollection<T> / IReadOnlyList<T>` interfaces and the allowed flexibility the compiler has in using an existing type or synthesized type when creating an instance of those in [*collection expressions*](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#non-mutable-interface-translation). \n\n\n### Mutable interface translation\n\nGiven the target type `IDictionary<TKey, TValue>`:\n\n1. The value must be an instance of `Dictionary<TKey, TValue>`\n\nTranslation mechanics will happen using the already defined rules that encompass the `Dictionary<TKey, TValue>` type (including handling of an initially provided [*comparer*](#Comparer-support)).\n\nThis follows the originating intuition around the `IList<T> / ICollection<T>` interfaces and the concrete `List<T>` destination type in [*collection expressions*](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#mutable-interface-translation). \n\n\n## Answered Questions\n\n### Answered question 1\n\nCan a dictionary type value be created without using a key_value_pair_element?  For example, are the following legal?\n\n```c#\nDictionary<string, int> d1 = [existingKvp];\nDictionary<string, int> d2 = [.. otherDict];\n```\n\nNote: the element `KeyValuePair<K1,V1>` types need not be identical to the `KeyValuePair<K2,V2>` type of the destination dictionary type.  They simply must be convertible to the `V1 this[K1 key] { ... }` indexer provided by the dictionary.\n\nYes.  These are legal: [LDM-2024-03-11](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-03-11.md#conclusions)\n\n### Answered question 2\n\nCan you spread a *non dictionary type* when producing a dictionary type'd value.  For example:\n\n```c#\nDictionary<string, int> nameToAge = [\"mads\": 21, .. existingListOfKVPS];\n``` \n\n**Resolution:** *Spread elements* of key-value pair collections will be supported in dictionary expressions. [LDM-2024-03-11](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-03-11.md#conclusions)\n\n### Answered question 3\n\nHow far do we want to take this KeyValuePair representation of things? Do we allow *key value pair elements* when producing normal collections? For example, should the following be allowed:\n\n```c#\nList<KeyValuePair<string, int>> = [\"mads\": 21];\n```\n\n**Resolution:** *Key value pair elements* will be supported in collection expressions for collection types that have a key-value pair element type. [LDM-2024-03-11](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-03-11.md#conclusions)\n\n### Answered question 4\n\nDictionaries provide two ways of initializing their contents.  A restrictive `.Add`-oriented form that throws when a key is already present in the dictionary, and a permissive indexer-oriented form which does not.  The restrictive form is useful for catching mistakes (\"oops, I didn't intend to add the same thing twice!\"), but is limiting *especially* in the spread case.  For example:\n\n```c#\nDictionary<string, Option> optionMap = [opt1Name: opt1Default, opt2Name: opt2Default, .. userProvidedOptions];\n```\n\nOr, conversely:\n\n```c#\nDictionary<string, Option> optionMap = [.. Defaults.CoreOptions, feature1Name: feature1Override];\n```\n\nWhich approach should we go with for dictionary expressions? Options include:\n\n1. Purely restrictive.  All elements use `.Add` to be added to the list.  Note: types like `ConcurrentDictionary` would then not work, not without adding support with something like the `CollectionBuilderAttribute`.\n2. Purely permissive.  All elements are added using the indexer.  Perhaps with compiler warnings if the exact same key is given the same constant value twice.\n3. Perhaps a hybrid model.  `.Add` if only using `k:v` and switching to indexers if using spread elements.  There is deep potential for confusion here.\n\n**Resolution:** Use *indexer* as the lowering form. [LDM-2024-03-11](https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-03-11.md#conclusions)\n\n### Answered question 5\n\nWhat types and translation should be used when targeting dictionary interfaces (`IDictionary<TKey, TValue>` or `IReadOnlyDictionary<TKey, TValue>`)?\n\n**Resolution:** Use the same rules used for mutable and non-mutable interfaces for normal\n[*collection expressions*](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#interface-translation)\nanalogously translated to dictionaries.  Full details can be found in [interface-translation](#interface-translation).  \n\n[LDM-2025-04-09](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-04-09.md#conclusion)\n\n### Conversion from expression element for `KeyValuePair<K, V>` collections\n\nConfirm the **allowed conversions** from an *expression element* when the target type is a `KeyValuePair<K, V>` collection.\n\n```csharp\nList<KeyValuePair<string, int>> list;\nlist = [default];             // ok\nlist = [new()];               // ok\nlist = [new StringIntPair()]; // error: UDC not supported\n```\n\n>  * If `Eᵢ` is an *expression element* then one of the following holds:\n>     * **There is an implicit conversion from `Eᵢ` to `KeyValuePair<K:V>` where the conversion is one of:**\n>       * ***default literal conversion***\n>       * ***target-typed new conversion***\n>     * **`Eᵢ` has type `KeyValuePair<Kᵢ:Vᵢ>` and there is an implicit conversion from `Kᵢ` to `K` and an implicit conversion from `Vᵢ` to `V`.**\n\n**Resolution:** Existing conversions should continue to apply for *expression elements* and *spread elements* before considering co-variant conversions of `Key` and `Value` for distinct `KeyValuePair<,>` types. [LDM-2025-03-17](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-03-17.md#conclusion-2)\n\n### Binding to indexer\n\nFor concrete dictionary types that do not use `CollectionBuilderAttribute`, where the compiler constructs the resulting instance using a constructor and repeated calls to an indexer, how should the compiler resolve the appropriate indexer for each element?\n\n```csharp\nMyDictionary<string, int> d =\n  [\n    (object)\"one\":1, // this[object] { set; }\n    \"two\":2          // this[string] { set; }\n  ];\n\nclass MyDictionary<K, V> : IEnumerable<KeyValuePair<object, object>>\n{\n  // ...\n  public V this[K k] { ... }\n  public object this[object o] { ... }\n}\n```\n\nOptions include:\n1. For each element individually, use normal lookup rules and overload resolution to determine the resulting indexer based on the element expression (for an expression element) or type (for a spread or key-value pair element). *This corresponds to the binding behavior for `Add()` methods for non-dictionary collection expressions.*\n2. Use the target type implementation of `IDictionary<K, V>.this[K] { get; set; }`.\n3. Use the accessible indexer that matches the signature `V this[K] { get; set; }`.\n\n**Resolution:** Option 3: Use the indexer that qualifies the type as a dictionary type. [LDM-2025-03-05](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-03-05.md#conclusion)\n\n### Type inference for `KeyValuePair<K, V>` collections\n\nConfirm the [*type inference*](#type-inference) rules for elements when the target type is a `KeyValuePair<K, V>` collection.\n\n```csharp\nstring x; int y;\nKeyValuePair<string, long> e;\nDictionary<object, int> d;\n...\nPrint([x:y]);         // Print<string, int>\nPrint([e]);           // Print<string, long>\nPrint([..d]);         // Print<object, int>\nPrint([x:y, e, ..d]); // Print<object, long>\n\nvoid Print<K, V>(List<KeyValuePair<K, V>> pairs) { ... }\n```\n\n>   * **If `T` has an *element type* `KeyValuePair<Kₑ, Vₑ>`, or `T` is a *nullable value type* `T0?` and `T0` has an *element type* `KeyValuePair<Kₑ, Vₑ>`, then for each `Eᵢ`**:\n>     * **If `Eᵢ` is a *key value pair element* `Kᵢ:Vᵢ`, then an *input type inference* is made *from* `Kᵢ` *to* `Kₑ` and an *input type inference* is made *from* `Vᵢ` *to* `Vₑ`.**\n>     * **If `Eᵢ` is an *expression element* with type `KeyValuePair<Kᵢ, Vᵢ>`, then a [*lower-bound inference*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/expressions.md#116310-lower-bound-inferences) is made *from* `Kᵢ` *to* `Kₑ` and a [*lower-bound inference*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/expressions.md#116310-lower-bound-inferences) is made *from* `Vᵢ` *to* `Vₑ`.**\n>     * **If `Eᵢ` is a *spread element* with an [*iteration type*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/statements.md#1295-the-foreach-statement) `KeyValuePair<Kᵢ, Vᵢ>`, then a [*lower-bound inference*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/expressions.md#116310-lower-bound-inferences) is made *from* `Kᵢ` *to* `Kₑ` and a [*lower-bound inference*](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/expressions.md#116310-lower-bound-inferences) is made *from* `Vᵢ` *to* `Vₑ`.**\n\n**Resolution:** Rules accepted as written. [LDM-2025-03-24](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-03-24.md#conclusion-1)\n\n### Overload resolution for `KeyValuePair<K, V>` collections\n\nConfirm the *better conversion* rules for [*overload resolution*](#overload-resolution) when the target types are `KeyValuePair<K, V>` collections.\n\n```csharp\nKeyValuePair<byte, int> e;\nDictionary<byte, int> d;\n...\nPrint([1:2]); // <int, int>\nPrint([e])    // ambiguous\nPrint([..d])  // ambiguous\n\nvoid Print(List<KeyValuePair<int, int>> pairs) { ... }\nvoid Print(List<KeyValuePair<byte, object>> pairs) { ... }\n```\n\n> Conversion comparisons are made as follows:\n> - **If the target is a type with an *element type* `KeyValuePair<Kₑ, Vₑ>`:**\n>   - **If `ELᵢ` is a *key value pair element* `Kᵢ:Vᵢ`, conversion comparison uses better conversion from expression from `Kᵢ` to `Kₑ` and better conversion from expression from `Vᵢ` to `Vₑ`.**\n>   - **If `ELᵢ` is an *expression element* with *element type* `KeyValuePair<Kᵢ, Vᵢ>`, conversion comparison uses better conversion from type `Kᵢ` to `Kₑ` and better conversion from type `Vᵢ` to `Vₑ`.**\n>   - **If `ELᵢ` is an *spread element* with an expression with *element type* `KeyValuePair<Kᵢ, Vᵢ>`, conversion comparison uses better conversion from type `Kᵢ` to `Kₑ` and better conversion from type `Vᵢ` to `Vₑ`.**\n\n**Resolution:** Rules accepted as written. [LDM-2025-03-24](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-03-24.md#conclusion-2)\n\n### Support dictionary types as `params` type\n\nShould types with element type `KeyValuePair<K, V>`, that are not otherwise collection types, be supported as `params` parameter types?\n\n```csharp\nKeyValuePair<string, int> x, y;\n\nToDictionary(x, y);\nToReadOnlyDictionary(x, y);\n\nstatic Dictionary<K, V> ToDictionary<K, V>(\n    params Dictionary<K, V> elements) => elements;          // C#14: ok?\n\nstatic IReadOnlyDictionary<K, V> ToReadOnlyDictionary<K, V>(\n    params IReadOnlyDictionary<K, V> elements) => elements; // C#14: ok?\n```\n\nNote that regardless of whether we support dictionary types for `params`, or simply continue to support C#12 collection types with `KeyValuePair<K, V>` element type, it won't be possible to use `k:v` syntax when calling a `params` method with *expanded form*.\n\n```csharp\nToList(\"one\":1);   // error: syntax error ':'\nToList([\"two\":2]); // C#14: ok\n\nstatic List<KeyValuePair<K, V>> ToList<K, V>(params List<KeyValuePair<K, V>> elements) => elements;\n```\n\n**Resolution:** Allow `params` on dictionary-like types that can be targeted with a collection expression, and constructing those types will prefer using indexers when available. [LDM-2025-03-24](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-03-24.md#conclusion)\n\n### Question: Types that support both collection and dictionary initialization\n\nC# 12 supports collection types where the element type is some `KeyValuePair<,>`, where the type has an applicable `Add()` method that takes a single argument. Which approach should we use for initialization if the type also includes an indexer?\n\nFor example, consider a type like so:\n\n```c#\npublic class Hybrid<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>\n{\n    public void Add(KeyValuePair<TKey, TValue> pair);\n    public TValue this[TKey key] { ... }\n}\n\n// This would compile in C# 12:\n// Translating to calls to .Add.\nHybrid<string, int> nameToAge = [someKvp];\n```\n\nOptions include:\n\n1. Use applicable instance indexer if available; otherwise use C#12 initialization.\n2. Use applicable instance indexer if available; otherwise report an error during construction (or conversion?).\n3. Use C#12 initialization always.\n\n**Resolution:** If the target type is a struct or class type that implements `IEnumerable` and has an iteration type of `KeyValuePair<K, V>`, and the type has the expected instance indexer (see [*Conversions*](#conversions)), then the indexer is used for initialization rather than any `Add` methods. [LDM-2025-03-05](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-03-05.md#conclusion)\n\n### Question: Parsing ambiguity\n\nParsing ambiguity around: `[a ? [b] : c]`\n\n**Resolution:** Parse as `[a ? ([b]) : (c)]`. [LDM-2025-04-14](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-04-14.md#conclusion)\n\n### Question: Implement non-generic `IDictionary` when targeting `IReadOnlyDictionary<,>`\n\nCollection expressions specified explicitly:\n\n> Given a target type which does not contain mutating members, namely `IEnumerable<T>`, `IReadOnlyCollection<T>`, and `IReadOnlyList<T>`, a compliant implementation is required to produce a value that implements that interface. ...\n>\n> In addition, the value must implement the nongeneric `ICollection` and `IList` interfaces. This enables collection expressions to support dynamic introspection in scenarios such as data binding.\n\nDo we want a similar correspondance when the target type is `IReadOnlyDictionary<,>`?  Specifically, should the value be required to implement the non-generic `IDictionary` interface?\n\n**Resolution:** The type used to implement `IReadOnlyDictionary<K, V>` should implement `System.Collections.IDictionary`. [LDM-2025-04-14](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-04-14.md#conclusion-1)\n\n## Retracted Designs/Questions\n\n### Question: Should `k:v` elements force dictionary semantics?\n\nIs there a concern around the following interface destinations:\n\n```c#\n// NOTE: These are not overloads.\n\nvoid AAA(IEnumerable<KeyValuePair<string, int>> pairs) ...\nvoid BBB(IDictionary<string, int> pairs) ...\n\nAAA([\"mads\": 21, .. ldm]);\nBBB([\"mads\": 21, .. ldm]);\n```\n\nWhen the destination is an `IEnumerable<T>`, we tend to think we're producing a sequence (so \"mads\" could show up twice).  However, the use of the `k:v` syntax more strongly indicates production of a dictionary-value.\n\nWhat should we do here when targeting `IEnumerable<...>` *and* using `k:v` elements? Produce an ordered sequence, with possibly duplicated values?  Or produce an unordered dictionary, with unique keys?\n\nResolution: `IEnumerable<KVP>` is not a dictionary type (as it lacks an indexer).  As such, it has sequential value semantics (and can include duplicates).  This would happen today anyways if someone did `[.. ldm]` and we do not think the presence of a `k:v` element changes how the semantics should work.\n\nThis is also similar to how passing to an `IEnumerable<T>` would differ from passing to some *set* type with normal collection expressions.  The target type *intentionally* affects semantics, and there is no expectation that across very different target types that one would receive the same resultant values with the same behaviors.  We do not view *dictionary types* or *key value pair elements* as changing the calculus here.\n\n### Question: Allow deconstructible types?\n\nShould we take a very restrictive view of `KeyValuePair<,>`?  Specifically, should we allow only that exact type?  Or should we allow any types with an implicit conversion to that type?  For example:\n\n```c#\nstruct Pair<X, Y>\n{\n  public static implicit operator KeyValuePair<X, Y>(Pair<X, Y> pair) => ...;\n}\n\nDictionary<int, string> map1 = [pair1, pair2]; // ?\n\nList<Pair<int, string>> pairs = ...;\nDictionary<int, string> map2 = [.. pairs]; // ?\n```\n\nSimilarly, instead of `KeyValuePair<,>` we could allow *any* type deconstructible to two values? For example:\n\n```c#\nrecord struct Pair<X, Y>(X x, Y y);\n\nDictionary<int, string> map1 = [pair1, pair2]; // ?\n```\n\nResolution: While cute, these capabilities are not needed for core scenarios to work.  They also raise concerns about where to draw the line wrt to what is the dictionary space and what is not.  As such, we will only allow `KeyValuePair<,>` for now.  And we will not do anything with tuples and/or other deconstructible types.  This is also something that could be relaxed in the future if there is sufficient feedback and motivation to warrant it.  This design space is withdrawn from dictionary expressions.\n\n### Question: Semantics when a type implements the *dictionary type* shape in multiple ways.\n\nWhat are the rules when types have multiple indexers and multiple implementations of `IEnumerable<KVP<,>>`?\n\nThis concern already exists with *collection types*.  For those types, the rule is that we must have an *element type* as per the existing language rules.  This follows for *dictionary types*, along with the rule that there must be a corresponding indexer for this *element type*.  If those hold, the type can be used as a *dictionary type*.  If these don't hold, it cannot be.\n\n\n### Question: Special case 'comparer' support for dictionaries (and regular collections)?\n\n[Collection expression arguments](https://github.com/dotnet/csharplang/blob/main/proposals/collection-expression-arguments.md) proposes a generalized system for providing arguments for constructible (`new(...)`) collection types, collection builder types, and for a subset of interface types.  This solves the problem of how can a comparer be passed to a dictionary-like type, as well as for other collections that can benefit from customization (like hash sets and the like).  However, in the absence of an approved language change to support a generalized argument passing system, do we want to be able to have special support for passing *only* comparers along?\n\nFor example, a hypothetical syntax could be something like:\n\n```c#\nDictionary<string, object> nameToOptions = [\n    comparer: StringComparer.OrginalIgnoreCase,\n    .. GetDefaultOptions(),\n    .. GetHostSpecificOptions(),\n    .. GetPlatformSpecificOptions(),\n];\n```\n\nPros: A specialized syntax can be clearer and more focused to the exact problem at hand, side stepping lots of complexity related to arbitrary argument passing (for example, out/ref arguments, named arguments, optional arguments, and the like).\n\nCons: Some user will still want to pass arbitrary arguments along (for cases like 'capacity: ...', and for collections that capture/wrap some other collection).  They will still be left out if we do not have a general system.  And, if we add a general system later, there would be multiple ways to support passing a comparer along.\n\n<details>\nPossible syntactic options here are:\n\n1. `[comparer: StringComparer.OrginalIgnoreCase]`.  Simple and clear.  But a long contextual keyword for 'comparer'.\n2. `[comp: StringComparer.OrginalIgnoreCase]`. A bit less clear, but generally readable in context.  Similar to `init` where we truncate a word to something reasonable in context.\n3. `[...] with StringComparer.OrdinalIgnoreCase`.  Not desirable.  Collections may be quite large, and having to get to the end to understand core behavior/semantics of how the collection operates is not great.  This especially clashes with all existing forms to make collections today, where the comparer will be at the start.\n4. `[ == StringComparer.OrdinalIgnoreCase]`.  Cutesy syntax.  `==` represents 'equality', and thus this is a special element saying \"equality is provided by this comparer\"\n5. `[ == : StringComparer.OrdinalIgnoreCase]`.  Similarly cutesy, just using a colon to indicate \"provided by\".\n6. `[ <=> StringComparer.OrdinalIgnoreCase]`.  Cutesy, and in line with C++ (and potential future language changes) where the \"spaceship operator\" represents the way things compare against each other.\n\nNote: Any solution should support both `IComparer<>` (for `SortedSet<>`, `SortedDictionary<,>`, and their immutable variants) and `IEqualityComparer<>` (for all the hashing based collections).  As such, a mild word like `comparer/comp` seems to fit the bill best.\n\nIf we do special case comparers, the rules would say something intuitively akin to the following:\n\n> If a comparer element is provided, then:\n> 1. If generating a `new()` type, the type must have a constructor callable with the single comparer argument.\n> 2. If generating a collection builder type, there must be a factory method referenced that can take the comparer as the first argument, and the elements as the second.\n> 3. If generating an interface, the only supported interfaces are `IDictionary<,>` and `IReadOnlyDictionary<,>`.  For the former, the comparer will be passed to the `new(IEqualityComparer<>)` constructor on `Dictionary<>`.  For the latter, the dictionary created by the compiler will be guaranteed to use the specified equality comparer to perform hashing and equality checks of the provided keys.\n\nNote: real rules would be tbd.  The above is just a light sketch to motivate discussion.\n</details>\n\nResolution: We do not believe specialized syntax is worth it.  We prefer this space be fully subsumed by the [Collection Expression Arguments](https://github.com/dotnet/csharplang/blob/main/proposals/collection-expression-arguments.md) feature. [LDM-2025-04-23](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-04-23.md#conclusion-2)\n\n## Open Questions\n\n### Support `KeyValuePair<,>` variance with `params`?\n\nShould key and value variance be supported for expanded calls for a `params` collection of `KeyValuePair<K, V>`?\n\n```csharp\nKeyValuePair<string, int> kvp = new(\"one\", 1);\n\nPrintOne(kvp);    // error: cannot convert from KeyValuePair<string, int> to KeyValuePair<object, int?>\nPrintMany([kvp]); // ok!\nPrintMany(kvp);   // ok?\n\nstatic void PrintOne(KeyValuePair<object, int?> arg) { }\nstatic void PrintMany(params KeyValuePair<object, int?>[] args) { }\n```\n\nIf so, [*params collections*](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-13.0/params-collections.md#parameter-collections) will need to be **updated** to allow implicit conversions for key and value types.\n\n> A parameter collection permits arguments to be specified in one of two ways in a method invocation:\n> \n> - The argument given for a parameter collection can be a single expression that is implicitly convertible to the parameter collection type.\n>   In this case, the parameter collection acts precisely like a value parameter.\n> - Alternatively, the invocation can specify zero or more arguments for the parameter collection, where each argument is an expression\n>   that is implicitly convertible to the parameter collection's *element type*, **or**\n>   **the argument is an expression of type `KeyValuePair<Kᵢ, Vᵢ>` and the collection *element type* is `KeyValuePair<Kₑ, Vₑ>` and there is a implicit conversion from `Kᵢ` to `Kₑ` and an implicit conversion from `Vᵢ` to `Vₑ`.**\n>   In this case, the invocation creates an instance of the parameter collection type according to the rules specified in\n>   [Collection expressions](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md)\n>   as though the arguments were used as expression elements in a collection expression in the same order,\n>   and uses the newly created collection instance as the actual argument.\n>   When constructing the collection instance, the original *unconverted* arguments are used.\n"
  },
  {
    "path": "proposals/enhanced-switch-statements.md",
    "content": "# Enhanced switch statements\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/8611>\n\n## Summary\n[summary]: #summary\n\nThis proposal is an enhancement to the existing switch statement syntax to permit switch-expression-style arms instead of using case statements. This feature is orthogonal to https://github.com/dotnet/csharplang/issues/3037 and can be done independently, but was conceived of as taking https://github.com/dotnet/csharplang/issues/3037's switch expressions and applying them to switch statements.\n\n## Motivation\n[motivation]: #motivation\n\nThis is an attempt to bring more recent C# design around switch expressions into a statement form, that can be used when there is nothing to return. The existing switch statement construct, while very familiar to C/C++ programmers, has several design choices that can feel dated by current C# standards. These include requiring `break;` statements in each case, even though there is no implicit fall-through in C#, and variable scopes that extend across all cases of the switch statement for variables declared _in_ the body, but not for variables declared in patterns in the case labels. We attempt to modernize this by providing an alternate syntax based on the switch expression syntax added in C# 8.0 and improved with the first part of this proposal.\n\n## Detailed design\n[design]: #detailed-design\n\nWe enhance the grammar of switch statements, creating an alternate form based on the grammar of switch expressions. This alternate form is not compatible with the existing form of switch statements: you must use either the new form or the old form, but not both.\n\n```cs\nvar o = ...;\nswitch (o)\n{\n    1 => Console.WriteLine(\"o is 1\"),\n    string s => Console.WriteLine($\"o is string {s}\"),\n    List<string> l => {\n        Console.WriteLine(\"o is a list of strings:\");\n        foreach (var s in l)\n        {\n            Console.WriteLine($\"\\t{s}\");\n        }\n    }\n}\n```\n\nWe make the following changes to the grammar:\n\n```antlr\nswitch_block\n    : '{' switch_section* '}'\n    | '{' switch_statement_arms ','? '}'\n    ;\n\nswitch_statement_arms\n    : switch_statement_arm\n    | switch_statement_arms ',' switch_statement_arm\n    ;\n\nswitch_statement_arm\n    : pattern case_guard? '=>' statement_expression\n    | pattern case_guard? '=>' block\n    ;\n```\n\nUnlike a switch expression, an enhanced switch statement does not require the switch_statement_arms to have a best common type or to be target-typed. Whether the arm conditions have to be exhaustive like a switch expression is currently an open design question. Block-bodied statement arms are not required to have the end of the block be unreachable, and while a `break;` in the body will exit the switch arm, it is not required at the end of the block like in traditional switch statements.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nAs with any proposals, we will be complicating the language further by doing these proposals. In particular, we will be adding another syntactic form to switch statements that has some very different semantics to existing forms.\n\n## Alternatives\n[alternatives]: #alternatives\n\nhttps://github.com/dotnet/csharplang/issues/2632: The original issue proposed that we allow C# 8.0 switch expressions as `expression_statement`s. We had a few initial problems with this proposal:\n\n* We're uncomfortable making these a top-level statement without the ability to put more than 1 statement in an arm.\n* There's some concern that making an infix expression a top-level statement is not very CSharpy.\n* Requiring a semicolon at the end of a switch expression in an expression-statement context feels bad like a mistake, but we also don't want to convolute the grammar in such a way as to fix this issue.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n* Should enhanced switch statement arms be an all-or-nothing choice? ie, should you be able to use an old-style `case` label and a new-style arrow arm in the same statement? This proposal takes the opinion that this should be an exclusive choice: you use one or the other. This enables a debate about the second unresolved question for enhanced switch, whether they should be exhaustive. If we decide that enhanced switch should not be exhaustive, then this debate becomes largely a syntactic question.\n  * An important note about modern switch expression arms is that you cannot have multiple `when` clauses with fallthrough, like you can with traditional switch statements today. If this is an all-or-nothing choice, this means that the moment you need multiple when clauses you fall off the rails and must convert the whole thing back to a traditional switch statement.\n\n* Should enhanced switch be exhaustive? Switch expressions, where enhanced switch statements are inspired from, are exhaustive. However, while the exhaustivity makes sense in an expression context where something must be returned in all cases, this makes less sense in a statement context. Until we get discriminated unions in the language, the only times we can be truly exhaustive in C# is when operating on a closed type heirarchy that includes a catch-all case, or we are operating on a value type. And if the user is required to add a catch-all do nothing case, then purpose of exhaustivity has been largely obviated.\n"
  },
  {
    "path": "proposals/expand-ref.md",
    "content": "Expanding ref support\n===\n\n## Summary\nThis proposal expands the capabilities of `ref` and `scoped` in the language. The goal being to leverage the existing types of rules in the model to allow `ref struct` usage in more locations and provide more lifetime expressiveness for APIs.\n\n## Motivation\nThere are still a number of scenarios around `ref` which cannot be safely expressed in the language. These are generally when using multiple mutable `ref struct` parameters where many are passed by `ref` or when trying to use `ref struct` in `ref` fields.\n\nTo _fully_ satisfy all of these scenarios would require us to introduce explicit lifetime parameters and relationships into the language. That is a _huge_ investment that is not yet motivated by need. Instead this proposal takes our existing lifetime annotation, `scoped`, and sees how much further `ref` safety can be taken without introducing any other annotations or keywords. \n\nThis doesn't solve all scenarios but does remove several known friction points in the language. It also serves to show us exactly where the limits are without introducing explicit lifetime parameters.\n\n## Detailed Design\nThe rules for `ref struct` safety are defined in the following documents:\n\n- [ref safety proposal](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/span-safety.md).\n- [ref fields proposal](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/low-level-struct-improvements.md)\n\nThis proposal will be building on top of those previous ones. \n\nThe more detailed rules will rely on the [annotation syntax](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/low-level-struct-improvements.md#annotations) to describe the detailed rules. This is the most direct way to discuss how syntax behaves in the greater model. Readers interested in the very low level details should familiarize themselves with that syntax before digesting this proposal. \n\n### ref scoped parameters\nThe language will allow for parameters to be declared as `ref scoped`. This will serve to constrain the _safe-to-escape_ of the value such that it cannot be returned from the current method. \n\n```csharp\nSpan<int> M(Span<T> p1, ref scoped Span<int> p2)\n{\n    // Error: cannot return scoped value\n    return p2;\n\n    // Error: the safe-to-escape of p1 is not convertible to p2.\n    p2 = p1;\n\n    // Okay: heap can always be assigned\n    p2 = default;\n\n    // Okay\n    p2[0] = 42;\n}\n```\n\nThis capability will help cases where multiple `ref struct` values with different lifetimes are passed by `ref`. Having `ref scoped` allows developers to note which values do not escape and that allows for more call site flexibility.\n\n```csharp\nref struct Data { ... }\nvoid Copy1(ref Data source, ref Data dest) { ... }\nvoid Copy2(ref Data source, ref scoped Data dest) { ... }\n\nvoid Use(ref Data data)\n{\n    // STE: current method\n    var local = new Data(stackalloc int[42]);\n\n    // Error: compiler has to assume local copied to data \n    Copy1(ref data, ref local);\n\n    // Okay: compiler knows lifetime only flows data -> local\n    Copy2(ref data, ref local);\n}\n\n```\n\nThis is accomplished by giving every `ref scoped` parameter a new escape scope named _current parameter N_ where _N_ is the numeric order of the parameter. For example the first parameter has a _safe-to-escape_ of _current parameter 1_. An escape scope of _current parameter N_ can be converted to _current method_ but has no other defined relationship. That serves to restrict their usage to the current method. \n\nIt's important to note each parameter has a different _current parameter N_ scope. That means they cannot be assigned to each other. This is necessary to prevent `ref scoped` parameters from returning each others data.\n\n```csharp\nvoid Swap(ref scoped Span<int> p1, ref scoped Span<int> p2)\n{\n    // Error: can't assign current parameter 2 to current parameter 1\n    p2 = p1;\n\n    // Error: can't assign current parameter 1 to current parameter 2\n    p1 = p2;\n\n    // Okay: as current parameter 1 and 2 can be converted to current method\n    scoped Span<int> local1 = p1; \n    scoped Span<int> local2 = p2; \n\n    // Okay: however the safe-to-escape here is current parameter N, not \n    // current method so this could cause a bit of confusion later on\n    Span<int> local3 = p1; \n    Span<int> local4 = p2; \n\n    // Okay: the safe-to-escape of the value is inferred in this case as it is \n    // done for ref locals today.\n    ref Span<int> refLocal1 = ref p1;\n    ref Span<int> refLocal2 = ref p2;\n}\n```\n\nA `ref scoped` parameter is also implicitly `scoped ref`. That means neither the value nor its `ref` can be returned from the method. Both `ref` and `in` parameters can have their values modified with `scoped`. An `out` parameter cannot have its value modified with `scoped` as such a declaration is non-sensical. \n\n```csharp\nvoid M(\n    ref scoped Span<int> p1,    // Okay\n    in scoped Span<int> p2,     // Okay\n    out scoped Span<int> p2,    // Error\n)\n```\n\nThe [method arguments must match](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/low-level-struct-improvements.md#rules-method-arguments-must-match) rules will be updated to take `ref scoped` into account. Values passed to such parameters do not need to be considered when calculating the return scopes.\n\nDetailed notes:\n- A `ref scoped` parameter is implicitly `scoped ref`\n- An `out scoped` parameter declaration is an error\n\n### ref field to ref struct\nThe language will allow for `ref struct` to appear as `ref scoped` fields. This `scoped` will serve to ensure the values cannot be escaped outside the containing instance but can be read and manipulated within it. \n\n```csharp\nref struct Deserializer\n{\n    ref scoped Utf8JsonReader reader;\n\n    ReadOnlySpan<byte> M1()\n    {\n        // okay: implicitly scoped to current method\n        var span = reader.ValueSpan; \n\n        // okay\n        reader.Skip();\n\n        // Error: can't escape the ref data the ref scoped field refers to\n        return reader.ValueSpan;\n    }\n}\n```\n\nThis is accomplished by giving every `ref scoped` field two new escape scopes named _current field N_ and _current ref field N_ where _N_ is the numeric order of the field. For example, the first field has a _safe-to-escape_ of _current field 1_ and a _ref-safe-to-escape_ of _current ref field N_. Both escape scopes can be converted to _current method_, and _current field N_ can be converted to _current ref field N_, but no other defined relationships exist. That serves to restrict their usage to the current method where the containing value is used. This escape scope applies to both.\n\nBelow are a few examples of these rules in action\n\n```csharp\nref struct NestedRefStruct { }\nref struct RefStruct\n{\n    public NestedRefStruct NestedField;\n}\n\nref struct S\n{\n    ref scoped RefStruct field;\n\n    RefStruct M1(RefStruct s)\n    {\n        // Okay\n        field = new(); \n\n        // Error: calling-method is not convertible to current-field-1 as they have \n        // no relationship\n        field = s;\n\n        // Error: safe-to-escape is current-field-1 which isn't returnable \n        return field;\n    }\n\n    NestedRefStruct M2()\n    {\n        // Error: safe-to-escape is current-field-1 which isn't returnable \n        return field.NestedField;\n    }\n\n    ref RefStruct M3()\n    {\n        // Error: safe-to-escape is current-ref-field-1 which isn't returnable \n        return ref field;\n    }\n}\n```\n\nThe [method arguments must match](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/low-level-struct-improvements.md#rules-method-arguments-must-match) rules do not need to be updated here as they already account for `ref` parameters being captured as `ref` field. Even though a `ref` to `ref struct` was not directly returnable before, it could be returned indirectly by a `ref` to a `struct` field of the value.\n\nThe language will also allow for `ref` fields to be declared as `scoped ref`. There are less use cases for this but `ref scoped` implies `scoped ref` hence the rules must be adjusted to account for this. As such the syntax will be exposed because while the use cases are small the infrastructure already exists. The _ref-safe-to-escape_ of such fields follows the logic above for `ref scoped` fields.\n\nDetailed notes:\n- A `ref` field where the type is a `ref struct` must be `ref scoped`\n- A `ref` field may be marked `scoped ref`\n\n### Sunset restricted types\nThe ability for any type to be a `ref` field allows us to fully sunset the notion of restricted types.  The compiler has a concept of a set of _restricted types_ which is largely undocumented. These types were given a special status because in C# 1.0 there was no general purpose way to express their behavior. Most notably the fact that the types can contain references to the execution stack. Instead the compiler had special knowledge of them and restricted their use to ways that would always be safe: disallowed returns, cannot use as array elements, cannot use in generics, etc ...\n\nOnce `ref` fields are available and extended to support `ref struct` these types can be fully rationalized within those rules. As such the compiler will no longer have the notion of restricted types when using a language version that supports `ref` fields of `ref struct`.\n\nTo support this our `ref` safety rules will be updated as follows:\n\n- `__makeref(e)` will be logically treated as a method with the signature `static TypedReference __makeref(ref T value)` were `T` is the type of `e`.\n- `__refvalue(e, T)` \n    - When `T` is a `ref struct`: will be treated as accessing a field declared as `ref scoped T` inside `e`. \n    - Will be treated as accessing a field declared as `ref T` inside `e`\n- `__arglist` as a parameter will be implicitly `scoped`\n- `__arglist(...)` as an expression will have a *ref-safe-to-escape* and *safe-to-escape* of *current method*. \n\nConforming runtimes will ensure that `TypedReference`, `RuntimeArgumentHandle` and `ArgIterator` are defined as `ref struct`. Further `TypedReference` must be viewed as having a `ref` field to a `ref struct` for any possible type (it can store any value). That combined with the above rules will ensure references to the stack do not escape beyond their lifetime.\n\nNote: strictly speaking this is a compiler implementation detail vs. part of the language. But given the relationship with `ref` fields it is being included in the language proposal for simplicity.\n\n### Annotation Definition\n\n<a name=\"annotations-param\"></a>\nAt an annotation level every parameter marked `ref scoped` will have a new lifetime parameter defined. The name will be `$paramN` where _N_ is the numerical order of the parameter. That lifetime will only have the relationship `where $paramN : $local`. \n\n```csharp\nref struct S { } \nvoid M(ref scoped S s) \n\n// maps to \n\nvoid M<$param1>(ref<$local> S<$param1> s)\n    where $param1 : $local\n```\n\nThis definition prevents the value from escaping from the method as the lifetime is not returnable. It also prevents local data from escaping from the current method through the parameter as the lifetime is wider than `$local` but not equivalent.\n\n```csharp\nvoid M<$param1>(ref<$local> S<$param1> p)\n    where $param1 : $local\n{\n\n    S<$local> s = new S<$local>(stackalloc int[42]);\n\n    // error: cannot convert S<$local> to S<$param1>\n    p = s;\n}\n```\n\n<a name=\"annotations-field\"></a>\nAt an annotation level every field marked `scoped ref` (explicitly or implicitly via `ref scoped`) will have a new lifetime parameter defined. The name will be `$refFieldN` where _N_ is the numerical order of the field. That lifetime will have the relationship `where $refFieldN : $local` in all methods that use the type.\n\n```csharp\nref struct S\n{\n    scoped ref int i;\n}\nS M(S p) { }\n\n// maps to \nref struct S<out $this, $refField1>\n{\n    ref<$refField1> int i;\n}\n\nS<$cm> M<$cm, $l1>(S<$cm, $l1> p)\n    where $l1 : $local\n{\n\n}\n```\n\nEvery field marked as `ref scoped` will have a new lifetime parameter defined. The name will be `$fieldN` where _N_ is the numerical order of the field. That lifetime will have the relationship `where $fieldN : $refFieldN` defined on the type. It will also have the relationship `where $fieldN : $local` in all method that use the type.\n\n```csharp\nref struct S1 { }\nref struct S2 \n{\n    ref scoped S1 field;\n}\n\nS2 M(S2 p) { }\n\n// maps to \nref struct S1<out $this> { }\nref struct S2<out $this, $refField1, $field1>\n    where $field1 : $refField1\n{\n    ref<$refField1> S1<$field1> field;\n}\n\nS1<$cm, $l1, $l2> M<$cm, $l1>M(S<$cm, $l1, $l2> p)\n    where $l2 : $l1\n    where $l1 : $local\n{\n\n}\n```\n\nThese definitions prevent the values (`ref` or value) from escaping as their lifetimes are never returnable. It does allow for them to be manipulated and adjusted though. Non `ref` data, or data known to have `$heap` lifetime, can be assigned into such fields.\n\n## Open Issues\n\n### Ability to mark this as ref scoped\nThe proposal does not provide any way to mark `this` as `ref scoped` for a given method. At this time the author can see no significant benefits to this. If such scenarios do come along then an attribute such as `[RefScoped]` could be introduced similar to how `[UnscopedRef]` works.\n\n### Requiring ref fields to ref struct to be scoped\nCertain readers are likely to be disappointed that `ref` field to `ref struct` must be `ref scoped`. That limits the number of scenarios which can assign `ref` data into such fields. \n\nThis is unfortunately necessary given the constraints of the design. Having a plain `ref` effectively requires that explicit lifetime annotations exist in the language. There is no other way to safely express the relationship between the value and the container. \n\n\n\n\n\n"
  },
  {
    "path": "proposals/extension-indexers.md",
    "content": "# Extension indexers\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9856  \n\n## Declaration\n\n### Grammar\n\nExtension indexers are added to the set of permitted members inside an extension\ndeclaration by extending the grammar as follows (relative to\n[proposals/csharp-14.0/extensions.md](proposals/csharp-14.0/extensions.md#declaration)):\n\n```antlr\nextension_member_declaration\n        : method_declaration\n        | property_declaration\n        | indexer_declaration // new\n        | operator_declaration\n        ;\n```\n\nLike ordinary indexers, extension indexers have no identifier and are identified\nby their parameter list. Extension indexers may use the full set of features that\nordinary indexers support today (accessor bodies, expression-bodied members,\nref-returning accessors, `scoped` parameters, attributes, etc.).\n\nBecause indexers are always instance members, an extension block that declares\nan indexer must provide a named receiver parameter.  \n\nThe existing restrictions on extension members continue to apply: indexers inside an\nextension declaration cannot specify `abstract`, `virtual`, `override`, `new`,\n`sealed`, `partial`, `protected` (or any of the related accessibility modifiers),\nor `init` accessors.\n\n```csharp\npublic static class BitExtensions\n{\n    extension(int i)\n    {\n        public bool this[int index]\n        {\n            get => ...;\n        }\n    }\n}\n```\n\nAll rules from the C# standard that apply to ordinary indexers apply to extension indexers,\nbut extension members do not have an implicit or explicit `this`.\n\nThe existing extension member inferrability rule still applies: For each non-method extension member, \nall the type parameters of its extension block must be used in the combined set of parameters from the extension and the member.\n\n### `IndexerName` attribute\n\n`IndexerNameAttribute` may be applied to an extension indexer. The attribute is\nnot emitted in metadata, but its value affects conflicts between members,\nit determines the name of the property and accessors in metadata, \nand is used when emitting `[DefaultMemberAttribute]` (see [Metadata](#metadata)).\n\n## Consumption\n\n### Indexer access\n\nThe rules in [Indexer access](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#128124-indexer-access)\nare updated: if the normal processing of the indexer access finds no applicable indexer,\nan attempt is made to process the construct as an extension indexer access.\n\n1. Attempt to bind using only the instance indexers declared (or inherited) on\n    the receiver type. If an applicable candidate is found, overload resolution\n    selects among those instance members as today and stops.\n2. If the set of applicable indexers is empty, \n    an attempt is made to process the **element_access** as\n    an implicit `System.Index`/`System.Range` indexer access\n    (which relies on `Length`/`Count` plus `this[int]`/`Slice(int, int)`).\n3. If both steps fail to identify any applicable indexers, an attempt is made to process the \n    **element_access** as an extension indexer access.\n   \nNote: the element access section handles the case where an argument has type `dynamic`,\nso it never gets processed as an indexer access.\n\n#### Extension indexer access\n\nExtension members, including extension indexers, are never considered when the\nreceiver is a **base_access** expression.\n\nNote: we only process an **element_access** as an indexer access if the receiver\nis a variable or value, so extension indexers are never considered when the\nreceiver is a type.\n\nGiven an **element_access** `E[A]`, the objective is to identify an extension indexer.\n\nA candidate extension indexer is ***applicable*** with respect to receiver `E` and argument list `A`\nif an expanded signature, comprised of the type parameters of the extension block and\na parameter list combining the extension parameter with the indexer's parameters, is applicable\nwith respect to an argument list combining the receiver `E` with the argument list `A`.\n\nWe reuse the extension method scope-walk: we traverse the same scopes consulted for\nextension method invocation, including the current and enclosing lexical scopes\nand `using` namespace or `using static` imports.\n\nConsidering each scope in turn:\n- Extension blocks in non-generic static class declarations in the current scope are considered.\n- The indexers in those extension blocks comprise the candidate set.\n- Candidates that are not accessible are removed from the set.\n- Candidates that are not applicable (as defined above) are removed from the set.\n- If the resulting set is not empty, overload resolution is applied to the candidate set. \n  - If a single best indexer can be identified, then we have successfully processed the indexer access.\n  - Otherwise, the extension indexer access is ambiguous and a compile-time error occurs.\n- Otherwise, an attempt is made to process the **element_access** as an implicit `System.Index`/`System.Range` indexer access\n  (which relies on `Length`/`Count` plus `this[int]`/`Slice(int, int)`) using extension members in the current scope.\n  - If there is no applicable candidate for one or both parts, then we proceed to the next scope.\n  - If an applicable candidate is found for both parts (the `Length`/`Count` part and the `this[int]`/`Slice(int, int)` part),\n    then we consider there was an applicable extension implicit indexer and this is the last scope we will consider.\n    - If a single best member can be identified for each part, then we have successfully processed the implicit indexer access. \n    - Otherwise, a compile-time error occurs.\n\nUsing this single best indexer identified at the previous step, the indexer access \nis then processed as a static method invocation.  \n\nDepending on the context in which it is used, an indexer access causes invocation of either \nthe *get_accessor* or the *set_accessor* of the indexer.  \nIf the indexer access is the target of an assignment, the *set_accessor* static implementation method\nis invoked to assign a new value.  \nIn all other cases, the *get_accessor* static implementation method is invoked\nto obtain the current value.  \nEither way, the invocation will use generic arguments inferred during the applicability check and\nthe receiver as the first argument.\n\n### Other element-access forms\n\nAny construct that defers to element-access binding (null-conditional element access or assignments,\nindex assignments in object initializers, or list and spread patterns) automatically\nparticipates in the extension indexer resolution described above.\n\n- So a type with a suitable `Length` or  `Count` extension properties is considered *countable* for the purpose of\n    those patterns.\n- The implicit `System.Index`/`System.Range` fallback indexers can also be extensions,\n   but the two parts (`Length`/`Count` and  `this[int]`/`Slice(int, int)`) must be found in the same scope.\n\nNote:  Since a list-pattern with a spread-pattern needs to bind a `Length`/`Count`, a real or implicit `this[Index]` and a real or implicit `this[Range]`, \n  it may use the `Length` from one scope, the `this[int]` and corresponding `Length` from another scope\n  and the `Slice(int, int)` and `Length` from yet another scope.\n  The compiler assumes that the `Length`/`Count` properties are well-behaved and give the same result. \n\n### Expression trees\n\nExtension indexers cannot be captured in expression trees.\n\n### XML docs\n\nCREF syntax allows referring to an extension indexer and its accessors, as well as its implementation methods.\n\nExample:\n```csharp\n/// <see cref=\"E.extension(int).this[string]\"/>\n/// <see cref=\"E.extension(int).get_Item(string)\"/>\n/// <see cref=\"E.extension(int).get_Item\"/>\n/// <see cref=\"E.extension(int).set_Item(string, int)\"/>\n/// <see cref=\"E.extension(int).set_Item\"/>\n/// <see cref=\"E.get_Item(int, string)\"/>\n/// <see cref=\"E.get_Item\"/>\n/// <see cref=\"E.set_Item(int, string, int)\"/>\n/// <see cref=\"E.set_Item\"/>\npublic static class E\n{\n    extension(int i)\n    {\n        /// <summary></summary>\n        public int this[string s]\n        {\n            get => throw null;\n            set => throw null;\n        }\n    }\n}\n```\n\n## Metadata\n\nExtension indexers follow the same lowering model as extension properties. For\neach CLR-level extension grouping type that contains at least one indexer, the\ncompiler emits:\n\n- An extension property named `Item` (or the value supplied by\n    `IndexerNameAttribute`) with accessor bodies that `throw NotImplementedException()`\n    and an `[ExtensionMarkerName]` attribute referencing the appropriate extension\n    marker type.\n- Implementation methods named `get_Item`/`set_Item` in the enclosing static\n    class. These methods prepend the receiver parameter to the parameter list and\n    contain the user-defined bodies. They are `static` and participate in overload\n    resolution in the same way as implementation methods for extension properties.\n\nTo mirror the behavior of ordinary indexers, the compiler also emits\n`[DefaultMemberAttribute]` on any extension grouping type that contains one or\nmore extension indexers. The attribute’s `MemberName` equals the metadata name of\nthe indexer (`Item` by default, or the value from `IndexerNameAttribute`).\n\n### Example\n\nSource code:\n\n```csharp\nstatic class BitExtensions\n{\n    extension<T>(T t)\n    {\n        public bool this[int index]\n        {\n            get => ...;\n            set => ...;\n        }\n    }\n}\n```\n\nEmitted metadata (simplified to C#-like syntax):\n\n```csharp\n[Extension]\nstatic class BitExtensions\n{\n    [Extension, SpecialName, DefaultMember(\"Item\")]\n    public sealed class <G>$T0 // grouping type\n    {\n        [SpecialName]\n        public static class <M>$T_t // marker type\n        {\n            [SpecialName]\n            public static void <Extension>$(T t) { } // marker method\n        }\n\n        [ExtensionMarkerName(\"<M>$T_t\")]\n        public bool this[int index] // extension indexer\n        {\n            get => throw new NotImplementedException();\n            set => throw new NotImplementedException();\n        }\n    }\n\n    // accessor implementation methods\n    public static bool get_Item<T>(T t, int index) => ...;\n    public static void set_Item<T>(T t, int index, bool value) => ...;\n}\n```\n\n## Open issues\n\n### ~~Dealing with `params`~~\n\nIf you have an extension indexer with `params`, such as `int this[int i, params string[] s] { get; set; }`,\nthere are three ways you could use it:\n- extension indexing:  `receiver[i: 0, \"Alice\", \"Bob\"]`\n- getter implementation invocation: `E.get_Item(receiver, i: 0, \"Alice\", \"Bob\")`\n- setter implementation invocation: `E.set_Item(...)`\n\nBut what is the signature of the setter implementation method?  \nIt only makes sense for the last parameter of a user-invocable method signature to have `params`,\nso it serves no purpose in `E.set_Item(... extension parameter ..., this i, params string[] s, int value)`.\n\nSome options:\n1. disallow `params` for extension indexers that have a setter\n2. omit the `[ParamArray]` attribute on the setter implementation method\n3. do nothing special (emit the `[ParamArray]`)\n\nI would propose option 2, as it maximizes `params` usefulness. The cost is only a small difference between\nextension indexing and disambiguation syntax.\n\nDecision (LDM 2026-02-02): emit the `[ParamArray]` and verify no negative impact on tooling\n\n### ~~Impact of assigned value to type inference~~\n\n```csharp\nint i = 0;\ni[42, null] = new object(); // fails inference\nE.set_Item(i, 42, null, new object()); // infer `E.set_Item<object>`\n\npublic static class E\n{\n    extension<T>(int i)\n    {\n        public T this[int j, T t] { set { } }\n    }\n}\n```\n\n```csharp\n#nullable enable\n\nint i = 0;\ni[new object()] = null; // infer `E.extension<object!>` and warn on conversion of null literal to `object!`\nE.set_Item(i, new object(), null); // infer `E.set_Item<object?>`\n\npublic static class E\n{\n    extension<T>(int i)\n    {\n        public T this[T t] { set { } }\n    }\n}\n```\n\nDecision (LDM 2026-02-02): the indexer is inferred only given the receiver and arguments in the argument list (ie. the assigned value doesn't contribute).\n\n### ~~Should extension `Length`/`Count` properties make a type countable?~~\n\nAs a reminder, extensions do not come into play when binding [implicit Index or Range indexers](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-8.0/ranges.md#adding-index-and-range-support-to-existing-library-types):\n```csharp\nC c = new C();\n_ = c[..]; // Cannot apply indexing with [] to an expression of type 'C'\n\nclass C\n{\n    public int Length => 0;\n}\n\nstatic class E\n{\n    public static C Slice(this C c, int i, int j) => null!;\n}\n```\n\nSo our position so far has been that extensions properties should not count as \"countable properties\"\nin list-patterns, collection expressions and implicit indexers.\n\nIf we expose `this[Index]` or `this[Range]` extension indexers in element access scenarios,\nit is natural to expect the target type to work in list patterns.  \nList patterns, however, require a `Length` or `Count` property.\n\nShould extension properties satisfy that requirement? (that would seem natural)\n\n```csharp\nC c = new C();\nvar x1 = c[^1];\nvar x2 = c[1..];\n\nif (c is [.., var y1]) { }\nif (c is [_, .. var y2]) { }\n\nclass C { }\n\nstatic class E\n{\n  extension(C c)\n  {\n    object this[System.Index] => ...;\n    C this[System.Range] => ...;\n    int Length => ...;\n  }\n}\n```\n\nBut then, should those properties also contribute to the implicit indexer fallback\n(`Length`/`Count` + `Slice`) that is used when an explicit `Index`/`Range` indexer\nis missing?\n\n```csharp\nC c = new C();\nif (c is [var y1, .. var y2]) { }\n\nclass C\n{\n  C Slice(int i, int j) => ...;\n}\n\nstatic class E\n{\n  extension(C c)\n  {\n    object this[System.Index] => ...;\n    int Length => ...;\n  }\n}\n```\n\nDecision (LDM 2026-02-02): extensions should contribute everywhere, including countable properties and implicit indexer fallback.\n\n### ~~Confirm whether extension indexer access comes before or after implicit indexers~~\n\n```csharp\nC c = new C();\n_ = c[^1];\n\nclass C\n{\n  public int Length => ...;\n  public int this[int i] => ...;\n}\n\nstatic class E\n{\n  extension(C c)\n  {\n    public int this[System.Index i] => ...;\n  }\n}\n```\n\nI've spec'ed and implemented extension indexer access as having priority over implicit indexers,\nbut now think they should come after to avoid unnecessary compat breaks.\n\nUpdate (LDM 2026-02-02): this needs further investigation. Yes, extensions should come after non-extension members,\nbut beyond that we need some concrete proposals in light of above decision to allow extensions to contribute to implicit indexer fallback.\n\n### Count/Length: Is the name prioritized first, or non-extension vs extension?\n\nWe also have an existing fallback: `Length` is prioritized over `Count` property.\nShould an extension `Length` come before or after a non-extension `Count` property?\n\nAnswer: the proposal is to look up scope by scope. Instance scope comes before extension scopes.  \nWithin each scope, we prefer `Length` over `Count`.\n\n### ~~Confirm proposed design for implicit indexers~~\n\nWe look scope-by-scope, starting from instance scope and then proceeding to extension scopes.  \nWithin a scope:\n1. we look for a real indexer,\n2. otherwise, if we have a single argument of the right type, then we look for an implicit indexer.\n\nDecision (LDM 2026-03-09): no, once we move into extension scopes, we're going to use all-the-way-through extension resolution.\n\n### ~~Confirm proposed design for list-patterns~~\n\nFor a list-pattern with a spread, we will look for:\n1. a `Length`/`Count`\n2. a real or implicit `this[Index]`\n3. a real or implicit `this[Range]`\n\nWe will look for each independently.\nBut when we look for an implicit `this[Index]` or `this[Range]`, the two parts must come from the same scope:\n1. `Length`/`Count`\n2. `this[int]`/`Slice(int, int)`\n\nNote: the non-negative handling for `Length` patterns kicks in when a type can be used in a list-pattern (ie. it is countable and indexable).\n\nDecision (LDM 2026-03-09): no, we'll follow this lookup order instead:\n1. List patterns are resolved as if we look for Length/Count, Index indexer and Range indexer individually\n2. For Index and Range indexers, proceed as follows:\n    a. With instance lookup only, find the \"real\" index if possible\n    b. With instance lookup only, find the parts of the implicit indexer if possible\n    c. With full lookup (instance+extension), find the \"real\" index if possible\n    d. With full lookup (instance+extension), find the parts of the implicit indexer if possible (each in individual lookups)\n\n### ~~Should extension `Slice` method also contribute?~~\n\n```cs\n_ = c[1..^1];\n\nstatic class E\n{\n  extension(C c)\n  {\n    public int Length => 3;\n  }\n  public static C Slice(this C c, int i, int j) => ...;\n}\n```\n\nDecision (LDM 2026-03-09): yes, we're treating classic and new extension methods exactly the same.\n\n### ~~Should extension `Length` contribute to spread optimization?~~\n\n```cs\nC c = new C();\nint[] i = [0, .. c]; // Uses Length, if available, to allocate the right size\n```\n\nDecision (LDM 2026-03-09): no, it's unlikely that an extension would be able to implement this in a performant way, so it would not help for optimization.\n"
  },
  {
    "path": "proposals/fieldof.md",
    "content": "# Allow direct use of backing field during construction\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/9031>\nChampion issue for `field` keyword: https://github.com/dotnet/csharplang/issues/8635  \nRelated discussion: https://github.com/dotnet/csharplang/discussions/8704\n\n## Summary\n[summary]: #summary\n\n<!-- One paragraph explanation of the feature. -->\n\nAllow direct assignment and use of a property's backing field during construction, without having to invoke the setter, via a new `fieldof(Prop)` expression.\n\n```cs\nclass C\n{\n    public C(DataStore store)\n    {\n        this.store = store;\n\n        fieldof(this.Prop) = store.ReadPropFromDisk();\n        M(ref fieldof(this.Prop));\n    }\n\n    void Method()\n    {\n        // error: 'fieldof' can only be used during initialization (see also Alternatives)\n        fieldof(this.Prop) = \"a\";\n    }\n\n    private DataStore store;\n\n    public string Prop\n    {\n        get => field;\n        set\n        {\n            if (value != field)\n            {\n                field = value;\n                store.WritePropToDisk(value);\n            }\n        }\n    }\n}\n```\n\n## Motivation\n[motivation]: #motivation\n\n<!-- Why are we doing this? What use cases does it support? What is the expected outcome? -->\n\nWe are seeing prominent source generators such as [MVVM Toolkit](https://github.com/CommunityToolkit/dotnet) and [ComputeSharp](https://github.com/Sergio0694/ComputeSharp) making heavy use of *partial field-backed properties*. Using a backing field for a partial property implementation comes with a number of experience improvements, including:\n1. avoiding the need for either generator or user to introduce an additional member with a distinct name (and in practice, often the generator needs to introduce it, which is bad for discoverability).\n2. avoiding the need for the generator to \"wire up\" the relationship between the field and property, in order to make it clear to user and compiler (e.g. for nullable constructor analysis).\n3. allowing user to put `[field: Attr]` on the definition part of the property, and have the attributes just go where they're supposed to, without any hacky workarounds from the generator itself.\n4. allowing user to put a property initializer on the definition part, letting the user initialize the field during construction without invoking the setter logic.\n\nUsers are hitting limitations related to (4). Specifically, by *only* allowing the property initializer itself to assign the backing field, we are imposing an inconvenient limitation on what values are allowed to \"bypass the setter\" during construction:\n\n```cs\nclass C1\n{\n    // \"stuff available in a static context\" can be used:\n    public partial string Prop { get; set; } = ValueFactory.GetValue();\n}\n\nclass C2(string prop)\n{\n    // primary constructor parameters can be used:\n    public partial string Prop { get; set; } = prop;\n}\n\npublic class C3\n{\n    // but non-primary constructors must go through setter logic.\n    internal C3()\n    {\n        // even though users may have reasons that a primary constructor isn't suitable.\n        // e.g. in this case, even if we figure out how to make things work with a primary constructor,\n        // we may not want that constructor to have the same accessibility as the containing type.\n        var (first, second) = GetValues();\n        Prop1 = first;\n        Prop2 = second;\n    }\n\n    public partial string Prop1 { get; set; }\n    public partial string Prop2 { get; set; }\n}\n```\n\nSee also [field-keyword.md#property-initializers](https://github.com/dotnet/csharplang/blob/main/proposals/field-keyword.md#property-initializers). It's fairly easy to imagine the `bool IsActive` example from that proposal, which motivated the property initializer behavior we have today, where the initial value doesn't simply come from a constant or a static, but needs to be passed in through a constructor.\n\n```cs\nclass SomeViewModel\n{\n    public SomeViewModel(bool isActive)\n    {\n        // without a way to assign the field directly,\n        // 'HasPendingChanges' is set to true, only when 'isActive' is true.\n        // But all we're trying to do is rehydrate state from a previous session/user setting/etc..\n        IsActive = isActive;\n    }\n\n    public bool HasPendingChanges { get; private set; }\n\n    public bool IsActive { get; set => Set(ref field, value); }\n\n    private bool Set<T>(ref T location, T value)\n    {\n        if (EqualityComparer<T>.Default.Equals(location, value))\n            return false;\n\n        location = value;\n        HasPendingChanges = true;\n        return true;\n    }\n}\n```\n\n### Why not just declare the field explicitly?\n\nWe believe that solutions involving explicitly declaring the backing field will significantly degrade the end user experience in source generator scenarios. Essentially, hand-rolled substitutes for the benefits outlined in [Motivation](#motivation) are unlikely to be uniform and fully correct across various generators. Users would have to get oriented with different solutions across different generators for associating the field and property, locating the related declarations in user code and generated code, applying attributes independently to the field and property, and applying field initializers. See also [Alternate generator patterns](#alternate-generator-patterns).\n\n### What about encapsulation?\n\nOne purported benefit of the `field` keyword feature is that it is *only* usable from within the property accessors. It may seem questionable that this proposal is to seemingly change that, and allow the `field` to *also* be used in constructors.\n\nHowever, this encapsulation has never been as complete as the above statement implies. Today, a type's constructors need to be concerned with which properties are *field-backed*, because it is directly related to nullable constructor analysis--forgetting to assign or check a field-backed property can result in a warning, while doing the same on a non-field-backed property will not.\n\n```cs\nclass C\n{\n    public string Prop1 { get => ValueStore.Get(); set => ValueStore.Set(value); }\n    public string Prop2 { get => field; set => field = value; }\n\n    // warning for Prop2, but not for Prop1\n    public C() { }\n}\n```\n\nThe fact that a property initializer (and by extension, a primary constructor) is permitted to \"bypass\" the setter logic is necessary and useful. We think that allowing such \"bypass\" to occur in ordinary constructors of the same type is useful for the same reasons. Because the capability remains limited to construction-time, we believe it preserves and reinforces the benefits of using the `field` keyword.\n\n## Detailed design\n[design]: #detailed-design\n\n<!-- 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. This section can start out light before the prototyping phase but should get into specifics and corner-cases as the feature is iteratively designed and implemented. -->\n\nThe grammar is updated as follows:\n\n```diff\n primary_no_array_creation_expression\n     : literal\n     | interpolated_string_expression\n     | simple_name\n     | parenthesized_expression\n (...)\n     | nameof_expression\n+    | fieldof_expression\n (...)\n     ;\n\n+fieldof_expression\n+    : 'fieldof' '(' expression ')'\n+    ;\n\n```\n\nA `fieldof_expression` of the form `fieldof(P)` is evaluated and classified as follows:\n- If the containing member of the expression is not a constructor or `init` accessor, a compile-time error occurs.\n- If `P` is not classified as a property access of a [field-backed property](https://github.com/dotnet/csharplang/blob/main/proposals/field-keyword.md#glossary), a compile-time error occurs.\n- If `P` is classified as a property access of a field-backed property, then `fieldof(P)` is classified as a variable, specifically the backing field of `P`.\n- If `P` is static and the containing constructor is not static, or vice-versa, a compile-time error occurs.\n- If `P` is not declared in the containing type, a compile-time error occurs. (`fieldof()` does not work with a property declared on a base type.)\n- Otherwise, `fieldof(P)` denotes the backing field of `P`.\n\nA `fieldof_expression` is subject to limitations on the receiver of its property access, similar to an assignment to a `readonly` field. Specifically, the receiver must be the instance being initialized by the containing constructor, i.e. explicit or implicit `this`. Otherwise, a compile-time error occurs.\n\n### Ref safety\n\nThe *ref-safe-context* ([§9.7.2.4](https://github.com/dotnet/csharpstandard/blob/81d9d57826f289fbf772e10dfec776227fab1006/standard/variables.md#9724-field-ref-safe-context)) for an expression of the form `fieldof(e.P)` is determined as follows:\n- If `e` is of a value type, then the *ref-safe-context* of `fieldof(e.P)` is the same as the *ref-safe-context* of `e`.\n- Otherwise, its *ref-safe-context* is *caller-context*.\n\nThe *safe-context* ([§16.4.12.4](https://github.com/dotnet/csharpstandard/blob/81d9d57826f289fbf772e10dfec776227fab1006/standard/structs.md#164124-field-safe-context)) for an expression of the form `fieldof(e.P)` is determined as follows:\n- If `e.P` is of ref struct type, then the *safe-context* of `fieldof(e.P)` is the same as the *safe-context* of `e`.\n- Otherwise, its *safe-context* is *caller-context*.\n\nThe above ref safety rules are strongly analogous to the existing, linked rules which apply to ordinary field accesses.\n\n### Compat\n\nThis design makes no concession to preserving existing `fieldof(P)` behavior when a symbol `fieldof` is already in scope. This is a divergence from existing `nameof` behavior, but aligns with the existing breaking change design of the `field` keyword itself.\n\nThis proposal also reserves `fieldof(P)` in expression contexts generally, rather than reserving it only in constructors and `init` accessors. Existing code containing calls like `fieldof(P)` would need to be changed to `@fieldof(P)` in order to avoid breaks. We could consider instead limiting the break to only apply within constructors and `init` accessors.\n\nDepending on feedback, we could also adjust the design so that `fieldof` works more like `nameof`, and simply becomes unavailable when a symbol `fieldof` is in scope.\n\nTo give a sense of relative risk of the break with `field`, versus `fieldof`, there are about ~86k results for `field` in C# source and comments on GitHub, and about 5 of the same for `fieldof`, at time of writing.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\n<!-- Why should we *not* do this? -->\n\nThe motivating scenarios may not rise to the level of justifying a new contextual keyword or specialized syntax form in the language.\n\n## Alternatives\n[alternatives]: #alternatives\n\n### Permit anywhere in the same type\n\nExcept for encapsulation, there isn't a specific reason we *need* to limit use of `fieldof()` to initialization. We could instead allow it anywhere in the same type if we wanted, which would effectively make `field` itself just a shorthand for `fieldof()` for the current property.\n\n```cs\nclass C\n{\n    string P { get => fieldof(P); set => field = value; }\n\n    void M0()\n    {\n        M1(ref fieldof(P));\n    }\n\n    void M1(ref string s) { }\n}\n```\n\nThe \"encapsulation\" behavior, as it currently exists in absence of `fieldof()`, seems appealing, as prevents misuse of the field outside the policy of the associated property. However, since `fieldof()` is always a more nested expression than a property access, it seems like users will tend to use the property *anyway* unless they have a specific reason for needing to use the field.\n\nIf we think that there are justified construction-specific cases for using the backing field directly, then perhaps there are also valid post-construction cases as well, that we may not know about yet, and it's not justified to put in a *cliff*, saying: sorry, only during initialization or in the accessors. Instead, we could simply see what the user is trying to do, and get out of their way.\n\nAt the same time, `field` was thought to be a stepping stone toward a more general \"property scoped fields\" feature--where it seems much harder to justify accessing the fields outside of the property. The *just get out of the user's way* line of reasoning also seems to lead to letting people specify any accessibility for the backing field, which somehow seems a little too far.\n\nEssentially, the `field` feature is providing both *encapsulation* and *association* benefits. The question is whether to allow users to drop the *encapsulation* part, if they wish, and keep the *association* part.\n\n### Alternate syntaxes\n\nWe could consider alternative syntax for doing the same thing, such as an [init prefix](https://github.com/dotnet/csharplang/discussions/8704#discussioncomment-11450489):\n```cs\npublic C(string prop)\n{\n    // 'init' prefix appearing before an assignment means assign a backing field.\n    init Prop = prop;\n}\n```\n\nArguably, `fieldof(Prop)` is more clear than `init Prop`. The latter is more of a \"knowledge check\" that a property initializer assigns the field without calling the setter, and that we are using `init` to \"simulate\" such an initializer outside of the property declaration. While `fieldof(Prop)` more directly states \"we are using the field here\".\n\nAlso, due to reusing an accessor keyword, it may be confusing to unfamiliar users:\n\n```cs\nclass C\n{\n    public string Prop { get; init { SideEffect(); field = value; } }\n    public C(string prop)\n    {\n        // wait.. putting 'init' here means \"don't use the init accessor\"?\n        init Prop = prop;\n    }\n}\n```\n\n### Alternate generator patterns\n\nGenerator authors could come up with a pattern where the field is explicitly declared by either generator or user, and associated to the property in a way that generator and compiler can understand (e.g., nullability attributes, naming conventions, and/or generator-specific attributes to associate members by name). Then, user can simply refer to the explicit field in a constructor.\n\nWe think this is a bad solution, because it requires generator authors to solve all the bullet points mentioned in [Motivation](#motivation), and necessarily results in a compromised end user experience.\n\n### `initialized` flag pattern\n\nWe could advise users in this situation to introduce a flag which is set at the end of construction:\n\n```cs\nclass C\n{\n    private readonly bool _initialized;\n\n    public C(string prop)\n    {\n        Prop = prop;\n        _initialized = true;\n    }\n\n    public string Prop\n    {\n        get => field;\n        set\n        {\n            if (!_initialized)\n            {\n                field = value;\n                return;\n            }\n\n            if (value != field)\n            {\n                field = value;\n                OnPropertyChanged();\n            }\n        }\n    }\n}\n```\n\nWe think this is not a palatable solution compared to simply being able to set the field, due to increasing memory usage and complicating setter and constructor logic.\n\n## Open questions\n[open]: #open-questions\n\n<!-- What parts of the design are still undecided? -->\n\nSee [Compat](#compat).\n"
  },
  {
    "path": "proposals/final-initializers.md",
    "content": "# Final initializers\n\n* [x] Proposed\n* [ ] Prototype: Not Started\n* [ ] Implementation: Not Started\n* [ ] Specification: Not Started\n\n## Summary\n[summary]: #summary\n\nFinal initializers are a proposed new kind of member declaration that runs at the end of an object's initialization - after constructors, object initializers and collection initializers.\n\n*Early notes refer to these as \"validators\".*\n\n## Motivation\n[motivation]: #motivation\n\nWith object and collection initializers in the language, there is not a place in a type declaration to write code that runs *after* the object is otherwise fully initialized - e.g. to do final validation, trim or clean up input, compute additional private state, register the object somewhere, etc. Final initializers provide a new kind of member declaration specifically for that purpose.\n\nAs an example, consider a type which has properties for the year, month and the day. The month should be a value in the range 1-12 and the day checked against the `DateTime.DaysInMonth` method which uses the year and month. While this check can easily be done in a constructor, there is currently no way to do the check when object initializers are allowed. These checks could be done in the final initializer which would run after all constructors and initialization, including initialization done in code instantiating a member of the class.\n\n## Detailed design\n[design]: #detailed-design\n\nRunning example:\n\n``` c#\npublic class Person\n{\n    public required string FirstName { get; init; }\n    public string? MiddleName { get; init; }\n    public required string LastName { get; init; }\n\n    private readonly string fullName;\n\n    init\n    {\n        // Fix up provided state\n        FirstName = FirstName.Trim();\n        MiddleName = MiddleName?.Trim();\n        LastName = LastName.Trim();\n\n        // Validate state\n        if (FirstName is \"\") throw new ArgumentException(\"Empty names not allowed\", nameof(FirstName));\n        if (LastName is \"\") throw new ArgumentException(\"Empty names not allowed\", nameof(LastName));\n\n        // Compute additional state\n        fullName = (MiddleName is null)\n            ? $\"{FirstName} {LastName}\"\n            : $\"{FirstName} {MiddleName} {LastName}\";\n    }\n\n    public override string ToString() => fullName;\n}\n```\n\n### Syntax\n\nThis production is added to `class_member_declaration`, etc.:\n\n``` antlr\nfinal_initializer_declaration\n    : attributes? `init` method_body\n    ;\n```\n\nNo modifiers can be specified. In some ways the declaration is a counterpart to a finalizer [14.13](https://github.com/dotnet/csharpstandard/blob/draft-v7/standard/classes.md#1413-finalizers), in that it has a very specific format with few points of decision for the programmer.\n\n### Semantics\n\nUnless one is specified, all types are considered to have an implicit, empty final initializer. A final initializer is considered a public virtual instance member. A final initializer declaration is considered an override, and will implicitly perform a call to the final initializer of the base class before executing the specified body, all the way up to the (empty) final initializer of the `object` class.\n\nJust like within constructor bodies and `init` accessor bodies, `readonly` fields and init-only properties can be assigned to within a final initializer body.\n\nIn the above example, all the assignments in the final initializer body are to readonly fields and init-only properties.\n\nAt the end of the execution of an object creation expression ([11.7.15.2](https://github.com/dotnet/csharpstandard/blob/draft-v7/standard/expressions.md#117152-object-creation-expressions)) or a `with` expression, the resulting object's final initializer is executed as a function member invocation [11.6.6](https://github.com/dotnet/csharpstandard/blob/draft-v7/standard/expressions.md#1166-function-member-invocation) on the resulting object, which means that it will be a virtual call based on the runtime type of that object.\n\n### Nullability\n\nWhen it comes to nullability analysis, the body of the final initializer would be assumed to benefit from member initializers and would consider `required` member annotations when it comes to *reading* non-nullable reference fields. It would in turn contribute to preventing nullability warnings by *writing* to non-nullable reference fields.\n\nIn the above example `FirstName.Trim()` does not yield a nullability warning, because the property is required. At the same time, the declaration of the non-nullable `fullName` does not yield a nullability error, because it is assigned to in the final initializer.\n\n### Inheritance hierarchies\n\nFinal initializers would always call the base class final initializer before performing the code of the initializer.\n\n### Implementation strategies\n\nFinal initializers would probably be implemented as a public virtual method with an unspeakable name (same across all final initializers), no parameters and a `void` return type. This proposal is for `object` itself to have such a virtual method, and for all final initializer declarations to be turned into overrides of this method with a `base` call prepended to the body. This would lead to every single object having such a method on it, which may or may not be an issue. The name of this method would be consistent across all final initializers and unspeakable, assuming use cases for users to directly call it are not discovered.\n\n\nUsing this strategy, the final initializer in the above example would generate a method override like the following:\n\n``` c#\n    public override void __final_initializer()\n    {\n        base.__final_initializer();\n\n        ...\n    }\n```\n\nAn object creation expression\n\n``` c#\nnew Person { FirstName = \"Marie\", LastName = \"Curie\" }\n```\n\nwould generate code to create the object and initialize the properties, as today, followed by a call to `__final_initializer()``:\n\n``` c#\nvar __tmp = new Person();\n__tmp.FirstName = \"Marie\";\n__tmp.LastName = \"Curie\";\n__.tmp.__final_initializer();\n```\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nThis is yet another mechanism related to object initialization. While it provides a means for behaviors and guarantees around object state that weren't available before, it needs to be weighed against the complexity it adds.\n\n## Alternatives\n[alternatives]: #alternatives\n\n### Implementation\n[implementation]: #implementation\n\nOther alternatives include introducing method declarations only when necessitated by final initializer declarations. Under such strategies, it is important that the presence of final initializer methods is dynamically discoverable (either through reflection, interface implementation or otherwise), so that even when the runtime type is not statically known, the final initializer can be found and called. This can be the case for `with` expressions.\n\nThe latter set of approaches can be vulnerable to binary breaks - if a base class introduces a final initializer, a derived class that is not recompiled may have the wrong semantics and not call the base.\n\n### Syntax/naming\n[syntax-naming]: #syntax-naming\n\n- Is the `init` syntax the best choice? Should it rather mirror finalizers in some way, with a glyph and an empty parameter list `()`?\n- Is unconditionally calling the base final initializer before the body too inflexible? Should there be an explicit base call syntax instead?\n\n### Inheritance\n[inheritance]: #inheritance\n\nAlternatively, the user be expected to call the base final initializer explicitly at some point in the execution of their final initializer, rather than emitting the code to call base automatically.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n- Which implementation strategy best balances performance with binary compatibility?\n- Should `extern` be supported, as it is for finalizers?\n\n## Design meetings\n\nhttps://github.com/dotnet/csharplang/blob/main/meetings/2020/LDM-2020-04-27.md#primary-constructor-bodies-and-validators\n"
  },
  {
    "path": "proposals/immediately-enumerated-collection-expressions.md",
    "content": "# Immediately Enumerated Collection Expressions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9754\n\n## Summary\n[summary]: #summary\n\nPermit collection expressions in \"immediately enumerated\" contexts, without requiring a target type.\n\n```cs\nforeach (bool b in [true, false])\n{\n    doMyLogicWith(b);\n}\n\nstring[] items1 = [\"a\", \"b\", .. [\"c\"]];\n```\n\nSee also https://github.com/dotnet/csharplang/blob/main/meetings/working-groups/collection-literals/collection-expressions-inferred-type.md.\n\n## Motivation\n[motivation]: #motivation\n\nChoosing a single \"natural type\" for collection expressions in the general case, e.g. `var coll = [1, 2, 3];`, has proven to be a difficult question and represents a major commitment. Should `coll` be a `List<int>`, `ReadOnlySpan<int>`, or something else? It's not obvious, and some of the possible answers represent a major engineering cost, and in any case a major statement about the defaults/preferences of the ecosystem.\n\nHowever, we do see a significant amount of demand for the ability to use collection expressions in contexts where the collection is immediately enumerated, and the collection value itself is not directly observable in user code. In this case, we should be able to define a solution which is convenient, optimal, and relatively low risk.\n\n## Detailed design\n[design]: #detailed-design\n\n### foreach\n\nGiven a foreach statement of the form:\n```cs\nforeach (iteration_type iteration_variable in collection)\n    embedded_stmt\n```\n- When `collection` lacks a natural type, we determine if a *collection expression iteration conversion* exists, from `collection` to type `IEnumerable<TElem>`, and apply the conversion if it exists.\n- `TElem` is determined in the following way:\n    - If `iteration_type` is explicitly typed (i.e. not `var`), then `TElem` is `iteration_type`.\n    - Otherwise, `TElem` is the *best common element type* of `collection`.\n- If the type of `TElem` can be determined, then the *collection expression iteration conversion* exists. Otherwise, the conversion does not exist.\n- As in [collection-expressions.md](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md), `IEnumerable<T>` refers to `System.Collections.Generic.IEnumerable<T>` throughout this specification.\n\n### spreads\n\nGiven a *spread element* of the form:\n```cs\n.. collection\n```\n- When `collection` lacks a natural type, we determine if a *collection expression iteration conversion* exists, from `collection` to type `IEnumerable<TElem>`, and apply the conversion if it exists.\n- `TElem` is determined in the following way:\n    - If the collection-expression containing the spread element `.. collection` is subject to a *collection expression conversion* to a type with an *element type*, then `TElem` is that *element type*.\n    - Otherwise, `TElem` is the *best common element type* of `collection`.\n- If the type of `TElem` can be determined, then the *collection expression iteration conversion* exists. Otherwise, the conversion does not exist.\n\n#### Remarks\n\nWe intend for the following cases, which push element type information down from a target type to just work:\n- `foreach (string? x in [null]) { }`\n- `string?[] items = [.. [null]];`\n- `List<string?> items = [.. [null]];`\n\nWhen no target element type is available, such as when `foreach (var x ...` form is being used, or when the element type of the containing collection-expression of a spread is not known, then, the *best common element type* mechanism is used to propagate the nested element type information outward.\n\n### Best common element type\n\nSee also [collection-expressions.md#type-inference](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#type-inference).\n\nThe *best common element type* of an expression `E` is determined similarly to the *best common type of a set of expressions* ([§12.6.3.16](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#126316-finding-the-best-common-type-of-a-set-of-expressions)):\n\n- A new *unfixed* type variable `X` is introduced.\n- An *output type inference* ([§12.6.3.8](expressions.md#12638-output-type-inferences)) is performed from `E` to `IEnumerable<X>`.\n- `X` is *fixed* ([§12.6.3.13](expressions.md#126313-fixing)), if possible, and the resulting type is the best common element type.\n- Otherwise inference fails.\n\nFor example, in the following statement, the element type of the collection being iterated, is same as the *best common type* of expressions `a, b, c`:\n\n```cs\nforeach (var item in [a, b, c])\n{\n}\n```\n\nNote that this feature is intentionally specified in such a way that an element type is determined similarly for the `foreach` collection above, as it is for a generic method call with an `IEnumerable<T>` parameter:\n\n```cs\nM([a, b, c]);\nvoid M<T>(IEnumerable<T> items)\n{\n}\n```\n\n### Implementation flexibility\n\nSimilar to [collection-expressions-in-foreach.md](https://github.com/dotnet/csharplang/blob/9d618b5eacaca9721550fb9a153a291087c10dae/proposals/collection-expressions-in-foreach.md), the implementation is encouraged to optimize based on the fact that user code can't observe the array which is created for a foreach-collection or spread-value under these new rules. So, it is free to use different strategies to allocate space for the collection elements such as an InlineArray on the stack, or not creating a collection instance at all and instead \"inlining\" the enumeration of elements.\n\n### Future considerations\n\nThis proposal doesn't get us 100% of the way there to \"conditional element inclusion\" scenarios like the following:\n\n```cs\n// The spread value is erroneous even after this proposal\nstring[] items2 = [\"a\", \"b\", .. includeRest ? [\"c\", \"d\"] : []];\n```\n\nWe are interested in pursuing type inference improvements which we expect to improve things across the board—for calls, foreach, and spreads—all in a similar way.\n```cs\n// Make all of the following work using a future type inference improvement:\nM1(cond ? [1] : [2]);\nM2(cond ? [1] : [2]);\nforeach (var item in cond ? [1] : [2]) { }\nstring[] array = [\"a\", \"b\", .. includeRest ? [\"c\", \"d\"] : []];\n\nvoid M1<T>(T[] items) { }\nvoid M2<T>(IEnumerable<T> items) { }\n```\n\nPermitting conditional element inclusion will also grow the optimization space, e.g.:\n\n```cs\nList<int> items = [a, b, .. includeMoreItems ? [c, d] : []];\n\n// someday could emit as:\nList<int> items = new List<int>(capacity: 2 + 2);\nitems.Add(a);\nitems.Add(b);\nif (includeMoreItems)\n{\n    items.Add(c);\n    items.Add(d);\n}\n```\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nEnsuring high-quality code generation in a wide variety of usage scenarios may be a significant amount of work.\n\n## Alternatives\n[alternatives]: #alternatives\n\nTake the [collection-expressions-in-foreach.md](https://github.com/dotnet/csharplang/blob/98d6837c32e8d0ab25a29001267be5be206a0f19/proposals/collection-expressions-in-foreach.md) proposal instead, which provides support for the \"base case\" `foreach (var item in [1, 2, 3])` only, and doesn't provide support in spreads.\n\n## Open questions\n[open]: #open-questions\n\n### Output type inference for spreads\n\nThe type inference rules (see [Method type argument inference](#method-type-argument-inference)) state the following regarding *output type inference*:\n\n> If `Eᵢ` is a *spread element*, no inference is made from `Eᵢ`.\n\nIt looks like this was added back in https://github.com/dotnet/csharplang/pull/7604 andthe significance of this decision isn't 100% clear. It's possibly because we were only making inferences from types at that time. In this proposal, we adjust this so that an output type inference can be made from expression, in the case of `[.. [() => expr1, () => expr2]]`, for example.\n\n**Resolution:** Break out type inference changes into its own proposal, and pare this proposal down to only providing a target type for collections and spread values which lack natural type.\n\n### Use of \"special language-level collection type\" for immediately enumerated collections\n\nInstead of `T[]`, we could choose to define the feature in terms of a new type kind defined at the language level. We would call it something like an *iteration type `T` with element type `Tₑ`.\n\nThis could potentially make it easier to define things in such a way that `foreach (Span<int> span in [span1, span2, span3]) { ... }` could work. However, we don't expect to have support for ref struct element type in the short term. Since ref structs don't work with so many things, that specific support requires careful design and possibly evolution of features like *ref fields* in order to permit types such as `ReadOnlySpan<Span<int>>`.\n\n**Resolution:** Use `IEnumerable<T>` as target type for the scenarios in this proposal. We think that using a special new type kind would add additional spec/implementation cost without adding significant value. Use of `IEnumerable<T>` permits ref structs as elements but not pointers. We'd like to investigate viability of actually generating code for the \"collection of Spans\" case, with caution, and understanding that the scenario may need to be blocked until separate, further language improvements are made.\n\n### Optimization of immediately enumerated `new[] { }` expressions\n\nSince we are already discussing optimization of `foreach (var i in [1, 2, 3])`, to avoid realizing the `int[]`, we may wish to also permit the compiler to optimize `foreach (var i in new[] { 1, 2, 3 })`.\n\n**Resolution:** We don't think the value is worth the risk, because array literals have been around such a long time. If people want the nice new codegen, they should move to the new syntax form.\n"
  },
  {
    "path": "proposals/inactive/README.md",
    "content": ""
  },
  {
    "path": "proposals/inactive/list-patterns-enumerables.md",
    "content": "# List patterns on enumerables\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/9005>\n\n## Summary\n\nLets you to match an enumerable with a sequence of patterns e.g. `enumerable is { 1, 2, 3 }` will match a sequence of the length three with 1, 2, 3 as its elements.\n\n## Detailed design\n\nThe pattern syntax is unchanged:\n\n```antlr\nprimary_pattern\n  : list_pattern\n  | length_pattern\n  | slice_pattern\n  | // all of the pattern forms previously defined\n  ;\n```\n\n### Pattern compatibility\n\nA *length_pattern* is now also compatible with any type that is not *countable* but is *enumerable* — it can be used in `foreach`.\n\nA *list_pattern* is now also compatible with any type that is not *indexable* but is *enumerable*.\n\nA *slice_pattern* without a subpattern is compatible with any type that is compatible with a *list_pattern*.\n\n```\nenumerable is { 1, 2, .. } // okay\nenumerable is { 1, 2, ..var x } // error\n```\n\n### Semantics\n\nIf the input type is *enumerable* but not *countable*, then the *length_pattern* is checked on the number of elements obtained from enumerating the collection.\n\nIf the input type is *enumerable* but not *indexable*, then the *list_pattern* enumerates elements from the collection and checks them against the listed patterns:  \nPatterns at the start of the *list_pattern* — that are before the `..` *slice_pattern* if one is present, or all otherwise — are matched against the elements produced at the start of the enumeration.  \nIf the collection does not produce enough elements to get a value corresponding to a starting pattern, the match fails. So the *constant_pattern* `3` in `{ 1, 2, 3, .. }` doesn't match when the collection has fewer than 3 elements.  \nPatterns at the end of the *list_pattern* (that are following the `..` *slice_pattern* if one is present) are matched against the elements produced at the end of the enumeration.  \nIf the collection does not produce enough elements to get values corresponding to the ending patterns, the *slice_pattern* does not match. So the *slice_pattern* in `{ 1, .., 3 }` doesn't match when the collection has fewer than 2 elements.  \nA *list_pattern* without a *slice_pattern* only matches if the number of elements produced by complete enumeration and the number of patterns are equals. So `{ _, _, _ }` only matches when the collection produces exactly 3 elements.\n\nNote that those implicit checks for number of elements in the collection are unaffected by the collection type being *countable*. So `{ _, _, _ }` will not make use of `Length` or `Count` even if one is available.\n\nWhen multiple *list_patterns* are applied to one input value the collection will be enumerated once at most:  \n```\n_ = collection switch\n{\n  { 1 } => ...,\n  { 2 } => ...,\n  { .., 3 } => ...,\n};\n\n_ = collectionContainer switch\n{\n  { Collection: { 1 } } => ...,\n  { Collection: { 2 } } => ...,\n  { Collection: { .., 3 } } => ...,\n};\n```\n\nIt is possible that the collection will not be completely enumerated. For example, if one of the patterns in the *list_pattern* doesn't match or when there are no ending patterns in a *list_pattern* (e.g. `collection is { 1, 2, .. }`).\n\nIf an enumerator is produced when a *list_pattern* is applied to an enumerable type and that enumerator is disposable it will be disposed when a top-level pattern containing the *list_pattern* successfully matches, or when none of the patterns match (in the case of a `switch` statement or expression). It is possible for an enumerator to be disposed more than once and the enumerator must ignore all calls to `Dispose` after the first one.\n```\n// any enumerator used to evaluate this switch statement is disposed at the indicated locations\n_ = collection switch\n{\n  { 1 } => /* here */  ...,\n  _ => /* here */ ...,\n};\n/* here too, with a spilled try/finally around the switch expression */\n```\n\n### Lowering on enumerable type\n\n> **Open question**: Need to investigate how to reduce allocation for the end circular buffer. `stackalloc` is bad in loops. Maybe we'll just have to fall back to locals and a `switch`.  (see [`params` feature discussion](https://github.com/dotnet/csharplang/blob/main/proposals/format.md#extending-params) also)\n\nAlthough a helper type is not necessary, it helps simplify and illustrate the logic.\n\n```\nclass ListPatternHelper\n{\n  // Notes: \n  // We could inline this logic to avoid creating a new type and to handle the pattern-based enumeration scenarios.\n  // We may only need one element in start buffer, or maybe none at all, if we can control the order of checks in the patterns DAG.\n  // We could emit a count check for a non-terminal `..` and economize on count checks a bit.\n  private EnumeratorType enumerator;\n  private int count;\n  private ElementType[] startBuffer;\n  private ElementType[] endCircularBuffer;\n\n  public ListPatternHelper(EnumerableType enumerable, int startPatternsCount, int endPatternsCount)\n  {\n    count = 0;\n    enumerator = enumerable.GetEnumerator();\n    startBuffer = startPatternsCount == 0 ? null : new ElementType[startPatternsCount];\n    endCircularBuffer = endPatternsCount == 0 ? null : new ElementType[endPatternsCount];\n  }\n\n  // targetIndex = -1 means we want to enumerate completely\n  private int MoveNextIfNeeded(int targetIndex)\n  {\n    int startSize = startBuffer?.Length ?? 0;\n    int endSize = endCircularBuffer?.Length ?? 0;\n    Debug.Assert(targetIndex == -1 || (targetIndex >= 0 && targetIndex < startSize));\n\n    while ((targetIndex == -1 || count <= targetIndex) && enumerator.MoveNext())\n    {\n      if (count < startSize)\n        startBuffer[count] = enumerator.Current;\n\n      if (endSize > 0)\n        endCircularBuffer[count % endSize] = enumerator.Current;\n\n      count++;\n    }\n\n    return count;\n  }\n\n  public bool Last()\n  {\n    return !enumerator.MoveNext();\n  }\n\n  public int Count()\n  {\n    return MoveNextIfNeeded(-1);\n  }\n\n  // fulfills the role of `[index]` for start elements when enough elements are available\n  public bool TryGetStartElement(int index, out ElementType value)\n  {\n    Debug.Assert(startBuffer is not null && index >= 0 && index < startBuffer.Length);\n    MoveNextIfNeeded(index);\n    if (count > index)\n    {\n      value = startBuffer[index];\n      return true;\n    }\n    value = default;\n    return false;\n  }\n\n  // fulfills the role of `[^hatIndex]` for end elements when enough elements are available\n  public ElementType GetEndElement(int hatIndex)\n  {\n    Debug.Assert(endCircularBuffer is not null && hatIndex > 0 && hatIndex <= endCircularBuffer.Length);\n    int endSize = endCircularBuffer.Length;\n    Debug.Assert(endSize > 0);\n    return endCircularBuffer[(count - hatIndex) % endSize];\n  }\n}\n```\n\n`collection is [3]` is lowered to\n```\n@{\n  var helper = new ListPatternHelper(collection, 0, 0);\n\n  helper.Count() == 3\n}\n```\n\n`collection is { 0, 1 }` is lowered to\n```\n@{\n  var helper = new ListPatternHelper(collection, 2, 0);\n\n  helper.TryGetStartElement(index: 0, out var element0) && element0 is 0 &&\n  helper.TryGetStartElement(1, out var element1) && element1 is 1 &&\n  helper.Last()\n}\n```\n\n`collection is { 0, 1, .. }` is lowered to\n```\n@{\n  var helper = new ListPatternHelper(collection, 2, 0);\n\n  helper.TryGetStartElement(index: 0, out var element0) && element0 is 0 &&\n  helper.TryGetStartElement(1, out var element1) && element1 is 1\n}\n```\n\n`collection is { .., 3, 4 }` is lowered to\n```\n@{\n  var helper = new ListPatternHelper(collection, 0, 2);\n\n  helper.Count() >= 2 && // `..` with 2 ending patterns\n  helper.GetEndElement(hatIndex: 2) is 3 && // [^2] is 3\n  helper.GetEndElement(1) is 4 // [^1] is 4\n}\n```\n\n`collection is { 1, 2, .., 3, 4 }` is lowered to\n```\n@{\n  var helper = new ListPatternHelper(collection, 2, 2);\n\n  helper.TryGetStartElement(index: 0, out var element0) && element0 is 1 &&\n  helper.TryGetStartElement(1, out var element1) && element1 is 2 &&\n  helper.Count() >= 4 && // `..` with 2 starting patterns and 2 ending patterns\n  helper.GetEndElement(hatIndex: 2) is 3 &&\n  helper.GetEndElement(1) is 4\n}\n```\n\nThe same way that a `Type { name: pattern }` *property_pattern* checks that the input has the expected type and isn't null before using that as receiver for the property checks, so can we have the `{ ..., ... }` *list_pattern* initialize a helper and use that as the pseudo-receiver for element accesses.  \nThis should allow merging branches of the patterns DAG, thus avoiding creating multiple enumerators.\n\nNote: async enumerables are out-of-scope for C# 10. (Confirmed in LDM 4/12/2021)\nNote: sub-patterns are disallowed in slice-patterns on enumerables for now despite some desirable uses: `e is { 1, 2, ..[var count] }` (LDM 4/12/2021)\n\n## Unresolved questions\n\n1. Should we limit the list-pattern to `IEnumerable` types? Then we could allow `{ 1, 2, ..var x }` (`x` would be an `IEnumerable` we would cook up) (answer [LDM 4/12/2021]: no, we'll disallow sub-pattern in slice pattern on enumerable for now)\n2. Should we try and optimize list-patterns like `{ 1, _, _ }` on a countable enumerable type? We could just check the first enumerated element then check `Length`/`Count`. Can we assume that `Count` agrees with enumerated count?\n3. Should we try to cut the enumeration short for length-patterns on enumerables in some cases? (computing min/max acceptable count and checking partial count against that)\n  What if the enumerable type has some sort of `TryGetNonEnumeratedCount` API?  \n4. Can we detect at runtime that the input type is sliceable, so as to avoid enumeration? .NET 6 may be adding some LINQ methods/extensions that would help. \n"
  },
  {
    "path": "proposals/inactive/pointer-null-coalescing.md",
    "content": "# Extend null-coalescing (??) and null coalescing assignment (??=) operators to pointers\n\n* [x] Proposed\n* [ ] Prototype: Not Started\n* [ ] Implementation: Not Started\n* [ ] Specification: In Progress\n\n## Summary\n[summary]: #summary\n\nThis proposal extends support of a commonly used feature in C# (?? and ??=) to unsafe code and pointer types specifcally. \n\n## Motivation\n[motivation]: #motivation\n\n\nThere is no reason for pointer types to be excluded from this feature as they semantically fit the feature's use case. Supporting this extends the feature's scope to what one would expect it to logically support. This concept is already supported in ternary expressions EG:\n\n `T *foo = bar != null ? bar : baz;`\n\nSo the same syntactic options that are offered to non-pointer types should be extended to pointer types.\n\n## Detailed design\n[design]: #detailed-design\n\nFor this addition to the language, no grammar changes are required. We are merely adding supported types to an existing operator. The current conversion rules will then determine the resulting type of the ?? expression.\nOther rules will remain the same with the exception of the relaxed type rules which will need to be modified.\n\nThe  C# spec will need to be updated to reflect this addition with the change of the line.\n> A null coalescing expression of the form `a` ?? `b` requires `a` to be of a nullable type or reference type.\n\nto\n\n> A null coalescing expression of the form `a` ?? `b` requires `a` to be of a nullable type, reference type or pointer type.\n\nas well as \n> If `A` exists and is not a nullable type or a reference type, a compile-time error occurs.\n\nto\n\n> If `A` exists and is not a nullable type, reference type or pointer type, a compile-time error occurs.\n\nCurrently the rules for `??=` do not prohibit pointer types; however, the operator was not implemented like that.\n\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nUnsafe code can be considered confusing and a vector for bugs that would not happen otherwise. Increasing the available syntactic options for pointer types could possibly lead to bugs where the developer was unaware of the semantic meaning of what was written. \n\n## Alternatives\n[alternatives]: #alternatives\n\nNo other designs have been considered as this is not a new feature, but it is rather an extension of an already implemented feature.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\nA possible question is if support should be extended to implicit dereferencing in the same vein as implicit conversions for `Nullable<T>` are supported.\n\nEG:\n\n    int* foo = null;\n    int bar = foo ?? 3;\n\n## Design meetings\n\nhttps://github.com/dotnet/csharplang/issues/418\n\n\n\n"
  },
  {
    "path": "proposals/inactive/repeated-attributes.md",
    "content": "# Repeated Attributes in Partial Members\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/8673>\n\n## Summary\n\nAllow each declaration of a partial member to independently apply an attribute not marked with `[AttributeUsage(AllowMultiple = true)]`, as long as the attribute arguments are identical in all applications.\n\n## Motivation\n\nWhen considering what attributes are present on a 'partial' method, the language unions together all the attributes in all corresponding positions on both declarations. For example, the method `M` below has attributes `A` and `B`.\n\n```cs\n[A]\npartial void M();\n\n[B]\npartial void M() { }\n```\n\nThis means that attributes which are not marked `[AttributeUsage(AllowMultiple = true)]` cannot be present across both parts:\n\n```cs\n[A]\npartial void M();\n\n[A] // error: duplicate attribute!\npartial void M() { }\n```\n\nThis presents a usability/readability issue, because some attributes are designed to inform the user and/or maintainer of the method of what pre/postconditions or invariants the method requires. For example:\n\n```cs\npublic partial bool TryGetValue([NotNullWhen(true)] out object? value);\npublic partial bool TryGetValue(out object? value) { ... }\n```\n\nA partial member typically facilitates the relationship between a code generator and an end user--each party provides one of the declarations of the partial member in order for a code generator to provide functionality to the user, or for the user to access an extension point in generated code. In the situation where only one declaration is allowed to have these single-application attributes, the generator and the user can't effectively communicate their requirements to each other. If a generator produces a defining declaration with a `NotNullWhen` attribute, for instance, the user cannot write an implementing declaration with that same attribute, even though the postcondition is applicable to the implementation, and checked by the compiler. This creates confusion for users when tracking down the root causes of warnings or when trying to understand the behaviors of a method.\n\n## Solution\n\nAllow a non-AllowMultiple attribute to be used once on each symbol (member, return, parameter, etc.) in each partial declaration, as long as the attribute arguments are identical. Since attribute arguments are all constants, the compiler can verify this. When attributes are unioned across declarations, each non-AllowMultiple attribute will be de-duplicated and only one instance of the attribute will be emitted.\n\n```cs\npublic partial bool TryGetValue([NotNullWhen(true)] out object? value);\npublic partial bool TryGetValue([NotNullWhen(true)] out object? value) { ... } // ok\n\n// equivalent to:\npublic bool TryGetValue([NotNullWhen(true)] out object value) { ... }\n\n// error when attribute arguments do not match\npublic partial bool TryGetValue([NotNullWhen(true)] out object? value);\npublic partial bool TryGetValue([NotNullWhen(false)] out object? value) { ... } // error\n```\n\n### Open questions\n\n1. Should such repetition of attributes be permitted on 'partial' type declarations or only on non-type members (e.g. methods)?\n2. Should attributes which *do* allow multiple usages on a symbol be permitted to \"opt in\" to de-duplication of equivalent usages of an attribute?\n\n### Design meetings\n#### [6th July 2020](../meetings/2020/LDM-2020-07-06.md#repeated-attributes-on-partial-members)\nThe proposal is accepted.\n  - Repetition of non-AllowMultiple attributes will be permitted across partial type declarations (open question 1).\n  - Repeated application of AllowMultiple attributes will not change in behavior, and an \"opt in\" mechanism for de-duplication may be considered in a future proposal (open question 2).\n"
  },
  {
    "path": "proposals/inference-for-constructor-calls.md",
    "content": "# Target-typed inference for constructor calls\n\n*This proposal builds on the [target-typed generic type inference](https://github.com/dotnet/csharplang/blob/main/proposals/target-typed-generic-type-inference.md) proposal.\n\n## Summary\n\nGeneric type inference is extended to 'new' expressions, which may infer type arguments for the newly created class or struct, including [from a target type](target-typed-generic-type-inference) if present. For instance, given:\n\n```csharp\npublic class MyCollection<T> : IEnumerable<T>\n{\n    public MyCollection() { ... }\n    ...\n}\n```\n\nWe would allow the constructor to be called without a type argument when it can be inferred from arguments or (in this case) a target type:\n\n```csharp\nIEnumerable<string> c = new MyCollection(); // 'T' = 'string' inferred from target type\n```\n\n## Motivation\n\nEven without [target-typed generic type inference](https://github.com/dotnet/csharplang/blob/main/proposals/target-typed-generic-type-inference.md) constructors are at a disadvantage to factory methods, because type arguments cannot be inferred on invocation. This frequently leads to trivial factory methods being declared simply for the benefit of type inference. If target-typed inference is added, this convenience gap is only going to grow.\n\nFor constructor calls we already have \"target type new\" for when a target type is exactly the type to be created, but even when that's not the case, arguments or the target type often have sufficient information between them that the type arguments for the constructed type could be inferred.\n\nThis is frequently the case for [closed hierarchies](https://github.com/dotnet/csharplang/blob/main/proposals/closed-hierarchies.md) and [unions](https://github.com/dotnet/csharplang/blob/main/proposals/nominal-type-unions.md). Most commonly, a target type will be the closed class or union type itself, whereas the constructed type will be one of the case types:\n\n```csharp\nOption<string> option = new Some<string>(\"Hello\");\n```\n\nWith this proposal, it could be written simply as\n\n```csharp\nOption<string> option = new Some(\"Hello\"); // Infer 'string' from argument and target type\n```\n\n## Detailed specification\n\nThe proposal is specified by treating the constructor \"as if\" it were a generic method, and the constructor call \"as if\" it were an invocation of that generic method.\n\nIn an *object_creation_expression* of the form `new T(E₁ ...Eₓ)` where `T` has no type argument list, if there is an accessible non-generic type `T` and it has one or more accessible and applicable constructors, then overload resolution proceeds as today.\n\nHowever, if no such type or constructors are found, then for each generic type `T<X₁...Xᵥ>` with the same type name `T`, and for each constructor of that generic type with the parameter list `(T₁ p₁ ... Tₓ pₓ)`, [generic type inference](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1263-type-inference) is attempted, as if the constructor were a generic method `M` with the same type parameter list as `T<X₁...Xᵥ>`, with the same parameter list `(T₁ p₁ ... Tₓ pₓ)` as the constructor, and with T<X₁...Xᵥ> as its return type:\n\n```csharp\nT<X₁...Xᵥ> M<X₁...Xᵥ>(T₁ p₁ ... Tₓ pₓ)\n```\n\nand as if the object creation expression were an invocation with no type arguments, and with the same argument list and target type `I` (if any) as the creation expression:\n\n```csharp\nM(E₁ ...Eₓ) // without target type\nI i = M(E₁ ...Eₓ) // with target type\n```\n\n(Where the names `i` and `M` are otherwise invisible and not in conflict with any other names in scope.)\n\nFor instance, for this type and invocation:\n\n```csharp\npublic class C<T1, T2> : IEnumerable<T1>\n{\n    public C(T2 t2) { ... }\n}\n\nIEnumerable<string> l = new C(5);\n```\n\nType inference would proceed as if with this method and invocation:\n\n```csharp\nC<T1, T2> M<T1, T2>(T2 t2);\n\nIEnumerable<string> l = M(5);\n```\n\nIf type inference succeeds, and the inferred type arguments satisfy their constraints, and the constructor is applicable when the type arguments are applied to its containing generic type, then the constructor is a candidate.\n\nOverload resolution then proceeds as normal between the resulting candidate constructors.\n"
  },
  {
    "path": "proposals/inference-for-type-patterns.md",
    "content": "# Target-typed inference for type patterns\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9630\n\n*This proposal builds on the [target-typed generic type inference](https://github.com/dotnet/csharplang/blob/main/proposals/target-typed-generic-type-inference.md) proposal.\n\n## Summary\n\nGeneric type inference is extended to type patterns, which may omit a type argument list when it can be inferred from the pattern input value. For instance, given a declaration `Option<int> intOption`, instead of:\n\n```csharp\nif (intOption is Some<int> some) ...\n```\n\nYou can simply write:\n\n```csharp\nif (intOption is Some some) ... // 'Some<int>' inferred from the type of 'intOption'\n```\n\n## Motivation\n\nType patterns can get unwieldy when the types are generic, which seems especially grating when the information to infer the type arguments is already available in context. \n\nFor [closed hierarchies](https://github.com/dotnet/csharplang/blob/main/proposals/closed-hierarchies.md) and [unions](https://github.com/dotnet/csharplang/blob/main/proposals/nominal-type-unions.md) in particular, there are already rules in place that ensure that type arguments for a case type depend functionally on those of the closed class or union. This means that those type arguments are almost *guaranteed* to be inferrable when the input value is of a closed class or union type, and the type pattern is for a case type.\n\n## Detailed specification\n\nThe proposal is specified by treating the type pattern \"as if\" it were a generic method, and the pattern application to the incoming value \"as if\" it were an invocation of that generic method with a target type of the incoming value.\n\nIn a type pattern `T ...` where `T` has no type arguments, if a non-generic `T` does not exist, or is not allowed in a pattern (e.g. it is static), or is not [pattern compatible](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/patterns.md#1122-declaration-pattern) with the input type `I`, then type inference is attempted:\n\nFor each generic type `T<X₁...Xᵥ>` with the same type name `T`, [generic type inference](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/expressions.md#1263-type-inference) is performed as if the type pattern were a generic method with the same type parameter list as `T<X₁...Xᵥ>`, with an empty parameter list, and with T<X₁...Xᵥ> as its return type:\n\n```csharp\nT<X₁...Xᵥ> M<X₁...Xᵥ>()\n```\n\nand as if the pattern application were an invocation with no type arguments, with an empty argument list and with `I` as a target type:\n\n```csharp\nI i = M()\n```\n\n(Where the names `i` and `M` are otherwise invisible and not in conflict with any other names in scope.)\n\nFor instance, in the following example:\n\n```csharp\npublic record None();\npublic record Some<T>(T value);\npublic union Option<T>(None, Some<T>);\n\nvoid M(Option<int> intOption) => intOption switch\n{\n    None => ...,\n    Some some => ..., // 'Some<int>' inferred for 'some'\n}\n```\n\nType inference proceeds as if with this method and invocation:\n\n```csharp\nSome<T> M<T>();\n\nOption<int> i = M();\n```\n\nWhich leads to `int` being inferred as the type argument corresponding to `T`.\n\nIf type inference succeeds and the inferred type arguments satisfy their constraints, then the type `T<X₁...Xᵥ>` is a candidate. If exactly one such candidate type is found, then that is the one inferred for use in the type pattern. Otherwise, inference fails and an error occurs. The type in the pattern must then be specified in full.\n"
  },
  {
    "path": "proposals/interpolated-string-handler-argument-value.md",
    "content": "# Interpolated string handler argument value\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/9046>\n\n## Summary\n[summary]: #summary\n\nIn order to solve a pain point in the creation of handler types and make them more useful in logging scenarios,\nwe add support for interpolated string handlers to receive a new piece of information,\na custom value supplied at the call site.\n\n```cs\npublic void LogDebug(\n    this ILogger logger,\n    [InterpolatedStringHandlerArgument(nameof(logger))]\n    [InterpolatedStringHandlerArgumentValue(LogLevel.Debug)]\n    LogInterpolatedStringHandler message);\n```\n\n## Motivation\n[motivation]: #motivation\n\nC# 10 introduced [interpolated string handlers][interpolated-string-spec], which were intended to allow interpolated strings to\nbe used in high-performance and logging scenarios, using more efficient building techniques and avoiding work entirely when the\nstring does not need to be realized. However, a common pain point has arisen since then; for logging APIs, you will often want to\nhave APIs such as `LogTrace`, `LogDebug`, `LogWarn`, etc, for each of your logging levels. Today, there is no way to use a single\nhandler type for all of those methods. Instead, our guidance has been to prefer a single `Log` method that takes a `LogLevel` or\nsimilar enum, and use `InterpolatedStringHandlerArgumentAttribute` to pass that value along. While this works for new APIs, the\nsimple truth is that we have many existing APIs that use the `LogTrace/Debug/Warn/etc` format instead. These APIs either must\nintroduce new handler types for each of the existing methods, which is a lot of overhead and code duplication, or let the calls\nbe inefficient.\n\nWe want to allow a custom value to be passed along to the interpolated string handler type.\nThe value would be specific to a particular method that uses interpolated string handler parameter.\nThis would then permit parameterization based on the value,\neliminating a large amount of duplication and making it viable to adopt\ninterpolation handlers for `ILogger` and similar scenarios.\n\nSome examples of this:\n* [fedavorich/ISLE][isle] uses T4 to get around the bloat, by generating handlers for every log level.\n* [This BCL proposal][ilogger-proposal] was immediately abandoned after it was realized that there would need to be a handler type\n  for every log level.\n\n## Detailed design\n[design]: #detailed-design\n\nThe compiler will recognizes the `System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentValueAttribute`:\n\n```cs\nnamespace System.Runtime.CompilerServices\n{\n    [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]\n    public sealed class InterpolatedStringHandlerArgumentValueAttribute : Attribute\n    {\n        public InterpolatedStringHandlerArgumentValueAttribute(object? value)\n        {\n            Value = value; \n        }\n\n        public object? Value { get; }\n    }\n}\n```\n\nThis attribute is used on parameters, to inform the compiler how to lower an interpolated string handler pattern used in a parameter position.\nThe attribute can be used on its own or in combination with `InterpolatedStringHandlerArgument` attribute. Arrays are disallowed as argument\nvalues for the attribute in order to preserve design space.\n\nWe make one small change to how interpolated string handlers perform [constructor resolution][constructor-resolution]. The change\nis bolded below:\n\n>2. The argument list `A` is constructed as follows:\n>    1. The first two arguments are integer constants, representing the literal length of `i`, and the number of _interpolation_ components in `i`, respectively.\n>    2. If `i` is used as an argument to some parameter `pi` in method `M1`, and parameter `pi` is attributed with `System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute`,\n>    then for every name `Argx` in the `Arguments` array of that attribute the compiler matches it to a parameter `px` that has the same name. The empty string is matched to the receiver\n>    of `M1`.\n>        * If any `Argx` is not able to be matched to a parameter of `M1`, or an `Argx` requests the receiver of `M1` and `M1` is a static method, an error is produced and no further\n>        steps are taken.\n>        * Otherwise, the type of every resolved `px` is added to the argument list, in the order specified by the `Arguments` array. Each `px` is passed with the same `ref` semantics as is specified in `M1`.\n>    3. **If `i` is used as an argument to some parameter `pi` in method `M1`, and parameter `pi` is attributed with `System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentValueAttribute`,\n>    the attribute value is added to the argument list.**\n>    4. The final argument is a `bool`, passed as an `out` parameter.\n>3. Traditional method invocation resolution is performed with method group `M` and argument list `A`. For the purposes of method invocation final validation, the context of `M` is treated\n>as a _member\\_access_ through type `T`.\n>    * If a single-best constructor `F` was found, the result of overload resolution is `F`.\n>    * If no applicable constructors were found, step 3 is retried, removing the final `bool` parameter from `A`. If this retry also finds no applicable members, an error is produced and\n>    no further steps are taken.\n>    * If no single-best method was found, the result of overload resolution is ambiguous, an error is produced, and no further steps are taken.\n\n### Example\n\n```cs\n// Original code\nvar someOperation = RunOperation();\nILogger logger = CreateLogger(LogLevel.Error, ...);\nlogger.LogWarn($\"Operation was null: {operation is null}\");\n\n// Approximate translated code:\nvar someOperation = RunOperation();\nILogger logger = CreateLogger(LogLevel.Error, ...);\nvar loggingInterpolatedStringHandler = new LoggingInterpolatedStringHandler(20, 1, logger, LogLevel.Warn, out bool continueBuilding);\nif (continueBuilding)\n{\n    loggingInterpolatedStringHandler.AppendLiteral(\"Operation was null: \");\n    loggingInterpolatedStringHandler.AppendFormatted(operation is null);\n}\nLoggingExtensions.LogWarn(logger, loggingInterpolatedStringHandler);\n\n\n// Helper libraries\nnamespace Microsoft.Extensions.Logging;\n{\n    using System.Runtime.CompilerServices;\n\n    [InterpolatedStringHandler]\n    public struct LoggingInterpolatedStringHandler\n    {\n        public LoggingInterpolatedStringHandler(int literalLength, int formattedCount, ILogger logger, LogLevel logLevel, out bool continueBuilding)\n        {\n            if (logLevel < logger.LogLevel)\n            {\n                continueBuilding = false;\n            }\n            else\n            {\n                continueBuilding = true;\n                // Set up the rest of the builder\n            }\n        }\n    }\n    public static class LoggerExtensions\n    {\n        public static void LogWarn(\n            this ILogger logger,\n            [InterpolatedStringHandlerArgument(nameof(logger))]\n            [InterpolatedStringHandlerArgumentValue(LogLevel.Warn)]\n            ref LogInterpolatedStringHandler message);\n    }\n}\n```\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nThe extra attribute and an additional compiler complexity.\n\n## Alternatives\n[alternatives]: #alternatives\n\nhttps://github.com/dotnet/csharplang/blob/main/proposals/interpolated-string-handler-method-names.md\n\n## Open questions\n[open]: #open-questions\n\nNone\n\n[interpolated-string-spec]: https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/improved-interpolated-strings.md\n[isle]: https://github.com/fedarovich/isle/blob/main/src/Isle/Isle.Extensions.Logging/LoggerExtensions.tt\n[ilogger-proposal]: https://github.com/dotnet/runtime/issues/111283\n[constructor-resolution]: https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/improved-interpolated-strings.md#constructor-resolution\n\n## Design meetings\n\n- [LDM-2025-04-07](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-04-07.md#interpolated-string-handler-argument-values)\n"
  },
  {
    "path": "proposals/iterators-in-lambdas.md",
    "content": "# Iterators in lambdas\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9467\n\n## Summary\n\nThis proposal will remove the restriction that lambda expressions cannot be iterators.\n\n## Motivation\n\nOver the years the idea of allowing lambdas to be iterators has come up several times. The proposal has generally [garnered lack luster support][iterator-meeting]. The conclusion is that it's not harmful to the language but also not a high priority.\n\nHowever, the [use of async streams][iterator-discussion-async-streams] in minimal API programs have made this proposal signifantly more relevant. `IAsyncEnumerator<T>` is now used heavily in streaming APIs, including AI related services. This means that the ability to create such APIs cannot be done with the existing style of top level statements. Developers must refactor their code out to a local method once they want to use async streaming.\n\n```cs\n\n// Desired code\napp.MapGet(\"/search\", async IAsyncEnumerable<Product>(\n    string query, VectorStoreCollection<int, Product> collection) =>\n{\n    await foreach (var result in collection.SearchAsync(query, top: 5, new() { Filter = r => r.TenantId == 8 }))\n    {\n        yield return result.Record;\n    }\n}\n\n// Actual code\napp.MapGet(\"/search\", MapForSearch);\n\nasync IAsyncEnumerable<Product> MapForSearch(string query, VectorStoreCollection<int, Product> collection)\n{\n    await foreach (var result in collection.SearchAsync(query, top: 5, new() { Filter = r => r.TenantId == 8 }))\n    {\n        yield return result.Record;\n    }\n}\n\n```\n\nThis motivation is simalar to the motivation for [lambdas to have optional parameters][lambda-optional-parameters]. The inability to have optional parameters in lambdas forced minimal API programs to unnecessarily fall back to local methods.\n\n## Detailed Design\n\nThis will allow lambdas that have a return type that is a recognized iterator type and contains a `yield` statement to be considered an iterator. Such lambdas will have all of the functionality and restrictions of method based iterators:\n\n- The `yield type` will be determined from the iterator type.\n- The iterator cannot have any `in / ref / out` parameters.\n- The iterator can be `async` or synchronous.\n- etc ...\n\nThe return type can be explicit or inferred. For example both of the following are valid iterator lambdas:\n\n```cs\nvar lambda1 = () =>\n{\n    yield return 1;\n    yield return 2;\n};\n\nFunc<IEnumerable<int>> lambda2 = () =>\n{\n    yield return 1;\n    yield return 2;\n};\n```\n\n## Miscelaneous\n\n## Open Issues\n\n### Iterator and Yield Type Inference\n\nThis proposal needs to dig into our inference rules and how it interacts with existing passes like return type inference.\n\n[iterator-meeting]: meetings\\2018\\LDM-2018-05-21.md\n[iterator-discussion-async-streams]: https://github.com/dotnet/csharplang/discussions/9393\n[lambda-optional-parameters]: https://github.com/dotnet/csharplang/issues/6051\n"
  },
  {
    "path": "proposals/labeled-break-continue.md",
    "content": "# Labeled `break` and `continue` Statements\n\n* Championed issue: https://github.com/dotnet/csharplang/issues/9875\n\n## Summary\n\nAllow `break` and `continue` statements to optionally specify a label that identifies which loop or `switch`\nstatement to target, enabling cleaner control flow in nested constructs without requiring `goto` statements,\nor other contortions like nested functions, tuple returns, etc.\n\n## Motivation\n\nWhen working with nested loops or loops containing `switch` statements, developers often need to break out\nof or continue an outer loop from within an inner context. Currently, there are two primary approaches to\nachieve this, both with significant drawbacks:\n\n### Using `goto` statements\n\n```csharp\nstring foundValue = null;\nfor (int x = 0; x < xMax; x++)\n{\n    for (int y = 0; y < yMax; y++)\n    {\n        foundValue = GetValue(x, y);\n        if (foundValue == target)\n            goto FOUND;\n    }\n}\nFOUND:\nProcessValue(foundValue);\n```\n\nWhile `goto` works, it requires placing labels after the loop construct and doesn't clearly\ncommunicate the intent to break from a specific loop. For continuing an outer loop, the\napproach becomes even more awkward:\n\n```csharp\nfor (int x = 0; x < xMax; x++)\n{\n    for (int y = 0; y < yMax; y++)\n    {\n        if (ShouldSkipRest(x, y))\n            goto CONTINUE_OUTER;\n    }\n    CONTINUE_OUTER: ;\n}\n```\n\nThis pattern is confusing because the label must be placed at the end of the loop body, just\nbefore the closing brace, so that the incrementor and condition checking happen. When both\n`break` and `continue` are needed for the same outer loop, two separate labels are required:\n\n```csharp\nfor (int x = 0; x < xMax; x++)\n{\n    for (int y = 0; y < yMax; y++)\n    {\n        if (ShouldSkipRest(x, y))\n            goto CONTINUE_OUTER;\n        \n        if (ShouldExitAll(x, y))\n            goto BREAK_OUTER;\n    }\n    CONTINUE_OUTER: ;\n}\nBREAK_OUTER:\n// Subsequent statements\n```\n\n### Using flag variables\n\n```csharp\nstring foundValue = null;\nbool shouldBreak = false;\nfor (int x = 0; x < xMax; x++)\n{\n    for (int y = 0; y < yMax; y++)\n    {\n        foundValue = GetValue(x, y);\n        if (foundValue == target)\n        {\n            shouldBreak = true;\n            break;\n        }\n    }\n    if (shouldBreak)\n        break;\n}\nProcessValue(foundValue);\n```\n\nThis approach requires additional state management, increases code verbosity, and obscures the control flow intent.\n\n### Proposed solution\n\nWith labeled `break` and `continue`, the code becomes clearer and more maintainable:\n\n```csharp\nstring foundValue = null;\nouter: for (int x = 0; x < xMax; x++)\n{\n    for (int y = 0; y < yMax; y++)\n    {\n        foundValue = GetValue(x, y);\n        if (foundValue == target)\n            break outer;\n    }\n}\nProcessValue(foundValue);\n```\n\nThe label is placed directly on the loop it identifies, and the break/continue statement explicitly names its target.\nFor continuing:\n\n```csharp\nouter: for (int x = 0; x < xMax; x++)\n{\n    for (int y = 0; y < yMax; y++)\n    {\n        if (ShouldSkipRest(x, y))\n            continue outer;\n    }\n}\n```\n\nThis naturally expresses \"continue the outer loop,\" without the confusion of label placement associated with\n`goto`. A single label can be used for both operations:\n\n```csharp\nouter: for (int x = 0; x < xMax; x++)\n{\n    for (int y = 0; y < yMax; y++)\n    {\n        if (ShouldSkipRest(x, y))\n            continue outer;\n        \n        if (ShouldExitAll(x, y))\n            break outer;\n    }\n}\n```\n\nThis feature has been requested extensively in the C# community, with discussions dating back decades and\nthe topic being reintroduced and rerequested continuously.  Similar features exist in several other modern languages:\n\n- **Java**: [Branching Statements (Oracle Tutorial)](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/branch.html)\n- **JavaScript**: [Labeled Statement (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label)\n- **Kotlin**: [Returns and Jumps](https://kotlinlang.org/docs/returns.html)\n- **Swift**: [Control Flow - Labeled Statements](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/controlflow/#Labeled-Statements)\n- **Rust**: [Loop Labels](https://doc.rust-lang.org/reference/expressions/loop-expr.html#loop-labels)\n- **Go**: [Labeled statements](https://go.dev/ref/spec#Labeled_statements)\n- **Zig**: [Labelled loops](https://zig.guide/language-basics/labelled-loops/)\n- **Dart**: [Loops](https://dart.dev/language/loops)\n\nIn all these cases, the languages operate in the saem way as in this specification.  Namely, some constructs can have a\nlabel, and it is possible to reference that label from their respective `continue` or `break` statements.  \n\n## Detailed design\n\n### Grammar changes\n\nThe grammar for `break` and `continue` statements is extended to allow an optional identifier:\n\n```diff\n break_statement\n-    : 'break' ';'\n+    : 'break' identifier? ';'\n     ;\n\n continue_statement\n-    : 'continue' ';'\n+    : 'continue' identifier? ';'\n     ;\n```\n\n### Semantic rules\n\n#### Label requirements\n\nWhen a `break` or `continue` statement includes an identifier:\n\n1. The identifier must refer to a label on a labeled statement that lexically contains the `break` or `continue` statement.\n\n2. For `break` statements, the labeled statement must be one of:\n   - An iteration statement (`for`, `foreach`, `while`, or `do` statement)\n   - A `switch` statement\n\n3. For `continue` statements, the labeled statement must be an iteration statement (`for`, `foreach`, `while`, or `do` statement).\n\n4. It is a compile-time error if the identifier does not refer to a label in scope.\n\n5. It is a compile-time error if the label refers to a statement that does not meet the requirements above.\n\n#### Updated `break` statement semantics\n\nThe existing semantics of the `break` statement are updated as follows:\n\n```diff\n A break statement exits the nearest enclosing switch statement,\n-while statement, do statement, for statement, or foreach statement.\n+while statement, do statement, for statement, or foreach statement,\n+or, if an identifier is specified, the labeled statement identified\n+by that label.\n+\n+When an identifier is specified, the labeled statement must be a\n+switch statement or iteration statement that lexically contains the\n+break statement.\n\n The target of a break statement is the end point of the nearest\n-enclosing switch statement, while statement, do statement, for statement,\n-or foreach statement.\n+enclosing construct (as determined above).\n```\n\n#### Updated `continue` statement semantics\n\nThe existing semantics of the `continue` statement are updated as follows:\n\n```diff\n A continue statement starts a new iteration of the nearest enclosing\n-while statement, do statement, for statement, or foreach statement.\n+while statement, do statement, for statement, or foreach statement,\n+or, if an identifier is specified, the labeled iteration statement\n+identified by that label.\n+\n+When an identifier is specified, the labeled statement must be an\n+iteration statement that lexically contains the continue statement.\n\n The target of a continue statement is the end point of the embedded\n-statement of the nearest enclosing while statement, do statement, for\n-statement, or foreach statement.\n+statement of the enclosing construct (as determined above).\n```\n\n### Behavior\n\nA `break` statement with a label behaves exactly as if it were an unlabeled `break` statement directly\nwithin the labeled construct. Similarly, a `continue` statement with a label behaves as if it were an\nunlabeled `continue` directly within the labeled iteration statement.\n\nFor example, these two code fragments are semantically equivalent:\n\n```csharp\n// With labeled break\nouter: for (int i = 0; i < 10; i++)\n{\n    for (int j = 0; j < 10; j++)\n    {\n        if (i * j > 20)\n            break outer;\n    }\n}\n```\n\n```csharp\n// Equivalent using goto\nfor (int i = 0; i < 10; i++)\n{\n    for (int j = 0; j < 10; j++)\n    {\n        if (i * j > 20)\n            goto END_OUTER;\n    }\n}\nEND_OUTER: ;\n```\n\nAnd for `continue`:\n\n```csharp\n// With labeled continue  \nouter: for (int i = 0; i < 10; i++)\n{\n    for (int j = 0; j < 10; j++)\n    {\n        if (ShouldSkip(i, j))\n            continue outer;\n    }\n}\n```\n\n```csharp\n// Equivalent using goto\nfor (int i = 0; i < 10; i++)\n{\n    for (int j = 0; j < 10; j++)\n    {\n        if (ShouldSkip(i, j))\n            goto CONTINUE_OUTER;\n    }\n    CONTINUE_OUTER: ;\n}\n```\n\n## Drawbacks/Alternatives\n\n### Keep using `goto` statements\n\nC# already supports `goto`, which can accomplish the same control flow. However, `goto` has several disadvantages compared to labeled break/continue:\n\n- Requires separate labels for break vs. continue scenarios (break labels go after the loop, continue labels go before the closing brace)\n- Label placement is less intuitive and differs based on whether you're breaking or continuing\n- Less explicit about intent (jumping to a location vs. breaking/continuing a specific loop)\n- Brittle and error-prone: developers must ensure no statements are accidentally placed between labels and their target constructs. For example, with `goto END_LOOP;` followed by `END_LOOP:`, it's easy to inadvertently insert a statement between them during maintenance, breaking the intended control flow. Labeled loops prevent this issue by binding the label directly to the construct.\n- Carries historical stigma that labeled break/continue avoids\n\n### Use flag variables\n\nAs shown in the motivation section, flag variables work but add significant boilerplate and obscure the control flow logic.\n\n### Use `break N` or `continue N` with numeric levels\n\n- Fragile during refactoring (adding/removing a loop level requires updating all numeric references)\n- Harder to read (must count levels to understand the target)\n- Less explicit than named labels\n- Lack of clarity (1-based? 0-based?)\n\n### Refactor into separate methods\n\nWhile this is often good practice, it's not always feasible or appropriate, and sometimes introduces unnecessary complexity for what should be simple control flow.\n\n## Related discussions and issues\n\nThis proposal consolidates and addresses the following community discussions:\n\n<details>\n\n- [Discussion #6634: C# Break nested loop](https://github.com/dotnet/csharplang/discussions/6634)\n- [Issue #869: Discussion: C# Break nested loop](https://github.com/dotnet/csharplang/issues/869)\n- [Discussion #5525: [Proposal] Labeled loops like in Java](https://github.com/dotnet/csharplang/discussions/5525)\n- [Issue #1597: [Proposal] Labeled loops like in Java](https://github.com/dotnet/csharplang/issues/1597)\n- [Discussion #5521: nested loops interruption with break X, continue X](https://github.com/dotnet/csharplang/discussions/5521)\n- [Issue #4109: [Proposal]: Syntactic sugar for breaking out of or continuing nested loops](https://github.com/dotnet/csharplang/issues/4109)\n- [Issue #3511: [Proposal] \"doublecontine\", to contine outer loop](https://github.com/dotnet/csharplang/issues/3511)\n- [Issue #2024: break and continue inhancements](https://github.com/dotnet/csharplang/issues/2024)\n- [Discussion #8434: Chained Control Flow Statements: break [, break]... [,continue]](https://github.com/dotnet/csharplang/discussions/8434)\n\n</details>\n\n## Design meetings\n\nTBD\n"
  },
  {
    "path": "proposals/left-right-join-in-query-expressions.md",
    "content": "# Introduce `left` and `right` modifiers to the `join` query expression clauses\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/8947>\n\n## Summary\n[summary]: #summary\n\nIntroduce `left` and `right` modifiers to the LINQ query expression syntax `join` clause, e.g.:\n\n```c#\nfrom student in students\nleft join department in departments on student.DepartmentID equals department.ID\nselect new { student.Name, department?.Name }\n```\n\n## Motivation\n[motivation]: #motivation\n\nLINQ has a [Join operator](https://learn.microsoft.com/dotnet/api/system.linq.enumerable.join), which, like its SQL INNER JOIN counterpart, correlates elements of two sequences based on matching keys; the C# language has a corresponding `join` clause which translates to this operator ([section 12.20.3.5 of the C# specs](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/expressions#122035-from-let-where-join-and-orderby-clauses)).\n\nIn addition to INNER JOIN, SQL also has LEFT JOIN, which returns outer elements even if there's no corresponding inner ones; LINQ and C#, in contrast, lack this operator. [The LINQ conceptual documentation shows how to combine existing operators to achieve a left join](https://learn.microsoft.com/en-us/dotnet/csharp/linq/standard-query-operators/join-operations#perform-left-outer-joins):\n\n```c#\nvar query =\n    from student in students\n    join department in departments on student.DepartmentID equals department.ID into gj\n    from subgroup in gj.DefaultIfEmpty()\n    select new\n    {\n        student.FirstName,\n        student.LastName,\n        Department = subgroup?.Name ?? string.Empty\n    };\n```\n\nOr using method syntax:\n\n```c#\nvar query = students\n    .GroupJoin(departments, student => student.DepartmentID, department => department.ID, (student, departmentList) => new { student, subgroup = departmentList })\n    .SelectMany(\n        joinedSet => joinedSet.subgroup.DefaultIfEmpty(),\n        (student, department) => new\n        {\n            student.student.FirstName,\n            student.student.LastName,\n            Department = department.Name\n        });\n```\n\nAlthough functionality sufficient for expressing a left join operation, this combining approach has the following drawbacks:\n\n- It's complicated, requiring combining multiple different LINQ operators in a specific way to form a complex construct, and is easy to accidentally get wrong. Many EF users have complained about the complexity of this construct for expressing a simple SQL LEFT JOIN.\n- It is inefficient - the combination of operators adds significant overhead compared to a single operator using an internal lookup table (or \"hash join\", as Join is implemented).\n\nIn .NET 10, new `LeftJoin()` and `RightJoin()` methods have been introduced into System.LINQ; see https://github.com/dotnet/runtime/issues/110292 for the API proposal, discussion, and performance information and benchmarks. Following are the relevant API signatures and examples:\n\n```c#\n// API signatures:\npublic static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(\n    this IEnumerable<TOuter> outer,\n    IEnumerable<TInner> inner,\n    Func<TOuter, TKey> outerKeySelector,\n    Func<TInner, TKey> innerKeySelector,\n    Func<TOuter, TInner, TResult> resultSelector);\n\npublic static IEnumerable<TResult> LeftJoin<TOuter, TInner, TKey, TResult>(\n    this IEnumerable<TOuter> outer,\n    IEnumerable<TInner> inner,\n    Func<TOuter, TKey> outerKeySelector,\n    Func<TInner, TKey> innerKeySelector,\n    Func<TOuter, TInner?, TResult> resultSelector);\n\npublic static IEnumerable<TResult> RightJoin<TOuter, TInner, TKey, TResult>(\n    this IEnumerable<TOuter> outer,\n    IEnumerable<TInner> inner,\n    Func<TOuter, TKey> outerKeySelector,\n    Func<TInner, TKey> innerKeySelector,\n    Func<TOuter?, TInner, TResult> resultSelector);\n\n// Usage examples:\n\n// Existing (inner) join operator: students are only returned if correlated departments are found\nvar query = students.Join(\n    departments,\n    student => s.DepartmentID,\n    department => department.ID,\n    (student, department) => new { student.FirstName, student.LastName, Department = department.Name });\n\n// New left (outer) join operator: all students are returned, even those without any correlated department\n// Departments without a correlated student are not returned.\nvar query = students.LeftJoin(\n    departments,\n    student => s.DepartmentID,\n    department => department.ID,\n    (student, department) => new { student.FirstName, student.LastName, Department = department?.Name });\n\n// New right (outer) join operator: all departments are returned, even those without any correlated student.\n// Students without a correlated department are not returned.\nvar query = students.RightJoin(\n    departments,\n    student => s.DepartmentID,\n    department => department.ID,\n    (student, department) => new { student?.FirstName, student?.LastName, Department = department.Name });\n```\n\nAside from allowing users to more easily express SQL LEFT/RIGHT JOIN when using a LINQ provider (such as EF Core), the new APIs also allow both easier and more efficient in-memory left/right joins, exactly in the way that inner joins are already supported.\n\nAlong with the introduction of the operators into System.Linq, the C# query expression syntax can be extended with new `left` and `right` modifiers for the `join` clauses, which would translate to these new methods, allowing for simpler and more efficient code where C# query syntax is used.\n\n## Detailed design\n[design]: #detailed-design\n\n### Grammar\n\nProposed grammar change ([§11.7.1](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/expressions.md#1117-query-expressions)):\n\n```diff\njoin_clause\n-    : 'join' type? identifier 'in' expression 'on' expression 'equals' expression\n+    : ('left' | 'right')? 'join' type? identifier 'in' expression 'on' expression 'equals' expression\n    ;\n```\n\nThe `join` clause is thus extended via new, optional `left` and `right` modifiers; the clause stays otherwise the same, with the modifiers only changing which LINQ method is translated to (see below):\n\n```c#\nfrom student in students\nleft join department in departments on student.DepartmentID equals department.ID\nselect new { student.Name, department?.Name }\n```\n\n### `join` clause specification\n\nThis proposes removing the `join` clause from the [From, let, where, join and orderby clauses (§11.7.1)](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/expressions.md#1117-query-expressions), and adding the following dedicated section for the `join` clause, including the new proposed modifiers.\n\n<details>\n<summary>Removal of `join` clause specs from [§11.7.1](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/expressions.md#1117-query-expressions)</summary>\n\nA `join` clause immediately followed by a `select` clause\n\n```csharp\nfrom «x1» in «e1»  \njoin «x2» in «e2» on «k1» equals «k2»  \nselect «v»\n```\n\n... remainder of existing join specification up through ...\n\n> the final translation of which is\n>\n> ```csharp\n> customers\n>     .GroupJoin(\n>         orders,\n>         c => c.CustomerID,\n>         o => o.CustomerID,\n>         (c, co) => new { c, co })\n>     .Select(x => new { x, n = x.co.Count() })\n>     .Where(y => y.n >= 10)\n>     .Select(y => new { y.x.c.Name, OrderCount = y.n })\n> ```\n>\n> where `x` and `y` are compiler generated identifiers that are otherwise invisible and inaccessible.\n>\n> *end example*\n\n</details>\n\nFollowing is the new proposed dedicated section for the `join` clauses. This section would be numbered as 11.17.3.6 (pushing down the existing sections), or appended at the end. Note that although the `join into` clause is moved into the new section, it is otherwise completely unaffected by this proposal; `join into` translates to `GroupJoin()`, which already performs a conceptual left join (where an outer element has no correlated inner element, it is returned with an empty inner group).\n\n#### 11.17.3.6 Join clauses\n\n##### 11.17.3.6.1 Join clause\n\n**PREVIOUS SECTION ON JOIN REMOVED ABOVE - NOT INCLUDING JOIN INTO - MOVED HERE VERBATIM**\n\nThe `left` and `right` modifiers of the `join` clause change the translation to the `LeftJoin()` and `RightJoin()` methods respectively, instead of `Join()`. Every other aspect of the translation remains the same.\n\n##### 11.17.3.6.2 Join range variable nullability\n\nA regular (inner) join introduces a range variable whose nullability follows from its source sequence. In other words, given the following code:\n\n```csharp\nfrom c in customersh\njoin o in orders on c.CustomerID equals o.CustomerID\nselect new { c.Name, o.OrderDate, o.Total }\n```\n\n... the nullability of the range variable `o` flows from `orders` (`o` is an `Order?` if `orders` is `List<Order?>`).\n\nIn contrast, since `left join` returns outer elements which don't have correlated inner elements, the inner range variable it introduces is always nullable:\n\n```csharp\nfrom c in customersh\nleft join o in orders on c.CustomerID equals o.CustomerID\nselect new { c.Name, o?.OrderDate, o?.Total }\n```\n\n... in this example, `o` is an `Order?` even if `orders` is a `List<Order>`. Note that \"nullable\" in this context means `T?` in an unconstrained generic context; in other words, if `orders` is a sequence of value types (e.g. `List<int>`), then `o` has the same type as the elements of that sequence (`int`, not `int?`).\n\n`right join` operates in a similar way, with one important difference: the already-existing, outer range variable is made nullable, rather than the inner range variable:\n\n```csharp\nfrom o in orders\nright join c in customersh on o.CustomerID equals c.CustomerID\nselect new { o?.OrderDate, o?.Total, c.Name }\n```\n\nIn other words, if `o` was non-nullable before the `right join` operation (since `orders` is a sequence of non-nullable elements), the `right join` operation makes it nullable.\n\n##### 11.17.3.6.3 Join into clause\n\n<details>\n<summary>Moved `join into` section, as-is</summary>\n\nA `join`-`into` clause immediately followed by a `select` clause\n\n```csharp\nfrom «x1» in «e1»  \njoin «x2» in «e2» on «k1» equals «k2» into «g»  \nselect «v»\n```\n\nis translated into\n\n```csharp\n( «e1» ) . GroupJoin( «e2» , «x1» => «k1» , «x2» => «k2» ,\n                     ( «x1» , «g» ) => «v» )\n```\n\nA `join into` clause followed by a query body clause\n\n```csharp\nfrom «x1» in «e1»  \njoin «x2» in «e2» on «k1» equals «k2» into *g»  \n...\n```\n\nis translated into\n\n```csharp\nfrom * in ( «e1» ) . GroupJoin(  \n   «e2» , «x1» => «k1» , «x2» => «k2» , ( «x1» , «g» ) => new { «x1» , «g» })\n...\n```\n\n> *Example*: The example\n>\n> ```csharp\n> from c in customers\n> join o in orders on c.CustomerID equals o.CustomerID into co\n> let n = co.Count()\n> where n >= 10\n> select new { c.Name, OrderCount = n }\n> ```\n>\n> is translated into\n>\n> ```csharp\n> from * in (customers).GroupJoin(\n>     orders,\n>     c => c.CustomerID,\n>     o => o.CustomerID,\n>     (c, co) => new { c, co })\n> let n = co.Count()\n> where n >= 10\n> select new { c.Name, OrderCount = n }\n> ```\n>\n> the final translation of which is\n>\n> ```csharp\n> customers\n>     .GroupJoin(\n>         orders,\n>         c => c.CustomerID,\n>         o => o.CustomerID,\n>         (c, co) => new { c, co })\n>     .Select(x => new { x, n = x.co.Count() })\n>     .Where(y => y.n >= 10)\n>     .Select(y => new { y.x.c.Name, OrderCount = y.n })\n> ```\n>\n> where `x` and `y` are compiler generated identifiers that are otherwise invisible and inaccessible.\n>\n> *end example*\n\n</details>\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nThere are no specific drawbacks to introduce `left join`/`right join` AFAICT. It's worth noting that C# query expression support for LINQ hasn't evolved in a long time - this would be the first change in quite a while. At the same time, AFAIK there hasn't been any formal deprecation/archiving of this area of the language.\n\nNote that the proposed `join` modifiers do not require any LINQ expression tree changes, as they're represented via existing MethodCallExpression's which reference the new `LeftJoin()` and `RightJoin()` methods. There is thus nothing blocking supporting them from LINQ providers (such as EF Core).\n\n## Alternatives\n[alternatives]: #alternatives\n\nIf support isn't added to C#, users can still use the `LeftJoin`/`RightJoin` methods being introduced into .NET 10, although this would force them to drop out of C# query syntax to method syntax. In order to keep using query syntax, users will more likely continue using the existing way of expressing left joins via `join into` + `DefaultIfEmpty()` ([docs](https://learn.microsoft.com/en-us/dotnet/csharp/linq/standard-query-operators/join-operations#perform-left-outer-joins)), which is both inefficient and more verbose.\n\nAlso, since first-class left/right join is being introduced into .NET and EF 10, not including support in C# would mean a partial feature that's implemented only in some parts of the stack and not in others.\n\n## Open questions\n[open]: #open-questions\n\nAs noted above, this is the first proposal for evolving C#'s support around LINQ in a long while; there are quite a few other gaps in this area: additional C# query expression clauses (distinct, aggregates, set operations...), as well as evolving expression tree support to allow for newer C# constructs ([discussion](https://github.com/dotnet/csharplang/issues/2545)). We should consider our strategy going forward in this area.\n\n"
  },
  {
    "path": "proposals/multiple-using-var-discards.md",
    "content": "# Treat multiple `using var _` as discards\r\n\r\nAlternate proposal to [anonymous-using-declarations.md](anonymous-using-declarations.md).\r\n\r\nChampion issue (anonymous using declarations): <https://github.com/dotnet/csharplang/issues/8606>\r\n\r\n## Summary\r\n\r\nAllow multiple `using var _` declarations by treating them as discards when conflicts would otherwise occur.\r\n\r\nThis follows the same conflict-detection philosophy as C# 9.0's lambda discard parameters, but applies it to using \r\ndeclarations - the one remaining context where developers are forced to create identifiers they don't want.\r\n\r\n## Motivation\r\n\r\nC# 8.0 introduced using declarations, allowing `using` to be applied directly to local variable declarations:\r\n\r\n```csharp\r\nusing var someDisposable = GetSomeDisposable();\r\n// someDisposable is disposed at the end of the enclosing scope\r\n```\r\n\r\nHowever, when acquiring multiple disposables solely for cleanup (without needing to reference them), developers hit a \r\npain point:\r\n\r\n```csharp\r\nusing var _ = GetDisposable();\r\nusing var _ = GetOtherDisposable();  // Error CS0128: A local variable named '_' is already defined\r\n```\r\n\r\nToday, the workaround is ugly numbered discards:\r\n\r\n```csharp\r\nusing var _ = GetDisposable();\r\nusing var __ = GetOtherDisposable();\r\nusing var ___ = GetYetAnotherDisposable();\r\n\r\n// or\r\n\r\nusing var _1 = GetDisposable();\r\nusing var _2 = GetOtherDisposable();\r\nusing var _3 = GetYetAnotherDisposable();\r\n```\r\n\r\nWe see these patterns extensively in real-world codebases - Roslyn itself has nearly 500 cases alone, and analysis of \r\ninternal and open-source projects shows thousands of instances. This is a genuine pain point that developers are \r\nactively working around with hacks. Rather than continuing to ignore this issue, we should provide a clean, first-class \r\nsolution.\r\n\r\nThis proposal makes the natural syntax just work:\r\n\r\n```csharp\r\nusing var _ = GetDisposable();\r\nusing var _ = GetOtherDisposable();\r\nusing var _ = GetYetAnotherDisposable();  // All three are discards\r\n```\r\n\r\n### Precedent: Lambda Discard Parameters\r\n\r\nC# 9.0 introduced a similar conflict-detection approach for lambda parameters:\r\n\r\n```csharp\r\n// C# 8.0 and earlier - ERROR\r\nAction<int, int> a = (_, _) => { };  // Error CS0100: duplicate parameter '_'\r\n\r\n// C# 9.0 and later - LEGAL (both parameters are discards)\r\nAction<int, int> a = (_, _) => { };\r\n```\r\n\r\nThis proposal applies that same philosophy to `using var _` declarations.\r\n\r\n## Detailed Design\r\n\r\n### No Syntax Changes\r\n\r\nThis proposal requires no changes to C#'s syntax or grammar. This is purely a change to semantics and binding behavior.\r\n\r\n### Core Rule and Scope\r\n\r\nWhen the compiler encounters conflicting `_` declarations that would produce CS0128 in **using var declarations** \r\n(`using var _`), it treats them as discards instead.\r\n\r\nThis transformation applies ONLY to `using var _` declarations. Regular local variable declarations (`var _` without \r\n`using`) are NOT affected - developers should use normal discard syntax (`_ = ...;`) for those cases. Lambda parameters \r\nalready have their own discard behavior from C# 9.0 and remain independent.\r\n\r\nThe detection is purely syntactic during binding:\r\n1. Detect conflicting `_` declarations within a local variable declaration space\r\n2. Check if all conflicts are `using var` declarations\r\n3. If so, treat all as discards instead of producing CS0128\r\n\r\n### Using Declarations\r\n\r\nMultiple `using var _` declarations in the same scope become discards:\r\n\r\n```csharp\r\nvoid Method()\r\n{\r\n    using var _ = GetDisposable();\r\n    using var _ = GetOtherDisposable();\r\n    using var _ = GetYetAnotherDisposable();  // All three are discards\r\n}\r\n```\r\n\r\nA single `using var _` with no conflicts remains a named variable (backward compatibility):\r\n\r\n```csharp\r\nusing var _ = GetDisposable();  // Named variable (current behavior preserved)\r\n```\r\n\r\n### Lambda and Local Function Boundaries\r\n\r\nLambda parameters already have their own discard behavior from C# 9.0, which operates independently. Lambdas and local \r\nfunctions create separate declaration spaces:\r\n\r\n```csharp\r\nvoid Method()\r\n{\r\n    using var _ = GetDisposable();\r\n    using var _ = GetOther();           // Both are discards (same scope)\r\n    \r\n    Action a = () =>\r\n    {\r\n        using var _ = GetThird();       // Named variable (separate scope)\r\n    };\r\n}\r\n```\r\n\r\n### Method and Local Function Parameters\r\n\r\nMethod and local function parameters are externally visible signatures and never participate in this transformation. A \r\nmethod or local function parameter named `_` conflicting with a `using var _` remains an error:\r\n\r\n```csharp\r\nvoid Method(int _)  // Parameter must stay named (externally visible)\r\n{\r\n    // ERROR CS0128: single using var _ doesn't get special treatment, conflicts with parameter\r\n    using var _ = GetDisposable();\r\n}\r\n```\r\n\r\n## Specification Changes\r\n\r\n### §7.3 Declarations - Declaration Spaces\r\n\r\nThe existing rule states that local variable declaration spaces may be nested, but it is an error for conflicting \r\ndeclarations to have the same name (producing CS0128). This error is detected syntactically during binding.\r\n\r\nAdd the following exception to this rule:\r\n\r\n> However, when multiple `using var` declarations would conflict solely because they all use the identifier `_`, then all \r\n> such conflicting declarations shall be treated as discards (§9.2.9.2) instead. The identifier `_` introduces no name \r\n> into any declaration space, and the value cannot be referenced.\r\n>\r\n> *Note*: This rule applies only when conflicts would occur. A single `using var _` with no conflicts retains its \r\n> meaning as a named variable for backward compatibility.\r\n\r\n### §7.3 Declarations - Method and Local Function Parameters (Optional)\r\n\r\nThis clarification may not be necessary if the above section is sufficiently clear, but can be added if desired:\r\n\r\n> Method and local function parameters are externally visible and must remain named identifiers. When a method or local \r\n> function parameter named `_` would conflict with a using declaration named `_`, the conflict remains a compile error.\r\n\r\n### §9.2.9.2 Discards\r\n\r\nUpdate the discard specification:\r\n\r\n> A discard is indicated by the identifier `_` in the following contexts:\r\n> - [existing contexts...]\r\n> - A using var declaration (`using var _`) when multiple such declarations with the same identifier would conflict in \r\n>   the same local variable declaration space (§7.3)\r\n\r\n### §13.14 The using statement\r\n\r\nAdd clarification for using declarations:\r\n\r\n> When multiple `using var _` declarations would conflict within the same local variable declaration space, the conflict \r\n> resolution rules in §7.3 apply.\r\n\r\n## Open Design Questions\r\n\r\n### Should this support explicit types (`using IDisposable _`)?\r\n\r\nThis proposal currently specifies `using var _` only. An alternative would be to also support explicitly-typed using \r\ndeclarations like `using IDisposable _`.\r\n\r\n**Arguments for `var _` only:**\r\n- Discards don't normally present their type (though they do acquire one from initialization)\r\n- `var _` is the closest analog to discard syntax in the variable declaration space\r\n- Simpler, more focused feature\r\n- Avoids questions about type compatibility when mixing `var _` and `Type _`\r\n\r\n**Arguments for supporting both `var _` and `Type _`:**\r\n- Some developers prefer explicit types and would be frustrated by being forced to use `var`\r\n- The implementation complexity is similar either way\r\n- More general solution\r\n- Example of mixing:\r\n  ```csharp\r\n  using var _ = GetDisposable();\r\n  using IDisposable _ = GetOtherDisposable();  // Would both become discards\r\n  ```\r\n\r\n**Recommendation**: Start with `var _` only. If explicit types prove to be a significant pain point, they can be added \r\nlater without breaking changes.\r\n\r\n### Should lambda parameter `_` and `using var _` unify?\r\n\r\nThis proposal keeps `using var _` discard detection separate from C# 9.0's lambda parameter discard detection. This \r\nmeans:\r\n\r\n```csharp\r\nAction a = _ =>\r\n{\r\n    using var _ = GetDisposable();  // ERROR CS0128 (parameter and using var conflict)\r\n};\r\n```\r\n\r\n**Arguments for keeping them separate:**\r\n- Simpler mental model - each feature operates independently within its own scope\r\n- Avoids complexity in the compiler's conflict detection spanning different declaration contexts\r\n- C# 9.0 lambda parameter discards already work well on their own\r\n- Clearer what's happening - conflicts are detected purely within one declaration space\r\n\r\n**Arguments for unifying:**\r\n- More consistent - both use the same philosophy of \"detect conflicts, make them all discards\"\r\n- Avoids surprising CS0128 errors when mixing lambda parameters and using declarations\r\n- More general solution that handles all `_` conflicts together\r\n- Example of unified behavior:\r\n  ```csharp\r\n  Action a = _ =>\r\n  {\r\n      using var _ = GetDisposable();  // Both parameter and using var become discards\r\n  };\r\n  \r\n  Action<int, int> b = (_, _) =>\r\n  {\r\n      using var _ = GetDisposable();  // All three become discards\r\n  };\r\n  ```\r\n\r\n**Recommendation**: Start with separate detection for simplicity. The LDM can decide if unification is desirable.\r\n\r\n## Drawbacks\r\n\r\n### Pragmatic Tradeoffs\r\n\r\nIdeally, `_` would be treated universally as a discard in all contexts. However, achieving that ideal would require \r\nbreaking changes to existing code where `_` is used as a regular identifier, and would introduce conflicts with using \r\nalias directives at the top level (`using _ = ...;`). The latter conflict is not hypothetical - we've observed `using _` \r\nin using aliases in several real codebases. Given C#'s strong commitment to compatibility, we're unlikely to get there \r\nsoon without severe breaks.\r\n\r\nThis proposal takes the proven pattern from C# 9.0 lambda discards and extends it minimally to solve the specific pain \r\npoint with using declarations. It's non-breaking, lightweight, and focused on the one scenario where developers are \r\nforced to create unwanted identifiers.\r\n\r\nImportantly, `using var _` is already in widespread use in existing codebases - developers have been working around the \r\nCS0128 limitation with numbered discards (`_1`, `_2`, etc.) for years. This proposal simply makes that existing pattern \r\nless painful and more natural.\r\n\r\n**Future Compatibility**: This proposal does not conflict with a hypothetical future where C# might treat `_` \r\nuniversally as a discard. If that day comes, this feature would simply become a subset of the broader change.\r\n\r\n### Specific Concerns\r\n\r\n1. **Context-dependent meaning**: The meaning of `using var _` changes based on whether conflicts exist. However:\r\n   - This only affects currently-illegal code (CS0128 error), so there is no breaking change\r\n   - This follows the precedent established by C# 9.0 lambda discard parameters\r\n\r\n2. **Asymmetry with regular locals**: `using var _` gets special treatment while `var _` does not. However:\r\n   - This asymmetry is justified: `using` requires a declaration; regular code doesn't (use `_ = ...;` instead)\r\n   - The pain point is specifically about being forced to create identifiers you don't want\r\n   - This keeps the feature focused and minimal\r\n\r\n## Alternatives\r\n\r\n### Alternative: Apply to all `var _` declarations\r\n\r\nExtend this to all local variable declarations, not just using declarations:\r\n\r\n```csharp\r\nvar _ = ComputeSomething();\r\nvar _ = ComputeOther();  // Would be legal\r\n```\r\n\r\nHowever, this is unnecessary. Developers can and should write:\r\n\r\n```csharp\r\n_ = ComputeSomething();\r\n_ = ComputeOther();\r\n```\r\n\r\nThe pain point only exists where syntax *requires* a declaration (using declarations and lambda parameters). Making \r\nthis change broadly would add complexity without addressing a real problem.\r\n\r\n## Additional Notes\r\n\r\n### IDE Support\r\n\r\nIDEs could provide analyzers that suggest converting numbered discards (`_1`, `_2`) in using declarations to the \r\n`using var _` pattern when multiple are present. However, no compiler diagnostics are proposed - this is purely \r\nenabling currently-illegal code to work naturally.\r\n\r\n## Related Issues\r\n\r\nThis proposal addresses [#2235](https://github.com/dotnet/csharplang/issues/2235) and champion issue \r\n[#8606](https://github.com/dotnet/csharplang/discussions/8605).\r\n"
  },
  {
    "path": "proposals/null-conditional-await.md",
    "content": "# null-conditional await\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/8631>\n\n## Summary\n[summary]: #summary\n\nSupport an expression of the form `await? e`, which awaits `e` if it is non-null, otherwise it results in `null`.\n\n## Motivation\n[motivation]: #motivation\n\nThis is a common coding pattern, and this feature would have nice synergy with the existing null-propagating and null-coalescing operators.\n\n## Detailed design\n[design]: #detailed-design\n\nWe add a new form of the *await_expression*:\n\n```antlr\nawait_expression\n    : 'await' '?' unary_expression\n    ;\n```\n\nThe null-conditional `await` operator awaits its operand only if that operand is non-null. Otherwise the result of applying the operator is null.\n\nThe type of the result is computed using the rules for the null-conditional operator [§11.7.7](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1177-null-conditional-member-access).\n\n> **NOTE:**\n> If `e` is of type `Task`, then `await? e;` would do nothing if `e` is `null`, and await `e` if it is not `null`.\n>\n> If `e` is of type `Task<K>` where `K` is a value type, then `await? e` would yield a value of type `K?`.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nAs with any language feature, we must question whether the additional complexity to the language is repaid in the additional clarity offered to the body of C# programs that would benefit from the feature.\n\n## Alternatives\n[alternatives]: #alternatives\n\nAlthough it requires some boilerplate code, uses of this operator can often be replaced by an expression something like `(e == null) ? null : await e` or a statement like `if (e != null) await e`.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n- [ ] Requires LDM review\n\n## Design meetings\n\nNone.\n"
  },
  {
    "path": "proposals/pattern-variables.md",
    "content": "# Variable declarations under disjunctive patterns\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/8622>\n\n## Summary  \n\n- Allow variable declarations under `or` and `not` patterns and across `case` labels in a `switch` section to share code.\n\t```cs\n\tif (e is C c or Wrapper { Prop: C c })\n\t    return c;\n\n\tExpr Simplify(Expr e)\n\t{\n\t  switch (e) {\n\t    case Mult(Const(1), var x):\n\t    case Mult(var x, Const(1)): \n\t    case Add(Const(0), var x):\n\t    case Add(var x, Const(0)):\n\t\treturn Simplify(x);\n\t    // ..\n\t  }\n\t}\n\t```\n\tInstead of:\n\n\t```cs\n\tif (e is C c1) \n\t    return c1;\n\tif (e is Wrapper { Prop: C c2 }) \n\t    return c2;\n\n\tExpr Simplify(Expr e)\n\t{\n\t  switch (e) {\n\t    case Mult(Const(1), var x):\n\t\treturn Simplify(x);\n\t    case Mult(var x, Const(1)): \n\t\treturn Simplify(x);\n\t    case Add(Const(0), var x):\n\t\treturn Simplify(x);\n\t    case Add(var x, Const(0)):\n\t\treturn Simplify(x);\n\t    // ..\n\t  }\n\t}\n\t```\n\n- Also relax single-declaration rules within expression boundaries as long as each variable is assigned once.\n\t```cs\n\tif (e is C c || e is Wrapper { Prop: C c }) ;\n\tif (b ? e is C c : e is Wrapper { Prop: C c }) ;\n\t```\n\t\n- Also relax single-declaration rules within conditions of an `if/else`:\n\t```cs\n\tif (e is C c) { }\n        else if (e is Wrapper { Prop: C c }) { }\n\t```\n\t\n## Detailed design\n\n### Variable redeclaration\n\n- Pattern variables are allowed to be redeclared in the following locations if not already definitely assigned:\n\t- Within case labels for the same switch section (includes `when` clauses)\n\t- Within a single expression (includes `is` expressions)\n\t- Within a single pattern (includes `switch` expression arms)\n\t- Across top-level condition expressions within a single `if` statement (includes `else if`)\n\n  These names can possibly reference either of variables based on the result of the pattern-matching at runtime.\n- Pattern variables with multiple declarations must be of the same type, excluding top-level nullability for reference types. Differences in nested nullability are subject to standard nullability conversion warnings.\n\n        if (e is C c || e is Wrapper { Prop: var c }) { /* c may be null */ }\n\n### Definite assignment\n\nFor an *is_pattern_expression* of the form `e is pattern`, the definite assignment state of *v* after *is_pattern_expression* is determined by:\n\n- The state of *v* after *is_pattern_expression* is definitely assigned, if *pattern* is irrefutable.\n- Otherwise, the state of *v* after *is_pattern_expression* is the same as the state of *v* after *pattern*.\n\nFor a *switch_section* of the form `case pattern_1 when condition_1: ... case pattern_N when condition_N:`, the definite assignment state of *v* is determined by:\n\n- The state of *v* before *condition_i* is definitely assigned, if the state of *v* after *pattern_i* is \"definitely assigned when true\".\n- The state of *v* before *switch_section_body* is definitely assigned, if the state of *v* after each *switch_section_label* is \"definitely assigned when true\".\n- Otherwise, the state of *v* is not definitely assigned.\n\n#### General definite assignment rules for pattern variables\n\nThe following rule applies to any *primary_pattern* *p* that declares a variable, namely *list_pattern*, *declaration_pattern*, *recursive_pattern*, and *var_pattern*, as well as any nested subpatterns.\n\n- The state of *v* after *p* is \"definitely assigned when true\".\n\n#### Definite assignment rules for pattern variables declared under logical patterns\n\nFor a *disjunctive_pattern* *p* of the form `left or right`, the definite assignment state of *v* is determined by:\n- The state of *v* before *right* is definitely assigned if and only if the state of *v* after *left* is \"definitely assigned when false\".\n- The state of *v* after *p* is \"definitely assigned when true\" if the state of *v* after both *left* and *right* is \"definitely assigned when true\".\n- The state of *v* after *p* is \"definitely assigned when false\" if the state of *v* after either *left* or *right* is \"definitely assigned when false\".\n\nFor a *conjunctive_pattern* *p* of the form `left and right`, the definite assignment state of *v* is determined by:\n- The state of *v* before *right* is definitely assigned if and only if the state of *v* after *left* is \"definitely assigned when true\".\n- The state of *v* after *p* is \"definitely assigned when true\" if the state of *v* after either *left* or *right* is \"definitely assigned when true\".\n- The state of *v* after *p* is \"definitely assigned when false\" if the state of *v* after both *left* and *right* is \"definitely assigned when false\".\n\nFor a *negated_pattern* *p* of the form `not pattern`, the definite assignment state of *v* after *p* is determined by:\n- If the state of *v* after *pattern* is \"definitely assigned when true\", then the state of *v* after *p* is \"definitely assigned when false\".\n- If the state of *v* after *pattern* is \"definitely assigned when false\", then the state of *v* after *p* is \"definitely assigned when true\".\n\nThese rules cover the existing top-level `is not` pattern variables. However, in any other scenario the variables could be left unassigned.\n\n## Unresolved questions\n- Would it be possible to permit different types for each variable especially within `if`/`else` chains?\n  And if so, would it be a part of this proposal or a separate feature? (discussed in LDM 2022/10/17)\n"
  },
  {
    "path": "proposals/proposal-template.md",
    "content": "# FEATURE_NAME\n\nChampion issue: <link to the champion issue>\n\n## Summary\n[summary]: #summary\n\nOne paragraph explanation of the feature.\n\n## Motivation\n[motivation]: #motivation\n\nWhy are we doing this? What use cases does it support? What is the expected outcome?\n\n## Detailed design\n[design]: #detailed-design\n\nThis 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. This section can start out light before the prototyping phase but should get into specifics and corner-cases as the feature is iteratively designed and implemented.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nWhy should we *not* do this?\n\n## Alternatives\n[alternatives]: #alternatives\n\nWhat other designs have been considered? What is the impact of not doing this?\n\n## Open questions\n[open]: #open-questions\n\nWhat parts of the design are still undecided?\n\n"
  },
  {
    "path": "proposals/readonly-parameters.md",
    "content": "# Readonly Parameters\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/8716>\n\n## Summary\n[summary]: #summary\n\nWe allow parameters to be marked with `readonly`. This disallows them from being assigned to or being passed by `ref` or `out`.\n\n## Motivation\n[motivation]: #motivation\n\nC# users have [long requested](https://github.com/dotnet/csharplang/issues/188) the ability to mark both locals and parameters as `readonly`. The design team has somewhat resisted this for two reasons:\n\n* The view that `readonly` on parameters and locals would be an attractive nuisance more than a helpful addition.\n* Indecision on what a succinct syntax for locals would be to minimize the nuisance part of the first objection.\n\nHowever, the addition of primary constructor parameters changes that calculus, at least for parameters. A significant piece of feedback from the initial preview is that users would like to be able to\nensure that primary constructor parameters are not modified. The scope of such parameters is much larger, so the danger of accidental modification is much higher. We therefore propose allowing `readonly`\nas a parameter modifier.\n\nThis proposal makes a few assumptions about `readonly` locals as part of it:\n\n* A future design would allow `readonly` as a local modifier.\n* That future design might allow a shorthand for `readonly var`, or may say that `readonly var` is not allowed, and the separate shorthand is required for a `readonly` type-inferred local. What that shorthand\n  is (`val`, `let`, `const`, or some other keyword) is beyond the scope of this proposal.\n\nThese assumptions allow us to presume that to fully spell out readonlyness for a parameter or local requires a modifier, and that modifier is `readonly`. In places where types can be inferred, we offer a\nshorthand that combines the meanings, but otherwise `readonly` is required.\n\n## Detailed design\n[design]: #detailed-design\n\n### Syntax\n\nWe modify [section 15.6.2.1](https://github.com/dotnet/csharpstandard/blob/draft-v7/standard/classes.md#15621-general) of the C# specification with the following new definition for `parameter_modifier`:\n\n```antlr\nparameter_modifier\n    : parameter_mode_modifier\n    | 'this'\n    | 'readonly'\n    ;\n```\n\nThe spec is not yet updated to include the draft C# 12 specification for [`ref readonly` parameters](https://github.com/dotnet/csharplang/blob/main/proposals/ref-readonly-parameters.md), but we will restrict\n`readonly` such that if a parameter is both `readonly` and `ref readonly`, the `readonly` must appear on the left side of the `ref readonly`, so that `readonly ref readonly` is permitted, but `ref readonly readonly`\nis not.\n\n### Semantics\n\nFor a `readonly` parameter, the compiler will issue an error when it is assigned to or taken as a mutable `lvalue`. This means that a `readonly` parameter cannot be passed by `out` or `ref`, but can be passed\nby value, `ref readonly`, or `in`.\n\n#### `partial` methods\n\nFor `partial` methods, we allow the implementing `partial` method declaration to add the `readonly` modifier to a parameter if the defining `partial` method did not. If the defining partial `method` included the\n`readonly` modifier, the implementing `partial` method must also include it.\n\n#### Signature-only locations\n\n`abstract` members, `interface` members, delegate types, and function pointer types are not permitted to specify `readonly` on their parameters\n\n#### Overriding\n\nOverriding members are not required to match the `readonly`ness of overridden member's parameters. `readonly` may be added or removed with no effect on the program.\n\n#### Lambda parameters\n\nUnresolved question\n\n### Emit\n\nThe presence of `readonly` on a parameter has no impact to the generated code. It is not possible to determine from metadata whether a parameter is `readonly` or not.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nEarlier the proposal alluded to this feature being an attractive nuisance. To spell it out more clearly, we are worried that by introducing a verbose modifier that many people would like to be the default (including ourselves!),\nit will become the new \"thing to do\" on every method definition, even in cases when it provides no real safety benefits.\n\n## Alternatives\n[alternatives]: #alternatives\n\nThe [championed issue](https://github.com/dotnet/csharplang/blob/main/proposals/ref-readonly-parameters.md) has a number of alternative designs, but most center around the axis of: should we introduce a new, shorter modifier, or\na shorthand that can apply to both locals and parameters? For example, `val int i` as a parameter definition would be what this proposal calls `readonly int i`. This shorthand is very inconsistent with standard C# behavior, so\nthis proposal takes the position that we would only want to introduce a shorthand for the `readonly` + type inference case.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n### Restrict to just primary ctor parameters\n\nThis general feature has historically been pushed back on due to the attractive nuisanceness of the feature. We could artificially restrict this to just primary constructor parameters to avoid introducing that in general.\n\n### Lambda parameters\n\nToday, when applying a modifier to a lambda parameter, the type must also be spelled out. For example, this is not permitted:\n\n```cs\ndelegate void D(ref int i);\nD d = (ref i) => {};\n```\n\nThe LDM has long thought about allowing the type here to be omitted, but has not yet done so. Should we make that change as part of this proposal? Or should we say that `readonly`, like `ref`, means that the type of the lambda\nparameter must be spelled out?\n\n### Emit consequences\n\nThis proposal states that `readonly` on parameters has no effect on the emitted code, and that it will not be possible to tell from metadata (including things that read metadata, such as reflection) that a parameter was declared as\n`readonly`. Are there use cases for reflecting this information in metadata, and if so, what should the emit strategy we use to convey this information be? And, if we do emit to metadata, should that change how overriding\ncarries through that information?\n"
  },
  {
    "path": "proposals/readonly-setter-calls-on-non-variables.md",
    "content": "# Readonly setter calls on non-variables\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/9174>\n\n## Summary\n\nPermits a readonly setter to be called on non-variable expressions, and permits object initializers to be used with value types:\n\n```cs\nvar c = new C();\n// Remove the current CS1612 error, because ArraySegment<T>.this is readonly:\nc.ArraySegmentProp[10] = new object();\n\n// Invocation expressions already omit the CS1612 error when the setter is readonly:\nc.ArraySegmentMethod()[10] = new object();\n\n// In limited cases, ref-returning indexers can be used to work around this:\nc.RefReturningIndexerWorkaround[10] = new object();\n\n_ = new C\n{\n    // Remove the current CS1918 error:\n    ArraySegmentProp = { [10] = new object() },\n    // Remove the current CS1918 error:\n    RefReturningIndexerWorkaround = { [10] = new object() },\n};\n\nclass C\n{\n    public ArraySegment<object> ArraySegmentProp { get; set; }\n    public ArraySegment<object> ArraySegmentMethod() => ArraySegmentProp;\n\n    public Span<object> RefReturningIndexerWorkaround => ArraySegmentProp.AsSpan();\n}\n\n// Partial declaration of System.ArraySegment<T> for demonstration\npublic readonly struct ArraySegment<T>\n{\n    // Implicitly readonly due to the readonly modifier on the struct\n    public T this[int index] { get => ...; set => ...; }\n}\n```\n\nCurrently, the code above gives the error CS1612 \"Cannot modify the return value of 'C.ArraySegmentProp' because it is not a variable.\" This restriction is unnecessary when the setter is readonly. The restriction is there to remind you to assign the modified struct value back to the property. But there is no supported modification to the struct value when the setter is readonly, so there is no reason to assign back to the property.\n\n```cs\n// Requested by the current CS1612 error:\nvar temp = c.ArraySegmentProp;\ntemp[10] = new object();\nc.ArraySegmentProp = temp; // But this line is purposeless; 'temp' cannot have changed.\n```\n\n## Motivation\n\nFolks who want to simulate named indexers in C# use properties that return a wrapper with an indexer on it. The wrapper that holds the indexer must be a class today, which increases GC overhead. The only reason the wrapper cannot be a struct is because of the restriction which this proposal removes:\n\n```cs\nvar c = new C();\n\n// Proposal: no error because the indexer's set accessor is readonly.\nc.SimulatedNamedIndexer[42] = new object();\n\nclass C\n{\n    public WrapperStruct SimulatedNamedIndexer => new(this);\n\n    public readonly struct WrapperStruct(C c)\n    {\n        public object this[int index]\n        {\n            // Indexer accesses private state or calls private methods in 'C'\n            get => ...;\n            set => ...;\n        }\n    }\n}\n```\n\nThis addresses recurring community requests. These requests are often around document object models, entity component systems, numerics and geometry, and other modeling scenarios, but sometimes more ordinary helpers or utilities. This is the common thread: folks would like to not have to declare a pair of accessor methods when the accessors would make logical sense together as a single property or indexer. And, they don't want a class wrapper providing the API, they want a readonly struct wrapper.\n\n```cs\n// Undesirable:\nc.SetXyz(\"key\", c.GetXyz(\"key\") + 1);\n\n// Desirable:\nc.Xyz[\"key\"]++;\n```\n\nThese use cases would no longer be blocked if CS1612 is fully updated with an understanding of readonly structs and readonly members.\n\n## Detailed design\n\nFor part 1, the CS1612 error is not produced for assignments where the setter is readonly. (If the whole struct is readonly, then the setter is also readonly.) The setter call is emitted the same way as any non-accessor readonly instance method call.\n\nFor part 2, object initializers are now permitted to be used on value types. This means that the CS1918 error will no longer be produced at all. This opens the door to assignments using readonly setters or using refs returned by getters. However, this does not open the door to assignments that would not be permitted in the desugared form. Errors such as CS1612 and CS0313 will be updated to appear within object initializers now that CS1918 is no longer blocking off the entire space.\n\n### Null-conditional assignment\n\nThe [Null-conditional assignment](https://github.com/dotnet/csharplang/blob/main/proposals/null-conditional-assignment.md) proposal enables the following syntax:\n\n```cs\na?.b = value;\na?.b.c = value;\na?[index] = value;\n```\n\nCS1612 errors will be produced for this new syntax in the same way that they are for the existing syntax below:\n\n```cs\na2.b = value;\na2.b.c = value;\na2[index] = value;\n```\n\nThus, when the setter is readonly, the assignments will be permitted in both cases, and when the setter is not readonly, the normal CS1612 error for structs will remain in both cases.\n\n### InlineArray\n\nInlineArray properties are covered by a separate error which this proposal does not affect:\n\n```cs\nvar c = new C();\n\n// ❌ CS0313 The left-hand side of an assignment must be a variable, property or indexer\nc.InlineArrayProp[42] = new object();\n\nclass C\n{\n    public InlineArray43<object> InlineArrayProp { get; set; }\n}\n\n[System.Runtime.CompilerServices.InlineArray(43)]\npublic struct InlineArray43<T> { public T Element0; }\n```\n\nIt's desirable for this error to remain, because the setter _does_ mutate the struct value.\n\n## Specification\n\nInsertions are in **bold**, deletions are in ~~strikethrough~~.\n\n### Updates permitting readonly setter calls on non-variables\n\nThe current v8 specification draft does not yet specify readonly members (<https://github.com/dotnet/csharplang/blob/main/proposals/csharp-8.0/readonly-instance-members.md>). The following updates intend to leverage the concept of a _readonly member_. A _readonly member_ is a member which either is directly marked with the `readonly` modifier or which is contained inside a _struct_type_ which is marked with the `readonly` modifier.\n\n[§12.21.2](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/expressions.md#12212-simple-assignment) _Simple assignment_ is updated:\n\n> When a property or indexer declared in a _struct_type_ is the target of an assignment, **either** the instance expression associated with the property or indexer access shall be classified as a variable, **or the set accessor of the property or indexer shall be a readonly member ([§16.2.2](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/structs.md#1622-struct-modifiers))**. If the instance expression is classified as a value **and the set accessor is not a readonly member**, a binding-time error occurs.\n\n### Updates permitting object initializers for value types\n\nThe CS1918 error is completely removed. There is no need to block value types. \"\\[T]he assignments in the nested object initializer are treated as assignments to members of the field or property.\" Such assignments must already conform to rules such as the one enforced by CS1612, including when inside an object initializer.\n\n[§12.8.16.3](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/expressions.md#128163-object-initializers) _Object initializers_ is updated:\n\n> A member initializer that specifies an object initializer after the equals sign is a ***nested object initializer***, i.e., an initialization of an embedded object. Instead of assigning a new value to the field or property, the assignments in the nested object initializer are treated as assignments to members of the field or property. ~~Nested object initializers cannot be applied to properties with a value type, or to read-only fields with a value type.~~\n\n## Downsides\n\nIf this proposal is taken, it becomes a source-breaking change to remove the `readonly` keyword from a struct or setter. Without the `readonly` keyword, the errors would then be relevant and would reappear.\n\nDue to what looks like an unintentional change in the compiler, this source-breaking change is already in effect when the setter is called on an invocation expression:\n\n```cs\n// Removing 'readonly' from S1 causes a CS1612 error.\nM().Prop = 1;\n\nS1 M() => default;\n\npublic readonly struct S1\n{\n    public int Prop { get => 0; set { } }\n}\n```\n\n```cs\n// Removing 'readonly' from S2.Prop.set causes a CS1612 error.\nM().Prop = 1;\n\nS2 M() => default;\n\npublic struct S2\n{\n    public int Prop { get => 0; readonly set { } }\n}\n```\n\n## Answered LDM questions\n\n### Should similar assignments be permitted in object initializers?\n\nThere's a separate error, CS1918 that blocks assignments through readonly setters when the assignments appear in object initializers. In addition, this error even blocks assignments to ref-returning properties and indexers, and those assignments are not blocked when they appear outside of object initializers.\n\n```cs\n// ❌ CS1918 Members of property 'C.ArraySegmentProp' of type 'ArraySegment<object>' cannot be assigned with an object\n// initializer because it is of a value type\n_ = new C { ArraySegmentProp = { [42] = new object() } };\n//          ~~~~~~~~~~~~~~~~\n\n// ❌ CS1918 Members of property 'C.StructWithRefReturningIndexer' of type 'Span<object>' cannot be assigned with an object\n// initializer because it is of a value type\n_ = new C { StructWithRefReturningIndexer = { [42] = new object() } };\n//          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nclass C\n{\n    public ArraySegment<object> ArraySegmentProp { get; set; }\n    public Span<object> StructWithRefReturningIndexer => ArraySegmentProp.AsSpan();\n}\n```\n\nSuch assignments desugar to the following form, the same form in which the CS1612 warning is being removed:\n\n```cs\nvar temp = new C();\n// Warning being removed:\n// CS1612 Cannot modify the return value of 'C.ArraySegmentProp' because it is not a variable\ntemp.ArraySegmentProp[42] = new object();\n```\n\n```cs\nvar temp = new C();\n// Permitted today\ntemp.StructWithRefReturningIndexer[42] = new object();\n```\n\nShould this check be made more granular, so that members of struct types may be assigned when they would be allowed to be assigned in the desugared form?\n\n#### Answer\n\nYes. This expansion will be included. [(LDM 2025-04-02)](https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-04-02.md#expansions)\n"
  },
  {
    "path": "proposals/rejected/README.md",
    "content": ""
  },
  {
    "path": "proposals/rejected/collection-expressions-in-foreach.md",
    "content": "# Collection Expressions in `foreach`\n\n[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]\n\nClosed in favor of [immediately enumerated collection expressions](../immediately-enumerated-collection-expressions.md).\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9739\n\n## Summary\n\n[Collection Expressions](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md)\nintroduced a terse syntax `[e1, e2, e3, etc]` to create common collection values.\nThis proposal extends their usage to `foreach` statements, where they can be used directly as the iteration\nsource without requiring an explicit target type.\n\n## Motivation\n\nIt is common and reasonable for developers to want to iterate over a known set of values. This pattern appears\nfrequently in real-world code:\n\n```csharp\n// Today, developers must write:\nforeach (var toggle in new[] { true, false })\n{\n    RunTestWithFeatureFlag(toggle);\n}\n\n// With this proposal, they can write:\nforeach (var toggle in [true, false])\n{\n    RunTestWithFeatureFlag(toggle);\n}\n```\n\nAnother common scenario is iterating through a fixed set of stages or phases:\n\n```csharp\n// Today:\nforeach (var phase in new[] { Phase.Parsing, Phase.Binding, Phase.Lowering, Phase.Emit })\n{\n    ExecuteCompilerPhase(phase);\n}\n\n// With this proposal:\nforeach (var phase in [Phase.Parsing, Phase.Binding, Phase.Lowering, Phase.Emit])\n{\n    ExecuteCompilerPhase(phase);\n}\n```\n\nRequests for this capability have been heard internally and throughout the ecosystem.  This feature\nwas originally part of the collection expressions work but was extracted to keep the initial scope\nminimal. Additionally, implementing this in the general case would require giving collection expressions\na \"natural type,\" which proved to be too large and complex a design space to tackle at that time.\n\nHowever, for `foreach` statements specifically, the problem space is much simpler. The collection is\ncreated and immediately consumed—user code cannot introspect the collection itself—giving the language\nand compiler broad flexibility in implementation without the complexities of determining a universal\nnatural type.  This flexibility follows the design principles of collection-expressions themselves, \nallowing optimal performance, with minimal syntax.\n\n## Detailed design\n\n### Syntax\n\nNo grammar changes are required. Collection expressions are already valid expressions syntactically; this\nproposal only extends where they can be used semantically.\n\n### Semantics\n\n#### Explicitly typed foreach\n\nFor an explicitly typed `foreach` statement of the form:\n\n```csharp\nforeach (T v in [e1, e2, ..s1, etc.])\n{\n    // ...\n}\n```\n\nThis is interpreted as:\n\n```csharp\nforeach (T v in (T[])[e1, e2, ..s1, etc.])\n{\n    // ...\n}\n```\n\nIn other words, the collection expression is target-typed to an array of the explicitly provided iteration type `T`.\n\n#### Implicitly typed foreach\n\nFor an implicitly typed `foreach` statement of the form:\n\n```csharp\nforeach (var v in [e1, e2, ..s1, etc.])\n{\n    // ...\n}\n```\n\nThe element type `T_e` is computed using the [best common type](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/expressions.md#116315-finding-the-best-common-type-of-a-set-of-expressions)\n\n- The types of all expression elements `e1`, `e2`, etc.\n- The [element types](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#conversions)\n  of all spread elements `..s1`, etc.\n\nThe statement is then interpreted as:\n\n```csharp\nforeach (T_e v in (T_e[])[e1, e2, ..s1, etc.])\n{\n    // ...\n}\n```\n\nIf no best common type can be determined, a compile-time error occurs.\n\nNote: this is also akin to having a method `void M<T>(T[] values);` and running type inference on `M([e1, e2, ..s1, etc.])` to see\nwhat type argument `T` is inferred to be.  That type for `T` is then the element type for the `foreach` and the rules for an \nexplicitly typed `foreach` statement (above) apply.\n\n### Implementation flexibility\n\nWhile the semantics are defined in terms of array creation, a compliant implementation is free to optimize\nthe collection expression however it deems appropriate, provided the observable behavior remains the same. For example:\n\n- Stored in the program's constant data segment when it contains only constant values.\n- Using a stack-allocated `ReadOnlySpan<T>` for the elements when the element count is known and there are no intervening `await` expressions or `yield` statements.\n- Complete elision of the collection entirely.\n\nFor example, `foreach (var i in [0, 1, 2, 3])` could be translated to:\n```csharp\nfor (var i = 0; i <= 3; i++)\n{\n    // ...\n}\n```\n\nThis follows the same implementation flexibility principle established in the base collection expressions\n[translation specification](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#collection-literal-translation).\n\n### Design decisions\n\n#### Using explicit type vs. best common type\n\nThe explicitly typed case uses the provided type `T` rather than computing best common type. This ensures the\niteration type properly informs the collection expression elements. For example:\n\n```csharp\nforeach (byte b in [1, 2, 3])  // Values treated as bytes\n{\n    // ...\n}\n```\n\nIf best common type was used in both cases, the values `1`, `2`, `3` would be typed as `int`, which would then fail to convert to `byte`.\n\n#### Empty collection expression\n\nThe empty collection expression `[]` is:\n- **Legal** in the explicitly typed case: `foreach (int i in []) { }` - the target type is known (`int[]`)\n- **Illegal** in the implicitly typed case: `foreach (var v in []) { }` - no element type can be inferred\n\nThis is not a special rule but follows naturally from the semantic translations above.\n\n#### Pointer types\n\nBecause the semantics are defined in terms of arrays, pointer types are supported:\n\n```csharp\nunsafe\n{\n    int* p = null;\n    foreach (var v in [p, p])  // Legal - creates int*[]\n    {\n        // ...\n    }\n}\n```\n\nThis would not be possible if the target type were `Span<T>` or `ReadOnlySpan<T>`, which cannot contain pointer types.\n\n## Examples\n\n### Valid usage\n\n```csharp\n// Implicitly typed with naturally typed literals\nforeach (var value in [1, 2, 3, 4, 5]) // Element type is int\n\n// Explicitly typed with strings\nforeach (string s in [\"hello\", \"world\"]) // Element type is string\n\n// With spread elements\nint[] existing = { 1, 2, 3 };\nforeach (var n in [0, ..existing, 4]) // Element type is int\n\n// Type inference with mixed elements\nIEnumerable<int> enumerable = GetNumbers();\nforeach (var n in [1, 2, ..enumerable, 3]) // Element type is int\n\n// With lambda expressions (requires explicit typing)\nforeach (Func<int, int> f in [null, i => i, i => i * i])\n\n// Empty collection with explicit type\nforeach (string s in [])\n\n// Boolean values\nforeach (var b in [true, false]) // Element type is bool\n\n// Null with reference types infers nullable\nforeach (var s in [null, \"hello\", \"world\"]) // Element type is string?\n\n// Dynamic elements\ndynamic d = GetDynamic();\nforeach (var x in [1, d, 3]) // Element type is dynamic\n\n// Await expressions (not await foreach)\nforeach (var result in [await GetValueAsync(), await GetOtherValueAsync()]) // Element type is BCT of the expressions\n\n// Anonymous types\nforeach (var item in [new { A = 1 }, new { A = 2 }]) // Element type is the anonymous type.\n\n// Mixed arrays with collection expression\nint[] arr = { 1, 2 };\nforeach (var a in [arr, [3, 4]]) // Legal.  Inner collection expression target typed to int[].  Outer to int[][]\n```\n\n### Invalid usage\n\n```csharp\n// Error: Cannot infer element type from empty collection\nforeach (var x in [])\n\n// Error: No best common type between incompatible types\nforeach (var x in [SyntaxKind.IfKeyword, \"string\"])\n\n// Error: Lambda expressions need target type\nforeach (var transform in [node => node.WithoutTrivia()])\n\n// Error: No best common type when all elements are collection expressions\nforeach (var tokens in [[SyntaxKind.Public, SyntaxKind.Private], \n                        [SyntaxKind.Static, SyntaxKind.Async]])\n\n// Error: await foreach doesn't work with collection expressions\n// (IAsyncEnumerable cannot be created from collection expression)\nawait foreach (var compilation in [comp1, comp2, comp3])\n{\n    // ...\n}\n```\n\n## Design notes\n\n### Relationship to natural types\n\nThis feature deliberately avoids giving collection expressions a general \"natural type.\" While there is\nclear user demand for expressions like `var x = [1, 2, 3]`, determining what type `x` should be (array, `List<T>`,\n`ImmutableArray<T>`, etc.) involves complex trade-offs around mutability, performance, and API design.\n\nThe `foreach` scenario sidesteps these issues because:\n1. The collection is immediately consumed and cannot be stored or passed elsewhere\n2. The compiler can choose the most efficient representation for each specific case\n3. User code cannot depend on the specific collection type chosen\n\nThis allows us to provide value to users now while leaving the door open for a future \"natural types\" feature.\n\n### Optimization opportunities\n\nImplementations are encouraged to aggressively optimize these patterns. Since the collection's lifetime is limited\nto the `foreach` statement itself, compilers can:\n\n- Use stack allocation for small, known-size collections\n- Embed constant data directly in the assembly\n- Transform simple patterns into equivalent `for` loops\n- Use specialized enumeration patterns that avoid allocations\n\nThe only requirement is that the iteration order and values match what would be produced by creating and iterating an array.\nThese optimizations are best-effort, consistent with the approach taken in the base collection expressions specification.\n\n### Special cases\n\n#### Nullability\n\nWhen `null` literals appear in a collection expression with reference types, the best common type computation will produce a\nnullable reference type. For example, `[null, \"hello\"]` has an element type of `string?`.\n\n#### Dynamic\n\nWhen any element in the collection expression is of type `dynamic`, the computed element type becomes `dynamic`. This\nfollows the standard best common type rules where `dynamic` acts as a \"top type\" for type inference purposes.\n\n#### Nested collection expressions\n\nCollection expressions cannot be nested when using implicit typing if all elements are collection expressions, as collection\nexpressions have no natural type. However, mixing arrays or other collections with collection expressions works:\n`[existingArray, [1, 2, 3]]` is valid because `existingArray` provides a concrete type for best common type computation.\n\n#### Async considerations\n\nThis feature does not support `await foreach` with collection expressions, as `IAsyncEnumerable<T>` cannot be created\nfrom a collection expression. However, `await` expressions can appear as elements:\n`foreach (var x in [await GetValueAsync(), await GetOtherAsync()])` is valid and the awaits are evaluated before iteration begins.\n\n## Open questions\n\nNone at this time.\n\n## Design meetings\n\n[TBD: Links to relevant LDM notes]\n"
  },
  {
    "path": "proposals/rejected/declaration-expressions.md",
    "content": "# Declaration expressions\n\nDiscussion: https://github.com/dotnet/csharplang/discussions/8935\n\nSupport declaration assignments as expressions.\n\n## Motivation\n[motivation]: #motivation\n\nAllow initialization at the point of declaration in more cases, simplifying code, and allowing `var` to be used.\n\n```csharp\nSpecialType ReferenceType =>\n    (var st = _type.SpecialType).IsValueType() ? SpecialType.None : st;\n```\n\nAllow declarations for `ref` arguments, similar to `out var`.\n\n```csharp\nConvert(source, destination, ref List<Diagnostic> diagnostics = null);\n```\n\n## Detailed design\n[design]: #detailed-design\n\nExpressions are extended to include declaration assignment. Precedence is the same as assignment.\n\n```antlr\nexpression\n    : non_assignment_expression\n    | assignment\n    | declaration_assignment_expression // new\n    ;\ndeclaration_assignment_expression // new\n    : declaration_expression '=' local_variable_initializer\n    ;\ndeclaration_expression // C# 7.0\n    | type variable_designation\n    ;\n```\n\nThe declaration assignment is of a single local.\n\nThe type of a declaration assignment expression is the type of the declaration.\nIf the type is `var`, the inferred type is the type of the initializing expression. \n\nThe declaration assignment expression may be an l-value, for `ref` argument values in particular.\n\nIf the declaration assignment expression declares a value type, and the expression is an r-value, the value of\nthe expression is a copy.\n\nThe declaration assignment expression may declare a `ref` local.\nThere is an ambiguity when `ref` is used for a declaration expression in a `ref` argument.\nThe local variable initializer determines whether the declaration is a `ref` local.\n\n```csharp\nF(ref int x = IntFunc());    // int x;\nF(ref int y = RefIntFunc()); // ref int y;\n```\n\nThe scope of locals declared in declaration assignment expressions is the same the scope of corresponding declaration expressions from C#7.0.\n\nIt is a compile time error to refer to a local in text preceding the declaration expression.\n\n## Alternatives\n[alternatives]: #alternatives\nNo change. This feature is just syntactic shorthand after all.\n\nMore general sequence expressions: see [#377](https://github.com/dotnet/csharplang/issues/377).\n\nTo allow use of `var` in more cases, allow separate declaration and assignment of `var` locals,\nand infer the type from assignments from all code paths.\n\n## See also\n[see-also]: #see-also\nSee Basic Declaration Expression in [#595](https://github.com/dotnet/csharplang/issues/595).\n\nSee Deconstruction Declaration in the [deconstruction](https://github.com/dotnet/roslyn/blob/master/docs/features/deconstruction.md) feature.\n"
  },
  {
    "path": "proposals/rejected/discriminated-unions.md",
    "content": "# Discriminated unions / `enum class`\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/8928>\n\n`enum class`es are a new kind of type declaration, sometimes referred to as discriminated unions,\nwhere each every possible instance the type is listed, and each instance is non-overlapping.\n\nAn `enum class` is defined using the following syntax:\n\n```antlr\nenum_class\n    : 'partial'? 'enum class' identifier type_parameter_list? type_parameter_constraints_clause* \n      '{' enum_class_body '}'\n    ;\n\nenum_class_body\n    : enum_class_cases?\n    | enum_class_cases ','\n    ;\n\nenum_class_cases\n    : enum_class_case\n    | enum_class_case ',' enum_class_cases\n    ;\n\nenum_class_case\n    : enum_class\n    | class_declaration\n    | identifier type_parameter_list? '(' formal_parameter_list? ')'\n    | identifier\n    ;\n\n```\n\nSample syntax:\n\n```C#\nenum class Shape\n{\n    Rectangle(float Width, float Length),\n    Circle(float Radius),\n}\n```\n\n## Semantics\n\nAn `enum class` definition defines a root type, which is an abstract class of the same name as\nthe `enum class` declaration, and a set of members, each of which has a type which is a subtype\nof the root type. If there are multiple `partial enum class` definitions, all members will be\nconsidered members of the enum class definition. Unlike a user-defined abstract class definition,\nthe `enum class` root type is partial by default and defined to have a default *private*\nparameter-less constructor.\n\nNote that, since the root type is defined to be a partial abstract class, partial definitions of\nthe *root type* may also be added, where standard syntax forms for a class body are allowed.\nHowever, no types may directly inherit from the root type in any declaration, aside from those\nspecified as `enum class` members. In addition, no user-defined constructors are permitted for\nthe root type.\n\nThere are four kinds of `enum class` member declarations:\n\n* simple class members\n\n* complex class members\n\n* `enum class` members\n\n* value members.\n\n### Simple class members\n\nA simple class member declaration defines a new nested \"record\" class (intentionally left undefined in\nthis document) with the same name. The nested class inherits from the root type.\n\nGiven the sample code above,\n\n```C#\nenum class Shape\n{\n    Rectangle(float Width, float Length),\n    Circle(float Radius)\n}\n```\n\nthe `enum class` declaration has semantics equivalent to the following declaration\n\n```C#\n abstract partial class Shape\n{\n    public record Rectangle(float Width, float Length) : Shape;\n    public record Circle(float Radius) : Shape;\n}\n```\n\n### Complex class members\n\nYou can also nest an entire class declaration below an `enum class` declaration. It will be treated as\na nested class of the root type. The syntax allows any class declaration, but it is required for the\ncomplex class member to inherit from the direct containing `enum class` declaration. \n\n### `enum class` members\n\n`enum classes` can be nested under each other, e.g.\n\n```C#\nenum class Expr\n{\n    enum class Binary\n    {\n        Addition(Expr left, Expr right),\n        Multiplication(Expr left, Expr right)\n    }\n}\n```\n\nThis is almost identical to the semantics of a top-level `enum class`, except that\nthe nested enum class defines a nested root type, and everything below the nested enum\nclass is a subtype of the nested root type, instead of the top-level root type.\n\n```C#\nabstract partial class Expr\n{\n    abstract partial class Binary : Expr\n    {\n        public record Addition(Expr left, Expr right) : Binary;\n        public record Multiplication(Expr left, Expr right) : Binary;\n    }\n}\n```\n\n### Value members\n\n`enum classes` can also contain value members. Value members define public get-only static\nproperties on the root type that also return the root type, e.g.\n\n```C#\nenum class Color\n{\n    Red,\n    Green\n}\n```\n\nhas properties equivalent to\n\n```C#\npartial abstract class Color\n{\n    public static Color Red => ...;\n    public static Color Green => ...;\n}\n```\n\nThe complete semantics are considered an implementation detail, but it is guaranteed that\none unique instance will be returned for each property, and the same instance will be returned\non repeated invocations.\n\n\n### Switch expression and patterns\n\nThere are some proposed adjustments to pattern matching and the switch expression to handle\n`enum classes`. Switch expressions can already match types through the variable pattern, but\nfor currently for reference types, no set of switch arms in the switch expression are considered\ncomplete, except for matching against the static type of the argument, or a subtype.\n\nSwitch expressions would be changed such that, if the root type of an `enum class` is the static\ntype of the argument to the switch expression, and there is a set of patterns matching all\nmembers of the enum, then the switch will be considered exhaustive.\n\nSince value members are not constants and do not define new static types, they currently cannot\nbe matched by pattern. To make this possible, a new pattern using the constant pattern syntax\nwill be added to allow match against `enum class` value members. The match is defined to succeed\nif and only if the argument to the pattern match and the value returned by the `enum class` value\nmember would be reference equal, although the implementation is not required to perform this\ncheck.\n\n\n## Open questions\n\n- [ ] What does the common type algorithm say about `enum class` members? Is this valid code?\n    * `var x = b ? new Shape.Rectangle(...) : new Shape.Circle(...)`\n\n- [ ] Adding a new pattern just for value members seems heavy handed. Is there a more general version\n      construction that makes sense?\n    - [ ] Value members also do not map well to a parallel nested class construction because of this\n\n- [ ] Is switching against an argument with an `enum class` static type guaranteed to be constant-time?\n\n- [ ] Should there be a way to make `enum class`es not be considered complete in the switch\n      expression? Prefix with `virtual`?\n\n- [ ] What modifiers should be permitted on `enum class`?\n"
  },
  {
    "path": "proposals/rejected/fixed-sized-buffers.md",
    "content": "# Fixed Sized Buffers\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/1314>\n\n## Summary\n[summary]: #summary\n\nProvide a general-purpose and safe mechanism for declaring fixed sized buffers to the C# language.\n\n## Motivation\n[motivation]: #motivation\n\nToday, users have the ability to create fixed-sized buffers in an unsafe-context. However, this requires the user to deal with pointers, manually perform bounds checks, and only supports a limited set of types (`bool`, `byte`, `char`, `short`, `int`, `long`, `sbyte`, `ushort`, `uint`, `ulong`, `float`, and `double`).\n\nThe most common complaint is that fixed-size buffers cannot be indexed in safe code. Inability to use more types is the second.\n\nWith a few minor tweaks, we could provide general-purpose fixed-sized buffers which support any type, can be used in a safe context, and have automatic bounds checking performed.\n\n## Detailed design\n[design]: #detailed-design\n\nOne would declare a safe fixed-sized buffer via the following:\n\n```csharp\npublic fixed DXGI_RGB GammaCurve[1025];\n```\n\nThe declaration would get translated into an internal representation by the compiler that is similar to the following\n\n```csharp\n[FixedBuffer(typeof(DXGI_RGB), 1024)]\npublic ConsoleApp1.<Buffer>e__FixedBuffer_1024<DXGI_RGB> GammaCurve;\n\n// Pack = 0 is the default packing and should result in indexable layout.\n[CompilerGenerated, UnsafeValueType, StructLayout(LayoutKind.Sequential, Pack = 0)]\nstruct <Buffer>e__FixedBuffer_1024<T>\n{\n    private T _e0;\n    private T _e1;\n    // _e2 ... _e1023\n    private T _e1024;\n\n    public ref T this[int index] => ref (uint)index <= 1024u ?\n                                         ref RefAdd<T>(ref _e0, index):\n                                         throw new IndexOutOfRange();\n}\n```\n\nSince such fixed-sized buffers no longer require use of `fixed`, it makes sense to allow any element type.  \n\n> NOTE: `fixed` will still be supported, but only if the element type is `blittable`\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\n* There could be some challenges with backwards compatibility, but given that the existing fixed-sized buffers only work with a selection of primitive types, it should be possible for the compiler to continue \"just-working\" if the user treats the fixed-buffer as a pointer.\n* Incompatible constructs may need to use slightly different `v2` encoding to hide the fields from old compiler.\n* Packing is not well defined in IL spec for generic types. While the approach should work, we will be bordering on undocumented behavior. We should make that documented and make sure other JITs like Mono have the same behavior.\n* Specifying a separate type for every length (an possibly another for `readonly` fields, if supported) will have impact on metadata. It will be bound by the number of arrays of different sizes in the given app.\n* `ref` math is not formally verifiable (since it is unsafe). We will need to find a way to update verification rules to know that our use is ok.\n\n## Alternatives\n[alternatives]: #alternatives\n\nManually declare your structures and use unsafe code to construct indexers.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n- should we allow `readonly`?  (with readonly indexer)\n- should we allow array initializers?\n- is `fixed` keyword necessary?\n- `foreach`?\n- only instance fields in structs?\n\n## Design meetings\n\nLink to design notes that affect this proposal, and describe in one sentence for each what changes they led to.\n"
  },
  {
    "path": "proposals/rejected/format.md",
    "content": "# Efficient Params and String Formatting\n\n## Summary\nThis combination of features will increase the efficiency of formatting `string` values and passing of `params` style\narguments.\n\n## Motivation\nThe allocation overhead of formatting `string` values can dominate the performance of many text based applications: \nfrom the boxing penalty of `struct` types, the `object[]` allocation for `params` and the intermediate `string` \nallocations during `string.Format` calls. In order to maintain efficiency such applications often need to abandon\nproductivity features such as `params` and `string` interpolation and move to non-standard, hand coded solutions. \n\nConsider MSBuild as an example. This is written using a lot of modern C# features by developers who are conscious of \nperformance. Yet in one representative build sample MSBuild will generate 262MB of `string` allocation\nusing minimal verbosity. Of that 1/2 of the allocations are short lived allocations inside `string.Format`. These \nfeatures would remove much of that on .NET Desktop and get it down to nearly zero on .NET Core due to the availability of `Span<T>`\n\nThe set of language features described here will enable applications to continue using these features, with very\nlittle or no churn to their application code base, while removing the unintended allocation overhead in the majority of \ncases.\n\n## Detailed Design \nThere are a set of features that will be used here to achieve these results:\n\n- Expanding `params` to support a broader set of collection types.\n- Allowing for developers to customize how `string` interpolation is achieved. \n- Allowing for interpolated `string` to bind to more efficient `string.Format` overloads.\n\n### Extending params\nThe language will allow for `params` in a method signature to have the types `Span<T>`, `ReadOnlySpan<T>` and \n`IEnumerable<T>`. The same rules for invocation will apply to these new types that apply to `params T[]`:\n\n- Can't overload where the only difference is a `params` keyword.\n- Can invoke by passing a series of arguments that are implicitly convertible to `T` or a single `Span<T>` / \n`ReadOnlySpan<T>` / `IEnumerable<T>` argument.\n- Must be the last parameter in a method signature.\n- Etc ... \n\nThe `Span<T>` and `ReadOnlySpan<T>` variants will be referred to as `Span<T>` below for simplicity. In cases where the \nbehavior of `ReadOnlySpan<T>` differs it will be explicitly called out. \n\nThe advantage the `Span<T>` variants of `params` provides is it gives the compiler great flexibility in how it allocates\nthe backing storage for the `Span<T>` value. With a `params T[]` the compiler must allocate a new `T[]` for every \ninvocation of a `params` method. Re-use is not possible because it must assume the callee stored and reused the \nparameter. This can lead to a large inefficiency in methods with lots of `params` invocations.\n\nGiven `Span<T>` variants are `ref struct` the callee cannot store the argument. Hence the compiler can optimize the \ncall sites by taking actions like re-using the argument. This can make repeated invocations very efficient as compared\nto `T[]`. The language though will make no specific guarantees about how such callsites are optimized. Only note that \nthe compiler is free to use values other than `T[]` when invoking a `params Span<T>` method. \n\nOne such potential implementation is the following. Consider all `params` invocation in a method body. The compiler \ncould allocate an array which has a size equal to the largest `params` invocation and use that for all of the \ninvocations by creating appropriately sized `Span<T>` instances over the array. For example:\n\n```csharp\nstatic class OneAllocation {\n    static void Use(params Span<string> spans) {\n        ...\n    }\n\n    static void Go() {\n        Use(\"jaredpar\");\n        Use(\"hello\", \"world\");\n        Use(\"a\", \"longer\", \"set\");\n    }\n}\n```\n\nThe compiler could choose to emit the body of `Go` as follows:\n\n```csharp\n    static void Go() {\n        var args = new string[3];\n        args[0] = \"jaredpar\";\n        Use(new Span<string>(args, start: 0, length: 1));\n\n        args[0] = \"hello\";\n        args[1] = \"world\";\n        Use(new Span<string>(args, start: 0, length: 2));\n\n        args[0] = \"a\";\n        args[1] = \"longer\";\n        args[2] = \"set\";\n        Use(new Span<string>(args, start: 0, length: 3));\n   }\n```\n\nThis can significantly reduce the number of arrays allocated in an application. Allocations can be even further \nreduced if the runtime provides utilities for smarter stack allocation of arrays.\n\nThis optimization cannot always be applied though. Even though the callee cannot capture the `params` argument it can \nstill be captured in the caller when there is a `ref` or a `out / ref` parameter that is itself a `ref struct`\ntype. \n\n```csharp\nstatic class SneakyCapture {\n    static ref int M(params Span<T> span) => ref span[0];\n\n    static void Oops() {\n        // This now holds onto the memory backing the Span<T> \n        ref int r = ref M(42);\n    }\n}\n```\n\nThese cases are statically detectable though. It potentially occurs whenever there is a `ref` return or a `ref struct`\nparameter passed by `out` or `ref`. In such a case the compiler must allocate a fresh `T[]` for every invocation. \n\nSeveral other potential optimization strategies are discussed at the end of this document.\n\nThe `IEnumerable<T>` variant is a merely a convenience overload. It's useful in scenarios which have frequent uses of\n`IEnumerable<T>` but also have lots of `params` usage. When invoked in `T` argument form the backing storage will \nbe allocated as a `T[]` just as `params T[]` is done today.\n\n### params overload resolution changes\nThis proposal means the language now has four variants of `params` where before it had one. It is sensible for methods\nto define overloads of methods that differ only on the type of a `params` declarations. \n\nConsider that `StringBuilder.AppendFormat` would certainly add a `params ReadOnlySpan<object>` overload in addition to\nthe `params object[]`. This would allow it to substantially improve performance by reducing collection allocations \nwithout requiring any changes to the calling code. \n\nTo facilitate this the language will introduce the following overload resolution tie breaking rule. When the candidate\nmethods differ only by the `params` parameter then the candidates will be preferred in the following order:\n\n1. `ReadOnlySpan<T>`\n1. `Span<T>`\n1. `T[]`\n1. `IEnumerable<T>`\n\nThis order is the most to the least efficient for the general case.\n\n### Variant\nCoreFX is prototyping a new managed type named [Variant](https://github.com/dotnet/corefxlab/pull/2595). This type \nis meant to be used in APIs which expect heterogeneous values but don't want the overhead brought on by using `object`\nas the parameter. The `Variant` type provides universal storage but avoids the boxing allocation for the most commonly\nused types. Using this type in APIs like `string.Format` can eliminate the boxing overhead in the majority of cases.\n\nThis type itself is not necessarily special to the language. It is being introduced in this document separately though\nas it becomes an implementation detail of other parts of the proposal. \n\n### Efficient interpolated strings\nInterpolated strings are a popular yet inefficient feature in C#. The most common syntax, using an interpolated `string`\nas a `string`, translates into a `string.Format(string, params object[])` call. That will incur boxing allocations for \nall value types, intermediate `string` allocations as the implementation largely uses `object.ToString` for formatting\nas well as array allocations once the number of arguments exceeds the amount of parameters on the \"fast\" overloads of \n`string.Format`. \n\nThe language will change its interpolation lowering to consider alternate overloads of `string.Format`. It will\nconsider all forms of `string.Format(string, params)` and pick the \"best\" overload which satisfies the argument types.\nThe \"best\" `params` overload will be determined by the rules discussed above. This means interpolated `string` can now\nbind to very efficient overloads like `string.Format(string format, params ReadOnlySpan<Variant> args)`. In many cases\nthis will remove all intermediate allocations.\n\n### Customizable interpolated strings\nDevelopers are able to customize the behavior of interpolated strings with `FormattableString`. This contains the data\nwhich goes into an interpolated string: the format `string` and the arguments as an array. This though still has the \nboxing and argument array allocation as well as the allocation for `FormattableString` (it's an `abstract class`). Hence\nit's of little use to applications which are allocation heavy in `string` formatting.\n\nTo make interpolated string formatting efficient the language will recognize a new type: \n`System.ValueFormattableString`. All interpolated strings will have a target type conversion to this type. This will \nbe implemented by translating the interpolated string into the call `ValueFormattableString.Create` exactly as is done\nfor `FormattableString.Create` today. The language will support all `params` options described in this document when\nlooking for the most suitable `ValueFormattableString.Create` method. \n\n```csharp\nreadonly struct ValueFormattableString {\n    public static ValueFormattableString Create(Variant v) { ... } \n    public static ValueFormattableString Create(string s) { ... } \n    public static ValueFormattableString Create(string s, params ReadOnlySpan<Variant> collection) { ... } \n}\n\nclass ConsoleEx { \n    static void Write(ValueFormattableString f) { ... }\n}\n\nclass Program { \n    static void Main() { \n        ConsoleEx.Write(42);\n        ConsoleEx.Write($\"hello {DateTime.UtcNow}\");\n\n        // Translates into \n        ConsoleEx.Write(ValueFormattableString.Create((Variant)42));\n        ConsoleEx.Write(ValueFormattableString.Create(\n            \"hello {0}\", \n            new Variant(DateTime.UtcNow)));\n    }\n}\n```\n\nOverload resolution rules will be changed to prefer `ValueFormattableString` over `string` when the argument is an \ninterpolated string. This means it will be valuable to have overloads which differ only on `string` and \n`ValueFormattableString`. Such an overload today with `FormattableString` is not valuable as the compiler will always\nprefer the `string` version (unless the developer uses an explicit cast). \n\n## Open Issues\n\n### ValueFormattableString breaking change\nThe change to prefer `ValueFormattableString` during overload resolution over `string` is a breaking change. It is\npossible for a developer to have defined a type called `ValueFormattableString` today and use it in method overloads\nwith `string`. This proposed change would cause the compiler to pick a different overload once this set of features\nwas implemented. \n\nThe possibility of this seems reasonably low. The type would need the full name `System.ValueFormattableString` and it \nwould need to have `static` methods named `Create`. Given that developers are strongly discouraged from defining any\ntype in the `System` namespace this break seems like a reasonable compromise.\n\n### Expanding to more types\nGiven we're in the area we should consider adding `IList<T>`, `ICollection<T>` and `IReadOnlyList<T>` to the set of\ncollections for which `params` is supported. In terms of implementation it will cost a small amount over the other\nwork here.\n\nLDM needs to decide if the complication to the language is worth it though. The addition of `IEnumerable<T>` removes \na very specific friction point. Lacking this `params` solution many customers were forced to allocate `T[]` from an \n`IEnumerable<T>` when calling a `params` method. The addition of `IEnumerable<T>` fixes this though. There is no\nspecific friction point that the other interfaces fix here. \n\n## Considerations\n\n### Variant2 and Variant3\nThe CoreFX team also has a non-allocating set of storage types for up to three `Variant` arguments. These are a single\n`Variant`, `Variant2` and `Variant3`. All have a pair of methods for getting an allocation free `Span<Variant>` off of \nthem: `CreateSpan` and `KeepAlive`. This means for a `params Span<Variant>` of up to three arguments the call site \ncan be entirely allocation free.\n\n```csharp\nstatic class ZeroAllocation {\n    static void Use(params Span<Variant> spans) {\n        ...\n    }\n\n    static void Go() {\n        Use(\"hello\", \"world\");\n    }\n}\n```\n\nThe `Go` method can be lowered to the following:\n\n```csharp\nstatic class ZeroAllocation {\n    static void Go() {\n        Variant2 _v;\n        _v.Variant1 = new Variant(\"hello\");\n        _v.Variant2 = new Variant(\"word\");\n        Use(_v.CreateSpan());\n        _v.KeepAlive();\n    }\n}\n```\n\nThis requires very little work on top of the proposal to re-use `T[]` between `params Span<T>` calls. The compiler\nalready needs to manage a temporary per call and do clean up work after (even if in one case it's just marking \nan internal temp as free). \n\nNote: the `KeepAlive` function is only necessary on desktop. On .NET Core the method will not be available and hence\nthe compiler won't emit a call to it.\n\n### CLR stack allocation helpers\nThe CLR only provides only \n[localloc](https://learn.microsoft.com/dotnet/api/system.reflection.emit.opcodes.localloc)\n for stack allocation of contiguous memory. This instruction is limited in that it only works for `unmanaged` types. \n This means it can't be used as a universal solution for efficiently allocating the backing storage for `params \n Span<T>`. \n\nThis limitation is not some fundamental restriction though but instead more an artifact of history. The CLR could choose\nto add new op codes / intrinsics which provide universal stack allocation. These could then be used to allocate the\nbacking storage for most `params Span<T>` calls.\n\n```csharp\nstatic class BetterAllocation {\n    static void Use(params Span<string> spans) {\n        ...\n    }\n\n    static void Go() {\n        Use(\"hello\", \"world\");\n    }\n}\n```\n\nThe `Go` method can be lowered to the following:\n\n```csharp\nstatic class ZeroAllocation {\n    static void Go() {\n        Span<T> span = RuntimeIntrinsic.StackAlloc<string>(length: 2);\n        span[0] = \"hello\";\n        span[1] = \"world\";\n        Use(span);\n    }\n}\n```\n\nWhile this approach is very heap efficient it does cause extra stack usage. In an algorithm which has a deep stack and\nlots of `params` usage it's possible this could cause a `StackOverflowException` to be generated where a simple `T[]`\nallocation would succeed. \n\nUnfortunately C# is not set up for the type of inter-method analysis where it could make an educated determination of\nwhether or not call should use stack or heap allocation of `params`. It can only really consider each call on its \nown.\n\nThe CLR is best setup for making this type of determination at runtime. Hence we'd likely have the runtime provide two\nmethods for universal stack allocation:\n\n1. `Span<T> StackAlloc<T>(int length)`: this has the same behaviors and limitations of `localloc` except it can work on\nany type `T`. \n1. `Span<T> MaybeStackAlloc<T>(int length)`: this runtime can choose to implement this by doing a stack or heap\nallocation. The runtime can then use the execution context in which it's called to determine how the `Span<T>` is \nallocated. The caller though will always treat it as if it were stack allocated.\n\nFor very simple cases, like one to two arguments, the C# compiler could always use `StackAlloc<T>` variant. This is \nunlikely to significantly contribute to stack exhaustion in most cases. For other cases the compiler could choose to \nuse `MaybeStackAlloc<T>` instead and let the runtime make the call.\n\nHow we choose will likely require a deeper investigation and examination of real world apps. But if these new intrinsics\nare available then it will give us this type of flexibility.\n\n### Why not varargs? \nThe existing [varargs](https://docs.microsoft.com/cpp/windows/variable-argument-lists-dot-dot-dot-cpp-cli)\nfeature was considered here as a possible solution. This feature though is meant primarily for C++/CLI scenarios and\nhas known holes for other scenarios. Additionally there is significant cost in porting this to Unix. Hence it wasn't\nseen as a viable solution.\n\n## Related Issues\nThis spec is related to the following issues: \n\n- https://github.com/dotnet/csharplang/issues/1757\n- https://github.com/dotnet/csharplang/issues/179\n- https://github.com/dotnet/corefxlab/pull/2595\n"
  },
  {
    "path": "proposals/rejected/interpolated-string-handler-method-names.md",
    "content": "# Interpolated string handler method names\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/9046>\n\n## Summary\n[summary]: #summary\n\nWe add support for interpolated string handlers to receive a new piece of information, the name of the method they are an argument\nto, in order to solve a pain point in the creation of handler types and make them more useful in logging scenarios.\n\n```cs\npublic void LogDebug(\n    this ILogger logger,\n    [InterpolatedStringHandlerArgument(nameof(logger), \"Method Name\")] LogInterpolatedStringHandler message);\n```\n\n## Motivation\n[motivation]: #motivation\n\nC# 10 introduced [interpolated string handlers][interpolated-string-spec], which were intended to allow interpolated strings to\nbe used in high-performance and logging scenarios, using more efficient building techniques and avoiding work entirely when the\nstring does not need to be realized. However, a common pain point has arisen since then; for logging APIs, you will often want to\nhave APIs such as `LogTrace`, `LogDebug`, `LogWarn`, etc, for each of your logging levels. Today, there is no way to use a single\nhandler type for all of those methods. Instead, our guidance has been to prefer a single `Log` method that takes a `LogLevel` or\nsimilar enum, and use `InterpolatedStringHandlerArgumentAttribute` to pass that value along. While this works for new APIs, the\nsimple truth is that we have many existing APIs that use the `LogTrace/Debug/Warn/etc` format instead. These APIs either must\nintroduce new handler types for each of the existing methods, which is a lot of overhead and code duplication, or let the calls\nbe inefficient. We want to introduce a small addition to the possible values in `InterpolatedStringHandlerArgumentAttribute` to\nallow the name of the method being called to be passed along to the interpolated string handler type; this would then permit\nparameterization based on the method name, eliminating a large amount of duplication and making it viable for the BCL to adopt\ninterpolation handlers for `ILogger`. Some examples of this:\n\n* [fedavorich/ISLE][isle] uses T4 to get around the bloat, by generating handlers for every log level.\n* [This BCL proposal][ilogger-proposal] was immediately abandoned after it was realized that there would need to be a handler type\n  for every log level.\n\n## Detailed design\n[design]: #detailed-design\n\nWe make one small change to how interpolated string handlers perform [constructor resolution][constructor-resolution]. The change\nis bolded below:\n\n> ...\n> 2. The argument list `A` is constructed as follows:\n>   1. ...\n>   2. If `i` is used as an argument to some parameter `pi` in method `M1`, and parameter `pi` is attributed with `System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute`,\n>   then for every name `Argx` in the `Arguments` array of that attribute the compiler matches it to a parameter `px` that has the same name. The empty string is matched to the receiver\n>   of `M1`. **The string `\"Method Name\"` is matched to the name of `M1`.**\n>       * If any `Argx` is not able to be matched to a parameter or the name of `M1`, or an `Argx` requests the receiver of `M1` and `M1` is a static method, an error is produced and no further\n>       steps are taken.\n>       * Otherwise, the type of every resolved `px` is added to the argument list, in the order specified by the `Arguments` array. Each `px` is passed with the same `ref` semantics as is specified in `M1`. **If `\"Method Name\"` was present in the `Arguments` array, then a type of `string` is added to the argument list in that position.**\n\n### Example\n\n```cs\n// Original code\nvar someOperation = RunOperation();\nILogger logger = CreateLogger(LogLevel.Error, ...);\nlogger.LogWarn($\"Operation was null: {operation is null}\");\n\n// Approximate translated code:\nvar someOperation = RunOperation();\nILogger logger = CreateLogger(LogLevel.Error, ...);\nvar loggingInterpolatedStringHandler = new LoggingInterpolatedStringHandler(20, 1, \"LogWarn\", logger, out bool continueBuilding);\nif (continueBuilding)\n{\n    loggingInterpolatedStringHandler.AppendLiteral(\"Operation was null: \");\n    loggingInterpolatedStringHandler.AppendFormatted(operation is null);\n}\nLoggingExtensions.LogWarn(logger, loggingInterpolatedStringHandler);\n\n\n// Helper libraries\nnamespace Microsoft.Extensions.Logging;\n{\n    using System.Runtime.CompilerServices;\n\n    [InterpolatedStringHandler]\n    public struct LoggingInterpolatedStringHandler\n    {\n        public LoggingInterpolatedStringHandler(int literalLength, int formattedCount, string methodName, ILogger logger, out bool continueBuilding)\n        {\n            var methodLogLevel = methodName switch\n            {\n                \"LogDebug\" => LogLevel.Debug,\n                \"LogInfo\" => LogLevel.Information,\n                \"LogWarn\" => LogLevel.Warn,\n                \"LogError\" => LogLevel.Error,\n                _ => throw new ArgumentOutOfRangeException(methodName),\n            };\n\n            if (methodLogLevel < logger.LogLevel)\n            {\n                continueBuilding = false;\n            }\n            else\n            {\n                continueBuilding = true;\n                // Set up the rest of the builder\n            }\n        }\n    }\n    public static class LoggerExtensions\n    {\n        public static void LogWarn(this ILogger logger, [InterpolatedStringHandlerArgument(\"Method Name\", nameof(logger))] ref LogInterpolatedStringHandler message);\n    }\n}\n```\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nArguably, the magic empty string that we do is already a bit of magic; we risk further complicating the feature by adding in\nmore magic strings that users need to know.\n\n## Alternatives\n[alternatives]: #alternatives\n\nWe could design a more complicated system that allows for passing of arbitrary constants to the interpolated string handler\nconstructor; for example, it could be considered a bit of a hack that we use the name of the logging method, instead of a proper\n`LogLevel` enum that the logging system likely already has. However, this would be a far more complicated language feature, would\nneed more BCL changes, and we don't know of any scenarios that actually need anything more than a string representing the method\nname. Given this, we've opted for the simpler approach of just passing the method name.\n\n## Open questions\n[open]: #open-questions\n\nNone\n\n[interpolated-string-spec]: https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/improved-interpolated-strings.md\n[isle]: https://github.com/fedarovich/isle/blob/main/src/Isle/Isle.Extensions.Logging/LoggerExtensions.tt\n[ilogger-proposal]: https://github.com/dotnet/runtime/issues/111283\n[constructor-resolution]: https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/improved-interpolated-strings.md#constructor-resolution\n"
  },
  {
    "path": "proposals/rejected/intptr-operators.md",
    "content": "# Operators should be exposed for `System.IntPtr` and `System.UIntPtr`\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/48>\n\n## Summary\n[summary]: #summary\n\nThe CLR supports a set of operators for the `System.IntPtr` and `System.UIntPtr` types (`native int`). These operators can be seen in `III.1.5` of the Common Language Infrastructure specification (`ECMA-335`). However, these operators are not supported by C#.\n\nLanguage support should be provided for the full set of operators supported by `System.IntPtr` and `System.UIntPtr`. These operators are: `Add`, `Divide`, `Multiply`, `Remainder`, `Subtract`, `Negate`, `Equals`, `Compare`, `And`, `Not`, `Or`, `XOr`, `ShiftLeft`, `ShiftRight`.\n\n## Motivation\n[motivation]: #motivation\n\nToday, users can easily write C# applications targeting multiple platforms using various tools and frameworks, such as: `Xamarin`, `.NET Core`, `Mono`, etc...\n\nWhen writing cross-platform code, it is often necessary to write interop code that interacts with a particular target platform in a specific manner. This could include writing graphics code, calling some System API, or interacting with an existing native library.\n\nThis interop code often has to deal with handles, unmanaged memory, or even just platform-specific sized integers.\n\nThe runtime provides support for this by defining a set of operators that can be used on the `native int` (`System.IntPtr`) and `native unsigned int` (`System.UIntPtr`) primitive types.\n\nC# has never supported these operators and so users have to work around the issue. This often increases code complexity and lowers code maintainability.\n\nAs such, the language should begin to support these operators to help advance the language to better support these requirements.\n\n## Detailed design\n[design]: #detailed-design\n\nThe full set of operators supported are defined in `III.1.5` of the Common Language Infrastructure specification (`ECMA-335`). The specification is available here: [https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-335.pdf](https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-335.pdf).\n\n* A summary of the operators is provided below for convenience.\n* The unverifiable operators defined by the CLI spec are not listed and are not currently part of this proposal (although it may be worth considering these as well).\n* Providing a keyword (such as `nint` and `nuint`) nor providing a way to for literals to be declared for `System.IntPtr` and `System.UIntPtr` (such as 0n) is not part of this proposal (although it may be worth considering these as well).\n\n### Unary Plus Operator\n\n```csharp\nSystem.IntPtr operator +(System.IntPtr)\n```\n\n```csharp\nSystem.UIntPtr operator +(System.UIntPtr)\n```\n\n### Unary Minus Operator\n\n```csharp\nSystem.IntPtr operator -(System.IntPtr)\n```\n\n### Bitwise Complement Operator\n\n```csharp\nSystem.IntPtr operator ~(System.IntPtr)\n```\n\n```csharp\nSystem.UIntPtr operator ~(System.UIntPtr)\n```\n\n### Cast Operators\n\n```csharp\nexplicit operator sbyte(System.IntPtr)               // Truncate\nexplicit operator short(System.IntPtr)               // Truncate\nexplicit operator int(System.IntPtr)                 // Truncate\nexplicit operator long(System.IntPtr)                // Sign Extend\n\nexplicit operator byte(System.IntPtr)                // Truncate\nexplicit operator ushort(System.IntPtr)              // Truncate\nexplicit operator uint(System.IntPtr)                // Truncate\nexplicit operator ulong(System.IntPtr)               // Zero Extend\n\nexplicit operator System.IntPtr(int)                 // Sign Extend\nexplicit operator System.IntPtr(long)                // Truncate\n\nexplicit operator System.IntPtr(uint)                // Sign Extend\nexplicit operator System.IntPtr(ulong)               // Truncate\n\nexplicit operator System.IntPtr(System.IntPtr)\nexplicit operator System.IntPtr(System.UIntPtr)\n```\n\n```csharp\nexplicit operator sbyte(System.UIntPtr)               // Truncate\nexplicit operator short(System.UIntPtr)               // Truncate\nexplicit operator int(System.UIntPtr)                 // Truncate\nexplicit operator long(System.UIntPtr)                // Sign Extend\n\nexplicit operator byte(System.UIntPtr)                // Truncate\nexplicit operator ushort(System.UIntPtr)              // Truncate\nexplicit operator uint(System.UIntPtr)                // Truncate\nexplicit operator ulong(System.UIntPtr)               // Zero Extend\n\nexplicit operator System.UIntPtr(int)                 // Zero Extend\nexplicit operator System.UIntPtr(long)                // Truncate\n\nexplicit operator System.UIntPtr(uint)                // Zero Extend\nexplicit operator System.UIntPtr(ulong)               // Truncate\n\nexplicit operator System.UIntPtr(System.IntPtr)\nexplicit operator System.UIntPtr(System.UIntPtr)\n```\n\n### Multiplication Operator\n\n```csharp\nSystem.IntPtr operator *(int, System.IntPtr)\nSystem.IntPtr operator *(System.IntPtr, int)\nSystem.IntPtr operator *(System.IntPtr, System.IntPtr)\n```\n\n```csharp\nSystem.UIntPtr operator *(uint, System.UIntPtr)\nSystem.UIntPtr operator *(System.UIntPtr, uint)\nSystem.UIntPtr operator *(System.UIntPtr, System.UIntPtr)\n```\n\n### Division Operator\n\n```csharp\nSystem.IntPtr operator /(int, System.IntPtr)\nSystem.IntPtr operator /(System.IntPtr, int)\nSystem.IntPtr operator /(System.IntPtr, System.IntPtr)\n```\n\n```csharp\nSystem.UIntPtr operator /(uint, System.UIntPtr)\nSystem.UIntPtr operator /(System.UIntPtr, uint)\nSystem.UIntPtr operator /(System.UIntPtr, System.UIntPtr)\n```\n\n### Remainder Operator\n\n```csharp\nSystem.IntPtr operator %(int, System.IntPtr)\nSystem.IntPtr operator %(System.IntPtr, int)\nSystem.IntPtr operator %(System.IntPtr, System.IntPtr)\n```\n\n```csharp\nSystem.UIntPtr operator %(uint, System.UIntPtr)\nSystem.UIntPtr operator %(System.UIntPtr, uint)\nSystem.UIntPtr operator %(System.UIntPtr, System.UIntPtr)\n```\n\n### Addition Operator\n\n```csharp\nSystem.IntPtr operator +(int, System.IntPtr)\nSystem.IntPtr operator +(System.IntPtr, int)\nSystem.IntPtr operator +(System.IntPtr, System.IntPtr)\n```\n\n```csharp\nSystem.UIntPtr operator +(uint, System.UIntPtr)\nSystem.UIntPtr operator +(System.UIntPtr, uint)\nSystem.UIntPtr operator +(System.UIntPtr, System.UIntPtr)\n```\n\n### Subtraction Operator\n\n```csharp\nSystem.IntPtr operator -(int, System.IntPtr)\nSystem.IntPtr operator -(System.IntPtr, int)\nSystem.IntPtr operator -(System.IntPtr, System.IntPtr)\n```\n\n```csharp\nSystem.UIntPtr operator -(uint, System.UIntPtr)\nSystem.UIntPtr operator -(System.UIntPtr, uint)\nSystem.UIntPtr operator -(System.UIntPtr, System.UIntPtr)\n```\n\n### Shift Operators\n\n```csharp\nSystem.IntPtr operator <<(System.IntPtr, int)\nSystem.IntPtr operator >>(System.IntPtr, int)\n```\n\n```csharp\nSystem.UIntPtr operator <<(System.UIntPtr, int)\nSystem.UIntPtr operator >>(System.UIntPtr, int)\n```\n\n### Integer Comparison Operators\n\n```csharp\nbool operator ==(int, System.IntPtr)\nbool operator ==(System.IntPtr, int)\nbool operator ==(System.IntPtr, System.IntPtr)\n\nbool operator !=(int, System.IntPtr)\nbool operator !=(System.IntPtr, int)\nbool operator !=(System.IntPtr, System.IntPtr)\n\nbool operator  <(int, System.IntPtr)\nbool operator  <(System.IntPtr, int)\nbool operator  <(System.IntPtr, System.IntPtr)\n\nbool operator  >(int, System.IntPtr)\nbool operator  >(System.IntPtr, int)\nbool operator  >(System.IntPtr, System.IntPtr)\n\nbool operator <=(int, System.IntPtr)\nbool operator <=(System.IntPtr, int)\nbool operator <=(System.IntPtr, System.IntPtr)\n\nbool operator >=(int, System.IntPtr)\nbool operator >=(System.IntPtr, int)\nbool operator >=(System.IntPtr, System.IntPtr)\n```\n\n```csharp\nbool operator ==(uint, System.UIntPtr)\nbool operator ==(System.UIntPtr, uint)\nbool operator ==(System.UIntPtr, System.UIntPtr)\n\nbool operator !=(uint, System.UIntPtr)\nbool operator !=(System.UIntPtr, uint)\nbool operator !=(System.UIntPtr, System.UIntPtr)\n\nbool operator  <(uint, System.UIntPtr)\nbool operator  <(System.UIntPtr, uint)\nbool operator  <(System.UIntPtr, System.UIntPtr)\n\nbool operator  >(uint, System.UIntPtr)\nbool operator  >(System.UIntPtr, uint)\nbool operator  >(System.UIntPtr, System.UIntPtr)\n\nbool operator <=(uint, System.UIntPtr)\nbool operator <=(System.UIntPtr, uint)\nbool operator <=(System.UIntPtr, System.UIntPtr)\n\nbool operator >=(uint, System.UIntPtr)\nbool operator >=(System.UIntPtr, uint)\nbool operator >=(System.UIntPtr, System.UIntPtr)\n```\n\n### Integer Logical Operators\n\n```csharp\nSystem.IntPtr operator &(int, System.IntPtr)\nSystem.IntPtr operator &(System.IntPtr, int)\nSystem.IntPtr operator &(System.IntPtr, System.IntPtr)\n\nSystem.IntPtr operator |(int, System.IntPtr)\nSystem.IntPtr operator |(System.IntPtr, int)\nSystem.IntPtr operator |(System.IntPtr, System.IntPtr)\n\nSystem.IntPtr operator ^(int, System.IntPtr)\nSystem.IntPtr operator ^(System.IntPtr, int)\nSystem.IntPtr operator ^(System.IntPtr, System.IntPtr)\n```\n\n```csharp\nSystem.UIntPtr operator &(uint, System.UIntPtr)\nSystem.UIntPtr operator &(System.UIntPtr, uint)\nSystem.UIntPtr operator &(System.UIntPtr, System.UIntPtr)\n\nSystem.UIntPtr operator |(uint, System.UIntPtr)\nSystem.UIntPtr operator |(System.UIntPtr, uint)\nSystem.UIntPtr operator |(System.UIntPtr, System.UIntPtr)\n\nSystem.UIntPtr operator ^(uint, System.UIntPtr)\nSystem.UIntPtr operator ^(System.UIntPtr, uint)\nSystem.UIntPtr operator ^(System.UIntPtr, System.UIntPtr)\n```\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nThe actual use of these operators may be small and limited to end-users who are writing lower level libraries or interop code. Most end-users would likely be consuming these lower level libraries themselves which would have the native sized integers, handles, and interop code abstracted away. As such, they would not have need of the operators themselves.\n\n## Alternatives\n[alternatives]: #alternatives\n\nHave the framework implement the required operators by writing them directly in IL. Additionally, the runtime could provide intrinsic support for the operators defined by the framework, so as to better optimize the end performance.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\nWhat parts of the design are still TBD?\n\n## Design meetings\n\nLink to design notes that affect this proposal, and describe in one sentence for each what changes they led to.\n"
  },
  {
    "path": "proposals/rejected/intrinsics.md",
    "content": "# Compiler Intrinsics\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/191>\n\n## Summary\n\nThis proposal provides language constructs that expose low level IL opcodes that cannot currently\nbe accessed efficiently, or at all: `ldftn`, `ldvirtftn`, `ldtoken` and `calli`. These low level \nopcodes can be important in high performance code and developers need an efficient way to access \nthem.\n\n## Motivation\n\nThe motivations and background for this feature are described in the following issue (as is a \npotential implementation of the feature): \n\nhttps://github.com/dotnet/csharplang/issues/191\n\nThis alternate design proposal comes after reviewing a prototype implementation of the original\nproposal by @msjabby as well as the use throughout a significant code base. This design was done \nwith significant input from @mjsabby, @tmat and @jkotas.\n\n## Detailed Design \n\n### Allow address of to target methods\n\nMethod groups will now be allowed as arguments to an address-of expression. The type of such an \nexpression will be `void*`. \n\n``` csharp\nclass Util { \n    public static void Log() { } \n}\n\n// ldftn Util.Log\nvoid* ptr = &Util.Log; \n```\n\nGiven there is no delegate conversion here the only mechanism for filtering members in the method\ngroup is by static / instance access. If that cannot distinguish the members then a compile time\nerror will occur.\n\n``` csharp\nclass Util { \n    public void Log() { } \n    public void Log(string p1) { } \n    public static void Log(int i) { };\n}\n\nunsafe {\n    // Error: Method group Log has more than one applicable candidate.\n    void* ptr1 = &Log; \n\n    // Okay: only one static member to consider here.\n    void* ptr2 = &Util.Log;\n}\n```\n\nThe addressof expression in this context will be implemented in the following manner:\n\n- ldftn: when the method is non-virtual.\n- ldvirtftn: when the method is virtual.\n\nRestrictions of this feature:\n\n- Instance methods can only be specified when using an invocation expression on a value\n- Local functions cannot be used in `&`. The implementation details of these methods are\ndeliberately not specified by the language. This includes whether they are static vs. instance or\nexactly what signature they are emitted with.\n\n### handleof\n\nThe `handleof` contextual keyword will translate a field, member or type into their equivalent \n`RuntimeHandle` type using the `ldtoken` instruction. The exact type of the expression will \ndepend on the kind of the name in `handleof`:\n\n- field: `RuntimeFieldHandle`\n- type: `RuntimeTypeHandle`\n- method: `RuntimeMethodHandle`\n\nThe arguments to `handleof` are identical to `nameof`. It must be a simple name, qualified name, \nmember access, base access with a specified member, or this access with a specified member. The \nargument expression identifies a code definition, but it is never evaluated.\n\nThe `handleof` expression is evaluated at runtime and has a return type of `RuntimeHandle`. This \ncan be executed in safe code as well as unsafe. \n\n``` \nRuntimeHandle stringHandle = handleof(string);\n```\n\nRestrictions of this feature:\n\n- Properties cannot be used in a `handleof` expression.\n- The `handleof` expression cannot be used when there is an existing `handleof` name in scope. For \nexample a type, namespace, etc ...\n\n### calli\n\nThe compiler will add support for a new type of `extern` function that efficiently translates into\na `.calli` instruction. The extern attribute will be marked with an attribute of the following\nshape:\n\n``` csharp\n[AttributeUsage(AttributeTargets.Method)]\npublic sealed class CallIndirectAttribute : Attribute\n{\n    public CallingConvention CallingConvention { get; }\n    public CallIndirectAttribute(CallingConvention callingConvention)\n    {\n        CallingConvention = callingConvention;\n    }\n}\n```\n\nThis allows developers to define methods in the following form:\n\n``` csharp\n[CallIndirect(CallingConvention.Cdecl)]\nstatic extern int MapValue(string s, void *ptr);\n\nunsafe {\n    var i = MapValue(\"42\", &int.Parse);\n    Console.WriteLine(i);\n}\n```\n\nRestrictions on the method which has the `CallIndirect` attribute applied:\n\n- Cannot have a `DllImport` attribute.\n- Cannot be generic.\n\n## Open Issues\n\n### CallingConvention\n\nThe `CallIndirectAttribute` as designed uses the `CallingConvention` enum which lacks an entry for\nmanaged calling conventions. The enum either needs to be extended to include this calling convention\nor the attribute needs to take a different approach.\n\n## Considerations\n\n### Disambiguating method groups\n\nThere was some discussion around features that would make it easier to disambiguate method groups\npassed to an address-of expression. For instance potentially adding signature elements to the \nsyntax:\n\n``` csharp\nclass Util {\n    public static void Log() { ... }\n    public static void Log(string) { ... }\n}\n\nunsafe {\n    // Error: ambiguous Log\n    void *ptr1 = &Util.Log;\n\n    // Use Util.Log();\n    void *ptr2 = &Util.Log();\n}\n```\n\nThis was rejected because a compelling case could not be made nor could a simple syntax be \nenvisioned here. Also there is a fairly straight forward work around: simple define another \nmethod that is unambiguous and uses C# code to call into the desired function. \n\n``` csharp\nclass Workaround {\n    public static void LocalLog() => Util.Log();\n}\nunsafe { \n    void* ptr = &Workaround.LocalLog;\n}\n```\n\nThis becomes even simpler if `static` local functions enter the language. Then the work around\ncould be defined in the same function that used the ambiguous address-of operation:\n\n``` csharp\nunsafe { \n    static void LocalLog() => Util.Log();\n    void* ptr = &Workaround.LocalLog;\n}\n```\n\n### LoadTypeTokenInt32\n\nThe original proposal allowed for metadata tokens to be loaded as `int` values at compile time. \nEssentially have `tokenof` that has the same arguments as `handleof` but is evaluated at \ncompile time to an `int` constant. \n\nThis was rejected as it causes significant problem for IL rewrites (of which .NET has many). Such \nrewriters often manipulate the metadata tables in a way that could invalidate these values. There \nis no reasonable way for such rewriters to update these values when they are stored as simple \n`int` values.\n\nThe underlying idea of having an opaque handle for metadata entries will continue to be explored \nby the runtime team. \n\n## Future Considerations\n\n### static local functions\n\nThis refers to [the proposal](https://github.com/dotnet/csharplang/issues/1565) to allow the \n`static` modifier on local functions. Such a function would be guaranteed to be emitted as \n`static` and with the exact signature specified in source code. Such a function should be a valid\nargument to `&` as it contains none of the problems local functions have today.\n\n### NativeCallableAttribute\n\nThe CLR has a feature that allows for managed methods to be emitted in such a way that they are \ndirectly callable from native code. This is done by adding the `NativeCallableAttribute` to \nmethods. Such a method is only callable from native code and hence must contain only blittable \ntypes in the signature. Calling from managed code results in a runtime error. \n\nThis feature would pattern well with this proposal as it would allow:\n\n- Passing a function defined in managed code to native code as a function pointer (via address-of)\nwith no overhead in managed or native code. \n- Runtime can introduce use site errors for such functions in managed code to prevent them from\nbeing invoked at compile time.\n\n\n\n\n"
  },
  {
    "path": "proposals/rejected/nullable-enhanced-common-type.md",
    "content": "# Nullable-Enhanced Common Type\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/33>\n\n## Summary\n[summary]: #summary\n\nThere is a situation in which the current common-type algorithm results are counter-intuitive, and results in the programmer adding what feels like a redundant cast to the code. With this change, an expression such as `condition ? 1 : null` would result in a value of type `int?`, and an expression such as `condition ? x : 1.0` where `x` is of type `int?` would result in a value of type `double?`.\n\n## Motivation\n[motivation]: #motivation\n\nThis is a common cause of what feels to the programmer like needless boilerplate code.\n\n## Detailed design\n[design]: #detailed-design\n\nWe modify the specification for finding the best common type of a set of expressions [§11.6.3.15](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#116315-finding-the-best-common-type-of-a-set-of-expressions) to affect the following situations:\n\n- If one expression is of a non-nullable value type `T` and the other is a null literal, the result is of type `T?`.\n- If one expression is of a nullable value type `T?` and the other is of a value type `U`, and there is an implicit conversion from `T` to `U`, then the result is of type `U?`.\n\nThis is expected to affect the following aspects of the language:\n\n- the ternary expression [§11.15](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1115-conditional-operator)\n- implicitly typed array creation expression [§11.7.15.5](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#117155-array-creation-expressions)\n- inferring the return type of a lambda [§11.6.3.13](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#116313-inferred-return-type) for type inference\n- cases involving generics, such as invoking `M<T>(T a, T b)` as `M(1, null)`.\n\nMore precisely, we change the following sections of the specification (insertions in bold, deletions in strikethrough):\n\n> #### Output type inferences\n> \n> An *output type inference* is made *from* an expression `E` *to* a type `T` in the following way:\n> \n> *  If `E` is an anonymous function with inferred return type  `U` ([§11.6.3.13](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#116313-inferred-return-type)) and `T` is a delegate type or expression tree type with return type `Tb`, then a *lower-bound inference* ([§11.6.3.10](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#116310-lower-bound-inferences)) is made *from* `U` *to* `Tb`.\n> *  Otherwise, if `E` is a method group and `T` is a delegate type or expression tree type with parameter types `T1...Tk` and return type `Tb`, and overload resolution of `E` with the types `T1...Tk` yields a single method with return type `U`, then a *lower-bound inference* is made *from* `U` *to* `Tb`.\n> *  **Otherwise, if `E` is an expression with nullable value type `U?`, then a *lower-bound inference* is made *from* `U` *to* `T` and a *null bound* is added to `T`. **\n> *  Otherwise, if `E` is an expression with type `U`, then a *lower-bound inference* is made *from* `U` *to* `T`.\n> *  **Otherwise, if `E` is a constant expression with value `null`, then a *null bound* is added to `T`** \n> *  Otherwise, no inferences are made.\n\n> #### Fixing\n> \n> An *unfixed* type variable `Xi` with a set of bounds is *fixed* as follows:\n> \n> *  The set of *candidate types* `Uj` starts out as the set of all types in the set of bounds for `Xi`.\n> *  We then examine each bound for `Xi` in turn: For each exact bound `U` of `Xi` all types `Uj` which are not identical to `U` are removed from the candidate set. For each lower bound `U` of `Xi` all types `Uj` to which there is *not* an implicit conversion from `U` are removed from the candidate set. For each upper bound `U` of `Xi` all types `Uj` from which there is *not* an implicit conversion to `U` are removed from the candidate set.\n> *  If among the remaining candidate types `Uj` there is a unique type `V` from which there is an implicit conversion to all the other candidate types, then ~~`Xi` is fixed to `V`.~~\n>     -  **If `V` is a value type and there is a *null bound* for `Xi`, then `Xi` is fixed to `V?`**\n>     -  **Otherwise   `Xi` is fixed to `V`**\n> *  Otherwise, type inference fails.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nThere may be some incompatibilities introduced by this proposal.\n\n## Alternatives\n[alternatives]: #alternatives\n\nNone.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n- [ ] What is the severity of incompatibility introduced by this proposal, if any, and how can it be moderated?\n\n## Design meetings\n\nNone.\n"
  },
  {
    "path": "proposals/rejected/param-nullchecking.md",
    "content": "# Parameter Null Checking\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/2145>\n\n## Summary\nThis proposal provides a simplified syntax for validating method arguments are not `null` and throwing \n`ArgumentNullException` appropriately.\n\n## Motivation\nThe work on designing nullable reference types has caused us to examine the code necessary for `null` argument \nvalidation. Given that NRT doesn't affect code execution developers still must add `if (arg is null) throw` boiler \nplate code even in projects which are fully `null` clean. This gave us the desire to explore a minimal syntax for \nargument `null` validation in the language. \n\nWhile this `null` parameter validation syntax is expected to pair frequently with NRT, the proposal is fully independent\nof it. The syntax can be used independent of `#nullable` directives.\n\n## Detailed Design \n\n### Null validation parameter syntax\nThe bang-bang operator, `!!`, can be positioned after a parameter name in a parameter list and this will cause the C# \ncompiler to emit `null` checking code for that parameter. This is referred to as `null` validation parameter\nsyntax. For example:\n\n``` csharp\nvoid M(string name!!) {\n    ...\n}\n```\n\nWill be translated into code similar to the following:\n\n``` csharp\nvoid M(string name) {\n    if (name is null) {\n        throw new ArgumentNullException(nameof(name));\n    }\n    ...\n}\n```\n\nThere are a few guidelines limiting where `!!` can be used:\n\n1. Only a parameter of something with an implementation can use it. For example, an abstract method parameter cannot use `!!`. Further examples include:\n   - extern method parameters\n   - delegate parameters\n   - interface method parameters when the method is not a DIM\n2. It must be possible to include an equivalent \"check then throw\" of the given parameter at the beginning of the method, ignoring syntactic limitations such as the need to replace an expression body with a block body.\n\nBecause of (2), the `!!` operator cannot be used on a discard.\n``` csharp\nSystem.Action<string, string> lambda = (_!!, _!!) => { }; // error\n```\n\nAlso because of (2), the `!!` operator cannot be used on an `out` parameter, but it can be used on a `ref` or `in` parameter.\n``` csharp\nvoid M1(ref string x!!) { } // ok\nvoid M2(in string y!!) { } // ok\nvoid M3(out string z!!) { } // error\n```\n\nDeclarations that have parameters and implementations can generally use `!!`. Therefore, it's permitted to use it on an indexer parameter, and the behavior is that all the indexer's accessors will insert a null check.\n\n``` csharp\npublic string this[string key!!] { get { ... } set { ... } } // ok\n```\n\nThe implementation behavior must be that if the parameter is null, it creates and throws an `ArgumentNullException` with the parameter name as a constructor argument. The implementation is free to use any strategy that achieves this. This could result in observable differences between different compliant implementations, such as whether calls to helper methods are present above the call to the method with the null-checked parameter in the exception stack trace.\n\nWe make these allowances because parameter null checks are used frequently in libraries with tight performance and size constraints. For example, to optimize code size, inlining, etc., the implementation may use helper methods to perform the null check a la the [ArgumentNullException.ThrowIfNull](https://github.com/dotnet/runtime/blob/1d08e154b942a41e72cbe044e01fff8b13c74496/src/libraries/System.Private.CoreLib/src/System/ArgumentNullException.cs#L56-L69) methods.\n\nThe generated `null` check will occur before any developer authored code in the method. When multiple parameters contain\nthe `!!` operator then the checks will occur in the same order as the parameters are declared.\n\n``` csharp\nvoid M(string p1, string p2) {\n    if (p1 is null) {\n        throw new ArgumentNullException(nameof(p1));\n    }\n    if (p2 is null) {\n        throw new ArgumentNullException(nameof(p2));\n    }\n    ...\n}\n```\n\nThe check will be specifically for reference equality to `null`, it does not invoke `==` or any user defined operators. \nThis also means the `!!` operator can only be added to parameters whose type can be tested for equality against `null`. \nThis means it can't be used on a parameter whose type is known to be a value type.\n\n``` csharp\n// Error: Cannot use !! on parameters who types derive from System.ValueType\nvoid G<T>(T arg!!) where T : struct {\n\n}\n```\n\nIn the case of a constructor, the `null` validation will occur before any other code in the constructor. That includes: \n\n- Chaining to other constructors with `this` or `base` \n- Field initializers which implicitly occur in the constructor\n\nFor example:\n\n``` csharp\nclass C {\n    string field = GetString();\n    C(string name!!): this(name) {\n        ...\n    }\n}\n```\n\nWill be roughly translated into the following:\n\n``` csharp\nclass C {\n    C(string name)\n        if (name is null) {\n            throw new ArgumentNullException(nameof(name));\n        }\n        field = GetString();\n        :this(name);\n        ...\n}\n```\n\nNote: this is not legal C# code but instead just an approximation of what the implementation does. \n\nThe `null` validation parameter syntax will also be valid on lambda parameter lists. This is valid even in the single\nparameter syntax that lacks parens.\n\n``` csharp\nvoid G() {\n    // An identity lambda which throws on a null input\n    Func<string, string> s = x!! => x;\n}\n```\n\n`async` methods can have null-checked parameters. The null check occurs when the method is invoked.\n\nThe syntax is also valid on parameters to iterator methods. Unlike other code in the iterator the `null` validation will\noccur when the iterator method is invoked, not when the underlying enumerator is walked. This is true for traditional\nor `async` iterators.\n\n``` csharp\nclass Iterators {\n    IEnumerable<char> GetCharacters(string s!!) {\n        foreach (var c in s) {\n            yield return c;\n        }\n    }\n\n    void Use() {\n        // The invocation of GetCharacters will throw\n        IEnumerable<char> e = GetCharacters(null);\n    }\n}\n```\n\nThe `!!` operator can only be used for parameter lists which have an associated method body. This\nmeans it cannot be used in an `abstract` method, `interface`, `delegate` or `partial` method \ndefinition.\n\n### Extending is null\nThe types for which the expression `is null` is valid will be extended to include unconstrained type parameters. This \nwill allow it to fill the intent of checking for `null` on all types which a `null` check is valid. Specifically that\nis types which are not definitely known to be value types. For example Type parameters which are constrained to \n`struct` cannot be used with this syntax.\n\n``` csharp\nvoid NullCheck<T1, T2>(T1 p1, T2 p2) where T2 : struct {\n    // Okay: T1 could be a class or struct here.\n    if (p1 is null) {\n        ...\n    }\n\n    // Error \n    if (p2 is null) { \n        ...\n    }\n}\n```\n\nThe behavior of `is null` on a type parameter will be the same as `== null` today. In the cases where the type parameter\nis instantiated as a value type the code will be evaluated as `false`. For cases where it is a reference type the \ncode will do a proper `is null` check.\n\n### Intersection with Nullable Reference Types\nAny parameter which has a `!!` operator applied to it's name will start with the nullable state being not `null`. This is\ntrue even if the type of the parameter itself is potentially `null`. That can occur with an explicitly nullable type, \nsuch as say `string?`, or with an unconstrained type parameter. \n\nWhen a `!!` syntax on parameters is combined with an explicitly nullable type on the parameter then a warning will\nbe issued by the compiler:\n\n``` csharp\nvoid WarnCase<T>(\n    string? name!!, // Warning: combining explicit null checking with a nullable type\n    T value1!! // Okay\n)\n```\n\n## Open Issues\nNone\n\n## Considerations\n\n### Constructors\nThe code generation for constructors means there is a small, but observable, behavior change when moving from standard\n`null` validation today and the `null` validation parameter syntax (`!!`). The `null` check in standard validation \noccurs after both field initializers and any `base` or `this` calls. This means a developer can't necessarily migrate\n100% of their `null` validation to the new syntax. Constructors at least require some inspection.\n\nAfter discussion though it was decided that this is very unlikely to cause any significant adoption issues. It's more\nlogical that the `null` check run before any logic in the constructor does. Can revisit if significant compat issues\nare discovered.\n\n### Warning when mixing ? and !\nThere was a lengthy discussion on whether or not a warning should be issued when the `!!` syntax is applied to a\nparameter which is explicitly typed to a nullable type. On the surface it seems like a nonsensical declaration by \nthe developer but there are cases where type hierarchies could force developers into such a situation. \n\nConsider the following class hierarchy across a series of assemblies (assuming all are compiled with `null` checking\nenabled):\n\n``` csharp\n// Assembly1\nabstract class C1 {\n    protected abstract void M(object o); \n}\n\n// Assembly2\nabstract class C2 : C1 {\n\n}\n\n// Assembly3\nabstract class C3 : C2 { \n    protected override void M(object o!!) {\n        ...\n    }\n}\n```\n\nHere the author of `C3` decided to add `null` validation to the parameter `o`. This is completely in line with how the\nfeature is intended to be used.\n\nNow imagine at a later date the author of Assembly2 decides to add the following override:\n\n``` csharp\n// Assembly2\nabstract class C2 : C1 {\n   protected override void M(object? o) { \n       ...\n   }\n}\n```\n\nThis is allowed by nullable reference types as it's legal to make the contract more flexible for input positions. The \nNRT feature in general allows for reasonable co/contravariance on parameter / return nullability. However the language\ndoes the co/contravariance checking based on the most specific override, not the original declaration. This means the\nauthor of Assembly3 will get a warning about the type of `o` not matching and will need to change the signature to the\nfollowing to eliminate it: \n\n``` csharp\n// Assembly3\nabstract class C3 : C2 { \n    protected override void M(object? o!!) {\n        ...\n    }\n}\n```\n\nAt this point the author of Assembly3 has a few choices:\n\n- They can accept / suppress the warning about `object?` and `object` mismatch.\n- They can accept / suppress the warning about `object?` and `!!` mismatch.\n- They can just remove the `null` validation check (delete `!!` and do explicit checking)\n\nThis is a real scenario but for now the idea is to move forward with the warning. If it turns out the warning happens\nmore frequently than we anticipate then we can remove it later (the reverse is not true).\n\n### Implicit property setter arguments\nThe `value` argument of a parameter is implicit and does not appear in any parameter list. That means it cannot be a \ntarget of this feature. The property setter syntax could be extended to include a parameter list to allow the `!!` \noperator to be applied. But that cuts against the idea of this feature making `null` validation simpler. As such the \nimplicit `value` argument just won't work with this feature.\n\n## Future Considerations\nNone\n"
  },
  {
    "path": "proposals/rejected/params-span.md",
    "content": "# `params ReadOnlySpan<T>`\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/1757>\n\n## Summary\nAvoid heap allocation of implicitly allocated `params` arrays.\n\n## Motivation\n`params` array parameters provide a convenient way to call a method that takes an arbitrary length list of arguments.\nHowever, using an array type for the parameter means the compiler must implicitly allocate an array on the heap at each call site.\n\nIf we extend `params` support to `ReadOnlySpan<T>`, where the implicitly created span cannot escape the calling method, the underlying buffer at the call site may be created on the stack instead.\n\nIf overload resolution prefers `params ReadOnlySpan<T>` over `params T[]`, then adding a `params ReadOnlySpan<T>` overload to an existing API would reduce allocations when recompiling callers.\n\nThe benefit of `params ReadOnlySpan<T>` is primarily for APIs that don't already include optimized overloads. Commonly used APIs such as `Console.WriteLine()` and `StringBuilder.AppendFormat()` that already have non-`params` overloads for callers with few arguments would benefit less.\n```csharp\n// Existing API with params and non-params overloads\npublic static class Console\n{\n    public static void WriteLine(string value);\n    public static void WriteLine(string format, object arg0);\n    public static void WriteLine(string format, object arg0, object arg1);\n    public static void WriteLine(string format, object arg0, object arg1, object arg2);\n    public static void WriteLine(string format, params object[] arg);\n}\n\n// New API with single overload\nabstract class Logger\n{\n    public abstract void Log(string format, params ReadOnlySpan<object> args);\n}\n```\n\n## Detailed design\n\n### Extending `params`\nA `params` parameter type may be `System.ReadOnlySpan<T>` for a valid type argument `T`.\n\nA call in [_expanded form_](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11642-applicable-function-member) to a method with a `params ReadOnlySpan<T>` parameter will result in a `ReadOnlySpan<T>` instance implicitly created by the compiler.\n\n```csharp\nlog.Log(\"({0}, {1}, {2})\", x, y, z);\n\n// Potentially emitted as:\nlog.Log(\"({0}, {1}, {2})\",\n    new System.ReadOnlySpan<object>(new object[] { x, y, z }));\n```\n\nA `params` parameter must be the last parameter in the method signature and cannot include a `ref`, `out`, or `in` modifier.\n\nTwo overloads cannot differ by `params` modifier alone.\n\n`params` parameters are marked in metadata with a `System.ParamArrayAttribute`.\n\nA `params ReadOnlySpan<T>` is implicitly `scoped`.\nThe parameter _cannot_ be annotated with `[UnscopedRef]` and _cannot_ be declared `scoped` explicitly.\nWithin the `params` method, the compiler will use escape analysis to report diagnostics if the span is captured or returned.\n\n### Overload resolution\nOverload resolution prefers overloads that are applicable in [_normal form_](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11642-applicable-function-member) over [_expanded form_](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11642-applicable-function-member).\n\n[_Better function member_](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11643-better-function-member) will prefer `params ReadOnlySpan<T>` over `params T[]` for overloads applicable in [_expanded form_](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11642-applicable-function-member):\n\n> In case the parameter type sequences `{P1, P2, ..., Pn}` and `{Q1, Q2, ..., Qn}` are equivalent (i.e. each `Pi` has an identity conversion to the corresponding `Qi`), the following tie-breaking rules are applied, in order, to determine the better function member.\n> \n> *  If `Mp` is a non-generic method and `Mq` is a generic method, then `Mp` is better than `Mq`.\n> *  ...\n> *  Otherwise if one member is a non-lifted operator and the other is a lifted operator, the non-lifted one is better.\n> *  **Otherwise, if both methods have `params` parameters and are applicable only in their expanded forms, and the `params` types are distinct types with equivalent element type (there is an identity conversion between element types), the more specific `params` type is the first of:**\n>    *  **`ReadOnlySpan<T>`**\n>    *  **`T[]`**\n> *  Otherwise, neither function member is better.\n\nOverload resolution will prefer `params T[]` at callsites where the type substituted for `T` is not a valid generic type argument since a `params ReadOnlySpan<T>` will not be applicable in those cases. The types that are valid as array elements but not as generic type arguments are:\n- _pointers_ and\n- _function pointers_.\n\n### Allocation and reuse\nThe compiler will include the following optimizations for implicitly allocated `params` buffers. Additional optimizations may be added in future for cases where the compiler can determine there are _no reachable aliases_ to the buffer.\n\nThe compiler _will allocate the buffer on the stack_ for a `params ReadOnlySpan<T>` argument when\n- the parameter is implicitly or explicitly `scoped` _which is required from source_,\n- the argument is implicitly allocated, and\n- the runtime supports [_fixed size buffers of managed types_](#runtime-stack-allocation).\n\nThe compiler _will reuse the buffer_ allocated on the stack for implicit arguments to `params ReadOnlySpan<T>` and `params ReadOnlySpan<U>` when there is an identity conversion between element types `T` and `U`.\n\nFor target frameworks that do not support _fixed size buffers_, implicitly allocated buffers will be allocated on the heap. \n\nThe parameter must be `scoped` to ensure the implicitly allocated buffer is not returned or aliased which might prevent allocating on the stack or reusing the buffer.\n\nThe buffer is allocated on the stack regardless of argument length or element size.\nThe buffer is allocated to the length of the longest `params` argument across all applicable uses for matching `T`.\n\nTo _opt out_ of compiler optimizations at a call site, the calling code should allocate the span explicitly (directly or indirectly using `new ReadOnlySpan<T>(new[] { ... })`).\n\nThe span for a particular `params` argument will be a slice of the buffer matching the argument length at that call site.\n\nAt runtime, the stack space for the buffer is reserved for the lifetime of the method, regardless of where in the method the buffer is used.\n\nReuse is within the same method and thread of execution only and may be across distinct call sites _or_ repeated calls from the same call site.\n\nBefore exiting a C# scope, the compiler ensures the buffer contains no references from the scope.\n\n### Runtime stack allocation\nThere is a runtime request to support fields of [_fixed size buffers of managed types_](https://github.com/dotnet/runtime/issues/61135).\nWith _fixed size buffer_ fields, we can define `ref struct` types that allow using locals for stack allocated buffers.\n\nFor example, consider a `FixedSizeBuffer3<T>` type defined below which includes an inline buffer with 3 items:\n```csharp\nref struct FixedSizeBuffer3<T>\n{\n    public fixed T Items[3]; // pseudo-code for inline fixed size buffer\n}\n```\n\nWith that type, a call to `log.Log(\"({0}, {1}, {2})\", x, y, z)` could be emitted as:\n```csharp\nvar _tmp = new FixedSizeBuffer3<object>();\n_tmp.Items[0] = x;\n_tmp.Items[1] = y;\n_tmp.Items[2] = z;\n\n// Logger.Log(string format, params ReadOnlySpan<object> args);\nlog.Log(\"({0}, {1}, {2})\",\n    MemoryMarshal.CreateReadOnlySpan<object>(ref _tmp.Items, 3));\n```\n\nIdeally the base class library will provide types such as `FixedSizeBuffer1<T>`, `FixedSizeBuffer2<T>`, etc. for a limited number of span lengths.\nAnd if the compilation requires buffers for other span lengths, the compiler will generate and emit the additional types.\n\n### Example\nConsider the following extension method for logging the contents of a dictionary:\n```csharp\nstatic void LogDictionary<K, V>(this Logger log, Dictionary<K, V> dictionary)\n{\n    log.Log(\"Dictionary\");\n\n    foreach (var (k, v) in dictionary)\n        log.Log(\"{0}, {1}\", k, v);\n\n    log.Log(\"Count = {0}\", dictionary.Count);\n}\n```\n\nThe method could be lowered to:\n```csharp\nstatic void LogDictionary<K, V>(this Logger log, Dictionary<K, V> dictionary)\n{\n    FixedSizeBuffer2<object> _tmp = new FixedSizeBuffer2<object>();\n\n    log.Log(\"Dictionary\",\n        new ReadOnlySpan<object>(Array.Empty<object>()); // no reuse\n\n    foreach (var (k, v) in dictionary)\n    {\n        _tmp.Items[0] = k;\n        _tmp.Items[1] = v;\n        log.Log(\"{0}, {1}\",\n            MemoryMarshal.CreateReadOnlySpan<object>(ref _tmp.Items, 2)); // reuse\n        MemoryMarshal.CreateSpan<object>(ref _tmp.Items, 2).Clear();      // clear\n    }\n\n    _tmp.Items[0] = dictionary.Count;\n    log.Log(\"Count = {0}\",\n        MemoryMarshal.CreateReadOnlySpan<object>(ref _tmp.Items, 1)); // reuse slice\n}\n```\n\n## Open issues\n### Support `params scoped T[]`?\nAllow a `params T[]` to be marked as `scoped` and allocate argument arrays on the stack at call sites? That would avoid heap allocation at each call site, but allocations could only be reused at call sites with matching argument type _and length_.\n\n### Support `params Span<T>`?\nSupport `params Span<T>` to allow the `params` method to modify the span contents, even though the effects are only observable at call sites that explicitly allocate the span?\n\n### Support `params IEnumerable<T>`, etc.?\nIf we're extending `params` to support `ReadOnlySpan<T>`, should we also support `params` parameters of other collection types, including interfaces and concrete types?\n\nThe reason to support `params ReadOnlySpan<T>` is to improve performance of existing callers by allowing stack allocation of `params` buffers.\nThe reason to extend `params` to other collection types is not performance but to support implicit collections at call sites while _also_ supporting APIs or call sites that use collections other than arrays.\n\nFor APIs, supporting `params` and other collection types is already possible through overloads:\n```csharp\nabstract class Logger\n{\n    public abstract void Log(string format, IEnumerable<object> args);\n\n    public void Log(string format, params object[] args)\n    {\n        Log(format, (IEnumerable<object>)args);\n    }\n}\n```\n\nAnd for callers where the API takes an explicit collection type rather than `params`, [_collection literals_](https://github.com/dotnet/csharplang/issues/5354) provide a simple syntax that reduces the need for `params`.\n```csharp\nlog.Log(\"({0}, {1}, {2})\", [x, y, z]);\n\nabstract class Logger\n{\n    public abstract void Log(string format, IEnumerable<object> args);\n}\n```\n\nThat said, this proposal doesn't prevent extending `params` to other types in the future.\n\n### Opting out\nShould we allow opt-ing out of _implicit allocation_ on the call stack?\nPerhaps an attribute that can be applied to a method, type, or assembly.\n\n## Related proposals\n- https://github.com/dotnet/csharplang/issues/1757\n- https://github.com/dotnet/csharplang/blob/main/proposals/format.md#extending-params\n"
  },
  {
    "path": "proposals/rejected/readonly-locals.md",
    "content": "# readonly locals and parameters\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/188>\n\n## Summary\n[summary]: #summary\n\nAllow locals and parameters to be annotated as readonly in order to prevent shallow mutation of those locals and parameters.\n\n## Motivation\n[motivation]: #motivation\n\nToday, the `readonly` keyword can be applied to fields; this has the effect of ensuring that a field can only\nbe written to during construction (static construction in the case of a static field, or instance construction in the case of an instance field),\nwhich helps developers avoid mistakes by accidentally overwriting state which should not be modified. But fields aren't the only places developers\nwant to ensure that values aren't mutated. In particular, it's common to create a local variable to store temporary state, and accidentally updating\nthat temporary state can result in erroneous calculations and other such bugs, especially when such \"locals\" are captured in lambdas, at which point\nthey are lifted to fields, but there's no way today to mark such lifted fields as `readonly`.\n\n## Detailed design\n[design]: #detailed-design\n\nLocals will be annotatable as `readonly` as well, with the compiler ensuring that they're only set at the time of declaration (certain locals in C# are\nalready implicitly readonly, such as the iteration variable in a 'foreach' loop or the used variable in a 'using' block, but currently a developer has\nno ability to mark other locals as `readonly`). Such `readonly` locals must have an initializer:\n\n```csharp\nreadonly long maxBytesToDelete = (stream.LimitBytes - stream.MaxBytes) / 10;\n...\nmaxBytesToDelete = 0; // Error: can't assign to readonly locals outside of declaration\n```\n\nAnd as shorthand for `readonly var`, the existing contextual keyword `let` may be used, e.g.\n\n```csharp\nlet maxBytesToDelete = (stream.LimitBytes - stream.MaxBytes) / 10;\n...\nmaxBytesToDelete = 0; // Error: can't assign to readonly locals outside of declaration\n```\n\nThere are no special constraints for what the initializer can be, and can be anything currently valid as an initializer for locals, e.g.\n\n```csharp\nreadonly T data = arg1 ?? arg2;\n```\n\n`readonly` on locals is particularly valuable when working with lambdas and closures. When an anonymous method or lambda accesses local state from the enclosing scope,\nthat state is captured into a closure by the compiler, which is represented by a \"display class.\"  Each \"local\" that's captured is a field in this class, yet\nbecause the compiler is generating this field on your behalf, you have no opportunity to annotate it as `readonly` in order to prevent the lambda from erroneously\nwriting to the \"local\" (in quotes because it's really not a local, at least not in the resulting MSIL). With `readonly` locals, the compiler can prevent the lambda\nfrom writing to local, which is particularly valuable in scenarios involving multithreading where an erroneous write could result in a dangerous but rare and\nhard-to-find concurrency bug.\n\n```csharp\nreadonly long index = ...;\nParallel.ForEach(data, item => {\n    T element = item[index];\n    index = 0; // Error: can't assign to readonly locals outside of declaration\n});\n```\n\nAs a special form of local, parameters will also be annotatable as `readonly`. This would have no effect on what the caller of the method is able to pass to the\nparameter (just as there's no constraint on what values may be stored into a `readonly` field), but as with any `readonly` local, the compiler would prohibit code\nfrom writing to the parameter after declaration, which means the body of the method is prohibited from writing to the parameter.\n\n```csharp\npublic void Update(readonly int index = 0) // Default values are ok though not required\n{\n    ...\n    index = 0; // Error: can't assign to readonly parameters\n    ...\n}\n```\n\n`readonly` parameters do not affect the signature/metadata emitted by the compiler for that method, and simply affect how the compiler handles the compilation of\nthe method's body. Thus, for example, a base virtual method could have a `readonly` parameter, and that parameter could be writable in an override.\n\nAs with fields, `readonly` for locals and parameters is shallow, affecting the storage location but not transitively affecting the object graph. However, also\nas with fields, calling a method on a `readonly` local/parameter struct will actually make a copy of the struct and call the method on the copy, in order to avoid\ninternal mutation of `this`.\n\n`readonly` locals and parameters can't be passed as `ref` or `out` arguments, unless/until `ref readonly` is also supported.\n\n## Alternatives\n[alternatives]: #alternatives\n\n- `val` could be used as an alternative shorthand to `let`.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\n- `readonly ref` / `ref readonly` / `readonly ref readonly`: I've left the question of how to handle `ref readonly` as separate from this proposal.\n- This proposal does not tackle readonly structs / immutable types. That is left for a separate proposal.\n\n## Design meetings\n\n- Briefly discussed on Jan 21, 2015 (<https://github.com/dotnet/roslyn/issues/98>)\n"
  },
  {
    "path": "proposals/rejected/records.md",
    "content": "# records\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/39>\n\n## Summary\n[summary]: #summary\n\nRecords are a new, simplified declaration form for C# class and struct types that combine the benefits of a number of simpler features. We describe the new features (caller-receiver parameters and *with-expression*s), give the syntax and semantics for record declarations, and then provide some examples.\n\n\n## Motivation\n[motivation]: #motivation\n\nA significant number of type declarations in C# are little more than aggregate collections of typed data. Unfortunately, declaring such types requires a great deal of boilerplate code. *Records* provide a mechanism for declaring a datatype by describing the members of the aggregate along with additional code or deviations from the usual boilerplate, if any.\n\nSee [Examples](#examples), below.\n\n## Detailed design\n[design]: #detailed-design\n\n### caller-receiver parameters\n\nCurrently a method parameter's *default-argument* must be \n- a *constant-expression*; or\n- an expression of the form `new S()` where `S` is a value type; or\n- an expression of the form `default(S)` where `S` is a value type\n\nWe extend this to add the following\n- an expression of the form `this.Identifier`\n\nThis new form is called a *caller-receiver default-argument*, and is allowed only if all of the following are satisfied\n- The method in which it appears is an instance method; and\n- The expression `this.Identifier` binds to an instance member of the enclosing type, which must be either a field or a property; and\n- The member to which it binds (and the `get` accessor, if it is a property) is at least as accessible as the method; and\n- The type of `this.Identifier` is implicitly convertible by an identity or nullable conversion to the type of the parameter (this is an existing constraint on *default-argument*).\n\nWhen an argument is omitted from an invocation of a function member for a corresponding optional parameter with a *caller-receiver default-argument*, the value of the receiver's member is implicitly passed. \n\n> **Design Notes**: the main reason for the caller-receiver parameter is to support the *with-expression*. The idea is that you can declare a method like this\n> ```cs\n> class Point\n> {\n>     public readonly int X;\n>     public readonly int Y;\n>     public Point With(int x = this.X, int y = this.Y) => new Point(x, y);\n>     // etc\n> }\n> ```\n> and then use it like this\n> ```cs\n>     Point p = new Point(3, 4);\n>     p = p.With(x: 1);\n> ```\n> To create a new `Point` just like an existing `Point` but with the value of `X` changed.\n> \n> It is an open question whether or not the syntactic form of the *with-expression* is worth adding once we have support for caller-receiver parameters, so it is possible we would do this *instead of* rather than *in addition to* the *with-expression*.\n\n- [ ] **Open issue**: What is the order in which a *caller-receiver default-argument* is evaluated with respect to other arguments? Should we say that it is unspecified?\n\n### with-expressions\n\nA new expression form is proposed:\n\n```antlr\nprimary_expression\n    : with_expression\n    ;\n\nwith_expression\n    : primary_expression 'with' '{' with_initializer_list '}'\n    ;\n\nwith_initializer_list\n    : with_initializer\n    | with_initializer ',' with_initializer_list\n    ;\n\nwith_initializer\n    : identifier '=' expression\n    ;\n```\n\nThe token `with` is a new context-sensitive keyword.\n\nEach *identifier* on the left of a *with_initializer* must bind to an accessible instance field or property of the type of the *primary_expression* of the *with_expression*. There may be no duplicated name among these identifiers of a given *with_expression*.\n\nA *with_expression* of the form\n\n> *e1* `with` `{` *identifier* = *e2*, ... `}`\n\nis treated as an invocation of the form\n\n> *e1*`.With(`*identifier2*`:` *e2*, ...`)`\n\nWhere, for each method named `With` that is an accessible instance member of *e1*, we select *identifier2* as the name of the first parameter in that method that has a caller-receiver parameter that is the same member as the instance field or property bound to *identifier*. If no such parameter can be identified that method is eliminated from consideration. The method to be invoked is selected from among the remaining candidates by overload resolution.\n\n> **Design Notes**: Given caller-receiver parameters, many of the benefits of the *with-expression* are available without this special syntax form. We are therefore considering whether or not it is needed. Its main benefit is allowing one to program in terms of the names of fields and properties, rather than in terms of the names of parameters. In this way we improve both readability and the quality of tooling (e.g. go-to-definition on the identifier of a *with_expression* would navigate to the property rather than to a method parameter).\n\n- [ ] **Open issue**: This description should be modified to support extension methods.\n\n### pattern-matching\n\nSee the [Pattern Matching Specification](csharp-8.0/patterns.md#positional-pattern) for a specification of `Deconstruct` and its relationship to pattern-matching.\n\n> **Design Notes**: By virtue of the compiler-generated `Deconstruct` as specified herein, and the specification for pattern-matching, a record declaration\n> ```cs\n> public class Point(int X, int Y);\n> ```\n> will support positional pattern-matching as follows\n> ```cs\n> Point p = new Point(3, 4);\n> if (p is Point(3, var y)) { // if X is 3\n>     Console.WriteLine(y);   // print Y\n> }\n> ```\n\n### record type declarations\n\nThe syntax for a `class` or `struct` declaration is extended to support value parameters; the parameters become properties of the type:\n\n```antlr\nclass_declaration\n    : attributes? class_modifiers? 'partial'? 'class' identifier type_parameter_list?\n      record_parameters? record_class_base? type_parameter_constraints_clauses? class_body\n    ;\n\nstruct_declaration\n    : attributes? struct_modifiers? 'partial'? 'struct' identifier type_parameter_list?\n      record_parameters? struct_interfaces? type_parameter_constraints_clauses? struct_body\n    ;\n\nrecord_class_base\n    : class_type record_base_arguments?\n    | interface_type_list\n    | class_type record_base_arguments? ',' interface_type_list\n    ;\n\nrecord_base_arguments\n    : '(' argument_list? ')'\n    ;\n\nrecord_parameters\n    : '(' record_parameter_list? ')'\n    ;\n\nrecord_parameter_list\n    : record_parameter\n    | record_parameter ',' record_parameter_list\n    ;\n\nrecord_parameter\n    : attributes? type identifier record_property_name? default_argument?\n    ;\n\nrecord_property_name\n    : ':' identifier\n    ;\n\nclass_body\n    : '{' class_member_declarations? '}'\n    | ';'\n    ;\n\nstruct_body\n    : '{' struct_members_declarations? '}'\n    | ';'\n    ;\n```\n\n> **Design Notes**: Because record types are often useful without the need for any members explicitly declared in a class-body, we modify the syntax of the declaration to allow a body to be simply a semicolon.\n\nA class (struct) declared with the *record-parameters* is called a *record class* (*record struct*), either of which is a *record type*.\n\n- [ ] **Open issue**: We need to include *primary_constructor_body* in the grammar so that it can appear inside a record type declaration.\n- [ ] **Open issue**: What are the name conflict rules for the parameter names? Presumably one is not allowed to conflict with a type parameter or another *record-parameter*.\n- [ ] **Open issue**: We need to specify the scope of the record-parameters. Where can they be used? Presumably within instance field initializers and *primary_constructor_body* at least.\n- [ ] **Open issue**: Can a record type declaration be partial? If so, must the parameters be repeated on each part?\n\n#### Members of a record type\n\nIn addition to the members declared in the *class-body*, a record type has the following additional members:\n\n##### Primary Constructor\n\nA record type has a `public` constructor whose signature corresponds to the value parameters of the type declaration. This is called the *primary constructor* for the type, and causes the implicitly declared *default constructor* to be suppressed.\n\nAt runtime the primary constructor\n\n* initializes compiler-generated backing fields for the properties corresponding to the value parameters (if these properties are compiler-provided; [see 1.1.2](#1.1.2)); then\n* executes the instance field initializers appearing in the *class-body*; and then\n* invokes a base class constructor:\n    * If there are arguments in the *record_base_arguments*, a base constructor selected by overload resolution with these arguments is invoked;\n    * Otherwise a base constructor is invoked with no arguments.\n* executes the body of each *primary_constructor_body*, if any, in source order.\n\n- [ ] **Open issue**: We need to specify that order, particularly across compilation units for partials.\n- [ ] **Open Issue**: We need to specify that every explicitly declared constructor must chain to the primary constructor.\n- [ ] **Open issue**: Should it be allowed to change the access modifier on the primary constructor?\n- [ ] **Open issue**: In a record struct, it is an error for there to be no record parameters?\n\n##### Primary constructor body\n\n```antlr\nprimary_constructor_body\n    : attributes? constructor_modifiers? identifier block\n    ;\n```\n\nA *primary_constructor_body* may only be used within a record type declaration. The *identifier* of a *primary_constructor_body* shall name the record type in which it is declared.\n\nThe *primary_constructor_body* does not declare a member on its own, but is a way for the programmer to provide attributes for, and specify the access of, a record type's primary constructor. It also enables the programmer to provide additional code that will be executed when an instance of the record type is constructed.\n\n- [ ] **Open issue**: We should note that a struct default constructor bypasses this.\n- [ ] **Open issue**: We should specify the execution order of initialization.\n- [ ] **Open issue**: Should we allow something like a *primary_constructor_body* (presumably without attributes and modifiers) in a non-record type declaration, and treat it like we would the code of an instance field initializer?\n\n##### Properties\n\nFor each record parameter of a record type declaration there is a corresponding `public` property member whose name and type are taken from the value parameter declaration. Its name is the *identifier* of the *record_property_name*, if present, or the *identifier* of the *record_parameter* otherwise. If no concrete (i.e. non-abstract) public property with a `get` accessor and with this name and type is explicitly declared or inherited, it is produced by the compiler as follows:\n\n* For a *record struct* or a `sealed` *record class*:\n * A `private` `readonly` field is produced as a backing field for a `readonly` property. Its value is initialized during construction with the value of the corresponding primary constructor parameter.\n * The property's `get` accessor is implemented to return the value of the backing field.\n * Each \"matching\" inherited virtual property's `get` accessor is overridden.\n\n> **Design notes**: In other words, if you extend a base class or implement an interface that declares a public abstract property with the same name and type as a record parameter, that property is overridden or implemented.\n\n- [ ] **Open issue**: Should it be possible to change the access modifier on a property when it is explicitly declared?\n- [ ] **Open issue**: Should it be possible to substitute a field for a property?\n\n##### Object Methods\n\nFor a *record struct* or a `sealed` *record class*, implementations of the methods `object.GetHashCode()` and `object.Equals(object)` are produced by the compiler unless provided by the user.\n\n- [ ] **Open issue**: We should precisely specify their implementation.\n- [ ] **Open issue**: We should also add the interface `IEquatable<T>` for the record type and specify that implementations are provided.\n- [ ] **Open issue**: We should also specify that we implement every `IEquatable<T>.Equals`.\n- [ ] **Open issue**: We should specify precisely how we solve the problem of Equals in the face of record inheritance: specifically how we generate equality methods such that they are symmetric, transitive, reflexive, etc.\n- [ ] **Open issue**: It has been proposed that we implement `operator ==` and `operator !=` for record types.\n- [ ] **Open issue**: Should we auto-generate an implementation of `object.ToString`?\n\n##### `Deconstruct`\n\nA record type has a compiler-generated `public` method `void Deconstruct` unless one with any signature is provided by the user. Each parameter is an `out` parameter of the same name and type as the corresponding parameter of the record type. The compiler-provided implementation of this method shall assign each `out` parameter with the value of the corresponding property.\n\nSee [the pattern-matching specification](csharp-8.0/patterns.md#positional-pattern) for the semantics of `Deconstruct`.\n\n##### `With` method\n\nUnless there is a user-declared member named `With` declared, a record type has a compiler-provided method named `With` whose return type is the record type itself, and containing one value parameter corresponding to each *record-parameter* in the same order that these parameters appear in the record type declaration. Each parameter shall have a *caller-receiver default-argument* of the corresponding property.\n\nIn an `abstract` record class, the compiler-provided `With` method is abstract. In a record struct, or a sealed record class, the compiler-provided `With` method is `sealed`. Otherwise the compiler-provided `With` method is `virtual and its implementation shall return a new instance produced by invoking the primary constructor with the parameters as arguments to create a new instance from the parameters, and return that new instance.\n\n- [ ] **Open issue**: We should also specify under what conditions we override or implement inherited virtual `With` methods or `With` methods from implemented interfaces.\n- [ ] **Open issue**: We should say what happens when we inherit a non-virtual `With` method.\n\n> **Design notes**: Because record types are by default immutable, the `With` method provides a way of creating a new instance that is the same as an existing instance but with selected properties given new values. For example, given\n> ```cs\n> public class Point(int X, int Y);\n> ```\n> there is a compiler-provided member\n> ```cs\n>     public virtual Point With(int X = this.X, int Y = this.Y) => new Point(X, Y);\n> ```\n> Which enables an variable of the record type\n> ```cs\n> var p = new Point(3, 4);\n> ```\n> to be replaced with an instance that has one or more properties different\n> ```cs\n>     p = p.With(X: 5);\n> ```\n> This can also be expressed using the *with_expression*:\n> ```cs\n>     p = p with { X = 5 };\n> ```\n\n### Examples\n\n#### Compatibility of record types\n\nBecause the programmer can add members to a record type declaration, it is often possible to change the set of record elements without affecting existing clients. For example, given an initial version of a record type\n\n```cs\n// v1\npublic class Person(string Name, DateTime DateOfBirth);\n```\n\nA new element of the record type can be compatibly added in the next revision of the type without affecting binary or source compatibility:\n\n```cs\n// v2\npublic class Person(string Name, DateTime DateOfBirth, string HomeTown)\n{\n    // Note: below operations added to retain binary compatibility with v1\n    public Person(string Name, DateTime DateOfBirth) : this(Name, DateOfBirth, string.Empty) {}\n    public static void operator is(Person self, out string Name, out DateTime DateOfBirth)\n        { Name = self.Name; DateOfBirth = self.DateOfBirth; }\n    public Person With(string Name, DateTime DateOfBirth) => new Person(Name, DateOfBirth);\n}\n```\n\n#### record struct example\n\nThis record struct\n\n```cs\npublic struct Pair(object First, object Second);\n```\n\nis translated to this code\n\n```cs\npublic struct Pair : IEquatable<Pair>\n{\n    public object First { get; }\n    public object Second { get; }\n    public Pair(object First, object Second)\n    {\n        this.First = First;\n        this.Second = Second;\n    }\n    public bool Equals(Pair other) // for IEquatable<Pair>\n    {\n        return Equals(First, other.First) && Equals(Second, other.Second);\n    }\n    public override bool Equals(object other)\n    {\n        return (other as Pair)?.Equals(this) == true;\n    }\n    public override int GetHashCode()\n    {\n        return (First?.GetHashCode()*17 + Second?.GetHashCode()).GetValueOrDefault();\n    }\n    public Pair With(object First = this.First, object Second = this.Second) => new Pair(First, Second);\n    public void Deconstruct(out object First, out object Second)\n    {\n        First = self.First;\n        Second = self.Second;\n    }\n}\n```\n\n- [ ] **Open issue**: should the implementation of Equals(Pair other) be a public member of Pair?\n- [ ] **Open issue**: This implementation of `Equals` is not symmetric in the face of inheritance.\n- [ ] **Open issue**: Should a record declare `operator ==` and `operator !=`?\n\n> **Design notes**: Because one record type can inherit from another, and this implementation of `Equals` would not be symmetric in that case, it is not correct. We propose to implement equality this way:\n> ```cs\n>     public bool Equals(Pair other) // for IEquatable<Pair>\n>     {\n>         return other != null && EqualityContract == other.EqualityContract &&\n>             Equals(First, other.First) && Equals(Second, other.Second);\n>     }\n>     protected virtual Type EqualityContract => typeof(Pair);\n> ```\n> Derived records would `override EqualityContract`. The less attractive alternative is to restrict inheritance.\n\n#### sealed record example\n\nThis sealed record class\n\n```cs\npublic sealed class Student(string Name, decimal Gpa);\n```\n\nis translated into this code\n\n```cs\npublic sealed class Student : IEquatable<Student>\n{\n    public string Name { get; }\n    public decimal Gpa { get; }\n    public Student(string Name, decimal Gpa)\n    {\n        this.Name = Name;\n        this.Gpa = Gpa;\n    }\n    public bool Equals(Student other) // for IEquatable<Student>\n    {\n        return other != null && Equals(Name, other.Name) && Equals(Gpa, other.Gpa);\n    }\n    public override bool Equals(object other)\n    {\n        return this.Equals(other as Student);\n    }\n    public override int GetHashCode()\n    {\n        return (Name?.GetHashCode()*17 + Gpa?.GetHashCode()).GetValueOrDefault();\n    }\n    public Student With(string Name = this.Name, decimal Gpa = this.Gpa) => new Student(Name, Gpa);\n    public void Deconstruct(out string Name, out decimal Gpa)\n    {\n        Name = self.Name;\n        Gpa = self.Gpa;\n    }\n}\n```\n\n#### abstract record class example\n\nThis abstract record class\n\n```cs\npublic abstract class Person(string Name);\n```\n\nis translated into this code\n\n```cs\npublic abstract class Person : IEquatable<Person>\n{\n    public string Name { get; }\n    public Person(string Name)\n    {\n        this.Name = Name;\n    }\n    public bool Equals(Person other)\n    {\n        return other != null && Equals(Name, other.Name);\n    }\n    public override bool Equals(object other)\n    {\n        return Equals(other as Person);\n    }\n    public override int GetHashCode()\n    {\n        return (Name?.GetHashCode()).GetValueOrDefault();\n    }\n    public abstract Person With(string Name = this.Name);\n    public void Deconstruct(Person self, out string Name)\n    {\n        Name = self.Name;\n    }\n}\n```\n\n#### combining abstract and sealed records\n\nGiven the abstract record class `Person` above, this sealed record class\n\n```cs\npublic sealed class Student(string Name, decimal Gpa) : Person(Name);\n```\n\nis translated into this code\n\n```cs\npublic sealed class Student : Person, IEquatable<Student>\n{\n    public override string Name { get; }\n    public decimal Gpa { get; }\n    public Student(string Name, decimal Gpa) : base(Name)\n    {\n        this.Name = Name;\n        this.Gpa = Gpa;\n    }\n    public override bool Equals(Student other) // for IEquatable<Student>\n    {\n        return Equals(Name, other.Name) && Equals(Gpa, other.Gpa);\n    }\n    public bool Equals(Person other) // for IEquatable<Person>\n    {\n        return (other as Student)?.Equals(this) == true;\n    }\n    public override bool Equals(object other)\n    {\n        return (other as Student)?.Equals(this) == true;\n    }\n    public override int GetHashCode()\n    {\n        return (Name?.GetHashCode()*17 + Gpa.GetHashCode()).GetValueOrDefault();\n    }\n    public Student With(string Name = this.Name, decimal Gpa = this.Gpa) => new Student(Name, Gpa);\n    public override Person With(string Name = this.Name) => new Student(Name, Gpa);\n    public void Deconstruct(Student self, out string Name, out decimal Gpa)\n    {\n        Name = self.Name;\n        Gpa = self.Gpa;\n    }\n}\n```\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nAs with any language feature, we must question whether the additional complexity to the language is repaid in the additional clarity offered to the body of C# programs that would benefit from the feature.\n\n## Alternatives\n[alternatives]: #alternatives\n\nWe considered adding *primary constructors* in C# 6. Although they occupy the same syntactic surface as this proposal, we found that they fell short of the advantages offered by records.\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\nOpen questions appear in the body of the proposal.\n\n## Design meetings\n\nTBD\n"
  },
  {
    "path": "proposals/rejected/recordsv2.md",
    "content": "# Records v2\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/39>\n\nIn the past we've thought about records as a feature to enable working with data.\n\n\"Working with data\" is a big group with a number of facets, so it may be interesting to look at\neach in isolation. Let's start by looking at an example of records today and some of its drawbacks.\n\nFor instance, a simple record would be defined today as follows\n\n```C#\npublic class UserInfo\n{\n    public string Username { get; set; }\n    public string Email { get; set; }\n    public bool IsAdmin  { get; set; } = false;\n}\n```\n\nand the usage would read\n\n```C#\nvoid M()\n{\n    var userInfo = new UserInfo() \n    {\n        Username = \"andy\",\n        Email = \"angocke@microsoft.com\",\n        IsAdmin = true\n    };\n}\n```\n\nThere are significant advantages in this code:\n\n1. The definition is version resilient, properties can easily be added or moved\n2. Properties can be set in any order, and the names in the initialization always\n   match the accessors\n3. Properties with default values can simply be skipped\n\nThe first flaw is that the properties must now be mutable.\n\n# Mutability\n\nWhat we'd like is for C# to provide a way to set a `readonly` member in object initializers.\nSince some types may not have been designed with this initialization in mind, we'd also like\nit to be opt-in.\n\nThe proposed solution is a new modifier, `initonly`, that can be applied to\nproperties and fields:\n\n```C#\npublic class UserInfo\n{\n    public initonly string Username { get; }\n    public initonly string Email { get; }\n    public initonly bool IsAdmin { get; } = false;\n}\n```\n\nThe codegen for this is surprisingly straight forward: we just set the readonly field.\nSpecifically, the lowered properties would look like:\n\n```C#\npublic class UserInfo\n{\n    private readonly string <Backing>_username;\n    public string get_Username() => <Backing>_username;\n    [return: modreq(initonly)]\n    public void set_Username(string value) { <Backing>_username = value; }\n    ...\n}\n```\n\nThe CLR considers setting readonly fields to be unverifiable, but not unsafe. To support\na more advanced verifier, the following rule is proposed: a readonly field can be modified\nonly inside `initonly` methods, or on a new object that is on the CLR stack and has not been\npublished via a store or method call.\n\nThis should solve many of the problems with mutability in the `UserInfo` example, while not\nrequiring complicated or brittle emit strategies. However, immutability does present a new\nproblem: easily constructing an object with changes.\n\n# With-ing\n\nWhen programming with immutability, making changes to an object is done by constructing a\ncopy with changes instead of making the changes directly on the object. Unfortunately, there's\nno convenient way to do this in C#, even with current-style records. It's been previously\nproposed that some kind of autogenerated \"With\" method be provided for records that implements\nthat functionality. If we have such a mechanism, it's important that it work with `initonly`\nmembers. To achieve this, it's proposed that we add a `with` expression, analogous to an object\ninitializer. Sample usage would be as follows:\n\n```C#\nvar userInfo = new UserInfo() \n{\n    Username = \"andy\",\n    Email = \"angocke@microsoft.com\",\n    IsAdmin = true\n};\nvar newUserName = userInfo with { Username = \"angocke\" };\n```\n\nThe resulting `newUserName` object would be a copy of `userInfo`, with `Username` set to \"angocke\".\nThe codegen on the `with` expression would also be similar to the object initializer: a new object\nis constructed, and then the `initonly` `Username` setter would be called in the method body.\n\nOf course, the difference here is that the new object being constructed is not a simple new object\ncreation, it is a duplicate of the original object. To provide this functionality, we require that\nthe object provide a \"With constructor\" that provides a duplicate object. A sample `With` constructor\nwould look like:\n\n```C#\nclass UserInfo\n{\n    ...\n    [WithConstructor] // placeholder syntax, up for debate\n    public UserInfo With()\n    {\n        return new UserInfo() { Username = this.Username, Email = this.Email, IsAdmin = this.IsAdmin };\n    }\n}\n```\n\nNotably, the `with` expression will set `initonly` members, just like the object initializer, so to\nsupport verification we must ensure that the object cannot have been published before the `initonly`\nmembers are set. To enforce this, the `WithConstructor` attribute (or equivalent syntax) will enforce\na new rule for the method: all return statements must directly contain an object creation expression,\npossibly with an object initializer.\n\nIf the `With` constructor requires validation, the user may introduce a constructor to do that validation,\ne.g.\n\n```C#\nclass UserInfo\n{\n    ...\n    private UserInfo(UserInfo original)\n    {\n        // validation code\n    }\n    [WithConstructor]\n    public UserInfo With() => new UserInfo(this);\n}\n```\n\nThe last piece of complexity associated with `With` is inheritance. If your record is extensible, you\nwill need to provide a new `With` for the subclass. This can be achieved as follows:\n\n```C#\nclass Base\n{\n    ...\n    protected Base(Base original)\n    {\n        // validation\n    }\n    [WithConstructor]\n    public virtual Base With() => new Base(this);\n}\nclass Derived : Base\n{\n    ...\n    protected Derived(Derived original)\n    : base(original)\n    {\n        // validation\n    }\n    [WithConstructor]\n    public override Derived With() => new Derived(this);\n}\n```\n\nNote one additional piece of complexity here: in order to override the `With` constructor with\nthe derived type the language will also need to support covariant return types in overrides.\nThere is already a separate proposal for this feature\n[here](https://github.com/dotnet/csharplang/blob/725763343ad44a9251b03814e6897d87fe553769/proposals/covariant-returns.md).\n\n**Drawbacks**\n\n- Making all return statements in `WithConstructor`s contain new object expressions is restrictive.\n  This could be possibly be mitigated by flow analysis that ensures the new object doesn't escape\n  the method\n- Supporting variance in overrides through compiler tricks will require stub methods, which will\n  grow quadratically with the inheritance depth. The need for a stub method is due to a runtime\n  requirement that override signatures match exactly. If the runtime requirement were loosened,\n  the stub methods would not be required at all.\n- Using chained constructors of the form `Type(Type original)` effectively reserves that constructor\n  for the use of the pattern. Since constructors have unique semantics and cannot be re-named this\n  could be limiting.\n\n\n## Wrapping it all up: Records\n\nThe above features enable a style of programming that was very difficult before. But even with\nthe new features it could be quite verbose and error prone to annotate everything yourself. There\nare also a few items, like Equals and GetHashCode, which can already be written today, it's just laborious.\nMoreover, a significant flaw in implementing equality on top of these new primitives is that\nstructural equality is something that should change with your data type as new data is added, but\nwhen handling it manually it is likely that these things can get out of sync.\n\nTherefore, it is proposed that C# support new syntax for records, not for providing new features,\nbut for setting defaults and generating code designed for use in records. Example syntax would\nlook like\n\n```C#\ndata class UserInfo\n{\n    public string Username { get; }\n    public string Email { get; }\n    public bool IsAdmin { get; } = false;\n}\n```\n\nThe generated code for this class would regard all public fields and auto-properties as structural\nmembers of the record. Record members could be customized using a new `RecordMember(bool)` attribute\nthat could be used to either include or exclude members. Record members would be `initonly` by default\nand equality would be autogenerated for the class based on the record members. At any point the behavior\nof these members could be customized simply by declaring them in source. The user-written implementation\nwould replace the default implementation in all pattern usage.\n\nNote that equality in the face of inheritance is complex, but seems to have been\nadequately solved in the [other records proposal](records.md).\n\n## Primary constructors\n\nPrevious record proposal have also included a new syntax for a parameter list on the type itself, e.g.\n\n```C#\nclass Point(int X, int Y);\n```\n\nIn the new design, the parameter list would be an orthogonal C# feature, which could be cleanly integrated\nwith records. If a primary constructor is included in a record, it would have new defaults, just like\npublic fields and auto-properties: the parameters in the primary constructor would be used to generate\npublic record-member properties with the same name. In addition, the primary constructor could now be\nused to auto-generate a deconstructor.\n\nFor example, the following record with a primary constructor\n\n```C#\ndata class Point(int X, int Y);\n```\n\nwould be equivalent to\n\n```C#\ndata class Point\n{\n    public int X { get; }\n    public int Y { get; }\n\n    public Point(int x, int y)\n    {\n        X = x;\n        Y = y;\n    }\n\n    public void Deconstruct(out int X, out int Y)\n    {\n        X = this.X;\n        Y = this.Y;\n    }\n}\n```\n\nand the final generation of the above would be\n\n```C#\nclass Point\n{\n    public initonly int X { get; }\n    public initonly int Y { get; }\n\n    public Point(int x, int y)\n    {\n        X = x;\n        Y = y;\n    }\n\n    protected Point(Point other)\n    : this(other.X, other.Y)\n    { }\n\n    [WithConstructor]\n    public virtual Point With() => new Point(this);\n\n    public void Deconstruct(out int X, out int Y)\n    {\n        X = this.X;\n        Y = this.Y;\n    }\n\n    // Generated equality\n}\n```\n\nNote that we've taken one other piece of information into account\nfor a data class with a primary constructor: instead of setting\nthe primary fields inside the generated protected constructor, we delegate\nto the primary constructor. If the Point class had another non-primary\nrecord member, e.g.\n\n```C#\ndata class Point(int X, int Y)\n{\n    public int Z { get; }\n}\n```\n\nthen that would change the generated protected constructor as follows:\n\n```C#\nclass Point\n{\n    // ...\n    protected Point(Point other)\n    : this(other.X, other.Y)\n    {\n        Z = other.Z;\n    }\n    // ...\n}\n```\n\nNotably, this doesn't answer what to do about inheritance of records\nwith primary constructors. For instance,\n\n```C#\ndata class A(int X, int Y);\ndata class B(int X, int Y, int Z) : A;\n```\n\nRather than resolving in an arbitrary manner, a more explicit approach\ncould require that a parameter list be provided with the base list, e.g.\n\n```C#\ndata class A(int X, int Y);\ndata class B(int X, int Y, int Z) : A(X, Y);\n```\n\nThe parameter list in the base list would then be applied to a `base` call\nin the generated primary constructor:\n\n```C#\nclass B\n{\n    // ..\n    public B(int x, int y, int z)\n    : base(x, y)\n    // ..\n}\n```\n\nAs for what a primary constructor could mean outside of a record, that is still open to further proposal.\n"
  },
  {
    "path": "proposals/rejected/self-constraint.md",
    "content": "# Self constraint for generic type parameters\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/5413>\n\n## Summary\n[summary]: #summary\n\nA single generic type parameter on a given interface declaration can be specified to be the `self type` and the corresponding type argument must be a type that implements the interface. In addition, a type implementing any constructed form of the interface directly (not through its base class), must use itself as a type argument for the self type type parameter in that constructed form.\n\n## Motivation\n[motivation]: #motivation\n\nWhen dealing with static abstracts in interfaces for operator declarations, the interface must currently declare one of the generic type parameters to have a recursive constraint:\n```csharp\ninterface IAdditionOperators<TSelf, TOther, TResult>\n    where TSelf : IAdditionOperators<TSelf, TOther, TResult>\n{\n    static abstract TResult operator +(TSelf left, TOther right);\n}\n```\n\nThis recursive constraint allows the language to infer that the constrainted type parameter is the implementing type and therefore that the `operator` will meet the C# requirement that at least one of the types participating in the operator signature be the declaring type.\n\nHowever, this rule breaks down somewhat when going outside operators:\n```csharp\ninterface IAdditiveIdentity<TSelf>\n    where TSelf : IAdditiveIdentity<TSelf>\n{\n    static abstract TSelf AdditiveIdentity { get; }\n}\n```\n\nIn the above example, even though the intent here is the same as for operators, it is perfectly legal for a user to define and implement `struct S : IAdditiveIdentity<int> { ... }` assuming that `int` also implements `IAdditiveIdentity<int>`.\n\nThis also hinders various usages of `static abstracts in interfaces` in that there is no way to provide the underlying `constraint` token required for the emitted call and so users in the C# 10 preview must declare their own wrapper methods to handle the transition.\n\nFor example, say a user explicitly implements an interface:\n```csharp\ninterface IAdditiveIdentity<TSelf>\n    where TSelf : IAdditiveIdentity<TSelf>\n{\n    static abstract TSelf AdditiveIdentity { get; }\n}\n\npublic struct Half : IAdditiveIdentity<Half>\n{\n    public Half IAdditiveIdentity<Half>.AdditiveIdentity { get; }\n}\n```\n\nFor non-static abstract members, this can be invoked simply by utilizing the interface `((ISomeInterface)value).SomeMethod()`. While for `static abstracts` there is no current equivalent and users must instead declare a wrapper method:\n```csharp\ninternal static T GetAdditiveIdentity<T>()\n    where T : IAdditiveIdentity<T>\n{\n    return T.AdditiveIdentity;\n}\n```\n\nThis allows them to then call `GetAdditiveIdentity<Half>()` to achieve the desired result. However, this is verbose and becomes unnecessary with a proper `self constraint` which would allow `IAdditiveIdentity<Half>.AdditiveIdentity` to correctly resolve to the implementation of `Half.AdditiveIdentity`, whether implicitly or explicitly implemented.\n\n## Detailed design\n[design]: #detailed-design\n\nThe following syntax would become valid:\n```csharp\ninterface IAdditionOperators<this TSelf, TOther, TResult>\n{\n    static abstract TResult operator +(TSelf left, TOther right);\n}\n\ninterface IAdditiveIdentity<this TSelf>\n{\n    static abstract TSelf AdditiveIdentity { get; }\n}\n```\n\nThis would cause the constraint for the `TSelf` generic type parameter to have a `modreq` emitted (similarly to how the `modreq` for the `unmanaged` constraint works) that indicates it is the \"self type\" as well as the standard recursive constraint that was already being declared beforehand. The language can then depend on this information when interacting with the interface and know, for example, that `IAdditionOperators<int, TOther, TResult>` should resolve to the corresponding APIs exposed on `int`.\n\nOnly a single generic-type parameter would be allowed to be annotated as the `self type` as there is no reason for two types representing the same contract.\n\nThe self-constrained type argument must still be specified at the use site. That is the user must still fully specify `struct Half : IAdditiveIdentity<Half>` and could not choose to elide or otherwise not specify `<Half>`.\n\n** TODO: Insert list of actual spec changes required here **\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nThe new syntax may be confusing to some users as the constraint is now specified in a different location.\n\nUtilizing the new syntax would be a breaking change for existing types and so you could not, for example, modify `System.IEquatable<T>` to be `System.IEquatable<this T>`.\n\n## Alternatives\n[alternatives]: #alternatives\n\nConsider exposing the constraint in a different manner such as:\n```csharp\ninterface IAdditiveIdentity<TSelf>\n    where TSelf : this\n{\n    static abstract TSelf AdditiveIdentity { get; }\n}\n```\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\nShould you be able to place additional constraints on the `self` type? For example, would `this TSelf` and `where TSelf : this, struct` be valid if you only wanted the interface to be implementable by struct types?\n\nDoes this need to be a `modopt` (or `modreq`?) or can it be expressed in some way such that existing types can \"move forward\" if they have existing scenarios where this was the intended contract?\n\nHow does this play into variance for classes and possible eventual support for static abstracts in classes? Would variance conversions between interface types lead to a loss of information in some way or another? Etc.\n\nWould a proper self constraint allow a simpler model for encoding the `call` in IL? That is, if the runtime also supports a proper self constraint then rather than requiring ``constrained. !!T call !0 class IAdditiveIdentity`1<!!T>.get_AdditiveIdentity()`` it could simply support ``call !0 class IAdditiveIdentity`1<!!T>.get_AdditiveIdentity()``.\n\nCould the self type be represented as an associated type rather than as a type parameter to an interface?\n\nObligatory general syntax questions: should we use a keyword other than `this`? Should the keyword go where the proposal puts it, or with the rest of the type constraints?\n\n## Design meetings\n\n<!-- Link to design notes that affect this proposal, and describe in one sentence for each what changes they led to. -->\n"
  },
  {
    "path": "proposals/rejected/static-delegates.md",
    "content": "# Static Delegates (superseded by [../csharp-9.0/function-pointers.md](../csharp-9.0/function-pointers.md))\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/302>\n\n## Summary\n[summary]: #summary\n\nProvide a general-purpose, lightweight callback capability to the C# language.\n\n## Motivation\n[motivation]: #motivation\n\nToday, users have the ability to create callbacks using the `System.Delegate` type. However, these are fairly heavyweight (such as requiring a heap allocation and always having handling for chaining callbacks together).\n\nAdditionally, `System.Delegate` does not provide the best interop with unmanaged function pointers, namely due being non-blittable and requiring marshalling anytime it crosses the managed/unmanaged boundary.\n\nWith a few minor tweaks, we could provide a new type of delegate that is lightweight, general-purpose, and interops well with native code.\n\n## Detailed design\n[design]: #detailed-design\n\nOne would declare a static delegate via the following:\n\n```C#\nstatic delegate int Func()\n```\n\nOne could additionally attribute the declaration with something similar to `System.Runtime.InteropServices.UnmanagedFunctionPointer` so that the calling convention, string marshalling, and set last error behavior can be controlled. NOTE: Using `System.Runtime.InteropServices.UnmanagedFunctionPointer` itself will not work, as it is only usable on Delegates.\n\nThe declaration would get translated into an internal representation by the compiler that is similar to the following\n\n```C#\nstruct <Func>e__StaticDelegate\n{\n    IntPtr pFunction;\n\n    static int WellKnownCompilerName();\n}\n```\n\nThat is to say, it is internally represented by a struct that has a single member of type `IntPtr` (such a struct is blittable and does not incur any heap allocations):\n* The member contains the address of the function that is to be the callback.\n* The type declares a method matching the method signature of the callback.\n* The name of the struct should not be user-constructible (as we do with other internally generated backing structures).\n * For example: fixed size buffers generate a struct with a name in the format of `<name>e__FixedBuffer` (`<` and `>` are part of the identifier and make the identifier not constructible in C#, but still useable in IL).\n* The name of the method declaration should be a well known name used across all static delegate types (this allows the compiler to know the name to look for when determining the signature).\n\nThe value of the static delegate can only be bound to a static method that matches the signature of the callback.\n\nChaining callbacks together is not supported.\n\nInvocation of the callback would be implemented by the `calli` instruction.\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nStatic Delegates would not work with existing APIs that use regular delegates (one would need to wrap said static delegate in a regular delegate of the same signature).\n* Given that `System.Delegate` is represented internally as a set of `object` and `IntPtr` fields (http://source.dot.net/#System.Private.CoreLib/src/System/Delegate.cs), it would be possible to allow implicit conversion of a static delegate to a `System.Delegate` that has a matching method signature. It would also be possible to provide an explicit conversion in the opposite direction, provided the `System.Delegate` conformed to all the requirements of being a static delegate.\n\nAdditional work would be needed to make Static Delegate readily usable in the core framework.\n\n## Alternatives\n[alternatives]: #alternatives\n\nTBD\n\n## Unresolved questions\n[unresolved]: #unresolved-questions\n\nWhat parts of the design are still TBD?\n\n## Design meetings\n\nLink to design notes that affect this proposal, and describe in one sentence for each what changes they led to.\n\n\n"
  },
  {
    "path": "proposals/relaxed-partial-ref-ordering.md",
    "content": "# Relaxed ordering for `partial` and `ref` modifiers\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9804\n\n## Summary\n[summary]: #summary\n\n- https://github.com/dotnet/csharplang/issues/946\n- https://github.com/dotnet/csharplang/blob/main/meetings/2020/LDM-2020-09-09.md#champion-relax-ordering-constraints-around-ref-and-partial-modifiers-on-type-declarations\n\nAllow the `partial` modifier to appear in any position in a modifier list on a type or member declaration.  \nAllow the `ref` modifier to appear in any position in a modifier list on a struct declaration.\n\n```cs\n// All errors in this sample would be removed by adopting the proposal:\ninternal partial class C { }\npartial internal class C { } // error\n\ninternal ref struct RS { }\nref internal struct RS { } // error\n\ninternal ref partial struct RS { }\ninternal partial ref struct RS { } // error\npartial ref internal struct RS { } // error\n\npartial class Program\n{\n    public partial Program();\n    partial public Program() { } // error\n\n    public partial int Prop { get; set; }\n    partial public int Prop { get => field; set; } // error\n\n    public partial void Method();\n    partial public void Method() { } // error\n\n    partial public event Action Event; // error\n    public partial event Action Event { add { } remove { } }\n}\n```\n\n## Motivation\n[motivation]: #motivation\n\nMost modifiers in the language can be written in any order. It feels arbitrary that `partial` and `ref` use a more stringent rule, and need to come at the end of the modifier list. This is especially cumbersome in the case of `ref partial` on structs, where even the opposite order `partial ref` is not permitted.\n\nIn order to avoid getting in the user's way needlessly, we should allow `partial` and `ref` modifiers to appear in any position in a modifier list, just like the other modifiers.\n\n## Detailed design\n[design]: #detailed-design\n\nNote that some of the below grammars are from C# 7 and are missing more recent modifiers such as `required` and `file`.  \nSince we have a precedent for contextual keywords `required` and `file` being modifiers, we believe we know how to parse `partial` as a modifier in any valid position it could appear in.\n\nThe method grammar [(§15.6.1)](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/classes.md#1561-general) is updated as follows:\n\n```diff\n method_modifiers\n-    : method_modifier* 'partial'?\n+    : method_modifier*\n     ;\n\n method_modifier\n     : ref_method_modifier\n     | 'async'\n     ;\n\n ref_method_modifier\n     : 'new'\n     | 'public'\n     | 'protected'\n     | 'internal'\n     | 'private'\n     | 'static'\n     | 'virtual'\n     | 'sealed'\n     | 'override'\n     | 'abstract'\n     | 'extern'\n+    | 'partial'\n     | unsafe_modifier   // unsafe code support\n     ;\n```\n\nThe property grammar [(§15.7.1)](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/classes.md#1571-general) is updated as follows:\n\n```diff\nproperty_declaration\n-    : attributes? property_modifier* 'partial'? type member_name property_body\n+    : attributes? property_modifier* type member_name property_body\n    ;\n\n property_modifier\n     : 'new'\n     | 'public'\n     | 'protected'\n     | 'internal'\n     | 'private'\n     | 'static'\n     | 'virtual'\n     | 'sealed'\n     | 'override'\n     | 'abstract'\n     | 'extern'\n+    | 'partial'\n     ;\n```\n\nThe event grammar [(§15.8.1)](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/classes.md#1581-general) is updated as follows:\n\n```diff\n event_declaration\n-    : attributes? event_modifier* 'partial'? 'event' type variable_declarators ';'\n+    : attributes? event_modifier* 'event' type variable_declarators ';'\n-    | attributes? event_modifier* 'partial'? 'event' type member_name\n+    | attributes? event_modifier* 'event' type member_name\n         '{' event_accessor_declarations '}'\n     ;\n\n event_modifier\n     : 'new'\n     | 'public'\n     | 'protected'\n     | 'internal'\n     | 'private'\n     | 'static'\n     | 'virtual'\n     | 'sealed'\n     | 'override'\n     | 'abstract'\n     | 'extern'\n+    | 'partial'\n     | unsafe_modifier   // unsafe code support\n     ;\n```\n\nThe indexer grammar [(§15.9.1)](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/classes.md#1591-general) is updated as follows:\n\n```diff\nindexer_declaration\n-    : attributes? indexer_modifier* 'partial'? indexer_declarator indexer_body\n+    : attributes? indexer_modifier* indexer_declarator indexer_body\n-    | attributes? indexer_modifier* 'partial'? ref_kind indexer_declarator ref_indexer_body\n+    | attributes? indexer_modifier* ref_kind indexer_declarator ref_indexer_body\n    ;\n\n indexer_modifier\n     : 'new'\n     | 'public'\n     | 'protected'\n     | 'internal'\n     | 'private'\n     | 'virtual'\n     | 'sealed'\n     | 'override'\n     | 'abstract'\n     | 'extern'\n+    | 'partial'\n     | unsafe_modifier   // unsafe code support\n     ;\n```\n\nInstance constructor declaration syntax [(§15.11.1)](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/classes.md#15111-general) is updated as follows:\n\n```diff\n constructor_declaration\n-    : attributes? constructor_modifier* 'partial'? constructor_declarator constructor_body\n+    : attributes? constructor_modifier* constructor_declarator constructor_body\n     ;\n\n constructor_modifier\n     : 'public'\n     | 'protected'\n     | 'internal'\n     | 'private'\n     | 'extern'\n+    | 'partial'\n     | unsafe_modifier   // unsafe code support\n     ;\n```\n\nThe classes grammar [(§15.2.1)](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/classes.md#1521-general) is updated as follows:\n\n```diff\n class_declaration\n-    : attributes? class_modifier* 'partial'? 'class' identifier\n+    : attributes? class_modifier* 'class' identifier\n         type_parameter_list? class_base? type_parameter_constraints_clause*\n         class_body ';'?\n     ;\n\n class_modifier\n     : 'new'\n     | 'public'\n     | 'protected'\n     | 'internal'\n     | 'private'\n     | 'abstract'\n     | 'sealed'\n     | 'static'\n+    | 'partial'\n     | unsafe_modifier   // unsafe code support\n     ;\n```\n\nThe interfaces grammar [(§18.2.1)](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/interfaces.md#1821-general) is updated as follows:\n\n```diff\n interface_declaration\n-    : attributes? interface_modifier* 'partial'? 'interface'\n+    : attributes? interface_modifier* 'interface'\n       identifier variant_type_parameter_list? interface_base?\n       type_parameter_constraints_clause* interface_body ';'?\n     ;\n\n interface_modifier\n     : 'new'\n     | 'public'\n     | 'protected'\n     | 'internal'\n     | 'private'\n+    | 'partial'\n     | unsafe_modifier   // unsafe code support\n     ;\n```\n\nThe structs grammar [(§18.2.1)](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/structs.md#1621-general) is updated as follows:\n\n```diff\n struct_declaration\n-    : attributes? struct_modifier* 'ref'? 'partial'? 'struct'\n+    : attributes? struct_modifier* 'struct'\n       identifier type_parameter_list? struct_interfaces?\n       type_parameter_constraints_clause* struct_body ';'?\n     ;\n```\n\n```diff\n struct_modifier\n     : 'new'\n     | 'public'\n     | 'protected'\n     | 'internal'\n     | 'private'\n     | 'readonly'\n+    | 'ref'\n+    | 'partial'\n     | unsafe_modifier   // unsafe code support\n     ;\n```\n\n## Drawbacks\n[drawbacks]: #drawbacks\n\nN/A\n\n## Alternatives\n[alternatives]: #alternatives\n\nWe could decide that we don't want to change this. In that case, the next time we spec allowing a new declaration kind to be `partial` or `ref`, we won't have to spend time thinking about whether now is the time to remove the ordering restriction.\n\n## Open questions\n[open]: #open-questions\n\nN/A\n"
  },
  {
    "path": "proposals/speclet-disclaimer.md",
    "content": "> [!NOTE]\n> This article is a feature specification. The specification serves as the design document for the feature. It includes proposed specification changes, along with information needed during the design and development of the feature. These articles are published until the proposed spec changes are finalized and incorporated in the current ECMA specification.\n>\n> There may be some discrepancies between the feature specification and the completed implementation. Those differences are captured in the pertinent [language design meeting (LDM) notes](https://github.com/dotnet/csharplang/tree/main/meetings).\n>\n> You can learn more about the process for adopting feature speclets into the C# language standard in the article on the [specifications](https://learn.microsoft.com/dotnet/csharp/specification/feature-spec-overview).\n"
  },
  {
    "path": "proposals/standard-unions.md",
    "content": "# Standard Unions\n\n## Summary\n\nA family of nominal type unions exist in the *TBD* namespace that can be used across assemblies as the standard way to specify a type union without needing to declare and name one.\n\n```csharp\npublic union Union<T1, T2>(T1, T2);\npublic union Union<T1, T2, T3>(T1, T2, T3);\npublic union Union<T1, T2, T3, T4>(T1, T2, T3, T4);\n...\n\nUnion<int, string> x = 10;\n...\nvar _ = x switch \n{\n    int v => ...,\n    string v => ...\n}\n```\n\n## Detailed Design\n\n* A small number of generic nominal type unions named `Union` are added to a runtime library.\n* The union are declared using the *Nominal Type Union* syntax and generated by the C# compiler.\n\n### Runtime Library\n\nThe union types are added to the same assembly that houses the `ValueTuple`, `Func` and `Action` types. \n"
  },
  {
    "path": "proposals/target-typed-generic-type-inference.md",
    "content": "# Target-typed generic type inference\n\n## Summary\n\nGeneric type inference may take a target type into account. For instance, given:\n\n```csharp\npublic class MyCollection\n{\n    public static MyCollection<T> Create<T>() { ... }\n}\npublic class MyCollection<T> : IEnumerable<T> { ... }\n```\n\nWe would allow the `Create` method to be called without type argument when it can be inferred from a target type:\n\n```csharp\nIEnumerable<string> c = MyCollection.Create(); // 'T' = 'string' inferred from target type\n```\n\n## Motivation\n\nGeneric factory methods often need explicit type arguments, even when the information is clear from context; i.e. from the target type. That's because generic type inference only takes arguments into account, not target types.\n\nThis would also make generic type inference a more helpful addition in non-method situations, as proposed for [constructor calls](https://github.com/dotnet/csharplang/blob/main/proposals/inference-for-constructor-calls.md) and [type patterns](https://github.com/dotnet/csharplang/blob/main/proposals/inference-for-type-patterns.md). Specifically, [union types](https://github.com/dotnet/csharplang/blob/main/proposals/nominal-type-unions.md) and [closed classes](https://github.com/dotnet/csharplang/blob/main/proposals/closed-hierarchies.md) would benefit from this, as they are frequently a target type when case types are constructed or matched.\n\n## Detailed design\n\nGeneric type inference currently has a [first phase](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12632-the-first-phase) that consists of collecting \"bounds\" on type parameters based on comparing each parameter type with its corresponding incoming argument. A second phase then uses the collected bounds for each type parameter to infer the corresponding type argument, if possible.\n\nThis proposal adds to the first phase a facility for also collecting bounds by comparing the generic method's *return type* with the *target type* for the invocation, if one exists (new text in **bold**):\n\n> For each of the method arguments `Eᵢ`, an input type inference ([§12.6.3.7](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12637-input-type-inferences)) is made from `Eᵢ` to the corresponding parameter type `Tᵢ`.\n>\n> **Additionally, if the invocation has a target type `T`, then an *upper-bound inference* ([§12.6.3.12](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#126312-upper-bound-inferences)) is made from `T` to `Tₑ`.**\n\nHere `Tₑ`, introduced [earlier in the section](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12631-general), refers to the return type of the generic method being invoked.\n\nNote that, unlike arguments, which generally introduce a *lower bound* on a parameter type (or an *exact bound* when the parameter is e.g. a `ref` parameter), a target type introduces an *upper bound* on the return type. Intuitively, type inference must pick type arguments to make sure that each parameter type is \"big enough\" for its argument to fit, while (with this proposal) the return type is \"small enough\" to fit the target type.\n\n## Example\n\nIn the `MyCollection` example above, an *upper-bound inference* will be made from the target type `IEnumerable<string>` to the return type of the method, `MyCollection<T>`. Because `IEnumerable<out T>` is \"covariant\" in `T`, this recursively leads to an *upper-bound inference* from `string` to `T`, which puts an *upper bound* `string` on the type parameter `T` itself. When `T` is \"fixed\" in the second phase, `string` is the only bound on it, and becomes the inferred type argument for `T`.\n\n## Open questions\n\n- This is probably a breaking change! Certainly, like all improvements to type inference, it may cause new candidates to succeed, leading to ambiguity or to the new candidate to be picked. Additionally it may change what is inferred for already-successful candidates, or even thwart the inference completely. However, consider that if a target type causes such a change in the inference of a type parameter, it is likely because the current inference result - without the target type - would cause a subsequent type error in assignment to the target! So perhaps the break isn't as bad, but of course it needs to be investigated!\n\n## Implementation considerations\n\nThe point of this section is to argue that the proposal is probably not expensive from an implementation point of view. The argument is somewhat gnarly, and can be safely skipped for the purposes of just understanding the proposal at the language level.\n\nThe type inference machinery required for this feature is all already there in the compiler. To see this, we can systematically \"map\" examples such as `MyCollection<T>` to code for which the inference works today. \n\nWe're going to rewrite the `Create` method - the one that we want to do type inference for - into one that doesn't return its result, but instead passes it to a `Receptacle<T>` delegate: an extra optional parameter that can receive the result:\n\n```csharp\n    //public static MyCollection<T> Create<T>() { ... ; return result; }\n    public static void Create<T>(Receptacle<MyCollection<T>>? use = null!) { ... ; use?.Invoke(result); }\n```\n\n`Receptacle<T>` is a delegate type that is *contravariant* in `T`:\n\n```csharp\npublic delegate void Receptacle<in T>(T value);\n```\n\n(Incidentally, `Receptacle<T>` is identical to `Action<T>`.)\n\nAt the point of inference, instead of assigning the result of `Create` to the fresh variable `c`, we need to create a `Receptacle` for the variable:\n\n```csharp\n// IEnumerable<string> c = MyCollection.Create();\nIEnumerable<string> c;\nReceptacle<IEnumerable<string>> set_c = value => c = value;\n```\n\nNow we're ready to call our modified `Create` method, passing in the `Receptacle` for `c`:\n\n```csharp\nMyCollection.Create(set_c); // 'T' = 'string' inferred from receptacle type\n```\n\nType inference succeeds with `T` = `string`!\n\nTo see that this is isomorphic to the inference in the proposed feature, let's follow type inference through the first couple of steps:\n\n1. The [first phase](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12632-the-first-phase) performs an *input type inference* from the argument `set_c` to the parameter type `Receptacle<MyCollection<T>>`.\n2. The [input type inference](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12637-input-type-inferences) performs a *lower-bound inference* from `set_c`'s type `Receptacle<IEnumerable<string>>` to the parameter type `Receptacle<MyCollection<T>>`.\n3. The [lower-bound inference](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#126311-lower-bound-inferences) matches up the `Receptacle<...>` on each side, and, because the type parameter of `Receptacle` is contravariant, performs an *upper-bound inference* from `IEnumerable<string>` to `MyCollection<T>`.\n\nAnd now we're at the point where this proposal begins: Performing an *upper-bound inference* from the target type to the return type. \n\nIn other words, the existence of contravariant type parameters in C# and their ability to \"flip the sign\" in type inference is how this expressiveness is already there. In fact, an alternative and equivalent (but more convoluted) way of specifying the proposal would be through such a mapping of the code in terms of the existing type inference machinery.\n"
  },
  {
    "path": "proposals/target-typed-static-member-access.md",
    "content": "# Target-typed static member access\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/9138>\n\nThanks to those who provided insight and input into this proposal, especially @CyrusNajmabadi!\n\n## Summary\n\nThis feature enables a type name to be omitted from static member access when it is the same as the target type.\n\nThis reduces construction and consumption verbosity for factory methods, nested derived types, enum values, constants, singletons, and other static members.\n\nBesides making existing types easier to use, this feature also opens the door so that when designing discriminated unions, the option is available to lower to nested derived types without compromising ease of construction and consumption.\n\n```cs\ntype.GetMethod(\"Name\", .Public | .Instance | .DeclaredOnly); // BindingFlags.Public | ...\n\nif (someString.Equals(\"Value\", .OrdinalIgnoreCase)) // StringComparison.OrdinalIgnoreCase\n    ...\n\ncontrol.ForeColor = .Red;    // Color.Red\nentity.InvoiceDate = .Today; // DateTime.Today\n\n// Production (static members on Option<int>)\nOption<int> option = condition ? .None : .Some(42);\n\n// Production (nested derived types)\nCustomResult result = condition ? new .Success(42) : new .Error(\"message\");\n\n// Consumption (nested derived types)\nreturn result switch\n{\n    .Success(var val) => val,\n    .Error => defaultVal,\n};\n\n[AttributeUsage(.Class | .Struct | .Interface | .Enum | .Delegate)]\nclass MyAttribute : Attribute;\n```\n\n## Motivation\n\nThis feature removes painful boilerplate, matches with industry trends, and responds to the community's steady interest in this feature in terms of discussions and upvotes.\n\nRepeating a full type name before each `.` can be redundant. This happens often enough that it would make sense to put the choice in developers' hands to avoid the redundancy. Today, there's no scalable workaround for the verbosity in the following example:\n\n```cs\npublic void M(Result<ImmutableArray<int>, string> result)\n{\n    switch (result)\n    {\n        case Result<ImmutableArray<int>, string>.Success(var array): ...\n        case Result<ImmutableArray<int>, string>.Error(var message): ...\n    }\n}\n```\n\nThis feature brings a dramatic quality-of-life improvement:\n\n```cs\npublic void M(Result<ImmutableArray<int>, string> result)\n{\n    switch (result)\n    {\n        case .Success(var array): ...\n        case .Error(var message): ...\n    }\n}\n```\n\nThe industry has already started moving in the same direction. The Swift, Dart, and Zig languages have all added the `.xyz` syntax with the same meaning as this proposal for C#, and Rust has an RFC proposing the same dotted syntax:\n\n- Swift calls it [implicit member expressions](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/expressions#Implicit-Member-Expression).\n- Dart calls it \"dot shorthands\" or [static access shorthand](https://github.com/dart-lang/language/blob/c31243942eacadcc1be8cf81016f758fe831b99c/working/3616%20-%20enum%20value%20shorthand/proposal-simple-lrhn.md).\n- Rust has an active RFC which calls it [path inference](https://github.com/rust-lang/rfcs/pull/3444).\n- Zig calls it [enum literals](https://ziglang.org/documentation/master/#Enum-Literals).\n\nThis feature also puts more options on the table for the design of discriminated unions by improving the ergonomics of nested derived types. This ergonomic improvement is worth doing anyway for the sake of existing types, but it also evens the playing field among the various lowering options for discriminated unions.\n\n## Detailed design\n\n### Basic expression\n\nThere is a new primary expression, _target-typed member binding expression_, which starts with `.` and is followed by an identifier: `.Xyz`. What makes it a target-typed member binding, rather than some other kind of member binding, is its location as a primary expression.\n\nIf this expression appears in a location where there is no target type, a compiler error is produced. Otherwise, this expression is bound in the same way as though the identifier had been qualified with the target type.\n\nTo determine whether there is a target type and what that target type is, the language adds an implicit _target-typed member binding conversion_, from _target-typed member binding expression_ to any type. The conversion succeeds regardless of the target type. This allows errors to be handled in binding after the conversion succeeds, such as not finding an accessible or applicable member with the given identifier, or such as the expression evaluating to an incompatible type. For example:\n\n```cs\nSomeTarget a = .A; // Same as SomeTarget.A, succeeds\nSomeTarget b = .B; // Same as SomeTarget.B, fails with accessibility error\nSomeTarget c = .C; // Same as SomeTarget.C, fails trying to assign `int` to `SomeTarget`\nSomeTarget d = .D; // Same as SomeTarget.D, succeeds via implicit conversion\nSomeTarget e = .E; // Same as SomeTarget.E, fails to locate a static member\n// etc\n\nclass SomeTarget\n{\n    public static SomeTarget A;\n    private static SomeTarget B;\n    public static int C;\n    public static string D;\n    public SomeTarget E;\n\n    public static implicit operator SomeTarget(string d) => ...\n}\n```\n\nThe fact that the conversion succeeds regardless of target type also enables [target-typing with invocations](#target-typing-with-invocations).\n\nThis is sufficient to allow this new construct to be combined with constructs which allow target-typing. For example:\n\n```cs\nSomeTarget a = condition ? .A : .D;\n```\n\nIf the resulting bound member is a constant, it may be used in locations which require constants, no differently than if it was qualified:\n\n```cs\nconst BindingFlags f = .Public;\n```\n\n### Pattern matching\n\nA core scenario for this proposal is to be able to match nested derived types without repeating the containing type name, which may be long especially with generics.\n\n```cs\npublic void M(Result<ImmutableArray<int>, string> result)\n{\n    switch (result)\n    {\n        case .Success(var array): ...\n        case .Error(var message): ...\n    }\n}\n```\n\nThis includes nested patterns:\n\n```cs\nexpr is { A: .Some(0) or .None }\n```\n\nAny type expression in a type pattern may begin with a `.`. It is bound as though it was qualified with the type of the expression or pattern being matched against. If such qualified access is permitted, the target-typed type pattern is permitted. If such qualified access is not permitted, the target-typed type pattern fails with the same message.\n\n### Target-typing with overloadable operators\n\nA core scenario for this proposal is using bitwise operators on flags enums. To enable this without adding arbitrary limitations, this proposal enables target-typing on the operands of overloadable operators.\n\n```cs\nGetMethod(\"Name\", .Public | .Static)\nMyFlags f = ~.None;\nif ((myFlags & ~.Mask) != 0) { ... }\n```\n\nOther target-typed expressions besides `.Xyz` will be able to benefit from this, such as `null`, `default` and `[]`. One exception to this target-typed `new`, which explicitly states that it may not appear as an operand of a unary or binary operator. If desired, we could lift this restriction so that it is not the odd one out:\n\n```cs\nPoint p = origin + new(50, 100);\n```\n\nThis is done by adding three new conversions: _unary operator target-typing conversion_, _binary operator target-typing conversion_, and _binary cross-operand target-typing conversion_.\n\nFor a unary operator expression such as `~e`, we define a new implicit _unary operator target-typing conversion_ that permits an implicit conversion from the unary operator expression to any type `T` for which there is a conversion-from-expression from `e` to `T`.\n\nFor a binary operator expression such as `e1 | e2`, we define a new implicit _binary operator target-typing conversion_ that permits an implicit conversion from the binary operator expression to any type `T` for which there is a conversion-from-expression from `e1` to `T` and/or from `e2` to `T`.\n\nFor _either operand_ of a binary operator expression such as `e1 | e2`, if one expression has a type `T` and the other expression does not have a type, and there is a conversion-from-expression from the typeless operand expression to `T`, we define a new implicit _binary cross-operand target-typing conversion_ that permits an implicit conversion from the typeless operand expression to `T`.\n\nTarget-typing from one operand to another is helpful in the following scenario:\n\n```cs\nM(BindingFlags.Public | .Static | .DeclaredOnly); // Succeeds\n\nM(.Public | .Static | .DeclaredOnly); // ERROR: overload resolution fails\n\nvoid M(BindingFlags p) => ...\nvoid M(string p) => ...\n```\n\n### Target-typing with invocations\n\nA core scenario for this proposal is calling factory methods. This enables the use of the feature with some of today's class and struct types.\n\n```cs\nSomeResult = .Error(\"Message\");\nOption<int> M() => .Some(42);\n```\n\nTo enable target-typing for the invoked expression within an invocation expression, a new conversion is added, _invocation target-typing conversion_.\n\nFor an invocation expression such as `e(...)` where the invoked expression `e` is a _target-typed member binding expression_, we define a new implicit _invocation target-typing conversion_ that permits an implicit conversion from the invocation expression to any type `T` for which there is a _target-typed member binding conversion_ from `e` to `Tₑ`.\n\nEven though the conversion always succeeds when the invoked expression `e` is a  _target-typed member binding expression_, further errors may occur if the invocation expression cannot be bound for any of the same reasons as though the _target-typed member binding expression_ was a non-target-typed expression, qualified as a member of `T`. For instance, the member might not be invocable, or might return a type other than `T`.\n\n### Target-typing after the `new` keyword\n\nA core scenario for this proposal is enable the `new` operator to look up nested derived types. This provides symmetry between production and consumption of values with class DUs and with today's type hierarchies based on nested derived classes or records.\n\n```cs\nnew .Case1(arg1, arg2)\n```\n\nThis balances the consumption syntax:\n\n```cs\ndu switch\n{\n    .Case1(var arg1, var arg2) => ...\n}\n```\n\nThis would continue to be target-typed static member access (since nested types are members of their containing type), which is distinct from target-typed `new` since a definite type is provided to the `new` operator.\n\nTODO: spec the conversion\n\n### Notes\n\nAs with target-typed `new`, targeting a nullable value type should access members on the inner value type:\n\n```cs\nPoint? p = new();  // Equivalent to: new Point()\nPoint? p = .Empty; // Equivalent to: Point.Empty\n```\n\nAs with target-typed `new`, overload resolution is not influenced by the presence of a target-typed static member expression. If overload resolution was influenced, it would become a breaking change to add any new static member to a type.\n\n```cs\nM(.Empty); // Overload ambiguity error\n\nvoid M(string p) { }\nvoid M(object p) { }\n```\n\nFinally, extension members are included in the lookup.\n\n### Factory containers\n\n#### Summary (factory containers)\n\nTarget-typed static members will be found on separate factory container types, for example:\n\n- `Option<ImmutableArray<int>> result = .Some([42]);` - Calls `Some<T>` on the nongeneric `Option` type\n- `SearchValues<char> separators = .Create(',', ';');` - Calls `Create(ReadOnlySpan<char>)` on the nongeneric `SearchValues` type\n- `Tensor<T> c = .Add(a, b);` - Calls `Add<T>` on the nongeneric `Tensor` type\n\nThis will happen automatically when the factory member is on a nongeneric sibling type with the same name. There is also an opt-in model to enable the same lookup in classes where the name does not match. For example:\n\n- `IEnumerable<int> numbers = .Range(1, 10);` - Calls `Range` on the `Enumerable` type\n- `IEqualityComparer<string> comparer = .OrdinalIgnoreCase;` - Calls `OrdinalIgnoreCase` on the `StringComparer` type\n- `IEqualityComparer<T> comparer = .Default;` - Calls `Default` on `EqualityComparer<T>`\n\nFor the above examples to work, the `IEnumerable<T>` interface definition would be decorated with an attribute referring to the `Enumerable` class, and the `IEqualityComparer<T>` interface definition would be decorated with an attribute referring to the `StringComparer` and `EqualityComparer<>` classes.\n\n#### Motivation (factory containers)\n\nA common .NET pattern for obtaining a value of some generic type is to call a factory method on a nongeneric type of the same name so that the type argument can be inferred. The core libraries follow this pattern. For example:\n\n- `KeyValuePair.Create<TKey, TValue>` to obtain a `KeyValuePair<TKey, TValue>`\n- `Task.FromResult<T>` to obtain a `Task<T>`\n- `Vector.Add<T>` to obtain a `Vector<T>`, along with many other factory methods for other operations.\n- `Tensor.Add<T>` to obtain a `Tensor<T>`, along with many other factory methods for other operations.\n- `Vector128.Add<T>` to obtain a `Vector128<T>`, along with many other factory methods for other operations.\n- `ImmutableArray.Create<T>` to obtain an `ImmutableArray<T>`\n- `Tuple.Create<T1, T2, ...>` to obtain a `Tuple<T1, T2, ...>`\n- `Channel.CreateBounded<T>` to obtain a `Channel<T>`\n- `SearchValues.Create(ReadOnlySpan<byte>)` to obtain a `SearchValues<byte>`, and overloads for `<char>` and `<string>`\n- `Expression.Lambda<TDelegate>` to obtain an `Expression<TDelegate>`\n\nThis pattern has wide uptake in community APIs as well. The SDK steers users in this direction with the [CA1000: Do not declare static members on generic types](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1000) rule.\n\nFollowing these patterns and warnings, existing `Option<T>` types should put their `.Some` factory method on a nongeneric class, `Option.Some<T>`. This enables generic type inference, so `Option.Some(42)` can be written.\n\nHowever, this means that the method `Option.Some<T>` does not exist. This would cause an odd asymmetry: in the core proposal, you'd be able to write `.None`, but not `.Some(val)`. The `None` member is on `Option<T>` because there are no type inference opportunities, in the same manner as `ImmutableArray<T>.Empty`. But the `Some` member is on nongeneric `Option`, not on `Option<T>`.\n\nThere is a clear relationship between `Option<T>` and `Option`, `KeyValuePair<TKey, TValue>` and `KeyValuePair`, `Task<T>` and `Task`, `ImmutableArray<T>` and `ImmutableArray`, `Tensor<T>` and `Tensor`. The relationship is clear both from the naming convention and due to the static members on the factory type that return instances of the generic type.\n\nThis doesn't always involve generics, either. There is a community request for `Color color = .Red;` to refer to `Colors.Red`. This requires forming an association between the [`Color` struct](https://learn.microsoft.com/en-us/dotnet/api/system.windows.media.color) and the [`Colors` class](https://learn.microsoft.com/en-us/dotnet/api/system.windows.media.colors).\n\nIt would be a lost opportunity not to make use of these clear relationships in order to make consumption more consistent.\n\nIn addition, if a separate proposal were to make `IEnumerable<T>` the target type of spreads and foreach, the syntax `foreach (var x in .Range(1, 10))` or `[.. .Repeat(1, 10)]` would just fall out.\n\n#### Detailed design (factory containers)\n\nAs a guiding principle, the outcome for the call site can be thought of as equivalent to static extension methods being provided on the generic type which directly call the factory member on the generic type. The specifics below are aimed at this equivalence.\n\nMember lookup for a _target-typed member binding expression_ would consider not just static members on the targeted type, but also _applicable factory members_, a subset of the static members of the target type's related _factory container types_.\n\nA type `F` serves as a _factory container type_ for another type `G` if `F` is explicitly referenced by a FactoryContainerAttribute on `G` as defined below, or implicitly if `F` has no type parameters of its own and `G` does have type parameters of its own, and they are both declared in the same module, and they are both declared in either the same containing type if any, or the same namespace if not.\n\nA member of a _factory container type_ is an _applicable factory member_ if it is static and the result of evaluating the member has an identity conversion to the target type. If the _target-typed member binding expression_ is the expression of an invocation expression, then the result of evaluating the invocation is considered instead, and any inferred type arguments in the invocation that appear in the return type will be inferred outside-in to match the target type. For example, `Option<short> opt = .Some(42)` will infer `Option.Some<short>`.\n\nThe filter of _applicable factory members_ means that `IEqualityComparer<string> comparer = .OrdinalIgnoreCase;` will work if `IEqualityComparer<T>` declares `[FactoryContainer(typeof(StringComparer))]`, but `IEqualityComparer<int> comparer = .OrdinalIgnoreCase;` will fail with an error that `.OrdinalIgnoreCase` cannot be found, rather than an error that it returns a comparer with an incompatible type.\n\nThis is the definition of the attribute that enables a type to use factory members in another type when constructed through target-typed static member access:\n\n```cs\nnamespace System.Runtime.CompilerServices;\n\n[AttributeUsage(.Class | .Struct | .Interface | .Enum | .Delegate, AllowMultiple = true, Inherited = false)]\npublic sealed class FactoryContainerAttribute(Type containerType) : Attribute\n{\n    public Type ContainerType { get; } = containerType;\n}\n```\n\nErrors will be produced in the following scenarios:\n\n- If the attribute is used in older language versions.\n- If the referenced type contains no members that could be _applicable factory members_ for any generic instantiation of the target type which are at least as accessible as the target type.\n\n#### Alternatives (factory containers)\n\nStatic extension methods would be able to achieve the same end goal of writing `.Some(42)` for `Option<T>` or `.Range(1, 10)` for `IEnumerable<int>` or `.OrdinalCompareCase` for `IEqualityComparer<string>`. This would not fall foul of the [CA1000: Do not declare static members on generic types](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1000) rule, since the extension method itself is not declared on the generic type.\n\nWhile this shows the power of combining the core proposal with static extension methods, there are scaling problems with using static extension methods to provide the missing consistency in consumption syntax.\n\n1. This would not be automatic out of the box. It would become best practice to declare static extension methods on your own types to enable the nicer consumption pattern. This would not be done consistently, and users would run into the inconsistencies.\n1. The core libraries would likely not be willing to declare such static extension methods for the core types. In general, they prefer not to bloat metadata by declaring simple forwarders to other methods.\n\n## Specification\n\n`'.' identifier type_argument_list?` is consolidated into a standalone syntax, `member_binding`, and this new syntax is added as a production of the [§12.8.7 Member access](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1287-member-access) grammar:\n\n```diff\n member_access\n-    : primary_expression '.' identifier type_argument_list?\n-    | predefined_type '.' identifier type_argument_list?\n-    | qualified_alias_member '.' identifier type_argument_list?\n+    : primary_expression member_binding\n+    | predefined_type member_binding\n+    | qualified_alias_member member_binding\n+    | member_binding\n     ;\n\n+member_binding\n+    '.' identifier type_argument_list?\n\n base_access\n-    : 'base' '.' identifier type_argument_list?\n+    : 'base' member_binding\n     | 'base' '[' argument_list ']'\n     ;\n\n null_conditional_member_access\n-    : primary_expression '?' '.' identifier type_argument_list?\n+    : primary_expression '?' member_binding\n       (null_forgiving_operator? dependent_access)*\n     ;\n\n dependent_access\n-    : '.' identifier type_argument_list?    // member access\n+    : member_binding            // member access\n     | '[' argument_list ']'     // element access\n     | '(' argument_list? ')'    // invocation\n     ;\n\n null_conditional_projection_initializer\n-    : primary_expression '?' '.' identifier type_argument_list?\n+    : primary_expression '?' member_binding\n     ;\n\n object_creation_expression\n-    : 'new' type '(' argument_list? ')' object_or_collection_initializer?\n-    | 'new' type object_or_collection_initializer\n+    : 'new' (type | member_binding) '(' argument_list? ')' object_or_collection_initializer?\n+    | 'new' (type | member_binding) object_or_collection_initializer\n     ;\n```\n\nTODO: clarify that `member_access` is only valid as a `member_binding` if a conversion exists which binds it. No conversion exists which binds `.A.B`, `.A?.B`, `.A->B`, `.A().B`, and so on, so they are not valid expressions. Similar statement needed about `object_creation_expression` with `member_binding` for `new .A().B`.\n\nTODO: disambiguation rule for `A ? . B ? . C : D`\n\nTODO: patterns\n\n## Limitations\n\nOne of the use cases this feature serves is production and consumption of values of nested derived types. But one consumption scenario that is left out of this improvement is `results.OfType<.Error>()`. It's not possible to target-type in this location because the `T` is not correlated with `results`. This problem would likely only be solvable in a general way with annotations that would need to ship with the `OfType` declaration.\n\nA new operator could solve this, such as `results.SelectNonNull(r => r as .Error?)`.\n\n## Drawbacks\n\n### Ambiguities\n\nThere are a couple of ambiguities, with [parenthesized expressions](#ambiguity-with-parenthesized-expression) and [conditional expressions](#ambiguity-with-conditional-expression). See each link for details.\n\n## Anti-drawbacks\n\nThere's been a separate request to mimic VB's `With` construct, allowing dotted access to the expression anywhere within the block:\n\n```cs\nwith (expr)\n{\n    .PropOnExpr = 42;\n    list.Add(.PropOnExpr);\n}\n```\n\nThis doesn't seem to be a popular request among the language team members who have commented on it. If we go ahead with the proposed target-typing for `.Name` syntax, this seals the fate of the requested `with` statement syntax shown here.\n\n## Alternatives\n\n#### Workaround: `using static`\n\nAs a mitigation, `using static` directives can be applied as needed at the top of the file or globally. This allows syntax such as `GetMethod(\"Name\", Public | Static)` today.\n\nThis comes with a severe limitation, however, in that it doesn't help much with generic types. If you import `Option<int>`, you can write `is Some`, but only for `Option<int>` and not `Option<string>` or any other constructed type.\n\nSecondly, the `using static` workaround suffers from lack of precedence. Anything in scope with the same name takes precedence over the member you're trying to access. For example, `case IBinaryOperation { OperatorKind: Equals }` binds to `object.Equals` and fails. The proposed syntax for this feature solves this with the leading `.`, which unambiguously shows that the identifier that follows comes from the target type, and not from the current scope.\n\nThird, the `using static` workaround is an imprecise hammer. It puts the names in scope in places where you might not want them. Imagine `var materialType = Slate;`: Maybe you thought this was an enum value in your roofing domain, but accidentally picked up a web color instead.\n\nThe `using static` approach has also not found broad adoption over fully qualifying. There are very low hit counts on grep.app and github.com for `using static System.Reflection.BindingFlags`.\n\n### Alternative: no sigil\n\nThe target-typed static member access feature benefits from the precision of the `.` sigil, but it does not require a sigil. Here's how the feature would look without a sigil:\n\n```cs\ntype.GetMethod(\"Name\", Public | Instance | DeclaredOnly); // BindingFlags.Public | ...\n\ncontrol.ForeColor = Red;          // Color.Red\nentity.InvoiceDate = Today;       // DateTime.Today\n\n// Production (static members on Option<int>)\nOption<int> option = condition ? None : Some(42);\n\n// Production (nested derived types)\nCustomResult result = condition ? new Success(42) : new Error(\"message\");\n\n// Consumption (nested derived types)\nreturn result switch\n{\n    Success(var val) => val,\n    Error => defaultVal,\n};\n```\n\nA sigil is strongly recommended for two reasons: user comprehension, and power.\n\nFirstly, the feature would be **harder to understand** without a sigil. The presence of `.` makes reading much more efficient. If no such marker is in place, it will slow down understanding of code, in both directions. Any identifier could suddenly be target-typing, and any existing occurrence of target-typing could change meaning with spooky action at a distance if conflicted names are imported, or defined in scope at some higher level.\n\nFor example, is `Instance` using target-typing? What about `Error`?\n\n```cs\npublic ResultCodes PerformTask()\n{\n    var methods = type.GetMethods(Instance);\n    // ...\n    return Error;\n}\n```\n\nImpossible to say without thinking through a lot of context. You'd have to know if there are any members named `Instance` or `Error` in the current class or base classes, or any containing classes and their base classes, or if there are any types in the namespace or in any imported namespaces named `Instance` or `Error`, or if any class is imported that has a static member named `Instance` or `Error`.\n\nHow about this? Is `ModifierKeys` ending up target-typed? Is `MaxValue`?\n\n```cs\nif (ModifierKeys == Keys.Control)\n{\n    Value = MaxValue;\n}\n```\n\nA sigil thus provides essential context. With a sigil, there is no longer any spooky action at a distance which changes the fundamental meaning of the expression.\n\n(The language has prior art in `default` and `new()`. In both cases, when the type is dropped, the remaining syntax cannot stand alone without a target type.)\n\nSecondly, the feature would become **less powerful** without a sigil. To avoid changes in meaning, this would have to prefer binding to other things in the current scope name, with target-typing as a fallback. This would result in unpleasant interruptions with no recourse other than typing out the full type name. These interruptions are expected to be frequent enough to hamper the success of the feature.\n\nThis specific sigil is a good fit with modern language sensibilities and audiences. The Swift, Dart, and Zig languages have all added the `.xyz` syntax with the same meaning as this proposal for C#, and Rust has an RFC proposing the same dotted syntax:\n\n- Swift calls it [implicit member expressions](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/expressions#Implicit-Member-Expression).\n- Dart calls it \"dot shorthands\" or [static access shorthand](https://github.com/dart-lang/language/blob/c31243942eacadcc1be8cf81016f758fe831b99c/working/3616%20-%20enum%20value%20shorthand/proposal-simple-lrhn.md).\n- Rust has an active RFC which calls it [path inference](https://github.com/rust-lang/rfcs/pull/3444).\n- Zig calls it [enum literals](https://ziglang.org/documentation/master/#Enum-Literals).\n\n## Open questions\n\n### Ambiguity with parenthesized expression\n\nThis is valid grammar today, which fails in binding if `A` is a type and not a value: `(A).B`.\n\nThe new grammar we're adding would allow this to be parsed as a cast followed by a target-typed static member access. This new interpretation is consistent with `(A)new()` and `(A)default` working today, but it would not be practically useful. `A.B` is a simpler and clearer way to write the same thing.\n\nShould `(A).B` continue to fail when `A` is a type, or be made to work the same as `A.B`?\n\n**Recommendation:** `(A).B` should continue to fail when `A` is a type. Even though blocking this syntax is an additional rule, the syntax is not beneficial.\n\n### Ambiguity with conditional expression\n\nThere is an ambiguity if target-typed static member access is used as the first branch of a conditional expression, where it would parse today as a null-safe dereference: `expr ? .Name : ...`\n\nWe can follow the approach already taken for the similar ambiguity in collection expressions with `expr ? [` possibly being an indexer and possibly being a collection expression.\n\nAlternatively, target-typed static member access could be always disallowed within the first branch of a conditional expression unless surrounded by parens: `expr ? (.Name) : ...`. The downside is that this puts a usability burden onto users, since the compiler can work out the ambiguity by looking ahead for the `:` as with collection expressions.\n\n**Recommendation:** Allow `expr ? .Name :` by looking ahead for `:`, just as with collection expressions.\n\n### Allowing overload resolution to be informed by target-typed access\n\nIn [Notes](#notes), it is currently specified that overload resolution is not influenced by `.Xyz` expressions. This is consistent with `new()`. One risk of allowing overload resolution to be influenced is that the following code would break if a new static member `CustomType.MinValue` was created:\n\n```cs\nM(.MinValue);\n\nvoid M(int p) { }\nvoid M(CustomType p) { }\n```\n\nThis comes with one fairly significant downside in a common use case, which is that the following code fails:\n```cs\n// error CS0121: The call is ambiguous between the following methods or properties:\n// 'Dictionary<TKey, TValue>.Dictionary(int)' and 'Dictionary<TKey, TValue>.Dictionary(IEqualityComparer<TKey>)'\nDictionary<string, int> d1 = new Dictionary<string, int>(.OrdinalIgnoreCase);\n\n// Same issue here\nDictionary<string, int> d2 = [with(.OrdinalIgnoreCase), a: b, c: d];\n```\n\nAlso consider more deeply nested expressions which allow target typed static member access, such as:\n```cs\nnew Dictionary<string, int>(ignoreCase ? .OrdinalIgnoreCase : .Ordinal);\n```\n\nIs it worth making overload resolution smarter to allow this, perhaps by adding a tiebreaker when target-typed member access expressions resolve for exactly one overload?\n\nAlternatively, because this issue (while significant) does not crop up in many APIs, is this a good use case for OverloadResolutionPriorityAttribute on constructors and Create methods that fall into this issue?\n\n**Recommendation:** If the runtime is willing to use ORPA, keep target-typed member access free of interactions with overload resolution, just like target-typed new.\n\n## Examples\n\n### Pattern matching enums\n\n```cs\npublic static string GetTypeString(ContractTransactionMode mode)\n{\n    return mode switch\n    {\n        .Preproduction => Preproduction,\n        .MoltPreproduction => MoltPreproduction,\n        .Production => ProductionFixedWeekly,\n        .EggProduction => ProductionPerGradeADozen,\n        .LayerBonus => LayerBonus,\n        .PulletGrower or .PulletGrowerFinal or .PulletGrowingFinal\n        or .PulletGrowingAP or .PulletGrowingAR or .PulletGrowerBonus => PulletGrowerOrGrowingPayment,\n    };\n}\n```\n\n```cs\nif (alias.ItemAliasType is not (.Vendor or .User)) ...\n```\n\n### Returning enums\n\n```cs\nprivate static ContractTransactionMode GetMode(string paymentType)\n{\n    return paymentType switch\n    {\n        Preproduction => .Preproduction,\n        MoltPreproduction => .MoltPreproduction,\n        ProductionFixedWeekly => .Production,\n        ProductionPerGradeADozen => .EggProduction,\n        PulletGrowerOrGrowingPayment => .Pullet,\n        LayerBonus => .LayerBonus,\n    };\n}\n```\n\n### Translating one enum to another\n\n```cs\nLineItemType lineItemType = transactionType switch\n{\n    .Invoice => .Sale,\n    .CreditMemo => .Return,\n};\n```\n\n### Using System.Reflection enums\n\nAll the focus is on the meaning and not on repeating the containing enum name four and five times:\n\n```cs\nforeach (var property in type.GetProperties(.Public | .NonPublic | .Static | .Instance | .DeclaredOnly))\n{\n    if (property.SetMethod is not { } setter)\n    {\n        continue;\n    }\n\n    if ((setter.Attributes & .MemberAccessMask) is not (.Public or .Family or .FamORAssem))\n    {\n        continue;\n    }\n    \n    // ...\n}\n```\n\n### Using generated interop (e.g. CsWin32)\n\nIt's typical to see generated enum member names be the same as the original constant, which is to say that the enum name itself is pretty redundant:\n\n`FILE_ACCESS_FLAGS.FILE_GENERIC_READ | FILE_ACCESS_FLAGS.FILE_GENERIC_WRITE`\n\nInstead, this could just mention the well-known constant names which are what you'd search anyway :\n\n`.FILE_GENERIC_READ | .FILE_GENERIC_WRITE`\n"
  },
  {
    "path": "proposals/top-level-members.md",
    "content": "# Top-Level Members\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9803\n\n## Summary\n\nAllow some members (methods, operators, extension blocks, fields, constants) to be declared in namespaces\nand make them available when the corresponding namespace is imported\n(this is a similar concept to instance extension members which are also usable without referencing the container class).\n\n```cs\n// util.cs\nnamespace MyApp;\n\nvoid Print(string s) => Console.WriteLine(s);\n\nstring Capitalize(this string input) =>\n    input.Length == 0 ? input : char.ToUpper(input[0]) + input[1..];\n```\n\n```cs\n// app.cs\n#!/usr/bin/env dotnet\n\nusing MyApp;\n\nPrint($\"Hello, {args[0].Capitalize()}!\");\n```\n\n```cs\n// Fields are useful:\nnamespace MyUtils;\n\nstring? cache;\n\nstring GetValue() => cache ??= Compute();\n```\n\n```cs\n// Simplifies extensions:\nnamespace System.Linq;\n\nextension<T>(IEnumerable<T> e)\n{\n    public IEnumerable<T> AsEnumerable() => e;\n}\n```\n\n## Motivation\n\n- Avoid boilerplate utility static classes.\n- Evolve top-level statements from C# 9.\n\n## Detailed design\n\n- Some members can be declared directly in a namespace (file-scoped or block-scoped).\n  - Allowed kinds currently are: methods, operators, extension blocks, fields, constants.\n  - Existing declarations like classes still work the same, there shouldn't be any ambiguity.\n  - There is no ambiguity with top-level statements because those are not allowed inside namespaces.\n\n- Top-level members in a namespace are semantically members of an \"implicit\" class which:\n  - is `static` and `partial`,\n  - has accessibility either `internal` (by default) or `public` (if any member is also `public`),\n  - has a generated unspeakable name `<>TopLevel`,\n  - has the namespace in which it is declared in,\n  - is synthesized per each namespace and compilation unit (so having top-level members in the same namespace across assemblies can lead to [ambiguities](#drawbacks)).\n\n  For top-level members, this means:\n    - The `static` modifier is disallowed (the members are implicitly static).\n    - The default accessibility is `internal`.\n      `public` and `private` is also allowed.\n      `protected` and `file` is disallowed.\n    - Overloading is supported.\n    - `extern` and `partial` are supported.\n    - XML doc comments work.\n\n- Metadata:\n  - The implicit class is recognized only if it has an attribute `[TopLevel]` (full attribute name is TBD).\n\n- Usage (if there is an appropriately-shaped `[TopLevel]` type in namespace `NS`):\n  - `using NS;` implies `using static NS.<>TopLevel;`.\n  - Lookup for `NS.Member` can find `NS.<>TopLevel.Member` (useful for disambiguation).\n  - Nothing really changes for extension member lookup (the class name is already not used for that).\n\n- Entry points:\n  - Top-level `Main` methods can be entry points.\n  - Top-level statements are generated into `Program.Main` (speakable function; previously it was unspeakable).\n    This is a breaking change: there could be a conflict with an existing `Program.Main` method declared by the user.\n  - Simplify the logic: TLS entry-points are normal candidates (previously they were not considered to be candidates and for example `-main` could not be used to point to them).\n    This is a breaking change: if the user has custom `Main` methods and top-level statements, they will get an error now because the compiler doesn't know which entrypoint to choose\n    (to fix that, they can specify `-main`).\n\n## Drawbacks\n\n- Polluting namespaces with loosely organized helpers.\n- Requires tooling updates to properly surface and organize top-level methods in IntelliSense, refactorings, etc.\n- Entry point resolution breaking changes.\n\n## Alternatives\n\n- Support `args` keyword in top-level members (just like it can be accessed in top-level statements). But we have `System.Environment.GetCommandLineArgs()`.\n- Allow capturing variables from top-level statements inside non-`static` top-level members.\n  Could be used to refactor a single-file program into multi-file program just by extracting functions to separate files.\n  But it would mean that a method's implementation (top-level statements) can influence what other methods see (which variables are available in top-level members).\n- Allow declaring top-level members outside namespaces as well.\n  - Would introduce ambiguities with top-level statements.\n  - Could be brought to scope via `extern alias`.\n    - To avoid needing to specify those in project files (e.g., so file-based apps also work),\n      there could be a syntax for that like `extern alias Util = Util.dll`.\n    - Or they could be in scope only in the current assembly.\n- Allow declaring top-level statements inside namespaces as well.\n  - Top-level local functions would introduce ambiguities with top-level methods. Wouldn't be a breaking change though, just need to decide which one wins.\n- If we ever allow the `file` modifier on members (methods, fields, etc.), that would be naturally useful for top-level members, too.\n  `file` members would be scoped to the current file.\n  Compare that with `private` members which are scoped to the current _namespace_.\n\n- Indentation concerns about current utility/extension methods could be resolved with\n  [file-scoped types](https://github.com/dotnet/csharplang/discussions/928) instead, i.e., allowing something like `class MyNamespace.MyClass;`\n  (although beware that `class MyClass;` has already a valid meaning today).\n  That wouldn't solve the use-site though, where you'd still need `using static MyNamespace.MyClass;` instead of just `using MyNamespace;` as with this proposal.\n\n- We could have something similar to VB's modules which are mostly like static classes\n  but their members don't need to be qualified with the module name if they are brought to scope via an import:\n  ```vb\n  Imports N\n\n  Namespace N\n      Module M\n          Sub F()\n          End Sub\n      End Module\n  End Namespace\n\n  Class C\n      Sub Main()\n          F()\n      End Sub\n  End Class\n  ```\n\n  F# has something similar, too:\n  ```fs\n  module Utilities =\n    let M() = ()\n\n  open Utilities\n  M()\n  ```\n\n  For example, C# could have `implicit` classes like:\n  ```cs\n  public implicit static class Utilities\n  {\n      public static void M() { }\n  }\n  ```\n\n  Combined with top-level classes feature mentioned above, this could look like:\n  ```cs\n  public implicit static class Utilities;\n  public static void M() { }\n  extension(int) { /* ... */ }\n  ```\n\n  This makes the declaration side a bit more complicated to write,\n  but it avoids problems with naming the implicit static class.\n\n  Open questions for this alternative:\n  - Should we allow non-`static` members?\n\n## Open questions\n\n- Which member kinds? Methods, fields, constants, properties, indexers, events, constructors, operators.\n- Accessibility: what should be the default and which modifiers should be allowed?\n- Clustering: currently each namespace per assembly gets its `<>TopLevel` class.\n- Shape of the synthesized static class (currently `[TopLevel] <>TopLevel`).\n  - Should it be speakable at least in other languages (so it's usable from VB/F#)?\n    - We could make that opt in via some attribute (`[file: TopLevel(\"MyTopLevelClassName\")]`).\n    - The naming could be based on the assembly name and/or the file name.\n    - If the name was constant, that could lead to ambiguity errors\n      when the same namespace is declared across multiple assemblies which are then referenced in one place.\n- Should we simplify the TLS entry point logic? Should it be a breaking change?\n- Should we require the `static` modifier (and keep our doors open if we want to introduce some non-`static` top-level members in the future)?\n- Should we disallow mixing top-level members and existing declarations in one file?\n  - Or we could limit their relative ordering, like top-level statements vs. other declarations are limited today.\n  - Allowing such mixing might be surprising, for example:\n    ```cs\n    namespace N;\n    int s_field;\n    int M() => s_field; // ok\n    static class C\n    {\n      static int M() => s_field; // error, `s_field` is not visible here\n    }\n    ```\n  - Disallowing such mixing might be surprising too, for example, consider there is an existing code:\n    ```cs\n    namespace N;\n    class C;\n    ```\n    and I just want to add a new declaration to it which fails and forces me to create a new file or namespace block:\n    ```cs\n    namespace N;\n    extension(object) {} // error\n    class C;\n    ```\n- Should we [relax the order of mixing top-level statements and declarations](https://github.com/dotnet/csharplang/discussions/5780) as part of this feature?\n- Do we need new name conflict rules for declarations and/or usages?\n  For example, should the following be an error when declared (and/or when used)?\n  ```cs\n  namespace NS;\n  int Foo;\n  class Foo { }\n  ```\n"
  },
  {
    "path": "proposals/type-parameter-inference-from-constraints.md",
    "content": "# Type Parameter Inference from Constraints\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9453\n\n## Summary\n\nAllow type inference to succeed in overload resolution scenarios by promoting generic constraints of inferred type parameters to \"fake arguments\" during type inference, enabling\nthe bounds of type variables to participate in the inference process. An example is:\n\n```cs\nList<int> l = [1, 2, 3];\nM(l); // Today: TElement cannot be inferred. With this proposal, successful call.\n\nvoid M<TEnumerable, TElement>(TEnumerable t) where TEnumerable : IEnumerable<TElement>\n{\n    Console.WriteLine(string.Join(\",\", t));\n}\n```\n\n## Motivation\n\nCurrently, C# type inference can fail in scenarios where the compiler has all the information it needs to determine the correct type parameters through constraint relationships.\nThis leads to verbose code requiring explicit type arguments or prevents valid overloads from being considered. This has long been a thorn in the side of C# users: no less than\n9 different issues/discussions on it have come up over the past decade on csharplang.\n\n* https://github.com/dotnet/roslyn/issues/5023\n* https://github.com/dotnet/roslyn/issues/15166\n* https://github.com/dotnet/csharplang/discussions/478\n* https://github.com/dotnet/csharplang/discussions/741\n* https://github.com/dotnet/csharplang/discussions/997\n* https://github.com/dotnet/csharplang/discussions/1018\n* https://github.com/dotnet/csharplang/discussions/6930\n* https://github.com/dotnet/csharplang/discussions/7262\n* https://github.com/dotnet/csharplang/discussions/8767\n\nThere was even one implementation of a proposed change, https://github.com/dotnet/roslyn/pull/7850, but LDM looked at this in 2016 and decided that it would be too potentially\nbreaking. Since then, C# has taken larger breaking change steps; most notably for this proposal, adding natural types to lambdas and method groups in overload resolution, but\nalso adding things like target-typing for ternary expressions, adding span conversions as first-class conversions in the language, the `field` keyword, and others. Given this,\nnow is an excellent time to re-examine the concern on the breaking change here, and potentially move forward with the proposal.\n\nCredit to [@HellBrick](https://github.com/HellBrick) for the [original proposed mechanics](https://github.com/dotnet/roslyn/issues/5023#issuecomment-154728796) of the design.\nThis proposal has been further refined from their original starting point.\n\n### Use cases this supports:\n\n```csharp\nprivate static void M<T, X>(T Object) where T : IEnumerable<X>, IComparable<X> \n{\n}\n\nprivate class MyClass : IComparable<String>, IEnumerable<String> \n{\n}\n\nprivate static void CallMyFunction() \n{\n    var c = new MyClass();\n    M(c);\n}\n```\n\n## Detailed design\n\n### Changes to Type Inference Algorithm\n\nWe modify the type inference process described in [§12.6.3](https://github.com/dotnet/csharpstandard/blob/draft-v9/standard/expressions.md#1263-type-inference) to include\nconstraint relationships in the dependence relationship between type variables.\n\n#### Enhanced Dependence Relationship - Modified Spec Text\n\nThe following text from [§12.6.3.6 Dependence](https://github.com/dotnet/csharpstandard/blob/draft-v9/standard/expressions.md#12636-dependence) is modified:\n\n> **12.6.3.6 Dependence**\n>\n> An *unfixed* type variable `Xᵢ` *depends directly on* an *unfixed* type variable `Xₑ` if one of the following holds:\n>\n> - For some argument `Eᵥ` with type `Tᵥ` `Xₑ` occurs in an *input type* of `Eᵥ` with type `Tᵥ` and `Xᵢ` occurs in an *output type* of `Eᵥ` with type `Tᵥ`.\n> - **`Xᵢ` occurs in a constraint for `Xₑ`.**\n>\n> `Xₑ` *depends on* `Xᵢ` if `Xₑ` *depends directly on* `Xᵢ` or if `Xᵢ` *depends directly on* `Xᵥ` and `Xᵥ` *depends on* `Xₑ`. Thus \"*depends on*\" is the transitive but not reflexive closure of \"*depends directly on*\".\n\n#### Enhanced Fixing Process - Modified Spec Text\n\nThe following text from [§12.6.3.12 Fixing](https://github.com/dotnet/csharpstandard/blob/draft-v9/standard/expressions.md#126312-fixing) is modified:\n\n> **12.6.3.12 Fixing**\n>\n> An *unfixed* type variable `Xᵢ` with a set of bounds is *fixed* as follows:\n>\n> - The set of *candidate types* `Uₑ` starts out as the set of all types in the set of bounds for `Xᵢ`.\n> - Each bound for `Xᵢ` is examined in turn: For each exact bound U of `Xᵢ` all types `Uₑ` that are not identical to `U` are removed from the candidate set. For each lower bound `U` of `Xᵢ` all types `Uₑ` to which there is *not* an implicit conversion from `U` are removed from the candidate set. For each upper-bound U of `Xᵢ` all types `Uₑ` from which there is *not* an implicit conversion to `U` are removed from the candidate set.\n> - If among the remaining candidate types `Uₑ` there is a unique type `V` to which there is an implicit conversion from all the other candidate types, then `Xᵢ` is fixed to `V` **and a lower-bound inference is performed from `V` to each of the types in `Xᵢ`'s constraints, if any**.\n> - Otherwise, type inference fails.\n\n## Drawbacks\n\nThe primary concern with this proposal is that it introduces potential breaking changes in overload resolution. Code that currently compiles and calls one overload might start\ncalling a different overload after this feature is implemented.\n\n**Example breaking change:**\n\n```cs\nvoid M(object obj) \n{\n    Console.WriteLine(\"Called non-generic overload\");\n}\n\nvoid M<T, U>(T t) where T : IEnumerable<U> \n{\n    Console.WriteLine(\"Called generic overload\");\n}\n\n// Call site:\nM(\"test\"); // Currently prints \"Called non-generic overload\", would print \"Called generic overload\"\n```\n\nThis is somewhat similar to the breaks that occurred with lambda and method group natural types; the most common change there was that type inference failed on an instance\nmethod, and then fell back to an extension method instead. And, similarly to that proposal, the likelihood is that the new overload chosen is actually the more \"correct\" one;\nit's more likely to be what the user intended.\n\nThere are options to mitigate this break if we so choose; we could do two runs of overload resolution, first without constraint promotion, then if that fails to find a single\napplicable overload we could rerun with constraint promotion. This would be significantly more complex, but it could be done, and would mitigate the breaking change.\n\n## Alternatives\n\nThere are a couple of other options:\n\n* Introduce a new keyword at generic parameter declaration, such as `void M<TEnumerable, infer TElement>(TEnumerable t) where TEnumerable : IEnumerable<TElement>`, and only\n  perform the promotion for such parameters. While this is doable, and entirely mitigates the breaking change, it immediately because the \"default\" that everyone should use,\n  and not doing so is a bug on the author's part, and thus is not good for the future of the language.\n* Partial type inference - https://github.com/dotnet/csharplang/issues/8968 covers partial type inference, so that users could use an `_` or an empty identifier to avoid\n  restating what can be inferred from the signature, and only state what cannot be inferred. While this is a decent idea, it doesn't fully solve this issue, as we want to avoid\n  needing to specify _any_ type parameters in this case when they can be inferred.\n* Associated types - https://github.com/dotnet/csharplang/issues/8712 covers this. Another very related proposal, and one this proposal does not rule out. But partial type\n  inference will cover more scenarios around inference that won't be fixed by associated types, for scenarios where the input is truly not an associated type but has constraints\n  based on other type parameters.\n\n## Open questions\n[open]: #open-questions\n\nTBD\n"
  },
  {
    "path": "proposals/unions.md",
    "content": "# Unions\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9662\n\n## Summary\n[summary]: #summary\n\n*Unions* is a set of interlinked features, that combine to provide C# support for union types:\n\n- *Union types*: Structs and classes that have a `[Union]` attribute are recognized as *union types*, and support the *union behaviors*.\n- *Case types*: Union types have a set of *case types*, which is given by parameters to constructors and factory methods.\n- *Union behaviors*: Union types support the following *union behaviors*:\n    - *Union conversions*: There are implicit *union conversions* from each case type to a union type.\n    - *Union matching*: Pattern matching against union values implicitly \"unwraps\" their contents, applying the pattern to the underlying value instead.\n    - *Union exhaustiveness*: Switch expressions over union values are exhaustive when all case types have been matched, without need for a fallback case.\n    - *Union nullability*: Nullability analysis has enhanced tracking of the null state of a union's contents.\n- *Union patterns*: All union types follow a basic *union pattern*, but there are additional optional patterns for specific scenarios.\n- *Union declarations*: A shorthand syntax allows declaration of union types directly. The implementation is \"opinionated\" - a struct declaration that follows the basic union pattern and stores the contents as a single reference field.\n- *Union interfaces*: A few interfaces are known by the language and used in its implementation of union declarations. \n\n## Motivation\n[motivation]: #motivation\n\nUnions are a long-requested C# feature, which allows expressing values from a closed set of types in a way that pattern matching can trust to be exhaustive.\n\nThe separation between union *types* and union *declarations* allows C# to have a succinct union declaration syntax with opinionated semantics, while also allowing existing types or types with other implementation choices to opt into union behaviors.\n\nThe proposed unions in C# are unions of *types* and not \"discriminated\" or \"tagged\". \"Discriminated unions\" can be expressed in terms of \"type unions\" by using fresh type declarations as case types. Alternatively they can be implemented as a [closed hierarchy](https://github.com/dotnet/csharplang/blob/main/proposals/closed-hierarchies.md), which is another, related, upcoming C# feature focused on exhaustiveness.\n\n## Detailed design\n[design]: #detailed-design\n\n### Union types\n\nAny class or struct type with a `System.Runtime.CompilerServices.UnionAttribute` attribute is considered a *union type*:\n\n```csharp\nnamespace System.Runtime.CompilerServices\n{\n    [AttributeUsage(Class | Struct, AllowMultiple = false)]\n    public class UnionAttribute : Attribute;\n}\n```\n\nA union type must follow a certain pattern of public *union members*, which must either be declared on the union type itself or delegated to a \"union member provider\".\n\nSome union members are mandatory, and others are optional.\n\nA union type has a set of *case types* which are established based on the signatures of certain union members.\n\nThe contents of a union value can be accessed through a `Value` property. The language assumes that `Value` only ever contains a value of one of the case types, or null (see [Well-formedness](#well-formedness)).\n\n#### Union member providers\n\nBy default, union members are found on the union type itself. However, if the union type *directly contains* a declaration of an interface called `IUnionMembers` then the interface acts as a *union member provider*. In that case, union members are *only* found on the union member provider, not on the union type itself.\n\nA union member provider interface must be public, and the union type itself must implement it as an interface.\n\nWe use the term *union-defining type* for the type where the union members are found: The union member provider if it exists, and the union type itself otherwise.\n\n#### Union members\n\nUnion members are looked up by name and signature on the union-defining type. They do not have to be declared directly on the union-defining type, but can be inherited. \n\nIt is an error for any union member not to be public.\n\nThe creation members and the `Value` property are mandatory, and are collectively referred to as the *basic union pattern*.\n\nThe `HasValue` and `TryGetValue` members are collectively referred to as the *non-boxing union access pattern*.\n\nThe different union members are described in the following.\n\n#### Union creation members\n\nUnion creation members are used to create new union values from a case type value.\n\nIf the union-defining type is the union type itself, each constructor with a single parameter is a *union constructor*.\nThe case types of the union are identified as the set of types built from parameter types of these constructors in the following way:\n - If the parameter type is a nullable type (whether a value or a reference), the case type is the underlying type\n - Otherwise, the case type is the parameter type.\n\n```csharp\n// Union constructor making `Dog` a case type\npublic Pet(Dog value) { ... }\n```\n```csharp\n// Union constructor making `int` a case type\npublic Union(int? value) { ... }\n```\n```csharp\n// Union constructor making `string` a case type\npublic Union(string? value) { ... }\n```\n\nIf the union-defining type is a union member provider, each static `Create` method with a single parameter and a return type \nthat is identity-convertible to the union type itself is a *union factory method*. \nThe case types of the union are identified as the set of types built from parameter types of these factory methods in the following way:\n - If the parameter type is a nullable type (whether a value or a reference), the case type is the underlying type\n - Otherwise, the case type is the parameter type.\n\n```csharp\n// Union factory method making `Cat` a case type\npublic static Pet Create(Cat value) { ... }\n```\n```csharp\n// Union factory method making `int` a case type\npublic static Union Create(int? value) { ... }\n```\n```csharp\n// Union factory method making `string` a case type\npublic static Union Create(string? value) { ... }\n```\n\nUnion constructors and union factory methods are referred to collectively as *union creation members*.\n\nThe single parameter of a union creation member must be a by-value or `in` parameter.\n\nA union type must have at least one union creation member, and therefore at least one case type.\n\n#### Value property\n\nThe `Value` property allows access to the value contained in a union, regardless of its case type.\n\nEvery union-defining type must declare a `Value` property of type `object?` or `object`. The property must have a `get` accessor and may optionally have an `init` or `set` accessor, which can be of any accessibility and is not used by the compiler.\n\n```csharp\n// Union 'Value' property\npublic object? Value { get; }\n```\n\n#### Non-boxing access members\n\nA union type can choose to additionally implement the *non-boxing union access pattern*, which allows strongly typed conditional access to each case type, as well as a way to check for null.\n\nThis allows the compiler to implement pattern matching more efficiently when case types are value types and stored as such within the union.\n\nThe non-boxing access members are:\n\n- A `HasValue` property of type `bool` with a public `get` accessor. It may optionally have an `init` or `set` accessor, which can be of any accessibility and is not used by the compiler. \n- A `TryGetValue` method for each case type. The method returns `bool` and takes a single out-parameter of a type that is identity-convertible to the case type.\n    \n```csharp\n// Non-boxing access members\npublic bool HasValue { get { ... } }\npublic bool TryGetValue(out Dog value) { ... }\n```\n\n`HasValue` is expected to return true if and only if the union's `Value` is not null.\n\n`TryGetValue` is expected to return true if and only if the union's `Value` is of the given case type, and if so, deliver that value in the method's out parameter.\n\n#### Well-formedness\n\nThe language and compiler make a number of behavioral assumptions about union types. If a type qualifies as a union type but does not satisfy those assumptions, then union behaviors may not work as expected.\n\n* *Soundness*: The `Value` property always evaluates to null or to a value of a case type. That is true even for the default value of the union type.\n* *Stability*: If a union value is created from a case type, the `Value` property will match that case type or null. If a union value is created from a `null` value, the `Value` property will be `null`.\n* *Creation equivalence*: If a value is implicitly convertible to two different case types then the creation member for either of those case types has the same observable behavior when called with that value.\n* *Access pattern consistency*: The behavior of the `HasValue` and `TryGetValue` non-boxing access members, if present, is observably equivalent to that of checking against the `Value` property directly.\n\n#### Examples of union types\n\n`Pet` implements the basic union pattern on the union type itself:\n\n```csharp\n[Union] public record struct Pet\n{\n    // Creation members = case types are 'Dog' and 'Cat'\n    public Pet(Dog value) => Value = value;\n    public Pet(Cat value) => Value = value;\n\n    // 'Value' property\n    public object? Value { get; }\n}\n```\n\n`IntOrBool` implements the non-boxing access pattern on the union type itself:\n\n```csharp\npublic record struct IntOrBool\n{\n    private bool _isBool;\n    private int _value;\n\n    public IntOrBool(int value) => (_isBool, _value) = (false, value);\n    public IntOrBool(bool value) => (_isBool, _value) = (true, value ? 1 : 0);\n\n    public object Value => _isBool ? _value is 1 : _value;\n\n    public bool HasValue => true;\n    public bool TryGetValue(out int value)\n    {\n        value = _value;\n        return !_isBool;\n    }\n    public bool TryGetValue(out bool value)\n    {\n        value = _isBool && _value is 1;\n        return _isBool;\n    }\n}\n```\n\n*Note:* This is just an example of how the non-boxing access pattern might be implemented. The user code can store the content any way it likes. In particular, it does not prevent the implementation from boxing! The `non-boxing` in its name refers to allowing the compiler's pattern matching implementation to access each case type in a strongly typed way, as opposed to the `object?`-typed `Value` property.\n\n`Result<T>` implements the basic pattern via a union member provider:\n\n```csharp\npublic record class Result<T> : Result<T>.IUnionMembers\n{\n    object? _value;\n\n    public interface IUnionMembers\n    {\n        public static Result<T> Create(T value) => new() { _value = value };\n        public static Result<T> Create(Exception value) => new() { _value = value };\n\n        public object? Value { get; }\n    }\n\n    object? IUnionMembers.Value => _value;\n}\n```\n\n### Union behaviors\n\nThe union behaviors are generally implemented by means of the basic union pattern. If the union offers the non-boxing access pattern, union pattern matching will preferentially make use of it.\n\n#### Union conversions\n\nA *union conversion* implicitly converts to a union type from each of its case types. Specifically, there's a union conversion to a union type `U` from a type or expression `E` if there's a standard implicit conversion from `E` to a type `C` and `C` is a parameter type of a *union creation member* of `U`.\nIf union type `U` is a struct, there's a union conversion to type `U?` from a type or expression `E` if there's a standard implicit conversion from `E` to a type `C` and `C` is a parameter type of a *union creation member* of `U`.\n\nA union conversion is not itself a standard implicit conversion. It may therefore not participate in a user-defined implicit conversion or another union conversion.\n\nThere are no explicit union conversions beyond the implicit union conversions. Thus, even if there is an explicit conversion from `E` to a union's case type `C`, that doesn't mean there is an explicit conversion from `E` to that union type.\n\nA union conversion is executed by calling the union's creation member:\n\n``` c#\nPet pet = dog;\n// becomes\nPet pet = new Pet(dog);\n// and\nResult<string> result = \"Hello\"\n//becomes\nResult<string> result = Result<string>.IUnionMembers.Create(\"Hello\");\n```\n\nIt is an error if overload resolution does not find a single best candidate member, or if that member is not one of the union type's union members.\n\nUnion conversion is just another \"form\" of an implicit user-defined conversion. An applicable\nuser-defined conversion operator \"shadows\" union conversion.\n\nThe rationale behind this decision:\n> If someone written a user-defined operator, it should get priority.\n> In other words, if the user actually wrote their own operator, they want us to call it.\n> Existing types with conversion operators transformed into union types continue to work\n> the same way with respect to existing code utilizing the operators today.\n\nIn the following example an implicit user-defined conversion takes priority over a union conversion. \n``` c#\nstruct S1 : System.Runtime.CompilerServices.IUnion\n{\n    public S1(int x) => ...\n    public S1(string x) => ...\n    object System.Runtime.CompilerServices.IUnion.Value => ...\n    public static implicit operator S1(int x) => ...\n}\n\nclass Program\n{\n    static S1 Test1() => 10; // implicit operator S1(int x) is used\n    static S1 Test2() => (S1)20; // implicit operator S1(int x) is used\n}\n```\n\nIn the following example, when explicit cast is used in code, an explicit user-defined conversion\ntakes priority over a union conversion. But, when there is no explicit cast in code, a union conversion\nis used because explicit user-defined conversion is not applicable.\n``` c#\nstruct S2 : System.Runtime.CompilerServices.IUnion\n{\n    public S2(int x) => ...\n    public S2(string x) => ...\n    object System.Runtime.CompilerServices.IUnion.Value => ...\n    public static explicit operator S2(int x) => ...\n}\n\nclass Program\n{\n    static S2 Test3() => 10; // Union conversion S2.S2(int) is used\n    static S2 Test4() => (S2)20; // explicit operator S2(int x)\n}\n```\n\n#### Union matching\n\nWhen the incoming value of a pattern is of a union type or of a nullable of a union type, \nthe nullable value and the underlying union value's contents may be \"unwrapped\", depending on the pattern.\n\nFor the unconditional `_` and `var` patterns, the pattern is applied to the incoming value itself. For example:\n\n```csharp\nif (GetPet() is var pet) { ... } // 'pet' is the union value returned from `GetPet`\n```\n\nHowever, all other patterns get implicitly applied to the underlying union's `Value` property:\n\n``` c#\nif (GetPet() is Dog dog) { ... }   // 'Dog dog' is applied to 'GetPet().Value'\nif (GetPet() is null) { ... }      // 'null' is applied to 'GetPet().Value'\nif (GetPet() is { } value) { ... } // '{ } value' is applied to 'GetPet().Value'\n```\n\nFor logical patterns, this rule is applied individually to the branches, bearing in mind that the left branch of an `and` pattern can affect the incoming type of the right branch:\n\n``` c#\nGetPet() switch\n{\n    var pet and not null   => ... // 'var pet' applies to the incoming 'Pet' and 'not null' to its 'Value'\n    not null and var value => ... // 'not null' applies to the 'Value' as does 'var value' because of the \n                                  // left branch changing the incoming type to `object?`.\n}\n```\n\n*Note:* This rule means that `GetPet() is Pet pet` will likely not succeed, as `Pet` is applied to the _contents_, not to the `Pet` union itself.\n\n*Note:* The reason for the different treatment of unconditional `var` pattern (as well as `_`, which is essentially a shorthand for `var _`) is an assumption that their use is qualitatively different from other patterns. `var` patterns are used simply to name the value being matched against, oftentimes in nested patterns, such as `PetOwner{ Pet: var pet }`. Here, the helpful semantics is for `pet` to retain the union type `Pet`, instead of the `Value` property being dereferenced to a useless `object?` type.\n\nIf the incoming value is a class type, then the `null` pattern will succeed regardless of whether the union value itself is `null` or its contained value is `null`:\n\n```csharp\nif (result is null) { ... } // if (result == null || result.Value == null)\n```\n\nOther union matching patterns will succeed only when the union value itself is not `null`.\n```csharp\nif (result is 1) { ... } // if (result != null && result.Value is 1)\n```\n\nSimilarly, if the incoming value is a nullable values type (wrapping a struct union type), then the `null` pattern will succeed \nregardless of whether the incoming value itself is `null` or its contained value is `null`:\n\n```csharp\nif (result is null) { ... } // if (result.HasValue == false || result.GetValueOrDefault().Value == null)\n```\n\nOther union matching patterns will succeed only when the the incoming value itself is not `null`.\n```csharp\nif (result is 1) { ... } // if (result.HasValue && result.GetValueOrDefault().Value is 1)\n```\n\n\nThe compiler will prefer implementing pattern behavior by means of members prescribed by the non-boxing access pattern. While it is free to do any optimization within the bounds of the well-formedness rules, the following are the minimum set guaranteed to be applied:\n\n* For a pattern that implies checking for a specific type `T`, if a `TryGetValue(S value)` method is available, and there is an identity, or implicit reference/boxing conversion from `T` to `S`, then that method is used to obtain the value. The pattern is then applied to that value. If there is more than one such method, then any where the conversion from `T` to `S` is not a boxing conversion is preferred if available. If there is still more than one method, one is chosen in an implementation-defined manner.\n* Otherwise, for a pattern that implies checking for `null`, if a `HasValue` property is available, that property is used to check if the union value is null.\n* Otherwise, the pattern is applied to the result of accessing the `IUnion.Value` property on the incoming union.\n\n[The is-type operator](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1214121-the-is-type-operator) applied to a union type\nhas the same meaning as a type pattern applied to the union type.\n\n#### Union exhaustiveness\n\nA union type is assumed to be \"exhausted\" by its case types. This means that a `switch` expression is exhaustive if it handles all of a union's case types:\n\n\n``` c#\nvar name = pet switch\n{\n    Dog dog => ...,\n    Cat cat => ...,\n    // No warning about non-exhaustive switch\n};\n```\n\n#### Nullability\n\nThe null state of a union's `Value` property is tracked like any other property, with these modifications: \n\n- When a union creation member is called (explicitly or through a union conversion), the new union's `Value` gets the null state of the incoming value.\n- When the non-boxing access pattern's `HasValue` or `TryGetValue(...)` are used to query the contents of a union type (explicitly or via pattern matching), it impacts `Value`'s nullability state in the same way as if `Value` had been checked directly: The null state of `Value` becomes \"not null\" on the `true` branch.\n\nEven when a union switch is otherwise exhaustive, if the null state of the incoming union's `Value` property is \"maybe null\", a warning will be given on unhandled null.\n\n``` c#\nPet pet = GetNullableDog(); // 'pet.Value' is \"maybe null\"\nvar value = pet switch\n{\n    Dog dog => ...,\n    Cat cat => ...,\n    // Warning: 'null' not handled\n}\n```\n\n### Union interfaces\n\nThe following interfaces are used by the language in its implementation of union features.\n\n#### Union access interface\n\nThe `IUnion` interface marks a type as a union type at compile time and provides a way to access union contents at runtime.\n\n```csharp\npublic interface IUnion\n{\n    // The value of the union or null\n    object? Value { get; }\n}\n```\n\nUnions generated by the compiler implement this interface.\n\nExample use:\n\n```csharp\nif (value is IUnion { Value: null }) { ... }\n```\n\n### Union declarations\n\nUnion declarations are a succinct and opinionated way of declaring union types in C#. They declare a struct which uses a single object reference for storing its `Value`, which means:\n\n* *Boxing*: Any value types among their case types will be boxed on entry.\n* *Compactness*: Union values only contain a single field.\n\nThe intent is for union declarations to cover the vast majority of use cases quite nicely. The two main reasons for hand coding specific union types rather than use union declarations are expected to be:\n\n* Adapting existing types to the union patterns to gain union behaviors.\n* Implementing a different storage strategy for e.g. efficiency or interop reasons.\n\n#### Syntax\n\nA union declaration has a name and a list of *union constructors* types.\n\n``` antlr\nunion_declaration\n    : attributes? struct_modifier* 'partial'? 'union' identifier type_parameter_list?\n      '(' type (',' type)* ')'  struct_interfaces? type_parameter_constraints_clause* \n      (`{` struct_member_declaration* `}` | ';')\n    ;\n```\n\nIn addition to the restrictions on struct members ([§16.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/structs.md#163-struct-members)), the following applies to union members:\n\n* Instance fields, auto-properties or field-like events are not permitted.\n* Explicitly declared public constructors with a single parameter are not permitted.\n* Explicitly declared constructors must use a `this(...)` initializer to (directly or indirectly) delegate to one of the generated constructors.\n\nThe *union constructors* types can be any type that converts to `object`, e.g., interfaces, type parameters, nullable types and other unions. It is fine for resulting cases to overlap, and for unions to nest or be null.\n\nExamples:\n\n```csharp\n// Union of existing types\npublic union Pet(Cat, Dog, Bird);\n\n// Union with function member\npublic union OneOrMore<T>(T, IEnumerable<T>)\n{\n    public IEnumerable<T> AsEnumerable() => Value switch\n    {\n        IEnumerable<T> list => list,\n        T value => [value],\n    }\n}\n\n// \"Discriminated\" union with freshly declared case types\npublic record class None();\npublic record class Some<T>(T value);\npublic union Option<T>(None, Some<T>);\n\n#### Lowering\n\nA union declaration is lowered to a struct declaration with\n\n* the same attributes, modifiers, name, type parameters and constraints,\n* implicit implementations of `IUnion`,\n* a `public object? Value { get; }` auto-property,\n* a public constructor for each *union constructor* type,\n* any members in the union declaration's body.\n\nIt is an error for user-declared members to conflict with generated members.\n\nExample:\n\n``` c#\npublic union Pet(Cat, Dog){ ... }\n```\n\nIs lowered to:\n\n``` c#\n[Union] public struct Pet : IUnion\n{\n    public Pet(Cat value) => Value = value;\n    public Pet(Dog value) => Value = value;\n    \n    public object? Value { get; }\n    \n    ... // original body\n}\n```\n\n## Open questions\n[open]: #open-questions\n\n### [Resolved] Is union declaration a record?\n\n> A union declaration is lowered to a record struct\n\nI think this default behavior is unnecessary and, given that it is not configurable, going to significantly\nlimit usage scenarios. Records generate a lot of code that is either unused or doesn't match specific requirements.\nFor example, records are pretty much forbidden in compiler's code base because of that code bloat. I think that it would be better\nto change the default:\n - By default, a union declaration declares a regular struct with just union-specific members.\n - A user can declare a record union: ``` record union U(E1, ...) ... ``` \n\n**Resolution:** A union declaration is a plain struct, not record struct. The ```record union ...``` isn't supported\n\n### [Resolved] Union declaration syntax\n\nIt looks like the proposed syntax is incomplete or unnecessarily limiting. For example, it looks like\nbase clause is not permitted. However, I can easily imagine a need to implement an interface, for example.\nI think that apart from the element-types-list the syntax should match regular `struct`/`record struct`\ndeclaration where the `struct` keyword is replaced with `union` keyword.\n\n**Resolution:** The restriction is removed.\n\n### [Resolved] Union declaration members\n\n> Instance fields, auto-properties or field-like events are not permitted.\n\nThis feels arbitrary and absolutely unnecessary.\n\n**Resolution:** The restriction is kept.\n\n### [Resolved] Nullable value types as Union case types\n\n> The case types of the union are identified as the set of parameter types from these constructors.\n> The case types of the union are identified as the set of parameter types from these factory methods.\n\nAt the same time:\n\n> A `TryGetValue` method for each case type. The method returns `bool` and takes a single out-parameter of a type that corresponds to the given case type in the following way:\n>    - If the case type is a nullable value type, the type of the parameter should be identity-convertible to the underlying type\n>    - Otherwise, the type should be identity-convertible to the case type.\n\nIs there an advantage to have a nullable value type among the case types especially that a type pattern cannot use\nnullable value type as the target type? It feels like we could simply say that, if constructor's/factory's parameter\ntype is a nullable value type, then corresponding case type is the underlying type. Then we wouldn't need that extra clause\nfor the `TryGetValue` method, all out parameters are case types.\n\n**Resolution:** The suggestion is approved\n\n### [Resolved] Default nullable state of `Value` property\n\n> For union types where none of the case types are nullable, the default state for `Value` is \"not null\" rather than \"maybe null\". \n\nWith the new design, where `Value` property is not defined in some general interface, but \nis an API that specifically belongs to the declared type, the rule quoted above feels like\nover-engineering. Moreover, the rule likely will force consumers to use nullable types in situations where\notherwise nullable types wouldn't be used.\n\nFor example, consider the following union declaration:\n``` c#\nunion U1(int, bool, DateTime);\n```\n\nAccording to the quoted rule, the default state for `Value` is \"not null\". But that doesn't match behavior of the\ntype, `default(U1).Value` is `null`. In order to realign the behavior, consumer is forced to make at least one \ncase type nullable. Something like: \n``` c#\nunion U1(int?, bool, DateTime);\n```\n\nBut that is likely undesirable, consumer might not want to allow explicit creation with `int?` value.\n\nProposal: Remove the quoted rule, nullable analysis should use annotations from the `Value` property\n          to infer its default nullability.\n\n**Resolution:** The proposal is approved\n\n### [Resolved] Union matching for Nullable of a union value type\n\n> When the incoming value of a pattern is of a union type, the union value's contents may be \"unwrapped\", depending on the pattern.\n\nShould we expand this rule to scenarios when incoming value of a pattern is of a `Nullable<union type>`?\n\nConsider the following scenario:\n``` C#\n    static bool Test1(StructUnion? u)\n    {\n        return u is 1;\n    }   \n\n    static bool Test2(ClassUnion? u)\n    {\n        return u is 1;\n    }   \n```\n\nThe meaning of ```u is 1``` in Test1 and Test2 are very different. In Test1 it is not a union matching, in Test2 it is.\nPerhaps \"union matching\" should \"dig\" through `Nullable<T>` as pattern matching usually does in other situations.\n\nIf we go with that, then the union matching `null` pattern against `Nullable<union type>` should work as against classes.\nI.e. the pattern is true when ```(!nullableValue.HasValue || nullableValue.Value.Value is null)```.\n\n**Resolution:** The proposal is approved.\n\n### What to do about \"bad\" APIs?\n\nWhat should compiler do about union matching APIs that look like a match, but otherwise \"bad\"?\nFor example, compiler finds TryGetValue/HasValue with matching signature, but it is \"bad\" because\na required custom modifier or it requires an unknown feature, etc. Should compiler silently ignore the API or\nreport an error?\nSimilar, the API might be marked as Obsolete/Experimental. Should compiler report any diagnostics, silently use the API\nor silently not use the API?\n\n### What if types for union declaration are missing\n\nWhat happens if `UnionAttribute`, `IUnion` or `IUnion<TUnion>` are missing? Error? Synthesize? Something else?\n\n### [Resolved] Design of generic IUnion interface\n\nArguments have been made that `IUnion<TUnion>` should not inherit from `IUnion` or constrain its type parameter to `IUnion<TUnion>`. We should revisit.\n\n**Resolution:** The `IUnion<TUnion>` interface is removed for now.\n\n### [Resolved] Nullable value types as case types and their interaction with `TryGetValue`\n\nThe rules above state that if a case type is a nullable value type, the parameter type used in a corresponding `TryGetValue` method should be the *underlying* type. \nThis is motivated by the fact that a `null` value would never be yielded through this method. On the consumption side, a nullable value type is not allowed as a type pattern, whereas a match against the underlying type should be able to map to a call of this method.\n\nWe should confirm that we agree with this unwrapping.\n\n**Resolution:** Agreed/confirmed\n\n### *The non-boxing union access pattern*\n\nNeed to specify precise rules for finding suitable `HasValue` and `TryGetValue` APIs.\nIs inheritance involved? Is read/write `HasValue` an acceptable match? Etc.\n\n### [Resolved] `TryGetValue` matching conversions\n\nThe Union Matching section says:\n> For a pattern that implies checking for a specific type `T`, if a `TryGetValue(S value)`\n> method is available, and there is an implicit conversion from `T` to `S`,\n> then that method is used to obtain the value.\n\nIs the set of implicit conversions restricted in any way? For example, are user-defined conversions allowed?\nWhat about tuple conversions and other not so trivial conversions? Some of those are even standard conversions. \n\nIs the set of `TryGetValue` methods restricted in any other way? For example, Union Patterns section implies\nthat only methods with a parameter type matching a case type are considered:\n> a `public bool TryGetValue(out T value)` method for each case type `T`.\n\nIt would be good to have an explicit answer. \n\n**Resolution:** Only implicit identity, or reference, or boxing conversions are considered \n\n### `TryGetValue` and nullable analysis\n\n> When the non-boxing access pattern's `HasValue` or `TryGetValue(...)`\n> are used to query the contents of a union type (explicitly or via pattern matching),\n> it impacts `Value`'s nullability state in the same way as if `Value` had been\n> checked directly: The null state of `Value` becomes \"not null\" on the `true` branch.\n\nIs the set of `TryGetValue` methods restricted in any way? For example, Union Patterns section implies\nthat only methods with a parameter type matching a case type are considered:\n> a `public bool TryGetValue(out T value)` method for each case type `T`.\n\nIt would be good to have an explicit answer. \n\n### Clarify rules around `default` values of struct union types\n\n*Note*: The default nullability rule mentioned below has been removed.\n\n*Note*: The \"default\" well-formedness rules mentioned below have been removed. We should confirm that this is what we want.\n\n[Nullability](#Nullability) section says:\n> For union types where none of the case types are nullable, the default state for `Value` is \"not null\" rather than \"maybe null\". \n\nGiven that, for the example below, current implementation considers `Value` of `s2` as \"not null\":\n``` c#\nS2 s2 = default;\n\nstruct S2 : System.Runtime.CompilerServices.IUnion\n{\n    public S2(int x) => throw null!;\n    public S2(bool x) => throw null!;\n    object? System.Runtime.CompilerServices.IUnion.Value => throw null!;\n}\n```\n\nAt the same time, [Well-formedness](#Well-formedness) section says:\n>* *Default value*: If a union type is a value type, it's default value has `null` as its `Value`.\n>* *Default constructor*: If a union type has a nullary (no-argument) constructor, the resulting union has `null` as its `Value`.\n\nAn implementation like that will be in contradiction with nullable analysis behavior for the example above.\n\nShould the [Well-formedness](#Well-formedness) rules be adjusted, or should state of `Value` of `default` be \"maybe null\"?\nIf the latter, should initialization ```S2 s2 = default;``` produce a nullability warning?\n\n### Confirm that a type parameter is never a union type, even when constrained to one.\n\n``` C#\nclass C1 : System.Runtime.CompilerServices.IUnion\n{\n    private readonly object _value;\n    public C1(int x) { _value = x; }\n    public C1(string x) { _value = x; }\n    object System.Runtime.CompilerServices.IUnion.Value => _value;\n}\n\nclass Program\n{\n    static bool Test1<T>(T u) where T : C1\n    {\n        return u is int; // Not a union matching\n    }   \n\n    static bool Test2<T>(T u) where T : C1\n    {\n        return u is string; // Not a union matching\n    }   \n}\n```\n\n### Should post-condition attributes affect default nullability of a Union instance?\n\n*Note*: The default nullability rule mentioned below has been removed. And we no longer infer default nullability \nof `Value` property from union creation methods. Therefore, the question is obsolete/no longer applicable to the current design. \n> For union types where none of the case types are nullable, the default state for `Value` is \"not null\" rather than \"maybe null\". \n\nIs the warning expected in the following scenario\n``` c#\n#nullable enable\n\nstruct S1 : System.Runtime.CompilerServices.IUnion\n{\n    public S1(int x) => throw null!;\n    public S1([System.Diagnostics.CodeAnalysis.NotNull] bool? x) => throw null!;\n    object? System.Runtime.CompilerServices.IUnion.Value => throw null!;\n}\nclass Program\n{\n    static void Test2(S1 s)\n    {\n       // warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive).\n       //                 For example, the pattern 'null' is not covered.\n        _ = s switch { int => 1, bool => 3 }; // \n    } \n}\n```\n\n### Union conversions\n\n#### [Resolved] Where do they belong among other conversions priority-wise?\n\nUnion conversions feel like another form of a user-defined conversion. Therefore, current implementation\nclassifies them right after a failed attempt to classify an implicit user-defined conversion, and, in case\nof existence is treated as just another form of a user-defined conversion. This has the\nfollowing consequences:\n- An implicit user-defined conversion takes priority over a union conversion\n- When explicit cast is used in code, an explicit user-defined conversion takes priority over a union conversion \n- When there is no explicit cast in code, a union conversion takes priority over an explicit user-defined conversion \n\n``` c#\nstruct S1 : System.Runtime.CompilerServices.IUnion\n{\n    public S1(int x) => ...\n    public S1(string x) => ...\n    object System.Runtime.CompilerServices.IUnion.Value => ...\n    public static implicit operator S1(int x) => ...\n}\n\nstruct S2 : System.Runtime.CompilerServices.IUnion\n{\n    public S2(int x) => ...\n    public S2(string x) => ...\n    object System.Runtime.CompilerServices.IUnion.Value => ...\n    public static explicit operator S2(int x) => ...\n}\n\nclass Program\n{\n    static S1 Test1() => 10; // implicit operator S1(int x) is used\n    static S1 Test2() => (S1)20; // implicit operator S1(int x) is used\n    static S2 Test3() => 10; // Union conversion S2.S2(int) is used\n    static S2 Test4() => (S2)20; // explicit operator S2(int x)\n}\n```\n\nNeed to confirm this is the behavior that we like. Otherwise the conversion rules should be clarified.\n\n**Resolution:**\n\nApproved by the working group.\n\n#### [Resolved] Ref-ness of constructor's parameter\n\nCurrently language allows only by-value and `in` parameters for user-defined conversion operators.\nIt feels like reasons for this restriction are also applicable to constructors suitable for union\nconversions. \n\n**Proposal:**\n\nAdjust definition of a `case type constructor` in `Union types` section above:\n``` diff\n-For each public constructor with exactly one parameter, the type of that parameter is considered a *case type* of the union type.\n+For each public constructor with exactly one **by-value or `in`** parameter, the type of that parameter is considered a *case type* of the union type.\n```\n\n**Resolution:**\n\nApproved by the working group for now. However, we might consider \"splitting\" the set of case type constructors\nand the set of constructors suitable for union type conversions.\n\n#### [Resolved] Nullable Conversions\n\n[Nullable Conversions](https://github.com/dotnet/csharpstandard/blob/09d5f56455cab8868ee9798de8807a2e91fb431f/standard/conversions.md#1061-nullable-conversions) section explicitly lists conversions that can be used as underlying. Current specification doesn't propose\nany adjustments to that list. This result in an error for the following scenario:\n``` c#\nstruct S1 : System.Runtime.CompilerServices.IUnion\n{\n    public S1(int x) => throw null;\n    public S1(string x) => throw null;\n    object System.Runtime.CompilerServices.IUnion.Value => throw null;\n}\n\nclass Program\n{\n    static S1? Test1(int x)\n    {\n        return x; // error CS0029: Cannot implicitly convert type 'int' to 'S1?'\n    }   \n}\n```\n\n**Proposal:**\n\nAdjust the specification to support an implicit nullable conversion from `S` to `T?` backed by a union conversion.\nSpecifically, assuming `T` is a union type there's an implicit conversion to a type `T?` from a type or\nexpression `E` if there's a union conversion from `E` to a type `C` and `C` is a case type of `T`.\nNote, there is no requirement for type of `E` to be a non-nullable value type.\nThe conversion is evaluated as the underlying union conversion from `S` to `T` followed by a wrapping from `T` to `T?`\n\n**Resolution:**\n\nApproved.\n\n#### [Resolved] Lifted conversions\n\nDo we want to adjust [Lifted conversions](https://github.com/dotnet/csharpstandard/blob/09d5f56455cab8868ee9798de8807a2e91fb431f/standard/conversions.md#1062-lifted-conversions)\nsection to support lifted union conversions? Currently they are not allowed:\n\n``` c#\nstruct S1 : System.Runtime.CompilerServices.IUnion\n{\n    public S1(int x) => throw null;\n    public S1(string x) => throw null;\n    object System.Runtime.CompilerServices.IUnion.Value => throw null;\n}\n\nclass Program\n{\n    static S1 Test1(int? x)\n    {\n        return x; // error CS0029: Cannot implicitly convert type 'int?' to 'S1'\n    }   \n\n    static S1? Test2(int? y)\n    {\n        return y; // error CS0029: Cannot implicitly convert type 'int?' to 'S1?'\n    }   \n}\n```\n\n**Resolution:**\n\nNo lifted union conversions for now.\nSome notes from the discussion:\n> The analogy to the user defined conversions breaks down a little here.\n> In general unions are able to contain a null value that comes in.\n> It is not clear whether lifting should create an instance of a union type with `null`\n> value stored in it, or whether it should create a `null` value of `Nullable<Union>`.\n\n#### [Resolved] Block union conversion from an instance of a base type?\n\nOne might find the current behavior confusing:\n``` c#\nstruct S1 : System.Runtime.CompilerServices.IUnion\n{\n    public S1(System.ValueType x)\n    {\n    }\n    public S1(string x) => throw null;\n    object System.Runtime.CompilerServices.IUnion.Value => throw null;\n}\n\nclass Program\n{\n    static S1 Test1(System.ValueType x)\n    {\n        return x; // Union conversion\n    }   \n\n    static S1 Test2(System.ValueType y)\n    {\n        return (S1)y; // Unboxing conversion\n    }   \n}\n```\n\nNote, language explicitly disallows declaring user-defined conversions from a base type. Therefore, it might make sence to not\nallow union conversions like that.\n\n**Resolution:**\n\nDo nothing special for now. Generic scenarios cannot be fully protected anyway.\n\n#### [Resolved] Block union conversion from an instance of an interface type?\n\nOne might find the current behavior confusing:\n``` c#\nstruct S1 : I1, System.Runtime.CompilerServices.IUnion\n{\n    public S1(I1 x) => throw null;\n    public S1(string x) => throw null;\n    object System.Runtime.CompilerServices.IUnion.Value => throw null;\n}\n\ninterface I1 { }\n\nstruct S2 : System.Runtime.CompilerServices.IUnion\n{\n    public S2(I1 x) => throw null;\n    public S2(string x) => throw null;\n    object System.Runtime.CompilerServices.IUnion.Value => throw null;\n}\n\nclass C3 : System.Runtime.CompilerServices.IUnion\n{\n    public C3(I1 x) => throw null;\n    public C3(string x) => throw null;\n    object System.Runtime.CompilerServices.IUnion.Value => throw null;\n}\n\nclass Program\n{\n    static S1 Test1(I1 x)\n    {\n        return x; // Union conversion\n    }   \n\n    static S1 Test2(I1 x)\n    {\n        return (S1)x; // Unboxing\n    }   \n\n    static S2 Test3(I1 x)\n    {\n        return x; // Union conversion\n    }   \n\n    static S2 Test4(I1 x)\n    {\n        return (S2)x; // Union conversion\n    }   \n\n    static C3 Test3(I1 x)\n    {\n        return x; // Union conversion\n    }   \n\n    static C3 Test4(I1 x)\n    {\n        return (C3)x; // Reference conversion\n    }   \n}\n```\n\nNote, language explicitly disallows declaring user-defined conversions from a base type. Therefore, it might make sence to not\nallow union conversions like that.\n\n**Resolution:**\n\nDo nothing special for now. Generic scenarios cannot be fully protected anyway.\n\n### Namespace of IUnion interface\n\nContaining namespace for `IUnion` interface remains unspecified. If the intent is to keep it in a `global` namespace,\nLet’s state that explicitly. \n\n**Proposal**: If this is something simply overlooked,  we could use `System.Runtime.CompilerServices` namespace.\n\n### Classes as `Union` types\n\n#### [Resolved] Checking instance itself for `null`\n\nIf a union type is a class type, it's value might itself be null. What about null checks then?\nThe `null` pattern has been co-opted to check the `Value` property, so how do you check that the union itself isn't null?\n\nFor example:\n-\tWhen `S` is a `Union` struct, ```s is null``` for a value of `S?`is `true`only when `s` itself is `null`. \nWhen `C` is a `Union` class, ```c is null``` for a value of `C?`is `false`when `c` itself is `null`,\nbut it is `true` when `c` itself is not `null`and `c.Value` is `null`.\n\nAnother example:\n``` c#\nclass C1 : IUnion\n{\n    private readonly object? _value;\n\n    public C1(){}\n    public C1(int x) { _value = x; }\n    public C1(string x) { _value = x; }\n    object? IUnion.Value => _value;\n}\n\nclass Program\n{\n    static int Test1(C1? u)\n    {\n        // warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive).\n        //                 For example, the pattern 'null' is not covered.\n        // This is very confusing, the switch expression is indeed not exhaustive (u itself is not\n        // checked for null), but there is a case 'null => 3' in the switch expression. \n        // It looks like the only way to shut off the warning is to use 'case _'. Adding it removes\n        // all benefits of exhaustiveness checking, any union case could be missing and there would\n        // be no diagnostic about that.  \n        return u switch { int => 1, string => 2, null => 3 };\n    }\n}\n```\n\nThis part of the design is clearly optimized around the expectation that a union type is a struct.\nSome options:\n - Too bad. Use `==` for your null check instead of a pattern match.\n - Let the `null` pattern (and implicit null check in other patterns) apply to both the union value and its `Value` property: `u is null ==> u == null || u.Value == null`.\n - Disallow classes from being union types!\n\n#### [Resolved] Deriving from a `Union` class\n\nWhen a class uses a `Union`class as its base class, according to the current specification,\nit becomes a `Union`class itself. This happens because it automatically “inherits” implementation\nof `IUnion` interface, it is not required to re-implement it. At the same time, constructors of the\nderived type define the set of types in this new `Union`. It is very easy to get to very strange language\nbehavior around the two classes:\n\n``` c#\nclass C1 : IUnion\n{\n    private readonly object _value;\n    public C1(long x) { _value = x; }\n    public C1(string x) { _value = x; }\n    object IUnion.Value => _value;\n}\n\nclass C2(int x) : C1(x);\n\nclass Program\n{\n    static int Test1(C1 u)\n    {\n        // Good\n        return u switch { long => 1, string => 2, null => 3 };\n    } \n\n    static int Test2(C2 u)\n    {\n        // error CS8121: An expression of type 'C2' cannot be handled by a pattern of type 'long'.\n        // error CS8121: An expression of type 'C2' cannot be handled by a pattern of type 'string'.\n        return u switch { long => 1, string => 2, null => 3 };\n    } \n}\n```\n\nSome options:\n - Change when a class type is a `Union` type. For example, a class is a `Union` type when all true:\n   * It is `sealed` because derived types won't be considered as `Union`types, allowing which is confusing.\n   * None of its bases implement `IUnion`\n     \n   This is still not perfect. The rules are too subtle. It is easy to make a mistake. There is no diagnostic on\n   the declaration, but `Union` matching doesn’t work.    \n - Disallow classes from being union types.\n\n### [Resolved] The is-type operator\n\n[The is-type operator](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#1214121-the-is-type-operator)\nis specified as a runtime type check. Syntactically it looks very much like a type pattern, but it isn’t. Therefore, the special `Union`matching\nwon’t be used, which could lead to a user confusion.  \n\n``` c#\nstruct S1 : IUnion\n{\n    private readonly object _value;\n    public S1(int x) { _value = x; }\n    public S1(string x) { _value = x; }\n    object IUnion.Value => _value;\n}\n\nclass Program\n{\n    static bool Test1(S1 u)\n    {\n        return u is int; // warning CS0184: The given expression is never of the provided ('int') type\n    }   \n\n    static bool Test2(S1 u)\n    {\n        return u is string and ['1', .., '2']; // Good\n    }   \n}\n```\n\nIn case of a recursive union, the type pattern might give no warning, but it still won’t do what user might think it would do.\n\n**Resolution:**\nShould work as a type pattern.\n\n### List pattern\n\nList pattern always fails with `Union` matching:\n``` c#\nstruct S1 : IUnion\n{\n    private readonly object _value;\n    public S1(int[] x) { _value = x; }\n    public S1(string[] x) { _value = x; }\n    object IUnion.Value => _value;\n}\n\nclass Program\n{\n    static bool Test1(S1 u)\n    {\n        // error CS8985: List patterns may not be used for a value of type 'object'. No suitable 'Length' or 'Count' property was found.\n        // error CS0021: Cannot apply indexing with [] to an expression of type 'object'\n        return u is [10];\n    }   \n}\n\nstatic class Extensions\n{\n    extension(object o)\n    {\n        public int Length => 0;\n    }\n}\n```\n\n### Other questions\n* Both the use of constructors in union conversions and the use of `TryGetValue(...)` in union pattern matching are specified to be lenient when multiple ones apply: They'll just pick one. This should not matter per the well-formedness rules, but are we comfortable with it?\n* The specification subtly relies on the implementation of the `IUnion.Value` property rather than any `Value` property found on the union type itself. This is meant to give greater flexibility for existing types (which may have their own `Value` property for other uses) to implement the pattern. But it is awkward, and inconsistent with how other members are found and used directly on the union type. Should we make a change? Some other options:\n    * Require union types to expose a public `Value` property.\n    * Prefer a public `Value` property if it exists, but fall back to the `IUnion.Value` implementation if not (similar to `GetEnumerator` rules).\n* The proposed union declaration syntax isn't universally loved, particularly when it comes to expressing the case types. Alternatives so far also meet with criticism, but it's possible we will end up making a change. Some top concerns voiced about the current one:\n    * Commas as separators between case types may seem to imply that order matters.\n    * Parenthesized lists look too much like primary constructors (despite not having parameter names).\n    * Too different from enums, which have their \"cases\" in curly braces.\n* While union declarations generate structs with a single reference field, they are still somewhat susceptible to unexpected behavior when used in a concurrent context. For instance, if a user-defined function member dereferences `this` more than once, the containing variable may have been reassigned as a whole by another thread in between the two accesses. The compiler could generate code to copy `this` to a local when necessary. Should it? In general, what degree of concurrency resiliency is desirable and reasonably attainable?\n"
  },
  {
    "path": "proposals/unsafe-evolution.md",
    "content": "# Unsafe Evolution\n\nChampion issue: https://github.com/dotnet/csharplang/issues/9704\n\n## Summary\n\nWe update the definition of `unsafe` in C# from referring to locations where pointer types are used, to be locations where memory unmanaged by the runtime is dereferenced. These locations\nare where memory unsafety occurs, and are responsible for the bulk of CVEs (Common Vulnerabilities and Exposures) categorized as memory safety issues.\n\n```cs\nvoid M()\n{\n    int i = 1;\n    int* ptr = &i; // Not unsafe\n    unsafe\n    {\n        Console.WriteLine(*ptr); // Dereference of memory not managed by the runtime. This is unsafe.\n        ref int intRef = Unsafe.AsRef(ptr); // Conversion of memory not managed by the runtime to a `ref`. This is unsafe.\n    }\n}\n\nnamespace System.Runtime.CompilerServices\n{\n    public static class Unsafe\n    {\n        [RequiresUnsafe] // APIs annotated with this attribute need an unsafe context.\n        public static ref T AsRef<T>(void* source) { /* ... */ }\n    }\n}\n```\n\n## Motivation\n\nBackground for this feature can also be found in https://github.com/dotnet/designs/blob/main/accepted/2025/memory-safety/caller-unsafe.md, which tracks the broader ecosystem changes that will be needed as part of this proposal.\nThese include BCL updates to properly annotate methods as being unsafe, as well as tooling updates for better understanding of where memory unsafety occurs. For C#\nspecifically, we want to make sure that memory unsafety is properly tracked by the language; today, it can be difficult to look at a program holistically and understand all locations where\nmemory unsafety occurs. This is because various helpers such as the `System.Runtime.CompilerServices.Unsafe`, `System.Runtime.InteropServices.Marshal`, and others do not express that they\nviolate memory safety and need special consideration. Methods that then use these helpers aren't immediately obvious, and when auditing code for memory safety issues (either ahead of time\nwhen doing review, or when trying to determine the cause of a vulnerability that is being reported) it can be difficult to pinpoint the locations that could be contributing to issues.\n\nHistorically, `unsafe` in C# has referred to a specific memory-safety hole: the existence of pointer types. The moment that a pointer type is no longer involved, C# is perfectly happy to let\nmemory unsafety lie latent in code. It is this issue that we are looking to address with this evolution of `unsafe` in C# and the .NET ecosystem, labeling areas where memory unsafety could\npotentially occur, making it easier for reviewers and auditors to understand the boundaries of potential memory unsafety in a program. Importantly, this means that we will be _changing_\nthe meaning of `unsafe`, not just augmenting it. The existence of a pointer is not itself unsafe; the unsafe action is dereferencing the pointer. This extends further to types themselves;\ntypes cannot be inherently unsafe. It is only the action of using a type that could be unsafe, not the existence of that type.\n\nIn order for this information to flow through the system, we therefore need to have a way to mark methods themselves as unsafe. Applying an attribute (`RequiresUnsafe`) to a member will indicate that\nthe member has memory safety concerns and any usages must be manually validated by the programmer using the member (the error will go away if the member is used inside an `unsafe` context).\nWe are not going to use the `unsafe` modifier in signature to denote *requires-unsafe* members to avoid a breaking change\n(it won't even be required to allow pointers in signature as pointers are now safe; it will merely introduce an `unsafe` context).\n\nNevertheless, this is still a breaking change for particular segments of the C# user base. Our hope is that, for many of our users, this is effectively transparent, and updating to the new rules\nwill be seamless. However, given that some large API surfaces like large parts of reflection may need to be marked `unsafe`, we do think it likely that there will need to be a decent on-ramp to\nthe new rules to avoid entirely bifurcating the ecosystem.\n\n## Breaking changes\n\nThe following breaking changes can be observed when updating to a compiler implementing this language feature.\n\n- Specifying `[RequiresUnsafe]` attribute on [unsupported symbol kinds](#attributes) is a compile-time error.\n- If the [updated memory safety rules](#attributes) are enabled (which might be the default or even the only option in a future .NET version):\n  - APIs marked with `[RequiresUnsafe]` or `extern` require an `unsafe` context when used.\n  - `stackalloc` under [certain conditions](#stack-allocation) requires an `unsafe` context.\n- Under a new warnlevel:\n  - Applying `[RequiresUnsafe]` warns if the updated memory safety rules are not enabled.\n\n## Detailed Design\n\nTerminology: we call members *requires-unsafe* (previously known as *caller-unsafe*) if\n- under [the updated memory safety rules](#attributes) they [have the `RequiresUnsafe` attribute](#attributes) or [are `extern`](#extern),\n- under [the legacy memory safety rules](#attributes) they [contain pointers in signature](#compat-mode).\n\n### Existing `unsafe` rules\n\nThe existing C# specification has a large section devoted to `unsafe`: [§24 Unsafe code][unsafe-code]. It is defined as conditionally normative, as it is not required for a valid C# compiler\nto support the `unsafe` feature. Much of what is currently considered conditionally normative will no longer be so after this change, as most of the definition of pointers is no longer considered\nunsafe in itself. [Pointer types][pointer-types-spec], [Fixed and moveable variables][fixed-and-moveable-variables], all [pointer expressions][pointer-expressions] (except for\n[pointer indirection][pointer-indirection], [pointer member access][pointer-member-access], and [pointer element access][pointer-element-access]), and [the `fixed` statement][fixed-statement]\nare all no longer considered `unsafe`, and exist in normal C# with no requirement to be used in an `unsafe` context. Similarly, declaring a [fixed size buffer][fixed-size-buffer-declarations] or\nan initialized [`stackalloc`][stack-allocation-spec] are also perfectly legal in safe C#. For all of these cases, it is only _accessing_ the memory that is unsafe.\n\nGiven the extensive rewrite of both the `unsafe` code section and other parts C# specification inherent in this change, it would be unwieldy and likely not useful to provide a line-by-line diff\nof the existing rules of the specification. Instead, we will provide an overview of the change to make in a given section, as well as specific new rules for what is allowed in `unsafe` contexts.\n\n#### Redefining expressions that require unsafe contexts\n\nThe following expressions require an `unsafe` context when used:\n\n* [Pointer indirections][pointer-indirection]\n* [Pointer member access][pointer-member-access]\n* [Pointer element access][pointer-element-access]\n* Function pointer invocation\n* Element access on a fixed-size buffer\n* `stackalloc` under the conditions defined [below](#stack-allocation)\n\nIn addition to these expressions, expressions and statements can also conditionally require an `unsafe` context if they depend on any symbol that is marked as `unsafe`. For example, calling a method\nthat is *requires-unsafe* will cause the _invocation_expression_ to require an `unsafe` context. Statements with invocations embedded (such as `using`s, `foreach`, and similar) can also require an\n`unsafe` context when they use a *requires-unsafe* member.\n\nWhen we say \"requires an unsafe context\" or similar in this document, it means emitting an error that the construct requires an `unsafe` context to be used.\n\n> [!NOTE]\n> This section probably needs expansion to formally declare what each expression and statement must consider to require an `unsafe` context.\n\n#### Pointer types\n\nAs mentioned, pointers become no longer inherently unsafe. Any references to unsafe contexts in [§24.3][pointer-types-spec] are deleted. Pointer types exist in normal C# and do not require `unsafe`\nto bring them into existence. The type definitions should be worked into [§8.1](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/types.md#81-general) and its following sections, as\nother types.\n\nSimilarly, [pointer conversions][pointer-conversions] should be worked into [§10](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/conversions.md#10-conversions), with references to\n`unsafe` contexts removed.\n\nSimilarly, [pointer expressions][pointer-expressions], except for [pointer indirection][pointer-indirection], [pointer member access][pointer-member-access], and\n[pointer element access][pointer-element-access], should be worked into [§12](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md), with references to `unsafe` contexts\nremoved. No semantics change about the meaning of these expressions; the only change is that they no longer require an `unsafe` context to use.\n\nFor [pointer indirection][pointer-indirection], [pointer member access][pointer-member-access], and [pointer element access][pointer-element-access], these operators remain unsafe, as these\naccess memory that is not managed the runtime. They remain in [§24][unsafe-code], and continue to require an `unsafe` context to be used. Any use outside of an `unsafe` context is an error.\nNo semantics about these operators change; they still continue to mean exactly the same thing that they do today. These expressions must always occur in an `unsafe` context.\n\nThe [fixed statement][fixed-statement] moves to [§13](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md), with references to `unsafe` contexts removed.\n\nFunction pointers are not yet incorporated into the main C# specification, but they are similarly affected; everything but function pointer invocation is moved into the standard specification.\nA function pointer invocation expression must always occur in an `unsafe` context.\n\n#### Fixed-size buffers\n\nThe story for [fixed-size buffers][fixed-size-buffer-declarations] is similar to [pointers](#pointer-types). The definition of a fixed-size buffer is not itself dangerous, and moves to\n[§16.3](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/structs.md#163-struct-members). Accessing a fixed-size buffer in an expression is similarly safe, unless the expression occurs\nas the _primary_expression_ of an `element_access`; these are evaluated as a _pointer_element_access_, which is unsafe, as per the rules above.\n\n#### Stack allocation\n\nAgain, the story for [stack allocation][stack-allocation-spec] is very similar to [pointers](#pointer-types). Converting a `stackalloc` to a pointer is no longer unsafe; it is the deference of that\npointer that is unsafe. We do add one new rule, however:\n\nA _stackalloc_expression_ is unsafe if all of the following statements are true:\n\n* The _stackalloc_expression_ is being converted to a `Span<T>` or a `ReadOnlySpan<T>`.\n* The _stackalloc_expression_ does not have a _stackalloc_initializer_.\n* The _stackalloc_expression_ is used within a member that has `SkipLocalsInitAttribute` applied.\n\nIn these contexts, the resulting stack space could have unknown memory contents, and it is being converted to a type that provides a safe wrapper around unmanaged memory access. This violates the\ncontract of `Span<T>` and `ReadOnlySpan<T>`, and so must be subject to extra scrutiny by the author and reviewers of such code.\n\n> [!NOTE]\n> This means that assigning a `stackalloc` to a pointer is _always_ safe, regardless of context.\n\n#### `sizeof`\n\nFor certain predefined types, `sizeof` has always been constant and safe ([§12.8.19][sizeof-const]) and that remains unchanged under the new rules.\nFor other types, `sizeof` used to require unsafe context ([§24.6.9][sizeof-unsafe]) but it is now safe under the new memory safety rules.\n\n### Overriding, inheritance, and implementation\n\nIt is a memory safety error to add `RequiresUnsafe` at the member level in any override or implementation of a member that is not *requires-unsafe* originally, because callers may be using the base\ndefinition and not see any addition of `RequiresUnsafe` by a derived implementation.\n\n### Delegates and lambdas\n\nIt is a memory safety error to convert a *requires-unsafe* member to a delegate type outside the `unsafe` context.\nDelegate types and [_function types_](csharp-10.0/lambda-improvements.md#natural-function-type) cannot be *requires-unsafe*.\nIt is a compile-time error to apply `RequiresUnsafe` on a lambda symbol.\n\n### `extern`\n\nBecause `extern` methods are to native locations that cannot be guaranteed by the runtime, any `extern` method is automatically considered *requires-unsafe*\nif compiled under the updated memory safety rules (i.e., it gets the `RequiresUnsafeAttribute`).\nEven methods that only take `unmanaged` parameters by value cannot be safely called by C#,\nas the calling convention used for the method could be incorrectly specified by the user and must be manually verified by review.\n\n`extern` methods from assemblies using the legacy memory safety rules are not considered implicitly `unsafe` because\n`extern` is considered implementation detail that is not part of public surface.\n`extern` is not guaranteed to be preserved in reference assemblies.\n\nNote that this is different from the [compat mode](#compat-mode) which applies to legacy-rules assemblies too\nbecause methods with pointers in signature would always need an unsafe context at the call site.\n\n### Unsafe modifiers and contexts\n\nToday (and unchanged in this proposal), as covered by the [unsafe context specification][unsafe-context-spec], `unsafe` behaves in a lexical manner,\nmarking the entire textual body contained by the `unsafe` block as an `unsafe` context (except for iterator bodies),\nand also some surrounding contexts in case of declarations:\n\n```cs\nclass A : Attribute\n{\n    [RequiresUnsafe] public A() { }\n}\nclass C\n{\n    [A] void M1() { } // error: cannot use `A..ctor` in safe context\n    [A] unsafe void M1() { } // ok: the `unsafe` context applies to the `A..ctor` usage\n}\n```\n\nSince pointer types are now safe, an `unsafe` modifier on declarations without bodies does not have a meaning anymore. Hence `unsafe` on the following declarations will produce a warning:\n- `delegate`.\n\n`RequiresUnsafe` on a member is _not_ applied to any nested anonymous or local functions inside the member. To mark an anonymous or local function as *requires-unsafe*, it must manually be marked as `RequiresUnsafe`. The same goes for\nanonymous and local functions declared inside of an `unsafe` block.\n\nWhen a member is `partial`, both parts must agree on the `unsafe` modifier, but only one can specify the `RequiresUnsafe` attribute, unchanged from C# rules today.\n\nFor properties, `get` and `set/init` accessors can be independently declared as `RequiresUnsafe`; marking the entire property as `RequiresUnsafe` means that both the `get` and `set/init` accessors are *requires-unsafe*.\nFor events, `add` and `remove` accessors can be independently declared as `RequiresUnsafe`; marking the entire event as `RequiresUnsafe` means that both the `add` and `remove` accessors are *requires-unsafe*.\n\n#### Attributes\n\nWhen an assembly is compiled with the new memory safety rules, it gets marked with `MemorySafetyRulesAttribute` (detailed below), filled in with `15` as the language version. This is a signal to\nany downstream consumers that any members defined in the assembly will be properly attributed with `RequiresUnsafeAttribute` (detailed below) if an `unsafe` context is required to call them.\nAny member in such an assembly that is not marked with `RequiresUnsafeAttribute` does not require an `unsafe` context to be called, regardless of the types in the signature of the member.\n\nIt is an error to apply the `MemorySafetyRulesAttribute` to any symbol explicitly in source.\n\nThe compiler ignores `RequiresUnsafeAttribute`-marked members from assemblies that are using the legacy memory safety rules (instead, the [compat mode](#compat-mode) is used there).\n\nThe compiler will emit a warning if `RequiresUnsafe` is used under the legacy memory safety rules and an error if it is applied to unsupported symbol kinds\n(note that this excludes symbol kinds that should be banned already by `AttributeUsageAttribute` on the attribute's definition):\n- destructors,\n- static constructors,\n- lambdas.\n\nWhen a member under the new memory safety rules is `extern`, the compiler will implicitly apply the `RequiresUnsafeAttribute` to the member in metadata.\nWhen a user-facing *requires-unsafe* member generates hidden members, such as an auto-property's get/set methods,\nboth the user-facing member and any hidden members generated by that user-facing member are all *requires-unsafe*, and `RequiresUnsafeAttribute` is applied to all of them.\n\nThe `MemorySafetyRulesAttribute` definition is synthesized by the compiler if necessary per standard well-known member rules.\nThe `RequiresUnsafeAttribute` definition is _not_ synthesized by the compiler, and a compilation error is reported if the expected attribute constructor cannot be resolved per standard well-known member rules.\n\n```cs\nnamespace System.Runtime.CompilerServices\n{\n    /// <summary>Indicates the language version of the memory safety rules used when the module was compiled.</summary>\n    [AttributeUsage(AttributeTargets.Module, Inherited = false)]\n    public sealed class MemorySafetyRulesAttribute : Attribute\n    {\n        /// <summary>Initializes a new instance of the <see cref=\"MemorySafetyRulesAttribute\"/> class.</summary>\n        /// <param name=\"version\">The language version of the memory safety rules used when the module was compiled.</param>\n        public MemorySafetyRulesAttribute(int version) => Version = version;\n \n        /// <summary>Gets the language version of the memory safety rules used when the module was compiled.</summary>\n        public int Version { get; }\n    }\n\n    [AttributeUsage(AttributeTargets.Event | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Constructor, AllowMultiple = false, Inherited = true)]\n    public sealed class RequiresUnsafeAttribute : Attribute\n    {\n    }\n}\n```\n\n#### Compat mode\n\nFor compat purposes, and to reduce the number of false negatives that occur when enabling the new rules, we have a fallback rule for modules that have not been updated to the new rules. For such modules,\na member is considered *requires-unsafe* if it contains a pointer or function pointer type somewhere among its parameter types or return type (can be nested in a non-pointer type, e.g., `int*[]`).\nNote that this doesn't apply to pointers in constraint types (e.g., `where T : I<int*[]>`) as those wouldn't need unsafe context at the call sites previously either.\n\nThis does not include substituted generic parameters (e.g., method `I<T>.M(T)` when substituted `T` for `int*[]`)\nas there is no type-safe way for the target member to use that pointer type for anything anyway.\n\n### VB\n\nWe do not need to add support to Visual Basic for `[RequiresUnsafe]` members since there are no `unsafe` contexts in VB today and no way to work with pointers there either.\n\n## Alternatives\n\n### Use `unsafe` to denote *requires-unsafe* members\n\nInstead of using `RequiresUnsafeAttribute` to denote *requires-unsafe* members, we could use the `unsafe` keyword on the member\n(and only use the attribute for metadata representation of *requires-unsafe* members).\nSee [a previous version of this speclet](https://github.com/dotnet/csharplang/blob/61f06216967ed264a8f83c71bff482f3eb6ac113/proposals/unsafe-evolution.md)\nbefore [the alternative](https://github.com/dotnet/csharplang/blob/61f06216967ed264a8f83c71bff482f3eb6ac113/meetings/working-groups/unsafe-evolution/unsafe-alternative-syntax.md) was incorporated into it.\n\nAdvantages of `unsafe`:\n- similar to other languages and hence easier to understand,\n- more discoverable than an attribute.\n\nAdvantages of an attribute (or another keyword):\n- avoids breaking existing members marked as `unsafe`,\n- incremental adoption possible (member-by-member),\n- doesn't force marking the whole body as `unsafe` (even with `unsafe` keyword we could\n  [change](https://github.com/dotnet/csharplang/blob/61f06216967ed264a8f83c71bff482f3eb6ac113/proposals/unsafe-evolution.md#unsafe-context-defaults-in-members)\n  `unsafe` to not have an effect on bodies though).\n\n## Open questions\n\n### Local functions/lambda safe contexts\n\nRight now `unsafe` on a method body is lexically scoped. Any nested local functions or lambdas inherit this, and their bodies are in a memory unsafe context. Is this behavior that we want to keep in\nthe language?\n\n### Delegate type `unsafe`ty\n\nWe could allow marking delegate types and lambdas (and function types) as *requires-unsafe*.\nThis would require several additional rules (outside `unsafe` context):\n- disallow using *requires-unsafe* delegates as type arguments,\n- disallow converting those delegates to anything that's not *requires-unsafe* (`Delegate`,`Expression`, and `object`),\nWithout this, there is a risk of forcing `unsafe` annotations in the wrong spot and having an area where the real area of `unsafe`ty isn't properly called out.\n\n#### Lambda/method group conversion to safe delegate types\n\nIf we allow `unsafe` lambdas and delegates, should conversion of a *requires-unsafe* lambda or method group to a non-*requires-unsafe* delegate type permitted without warning or error in an `unsafe` context? If we don't do this, then it could be fairly painful\nfor various parts of the ecosystem, particularly any enumerables that are passed through LINQ queries.\n\n#### Lambda/method group natural types\n\nToday, the only real impact on semantics and codegen (besides additional metadata) is changing the *function_type* of a lambda or method group when marked as `RequiresUnsafe`. If we were to avoid doing this, then\nthere would be no real impact to either, which could give adopters more confidence that behavior has not subtly changed under the hood.\n\n### `stackalloc` as initialized\n\nToday, [the spec](https://github.com/dotnet/csharpstandard/blob/draft-v9/standard/expressions.md#12822-stack-allocation) always considers `stackalloc` memory as uninitialized, and says that the contents\nare undefined unless manually cleared or assigned. Do we consider this a spec bug, or do we need to change what we consider `unsafe` for `stackalloc` purposes?\n\n### `unsafe` expressions\n\nOther languages with more comprehensive `unsafe` features have added `unsafe` as an expression, to enable improved user ergonomics and allow authors to more precisely limit where `unsafe` is used. Is this\nsomething that we want to have in C#? Consider an inline call to an `unsafe` member that handles the safety directly: right now, the author would either need to wrap the entire statement in an `unsafe`\nblock, expanding the scope of the `unsafe` context, or they would need to break out the inner function call into an intermediate variable.\n\n```cs\nextern int Add(int i1, int i2); // Some fancy extern addition function\n\n// Code I want to write:\nConsole.WriteLine(unsafe(Add(1, 2)));\n\n// Code I have to write option 1, unsafe context unnecessary includes the WriteLine call\nunsafe\n{\n    Console.WriteLine(Add(1, 2));\n}\n\n// Code I have to write option 2, very verbose and harder to read:\nint result;\nunsafe\n{\n    result = Add(1, 2);\n}\nConsole.WriteLine(result);\n```\n\n### More `unsafe` contexts and relaxations\n\nBefore the change to use [an attribute instead of a modifier](#use-unsafe-to-denote-requires-unsafe-members) to denote *requires-unsafe* members,\nwe had allowed `unsafe` modifier on property accessors (we hadn't allowed it on event accessors since there were *no* modifiers allowed previously).\nWe since reverted that. Should we still allow it even though it wouldn't denote *requires-unsafe* members anymore, just an unsafe context?\n\nIf we are allowing more `unsafe` contexts, should we relax more restrictions around `unsafe` and pointer parameters in iterators and async methods too?\nEspecially allowing `await UnsafeMethod()` would be useful because now users have to rewrite that to `Task t; unsafe { t = UnsafeMethod(); } await t;`.\nSee [ref/unsafe in iterators/async](./csharp-13.0/ref-unsafe-in-iterators-async.md#alternatives) for more details.\n\nShould we also allow `&UnsafeMethod` in safe context? Today as the proposal stands, this requires `unsafe` context if the method is marked as `[RequiresUnsafe]`.\nBut since we are just getting its address, which will need `unsafe` context when dereferenced/called, we could allow the address-of itself in a safe context.\n\n### `unsafe` on types\n\nWe could consider not automatically making the entire lexical scope of an `unsafe` type to be an `unsafe` context and warn for an `unsafe` on a type as it would have no meaning\napart from edge cases like the following which we might not care about because they have no real-world use-cases:\n\n```cs\nclass A : Attribute\n{\n    [RequiresUnsafe] public A() { }\n}\n[A] class C; // unavoidable error for using requires-unsafe A..ctor?\n[A] unsafe class C; // if unsafe still introduces an unsafe context, this makes the error go away\n```\n\n### More meaningless `unsafe` warnings\n\nShould more declarations produce the meaningless `unsafe` warning?\nFor example, fields without initializers (assuming we don't support [*requires-unsafe* fields](#requires-unsafe-fields)), methods with empty bodies (or `extern`), etc.\nWe already have an IDE analyzer for unnecessary `unsafe` though.\n\n### *Requires-unsafe* fields\n\nToday, no proposal is made around `RequiresUnsafe` on a field. We may need to add it though, such that any read from or write to a field marked as *requires-unsafe* must be in an `unsafe` context. This would\nenable us to better annotate the concerns around code such as:\n\n```cs\nclass SafeWrapper\n{\n     internal byte* _p;\n\n     public void DoStuff()\n     {\n            unsafe\n            {\n                  // ... validate that the object state is good ...\n                  // ... perform operation with _p .... \n            }\n     }\n\n}\n\n// Elsewhere in safe code:\nvoid M(SafeWrapper w)\n{\n     w._p = stackalloc byte[10];\n}\n```\n\nShould we also mark auto-property's backing field with `[RequiresUnsafe]`?\n\n### Taking the address of an uninitialized variable\n\nToday, taking the address of a not definitely assigned variable can consider that variable definitely assigned, exposing uninitialized member. We have a couple of options to solving that:\n\n1. Require that variables be definitely assigned before allowing an address-of operator to be used on them.\n2. Make taking the address of an uninitialized variable unsafe.\n\nExamples:\n\n```cs\nstatic void SkipInit<T>(out T value)  \n{\n    // value is considered definitely assigned after the address-of\n    fixed (void* ptr = &value);\n}\n```\n\n```cs\nint i;\n// i is considered definitely assigned after the address-of\n_ = &i;\n// Incrementing whatever was on the stack\ni++;\n```\n\n### Value of `MemorySafetyRulesAttribute`\n\nWhat should be the \"enabled\"/\"updated\" memory safety rules version? `2`? `15`? `11`?\nSee also https://github.com/dotnet/designs/blob/main/accepted/2025/memory-safety/sdk-memory-safety-enforcement.md.\n\n### `extern` implicitly unsafe\n\nThis is currently the only place where `RequiresUnsafeAttribute` is implicitly applied by the compiler.\nAre we okay with this outlier?\n\nAlso, CoreLib exposes many extern methods (FCalls) as safe today.\nTreating extern methods as implicitly unsafe will require wrapping the implicitly unsafe extern methods with a safe wrapper.\nWe may run into situations where adding the extra wrapper is difficult due to runtime implementation details.\n\n### `RequiresUnsafe` on `partial` members\n\nIt is required to have the `unsafe` modifier at both partial member parts by pre-existing C# rules.\nOn the other hand, attributes may be specified only at one of those parts\nand even cannot be specified at both parts unless they have `AllowMultiple`, but then they are effectively present multiple times.\nWe have [changed](#use-unsafe-to-denote-requires-unsafe-members) the way to denote *requires-unsafe* members via an attribute instead of the `unsafe` modifier\nbut haven't discussed this aspect of the change.\nShould we allow the attribute to be specified multiple times (via `AllowMultiple` or via special compiler behavior for this attribute and `partial` members only),\nor even require it (via special compiler checks for this attribute only)?\n\n### `new()` constraint\n\nDo we want to support `new()` with *requires-unsafe* (something we currently don't seem to support in the compiler for other features, like `Obsolete`)?\n\n```cs\nM<C>(); // should be an error outside `unsafe` context since `M` calls the requires-unsafe `C..ctor`?\n\nvoid M<T>() where T : new()\n{\n    _ = new T();\n}\n\nclass C\n{\n    [RequiresUnsafe] public C() { }\n}\n```\n\n#### `new()` constraint and `using`s\n\nHow should it behave in aliases and static usings?\n- Should it be an error at the `using` declaration, suppressable via the `unsafe` keyword we already support there, or\n- should it be an error normally at the use site like it would be if used directly without an alias or static using?\n\n> [!NOTE]\n> In the second case, we would need to add \"meaningless `unsafe`\" warning for using aliases and static usings.\n\n```cs\nclass C\n{\n    [RequiresUnsafe] public C() { }\n}\n\nclass D<T> where T : new()\n{\n    public static void M() { _ = new T(); }\n}\n```\n\n```cs\nusing X = D<C>;\nusing unsafe X = D<C>;\n\nX.M();\n```\n\n```cs\nusing static D<C>;\nusing static unsafe D<C>;\n\nM();\n```\n\nNote that other constraints behave like the former option today:\n\n```cs\nusing X = D<C>; // error here\n\n_ = new X(); // ok\n_ = new D<C>(); // error here\n\nclass C\n{\n    public C(int x) { }\n}\n\nclass D<T> where T : new();\n```\n\n### Should more constructs be `unsafe`?\n\n- `dynamic` (probably should match what BCL decides for reflection APIs)\n\n## Answered questions\n\n### How breaking do we want to skew\n\n<details>\n<summary>Question text</summary>\n\nThe initial proposal is a maximally-breaking approach, mainly as a litmus test for how aggressive we want to be. It proposes no ability to opt in/out sections of the code, changes the meaning of `unsafe`\non methods, prohibits the usage of `unsafe` on types, uses errors instead of warnings, and generally forces migration to occur all at once, at the time the compiler is upgraded (and then potentially\nrepeatedly as dependencies update and add `unsafe` to members that were already in use). However, we have a wealth of experience in making changes like this that we can draw on to scope the size of\nthe breaks down and allow incremental adoption. These options are covered below.\n\n#### Opt in/out for code regions\n\nThis is not the first time that C# has redefined the \"base\" case of unannotated code. C# 8.0 introduced the nullable reference type feature, which in many ways can be seen as a blueprint for how the\n`unsafe` feature is shaping up. It had similar goals (prevent bugs that cost billions of dollars by redefining the way default C# is interpreted) and a similar general featureset (add new info to types\nto propagate states and avoid bugs). It was also heavily breaking, and needed a strong set of opt in and opt out functionality to allow the feature to be adopted over time by codebases. That\nfunctionality is the \"nullable reference type context\". This is a lexical scope that informs the compiler, for a given region in code, both how to interpret unannotated type references and what types\nof warnings to give to the user. We could use this as a model for `unsafe` as well, adding an \"safety rules context\" or similar to allow controlling whether these new rules are being applied or not.\n\nOne advantage that we have with the new `unsafe` features is that they are much less prevalent. While there are a decent number of `unsafe` calls in top libraries, our guesstimates on the percentage\nof top libraries that use `unsafe` is much lower than \"every single line of C# code ever written\". Hopefully this means that, while some ability to opt in/out is possibly needed, we don't need as\ncomplicated a mechanism as nullable has, with dedicated preprocessor switches and the like.\n\n#### Warnings vs errors\n\nThe proposal currently states that memory safety requirements are currently enforced via a warning, rather than error. This is drawing from our experience working with the nullable feature, where warnings\nallowed code bases to incrementally adopt the new feature and not need to convert large swathes of code all at once. We expect a similar process will be needed for unsafe warnings: many codebases will\nsimply be able to turn on the new rules globally and move on with their lives. But we expect the codebases we most care about adopting the new rules will have large amounts of code to annotate, and we\nwant them to be able to move forward with the feature, rather than seeing a wall of errors and giving up immediately. By making the requirements warnings, we allow these codebases to fix warnings file-by-file\nor method-by-method as required, disabling the warnings everywhere else.\n\n#### Method signature breaks\n\nRight now, we propose that `unsafe` as a keyword on the method move from something that is lexically scoped without a semantic impact to something that has semantic impact, and isn't lexically scoped.\nWe could limit this break by introducing a new keyword for when the caller of a method or member must be in an `unsafe` context; for example, `callerunsafe` as a modifier.\n\n#### Defaults for source generators\n\nFor nullable, we force generator authors to explicitly opt-in to nullable regardless of whether the entire project has opted into the feature by default, so that generator output isn't broken by the user\nturning on nullable and warn as error. Should we do the same for source generators?\n\n</details>\n\n#### Conclusion\n\nAnswered in https://github.com/dotnet/csharplang/blob/main/meetings/2025/LDM-2025-11-05.md#unsafe-evolution. We will report errors for memory safety issues when the new rules are turned on, and no exceptions\nfor source generators will be made.\n\n\n[unsafe-code]: https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#128-primary-expressions\n[sizeof-const]: https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12819-the-sizeof-operator\n[unsafe-context-spec]: https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#242-unsafe-contexts\n[pointer-types-spec]: https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#243-pointer-types\n[fixed-and-moveable-variables]: https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#244-fixed-and-moveable-variables\n[pointer-conversions]: https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#245-pointer-conversions\n[pointer-expressions]: https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#246-pointers-in-expressions\n[the-addressof-operator]: https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#2465-the-address-of-operator\n[pointer-indirection]: https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#2462-pointer-indirection\n[pointer-member-access]: https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#2463-pointer-member-access\n[pointer-element-access]: https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#2464-pointer-element-access\n[sizeof-unsafe]: https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#2469-the-sizeof-operator\n[fixed-statement]: https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#247-the-fixed-statement\n[fixed-size-buffer-declarations]: https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#2482-fixed-size-buffer-declarations\n[stack-allocation-spec]: https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#249-stack-allocation\n"
  },
  {
    "path": "proposals/unsigned-sizeof.md",
    "content": "# Unsigned `sizeof`\n\nChampion issue: <https://github.com/dotnet/csharplang/issues/9633>\n\n## Summary\n\nThis proposal enables `sizeof` expressions without a constant value to implicitly convert to unsigned integer types the same size as `uint` or larger:\n\n```cs\nuint size = sizeof(SomeStruct);\n```\n\n## Motivation\n\nThis is a minute language change which alleviates a paper cut within native interop domains.\n\nA common pattern for native Windows APIs involves assigning the size of a struct to one of its own fields, or passing the struct's size as an additional argument to a function along with a pointer to the struct. The language provides the required value easily using `sizeof(NativeStruct)`. This is only permitted in unsafe code, and it is safe so long as the struct is authored to be blittable—to have a memory layout identical to what the native API expects.\n\nThese same native APIs make heavy use of unsigned integer types. The C# struct or method representing the native API will often use `uint` or other unsigned types in order to faithfully preserve the native API's distinction between signed and unsigned values. For example, `Microsoft.Windows.CsWin32` is a source generator which autogenerates such structs and methods based on Windows header files.\n\nA size is never negative. Thus, invariably, the native API is defined to take an unsigned integer, and the automated C# projection of that API requires the language user to produce a `uint` value for the size. Since the C# `sizeof` operator produces a non-constant `int` value for a user-defined struct, this results in the user having to insert explicit `uint` casts most of the time that `sizeof` is used with a struct.\n\nFor example:\n\n```cs\nvar buffer = default(PROCESS_BASIC_INFORMATION);\n\nPInvoke.NtQueryInformationProcess(\n    processHandle,\n    PROCESSINFOCLASS.ProcessBasicInformation,\n    &buffer,\n    (uint)sizeof(PROCESS_BASIC_INFORMATION),\n    null);\n```\n\nOr:\n\n```cs\nvar header = default(BITMAPINFOHEADER);\nheader.biSize = (uint)sizeof(BITMAPINFOHEADER);\n\n// Generated from native headers:\nstruct BITMAPINFOHEADER\n{\n    public uint biSize;\n    public int biWidth;\n    // ...\n}\n```\n\nThe frequent insertion of explicit uint casts is ironic: the compiler is emitting the `sizeof` CIL instruction which itself natively produces an `unsigned int32` as defined by ECMA-335, 6th edition, §III.2.45.\n\n## Detailed design\n\nA new implicit conversion is defined, an _unsigned sizeof conversion_, from a `sizeof` expression to `uint`, `nuint`, or `ulong`.\n\nThis conversion is added to the list of standard implicit conversions so that a `sizeof` expression may implicitly convert to a user-defined type which has an implicit conversion from an unsigned integer type.\n\n## Specification\n\nThe [sizeof operator](https://github.com/dotnet/csharpstandard/blob/draft-v9/standard/expressions.md#12819-the-sizeof-operator) section is adjusted as follows (additions in **bold**):\n\n> ### 12.8.19 The sizeof operator\n>\n> The `sizeof` operator returns the number of 8-bit bytes occupied by a variable of a given type **as an `int` value**.\n\nThen, a new conversion is added to the [Implicit conversions](https://github.com/dotnet/csharpstandard/blob/draft-v9/standard/conversions.md#102-implicit-conversions) section:\n\n> ### Unsigned sizeof conversions\n>\n> An implicit conversion exists from a _sizeof_expression_ ([§12.8.19](https://github.com/dotnet/csharpstandard/blob/draft-v9/standard/expressions.md#12819-the-sizeof-operator)) to `uint`.\n\nThe new conversion is added to the [Standard implicit conversions](https://github.com/dotnet/csharpstandard/blob/draft-v9/standard/conversions.md#1042-standard-implicit-conversions) section:\n\n> The following implicit conversions are classified as standard implicit conversions:\n>\n> - Identity conversions ([§10.2.2](conversions.md#1022-identity-conversion))\n> - Implicit numeric conversions ([§10.2.3](conversions.md#1023-implicit-numeric-conversions))\n> - Implicit nullable conversions ([§10.2.6](conversions.md#1026-implicit-nullable-conversions))\n> - Null literal conversions ([§10.2.7](conversions.md#1027-null-literal-conversions))\n> - Implicit reference conversions ([§10.2.8](conversions.md#1028-implicit-reference-conversions))\n> - Boxing conversions ([§10.2.9](conversions.md#1029-boxing-conversions))\n> - Implicit constant expression conversions ([§10.2.11](conversions.md#10211-implicit-constant-expression-conversions))\n> - Implicit conversions involving type parameters ([§10.2.12](conversions.md#10212-implicit-conversions-involving-type-parameters))\n> - **Unsigned sizeof conversions**\n\n## Drawbacks\n\nNo drawbacks are anticipated.\n\n## Answered questions\n\n## Open questions\n\n1. Is a betterness rule needed in order to prevent this change from affecting overload resolution? For example:\n\n   ```cs\n   M(sizeof(SomeStruct));\n   void M(long s) { } // Selected in C# 14\n   void M(uint s) { }\n   ```\n"
  },
  {
    "path": "spec/LICENSE.md",
    "content": "THE FOLLOWING NOTICE GOVERNS THE C# SPEC\n=====\n\n(c) Copyright 1999-2017 Microsoft Corporation. All rights reserved.\nMicrosoft, Windows, Visual Basic, Visual C#, and Visual C++ are either registered trademarks or trademarks of Microsoft Corporation in the U.S.A. and/or other countries/regions.\nOther product and company names mentioned herein may be the trademarks of their respective owners.\n"
  },
  {
    "path": "spec/README.md",
    "content": "This content has moved to the [`dotnet/csharpstandard`](https://github.com/dotnet/csharpstandard) repository.\n\nThe full table of contents is in the [standard folder](https://github.com/dotnet/csharpstandard/tree/draft-v6/standard).\n\n> To view the text of the Microsoft spec before merging with the ECMA text, checkout the [ms-spec-text](https://github.com/dotnet/csharplang/releases/tag/ms-spec-text) tag in this repository.\n\n* [Lexical structure](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md)\n  - [§6.1](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#61-programs)  Programs\n  - [§6.2](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#62-grammars)  Grammars\n  - [§6.3](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#63-lexical-analysis)  Lexical analysis\n  - [§6.4](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#64-tokens)  Tokens\n  - [§6.5](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#65-pre-processing-directives)  Pre-processing directives\n- [§7](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#7-basic-concepts)  Basic concepts\n  - [§7.1](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#71-application-startup)  Application startup\n  - [§7.2](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#72-application-termination)  Application termination\n  - [§7.3](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#73-declarations)  Declarations\n  - [§7.4](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#74-members)  Members\n  - [§7.5](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#75-member-access)  Member access\n  - [§7.6](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#76-signatures-and-overloading)  Signatures and overloading\n  - [§7.7](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#77-scopes)  Scopes\n  - [§7.8](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#78-namespace-and-type-names)  Namespace and type names\n  - [§7.9](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#79-automatic-memory-management)  Automatic memory management\n  - [§7.10](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#710-execution-order)  Execution order\n- [§8](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#8-types)  Types\n  - [§8.1](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#81-general)  General\n  - [§8.2](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#82-reference-types)  Reference types\n  - [§8.3](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#83-value-types)  Value types\n  - [§8.4](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#84-constructed-types)  Constructed types\n  - [§8.5](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#85-type-parameters)  Type parameters\n  - [§8.6](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#86-expression-tree-types)  Expression tree types\n  - [§8.7](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#87-the-dynamic-type)  The dynamic type\n  - [§8.8](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#88-unmanaged-types)  Unmanaged types\n- [§9](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#9-variables)  Variables\n  - [§9.1](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#91-general)  General\n  - [§9.2](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#92-variable-categories)  Variable categories\n  - [§9.3](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#93-default-values)  Default values\n  - [§9.4](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#94-definite-assignment)  Definite assignment\n  - [§9.5](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#95-variable-references)  Variable references\n  - [§9.6](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#96-atomicity-of-variable-references)  Atomicity of variable references\n- [§10](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#10-conversions)  Conversions\n  - [§10.1](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#101-general)  General\n  - [§10.2](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#102-implicit-conversions)  Implicit conversions\n  - [§10.3](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#103-explicit-conversions)  Explicit conversions\n  - [§10.4](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#104-standard-conversions)  Standard conversions\n  - [§10.5](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#105-user-defined-conversions)  User-defined conversions\n  - [§10.6](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#106-conversions-involving-nullable-types)  Conversions involving nullable types\n  - [§10.7](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#107-anonymous-function-conversions)  Anonymous function conversions\n  - [§10.8](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#108-method-group-conversions)  Method group conversions\n- [§11](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11-expressions)  Expressions\n  - [§11.1](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#111-general)  General\n  - [§11.2](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#112-expression-classifications)  Expression classifications\n  - [§11.3](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#113-static-and-dynamic-binding)  Static and Dynamic Binding\n  - [§11.4](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#114-operators)  Operators\n  - [§11.5](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#115-member-lookup)  Member lookup\n  - [§11.6](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#116-function-members)  Function members\n  - [§11.7](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#117-primary-expressions)  Primary expressions\n  - [§11.8](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#118-unary-operators)  Unary operators\n  - [§11.9](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#119-arithmetic-operators)  Arithmetic operators\n  - [§11.10](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1110-shift-operators)  Shift operators\n  - [§11.11](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1111-relational-and-type-testing-operators)  Relational and type-testing operators\n  - [§11.12](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1112-logical-operators)  Logical operators\n  - [§11.13](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1113-conditional-logical-operators)  Conditional logical operators\n  - [§11.14](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1114-the-null-coalescing-operator)  The null coalescing operator\n  - [§11.15](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1115-conditional-operator)  Conditional operator\n  - [§11.16](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1116-anonymous-function-expressions)  Anonymous function expressions\n  - [§11.17](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1117-query-expressions)  Query expressions\n  - [§11.18](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1118-assignment-operators)  Assignment operators\n  - [§11.19](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1119-expression)  Expression\n  - [§11.20](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1120-constant-expressions)  Constant expressions\n  - [§11.21](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1121-boolean-expressions)  Boolean expressions\n- [§12](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#12-statements)  Statements\n  - [§12.1](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#121-general)  General\n  - [§12.2](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#122-end-points-and-reachability)  End points and reachability\n  - [§12.3](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#123-blocks)  Blocks\n  - [§12.4](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#124-the-empty-statement)  The empty statement\n  - [§12.5](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#125-labeled-statements)  Labeled statements\n  - [§12.6](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#126-declaration-statements)  Declaration statements\n  - [§12.7](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#127-expression-statements)  Expression statements\n  - [§12.8](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#128-selection-statements)  Selection statements\n  - [§12.9](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#129-iteration-statements)  Iteration statements\n  - [§12.10](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#1210-jump-statements)  Jump statements\n  - [§12.11](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#1211-the-try-statement)  The try statement\n  - [§12.12](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#1212-the-checked-and-unchecked-statements)  The checked and unchecked statements\n  - [§12.13](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#1213-the-lock-statement)  The lock statement\n  - [§12.14](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#1214-the-using-statement)  The using statement\n  - [§12.15](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#1215-the-yield-statement)  The yield statement\n- [§13](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#13-namespaces)  Namespaces\n  - [§13.1](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#131-general)  General\n  - [§13.2](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#132-compilation-units)  Compilation units\n  - [§13.3](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#133-namespace-declarations)  Namespace declarations\n  - [§13.4](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#134-extern-alias-directives)  Extern alias directives\n  - [§13.5](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#135-using-directives)  Using directives\n  - [§13.6](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#136-namespace-member-declarations)  Namespace member declarations\n  - [§13.7](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#137-type-declarations)  Type declarations\n  - [§13.8](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#138-qualified-alias-member)  Qualified alias member\n- [§14](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14-classes)  Classes\n  - [§14.1](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#141-general)  General\n  - [§14.2](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#142-class-declarations)  Class declarations\n  - [§14.3](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#143-class-members)  Class members\n  - [§14.4](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#144-constants)  Constants\n  - [§14.5](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#145-fields)  Fields\n  - [§14.6](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#146-methods)  Methods\n  - [§14.7](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#147-properties)  Properties\n  - [§14.8](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#148-events)  Events\n  - [§14.9](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#149-indexers)  Indexers\n  - [§14.10](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1410-operators)  Operators\n  - [§14.11](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1411-instance-constructors)  Instance constructors\n  - [§14.12](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1412-static-constructors)  Static constructors\n  - [§14.13](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1413-finalizers)  Finalizers\n  - [§14.14](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1414-iterators)  Iterators\n  - [§14.15](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1415-async-functions)  Async Functions\n- [§15](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/structs.md#15-structs)  Structs\n  - [§15.1](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/structs.md#151-general)  General\n  - [§15.2](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/structs.md#152-struct-declarations)  Struct declarations\n  - [§15.3](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/structs.md#153-struct-members)  Struct members\n  - [§15.4](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/structs.md#154-class-and-struct-differences)  Class and struct differences\n- [§16](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/arrays.md#16-arrays)  Arrays\n  - [§16.1](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/arrays.md#161-general)  General\n  - [§16.2](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/arrays.md#162-array-types)  Array types\n  - [§16.3](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/arrays.md#163-array-creation)  Array creation\n  - [§16.4](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/arrays.md#164-array-element-access)  Array element access\n  - [§16.5](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/arrays.md#165-array-members)  Array members\n  - [§16.6](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/arrays.md#166-array-covariance)  Array covariance\n  - [§16.7](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/arrays.md#167-array-initializers)  Array initializers\n- [§17](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#17-interfaces)  Interfaces\n  - [§17.1](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#171-general)  General\n  - [§17.2](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#172-interface-declarations)  Interface declarations\n  - [§17.3](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#173-interface-body)  Interface body\n  - [§17.4](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#174-interface-members)  Interface members\n  - [§17.5](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#175-qualified-interface-member-names)  Qualified interface member names\n  - [§17.6](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#176-interface-implementations)  Interface implementations\n- [§18](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/enums.md#18-enums)  Enums\n  - [§18.1](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/enums.md#181-general)  General\n  - [§18.2](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/enums.md#182-enum-declarations)  Enum declarations\n  - [§18.3](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/enums.md#183-enum-modifiers)  Enum modifiers\n  - [§18.4](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/enums.md#184-enum-members)  Enum members\n  - [§18.5](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/enums.md#185-the-systemenum-type)  The System.Enum type\n  - [§18.6](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/enums.md#186-enum-values-and-operations)  Enum values and operations\n- [§19](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/delegates.md#19-delegates)  Delegates\n  - [§19.1](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/delegates.md#191-general)  General\n  - [§19.2](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/delegates.md#192-delegate-declarations)  Delegate declarations\n  - [§19.3](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/delegates.md#193-delegate-members)  Delegate members\n  - [§19.4](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/delegates.md#194-delegate-compatibility)  Delegate compatibility\n  - [§19.5](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/delegates.md#195-delegate-instantiation)  Delegate instantiation\n  - [§19.6](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/delegates.md#196-delegate-invocation)  Delegate invocation\n- [§20](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/exceptions.md#20-exceptions)  Exceptions\n  - [§20.1](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/exceptions.md#201-general)  General\n  - [§20.2](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/exceptions.md#202-causes-of-exceptions)  Causes of exceptions\n  - [§20.3](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/exceptions.md#203-the-systemexception-class)  The System.Exception class\n  - [§20.4](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/exceptions.md#204-how-exceptions-are-handled)  How exceptions are handled\n  - [§20.5](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/exceptions.md#205-common-exception-classes)  Common exception classes\n- [§21](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#21-attributes)  Attributes\n  - [§21.1](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#211-general)  General\n  - [§21.2](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#212-attribute-classes)  Attribute classes\n  - [§21.3](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#213-attribute-specification)  Attribute specification\n  - [§21.4](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#214-attribute-instances)  Attribute instances\n  - [§21.5](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#215-reserved-attributes)  Reserved attributes\n  - [§21.6](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#216-attributes-for-interoperation)  Attributes for interoperation\n- [§22](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#22-unsafe-code)  Unsafe code\n  - [§22.1](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#221-general)  General\n  - [§22.2](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#222-unsafe-contexts)  Unsafe contexts\n  - [§22.3](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#223-pointer-types)  Pointer types\n  - [§22.4](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#224-fixed-and-moveable-variables)  Fixed and moveable variables\n  - [§22.5](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#225-pointer-conversions)  Pointer conversions\n  - [§22.6](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#226-pointers-in-expressions)  Pointers in expressions\n  - [§22.7](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#227-the-fixed-statement)  The fixed statement\n  - [§22.8](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#228-fixed-size-buffers)  Fixed-size buffers\n  - [§22.9](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#229-stack-allocation)  Stack allocation\n- [§D](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/documentation-comments.md#annex-d-documentation-comments)  Documentation comments\n  - [§D.1](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/documentation-comments.md#d1-general)  General\n  - [§D.2](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/documentation-comments.md#d2-introduction)  Introduction\n  - [§D.3](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/documentation-comments.md#d3-recommended-tags)  Recommended tags\n  - [§D.4](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/documentation-comments.md#d4-processing-the-documentation-file)  Processing the documentation file\n  - [§D.5](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/documentation-comments.md#d5-an-example)  An example\n"
  },
  {
    "path": "spec/arrays.md",
    "content": "# Arrays\n\nThis content has moved to the [`dotnet/csharpstandard`](https://github.com/dotnet/csharpstandard) repository.\nThe list below provides links to each heading in this section. The links specify the C# 6 branch, which is version when the specifications merged.\n\n> To view the text of the Microsoft spec before merging with the ECMA text, checkout the [ms-spec-text](https://github.com/dotnet/csharplang/releases/tag/ms-spec-text) tag in this repository.\n\n- <a id=\"arrays\"></a>[Arrays](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/arrays.md#16-arrays)\n  - <a id=\"array-types\"></a>[Array types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/arrays.md#162-array-types)\n    - <a id=\"the-systemarray-type\"></a>[The System.Array type](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/arrays.md#1622-the-systemarray-type)\n    - <a id=\"arrays-and-the-generic-ilist-interface\"></a>[Arrays and the generic IList interface](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/arrays.md#1623-arrays-and-the-generic-collection-interfaces)\n  - <a id=\"array-creation\"></a>[Array creation](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/arrays.md#163-array-creation)\n  - <a id=\"array-element-access\"></a>[Array element access](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/arrays.md#164-array-element-access)\n  - <a id=\"array-members\"></a>[Array members](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/arrays.md#165-array-members)\n  - <a id=\"array-covariance\"></a>[Array covariance](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/arrays.md#166-array-covariance)\n  - <a id=\"array-initializers\"></a>[Array initializers](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/arrays.md#167-array-initializers)\n"
  },
  {
    "path": "spec/attributes.md",
    "content": "# Attributes\n\nThis content has moved to the [`dotnet/csharpstandard`](https://github.com/dotnet/csharpstandard) repository.\nThe list below provides links to each heading in this section. The links specify the C# 6 branch, which is version when the specifications merged.\n\n> To view the text of the Microsoft spec before merging with the ECMA text, checkout the [ms-spec-text](https://github.com/dotnet/csharplang/releases/tag/ms-spec-text) tag in this repository.\n\n- <a id=\"attributes\"></a>[Attributes](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#21-attributes)\n  - <a id=\"attribute-classes\"></a>[ Attribute classes](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#212-attribute-classes)\n    - <a id=\"attribute-usage\"></a>[Attribute usage](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#2122-attribute-usage)\n    - <a id=\"positional-and-named-parameters\"></a>[Positional and named parameters](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#2123-positional-and-named-parameters)\n    - <a id=\"attribute-parameter-types\"></a>[Attribute parameter types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#2124-attribute-parameter-types)\n  - <a id=\"attribute-specification\"></a>[Attribute specification](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#213-attribute-specification)\n  - <a id=\"attribute-instances\"></a>[Attribute instances](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#214-attribute-instances)\n    - <a id=\"compilation-of-an-attribute\"></a>[Compilation of an attribute](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#2142-compilation-of-an-attribute)\n    - <a id=\"run-time-retrieval-of-an-attribute-instance\"></a>[Run-time retrieval of an attribute instance](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#2143-run-time-retrieval-of-an-attribute-instance)\n  - <a id=\"reserved-attributes\"></a>[Reserved attributes](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#215-reserved-attributes)\n    - <a id=\"the-attributeusage-attribute\"></a>[The AttributeUsage attribute](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#2152-the-attributeusage-attribute)\n    - <a id=\"the-conditional-attribute\"></a>[The Conditional attribute](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#2153-the-conditional-attribute)\n      - <a id=\"conditional-methods\"></a>[Conditional methods](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#21532-conditional-methods)\n      - <a id=\"conditional-attribute-classes\"></a>[Conditional attribute classes](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#21533-conditional-attribute-classes)\n    - <a id=\"the-obsolete-attribute\"></a>[The Obsolete attribute](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#2154-the-obsolete-attribute)\n    - <a id=\"caller-info-attributes\"></a>[Caller info attributes](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#2155-caller-info-attributes)\n      - <a id=\"the-callerlinenumber-attribute\"></a>[The CallerLineNumber attribute](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#21552-the-callerlinenumber-attribute)\n      - <a id=\"the-callerfilepath-attribute\"></a>[The CallerFilePath attribute](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#21553-the-callerfilepath-attribute)\n      - <a id=\"the-callermembername-attribute\"></a>[The CallerMemberName attribute](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#21554-the-callermembername-attribute)\n  - <a id=\"attributes-for-interoperation\"></a>[Attributes for Interoperation](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/attributes.md#216-attributes-for-interoperation)\n    - <a id=\"interoperation-with-com-and-win32-components\"></a>**Interoperation with COM and Win32 components**: This heading has been removed.\n    - <a id=\"interoperation-with-other-net-languages\"></a>**Interoperation with other .NET languages**: This heading has been removed.\n      - <a id=\"the-indexername-attribute\"></a>**The IndexerName attribute**: This heading has been removed.\n\n"
  },
  {
    "path": "spec/basic-concepts.md",
    "content": "# Basic concepts\n\nThis content has moved to the [`dotnet/csharpstandard`](https://github.com/dotnet/csharpstandard) repository.\nThe list below provides links to each heading in this section. The links specify the C# 6 branch, which is version when the specifications merged.\n\n> To view the text of the Microsoft spec before merging with the ECMA text, checkout the [ms-spec-text](https://github.com/dotnet/csharplang/releases/tag/ms-spec-text) tag in this repository.\n\n- <a id=\"basic-concepts\"></a>[Basic concepts](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#7-basic-concepts)\n  - <a id=\"application-startup\"></a>[Application Startup](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#71-application-startup)\n  - <a id=\"application-termination\"></a>[Application termination](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#72-application-termination)\n  - <a id=\"declarations\"></a>[Declarations](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#73-declarations)\n  - <a id=\"members\"></a>[Members](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#74-members)\n    - <a id=\"namespace-members\"></a>[Namespace members](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#742-namespace-members)\n    - <a id=\"struct-members\"></a>[Struct members](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#743-struct-members)\n    - <a id=\"enumeration-members\"></a>[Enumeration members](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#744-enumeration-members)\n    - <a id=\"class-members\"></a>[Class members](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#745-class-members)\n    - <a id=\"interface-members\"></a>[Interface members](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#746-interface-members)\n    - <a id=\"array-members\"></a>[Array members](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#747-array-members)\n    - <a id=\"delegate-members\"></a>[Delegate members](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#748-delegate-members)\n  - <a id=\"member-access\"></a>[Member access](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#75-member-access)\n    - <a id=\"declared-accessibility\"></a>[Declared accessibility](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#752-declared-accessibility)\n    - <a id=\"accessibility-domains\"></a>[Accessibility domains](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#753-accessibility-domains)\n    - <a id=\"protected-access-for-instance-members\"></a>[Protected access for instance members](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#754-protected-access)\n    - <a id=\"accessibility-constraints\"></a>[Accessibility constraints](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#755-accessibility-constraints)\n  - <a id=\"signatures-and-overloading\"></a>[Signatures and overloading](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#76-signatures-and-overloading)\n  - <a id=\"scopes\"></a>[Scopes](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#77-scopes)\n    - <a id=\"name-hiding\"></a>[Name hiding](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#772-name-hiding)\n      - <a id=\"hiding-through-nesting\"></a>[Hiding through nesting](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#7722-hiding-through-nesting)\n      - <a id=\"hiding-through-inheritance\"></a>[Hiding through inheritance](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#7723-hiding-through-inheritance)\n  - <a id=\"namespace-and-type-names\"></a>[Namespace and type names](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#78-namespace-and-type-names)\n    - <a id=\"fully-qualified-names\"></a>[Fully qualified names](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#783-fully-qualified-names)\n  - <a id=\"automatic-memory-management\"></a>[Automatic memory management](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#79-automatic-memory-management)\n  - <a id=\"execution-order\"></a>[Execution order](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/basic-concepts.md#710-execution-order)\n"
  },
  {
    "path": "spec/classes.md",
    "content": "# Classes\n\nThis content has moved to the [`dotnet/csharpstandard`](https://github.com/dotnet/csharpstandard) repository.\nThe list below provides links to each heading in this section. The links specify the C# 6 branch, which is version when the specifications merged.\n\n> To view the text of the Microsoft spec before merging with the ECMA text, checkout the [ms-spec-text](https://github.com/dotnet/csharplang/releases/tag/ms-spec-text) tag in this repository.\n\n- <a id=\"classes\"></a>[Classes](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14-classes)\n  - <a id=\"class-declarations\"></a>[Class declarations](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#142-class-declarations)\n    - <a id=\"class-modifiers\"></a>[Class modifiers](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1422-class-modifiers)\n      - <a id=\"abstract-classes\"></a>[Abstract classes](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14222-abstract-classes)\n      - <a id=\"sealed-classes\"></a>[Sealed classes](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14223-sealed-classes)\n      - <a id=\"static-classes\"></a>[Static classes](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14224-static-classes)\n    - <a id=\"partial-modifier\"></a>[Partial modifier](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1427-partial-declarations)\n    - <a id=\"type-parameters\"></a>[Type parameters](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1423-type-parameters)\n    - <a id=\"class-base-specification\"></a>[Class base specification](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1424-class-base-specification)\n      - <a id=\"base-classes\"></a>[Base classes](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14242-base-classes)\n      - <a id=\"interface-implementations\"></a>[Interface implementations](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14243-interface-implementations)\n    - <a id=\"type-parameter-constraints\"></a>[Type parameter constraints](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1425-type-parameter-constraints)\n    - <a id=\"class-body\"></a>[Class body](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1426-class-body)\n  - <a id=\"partial-types\"></a>[Partial types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1427-partial-declarations) - Note that the following headings (except partial methods) don't exist in the standard. The text is all contained in this section.\n    - <a id=\"attributes\"></a>Attributes\n    - <a id=\"modifiers\"></a>Modifiers\n    - <a id=\"type-parameters-and-constraints\"></a>Type parameters and constraints\n    - <a id=\"base-class\"></a>Base class\n    - <a id=\"base-interfaces\"></a>Base interfaces\n    - <a id=\"members\"></a>Members\n    - <a id=\"partial-methods\"></a>[Partial methods](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1469-partial-methods)\n    - <a id=\"name-binding\"></a>Name binding\n  - <a id=\"class-members\"></a>[Class members](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#143-class-members)\n    - <a id=\"the-instance-type\"></a>[The instance type](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1432-the-instance-type)\n    - <a id=\"members-of-constructed-types\"></a>[Members of constructed types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1433-members-of-constructed-types)\n    - <a id=\"inheritance\"></a>[Inheritance](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1434-inheritance)\n    - <a id=\"the-new-modifier\"></a>[The new modifier](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1435-the-new-modifier)\n    - <a id=\"access-modifiers\"></a>[Access modifiers](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1436-access-modifiers)\n    - <a id=\"constituent-types\"></a>[Constituent types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1437-constituent-types)\n    - <a id=\"static-and-instance-members\"></a>[Static and instance members](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1438-static-and-instance-members)\n    - <a id=\"nested-types\"></a>[Nested types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1439-nested-types)\n      - <a id=\"fully-qualified-name\"></a>[Fully qualified name](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14392-fully-qualified-name)\n      - <a id=\"declared-accessibility\"></a>[Declared accessibility](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14393-declared-accessibility)\n      - <a id=\"hiding\"></a>[Hiding](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14394-hiding)\n      - <a id=\"this-access\"></a>[this access](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14395-this-access)\n      - <a id=\"access-to-private-and-protected-members-of-the-containing-type\"></a>[Access to private and protected members of the containing type](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14396-access-to-private-and-protected-members-of-the-containing-type)\n      - <a id=\"nested-types-in-generic-classes\"></a>[Nested types in generic classes](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14397-nested-types-in-generic-classes)\n    - <a id=\"reserved-member-names\"></a>[Reserved member names](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14310-reserved-member-names)\n      - <a id=\"member-names-reserved-for-properties\"></a>[Member names reserved for properties](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#143102-member-names-reserved-for-properties) \n      - <a id=\"member-names-reserved-for-events\"></a>[Member names reserved for events](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#143103-member-names-reserved-for-events)\n      - <a id=\"member-names-reserved-for-indexers\"></a>[Member names reserved for indexers](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#143104-member-names-reserved-for-indexers)\n      - <a id=\"member-names-reserved-for-destructors\"></a>[Member names reserved for destructors](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#143105-member-names-reserved-for-finalizers)\n  - <a id=\"constants\"></a>[Constants](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#144-constants)\n  - <a id=\"fields\"></a>[Fields](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#145-fields)\n    - <a id=\"static-and-instance-fields\"></a>[Static and instance fields](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1452-static-and-instance-fields)\n    - <a id=\"readonly-fields\"></a>[Readonly fields](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1453-readonly-fields)\n      - <a id=\"using-static-readonly-fields-for-constants\"></a>[Using static readonly fields for constants](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14532-using-static-readonly-fields-for-constants)\n      - <a id=\"versioning-of-constants-and-static-readonly-fields\"></a>[Versioning of constants and static readonly fields](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14533-versioning-of-constants-and-static-readonly-fields)\n    - <a id=\"volatile-fields\"></a>[Volatile fields](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1454-volatile-fields)\n    - <a id=\"field-initialization\"></a>[Field initialization](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1455-field-initialization)\n    - <a id=\"variable-initializers\"></a>[Variable initializers](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1456-variable-initializers)\n      - <a id=\"static-field-initialization\"></a>[Static field initialization](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14562-static-field-initialization)\n      - <a id=\"instance-field-initialization\"></a>[Instance field initialization](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14563-instance-field-initialization)\n  - <a id=\"methods\"></a>[Methods](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#146-methods)\n    - <a id=\"method-parameters\"></a>[Method parameters](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1462-method-parameters)\n      - <a id=\"value-parameters\"></a>[Value parameters](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14622-value-parameters)\n      - <a id=\"reference-parameters\"></a>[Reference parameters](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14623-reference-parameters)\n      - <a id=\"output-parameters\"></a>[Output parameters](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14624-output-parameters)\n      - <a id=\"parameter-arrays\"></a>[Parameter arrays](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14625-parameter-arrays)\n    - <a id=\"static-and-instance-methods\"></a>[Static and instance methods](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1463-static-and-instance-methods)\n    - <a id=\"virtual-methods\"></a>[Virtual methods](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1464-virtual-methods)\n    - <a id=\"override-methods\"></a>[Override methods](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1465-override-methods)\n    - <a id=\"sealed-methods\"></a>[Sealed methods](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1466-sealed-methods)\n    - <a id=\"abstract-methods\"></a>[Abstract methods](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1467-abstract-methods)\n    - <a id=\"external-methods\"></a>[External methods](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1468-external-methods)\n    - <a id=\"partial-methods-(recap)\"></a>[Partial methods (recap)](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1469-partial-methods)\n    - <a id=\"extension-methods\"></a>[Extension methods](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14610-extension-methods)\n    - <a id=\"method-body\"></a>[Method body](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14611-method-body)\n    - <a id=\"method-overloading\"></a>[Method overloading](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#146-methods)\n  - <a id=\"properties\"></a>[Properties](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#147-properties)\n    - <a id=\"static-and-instance-properties\"></a>[Static and instance properties](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1472-static-and-instance-properties)\n    - <a id=\"accessors\"></a>[Accessors](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1473-accessors)\n    - <a id=\"automatically-implemented-properties\"></a>[Automatically implemented properties](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1474-automatically-implemented-properties)\n    - <a id=\"accessibility\"></a>[Accessibility](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1475-accessibility)\n    - <a id=\"virtual-sealed-override-and-abstract-property-accessors\"></a>[Virtual, sealed, override, and abstract property accessors](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1476-virtual-sealed-override-and-abstract-accessors)\n  - <a id=\"events\"></a>[Events](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#148-events)\n    - <a id=\"field-like-events\"></a>[Field-like events](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1482-field-like-events)\n    - <a id=\"event-accessors\"></a>[Event accessors](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1483-event-accessors)\n    - <a id=\"static-and-instance-events\"></a>[Static and instance events](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1484-static-and-instance-events)\n    - <a id=\"virtual-sealed-override-and-abstract-event-accessors\"></a>[Virtual, sealed, override, and abstract event accessors](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1485-virtual-sealed-override-and-abstract-accessors)\n  - <a id=\"indexers\"></a>[Indexers](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#149-indexers)\n    - <a id=\"indexer-overloading\"></a>[Indexer overloading](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#149-indexers)\n  - <a id=\"operators\"></a>[Operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1410-operators)\n    - <a id=\"unary-operators\"></a>[Unary operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14102-unary-operators)\n    - <a id=\"binary-operators\"></a>[Binary operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14103-binary-operators)\n    - <a id=\"conversion-operators\"></a>[Conversion operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14104-conversion-operators)\n  - <a id=\"instance-constructors\"></a>[Instance constructors](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1411-instance-constructors)\n    - <a id=\"constructor-initializers\"></a>[Constructor initializers](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14112-constructor-initializers)\n    - <a id=\"instance-variable-initializers\"></a>[Instance variable initializers](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14113-instance-variable-initializers)\n    - <a id=\"constructor-execution\"></a>[Constructor execution](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14114-constructor-execution)\n    - <a id=\"default-constructors\"></a>[Default constructors](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14115-default-constructors)\n    - <a id=\"private-constructors\"></a>[Private constructors](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1411-instance-constructors)\n    - <a id=\"optional-instance-constructor-parameters\"></a>[Optional instance constructor parameters](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1411-instance-constructors)\n  - <a id=\"static-constructors\"></a>[Static constructors](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1412-static-constructors)\n  - <a id=\"destructors\"></a>[Destructors](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1413-finalizers)\n  - <a id=\"iterators\"></a>[Iterators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1414-iterators)\n    - <a id=\"enumerator-interfaces\"></a>[Enumerator interfaces](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14142-enumerator-interfaces)\n    - <a id=\"enumerable-interfaces\"></a>[Enumerable interfaces](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14143-enumerable-interfaces)\n    - <a id=\"yield-type\"></a>[Yield type](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14144-yield-type)\n    - <a id=\"enumerator-objects\"></a>[Enumerator objects](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14145-enumerator-objects)\n      - <a id=\"the-movenext-method\"></a>[The MoveNext method](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#141452-the-movenext-method)\n      - <a id=\"the-current-property\"></a>[The Current property](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#141453-the-current-property)\n      - <a id=\"the-dispose-method\"></a>[The Dispose method](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#141454-the-dispose-method)\n    - <a id=\"enumerable-objects\"></a>[Enumerable objects](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14146-enumerable-objects)\n      - <a id=\"the-getenumerator-method\"></a>[The GetEnumerator method](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#141462-the-getenumerator-method)\n    - <a id=\"implementation-example\"></a>[Implementation example](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1414-iterators)\n  - <a id=\"async-functions\"></a>[Async functions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1415-async-functions)\n    - <a id=\"evaluation-of-a-task-returning-async-function\"></a>[Evaluation of a task-returning async function](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14152-evaluation-of-a-task-returning-async-function)\n    - <a id=\"evaluation-of-a-void-returning-async-function\"></a>[Evaluation of a void-returning async function](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#14153-evaluation-of-a-void-returning-async-function)\n"
  },
  {
    "path": "spec/conversions.md",
    "content": "# Conversions\n\nThis content has moved to the [`dotnet/csharpstandard`](https://github.com/dotnet/csharpstandard) repository.\nThe list below provides links to each heading in this section. The links specify the C# 6 branch, which is version when the specifications merged.\n\n> To view the text of the Microsoft spec before merging with the ECMA text, checkout the [ms-spec-text](https://github.com/dotnet/csharplang/releases/tag/ms-spec-text) tag in this repository.\n\n- <a id=\"conversions\"></a>[Conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md)\n  - <a id=\"implicit-conversions\"></a>[Implicit conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#102-implicit-conversions)\n    - <a id=\"identity-conversion\"></a>[Identity conversion](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#1022-identity-conversion)\n    - <a id=\"implicit-numeric-conversions\"></a>[Implicit numeric conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#1023-implicit-numeric-conversions)\n    - <a id=\"implicit-enumeration-conversions\"></a>[Implicit enumeration conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#1024-implicit-enumeration-conversions)\n    - <a id=\"implicit-interpolated-string-conversions\"></a>[Implicit interpolated string conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#1025-implicit-interpolated-string-conversions)\n    - <a id=\"implicit-nullable-conversions\"></a>[Implicit nullable conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#1026-implicit-nullable-conversions)\n    - <a id=\"null-literal-conversions\"></a>[Null literal conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#1027-null-literal-conversions)\n    - <a id=\"implicit-reference-conversions\"></a>[Implicit reference conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#1028-implicit-reference-conversions)\n    - <a id=\"boxing-conversions\"></a>[Boxing conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#1029-boxing-conversions)\n    - <a id=\"implicit-dynamic-conversions\"></a>[Implicit dynamic conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#10210-implicit-dynamic-conversions)\n    - <a id=\"implicit-constant-expression-conversions\"></a>[Implicit constant expression conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#10211-implicit-constant-expression-conversions)\n    - <a id=\"implicit-conversions-involving-type-parameters\"></a>[Implicit conversions involving type parameters](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#10212-implicit-conversions-involving-type-parameters)\n    - <a id=\"user-defined-implicit-conversions\"></a>[User-defined implicit conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#10213-user-defined-implicit-conversions)\n    - <a id=\"anonymous-function-conversions-and-method-group-conversions\"></a>[Anonymous function conversions and method group conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#10214-anonymous-function-conversions-and-method-group-conversions)\n  - <a id=\"explicit-conversions\"></a>[Explicit conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#103-explicit-conversions)\n    - <a id=\"explicit-numeric-conversions\"></a>[Explicit numeric conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#1032-explicit-numeric-conversions)\n    - <a id=\"explicit-enumeration-conversions\"></a>[Explicit enumeration conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#1033-explicit-enumeration-conversions)\n    - <a id=\"explicit-nullable-conversions\"></a>[Explicit nullable conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#1034-explicit-nullable-conversions)\n    - <a id=\"explicit-reference-conversions\"></a>[Explicit reference conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#1035-explicit-reference-conversions)\n    - <a id=\"unboxing-conversions\"></a>[Unboxing conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#1036-unboxing-conversions)\n    - <a id=\"explicit-dynamic-conversions\"></a>[Explicit dynamic conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#1037-explicit-dynamic-conversions)\n    - <a id=\"explicit-conversions-involving-type-parameters\"></a>[Explicit conversions involving type parameters](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#1038-explicit-conversions-involving-type-parameters)\n    - <a id=\"user-defined-explicit-conversions\"></a>[User-defined explicit conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#1039-user-defined-explicit-conversions)\n  - <a id=\"standard-conversions\"></a>[Standard conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#104-standard-conversions)\n    - <a id=\"standard-implicit-conversions\"></a>[Standard implicit conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#1042-standard-implicit-conversions)\n    - <a id=\"standard-explicit-conversions\"></a>[Standard explicit conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#1043-standard-explicit-conversions)\n  - <a id=\"user-defined-conversions\"></a>[User-defined conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#105-user-defined-conversions)\n    - <a id=\"permitted-user-defined-conversions\"></a>[Permitted user-defined conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#1052-permitted-user-defined-conversions)\n    - <a id=\"lifted-conversion-operators\"></a>[Lifted conversion operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#1062-lifted-conversions)\n    - <a id=\"evaluation-of-user-defined-conversions\"></a>[Evaluation of user-defined conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#1053-evaluation-of-user-defined-conversions)\n    - <a id=\"processing-of-user-defined-implicit-conversions\"></a>[Processing of user-defined implicit conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#1054-user-defined-implicit-conversions)\n    - <a id=\"processing-of-user-defined-explicit-conversions\"></a>[Processing of user-defined explicit conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#1055-user-defined-explicit-conversions)\n  - <a id=\"anonymous-function-conversions\"></a>[Anonymous function conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#107-anonymous-function-conversions)\n    - <a id=\"evaluation-of-anonymous-function-conversions-to-delegate-types\"></a>[Evaluation of anonymous function conversions to delegate types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#1072-evaluation-of-anonymous-function-conversions-to-delegate-types)\n    - <a id=\"evaluation-of-anonymous-function-conversions-to-expression-tree-types\"></a>[Evaluation of anonymous function conversions to expression tree types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#1073-evaluation-of-lambda-expression-conversions-to-expression-tree-types)\n    - <a id=\"implementation-example\"></a>[Implementation example](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#1073-evaluation-of-lambda-expression-conversions-to-expression-tree-types)\n  - <a id=\"method-group-conversions\"></a>[Method group conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/conversions.md#108-method-group-conversions)\n"
  },
  {
    "path": "spec/delegates.md",
    "content": "# Delegates\n\nThis content has moved to the [`dotnet/csharpstandard`](https://github.com/dotnet/csharpstandard) repository.\nThe list below provides links to each heading in this section. The links specify the C# 6 branch, which is version when the specifications merged.\n\n> To view the text of the Microsoft spec before merging with the ECMA text, checkout the [ms-spec-text](https://github.com/dotnet/csharplang/releases/tag/ms-spec-text) tag in this repository.\n\n- <a id=\"delegates\"></a>[Delegates](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/delegates.md#19-delegates)\n  - <a id=\"delegate-declarations\"></a>[Delegate declarations](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/delegates.md#192-delegate-declarations)\n  - <a id=\"delegate-compatibility\"></a>[Delegate compatibility](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/delegates.md#194-delegate-compatibility)\n  - <a id=\"delegate-instantiation\"></a>[Delegate instantiation](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/delegates.md#195-delegate-instantiation)\n  - <a id=\"delegate-invocation\"></a>[Delegate invocation](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/delegates.md#196-delegate-invocation)\n"
  },
  {
    "path": "spec/documentation-comments.md",
    "content": "# Documentation comments\n\nThis content has moved to the [`dotnet/csharpstandard`](https://github.com/dotnet/csharpstandard) repository.\nThe list below provides links to each heading in this section. The links specify the C# 6 branch, which is version when the specifications merged.\n\n> To view the text of the Microsoft spec before merging with the ECMA text, checkout the [ms-spec-text](https://github.com/dotnet/csharplang/releases/tag/ms-spec-text) tag in this repository.\n\n- <a id=\"documentation-comments\"></a>[Documentation comments](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#annex-d-documentation-comments)\n  - <a id=\"introduction\"></a>[Introduction](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d2-introduction)\n  - <a id=\"recommended-tags\"></a>[Recommended tags](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d3-recommended-tags)\n    - <a id=\"<c>\"></a>[`<c>`](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d32-c)\n    - <a id=\"<code>\"></a>[`<code>`](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d33-code)\n    - <a id=\"<example>\"></a>[`<example>`](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d34-example)\n    - <a id=\"<exception>\"></a>[`<exception>`](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d35-exception))\n    - <a id=\"<include>\"></a>[`<include>`](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d36-include)\n    - <a id=\"<list>\"></a>[`<list>`](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d37-list)\n    - <a id=\"<para>\"></a>[`<para>`](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d38-para)\n    - <a id=\"<param>\"></a>[`<param>`](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d39-param)\n    - <a id=\"<paramref>\"></a>[`<paramref>`](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d310-paramref)\n    - <a id=\"<permission>\"></a>[`<permission>`](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d311-permission)\n    - <a id=\"<remarks>\"></a>[`<remarks>`](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d312-remarks)\n    - <a id=\"<returns>\"></a>[`<returns>`](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d313-returns)\n    - <a id=\"<see>\"></a>[`<see>`](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d314-see)\n    - <a id=\"<seealso>\"></a>[`<seealso>`](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d315-seealso)\n    - <a id=\"<summary>\"></a>[`<summary>`](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d316-summary)\n    - <a id=\"<value>\"></a>[`<value>`](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d319-value)\n    - <a id=\"<typeparam>\"></a>[`<typeparam>`](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d317-typeparam)\n    - <a id=\"<typeparamref>\"></a>[`<typeparamref>`](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d318-typeparamref)\n  - <a id=\"processing-the-documentation-file\"></a>[Processing the documentation file](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d4-processing-the-documentation-file)\n    - <a id=\"id-string-format\"></a>[ID string format](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d42-id-string-format)\n    - <a id=\"id-string-examples\"></a>[ID string examples](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d43-id-string-examples)\n  - <a id=\"an-example\"></a>[An example](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d5-an-example)\n    - <a id=\"c#-source-code\"></a>[C# source code](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d51-c-source-code)\n    - <a id=\"resulting-xml\"></a>[Resulting XML](https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/documentation-comments.md#d52-resulting-xml)\n"
  },
  {
    "path": "spec/enums.md",
    "content": "# Enums\n\nThis content has moved to the [`dotnet/csharpstandard`](https://github.com/dotnet/csharpstandard) repository.\nThe list below provides links to each heading in this section. The links specify the C# 6 branch, which is version when the specifications merged.\n\n> To view the text of the Microsoft spec before merging with the ECMA text, checkout the [ms-spec-text](https://github.com/dotnet/csharplang/releases/tag/ms-spec-text) tag in this repository.\n\n- <a id=\"enums\"></a>[Enums](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/enums.md#18-enums)\n  - <a id=\"enum-declarations\"></a>[Enum declarations](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/enums.md#182-enum-declarations)\n  - <a id=\"enum-modifiers\"></a>[Enum modifiers](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/enums.md#183-enum-modifiers)\n  - <a id=\"enum-members\"></a>[Enum members](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/enums.md#184-enum-members)\n  - <a id=\"the-systemenum-type\"></a>[The System.Enum type](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/enums.md#185-the-systemenum-type)\n  - <a id=\"enum-values-and-operations\"></a>[Enum values and operations](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/enums.md#186-enum-values-and-operations)\n"
  },
  {
    "path": "spec/exceptions.md",
    "content": "# Exceptions\n\nThis content has moved to the [`dotnet/csharpstandard`](https://github.com/dotnet/csharpstandard) repository.\nThe list below provides links to each heading in this section. The links specify the C# 6 branch, which is version when the specifications merged.\n\n> To view the text of the Microsoft spec before merging with the ECMA text, checkout the [ms-spec-text](https://github.com/dotnet/csharplang/releases/tag/ms-spec-text) tag in this repository.\n\n- <a id=\"exceptions\"></a>[Exceptions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/exceptions.md#20-exceptions)\n  - <a id=\"causes-of-exceptions\"></a>[Causes of exceptions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/exceptions.md#202-causes-of-exceptions)\n  - <a id=\"the-systemexception-class\"></a>[The System.Exception class](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/exceptions.md#203-the-systemexception-class)\n  - <a id=\"how-exceptions-are-handled\"></a>[How exceptions are handled](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/exceptions.md#204-how-exceptions-are-handled)\n  - <a id=\"common-exception-classes\"></a>[Common Exception Classes](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/exceptions.md#205-common-exception-classes)\n"
  },
  {
    "path": "spec/expressions.md",
    "content": "# Expressions\n\nThis content has moved to the [`dotnet/csharpstandard`](https://github.com/dotnet/csharpstandard) repository.\nThe list below provides links to each heading in this section. The links specify the C# 6 branch, which is version when the specifications merged.\n\n> To view the text of the Microsoft spec before merging with the ECMA text, checkout the [ms-spec-text](https://github.com/dotnet/csharplang/releases/tag/ms-spec-text) tag in this repository.\n\n- <a id=\"expressions\"></a>[Expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md)\n  - <a id=\"expression-classifications\"></a>[Expression classifications](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#112-expression-classifications)\n    - <a id=\"values-of-expressions\"></a>[Values of expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1122-values-of-expressions) \n  - <a id=\"static-and-dynamic-binding\"></a>[Static and Dynamic Binding](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#113-static-and-dynamic-binding)\n    - <a id=\"binding-time\"></a>[Binding-time](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1132-binding-time)\n    - <a id=\"dynamic-binding\"></a>[Dynamic binding](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1133-dynamic-binding)\n    - <a id=\"types-of-constituent-expressions\"></a>[Types of constituent expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1134-types-of-subexpressions)\n  - <a id=\"operators\"></a>[Operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#114-operators)\n    - <a id=\"operator-precedence-and-associativity\"></a>[Operator precedence and associativity](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1142-operator-precedence-and-associativity)\n    - <a id=\"operator-overloading\"></a>[Operator overloading](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1143-operator-overloading)\n    - <a id=\"unary-operator-overload-resolution\"></a>[Unary operator overload resolution](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1144-unary-operator-overload-resolution)\n    - <a id=\"binary-operator-overload-resolution\"></a>[Binary operator overload resolution](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1145-binary-operator-overload-resolution)\n    - <a id=\"candidate-user-defined-operators\"></a>[Candidate user-defined operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1146-candidate-user-defined-operators)\n    - <a id=\"numeric-promotions\"></a>[Numeric promotions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1147-numeric-promotions)\n      - <a id=\"unary-numeric-promotions\"></a>[Unary numeric promotions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11472-unary-numeric-promotions)\n      - <a id=\"binary-numeric-promotions\"></a>[Binary numeric promotions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11473-binary-numeric-promotions)\n    - <a id=\"lifted-operators\"></a>[Lifted operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1148-lifted-operators)\n  - <a id=\"member-lookup\"></a>[Member lookup](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#115-member-lookup)\n    - <a id=\"base-types\"></a>[Base types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1152-base-types)\n  - <a id=\"function-members\"></a>[Function members](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#116-function-members)\n    - <a id=\"argument-lists\"></a>[Argument lists](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1162-argument-lists)\n      - <a id=\"corresponding-parameters\"></a>[Corresponding parameters](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11622-corresponding-parameters)\n      - <a id=\"run-time-evaluation-of-argument-lists\"></a>[Run-time evaluation of argument lists](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11623-run-time-evaluation-of-argument-lists)\n    - <a id=\"type-inference\"></a>[Type inference](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1163-type-inference)\n      - <a id=\"the-first-phase\"></a>[The first phase](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11632-the-first-phase)\n      - <a id=\"the-second-phase\"></a>[The second phase](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11633-the-second-phase)\n      - <a id=\"input-types\"></a>[Input types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11634-input-types)\n      - <a id=\"output-types\"></a>[Output types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11635-output-types)\n      - <a id=\"dependence\"></a>[Dependence](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11636-dependence)\n      - <a id=\"output-type-inferences\"></a>[Output type inferences](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11637-output-type-inferences)\n      - <a id=\"explicit-parameter-type-inferences\"></a>[Explicit parameter type inferences](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11638-explicit-parameter-type-inferences)\n      - <a id=\"exact-inferences\"></a>[Exact inferences](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11639-exact-inferences)\n      - <a id=\"lower-bound-inferences\"></a>[Lower-bound inferences](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#116310-lower-bound-inferences)\n      - <a id=\"upper-bound-inferences\"></a>[Upper-bound inferences](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#116311-upper-bound-inferences)\n      - <a id=\"fixing\"></a>[Fixing](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#116312-fixing)\n      - <a id=\"inferred-return-type\"></a>[Inferred return type](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#116313-inferred-return-type)\n      - <a id=\"type-inference-for-conversion-of-method-groups\"></a>[Type inference for conversion of method groups](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#116314-type-inference-for-conversion-of-method-groups)\n      - <a id=\"finding-the-best-common-type-of-a-set-of-expressions\"></a>[Finding the best common type of a set of expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#116315-finding-the-best-common-type-of-a-set-of-expressions)\n    - <a id=\"overload-resolution\"></a>[Overload resolution](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1164-overload-resolution)\n      - <a id=\"applicable-function-member\"></a>[Applicable function member](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11642-applicable-function-member)\n      - <a id=\"better-function-member\"></a>[Better function member](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11643-better-function-member)\n      - <a id=\"better-conversion-from-expression\"></a>[Better conversion from expression](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11644-better-conversion-from-expression)\n      - <a id=\"exactly-matching-expression\"></a>[Exactly matching Expression](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11645-better-conversion-from-expression)\n      - <a id=\"better-conversion-target\"></a>[Better conversion target](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11646-better-conversion-target)\n      - <a id=\"overloading-in-generic-classes\"></a>[Overloading in generic classes](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11647-overloading-in-generic-classes)\n    - <a id=\"compile-time-checking-of-dynamic-overload-resolution\"></a>[Compile-time checking of dynamic overload resolution](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1165-compile-time-checking-of-dynamic-member-invocation)\n    - <a id=\"function-member-invocation\"></a>[Function member invocation](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1166-function-member-invocation)\n      - <a id=\"invocations-on-boxed-instances\"></a>[Invocations on boxed instances](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11662-invocations-on-boxed-instances)\n  - <a id=\"primary-expressions\"></a>[Primary expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#117-primary-expressions)\n    - <a id=\"literals\"></a>[Literals](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1172-literals)\n    - <a id=\"interpolated-strings\"></a>[Interpolated strings](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1173-interpolated-string-expressions)\n    - <a id=\"simple-names\"></a>[Simple names](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1174-simple-names)\n    - <a id=\"parenthesized-expressions\"></a>[Parenthesized expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1175-parenthesized-expressions)\n    - <a id=\"member-access\"></a>[Member access](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1176-member-access)\n      - <a id=\"identical-simple-names-and-type-names\"></a>[Identical simple names and type names](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11762-identical-simple-names-and-type-names)\n      - <a id=\"grammar-ambiguities\"></a>[Grammar ambiguities](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#625-grammar-ambiguities)\n    - <a id=\"invocation-expressions\"></a>[Invocation expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1178-invocation-expressions)\n      - <a id=\"method-invocations\"></a>[Method invocations](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11782-method-invocations)\n      - <a id=\"extension-method-invocations\"></a>[Extension method invocations](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11783-extension-method-invocations)\n      - <a id=\"delegate-invocations\"></a>[Delegate invocations](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11784-delegate-invocations)\n    - <a id=\"element-access\"></a>[Element access](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11710-element-access)\n      - <a id=\"array-access\"></a>[Array access](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#117102-array-access)\n      - <a id=\"indexer-access\"></a>[Indexer access](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#117103-indexer-access)\n    - <a id=\"this-access\"></a>[This access](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11712-this-access)\n    - <a id=\"base-access\"></a>[Base access](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11713-base-access)\n    - <a id=\"postfix-increment-and-decrement-operators\"></a>[Postfix increment and decrement operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11714-postfix-increment-and-decrement-operators)\n    - <a id=\"the-new-operator\"></a>[The new operator](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11715-the-new-operator)\n      - <a id=\"object-creation-expressions\"></a>[Object creation expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#117152-object-creation-expressions)\n      - <a id=\"object-initializers\"></a>[Object initializers](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#117153-object-initializers)\n      - <a id=\"collection-initializers\"></a>[Collection initializers](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#117154-collection-initializers)\n      - <a id=\"array-creation-expressions\"></a>[Array creation expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#117155-array-creation-expressions)\n      - <a id=\"delegate-creation-expressions\"></a>[Delegate creation expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#117156-delegate-creation-expressions)\n      - <a id=\"anonymous-object-creation-expressions\"></a>[Anonymous object creation expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#117157-anonymous-object-creation-expressions)\n    - <a id=\"the-typeof-operator\"></a>[The typeof operator](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11716-the-typeof-operator)\n    - <a id=\"the-checked-and-unchecked-operators\"></a>[The checked and unchecked operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11718-the-checked-and-unchecked-operators)\n    - <a id=\"default-value-expressions\"></a>[Default value expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11719-default-value-expressions)\n    - <a id=\"nameof-expressions\"></a>[Nameof expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11720-nameof-expressions)\n    - <a id=\"anonymous-method-expressions\"></a>[Anonymous method expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11721-anonymous-method-expressions)\n  - <a id=\"unary-operators\"></a>[Unary operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#118-unary-operators)\n    - <a id=\"null-conditional-operator\"></a>**Null-conditional operator**: These sections have been rearranged.\n    - <a id=\"null-conditional-expressions-as-projection-initializers\"></a>**Null-conditional expressions as projection initializers**: These sections have been rearranged.\n    - <a id=\"null-conditional-expressions-as-statement-expressions\"></a>**Null-conditional expressions as statement expressions**: These sections have been rearranged.\n      - [§11.7.7](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1177-null-conditional-member-access)  Null Conditional Member Access\n      - [§11.7.9](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1179-null-conditional-invocation-expression)  Null Conditional Invocation Expression\n      - [§11.7.11](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11711-null-conditional-element-access)  Null Conditional Element Access\n    - <a id=\"unary-plus-operator\"></a>[Unary plus operator](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1182-unary-plus-operator)\n    - <a id=\"unary-minus-operator\"></a>[Unary minus operator](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1183-unary-minus-operator)\n    - <a id=\"logical-negation-operator\"></a>[Logical negation operator](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1184-logical-negation-operator)\n    - <a id=\"bitwise-complement-operator\"></a>[Bitwise complement operator](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1185-bitwise-complement-operator)\n    - <a id=\"prefix-increment-and-decrement-operators\"></a>[Prefix increment and decrement operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1186-prefix-increment-and-decrement-operators)\n    - <a id=\"cast-expressions\"></a>[Cast expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1187-cast-expressions)\n    - <a id=\"await-expressions\"></a>[Await expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1188-await-expressions)\n      - <a id=\"awaitable-expressions\"></a>[Awaitable expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11882-awaitable-expressions)\n      - <a id=\"classification-of-await-expressions\"></a>[Classification of await expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11883-classification-of-await-expressions)\n      - <a id=\"runtime-evaluation-of-await-expressions\"></a>[Runtime evaluation of await expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11884-run-time-evaluation-of-await-expressions)\n  - <a id=\"arithmetic-operators\"></a>[Arithmetic operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#119-arithmetic-operators)\n    - <a id=\"multiplication-operator\"></a>[Multiplication operator](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1192-multiplication-operator)\n    - <a id=\"division-operator\"></a>[Division operator](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1193-division-operator)\n    - <a id=\"remainder-operator\"></a>[Remainder operator](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1194-remainder-operator)\n    - <a id=\"addition-operator\"></a>[Addition operator](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1195-addition-operator)\n    - <a id=\"subtraction-operator\"></a>[Subtraction operator](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1196-subtraction-operator)\n  - <a id=\"shift-operators\"></a>[Shift operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1110-shift-operators)\n  - <a id=\"relational-and-type-testing-operators\"></a>[Relational and type-testing operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1111-relational-and-type-testing-operators)\n    - <a id=\"integer-comparison-operators\"></a>[Integer comparison operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11112-integer-comparison-operators)\n    - <a id=\"floating-point-comparison-operators\"></a>[Floating-point comparison operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11113-floating-point-comparison-operators)\n    - <a id=\"decimal-comparison-operators\"></a>[Decimal comparison operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11114-decimal-comparison-operators)\n    - <a id=\"boolean-equality-operators\"></a>[Boolean equality operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11115-boolean-equality-operators)\n    - <a id=\"enumeration-comparison-operators\"></a>[Enumeration comparison operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11116-enumeration-comparison-operators)\n    - <a id=\"reference-type-equality-operators\"></a>[Reference type equality operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11117-reference-type-equality-operators)\n    - <a id=\"string-equality-operators\"></a>[String equality operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11118-string-equality-operators)\n    - <a id=\"delegate-equality-operators\"></a>[Delegate equality operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11119-delegate-equality-operators)\n    - <a id=\"equality-operators-and-null\"></a>[Equality operators and null](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#111110-equality-operators-between-nullable-value-types-and-the-null-literal)\n    - <a id=\"the-is-operator\"></a>[The is operator](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#111111-the-is-operator)\n    - <a id=\"the-as-operator\"></a>[The as operator](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#111112-the-as-operator)\n  - <a id=\"logical-operators\"></a>[Logical operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1112-logical-operators)\n    - <a id=\"integer-logical-operators\"></a>[Integer logical operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11122-integer-logical-operators)\n    - <a id=\"enumeration-logical-operators\"></a>[Enumeration logical operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11123-enumeration-logical-operators)\n    - <a id=\"boolean-logical-operators\"></a>[Boolean logical operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11124-boolean-logical-operators)\n    - <a id=\"nullable-boolean-logical-operators\"></a>[Nullable boolean logical operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11125-nullable-boolean--and--operators)\n  - <a id=\"conditional-logical-operators\"></a>[Conditional logical operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1113-conditional-logical-operators)\n    - <a id=\"boolean-conditional-logical-operators\"></a>[Boolean conditional logical operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11132-boolean-conditional-logical-operators)\n    - <a id=\"user-defined-conditional-logical-operators\"></a>[User-defined conditional logical operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11133-user-defined-conditional-logical-operators)\n  - <a id=\"the-null-coalescing-operator\"></a>[The null coalescing operator](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1114-the-null-coalescing-operator)\n  - <a id=\"conditional-operator\"></a>[Conditional operator](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1115-conditional-operator)\n  - <a id=\"anonymous-function-expressions\"></a>[Anonymous function expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1116-anonymous-function-expressions)\n    - <a id=\"anonymous-function-signatures\"></a>[Anonymous function signatures](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11162-anonymous-function-signatures)\n    - <a id=\"anonymous-function-bodies\"></a>[Anonymous function bodies](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11163-anonymous-function-bodies)\n    - <a id=\"overload-resolution-and-anonymous-functions\"></a>[Overload resolution and anonymous functions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11164-overload-resolution)\n    - <a id=\"anonymous-functions-and-dynamic-binding\"></a>[Anonymous functions and dynamic binding](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11165-anonymous-functions-and-dynamic-binding)\n    - <a id=\"outer-variables\"></a>[Outer variables](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11166-outer-variables)\n      - <a id=\"captured-outer-variables\"></a>[Captured outer variables](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#111662-captured-outer-variables)\n      - <a id=\"instantiation-of-local-variables\"></a>[Instantiation of local variables](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#111663-instantiation-of-local-variables)\n    - <a id=\"evaluation-of-anonymous-function-expressions\"></a>[Evaluation of anonymous function expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11167-evaluation-of-anonymous-function-expressions)\n  - <a id=\"query-expressions\"></a>[Query expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1117-query-expressions)\n    - <a id=\"ambiguities-in-query-expressions\"></a>[Ambiguities in query expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11172-ambiguities-in-query-expressions)\n    - <a id=\"query-expression-translation\"></a>[Query expression translation](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11173-query-expression-translation)\n      - <a id=\"select-and-groupby-clauses-with-continuations\"></a>[Select and groupby clauses with continuations](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#111732-select-and-group--by-clauses-with-continuations)\n      - <a id=\"explicit-range-variable-types\"></a>[Explicit range variable types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#111733-explicit-range-variable-types)\n      - <a id=\"degenerate-query-expressions\"></a>[Degenerate query expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#111734-degenerate-query-expressions)\n      - <a id=\"from-let-where-join-and-orderby-clauses\"></a>[From, let, where, join and orderby clauses](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#111735-from-let-where-join-and-orderby-clauses)\n      - <a id=\"select-clauses\"></a>[Select clauses](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#111736-select-clauses)\n      - <a id=\"groupby-clauses\"></a>[Groupby clauses](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#111737-group-clauses)\n      - <a id=\"transparent-identifiers\"></a>[Transparent identifiers](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#111738-transparent-identifiers)\n    - <a id=\"the-query-expression-pattern\"></a>[The query expression pattern](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11174-the-query-expression-pattern)\n  - <a id=\"assignment-operators\"></a>[Assignment operators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1118-assignment-operators)\n    - <a id=\"simple-assignment\"></a>[Simple assignment](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11182-simple-assignment)\n    - <a id=\"compound-assignment\"></a>[Compound assignment](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11183-compound-assignment)\n    - <a id=\"event-assignment\"></a>[Event assignment](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#11184-event-assignment)\n  - <a id=\"expression\"></a>[Expression](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1119-expression)\n  - <a id=\"constant-expressions\"></a>[Constant expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1120-constant-expressions)\n  - <a id=\"boolean-expressions\"></a>[Boolean expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/expressions.md#1121-boolean-expressions)\n"
  },
  {
    "path": "spec/interfaces.md",
    "content": "# Interfaces\n\nThis content has moved to the [`dotnet/csharpstandard`](https://github.com/dotnet/csharpstandard) repository.\nThe list below provides links to each heading in this section. The links specify the C# 6 branch, which is version when the specifications merged.\n\n> To view the text of the Microsoft spec before merging with the ECMA text, checkout the [ms-spec-text](https://github.com/dotnet/csharplang/releases/tag/ms-spec-text) tag in this repository.\n\n- <a id=\"interfaces\"></a>[Interfaces](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#17-interfaces)\n  - <a id=\"interface-declarations\"></a>[Interface declarations](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#172-interface-declarations)\n    - <a id=\"interface-modifiers\"></a>[Interface modifiers](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#1722-interface-modifiers)\n    - <a id=\"partial-modifier\"></a>[Partial modifier](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/classes.md#1427-partial-declarations)\n    - <a id=\"variant-type-parameter-lists\"></a>[Variant type parameter lists](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#1723-variant-type-parameter-lists)\n      - <a id=\"variance-safety\"></a>[Variance safety](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#17232-variance-safety)\n      - <a id=\"variance-conversion\"></a>[Variance conversion](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#17233-variance-conversion)\n    - <a id=\"base-interfaces\"></a>[Base interfaces](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#1724-base-interfaces)\n    - <a id=\"interface-body\"></a>[Interface body](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#173-interface-body)\n  - <a id=\"interface-members\"></a>[Interface members](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#174-interface-members)\n    - <a id=\"interface-methods\"></a>[Interface methods](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#1742-interface-methods)\n    - <a id=\"interface-properties\"></a>[Interface properties](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#1743-interface-properties)\n    - <a id=\"interface-events\"></a>[Interface events](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#1744-interface-events)\n    - <a id=\"interface-indexers\"></a>[Interface indexers](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#1745-interface-indexers)\n    - <a id=\"interface-member-access\"></a>[Interface member access](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#1746-interface-member-access)\n  - <a id=\"fully-qualified-interface-member-names\"></a>[Fully qualified interface member names](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#175-qualified-interface-member-names)\n  - <a id=\"interface-implementations\"></a>[Interface implementations](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#176-interface-implementations)\n    - <a id=\"explicit-interface-member-implementations\"></a>[Explicit interface member implementations](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#1762-explicit-interface-member-implementations)\n    - <a id=\"uniqueness-of-implemented-interfaces\"></a>[Uniqueness of implemented interfaces](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#1763-uniqueness-of-implemented-interfaces)\n    - <a id=\"implementation-of-generic-methods\"></a>[Implementation of generic methods](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#1764-implementation-of-generic-methods)\n    - <a id=\"interface-mapping\"></a>[Interface mapping](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#1765-interface-mapping)\n    - <a id=\"interface-implementation-inheritance\"></a>[Interface implementation inheritance](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#1766-interface-implementation-inheritance)\n    - <a id=\"interface-re-implementation\"></a>[Interface re-implementation](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#1767-interface-re-implementation)\n    - <a id=\"abstract-classes-and-interfaces\"></a>[Abstract classes and interfaces](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/interfaces.md#1768-abstract-classes-and-interfaces)\n"
  },
  {
    "path": "spec/introduction.md",
    "content": "# Introduction\n\nThis content has moved to the [`dotnet/csharpstandard`](https://github.com/dotnet/csharpstandard) repository. This section has been removed from the standard. The [standard/README.md](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/README.md) has a detailed table of contents for the standard.\n\n> To view the text of the Microsoft spec before merging with the ECMA text, checkout the [ms-spec-text](https://github.com/dotnet/csharplang/releases/tag/ms-spec-text) tag in this repository.\n"
  },
  {
    "path": "spec/lexical-structure.md",
    "content": "# Lexical structure\n\nThis content has moved to the [`dotnet/csharpstandard`](https://github.com/dotnet/csharpstandard) repository.\nThe list below provides links to each heading in this section. The links specify the C# 6 branch, which is version when the specifications merged.\n\n> To view the text of the Microsoft spec before merging with the ECMA text, checkout the [ms-spec-text](https://github.com/dotnet/csharplang/releases/tag/ms-spec-text) tag in this repository.\n\n- <a id=\"lexical-structure\"></a>[Lexical structure](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md)\n  - <a id=\"programs\"></a>[Programs](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#61-programs)\n  - <a id=\"grammars\"></a>[Grammars](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#62-grammars)\n    - <a id=\"grammar-notation\"></a>[Grammar notation](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#622-grammar-notation)\n    - <a id=\"lexical-grammar\"></a>[Lexical grammar](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#623-lexical-grammar)\n    - <a id=\"syntactic-grammar\"></a>[Syntactic grammar](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#624-syntactic-grammar)\n  - <a id=\"lexical-analysis\"></a>[Lexical analysis](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#63-lexical-analysis)\n    - <a id=\"line-terminators\"></a>[Line terminators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#632-line-terminators)\n    - <a id=\"comments\"></a>[Comments](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#633-comments)\n    - <a id=\"white-space\"></a>[White space](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#634-white-space)\n  - <a id=\"tokens\"></a>[Tokens](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#64-tokens)\n    - <a id=\"unicode-character-escape-sequences\"></a>[Unicode character escape sequences](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#642-unicode-character-escape-sequences)\n    - <a id=\"identifiers\"></a>[Identifiers](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#643-identifiers)\n    - <a id=\"keywords\"></a>[Keywords](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#644-keywords)\n    - <a id=\"literals\"></a>[Literals](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#645-literals)\n      - <a id=\"boolean-literals\"></a>[Boolean literals](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#6452-boolean-literals)\n      - <a id=\"integer-literals\"></a>[Integer literals](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#6453-integer-literals)\n      - <a id=\"real-literals\"></a>[Real literals](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#6454-real-literals)\n      - <a id=\"character-literals\"></a>[Character literals](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#6455-character-literals)\n      - <a id=\"string-literals\"></a>[String literals](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#6456-string-literals)\n      - <a id=\"interpolated-string-literals\"></a>[Interpolated string literals](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#6456-string-literals)\n      - <a id=\"the-null-literal\"></a>[The null literal](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#6457-the-null-literal)\n    - <a id=\"operators-and-punctuators\"></a>[Operators and punctuators](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#646-operators-and-punctuators))\n  - <a id=\"pre-processing-directives\"></a>[Pre-processing directives](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#65-pre-processing-directives)\n    - <a id=\"conditional-compilation-symbols\"></a>[Conditional compilation symbols](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#652-conditional-compilation-symbols)\n    - <a id=\"pre-processing-expressions\"></a>[Pre-processing expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#653-pre-processing-expressions)\n    - <a id=\"declaration-directives\"></a>[Declaration directives](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#654-definition-directives)\n    - <a id=\"conditional-compilation-directives\"></a>[Conditional compilation directives](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#655-conditional-compilation-directives)\n    - <a id=\"diagnostic-directives\"></a>[Diagnostic directives](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#656-diagnostic-directives)\n    - <a id=\"region-directives\"></a>[Region directives](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#657-region-directives)\n    - <a id=\"line-directives\"></a>[Line directives](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#658-line-directives)\n    - <a id=\"pragma-directives\"></a> [Pragma directives](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#659-pragma-directives)\n      - <a id=\"pragma-warning\"></a>[Pragma warning](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/lexical-structure.md#659-pragma-directives)\n"
  },
  {
    "path": "spec/namespaces.md",
    "content": "# Namespaces\n\nThis content has moved to the [`dotnet/csharpstandard`](https://github.com/dotnet/csharpstandard) repository.\nThe list below provides links to each heading in this section. The links specify the C# 6 branch, which is version when the specifications merged.\n\n> To view the text of the Microsoft spec before merging with the ECMA text, checkout the [ms-spec-text](https://github.com/dotnet/csharplang/releases/tag/ms-spec-text) tag in this repository.\n\n- <a id=\"namespaces\"></a>[Namespaces](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#13-namespaces)\n  - <a id=\"compilation-units\"></a>[Compilation units](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#132-compilation-units)\n  - <a id=\"namespace-declarations\"></a>[Namespace declarations](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#133-namespace-declarations)\n  - <a id=\"extern-aliases\"></a>[Extern aliases](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#134-extern-alias-directives)\n  - <a id=\"using-directives\"></a>[Using directives](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#135-using-directives)\n    - <a id=\"using-alias-directives\"></a>[Using alias directives](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#1352-using-alias-directives)\n    - <a id=\"using-namespace-directives\"></a>[Using namespace directives](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#1353-using-namespace-directives)\n    - <a id=\"using-static-directives\"></a>[Using static directives](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#1354-using-static-directives)\n  - <a id=\"namespace-members\"></a>[Namespace members](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#136-namespace-member-declarations)\n  - <a id=\"type-declarations\"></a>[Type declarations](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#137-type-declarations)\n  - <a id=\"namespace-alias-qualifiers\"></a>[Namespace alias qualifiers](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#138-qualified-alias-member)\n    - <a id=\"uniqueness-of-aliases\"></a>[Uniqueness of aliases](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/namespaces.md#1382-uniqueness-of-aliases)\n"
  },
  {
    "path": "spec/statements.md",
    "content": "# Statements\n\nThis content has moved to the [`dotnet/csharpstandard`](https://github.com/dotnet/csharpstandard) repository.\nThe list below provides links to each heading in this section. The links specify the C# 6 branch, which is version when the specifications merged.\n\n> To view the text of the Microsoft spec before merging with the ECMA text, checkout the [ms-spec-text](https://github.com/dotnet/csharplang/releases/tag/ms-spec-text) tag in this repository.\n\n- <a id=\"statements\"></a>[Statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#12-statements)\n  - <a id=\"end-points-and-reachability\"></a>[End points and reachability](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#122-end-points-and-reachability)\n  - <a id=\"blocks\"></a>[Blocks](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#123-blocks)\n    - <a id=\"statement-lists\"></a>[Statement lists](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#1232-statement-lists)\n  - <a id=\"the-empty-statement\"></a>[The empty statement](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#124-the-empty-statement)\n  - <a id=\"labeled-statements\"></a>[Labeled statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#125-labeled-statements)\n  - <a id=\"declaration-statements\"></a>[Declaration statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#126-declaration-statements)\n    - <a id=\"local-variable-declarations\"></a>[Local variable declarations](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#1262-local-variable-declarations)\n    - <a id=\"local-constant-declarations\"></a>[Local constant declarations](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#1263-local-constant-declarations)\n  - <a id=\"expression-statements\"></a>[Expression statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#127-expression-statements)\n  - <a id=\"selection-statements\"></a>[Selection statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#128-selection-statements)\n    - <a id=\"the-if-statement\"></a>[The if statement](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#1282-the-if-statement)\n    - <a id=\"the-switch-statement\"></a>[The switch statement](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#1283-the-switch-statement)\n  - <a id=\"iteration-statements\"></a>[Iteration statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#129-iteration-statements)\n    - <a id=\"the-while-statement\"></a>[The while statement](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#1292-the-while-statement)\n    - <a id=\"the-do-statement\"></a>[The do statement](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#1293-the-do-statement)\n    - <a id=\"the-for-statement\"></a>[The for statement](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#1294-the-for-statement)\n    - <a id=\"the-foreach-statement\"></a>[The foreach statement](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#1295-the-foreach-statement)\n  - <a id=\"jump-statements\"></a>[Jump statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#1210-jump-statements)\n    - <a id=\"the-break-statement\"></a>[The break statement](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#12102-the-break-statement)\n    - <a id=\"the-continue-statement\"></a>[The continue statement](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#12103-the-continue-statement)\n    - <a id=\"the-goto-statement\"></a>[The goto statement](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#12104-the-goto-statement)\n    - <a id=\"the-return-statement\"></a>[The return statement](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#12105-the-return-statement)\n    - <a id=\"the-throw-statement\"></a>[The throw statement](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#12106-the-throw-statement)\n  - <a id=\"the-try-statement\"></a>[The try statement](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#1211-the-try-statement)\n  - <a id=\"the-checked-and-unchecked-statements\"></a>[The checked and unchecked statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#1212-the-checked-and-unchecked-statements)\n  - <a id=\"the-lock-statement\"></a>[The lock statement](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#1213-the-lock-statement)\n  - <a id=\"the-using-statement\"></a>[The using statement](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#1214-the-using-statement)\n  - <a id=\"the-yield-statement\"></a>[The yield statement](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/statements.md#1215-the-yield-statement)\n"
  },
  {
    "path": "spec/structs.md",
    "content": "# Structs\n\nThis content has moved to the [`dotnet/csharpstandard`](https://github.com/dotnet/csharpstandard) repository.\nThe list below provides links to each heading in this section. The links specify the C# 6 branch, which is version when the specifications merged.\n\n> To view the text of the Microsoft spec before merging with the ECMA text, checkout the [ms-spec-text](https://github.com/dotnet/csharplang/releases/tag/ms-spec-text) tag in this repository.\n\n- <a id=\"structs\"></a>[Structs](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/structs.md#15-structs)\n  - <a id=\"struct-declarations\"></a>[Struct declarations](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/structs.md#152-struct-declarations)\n    - <a id=\"struct-modifiers\"></a>[Struct modifiers](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/structs.md#1522-struct-modifiers)\n    - <a id=\"partial-modifier\"></a>[Partial modifier](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/structs.md#1523-partial-modifier)\n    - <a id=\"struct-interfaces\"></a>[Struct interfaces](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/structs.md#1524-struct-interfaces)\n    - <a id=\"struct-body\"></a>[Struct body](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/structs.md#1525-struct-body)\n  - <a id=\"struct-members\"></a>[Struct members](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/structs.md#153-struct-members)\n  - <a id=\"class-and-struct-differences\"></a>[Class and struct differences](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/structs.md#154-class-and-struct-differences)\n    - <a id=\"value-semantics\"></a>[Value semantics](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/structs.md#1542-value-semantics)\n    - <a id=\"inheritance\"></a>[Inheritance](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/structs.md#1543-inheritance)\n    - <a id=\"assignment\"></a>[Assignment](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/structs.md#1544-assignment)\n    - <a id=\"default-values\"></a>[Default values](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/structs.md#1545-default-values)\n    - <a id=\"boxing-and-unboxing\"></a>[Boxing and unboxing](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/structs.md#1546-boxing-and-unboxing)\n    - <a id=\"meaning-of-this\"></a>[Meaning of this](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/structs.md#1547-meaning-of-this)\n    - <a id=\"field-initializers\"></a>[Field initializers](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/structs.md#1548-field-initializers)\n    - <a id=\"constructors\"></a>[Constructors](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/structs.md#1549-constructors)\n    - <a id=\"destructors\"></a>**Destructors**: This section has been removed\n    - <a id=\"static-constructors\"></a>[Static constructors](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/structs.md#15410-static-constructors)\n  - <a id=\"struct-examples\"></a>**Struct examples** These sections have been removed.\n    - <a id=\"database-integer-type\"></a>Database integer type\n    - <a id=\"database-boolean-type\"></a>Database boolean type\n"
  },
  {
    "path": "spec/types.md",
    "content": "# Types\n\nThis content has moved to the [`dotnet/csharpstandard`](https://github.com/dotnet/csharpstandard) repository.\nThe list below provides links to each heading in this section. The links specify the C# 6 branch, which is version when the specifications merged.\n\n> To view the text of the Microsoft spec before merging with the ECMA text, checkout the [ms-spec-text](https://github.com/dotnet/csharplang/releases/tag/ms-spec-text) tag in this repository.\n\n- <a id=\"types\"></a>[Types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md)\n  - <a id=\"value-types\"></a>[Value types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#83-value-types)\n    - <a id=\"the-systemvaluetype-type\"></a>[The System.ValueType type](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#832-the-systemvaluetype-type)\n    - <a id=\"default-constructors\"></a>[Default constructors](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#833-default-constructors)\n    - <a id=\"struct-types\"></a>[Struct types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#834-struct-types)\n    - <a id=\"simple-types\"></a>[Simple types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#835-simple-types)\n    - <a id=\"integral-types\"></a>[Integral types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#836-integral-types)\n    - <a id=\"floating-point-types\"></a>[Floating point types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#837-floating-point-types)\n    - <a id=\"the-decimal-type\"></a>[The decimal type](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#838-the-decimal-type)\n    - <a id=\"the-bool-type\"></a>[The bool type](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#839-the-bool-type)\n    - <a id=\"enumeration-types\"></a>[Enumeration types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#8310-enumeration-types)\n    - <a id=\"nullable-types\"></a>[Nullable types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#8311-nullable-value-types)\n  - <a id=\"reference-types\"></a>[Reference types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#82-reference-types)\n    - <a id=\"class-types\"></a>[Class types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#822-class-types)\n    - <a id=\"the-object-type\"></a>[The object type](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#823-the-object-type)\n    - <a id=\"the-dynamic-type\"></a>[The dynamic type](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#824-the-dynamic-type)\n    - <a id=\"the-string-type\"></a>[The string type](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#825-the-string-type)\n    - <a id=\"interface-types\"></a>[Interface types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#826-interface-types)\n    - <a id=\"array-types\"></a>[Array types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#827-array-types)\n    - <a id=\"delegate-types\"></a>[Delegate types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#828-delegate-types)\n  - <a id=\"boxing-and-unboxing\"></a>[Boxing and unboxing](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#8312-boxing-and-unboxing)\n    - <a id=\"boxing-conversions\"></a>[Boxing conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#8312-boxing-and-unboxing)\n    - <a id=\"unboxing-conversions\"></a>[Unboxing conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#8312-boxing-and-unboxing)\n  - <a id=\"constructed-types\"></a>[Constructed types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#84-constructed-types)\n    - <a id=\"type-arguments\"></a>[Type arguments](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#842-type-arguments)\n    - <a id=\"open-and-closed-types\"></a>[Open and closed types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#843-open-and-closed-types)\n    - <a id=\"bound-and-unbound-types\"></a>[Bound and unbound types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#844-bound-and-unbound-types)\n    - <a id=\"satisfying-constraints\"></a>[Satisfying constraints](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#845-satisfying-constraints)\n  - <a id=\"type-parameters\"></a>[Type parameters](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#85-type-parameters)\n  - <a id=\"expression-tree-types\"></a>[Expression tree types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/types.md#86-expression-tree-types)\n"
  },
  {
    "path": "spec/unsafe-code.md",
    "content": "# Unsafe code\n\nThis content has moved to the [`dotnet/csharpstandard`](https://github.com/dotnet/csharpstandard) repository.\nThe list below provides links to each heading in this section. The links specify the C# 6 branch, which is version when the specifications merged.\n\n> To view the text of the Microsoft spec before merging with the ECMA text, checkout the [ms-spec-text](https://github.com/dotnet/csharplang/releases/tag/ms-spec-text) tag in this repository.\n\n- <a id=\"unsafe-code\"></a>[Unsafe code](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#22-unsafe-code)\n  - <a id=\"unsafe-contexts\"></a>[Unsafe contexts](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#222-unsafe-contexts)\n  - <a id=\"pointer-types\"></a>[Pointer types](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#223-pointer-types)\n  - <a id=\"fixed-and-moveable-variables\"></a>[Fixed and moveable variables](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#224-fixed-and-moveable-variables)\n  - <a id=\"pointer-conversions\"></a>[Pointer conversions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#225-pointer-conversions)\n    - <a id=\"pointer-arrays\"></a>[Pointer arrays](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#2252-pointer-arrays)\n  - <a id=\"pointers-in-expressions\"></a>[Pointers in expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#226-pointers-in-expressions)\n    - <a id=\"pointer-indirection\"></a>[Pointer indirection](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#2262-pointer-indirection)\n    - <a id=\"pointer-member-access\"></a>[Pointer member access](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#2263-pointer-member-access)\n    - <a id=\"pointer-element-access\"></a>[Pointer element access](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#2264-pointer-element-access)\n    - <a id=\"the-address-of-operator\"></a>[The address-of operator](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#2265-the-address-of-operator)\n    - <a id=\"pointer-increment-and-decrement\"></a>[Pointer increment and decrement](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#2266-pointer-increment-and-decrement)\n    - <a id=\"pointer-arithmetic\"></a>[Pointer arithmetic](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#2267-pointer-arithmetic)\n    - <a id=\"pointer-comparison\"></a>[Pointer comparison](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#2268-pointer-comparison)\n    - <a id=\"the-sizeof-operator\"></a>[The sizeof operator](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#2269-the-sizeof-operator)\n  - <a id=\"the-fixed-statement\"></a>[The fixed statement](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#227-the-fixed-statement)\n  - <a id=\"fixed-size-buffers\"></a>[Fixed size buffers](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#228-fixed-size-buffers)\n    - <a id=\"fixed-size-buffer-declarations\"></a>[Fixed size buffer declarations](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#2282-fixed-size-buffer-declarations)\n    - <a id=\"fixed-size-buffers-in-expressions\"></a>[Fixed size buffers in expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#2283-fixed-size-buffers-in-expressions)\n    - <a id=\"definite-assignment-checking\"></a>[Definite assignment checking](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#2284-definite-assignment-checking)\n  - <a id=\"stack-allocation\"></a>[Stack allocation](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/unsafe-code.md#229-stack-allocation)\n  - <a id=\"dynamic-memory-allocation\"></a>**Dynamic memory allocation**: Not included in the standard.\n"
  },
  {
    "path": "spec/variables.md",
    "content": "# Variables\n\nThis content has moved to the [`dotnet/csharpstandard`](https://github.com/dotnet/csharpstandard) repository.\nThe list below provides links to each heading in this section. The links specify the C# 6 branch, which is version when the specifications merged.\n\n> To view the text of the Microsoft spec before merging with the ECMA text, checkout the [ms-spec-text](https://github.com/dotnet/csharplang/releases/tag/ms-spec-text) tag in this repository.\n\n- <a id=\"variables\"></a>[Variables](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md)\n  - <a id=\"variable-categories\"></a>[Variable categories](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#92-variable-categories)\n    - <a id=\"static-variables\"></a>[Static variables](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#922-static-variables)\n    - <a id=\"instance-variables\"></a>[Instance variables](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#923-instance-variables)\n      - <a id=\"instance-variables-in-classes\"></a>[Instance variables in classes](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#9232-instance-variables-in-classes)\n      - <a id=\"instance-variables-in-structs\"></a>[Instance variables in structs](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#9233-instance-variables-in-structs)\n    - <a id=\"array-elements\"></a>[Array elements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#924-array-elements)\n    - <a id=\"value-parameters\"></a>[Value parameters](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#925-value-parameters)\n    - <a id=\"reference-parameters\"></a>[Reference parameters](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#926-reference-parameters)\n    - <a id=\"output-parameters\"></a>[Output parameters](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#927-output-parameters)\n    - <a id=\"local-variables\"></a>[Local variables](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#928-local-variables)\n  - <a id=\"default-values\"></a>[Default values](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#93-default-values)\n  - <a id=\"definite-assignment\"></a>[Definite assignment](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#94-definite-assignment)\n    - <a id=\"initially-assigned-variables\"></a>[Initially assigned variables](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#942-initially-assigned-variables)\n    - <a id=\"initially-unassigned-variables\"></a>[Initially unassigned variables](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#943-initially-unassigned-variables)\n    - <a id=\"precise-rules-for-determining-definite-assignment\"></a>[Precise rules for determining definite assignment](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#944-precise-rules-for-determining-definite-assignment)\n      - <a id=\"general-rules-for-statements\"></a>[General rules for statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#9442-general-rules-for-statements)\n      - <a id=\"block-statements-checked-and-unchecked-statements\"></a>[Block statements, checked, and unchecked statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#9443-block-statements-checked-and-unchecked-statements)\n      - <a id=\"expression-statements\"></a>[Expression statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#9444-expression-statements)\n      - <a id=\"declaration-statements\"></a>[Declaration statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#9445-declaration-statements)\n      - <a id=\"if-statements\"></a>[If statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#9446-if-statements)\n      - <a id=\"switch-statements\"></a>[Switch statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#9447-switch-statements)\n      - <a id=\"while-statements\"></a>[While statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#9448-while-statements)\n      - <a id=\"do-statements\"></a>[Do statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#9449-do-statements)\n      - <a id=\"for-statements\"></a>[For statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#94410-for-statements)\n      - <a id=\"break-continue-and-goto-statements\"></a>[Break, continue, and goto statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#94411-break-continue-and-goto-statements)\n      - <a id=\"throw-statements\"></a>[Throw statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#94412-throw-statements)\n      - <a id=\"return-statements\"></a>[Return statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#94413-return-statements)\n      - <a id=\"try-catch-statements\"></a>[Try-catch statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#94414-try-catch-statements)\n      - <a id=\"try-finally-statements\"></a>[Try-finally statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#94415-try-finally-statements)\n      - <a id=\"try-catch-finally-statements\"></a>[Try-catch-finally statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#94416-try-catch-finally-statements)\n      - <a id=\"foreach-statements\"></a>[Foreach statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#94417-foreach-statements)\n      - <a id=\"using-statements\"></a>[Using statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#94418-using-statements)\n      - <a id=\"lock-statements\"></a>[Lock statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#94419-lock-statements)\n      - <a id=\"yield-statements\"></a>[Yield statements](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#94420-yield-statements)\n      - <a id=\"general-rules-for-simple-expressions\"></a>[General rules for simple expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#94422-general-rules-for-simple-expressions)\n      - <a id=\"general-rules-for-expressions-with-embedded-expressions\"></a>[General rules for expressions with embedded expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#94423-general-rules-for-expressions-with-embedded-expressions)\n      - <a id=\"invocation-expressions-and-object-creation-expressions\"></a>[Invocation expressions and object creation expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#94424-invocation-expressions-and-object-creation-expressions)\n      - <a id=\"simple-assignment-expressions\"></a>[Simple assignment expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#94425-simple-assignment-expressions)\n      - <a id=\"-(conditional-and)-expressions\"></a>[&& (conditional AND) expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#94426--expressions)\n      - <a id=\"-(conditional-or)-expressions\"></a>[|| (conditional OR) expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#94427--expressions)\n      - <a id=\"-(logical-negation)-expressions\"></a>[! (logical negation) expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#94428--expressions)\n      - <a id=\"-(null-coalescing)-expressions\"></a>[?? (null coalescing) expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#94429--expressions)\n      - <a id=\"-(conditional)-expressions\"></a>[?: (conditional) expressions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#94430--expressions)\n      - <a id=\"anonymous-functions\"></a>[Anonymous functions](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#94431-anonymous-functions)\n  - <a id=\"variable-references\"></a>[Variable references](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#95-variable-references)\n  - <a id=\"atomicity-of-variable-references\"></a>[Atomicity of variable references](https://github.com/dotnet/csharpstandard/blob/draft-v6/standard/variables.md#96-atomicity-of-variable-references)\n"
  }
]