Skip to content

Optimize temporary string usage when DefaultInterpolatedStringHandler is used #77597

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
BrennanConroy opened this issue Feb 27, 2025 · 4 comments
Assignees
Labels
Area-Compilers Code Gen Quality Room for improvement in the quality of the compiler's generated code

Comments

@BrennanConroy
Copy link
Member

BrennanConroy commented Feb 27, 2025

Version Used:

.NET 10

Steps to Reproduce:

Today, the compiler generates code using DefaultInterpolatedStringHandler for various scenarios, I don't know all the places it's used and whether they might benefit from updates, so I'll focus on the one I do know.

Given the following simplified code

var str1 = "somevalue";
var str2 = "some";
var val1 = 1;
if (str1 == $"{str2}{val1}")
{
}

The compiler generates:

string value = "some";
int value2 = 1;
DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(0, 2);
defaultInterpolatedStringHandler.AppendFormatted(value);
defaultInterpolatedStringHandler.AppendFormatted(value2);
bool flag = "somevalue" == defaultInterpolatedStringHandler.ToStringAndClear();

The issue is that defaultInterpolatedStringHandler.ToStringAndClear() allocates a string just to do a string comparison, which should be allocation free if we could access the underlying ReadOnlySpan<char>.

With dotnet/runtime#112171 being merged, we now have access the the underlying ReadOnlySpan<char> and a way to clear the pooled memory when we're done with the string handler.

It would be nice if the compiler could now generate the allocation free code:

string value = "some";
int value2 = 1;
DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(0, 2);
defaultInterpolatedStringHandler.AppendFormatted(value);
defaultInterpolatedStringHandler.AppendFormatted(value2);
bool flag = "somevalue" == defaultInterpolatedStringHandler.Text;
defaultInterpolatedStringHandler.Clear();

Resulting in free perf for all!

@dotnet-issue-labeler dotnet-issue-labeler bot added Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead labels Feb 27, 2025
@jaredpar jaredpar transferred this issue from dotnet/roslyn Mar 11, 2025
@333fred 333fred transferred this issue from dotnet/csharplang Mar 13, 2025
@333fred
Copy link
Member

333fred commented Mar 13, 2025

@jaredpar I view this not as a language change, but just as a compiler optimization.

@jaredpar
Copy link
Member

@333fred doesn't this change the operator used to compare strings? From == on string to some equivalence of Span<char>? That is why I considered it a language issue.

@RikkiGibson
Copy link
Member

There might be some need to define "well-formedness" of these operators, such that for example we assume str == "a" to behave the same as str.AsSpan() == "a".AsSpan(), when the operands are non-null, or that kind of thing.

@333fred
Copy link
Member

333fred commented May 1, 2025

https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#12128-string-equality-operators does not describe exactly how the predefined string equality operator works. I believe that gives us the latitude to adjust how the implementation compares for a given expression, provided we continue to follow the exact semantics of the operation (compare by value, not by reference).

@jaredpar jaredpar added Code Gen Quality Room for improvement in the quality of the compiler's generated code and removed untriaged Issues and PRs which have not yet been triaged by a lead labels May 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compilers Code Gen Quality Room for improvement in the quality of the compiler's generated code
Projects
None yet
Development

No branches or pull requests

4 participants