Skip to content

[Version 9.0] Feature support for lambda discards - #1464

Open
BillWagner wants to merge 4 commits into
draft-v9from
v9-lambda-discards
Open

BillWagner wants to merge 4 commits into
draft-v9from
v9-lambda-discards

Conversation

@BillWagner

Copy link
Copy Markdown
Member

This replaces #995

@RexJaeschke RexJaeschke added this to the C# 9.0 milestone Nov 11, 2025
@RexJaeschke RexJaeschke added type: feature This issue describes a new feature Review: pending Proposal is available for review labels Nov 11, 2025
@BillWagner BillWagner self-assigned this Jan 16, 2026
@BillWagner BillWagner added the meeting: discuss This issue should be discussed at the next TC49-TG2 meeting label Jan 26, 2026
@BillWagner
BillWagner marked this pull request as ready for review January 26, 2026 16:53
@BillWagner

Copy link
Copy Markdown
Member Author

@jskeet This is very small, and ready for a first look at our next meeting.

@jskeet jskeet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remarkably simple - slightly odd, but I can see how it gets the desired effect.

@BillWagner BillWagner removed the meeting: discuss This issue should be discussed at the next TC49-TG2 meeting label Mar 11, 2026
BillWagner added a commit that referenced this pull request Apr 10, 2026
…commit

Delta: 1 commit (edf14c6 Review and updates)
Original: 937ff4a (alpha-v9) / b742bf8 (pr-1464)
Conflicts resolved: 3 (basic-concepts.md x2, variables.md x1)
Section refs updated: §12.21.2 -> §12.22.2 for alpha-v9 numbering
@RexJaeschke
RexJaeschke marked this pull request as draft May 5, 2026 14:53
@BillWagner
BillWagner force-pushed the v9-lambda-discards branch from edf14c6 to ec70e0c Compare May 12, 2026 20:40
@BillWagner
BillWagner force-pushed the v9-lambda-discards branch from ec70e0c to 577c911 Compare June 24, 2026 17:41
@BillWagner

Copy link
Copy Markdown
Member Author

An earlier version of this feature is already present on alpha-v9 from a prior meeting. Edits made to this PR since then are not yet on alpha-v9; they will land at the next propagation. If you need them on alpha-v9 sooner, please open a separate PR targeting alpha-v9.
Thanks!

@BillWagner
BillWagner force-pushed the v9-lambda-discards branch from 577c911 to 940a5dc Compare July 24, 2026 19:50
@BillWagner BillWagner added the meeting: discuss This issue should be discussed at the next TC49-TG2 meeting label Aug 18, 2026
@BillWagner

Copy link
Copy Markdown
Member Author

This is ready for a first review in our September meeting.

@Nigel-Ecma Nigel-Ecma left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some changes needed, otherwise looks OK (and an advert for why _ should no longer be allowed as a name, sometimes a breaking change is worth it, but yes this is MS… 😉)

Comment thread standard/expressions.md Outdated
### 12.21.2 Anonymous function signatures

The *anonymous_function_signature* of an anonymous function defines the names and optionally the types of the parameters for the anonymous function. The scope of the parameters of the anonymous function is the *anonymous_function_body* ([§7.7](basic-concepts.md#77-scopes)). Together with the parameter list (if given) the anonymous-method-body constitutes a declaration space ([§7.3](basic-concepts.md#73-declarations)). It is thus a compile-time error for the name of a parameter of the anonymous function to match the name of a local variable, local constant or parameter whose scope includes the *anonymous_method_expression* or *lambda_expression*.
If an *explicit_anonymous_function_parameter_list* or an *implicit_anonymous_function_parameter_list* contains multiple *identifier*s `_`, each of those identifiers denotes a discard ([§9.2.9.2](variables.md#9292-discards)). Otherwise, any single *identifier* `_` denotes a parameter.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not quite correct. It assumes that any identifiers in a explicit_anonymous_function_parameter_list/implicit_anonymous_function_parameter_list are parameter names, they could however be types. This needs to be written to restrict to the identifiers occurring directly in explicit_anonymous_function_parameter/implicit_anonymous_function_parameter.

A discard_token is a subset of identifier, so in both these cases the non-terminal is discard_token and referring to that is better than using _.

See also deconstructor_element where discard_token is explicitly included when other alternatives might also resolve to identifier, along with rules when to treat it as a discard or something else. This might help in deciding how this should be phrased.

@jskeet jskeet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed with Nigel's general comment too. It's pretty gnarly that the meaning changes between one and two occurrences...

Comment thread standard/basic-concepts.md Outdated
- The scope of a parameter declared in a *constructor_declaration* ([§15.11](classes.md#1511-instance-constructors)) is the *constructor_initializer* and *block* of that *constructor_declaration*.
- The scope of a parameter declared in a *lambda_expression* ([§12.21](expressions.md#1221-anonymous-function-expressions)) is the *lambda_expression_body* of that *lambda_expression*.
- The scope of a parameter declared in an *anonymous_method_expression* ([§12.21](expressions.md#1221-anonymous-function-expressions)) is the *block* of that *anonymous_method_expression*.
- With the exception of discard parameters (§12.21.2), the scope of a parameter declared in a *lambda_expression* ([§12.21](expressions.md#1221-anonymous-function-expressions)) is the *lambda_expression_body* of that *lambda_expression*.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Section 12.21.2 seems to split things into "discards" and "parameters" - in a way that suggests a discard isn't a parameter, making this change unnecessary. It might still be better for the sake of clarity, but we should probably decide that intentionally.

It's also worth noting that 12.21.2 just calls them discards, not discard parameters, at least sometimes.

Perhaps we should just change 12.21.2 to explicitly specify "non-discard parameters" rather than saying "otherwise they are parameters".

@jskeet

jskeet commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

We think this is ready for @BillWagner to make the final changes before we get final approval and merge.

@jnm2

jnm2 commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

The language team has been talking approvingly of making a hard break in an upcoming version so _ is a keyword everywhere (no longer a valid identifier), given the successful (i.e. uneventful/slightly happy) community reaction to the breaking changes we unleashed with the field keyword. We've been talking about this for years but it keeps coming up.

RexJaeschke and others added 3 commits October 13, 2026 14:24
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 21570b74-c6f5-4fc5-ab6d-7546918d6ddb
Found a number of locations where discards should be mentioned in the context of lambda expressions or anonymous functions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 21570b74-c6f5-4fc5-ab6d-7546918d6ddb
Found some locations where "local variable" was used for a discard. That's now inaccurate, because a discard can be a lambda parameter.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 21570b74-c6f5-4fc5-ab6d-7546918d6ddb
Update to address all feedback:

- Count only identifiers directly naming parameters and use  *discard_token*, so identifiers within parameter types aren’t counted.
- Consistently distinguish discard parameters from non-discard parameters, including the related scope rules.
@BillWagner
BillWagner marked this pull request as ready for review October 22, 2026 20:00
@BillWagner BillWagner added the Review requested: Final approval All comments on the detailed review have been addressed. A final look is requested. label Oct 22, 2026
@BillWagner

Copy link
Copy Markdown
Member Author

I've addressed the remaining comments. This should be ready to merge at the next meeting.

@BillWagner BillWagner added meeting: priority Review before meeting. Merge, merge with issues, or reject at the next TC49-TC2 meeting and removed meeting: discuss This issue should be discussed at the next TC49-TG2 meeting labels Oct 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

meeting: priority Review before meeting. Merge, merge with issues, or reject at the next TC49-TC2 meeting Review: pending Proposal is available for review Review requested: Final approval All comments on the detailed review have been addressed. A final look is requested. type: feature This issue describes a new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants