5.4 KiB
C# Language Design Meeting for May 3rd, 2021
Agenda
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.