1

I did a test and noticed the variables are evaluated from left to right in an interpolated string in .net c#. I am curious if this is specified and/or guaranteed behavior.

Example:

int cc = 0;
string dd = $@"first param is {cc++}
second {cc++}
and third is {cc++}";

Console.WriteLine(dd);

Prints this output:

first param is 0
second 1
and third is 2
Brady Moritz
  • 8,624
  • 8
  • 66
  • 100
  • Evaluation is left-to-right, just as if manual concatenation is used.. now, where are those links.. – user2864740 Jan 18 '20 at 22:36
  • Does this answer your question? [Pre & post increment operator behavior in C, C++, Java, & C#](https://stackoverflow.com/questions/6457130/pre-post-increment-operator-behavior-in-c-c-java-c-sharp) – Cid Jan 18 '20 at 22:37
  • 1
    If I were reviewing that code, I'd send back anything that counted on a side effect in an interpolated expression. – Joel Coehoorn Jan 18 '20 at 22:37
  • Uhg. So vague.. https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated indicates it can be transform to string.Format or Concat and says little else. This would seem to “indicate” that it’s equivalent to Format(m, expr1, expr2..) where the replacements are “in order” as the literals cannot use names. – user2864740 Jan 18 '20 at 22:39
  • @Cid question is about *if the order* of the evaluations is guaranteed.. for example, it is guaranteed in F(cc++, cc++, ..) – user2864740 Jan 18 '20 at 22:40
  • @user2864740 there's an [answer of Eric Lippert](https://stackoverflow.com/a/6457294/8398549) explaining that the order is guaranted left to right, in C# – Cid Jan 18 '20 at 22:56
  • @Cid Again, the order of `F(c++, --cc, ..)` is guaranteed. This question is about *string interpolation guarantees* - and if such *also* holds there. Here is a trivial (and very silly) example showing how such is not strictly transferable. Imagine if `$"{c++}{--cc}"` "was allowed" to be `string.Format("{1}{0}", --c, c++)`; it is only through *defined behavior* guarantees that such a transformation is not allowed. – user2864740 Jan 18 '20 at 23:25
  • If you have code that is dependent on the order of evaluation in an interpolated string, I'd argue that you should rejig your code to remove that dependency – Flydog57 Jan 19 '20 at 00:11

2 Answers2

2

As it's stated in documentation (https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated#compilation-of-interpolated-strings)

If an interpolated string has the type string, it's typically transformed into a String.Format method call. The compiler may replace String.Format with String.Concat if the analyzed behavior would be equivalent to concatenation.

So if I'm understand it correctly it is just compiled to String.Format("string", params[]), hence the order

  • The first sentence is not a guarantee. Here is a trivial counter example: `string.Format("{1}{0}", cc++, cc++)`. The latter "..may replace String.Format with String.Concat if the analyzed behavior would be equivalent to concatenation" *appears to* strongly imply `Format(m, a, b,..) <-> Concat(a, b, ..,)`, where the ordering guarantee comes from Concat, not the Format. However, it is also a *may* statement. The documentation could definitely use additional clarity. – user2864740 Jan 18 '20 at 22:51
  • 1
    I agree, but question is about string interpolation, where you're not able to change order of formatting using composite format string. – Sławomir Pawluk Jan 18 '20 at 22:54
  • The point is, without further documentation that statement is not a guarantee. An implementation could do something very silly and sill meet those "requirements". Go to the C# specification. – user2864740 Jan 18 '20 at 22:56
2

The order of evaluation is guaranteed left-to-right per the C# 6.0 Specification on Interpolated Strings.

This is because the algorithm of construction is specified. The relevant parts:

In both cases, the argument list of the call consists of a format string literal with placeholders for each interpolation, and an argument for each expression corresponding to the place holders ..

The format string literal is constructed as follows, where N is the number of interpolations in the interpolated_string_expression: ..

.. for each number n from 0 to N-1 [the format string "{n:..}" is added] ..

As the format sequence is guaranteed to use ordered [0,N) positional placeholders, then so too is the ordering of each "corresponding argument", and evaluation of, that is supplied to the string.Format call.

Thus the output of $@"A{cc++}B{--cc}C{++cc}" is guaranteed to be generated in a manner equivalent to string.Format("A{0}B{1}C{2}", c++, --c, ++c), where the order of the argument evaluation of F(..) is left-to-right.

The compiler could also generate equivalent code similar to string.Concat("A", c++, "B", --c, "C", ++c), which has a trivially equivalent evaluation order given the ordering guarantee of the core format specifier.

(The actual generated calls are different, see the conversions in the documentation; however, the examples above illustrate the evaluation ordering.)

Community
  • 1
  • 1
user2864740
  • 60,010
  • 15
  • 145
  • 220