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