This is part of a series of posts covering new C# 6 features. Currently there are posts covering the following:
String Interpolation
Expression-bodied Members
Improved Overload resolution
The Null Conditional operator
Auto-Property Initializers
C#, like many programming languages, is quite incredible. One of the biggest reasons I think C# is amazing is not so much what it is today, which is still quite spectacular- but because of what it could be. C# is constantly being improved, revised, and new versions come out fairly frequently. this is not without it’s downsides, the primary one is that in order to develop and maintain something you will quickly find that your work is with “legacy” libraries and language versions.
I was originally planning to go over each new C# feature in a single blog post, but with that sort of format I didn’t think I really had much unique information to add on the topic, as we can easily find a lot of great posts and articles that cover the new C# features. Instead, I’ve opted to look into each one more thoroughly.
Just what is String Interpolation, anyway?
The idea of String Interpolation is actually somewhat foreign to most statically-typed languages. Instead, it is found primarily in dynamically typed languages such as Perl. the effective idea is straightforward- rather than strings being treated as is, they can be interpolated by the interpreter, compiler, or at run-time, and changed in some fashion. Typically, this is done by indicating, for example, replacement text or information that get’s interpolated as part of parsing the string or during run-time. The best way is with an Example. We’ll start with a Perl example:
1 2 3 |
my $name = 'BC_Programming'; my $time = "this evening"; print "Hello $name,\nhow are you $time?\n"; |
if we run this code, we get the output:
1 |
Hello BC_Programming, how are you this evening? |
The String Interpolation feature of Perl works automatically, and in that environment we can put any in-scope variable name in the string itself directly and have perl interpolate the string and replace it with the current value of that variable at the time of interpolation.
When it comes to C#, The concepts are similar. in general, the best way to think of it in a C# context is as a “shortcut” for the use of String.Format(). for example, an analogous C# program like look like this:
1 2 3 |
String name="BC_Programming"; String time = "this evening"; Console.WriteLine("Hello {0} how are you {1}",name,time); |
this is, of course, without String interpolation. WriteLine supports the “String.Format” syntax, which is similar in many ways to the C printf() function and it’s equivalents. With C# 6’s String interpolation, we can make it a bit easier to follow:
1 2 3 |
String name="BC_Programming"; String time = "this evening"; Console.WriteLine($"Hello {name} how are you {time}"); |
This makes it a bit easier to follow; you can see here that the interpolated parts of the string reference the names of in-scope variables. This is a better approach- generally- than the String.Format() style which uses braced numeric indices to reference the additional parameters provided to the function.
Somewhat disappointingly, this is typically about as far as many of the articles and blog posts covering the feature tend to go. this makes it seem like a straight-up String.Format syntax sugar, but they tend to fail to truly show how many sugars you get from the feature in your C# cup. The contents of the interpolated parts of the string can actually be any expression- you aren’t merely limited to listing variable names, you can even insert function calls. Take this example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
class Program { static void Main(string[] args) { Adder created = new Adder(); Console.WriteLine($"First call returns {created.Increment()}, the second call returns {created.Increment()}"); Console.ReadKey(); } } public class Adder { private int Count = 0; public int Increment() { return Count++; } } |
This gives us:
1 |
First call returns 0, the second call returns 1 |
This example interpolates two calls to the same method on the same instance. This shows us something else about string interpolation, which is that it appears elements are interpolated left to right (arguably, this is how we would tend to expect it). Since this function has a side-effect of incrementing (as the method name sort of gives away) a field variable, the second interpolation of the same method call returns a different result which is then reflected in the output. This is really still a String.Format syntax sugar, but the result tends to be a bit easier to follow. There is, arguably, one downside compared to String.Format, which is that you cannot store the format strings in a string variable or a resource. This is because, as mentioned, the feature is more or less syntax sugar for String.Format(), which means the actual interpolation really takes place at compile time- the resulting code has no “String Interpolation” as it is, and of course variable contents that are only available at run-time can’t be considered when compiling. This means that String.Format() will continue to be a valuable “ally” when it comes to variable replacement within resource-defined strings.
Come to think of it, one could almost make an argument that the String Interpolation feature is encouraging poor style, since String interpolation is not as easy to move into string resources as straightforward String.Format() calls. While this may be true, I think any feature can be misused and possible misapplications or poor style that may be encouraged by the overuse of a feature is not a reason to not provide that feature. You cannot fix bad programming with language features (or lack thereof) and I personally feel that language features should merely be considered tools to be used by the programmer themselves, not tools to enforce the preferred programming styles of those providing the toolbox.
Have something to say about this post? Comment!