Scala Tutorials Part #11 - String Interpolation

String Interpolation

In this part we are going to see a pretty nifty feature of scala called String interpolation.

This is part 11 of the scala tutorial series. Check here for the full series.

Index

There is no string interpolation/string variable substitution in java so to speak. Seasoned java programmers are used to string concatenation.

public class JavaRunner { public static void main ( String [] args ) { String name = "John" ; String weight = "154" ; String unit = "Pounds" ; System . out . println ( name + " weighs " + weight + " " + unit ); } }

This works as intended so what is so special with interpolation? Read on to find out more.

Let’s see how we do the same thing with string interpolation.

val name = "John" val weight = 154 val unit = "Pounds" //String concatenation println ( name + " weighs " + weight + " " + unit ) //Interpolation println ( s "$name weighs $weight $unit" )

Both the versions produce the same result, but the interpolation seems to be slightly better in terms of syntax when compared with concatenation.

Also there are lesser chances to make mistakes in the interpolated version.

The syntax that we encountered might be weird in the beginning but the s"" before the string is actually a method in StringContext.scala .

It goes as follows,

def s ( args : Any* ) : String = standardInterpolator ( treatEscapes , args )

which then again calls another method called standardInterpolator .

In scala there are three string interpolators,

The Standard interpolator (The one we just used)

Raw interpolator

Format interpolator

We will look at the other ones in sections below.

If we follow the code path, it ends up in the method called standardInterpolator which does a couple of steps to transform the given result into a complete string. One important point to note is that the entire process uses a StringBuilder underneath.

This is different in terms of performance with the traditional string concatenation which in the above example creates additional 3 strings including the space string. Of course we can code that string using a StringBuilder but the syntactic sugar is pretty nice.

The $ symbol is used to differentiate variables and strings.

We can combine arithmetic operations with interpolation as follows.

val name = "John" val weight = 154 val unit = "Pounds" val name2 = "Jack" val weight2 = 166 println ( s "$name2 weighs ${weight2 - weight} $unit more than $name " )

The operation needs to be inside ${} to work correctly, otherwise it would replace the variables but will not perform the minus operation. For example,

println ( s "$name2 weighs $weight2-$weight $unit more than $name " )

would just print Jack weighs 166-154 Pounds more than John , so the ${} is important.

Any arbitrary expression can be embedded inside ${} and it would just work.

Another thing to note is that string interpolation is typesafe, you can’t just include variables that don’t exist or perform any syntax errors inside of ${} .

The format interpolator is similar to the printf command in the C language.

val height = 1.9d val name = "James Sawyer" println ( f "$name%s is $height%2.2f meters tall" )

Here instead of s"" we use f"" as the prefix.

In the given example %s is used to denote a string and %f to denote double.

The 2.2f is used to denote precision i.e 2 decimals before the point and 2 after the point.

If our need is just printing to the console we can just use the printf method.

val height = 1.9d val name = "James Sawyer" //The format interpolator. Produces a string as an output println ( f "$name%s is $height%2.2f meters tall" ) //C Style abstraction over java PrintStream printf ( "%s is %2.2f meters tall" , name , height )

But in many cases we would want to use the formatted value as a string elsewhere. A good example is printing out values in logs. Without string interpolation we would have to rely on the logging library or use string concatenation.

Note that the f interpolator is type safe i.e something like below will throw an error.

The raw interpolator is pretty similar to the standard one, except that literals are not escaped within the string.

val height = 1.9d val name = "James Sawyer" //Tab is printed after $name is println ( s "$name is \t $height meters tall" ) // \t is just printed as a string println ( raw "$name is \t $height meters tall" )

It was not named just r"" cause that would cause confusion with regular expressions.

This is useful when we dont want to escape literals.

One can also use the standard interpolator and ignore literals as below,

println ( s "$name is \\t $height meters tall" )

It is a design decision that the developer can take. If there are only a handful of literals to be ignored then we can hard code them or else use the raw interpolator.

We can also write our own interpolator, but that is kind of advanced and not needed in most of the cases.

We can annotate the types for the variables we put inside the interpolator and it will throw an error during compile time.

In the above example, the second element in the list or any element in that matter is of Any type and not of the String type.

As mentioned in the string intepolation wiki, this concept of embedding variable references is not new to scala.

In fact very early languages such as bash and perl had this functionality.

This is a pretty neat feature considering that Scala was aimed to used for everything including scripting.

We will look at how to use scala for scripting in future articles.

Interpolation is commonly used across many frameworks/libraries in scala. In fact it is considered a de-facto standard instead of string concatenation.

On the whole this might not seem as a pretty big thing when compared to Java string concatenation, but it is small things like these that transform the entire language into a better one.

Stay tuned