string interpolation: proposed design changes

Topics: C# Language Design, VB Language Design
Developer
Oct 20, 2014 at 10:57 PM
Edited Oct 22, 2014 at 11:14 PM

String Interpolation for C#

An interpolated string is a way to construct a value of type String (or IFormattable) by writing the text of the string along with expressions that will fill in "holes" in the string. The compiler constructs a format string and a sequence of fill-in values from the interpolated string.

When it is treated as a value of type String, it is a shorthand for an invocation of
String.Format(string format, params object args[])
When it is converted to the type IFormattable, the result of the string interpolation is an object that stores a compiler-constructed format string along with an array storing the evaluated expressions. The object's implementation of
IFormattable.ToString(string format, IFormatProvider formatProvider)
is an invocation of
String.Format(IFormatProviders provider, String format, params object args[])
By taking advantage of the conversion from an interpolated string expression to IFormattable, the user can cause the formatting to take place later in a selected locale. See the section System.Runtime.CompilerServices.FormattedString for details.

Note: the converted interpolated string may have more "holes" in the format string than there were interpolated expression holes in the interpolated string. That is because some characters (such as "\{" "}") may be translated into a hole and a corresponding compiler-generated fill-in.

Lexical Grammar

An interpolated string is treated initially as a token with the following lexical grammar:
interpolated-string:
    $ " "
    $ " interpolated-string-literal-characters "

interpolated-string-literal-characters:
    interpolated-string-literal-part interpolated-string-literal-parts
    interpolated-string-literal-part

interpolated-string-literal-part:
    single-interpolated-string-literal-character
    simple-escape-sequence
    hexadecimal-escape-sequence
    unicode-escape-sequence
    interpolation

simple-escape-sequence:  one of
    \'  \"  \\  \0  \a  \b  \f  \n  \r  \t  \v  \{  \}

single-interpolated-string-literal-character:
    Any character except " (U+0022), \ (U+005C), { (U+007B) and new-line-character

interpolation:
    { interpolation-contents }

interpolation-contents:
    balanced-text
    balanced-text : interpolation-format

balanced-text:
    balanced-text-part
    balanced-text-part balanced-text

balanced-text-part
    Any character except ", (, [, {, /, \ and new-line-character
    ( balanced-text )
    { balanced-text }
    [ balanced-text ]
    regular-string-literal
    delimited-comment
    unicode-escape-sequence
    / after-slash

after-slash
    Any character except ", (, [, {, /, \, * and new-line-character
    ( balanced-text )
    { balanced-text }
    [ balanced-text ]
    regular-string-literal
    * delimited-comment-text[opt] asterisks /
    unicode-escape-sequence

interpolation-format:
    regular-string-literal
    literal-interpolation-format

literal-interpolation-format:
    interpolation-format-part
    interpolation-format-part literal-interpolation-format

interpolation-format-part
    Any character except ", :, \, } and new-line-character
With the additional restriction that a delimited-comment-text that is a balanced-text-part may not contain a new-line-character.

This lexical grammar is ambiguous in that it allows a colon appearing in interpolation-contents to be considered part of the balanced-text, or as the separator between the balanced-text and the interpolation-format. This ambiguity is resolved by considering it to be a separator between the balanced-text and interpolation-format.

Syntactic Grammar

An interpolated-string token is reclassified, and portions of it are reprocessed lexically and syntactically, during syntactic analysis as follows:
  • If the interpolated-string contains no interpolation, then it is reclassified as a regular-string-literal.
  • Otherwise
    • the portion of the interpolated-string before the first interpolation is reclassified as an interpolated-string-start terminal;
    • the portion of the interpolated-string after the last interpolation is reclassified as an interpolated-string-end terminal;
    • the portion of the interpolated-string between one interpolation and another interpolation is reclassified as an interpolated-string-mid terminal;
    • the balanced-text of each interpolation-contents is reprocessed according to the language's lexical grammar, yielding a sequence of terminals;
    • the colon in each interpolation-contents that contains an interpolation-format is classified as a colon terminal;
    • each interpolation-format is reclassified as a regular-string-literal terminal; and
    • the resulting sequence of terminals undergoes syntactic analysis as an interpolated-string-expression.
expression:
    interpolated-string-expression

interpolated-string-expression:
    interpolated-string-start interpolations interpolated-string-end

interpolations:
    single-interpolation
    single-interpolation interpolated-string-mid interpolations

single-interpolation:
    interpolation-start
    interpolation-start : regular-string-literal

interpolation-start:
    expression
    expression , expression

Semantics

An interpolated-string-expression has type string, but there is an implicit conversion from expression from an interpolated-string-expression to the type System.IFormattable. By the existing rules of the language (7.5.3.3 Better conversion from expression), the conversion to string is a better conversion from expression.

An interpolated-string-expression is translated into an intermediate format string and object array which capture the contents of the interpolated string using the semantics of Composite Formatting. If treated as a value of type string, the formatting is performed using string.Format(string format, params object[] args) or equivalent code. If it is converted to System.IFormattable, an object of type System.Runtime.CompilerServices.FormattedString is constructed using the format string and argument array, and that object is the value of the interpolated-string-expression.

The format string is constructed of the literal portions of the interpolated-string-start, interpolated-string-mid, and interpolated-string-end portions of the expression, with special treatment for { and } characters (see Notes).

The evaluation order needs to be specified.

The definite assignment rules need to be specified.

single-interpolation Semantics

This section should describe in detail the construction of a format item from a single-interpolation, and the corresponding element of the object array.

If an interpolation-start has a comma and a second expression, the second expression must evaluate to a compile-time constant of type int, which is used as the alignment of a format item.

If a single-interpolation has a colon and a regular-string-literal, then the string literal is used as the formatString of a format item.

Notes

The compiler is free to translate an interpolated string into a format string and object array where the number of objects in the object array is not the same as the number of interpolations in the interpolated-string-expression. In particular, the compiler may translate { and } characters into a fill-in in the format string and a corresponding string literal containing the character. For example, the interpolated string $"\{ {n} \}" may be translated to String.Format("{0} {1} {2}", "{", n, "}").

The compiler is free to use any overload of String.Format in the translated code, as long as doing so preserves the semantics of calling string.Format(string format, params object[] args).

Examples

The interpolated string
$"{hello}, {world}!"
is translated to
String.Format("{0}, {1}!", hello, world)
The interpolated string
$"Name = {myName}, hours = {DateTime.Now:hh}"
is translated to
String.Format("Name = {0}, hours = {1:hh}", myName, DateTime.Now)
The interpolated string
$"\{{6234:D}\}"
is translated to
String.Format("{0}{1:D}{2}", "{", 6234, "}")
For example, if you want to format something in the invariant locale, you can do so using this helper method
public static string INV(IFormattable formattable)
{
    return formattable.ToString(null, System.Globalization.CultureInfo.InvariantCulture);
}
and writing your interpolated strings this way
   string coordinates = INV("longitude={longitude}; latitude={latitude}");

System.Runtime.CompilerServices.FormattedString

The following platform class is used to translate an interpolated string to the type System.IFormattable.
namespace System.Runtime.CompilerServices 
{ 
    public class FormattedString : System.IFormattable 
    {
        private readonly String format;
        private readonly object[] args;
        public FormattedString(String format, params object[] args)
        {
            this.format = format;
            this.args = args;
        }
        string IFormattable.ToString(string ignored, IFormatProvider formatProvider)
        {
            return String.Format(formatProvider, format, args);
        }
    } 
} 

Issues

  1. As specified, an interpolated string with no interpolations cannot be converted to IFormattable because it is a string literal. It should have such a conversion.
Marked as answer by nmgafter on 10/20/2014 at 4:06 PM
Oct 20, 2014 at 11:16 PM
I believe interpolated-string-literal-characters was intended to be interpolated-string-literal-parts in the lexical grammar.
Developer
Oct 20, 2014 at 11:40 PM
sharwell wrote:
I believe interpolated-string-literal-characters was intended to be interpolated-string-literal-parts in the lexical grammar.
Right you are. Fixed. Thanks.
Oct 20, 2014 at 11:57 PM
Edited Oct 21, 2014 at 12:06 AM
I like it, for the most part!

A few comments:
  • Wouldn't it be better to use "{{" rather than "\{" to escape braces? It would be more consistent with the composite formatting escape mechanism.
  • When you say that the interpolated-string-expression is convertible to IFormattable, do you mean that we should write IFormattable x = $"{hello}, {world}!"; ? Could you add an example of this use case?
  • The ability to specify a different format provider is nice, because we could, for instance, specify a culture. However I'm not sure about how it would allow us to customize how each item in args is formatted. Would we have to implement a custom IFormatProvider that returns a custom ICustomFormatter?
Oct 21, 2014 at 12:20 AM
I just browsed through the spec (past 1AM here) but it was not clear to me where the IFormatable plays in. Does it mean that I can write code like this: $"{DateTime.Now}"(string.Empty, CultureInfo.InvariantCulture)?
Oct 21, 2014 at 12:25 AM
Round and round we go!

So, back to prefixed syntax only? Seems very much like a verbatim string in terms of rules except requiring escaping of { and }, but there seems to be absolutely no way to embed a newline (short of interpolating one?)

I'm curious if the C# team saw my statement a couple of days ago about supporting both escaped syntax for normal string literals and a prefixed syntax for combination verbatim-interpolated strings.
// equivalent
var s1 = "Hello \{person.name}, you were born on \{person.dob:D}.  {\{person.age} years ago!}";
var s2 = $"Hello {person.name}, you were born on {person.dob:D}.  {{{person.age} years ago!}";
I'm also curious as to how it works as an IFormattable. That interface doesn't quite seem appropriate, both locking away many of the details while intended to be used within a larger formatted string. I kind of like how JavaScript tagged template strings work where the tag function accepts an array of n interpolated values and n+1 parts of the string and then returns a string. The only thing missing is the bits for composite formatting.
Oct 21, 2014 at 12:32 AM
PauloMorgado wrote:
I just browsed through the spec (past 1AM here) but it was not clear to me where the IFormatable plays in. Does it mean that I can write code like this: $"{DateTime.Now}"(string.Empty, CultureInfo.InvariantCulture)?
I think it means you can have a method like this:
string Url(IFormattable formattedString)
{
    return formattedString.ToString(null, new UrlFormatProvider());
}
And use it like this:
string searchTerms = "c# rocks";
string url = Url($"http://my.domain.com/search?q={searchTerms}");
(That leaves the question of how to implement UrlFormatProvider, but it seems relatively straightforward. You just need to return a ICustomFormatter that will format each item)
Oct 21, 2014 at 1:56 AM
Edited Oct 21, 2014 at 1:57 AM
I think the IFormattable solution is fantastic, and does a great job of solving the "which culture should the interpolated string be in" question. Nice job!

My grammar is a little rusty- is this saying there are no escaped characters allowed in the string except braces? Meaning there is no way to put a newline in this type of string at all? Or a double quote? I don't really understand the rational behind that decision. Can this string exist across multiple lines, like a verbatim string?

I think it should act like a normal string + the need for braces escaping. That seems like the least surprising implementation. I very frequently use double quotes in my strings for exception messages, so it would seem really strange if there was no non-hacky way to put one in an interpolated string. If you want to add "verbatim string interpolation" with stricter escaping rules, you could always do that in addition (or in a later release cycle).

It would help to add an example regarding the outstanding issue you list as well. Is it essentially this?
Url($"http://roslyn.codeplex.com") //This won't work because it has no interpolations

string Url(IFormattable formattedString) { ... }
Is this an implementation issue or a spec issue? It seems like you'd just apply the same rules regardless of whether there is an interpolation present in the string.
Coordinator
Oct 21, 2014 at 5:36 AM
Halo_Four wrote:
I'm also curious as to how it works as an IFormattable. That interface doesn't quite seem appropriate, both locking away many of the details while intended to be used within a larger formatted string.
It doesn't lock it away...
Function ExtractFromIFormattable(fable As IFormattable) As Tuple(Of String, List(Of Object))
    Dim mfp As New MyFormatProvider
    Dim s = fable.ToString(Nothing, mfp)
    Return Tuple.Create(s, mfp.args)
End Function

Class MyFormatProvider : Implements IFormatProvider
    Public args As New List(Of Object)
    Public Function GetFormat(formatType As Type) As Object Implements IFormatProvider.GetFormat
        Return New MyCustomFormatter
    End Function
End Class

Class MyCustomFormatter : Implements ICustomFormatter
    Public Function Format(format1 As String, arg As Object, formatProvider As IFormatProvider) As String Implements ICustomFormatter.Format
        Dim mfp = CType(formatProvider, MyFormatProvider)
        mfp.args.Add(arg)
        Return "{" & (mfp.args.Count - 1) & If(format1 Is Nothing, "", ":" & format1) & "}"
    End Function
End Class
Oct 21, 2014 at 5:41 AM
Edited Oct 21, 2014 at 5:44 AM
Will there be IFormattable overloads in BCL?

Specially for string.Format and StringBuilder

Can I define my own System.IFormattable interface for earlier BCL versions?
Oct 21, 2014 at 7:32 AM
Wow, this is much better now! I like the "work-around" with IFormattable and that you're back to the prefix syntax. Much better! Two comments, though:
nmgafter wrote:
The interpolated string
$"\{{6234:D}\}"
is translated to
String.Format("{0}{1:D}{2}", "{", 6234, "}")
Why?? Why escape braces with \? I would have expected $"{{{6234:D}}}" => String.Format("{{{0:D}}}, 6234). This would be (slightly) more efficient and less surprising, considering that most people know how to escape curly braces in a format string. I really don't like having a second way to escape curly braces, even though one is a language feature and the other a framework feature.

Even if you decide to use \ in the end, why don't you construct the format string directly and instead pass the curly braces as a format argument? Is that really that hard to implement?

Issues

  1. As specified, an interpolated string with no interpolations cannot be converted to IFormattable because it is a string literal. It should have such a conversion.
Agreed.
Oct 21, 2014 at 7:34 AM
madrian wrote:
Can I define my own System.IFormattable interface for earlier BCL versions?
IFormattable has been available since at least .NET 2.0. System.Runtime.CompilerServices.FormattedString seems to be new, though.
Oct 21, 2014 at 8:26 AM
Seems a very good step forward, although
  • I'd also prefer {{ instead of \{
  • it seems there's no way to include a " in the literal parts except as a hex/unicode escape sequence or an additional hole. Is that right?
  • same question with newlines.
I can live with no new lines in the hole expressions, but it would be important in the literal parts, especially when working with html/xml.
Oct 21, 2014 at 8:44 AM
The way stuff is escaped in strings in C# is by prefixing it with \. The fact that some idioms that C# programer have to deal with use the same escaping mechanism (like regular expressions) and others use double characer (like string.Format/IFormatable.ToString formta specifications) is something that we'll always have to live with.

I can live with the interpolatied string not being verbatim as long as I can write them in a way I can read it.

I expect thsi source definition:
var html =
/*----------*/"<html>" +
/*------------*/"<head>" +
/*--------------*/"<title>{title}</title>" +
/*------------*/"</head>" +
/*------------*/"<body>" +
/*------------*/"</body>" +
/*----------*/"</html>" 
to be translated by the compiler to:
"<html><head><title>{0}</title></head><body></body></html>"
Oct 21, 2014 at 9:33 AM
I also would prefer the {{ over \{

Some of the examples people are providing is xml / html like tree structures, which leads me to think and suggest it could be beneficial for the C# parser to become stateful like VB so it could implement xml-literals. Or even XAML Literals?
Oct 21, 2014 at 9:39 AM
Edited Oct 21, 2014 at 10:05 AM

Issues

  1. As specified, an interpolated string with no interpolations cannot be converted to IFormattable because it is a string literal. It should have such a conversion.
    Agreed.
I doesn't matter, it gets eventually passed to the following method, which can handle that possibility.

Other thing is to make it inherit from String.Literal
Public Class Interpolated_String
  Inherits Literal_String
  ' This allows the separating of Parsing ArgHoles and analysis of said hole.
   Public Iterator ArgHoles() As IEnumerable(Of ArgHole)
' Snipped out code 
   End Function

End Class
Example of an implementation of that function used in SFD.
    Public Iterator Function Yield_ArgHoles(theString As String, indexOffset As Integer) As IEnumerable(Of Results.Base_Result)
      If theString Is Nothing Then Return
      Dim sr As New StringReader(theString)
      Dim InHole As Boolean = False
      Dim InErrorState = False
      Dim IsQuoted = False
      While sr.IsNotEoT
        Select Case True
          Case (sr = "{"c) AndAlso (sr.Peek = "{"c) : IsQuoted = True
          Case (sr = "{"c) AndAlso Not InHole
            InHole = True
            Dim arg_Hole = Parse_ArgHole(sr)
            If (TypeOf arg_Hole Is Error_Result) OrElse (arg_Hole Is Nothing) Then InErrorState = True
            Yield arg_Hole
            If Not InErrorState Then InHole = False
          Case (sr = "{"c) AndAlso InHole ' Parsing Error: Recursize hole not allowed
            Yield New Error_Result(New UnexpectedChar(sr.Index, sr.Value))
          Case (sr = "}"c) AndAlso (sr.Peek = "}"c) : IsQuoted = True
          Case (sr = "}"c)
            If Not InHole Then
              ' Parsing Error: Mismatched brace.
              Yield New Error_Result(New UnexpectedChar(sr.Index, sr.Value))
            Else
              InHole = False
              InErrorState = False
            End If
        End Select
        If IsQuoted Then sr.Next() : IsQuoted = False
        sr.Next()
      End While
    End Function
The following is being used in and updated version of SFD. Note: IndexSpan is the position with the string and span of character cover. It enables highlighting of the different parts of the ArgHole
  Public Class ArgHole
    Public ReadOnly Property Identifier As Arg_Identifier
    Public ReadOnly Property Alignment As Arg_Alignment
    Public ReadOnly Property Format As Arg_Format
    Public ReadOnly Property Span As IndexSpan

    Public Sub New(Span As IndexSpan, Identifier As Arg_Identifier, Alignment As Arg_Alignment, Format As Arg_Format)
      Me._Span = Span
      Me._Identifier = Identifier
      Me._Alignment = Alignment
      Me._Format = Format
    End Sub

    Public Overrides Function ToString() As String
      Return String.Format("({0} , {1} : {2})", If(Identifier, ""), If(Alignment, ""), If(Format, ""))
    End Function
  End Class

  Public MustInherit Class Arg_Base
    Public ReadOnly Property Span As IndexSpan?

    Friend Sub New(Span As IndexSpan?)
      _Span = Span
    End Sub
    Public Overrides Function ToString() As String
      Return Span.ToString
    End Function
  End Class

  Public MustInherit Class Arg_Identifier
    Inherits Arg_Base

    Friend Sub New(Span As IndexSpan?)
      MyBase.New(Span)
    End Sub
    Public Overrides Function ToString() As String
      Return MyBase.ToString()
    End Function

  End Class

  Public Class Arg_Index
    Inherits Arg_Identifier

    Public Sub New(Span As IndexSpan?, ArgIndex As Integer)
      MyBase.New(Span)
      _ArgIndex = ArgIndex
    End Sub

    Public ReadOnly Property ArgIndex As Integer
    Public Overrides Function ToString() As String
      Return String.Format("{0}{1}", ArgIndex, MyBase.ToString)
    End Function
  End Class

  Public Class Arg_Alignment
    Inherits Arg_Base
    Public ReadOnly Property Alignment As Integer

    Public Sub New(Span As IndexSpan?, Alignment As Integer)
      MyBase.New(Span)
      _Alignment = Alignment
    End Sub
    Public Overrides Function ToString() As String
      Return String.Format("{0}{1}", Alignment, MyBase.ToString)
    End Function
  End Class

  Public Class Arg_Format
    Inherits Arg_Base
    Public ReadOnly Property Format As String
    Public Sub New(Span As IndexSpan?, Format As String)
      MyBase.New(Span)
      _Format = Format
    End Sub
    Public Overrides Function ToString() As String
      Return String.Format("{0}{1}", Format, MyBase.ToString)
    End Function
  End Class

Also it permits the Index of the ArgHole to also be an Identifier by implement another class the extends Arg_Identifier,

The exact same methods and classes are use for both the VB and C# diagnostics.
Oct 21, 2014 at 10:17 AM
You may have also have missed another possible error {} which results in a invalid format string. (Note: SFD warns you at compile-time)
Also what If the is no "Arg Index" present { ,-4, X4} the user forgot enter it.
Another is where the intent is Ambigious
Oct 21, 2014 at 10:54 AM
Halo_Four
AdamSpeight2008 wrote:
If they are Application Setting you coukd since therey are readonly at runtime.
Which isn't relevant since it's not known at compile time and the compiler would have no idea how to interpolate scoped expressions. Even if there were custom >interpolators the syntax and holes would have to be resolved at compile time in order to provide the correct tokens.
Parsing the Interpolation String wouldn't be that hard (So above) , resolving them at compile-time is also possible. The compiler does that already.
Oct 21, 2014 at 11:33 AM
AdamSpeight2008 wrote:
Halo_Four
AdamSpeight2008 wrote:
If they are Application Setting you coukd since therey are readonly at runtime.
Which isn't relevant since it's not known at compile time and the compiler would have no idea how to interpolate scoped expressions. Even if there were custom >interpolators the syntax and holes would have to be resolved at compile time in order to provide the correct tokens.
Parsing the Interpolation String wouldn't be that hard (So above) , resolving them at compile-time is also possible. The compiler does that already.
No, the compiler doesn't resolve the settings; it just compiles the .cs generated by the IDE.
But anyway, it wouldn't make a lot of sense to use settings for string interpolation. And when you say app settings are read-only: true, you can't easily change them at runtime, but the value comes from the .config file, which can be change externally.
Oct 21, 2014 at 2:56 PM
Edited Oct 21, 2014 at 2:57 PM
Does the IFormatteable generated object solves the problem of storing the strings in resources somehow?. That's for me the most important thing, and the reason I've ignored string interpolation discussion so far.
Oct 21, 2014 at 3:16 PM
Olmo wrote:
Does the IFormatteable generated object solves the problem of storing the strings in resources somehow?. That's for me the most important thing, and the reason I've ignored string interpolation discussion so far.
I can't imagine how given that the compiler would have no mechanism through which to identify the local expressions to capture. Even if the compiler did try to read into the resources those values can change or be replaced through satellite assemblies.

In my opinion the concept of "interpolated" resources or settings should be a project item in Visual Studio, a markup syntax which the tool could use to generate methods which accept the input as parameters, e.g.:
<data name="Foo" type="interpolated" xml:space="preserve">
  <value>Hello {0}!</value>
  <hole type="System.String, mscorlib" name="name" />
</data>
internal static string Foo(string name) {
    return String.Format(ResourceManager.GetString("Foo", resourceCulture), name);
}
Oct 21, 2014 at 5:37 PM
Edited Oct 21, 2014 at 5:48 PM
I also like this syntax better. I'm hoping this will open up the possibility of adding syntax sugar to the language so we can easily extend the operator via the Roslyn APIs, to make new operators such as URL$"..." and SQL$"...".

For example, as an alternative to the usage shown here:

tom103 wrote:
string Url(IFormattable formattedString)
{
    return formattedString.ToString(null, new UrlFormatProvider());
}
string searchTerms = "c# rocks";
string url = Url($"http://my.domain.com/search?q={searchTerms}");
We might have this instead:
string url = URL$"HTTP|my.domain.com|/search|{q,searchTerms}";
(Not necessarily a suggested format string but just showing what could be done)

Probably the "killer feature" here is that you can get an embedded DSL without screwing up the main C# language too much, along with syntax visualization and intellisense.
Developer
Oct 21, 2014 at 8:27 PM
Edited Oct 21, 2014 at 9:33 PM
madrian wrote:
Will there be IFormattable overloads in BCL?

Specially for string.Format and StringBuilder

Can I define my own System.IFormattable interface for earlier BCL versions?
IFormattable has been in the BCL for some time. That is how locales are represented.

For example, if you want to format something in the invariant locale, you can do so using this helper method
public static string INV(IFormattable formattable)
{
    return formattable.ToString(null, System.Globalization.CultureInfo.InvariantCulture);
}
and writing your interpolated strings this way
   string coordinates = INV("longitude={longitude}; latitude={latitude}");
Oct 21, 2014 at 8:30 PM
Edited Oct 21, 2014 at 8:30 PM
AdamSpeight2008 wrote:
I also would prefer the {{ over \{

Some of the examples people are providing is xml / html like tree structures, which leads me to think and suggest it could be beneficial for the C# parser to become stateful like VB so it could implement xml-literals. Or even XAML Literals?
I would think it would make more sense to pick a character sequence which would have no plausible pre-existing reason to appear, such as {|someVariable|} or {$someVariable$}. Given that many things use \ as a means of escaping characters that shouldn't be processed, it would be unclear whether the \ was intended to cause the { to be interpreted specially be C#, prevent it from being interpreted specially by C#, cause the insertion of a literal \ character which would then cause the following { to be processed specially by the next processing layer, or maybe insert a literal \ which would prevent the following { by being treated specially in the next processing layer, etc. Using a syntax with no existing meaning or connotations would avoid such issues.
Developer
Oct 21, 2014 at 8:34 PM
Expandable wrote:
Why?? Why escape braces with \? I would have expected $"{{{6234:D}}}" => String.Format("{{{0:D}}}, 6234). This would be (slightly) more efficient and less surprising, considering that most people know how to escape curly braces in a format string. I really don't like having a second way to escape curly braces, even though one is a language feature and the other a framework feature.
The reason is that the way you wrote it doesn't work. You end up with the first two }} considered to be inside the format string, so that the format string is "D}". The final string is "{D}" instead of "{6234}". This unfortunate result is explained in detail in the section "Escaping Braces" on the page Composite Formatting, and is a consequence of the fact that the composite formatting syntax is inherently ambiguous with no way to disambiguate. We've selected an escaping syntax that is unambiguous and we can translate it without any problems into the desired string using String.Format.
Developer
Oct 21, 2014 at 8:37 PM
BachratyGergely wrote:
Seems a very good step forward, although
  • I'd also prefer {{ instead of \{
  • it seems there's no way to include a " in the literal parts except as a hex/unicode escape sequence or an additional hole. Is that right?
  • same question with newlines.
I can live with no new lines in the hole expressions, but it would be important in the literal parts, especially when working with html/xml.
All of the usual escape sequences will work. The syntax rules above
simple-escape-sequence:
    \ {
    \ }
augment (do not replace) the existing lexical grammar rules in the C# language spec (section 2.4.4.4):
simple-escape-sequence:  one of
    \'  \"  \\  \0  \a  \b  \f  \n  \r  \t  \v
Developer
Oct 21, 2014 at 8:41 PM
AdamSpeight2008 wrote:
You may have also have missed another possible error {} which results in a invalid format string. (Note: SFD warns you at compile-time)
That doesn't fit the lexical grammar for an interpolated string, and therefore the compiler will produce an error at compile-time.
Also what If the is no "Arg Index" present { ,-4, X4} the user forgot enter it.
You'll get a parse error about an expression expected but comma found.
Another is where the intent is Ambigious
I have no idea how this relates to the proposal.
Oct 21, 2014 at 9:16 PM
Edited Oct 21, 2014 at 9:17 PM
nmgafter wrote:
BachratyGergely wrote:
Seems a very good step forward, although
  • I'd also prefer {{ instead of \{
  • it seems there's no way to include a " in the literal parts except as a hex/unicode escape sequence or an additional hole. Is that right?
  • same question with newlines.
I can live with no new lines in the hole expressions, but it would be important in the literal parts, especially when working with html/xml.
All of the usual escape sequences will work. The syntax rules above
simple-escape-sequence:
    \ {
    \ }
augment (do not replace) the existing lexical grammar rules in the C# language spec (section 2.4.4.4):
simple-escape-sequence:  one of
    \'  \"  \\  \0  \a  \b  \f  \n  \r  \t  \v
So in this scenario \{ actually escapes the { char so the { char appears in the output string rather than saying the \{...} is how you specify a hole? If so, I like it.
Developer
Oct 21, 2014 at 9:43 PM
r_keith_hill wrote:
So in this scenario \{ actually escapes the { char so the { char appears in the output string rather than saying the \{...} is how you specify a hole? If so, I like it.
Yes.

Incidentally the \} escape isn't strictly needed, as you can always use } wherever you would use the escape. But it would be odd to have to use \{ and not be able to write \}.
Oct 21, 2014 at 9:43 PM
Edited Oct 21, 2014 at 9:52 PM
@nngafter
{} 
Is an runtime error in String.Format so if youbre transmuting interpolated string in to string format. Then that issue doesn't arise until runtime

What is the rough object structure going to be for interpolated string? In should be language independant as possible.
It should just parse the interpolated strng:-
  • This a section of text.
    • This a hole
    • this is its identifier
    • this is its alignment,
    • this is its format string.
The analysis and resultant transformation should be left to a different object like code fix.
A code preview could show the transformed result, the during a debug breakpoint has the actual values in.

What about debug breakpoint diagnostics? Where that actual object values are available?
For example class object is null, give a warning.

Cos at the moment I write two analysers one for c# one for vb. Not like there is a dicumented way if doing
Funtion AnalyseNode(Of t As base_syntaxNode)( sn as t.... 
So it can shared between languages without having to duplicte large sections of code.


if this is just c# then why is discussion also in vb section of discussions?
Oct 21, 2014 at 10:13 PM
Edited Oct 21, 2014 at 10:16 PM
Why {{ over \{? So same basic structure for bith vb and c#. As per String.Format so no surprises when using it.
Only differences then are the existing language difference in strings.
All that changes is what is allowed as an arg hole identifier in this case an identifier rather than a index.

Also what about alignment arg of the hole?
Oct 21, 2014 at 10:27 PM
So there seem to be quite a lot of escaping stuff in C#, {{ for string.Format, \{ for DebuggerDisplay attribute, regular expressions and other character escaping, {}{ in XAML...

I would think about this feature in terms what DebuggerDisplay attribute is trying to provide, so it might make sense to be it consistent with that one.
Developer
Oct 21, 2014 at 11:35 PM
AdamSpeight2008 wrote:
@nngafter
{} 
Is an runtime error in String.Format so if youbre transmuting interpolated string in to string format. Then that issue doesn't arise until runtime
An interpolated string with empty curly braces like this would be a (lexical) error at compile-time because it doesn't fit the syntax of the specification. The compiler won't translate a program with errors into a program that calls String.Format.
What is the rough object structure going to be for interpolated string? In should be language independant as possible.
It should just parse the interpolated strng:-
  • This a section of text.
    • This a hole
    • this is its identifier
    • this is its alignment,
    • this is its format string.
Yes, that is about right. The syntax tree models the syntactic grammar. Look for InterpolatedStringSyntax in https://roslyn.codeplex.com/SourceControl/latest#Src/Compilers/CSharp/Portable/Syntax/Syntax.xml
The analysis and resultant transformation should be left to a different object like code fix.
A code preview could show the transformed result, the during a debug breakpoint has the actual values in.
The compiler doesn't show its work. From the point of view of the IDE and the compiler API, it is just regular syntax nodes.
What about debug breakpoint diagnostics? Where that actual object values are available?
For example class object is null, give a warning.
I don't understand what you're asking. Can you show a concrete scenario?
Oct 22, 2014 at 4:21 AM
nmgafter wrote:
IFormattable has been in the BCL for some time. That is how locales are represented.
What I meant was if there would be overloads so that

string.Format(CultureInfo.InvariantCulture, @"{x}");

will work as expected.

But I now see that string is a better match than IFormattable for overloads so it will not work anyway.


There are 2 things I don't understand with the IFormattable solution.
  1. Dependency on CompilerServices.FormattedString
    Will I get a compile-time or run-time error if I target .Net4?
  2. How to use IFormattable in e.g. a logging library
    IFormattable will only work if there is no string overload.
    This means I can not support both positional and interpolated format string without using different methodnames.
or will this work?
MyFormatter(IFormattable arg)
MyFormatter<T>(T fmt, params object[] args) where T:string

(it will be a breaking change for existing libraries)

I don't know how roslyn works but is it very difficult to detect if the interpolated string is used in a method call where a string+params overload is available?
(a different overload might actually be called due to overload rules but the existence of string+params ensures it will succeed)
Oct 22, 2014 at 8:33 AM
Edited Oct 22, 2014 at 8:33 AM
madrian wrote:
  1. Dependency on CompilerServices.FormattedString
    Will I get a compile-time or run-time error if I target .Net4?
That's a good question. I'd like it if we were able to provide the FormattedString class ourselves if it's not in the target framework (similar to what was done in LinqBridge, which provides the Enumerable and ExtensionAttribute classes for .NET 2)
or will this work?
MyFormatter(IFormattable arg)
MyFormatter<T>(T fmt, params object[] args) where T:string
No, it won't, because string can't be a generic constraint. You can do this instead:
MyFormatter<T>(T arg) where T : IFormattable
MyFormatter(string fmt, params object[] args)
But I'm not sure which overload it will pick...
Oct 22, 2014 at 9:51 AM
nmgafter wrote:
All of the usual escape sequences will work. The syntax rules above
augment (do not replace) the existing lexical grammar rules in the C# language spec (section 2.4.4.4):
Sorry, this really lead me astray. In the future could you please indicate this more explicitly in the grammar?

nmgafter wrote:
simple-escape-sequence:  one of
    \'  \"  \\  \0  \a  \b  \f  \n  \r  \t  \v
Does this also mean that verbatim strings are still out of the picture?

As for escaping braces would this work?
  • {{ = literal { when outside hole
  • { = open brace
  • \} = literal in the format specifier when inside hole
  • } = close brace when inside hole, illegal when outside hole (just for parity with the opening brace).
  • }} = literal } when outside hole. Could be simple }, just for parity with the opening brace.
Therefore "{{{6216:D}}}" would output "{6216}" and "{{{6216:D\}}}}" would output "{D}}".
This would make it more in line with String.Format for escaping braces and at the same time make it explicit that I want } as part of the format specifier.
Oct 22, 2014 at 1:51 PM
Perhaps the resource file usage could/should be considered a major usage for a super fast emit mechanism in a future version.

Although an extension of resources might also work. The goal (it would seem) would be adding names to the numeric holes, and then confirming that the usage in an analyzer, similar to SFD. This feels like just another column in the resource view/item in the XML (as Halo Four suggested).

I do think this is a problem worth solving. In many ways it's more important in resources, for the obvious reason that the position of the items is different in different languages.
Developer
Oct 22, 2014 at 2:52 PM
KathleenDollard wrote:
Perhaps the resource file usage could/should be considered a major usage for a super fast emit mechanism in a future version.

Although an extension of resources might also work. The goal (it would seem) would be adding names to the numeric holes, and then confirming that the usage in an analyzer, similar to SFD. This feels like just another column in the resource view/item in the XML (as Halo Four suggested).

I do think this is a problem worth solving. In many ways it's more important in resources, for the obvious reason that the position of the items is different in different languages.
The language doesn't know anything about resources today, so that would be a large change. Too large for the remaining time.
Oct 24, 2014 at 6:26 PM
And now for something completely different.

Obviously there has already been a lot of discussion about this issue and a lot of different opinions. Recently I sat down to write a string interpolation provider for string.format and I came up with a different take than what I see here. For what I needed, I had to be able to treat the format as a simple string that I could pull from a database, or store in a resource.

The formatter that I came up with uses formats like {0:FullName} and {1:BirthDate:D} to insert properties, fields, or dictionary values into the string. I am more comfortable with the idea of passing the variables as arguments than the idea of putting the variable name directly into the format.
string.Format(new InterpolationFormatProvider(),"{0:FullName} was born on {1:BirthDate:D}", person, personalInfo);
Anonymous types can also be used to give you a lot of control over the named values as in,
string.Format(new InterpolationFormatProvider(),"{0:FullName} was born on {0:BirthDate:D}", new { FullName = "John Schmoe", BirthDate = new Date(1970,7,7) });
My blog post is at http://coding.grax.com/2014/10/string-templating-with-interpolation.html, my code is on GitHub and there is a NuGet package.

I don't have anything to push here (I don't care if you use my program), it is just that this format makes more sense to me than what I see here now.
Oct 24, 2014 at 7:23 PM
This type of solution has been proposed before and there are a few implementations around. The problem with it is that it relies on reflection which will impact performance, and that it offers no compile-time validation of either the indexes or the requested properties. The latter issue could be resolved through code analysis, but otherwise you still run the risk of a run time error.

I'm not a huge fan of interpolation myself. It seems to encourage what would generally be considered anti-patterns. I'd much rather see better support in Visual Studio for defining resources that accept parameters. But string interpolation is becoming more common of a programming feature and I recognize that the vast majority of software written is never intended to be internationalized.
Oct 24, 2014 at 8:38 PM
I guess that's a big part of the issue. The way I like it is divorced from the actual variables, which makes it hard/impossible to validate the properties against a specific type, especially if the format string isn't even a part of the code at compile time.

It seems to me that you're either (virtually) creating a method that expects specific types when you compile a formatted string or like I'm doing, you are creating a fairly free-form format that isn't tied to the code and subject to refactoring problems.

Incidentally, I handled the performance issue by building and compiling expressions and storing them in a static dictionary based on their type. After the first one, performance seems pretty comparable with the current string.Format

In my test, the currently available format below took 3 seconds to format 1 million times.
string.Format("My name is {0} and my date is {1:D}", person.FirstName, person.BirthDate);
and with my provider, the following took about 4 seconds to format 1 million times.
var result4 = string.Format(provider, "My name is {0:FirstName} and my date is {0:BirthDate}", person.FirstName, person.BirthDate);
Oct 27, 2014 at 11:38 AM
Edited Oct 27, 2014 at 11:39 AM
What about use Razor Like Syntax ? to avoid compatibility issues you can use a new String Marker or like you suggest $""

Using Razor will unify experience and code across all .Net technologies

Here is the uservoice suggestion to vote if you think it worth considering

Add new string literal that contains Razor code (for example between «»)

http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/5903196-add-new-string-literal-that-contains-razor-code-f

Thanks
Nov 20, 2014 at 1:42 PM
Hi,

Wouldnt' be very nice if insteand of just IFormattable to have also an IFormattableEx :) that receives the Linq.Expression instances corresponding to string interpolation args.

So:
    Dsl.Run($"select \{o.Name} from \{o} ") 
will translate to
    Expression<Func<string>> e1 = ()=>o.Name;
    Expression<Func<MyObject>> e2 = ()=>o;
    Dsl.Run(IFormattable.Ex("select \{0} from \{1} ",new[]{ (Expression)e1, (Expression)e2 } ); 
This might help embed some custom DSLs that are easy to evaluate.
MyCustomLinqDslProvider.Run($" select \{o.Name}, sum( \{o.Amount}) from \{o}  where \{o.Created.Date == DateTime.Now} group by \{o.Name} having sum( \{o.Amount} ) > 100 ")
This linq alternative is the simpler to evaluate than writing a fully fledged linq provider...

the validation of the dsl may be done with a custom diagnostic.

The feature must seem esoteric but it may add some extra coolness to the language.
Developer
Nov 20, 2014 at 3:18 PM
ursuletzu wrote:
Wouldnt' be very nice if insteand of just IFormattable to have also an IFormattableEx :) that receives the Linq.Expression instances corresponding to string interpolation args.
I'm adding accessors for the format string and argument array to FormattedString. That will enable you to do that in an API based on the current design. Just have the Ex method receive FormattedString as its argument type.
Nov 21, 2014 at 12:40 AM
nmgafter wrote:
ursuletzu wrote:
Wouldnt' be very nice if insteand of just IFormattable to have also an IFormattableEx :) that receives the Linq.Expression instances corresponding to string interpolation args.
I'm adding accessors for the format string and argument array to FormattedString. That will enable you to do that in an API based on the current design. Just have the Ex method receive FormattedString as its argument type.
I assume that the format string is the composite formatting string with indexes where the holes should be? Is the Args array a object[] of the values passed in or would they be already formatted to string fragments?
FormattedString fs = $"Hello \{person.Name}, you were born on \{person.DateOfBirth:D}.";
string s = fs.FormatString;
object[] args = fs.Args;

Debug.Assert(s == "Hello {0}, you were born on {1:D}.");
Debug.Assert(args.Length == 2);
Debug.Assert(args[0] == person.Name);
Debug.Assert(args[1] == person.DateOfBirth);
Nov 21, 2014 at 9:29 AM
Edited Nov 21, 2014 at 9:29 AM
Is this available in VS 2015 preview?

I cannot find the type FormattedString
Nov 21, 2014 at 9:58 AM
ursuletzu wrote:
Is this available in VS 2015 preview?

I cannot find the type FormattedString
Not yet. The current preview still uses the old syntax ("Hello \{0}"), and doesn't implement the IFormattable feature
Nov 21, 2014 at 2:43 PM
On the master branch i did not find this type either. will it be defined in NET 4.6 core assemblies?
Nov 21, 2014 at 4:55 PM
Why not have FormattedString implicitly convertible to String?
Developer
Nov 21, 2014 at 8:34 PM
AdamSpeight2008 wrote:
Why not have FormattedString implicitly convertible to String?
Because then the following would be extremely inefficient because formatting would occur more than once.
var s = $"Hello, {name}";
Console.WriteLine(s); // calls String.Format
Console.WriteLine(s); // calls String.Format
Nov 21, 2014 at 10:16 PM
nmgafter wrote:
Because then the following would be extremely inefficient because formatting would occur more than once.
var s = $"Hello, {name}";
That reminds me of one of my wish-list items: a means by which a method's return type could specify that it should be "eagerly" converted to another type, such that FormattedString s =$"Hello, {name}"; would make s be a variable of type FormattedString, but var s=$"Hello, {name}"; would not. Otherwise, what would be the performance cost of using a class rather than a structure for FormattedString? Doing so would make it possible to have FormattedString cache its default string representation such that if it was only formatted using non-default options the default string representation would never have to be computed, but assigning the same FormattedString instance to multiple variables of type String could use the same constructed instance to satisfy all of them.
Developer
Nov 21, 2014 at 11:50 PM
supercat wrote:
Otherwise, what would be the performance cost of using a class rather than a structure for FormattedString?
An extra object allocation on every use of an interpolated string. Sounds pretty bad.
Nov 22, 2014 at 10:28 AM
Edited Nov 22, 2014 at 10:35 AM
nmgafter wrote:
AdamSpeight2008 wrote:
Why not have FormattedString implicitly convertible to String?
Because then the following would be extremely inefficient because formatting would occur more than once.
var s = $"Hello, {name}";
Console.WriteLine(s); // calls String.Format
Console.WriteLine(s); // calls String.Format
Not if it is, internally cached on first creation.
Nov 22, 2014 at 7:12 PM
Edited Nov 22, 2014 at 7:12 PM
nmgafter wrote:
An extra object allocation on every use of an interpolated string. Sounds pretty bad.
I would expect that something like $"The coordinates are ({X},{Y},{Z})" would at minimum require the creation of four new String objects [one each for the string representations of X, Y, Z, and one for the result] as well as at least one additional object (since the only overload of Concat which can handle more than four strings accepts an IEnumerable<T>, and that must almost certainly use either a StringBuilder or equivalent, or else use a heap-based collection to store the strings generated by the enumeration). Adding one more temporary heap object to the mix doesn't seem that bad to me.

If each thread had an thread-static instance of StringBuilder associated with it, and the virtual render-to-string methods had included a means of appending data to that rather than returning a new string instance, then a typical string interpolation would only require the creation of one heap object--the final result string--and the relative cost of allocating a second object would be much greater [note the key role of the thread-static StringBuilder; if a piece of code to build an interpolated string had to generate its own StringBuilder instance, that would require two additional allocations every time that code executed, while using a thread-static instance would require zero.]

Also, I just wrote up another concept (limited return-type overloading) that might be applicable here.
Dec 10, 2014 at 9:29 PM
Would this be a valid interpolated string? ``` $"X := {0}", if so what do it map to.
Dec 10, 2014 at 9:35 PM
AdamSpeight2008 wrote:
Would this be a valid interpolated string? ``` $"X := {0}", if so what do it map to.
I don't see why not; 0 is a valid expression, which evaluates to 0... so the result would be "X := 0".
Dec 11, 2014 at 2:24 PM
@tom103
So it be equivalent to String("X:= {0}",0)
Dec 11, 2014 at 2:39 PM
Edited Dec 11, 2014 at 2:40 PM
AdamSpeight2008 wrote:
@tom103
So it be equivalent to String("X:= {0}",0)
I assume you meant String.Format("X:= {0}", 0), but yes, that's the equivalent.

If you wanted the interpolated string to also contain open holes for use with a call to String.Format later you'd have to escape them: $"X:= \{0\}"

A warning diagnostic might be useful if the expression in the hole is found to be an integer literal.
Developer
Dec 11, 2014 at 3:42 PM
Halo_Four wrote:
If you wanted the interpolated string to also contain open holes for use with a call to String.Format later you'd have to escape them: $"X:= \{0\}"
That should be $"X:= {{0}}"
Dec 11, 2014 at 9:08 PM
nmgafter wrote:
Halo_Four wrote:
If you wanted the interpolated string to also contain open holes for use with a call to String.Format later you'd have to escape them: $"X:= \{0\}"
That should be $"X:= {{0}}"
Er? I thought it was going to be: $"X:= \{0\}" and $@"X:={{0}}. That's what the first post in this thread specifies and I haven't seen anything newer and definitive, but at this point it's impossible to keep this straight.
Developer
Dec 11, 2014 at 10:24 PM
Halo_Four wrote:
Er? I thought it was going to be: $"X:= \{0\}" and $@"X:={{0}}. That's what the first post in this thread specifies and I haven't seen anything newer and definitive, but at this point it's impossible to keep this straight.
I'm here to tell you that escaping them will be by doubling in both forms. I have not updated the spec, and I prefer to get the implementation done (rather than spending time on the spec right now) so I can be sure you can test it in the next CTP.
Dec 12, 2014 at 12:07 AM
nmgafter wrote:
Halo_Four wrote:
Er? I thought it was going to be: $"X:= \{0\}" and $@"X:={{0}}. That's what the first post in this thread specifies and I haven't seen anything newer and definitive, but at this point it's impossible to keep this straight.
I'm here to tell you that escaping them will be by doubling in both forms. I have not updated the spec, and I prefer to get the implementation done (rather than spending time on the spec right now) so I can be sure you can test it in the next CTP.
No problem. Either way all I intended to convey was that AdamSpeight2008's example did effectively amount to interpolating an int literal and that the curly braces would require escaping of whatever form.

Any thoughts about my comment about the warning if attempting to interpolate a literal integer like that? Might be useful in catching unexpected interpolations if a developer was combining interpolation with runtime composite formatting.

Either way, thanks for all of the hard work.
Dec 12, 2014 at 7:29 AM
When you up the spec would you mine you include an example of the roslyn object that is return f
var _int_ = 12;
var _string_ = "Some Text";
var _double_ = 12.345

var IString = $"Int:= \{_int_} string := \{_string_) _double_ := \{_double_} "
Let's say the text cursor is inside to the right of the " on the _IString_ line.
For example (note free form syntax)
 .InterpolatedString
  .Span : TextSpan
  .Args :  InterpolatedStringArgs
    .Arg(0)
       .InterpolatedStringArg
          .Span : TextSpan
          .ContainedExpression : Expression  ( Variable<integer> )
    .Arg(1)
       .InterpolatedStringArg
          .Span : TextSpan
          .ContainedExpression : Expression ( Variable<String>)
    .Arg(2)
       .InterpolatedStringArg
          .Span : TextSpan
          .ContainedExpression : Expression (Variable<Double>)
Just give a sense of what to expect, as well being used as learning material
Dec 19, 2014 at 9:49 AM
Edited Dec 19, 2014 at 9:51 AM
nmgafter wrote:
ursuletzu wrote:
Wouldnt' be very nice if insteand of just IFormattable to have also an IFormattableEx :) that receives the Linq.Expression instances corresponding to string interpolation args.
I'm adding accessors for the format string and argument array to FormattedString. That will enable you to do that in an API based on the current design. Just have the Ex method receive FormattedString as its argument type.
That's great news!

Perhaps in a future version that could be extended to allow a more structured representation so that the DSL implementation can avoid runtime overhead in re-parsing the format string, and perhaps even get type-checking for free.

For example, given a method void Method(DslFormatter formatString) and a format string MyMethod($"some string {myvariable:format} here, {a * b}!") you might imagine that the expression translates to
MyMethod(
    DslFormatter.FormatStringFactory()
        .AppendString("some string ")
        .AppendValue(myvariable, "format")
        .AppendString(" here, ")
        .AppendValue(a * b)
        .AppendString("!")
        .Finish()
    )
The advantage of that kind of translation is that it
  • isn't tied to some currently defined type, the library authors get full flexibility
  • can be much more efficient since the runtime dsl need not re-parse the format string (this also counts for the best known "DSL" equivalent to string.Format)
  • can avoid boxing values since AppendValue can be overloaded
  • can avoid memory allocation entirely since there's no params object array, and FormatStringFactory() can return a value type.
  • can introduce additional compile-time checks via the type system since AppendValue need not accept object, and since DslFormatter.FormatStringFactory() doesn't need to have the same type as DslFormatter.FormatStringFactory().AppendString("") there can even be some compile time structure enfored. For example, a DSL could enforce having exactly three expressions.
But for now, this looks great - I can't wait to get my hands on it and use it to write a DSL. For example, an SQL-injection safe parameterized query builder might be quite nice...
Dec 30, 2014 at 4:06 AM
Updated my references from the myGet repository and now all my interpolated strings are throwing an exception:
Error   CS1009  Unrecognized escape sequence    Project.ASP.NET 5.0 AccountController.cs    34
Here's my code:
var redirectUri = "\{var1}://\{var2}\{Url.Action("action")}";
Jan 6, 2015 at 6:13 PM
ninety7 wrote:
Updated my references from the myGet repository and now all my interpolated strings are throwing an exception:
Error   CS1009  Unrecognized escape sequence    Project.ASP.NET 5.0 AccountController.cs    34
Here's my code:
var redirectUri = "\{var1}://\{var2}\{Url.Action("action")}";
That's because it should be:
var redirectUri = $"{var1}://{var2}{Url.Action("action")}";
Assuming I'm reading the changes correctly.
Jan 7, 2015 at 3:01 AM
Nope, now it shows
    Error   CS1056  Unexpected character '$'
Jan 13, 2015 at 11:05 PM
Same here. I get CS1056 errors whenever I try to use string interpolation.

Microsoft Visual Studio Ultimate 2015 Preview
Version 14.0.22310.1 DP
Jan 21, 2015 at 10:54 AM
Same. Note that running a kpm build of the same project with both beta1 and beta2 KRE's yields normal build output. Only VS errors, regardless of build target.
Feb 24, 2015 at 6:57 AM
Edited Feb 24, 2015 at 7:25 AM
What is the status of the syntax for the string interpolation now (VS 2015 CTP 6, FW 4.6 Preview) ?
Both the "\{var1}" and the $"{var1}" syntaxes throw compiler errors.

Correction: The $"{var1}" syntax is supported by the compiler, but NOT by ReSharper 9 Update 1.
Feb 24, 2015 at 8:10 AM
@terje2000, the discussions have moved to https://github.com/dotnet/roslyn/notifications
Developer
Feb 25, 2015 at 4:26 AM
The Roslyn team no longer uses this site. Your comments are most welcome over at https://github.com/dotnet/roslyn