Final tips

The following sections enlist a few final tips and tricks that you might find handy while working with the REPL.

Copying and pasting in the REPL

As a reminder, this feature introduced in Chapter 8, Essential Properties of Modern Applications – Asynchrony and Concurrency, makes it easy to execute a full code snippet at once in the REPL. For instance, the following lines of command illustrate how the copy and paste feature in REPL helps the easy execution of code:

scala> :paste
// Entering paste mode (ctrl-D to finish)

[Copy a code block from somewhere with ctrl-C/ctrl-V]

  case class Person(name:String)

  val me = Person("Thomas")
  val you = Person("Current Reader")
  
  val we = List(you,me).map(_.name).reduceLeft(_+" & "+_)
  val status = s"$we have fun with Scala"
  
[Once you are done with pasting the code block, press ctrl-D]

// Exiting paste mode, now interpreting.

defined class Person
me: Person = Person(Thomas)
you: Person = Person(Current Reader)
we: String = Current Reader & Thomas
status: String = Current Reader & Thomas have fun with Scala

Timing code execution in the REPL

The REPL has been a very helpful tool throughout this book to discover and experiment with the various features of Scala. Together with the Scala worksheets introduced in Chapter 3, Understanding the Scala Ecosystem, they enhance our productivity by providing continuous feedback and make our development, therefore, more agile. Sometimes, it is convenient to measure the time it takes to execute statements or code snippets in the REPL. This is why we have given one way of achieving this.

First, we define a help function called using that takes two parameters, first a param argument of the type A and second, a function argument f that transforms the type of an argument from A into B:

scala> def using[A <: {def close(): Unit},B](param: A)(f: A=>B): B =
  try { f(param) } finally { param.close() }
using: [A <: AnyRef{def close(): Unit}, B](param: A)(f: A => B)B

What using does is to invoke the f(param) function, wrapping it into a try {} finally{} block. As the idea behind this function is to apply it on an I/O resource such as FileWriter or PrintWriter, we want to guarantee that we can close the resource no matter what. This is why you can see a param.close call in the finally block. That means the param argument cannot just be of any type A; it must have the additional requirement to have a close method. This is exactly what is declared at the beginning of the definition of the generic using method (that is, [A <: {def close(): Unit}, B]); the param argument should be a subtype of A that contains a method with the given signature.

In general, dealing with generic types is out of the scope of this book, and you don't need to really understand the previous definition to benefit from the using function. The example illustrates, however, how powerful the use of generic types in Scala can be. The type system of Scala is extremely powerful and the compiler will help you very much when writing generic code, unlike the use of generics in Java.

Let's now include the using function into an appendToFile function that will be responsible for logging the evaluation of the code we write in the REPL:

scala> def appendToFile(fileName:String, textData:String) =
  using (new java.io.FileWriter(fileName, true)){
    fileWriter => using (new java.io.PrintWriter(fileWriter)) {
      printWriter => printWriter.println(textData)
    }
  }
appendToFile: (fileName: String, textData: String)Unit

Finally, the following timeAndLogged function is declared to wrap a body snippet entered in the REPL with both the logging and timing functionalities:

scala> def timedAndLogged[T](body: => T): T = {
       val start = System.nanoTime
       try {
          val result = body
          appendToFile("/tmp/repl.log",result.toString)
          result
       }
       finally println(" "+(System.nanoTime - start) + " nanos elapsed. ")
}
timedAndLogged: [T](body: => T)T

Until Scala 2.10.0, you could use the :wrap method of the REPL power mode (accessible from the REPL via the > :power command) to be able to execute all the console statements without further involvement of the timedAndLogged function. The :wrap feature has recently been removed from the Scala release, so you will have to explicitly wrap the code that you want timing or logging for in the timedAndLogged method and therefore, do not need to involve the power mode of the REPL for that.

For instance, you can execute the following command:

scala> timedAndLogged{ val input = 2014 ; println(input) ; Thread.sleep(2000) ; input }

2014
 2004778000 nanos elapsed. 
res0: Int = 2014

The /tmp/repl.log file we specified in the timedAndLogged function should, of course, contain the logged result, that is, 2014.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.221.165.115