Customizing String Interpolation – An Example

OVERVIEW

This blog is continuation of – ‘An Invitation From Scala String Interpolation‘. Here we will explore how to define a custom string interpolator.

OBJECTIVE

In this blog the custom interpolator being designed works exactly like the ‘s interpolator’ with an extra ability to write the “post interpolation content” into a file and finally returning the status message whether the file write was successful or not.

STEPS TO SUCCESS

Step 1 “Starting Up” ->

Create new sbt project in intellij.

Step 2 “Including required dependencies and plugins” ->

a). libraryDependencies += “org.scalatest” %% “scalatest” % “2.2.4” % “test”

It includes the scalatest jar to project which facilitates code testing(add in build.sbt).

Also following plugins were used in the project (add in plugins.sbt)

a). addSbtPlugin(“org.scoverage” % “sbt-scoverage” % “1.3.5”)

Used to see the code coverage by unit tests

b). addSbtPlugin(“org.scalastyle” %% “scalastyle-sbt-plugin” % “0.8.0”)

this plugin checks if any scalastyle warning is present or not.

Step 3 “Creating Desired Directory Structure” ->

The following image shows the directory structure of the project :

blog6Pic

In ‘main’, the ‘scala’ sub-folder contains the implementation for our custom string interpolator and the ‘test’ sub-folder contains the test cases to test our implementation, the ‘resources’ folder contains the file ‘output’ in which the output is written.

Step 4 “Defining custom string interpolator” ->

Since all the String Interpolation methods are present in ‘StringContext’ class, our goal is to write code to add a new method to ‘StringContext’ (in this new method, we define what our custom interpolator does). We will achieve it using an implicit value class. Using an implicit class provides a more convenient syntax for defining extension methods(since we need not explicitly declare the class objects), while value classes do the job of adding new functionality to a class along with removing the run time overhead. A good example is the RichInt class in the standard library.
At compile time, the string literal of the form :

id”something1 $something2 something3″

is transformed into following call using compile time reflection :-

new StringContext(“something1 “,” something3″).id(something2)

‘something1 ‘ and ‘ something3’ are refered as ‘parts'(i.e. the number of parts a string breaks in while making a call to a string interpolator) and ‘something2’ is refered as ‘args'(argument to the string interpolation method) in the example below.
Now to make our own interpolator we create a class that adds a new method to ‘StringContext’ class

In above code the ‘WriteScore’ class is a value class since it extends from Anyval and it is declared as implicit so we do not need to explicitly instantiate the class to use its methods. ‘write’ method is our custom interpolator, it is similar to the ‘s interpolator’ i.e. it first process the string using ‘treatEscapes’ method of ‘StringContext’ object, then embed the variable expressions to it(by appending the string buffer) and finally write the post interpolation content to a file using ‘writeToFile’ method which returns the status whether write was successful or not.

Whenever we need this custom interpolator, we make following import :

After the import, just use the interpolator kind of syntax to use the ‘write interpolator’. It is demonstrated in the test cases.

Step 5 “Testing” (The Climax) ->

Test cases implementing the ‘write interpolator’ are as follows :-

We firstly import the implicit ‘WriteScore’ class and then use the ‘write interpolator’ just like the other interpolators provided by ‘StringContext’ class. One thing to note is that since we are processing the string here, ‘/t’ will be treated as a tab.’File written successfully’ is the status message returned when write to the file is successful. The content is written in file :

src -> test -> scala -> resources -> output
Full code is available on git :- https://github.com/knoldus/string-interpolation-example

Comments are welcomed.

References ->

1) https://github.com/scoverage/sbt-scoverage

2) http://docs.scala-lang.org/overviews/core/string-interpolation.html

3) http://www.scala-lang.org/api/current/index.html#scala.StringContext

happy coding…


KNOLDUS-advt-sticker

Written by 

Sahil is a Software Consultant, with experience of more than 2.5 years. He is Microsoft certified c# developer. He has sound knowledge of different technologies which include C#, C, SQL, Scala, Play, ANTLR4, Docker, Ansible, jenkins, Python, DataDog, Promethous, Lightbend Telemetry etc. His hobbies include of cooking , watching anime and Partying with friends.

3 thoughts on “Customizing String Interpolation – An Example

  1. Hello Sahil,
    You can ignore the implicit declaration of class below, if they are useless,

    object StringInterpolation {

    implicit class WriteScore(val sc: StringContext) extends AnyVal {

    def write(args: Any*): String = {

    checkLengths(sc.parts.length, args.length)
    val strings = sc.parts.iterator

    And you need not to assign the value to variable message in last statement as below,

    val buf = new StringBuffer(treatEscapes(strings.next))
    while (strings.hasNext) {
    buf.append(expressions.next)
    buf.append(treatEscapes(strings.next))
    }
    val message: String = writeToFile(buf.toString)
    message
    }

    Because in scala result of last statement is automatically returned.

    1. answer to first question ->

      Using an implicit class provides a more convenient syntax for defining extension methods since we need not explicitly declare the WriteScore class objects (mentioned in blog). The call to :

      write”$name is $age years old\nand earns ₹ $salary”

      is transformed into(at compile time)

      new StringContext(“”, ” is “,” years old\nand earns ₹ “,””).write(name, age,salary)

      The implicit class is then used to rewrite it to the following:

      new WriteScore(new StringContext(“”, ” is “,” years old\nand earns ₹ “,””).write(name, age,salary))

      Now since the class is implicit the compiler implicitly create an instance of ‘WriteScore’ class at the compile time. (Generally a combo of implicit and any value class is used when we want to append functionalities provided by an already existing class)

      You may refer from the Scala documentation on String Interpolation for more information (my explanation is picked from the doc)

      answer to second question ->

      You are absolutely correct the value yielded by an expression in the last statement of a method is the return value of the method, well i just used the variable ‘message’ to show that the call to ‘writeToFile’ method returns a message denoting if write to the file was successfull or not. Though a comment would have been more efficient way to put the thing. :p

      Thank you very much for the Question, hope your issues are resolved 🙂

Leave a Reply

%d bloggers like this: