A week ago I finished reading of Scala for the Impatient by Cay Horstmann. Here are some lessons which I learned from this book.

1. Method parentheses

For warming up, here’s the first tip - it’s well known that you can omit using of parentheses for methods without parameters. But there is a rule in scala world: you can omit parentheses on methods which don’t mutate a state.

class State {
  private var value = 0

  def change(): Unit = {
    value = Random.nextInt()
  }

  def current = value
}

...

s.change() // With parentheses
s.current // Without parentheses

2. Traits vs abstract classes

Java 8 brings a new experience to interface usage - interface methods can have a default implementation. But scala eliminates the distinction even more (moreover, it works on JVM < 8): scala traits can have a default method implementation, abstract and defined values and variables. That’s why, in scala world, there is a rule: if you don’t know that to use traits or abstract classes - use traits, you’ll always be able to change them to abstract classes.

trait Car {
  val color: String

  def print() = {
    println(s"Car is ${color}")
  }
}
...
new Car {
  override val color: String = "red"
}.print()

Why is it good

  • You can use traits as mixins. You even can use it during object creation:
abstract class Car {
  def specs() = {
    print(s"Car with ${wheels} wheels")
  }

  def wheels: Int
}

trait FourWheel {
  def wheels = 4
}
...
(new Car with FourWheel).specs() // Output: Car with 4 wheels

Why is it bad

  • You can’t define constructor
  • Most features aren’t supported in java. So, you loose java interoperability
  • This approach has lesser performance

3. ProcessBuilder DSL

There is a nice feature ti execute external one or more external processes from scala code using very convinient DSL:

object CMDExample extends App {
  println("ls" !) //(1)
  println("ls" !!) //(2)
  println("ls" #| "grep gradle " !!) //(3)
}
  1. Executes ls within working directory and prints to stdout, then returns exit code.
  2. The save as 1. but returns command output as a string
  3. Equivalent of ls | grep gradle

4. Regex

Scala provides an easy way to work with java RegEx api. There’s a class and companion object which hold all this convenience - scala.util.matching.Regex.

To create an instance of Regex, you can use method r mixed to a string. It may looks like this: "\\d+".r. Then, you can work with it as follows:

Find matches

val regex = s"""<a\\s+href=\"([^\"]*?)\"\\s*>([^<]*?)</a>""".r
val regex(href, name) = "<a href=\"test.html\">test</a>"
println(href + ":" + name) // Output: test.html:test

For multiple matchings:

val text =
    s"""
       |<a href="index.html">index</a>
       |<a href="secondary.html">secondary</a>
   """.stripMargin

for(regex(href,_) <- regex.findAllIn(text)) {
    println(href)
}

Replace

println(regex.replaceAllIn(text, { m => m.group(2) }))

The output of this line will be a string where all a tags replaced with a content of those tags.

5. Structural type

Structural type is very interesting feature. It allows to define method argument of any type but with requirement of presence of specific methods. This is how it looks like:

def printInfo(obj: {def info: String}) = println(obj.info)

class A {
  def info: String = "A"
}

class B {
  def info: String = "B"
}

printInfo(new A)
printInfo(new B)