# C# Language Design Meeting for May 15th, 2024

## Agenda

- [`field` and `value` as contextual keywords](#field-and-value-as-contextual-keywords)
  - [Usage in `nameof`](#usage-in-nameof)
  - [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)
  - [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)
  - [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)
- [Dictionary expressions](#dictionary-expressions)

## Quote of the Day

- "What the lowering implies here" _screen goes blank_ "Oh, you lowered too far"

## Discussion

### `field` and `value` as contextual keywords

Proposal: https://github.com/dotnet/csharplang/issues/7964  
Related: https://github.com/dotnet/csharplang/issues/8130, https://github.com/dotnet/csharplang/issues/140

We started today by looking at a number of open questions in the `field` and `value` as contextual keywords proposal.

#### Usage in `nameof`

First 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
working; 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)`.
First, 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"`,
but 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
`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`,
since 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,
we feel that it would be better to start with a tighter restriction we can loosen later if we hear feedback.

##### Conclusion

`nameof(value)` is legal, and will evaluate to `"value"`. `nameof(field)` will not be legal.

#### Should `value` be a keyword in a property or indexer get? Should `field` be a keyword in an indexer?

The 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
[example](https://github.com/dotnet/runtime/blob/19467dccf4e6786296eecd8007f90e6dafe01818/src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XAttribute.cs#L158-L172)
of where such a change would be unnecessarily breaking.

##### Conclusion

`value` will not be a keyword in property or indexer `get`s. `field` will not be a keyword in indexers.

#### Should `field` and `value` be considered keywords in lambdas and local functions within property accessors?

We 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
interpreted; 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
language, and also feels like the logical conclusion.

##### Conclusion

Yes, `field` and `value` will be contextual keywords within nested contexts when they exist.

#### Should `field` and `value` be keywords in property or accessor signatures? What about `nameof` in those spaces?

We split this question into two parts:

First, 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.
For `field` in this position, we don't see a reason to enable it, so it also won't be visible in the property declaration.

Second, inside accessor declarations, we have prior art of what we allow with `value` today. As an example:

```cs
public class C(string s) : Attribute
{
    public int P
    { 
        get;
        [param: C(nameof(value))] set;
    }
}
```

This 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:

```cs
class value(string type) : Attribute
{    
    value I
    {
        get;
        [param: value(nameof(value))] set;
    }
}
```

In 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`
or `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
the 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.

##### Conclusion

`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
signature.

### Dictionary expressions

Proposal: https://github.com/dotnet/csharplang/issues/7822
Related: [KeyValuePair Correspondence](./LDM-2024-05-15-KeyValuePairCorrespondence.md)

Today 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.
While we didn't get down to any hard decisions today, we did have a few comments during the overview to record:

* This proposal for making `KVP` transparent doesn't address how recursive to make it. For example, `KVP<string, KVP<int, int>>`.
* Proposal 4, where `KVP` is fully transparent everywhere in the language, is a potential breaking change.
* 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
  simply append.
