# C# Language Design Meeting for May 3rd, 2021

## Agenda

1. [Improved interpolated strings](#improved-interpolated-strings)
2. [Open questions in record structs](#open-questions-in-record-structs)

## Quote of the Day

- "You all have a special way of working"

## Discussion

### Improved interpolated strings

https://github.com/dotnet/csharplang/issues/4487

Today, we got through the last of the open questions around the improved interpolated strings feature proposal.

#### `Create` vs `.ctor`

The first open question is around using the `Create` method instead of a constructor call. The spec today uses a static `Create` method as
an abstraction, to allow a hypothetical builder type to pool reference types in a static context, rather than being forced to return a `new`
instance on every builder creation. However, while this is a nice abstraction, we don't know of any proposed builder types that would take
advantage of this feature, and there are real codegen benefits to using a constructor instead. If we later come across a use case that would
like a static `Create` method instead, we can also add it later by using a switch on the attribute.

##### Conclusion

For better codegen, we will go with a single method of creation, a constructor, not a `Create` method.

#### Converting regular strings to builder types

We could consider any `string` value as being convertible to a builder type automatically via the builder pattern, which is the trivial case
of `value.Length` number of characters with zero interpolation holes. If we were to do this, it would be in the interest of consistency: a
user could more readily reason about how all string types will interact with an API. However, we do already have a mechanism in the language
to enable this: implicit user-defined conversions. Pushing a string through the standard builder pattern will likely be worse for performance
than what an API-author would write in an implicit conversion, and user-defined conversions already have well-defined semantics and impacts
on overload resolution.

##### Conclusion

Rejected. If an API author wants string to be convertible to their builders, they can use a user-defined conversion.

#### `ref struct` builder types in `async` contexts

Today, `ref struct` types are generally forbbiden in `async` contexts. This is because `await` expressions can occur in any subexpression, and
we have not formalized rules around ensuring that a `ref struct` variable does not cross an `await` boundary. In order to enable `ref struct`
builder types in `async` methods, we'd need to do essentially that same work in order to make usage safe. We're not introducing any new tradeoffs
by avoiding this: already today, developers need to choose between using a `ref struct`, and allowing usage in `async` contexts. While we would
be interested in general rules here, we don't think we should do anything special with regard to interpolated strings builder types. If we enable
it in general, interpolated string builders will naturally come along for the ride.

##### Conclusion

We will treat interpolated string builder usage as any other usage of a `ref struct` in `async` methods (today, that means disallowed).

### Open questions in record structs

#### Implementing `ISpanFormattable`

The BCL is adding a new interface for .NET 6, `ISpanFormattable`, which allows types to be formatted directly into a span, rather than having to
create a separate string instance. One immediate thought we have is why are records (struct or class) special here? We often think of records as
being named versions of anonymous types/tuples, so if we were to do this for records we would likely want to do this for those types as well.
This is important because it does impact public API: new overloads of `PrintMembers` will need to be implemented, and how this will interact with
the existing `PrintMembers` method that takes a `StringBuilder` is unclear. We also don't have a clear scenario here: `ToString()` in records is
mainly focused around debugging and logging scenarios. While performance is a nice to have here, it's not an overridding concern, and users who
want to actually use `ToString()` to do more important work can provide their own implementation, and `ISpanFormattable` with it. They can handle
the problems around interop with existing APIs by simply not using those APIs, which will keep the considerations simpler for them.

##### Conclusion

Rejected.

#### Using `InterpolatedStringBuilder` in record formatting

We could potentially optimize the implementation of `ToString()` by using `InterpolatedStringBuilder` as the string-building mechanism, rather
than `StringBuilder`. Unfortunately, this again runs into the problem of needing to interop with existing code, which unfortunately limits our
options here. Without a clear scenario to try and solve, we don't think this is worth it.

##### Conclusion

Rejected.

#### Passing an `IFormatProvider`

We could potentially generate an overload of `ToString` that takes an `IFormatProvider` and passes it to nested contexts. This again runs the
question of lacking a clear scenario and interop with existing code. We additionally don't have a clear idea of when we'd pass the format
provider to a nested type, as there is no standardized `ToString(IFormatProvider)` method on all types. If a user wants to have formatted
strings in their records, they presumably are providing their own implementation anyway, so we don't feel this is appropriate.

##### Conclusion

Rejected.
