meetings/2021/LDM-2021-05-03.md
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 .ctorThe 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.
For better codegen, we will go with a single method of creation, a constructor, not a Create method.
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.
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 contextsToday, 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.
We will treat interpolated string builder usage as any other usage of a ref struct in async methods (today, that means disallowed).
ISpanFormattableThe 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.
Rejected.
InterpolatedStringBuilder in record formattingWe 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.
Rejected.
IFormatProviderWe 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.
Rejected.