The Scala Chronicles: The Beginning

The Scala Chronicles: The Beginning

The Scala Chronicles: The Beginning

This is the beginning of a multi-part series on Scala. Starting with an introduction to usage of var and val followed by Control Structures. If you have some prior programming experience, you’d feel right at home. If not, I’ll try to introduce the concepts in a way that you’d understand.

Declaring “var”, or maybe not!

Scala allows one to declare variables mutable or immutable. Immutable objects cannot be modified after they are created. This is in contrast to a mutable object, which can be modified after it is created.

Scala has two kinds of variables, vals(Similar to a final variable in Java) and vars(Similar to a non-final variable in Java). Once initialized, a val can never be reassigned. A var, by contrast, can be reassigned throughout its lifetime.

Scala> var mutableObject = "This is a String 
mutableObject: String = This is a String 

Scala> mutableObject = "This is also a String" 
mutableObject: String = This is also a String

In Scala, you are encouraged to use a val unless you absolutely need to change the contents. Immutability is a good thing for many reasons. One of them is: If an object doesn’t change internal state, you don’t have to worry if some other part of your code is changing it. This becomes particulary important with multithreaded systems.

Simply put, using val is safer and leads to more readable code.

scala> val immutableObject = "Immutability is good" 
immutableObject: String = Immutability is good 

scala> immutableObject = "Changed value" 
<console>:12: error: reassignment to val 
  immutableObject = "Changed value"

If you try to reassign an immutable object, the Scala compiler will throw an error.

The All Knowing: Type Inference in Scala

The Scala compiler has the ability to figure out types you leave off. A local type inference mechanism takes care that the user is not required to annotate the program with redundant type information. Operations that break type constraints leads to compiler errors, not run time errors.

An Extra Cookie: When the Scala Interpreter(or compiler) can infer types, it is often best to let it do so rather than fill in the code with unnecessary, explicit type annotations.
You can, however, specify a type if you wish.

scala> val greetings: String = "Hello!" 
greetings: String = Hello!

Control Your Battles: Control Structures

One of the important aspects of programming is the ability to express logic in our programs. We want to be able to control the way our program executes, and that’s where control structures come in.

A control structure is a block of programming that analyses variables and selects how to proceed based on certain parameters. You will encounter a fundamental difference between Scala and other programming languages.

In Java or C++, we differentiate between expressions and statements.

Expressions: have a value and a type.

Statements: carry out an action.

Conditional Expressions

Scala has an if/else construct with the same syntax as in Java. However, an if/else has a value(Expression): The value of the expression that follows the if or else.

Scala’s if/else are similar to the ternary operator in Java{ (condition)?(result 1): (result 2) }. However, you can’t put statements inside it. But, the Scala if/else combines the if/else and ?: constructs that are separate in Java.

For Example: for some variable count with a value of 25, the following expression is perfectly legal.

scala> val str = if(x>25) "Get in, Have a drink" else "Sorry!" 
str: String = Get in, Have a drink

Every expression has a type, like in the example above, both branches of the construct have the type String. For a mixed expression, the type of expression would be the common supertype of both data-types.

scala> val 
x=27 x: Int = 27 

scala> if (x>25) "Get in, Have a drink!" else -1 
res2: Any = Get in, Have a drink!

The type of the this expression would be the common super type Any.

Loops

Scala has the same while and do-while loops as Java. Let’s start off with an example of while loop, followed by an example of a do-while loop.

While Loop

var n = 10 
/* 
  *Entry controlled loop. Condition checked first. 
  */ 
while(n>0) 
{ 
  println("In loop!") 
  n -= 1 
}

Do-While Loop

var n = 10 
/* 
  * Exit Controlled 
  */ 
do 
{ 
  println("In Loop") 
  n-=1 }while(n>0)

For Loop

Scala has no direct analogue of the for  construct that we are familiar with(How’s it going Java programmers?). If you need such a loop, you can use a for statement like this:

/* 
  *Similar to calling 1.to(10) with a step size of 1. for a step 
  *size of 2 specify the step size like: 1.to(10,2) 
  */ 
for ( i <- 1 to 10) 
{ 
  println(i) 
}

To emulate the less than operator(<), type in the following:

/* 
  *Equivalent to using the <= operator in looping. Also, you can 
  *specify the step size. 
  */ 
for( i <- 1 until 10) 
{ 
  println(i) 
}

Advanced For Loop(Comprehensions)

Comprehensions have the below form.

scala> val a = for(i<- 1 to 10 if(i%2)==0) yield i*2 
a: scala.collection.immutable.IndexedSeq[Int] = Vector(4, 8, 12, 16, 20)

The above for comprehension would result in a vector{ Vector(4,8,12,16,20) }. The <- is called a generator, the if construct is the guard condition{filter}, yield constructs a collection of values. This type of for loop is called a for comprehension

That’s it for this blog, then. Here’s hoping that you find this blog helpful. Please, comment below and let us know if the blog was helpful to you in any way or the topics that you’d want us to cover in the future.

Java and Scala: Why Should You Learn Scala?

Java and Scala: Why Should You Learn Scala?

Java is a general purpose object oriented language. Scala is less readable due to nested code. The process of compiling source code into byte code is slow. ... Scala treated everything as an instance of the class and it is more object oriented language as compare to Java.

There is admittedly some truth to the statement that “Scala is hard”, but the learning curve is well worth the investment. Some of the more complex features of the language (TuplesFunctionsMacros, to name a few) ultimately make it easier for the developer to write better code and increase performance by programming in Scala. Frankly, we are programmers, and if we’re not smart enough to learn a language that has some complexity, then we’re in the wrong business.

Scala is a type-safe JVM language that incorporates both object oriented and functional programming into an extremely concise, logical, and extraordinarily powerful language. Some may be surprised to know that Scala is not quite as new as they thought, having first been introduced in 2003. However, it is particularly within the past few years that Scala has begun to develop a significant following. Which begs the question of “Why Scala?”.

This article examines the advantages of Scala, especially versus Java (since Scala is written to run in the JVM). Scala is not the only attempt to create a “better Java”. Alternatives such as Kotlin and Ceylon have also gone down that path, but they made the fundamental decision to remain very close in syntax to the Java language itself, so as to minimize the learning curve. This may seem like a great idea, but it is ultimately somewhat self-defeating in that it forces you to stay within a number of those very same Java paradigms that were the reason for wanting to create a “better Java” in the first place.

In contrast, Scala was created specifically with the goal of being a better language, shedding those aspects of Java which it considered restrictive, overly tedious, or frustrating for the developer. As a result, there are indeed code distinctions and paradigm shifts that can make early learning of Scala programming a bit more difficult, but the result is a much cleaner and well organized language that is ultimately easier to use and increases productivity.

Java vs. Scala: Which is Really More Complex?

While the simplicity of the Java language has been part of its success, ironically, it has also contributed to its complexity. Sure, you can write nearly anything in Java, but the lines of code required to do so can be daunting. Programming in Scala, on the other hand, has a slightly more complex structure. But if you can write a slightly more complex single line of code that replaces 20 “simpler” lines of Java, which one is really more complex?

The truth is that Java is often just way too verbose. In Scala, the compiler is incredibly smart, so this avoids the developer needing to specify explicitly those things that the compiler can infer. Compare, for example, this simple “Hello World!” program in Java vs. Scala:

Hello World in Java:

public class HelloJava {
    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}

Hello World in Scala:

object HelloScala {
    def main(args: Array[String]): Unit = {
        println("Hello World!")
    }
}

While there’s not a huge distinction between the two languages here, Scala is less verbose even in this simple example.

For a more practical example, let’s take a look at creating a simple list of Strings:

Java:

List<String> list = new ArrayList<String>();
list.add("1");
list.add("2");
list.add("3");

Scala:

val list = List("1", "2", "3")

Certainly there are some tricks in Java to shorten the code a bit, but not in standard usage.

Now consider a case where we have a list of strings that are numbers, but we want to convert that list to a list of integers:

Java:

List<Integer> ints = new ArrayList<Integer>();
for (String s : list) {
    ints.add(Integer.parseInt(s));
}

Scala:

val ints = list.map(s => s.toInt)

Thanks to Scala’s functional properties, this conversion becomes extremely simple.

A Class Example: Java vs. Scala

Let’s take things a step further and compare standard bean / plain old Java object (POJO) creation in Java and Scala.

First, the Java version:

public class User {
    private String name;
    private List<Order> orders;
public User() {
    orders = new ArrayList&lt;Order&gt;();
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public List&lt;Order&gt; getOrders() {
    return orders;
}

public void setOrders(List&lt;Order&gt; orders) {
    this.orders = orders;
}

}

public class Order {
private int id;
private List<Product> products;

public Order() {
    products = new ArrayList&lt;Product&gt;();
}

public int getId() {
    return id;
}

public void setId(int id) {
    this.id = id;
}

public List&lt;Product&gt; getProducts() {
    return products;
}

public void setProducts(List&lt;Product&gt; products) {
    this.products = products;
}

}

public class Product {
private int id;
private String category;

public int getId() {
    return id;
}

public void setId(int id) {
    this.id = id;
}

public String getCategory() {
    return category;
}

public void setCategory(String category) {
    this.category = category;
}

}

Phew. Lotta code.

Now the Scala version:

class User {
var name: String = _
var orders: List[Order] = Nil
}

class Order {
var id: Int = _
var products: List[Product] = Nil
}

class Product {
var id: Int = _
var category: String = _
}

Which language did we say was more complicated?!

Are We Being Fair?

If you’ve made it this far, and are a Java programmer, you may at this point be thinking that I’m making an unfair comparison of code. After all, there’s nothing stopping me from making public variables in Java and then getting rid of the getters and setters.

However, if you think back to the reasoning behind getters and setters in Java, it is specifically for future-proofing. That is, if you later need to add some logic to either the getting or setting of variables you would have to re-write those public variables to use methods instead (which is why the use of getters and setters to begin with is encouraged in Java). However, in Scala programming this isn’t the case. Because of the language design, the abstraction remains intact without needing getters and setters. Consider, for example, this modified User class in Scala that throws a NullPointerException if you try to set the name to null:

class User {
private var _name: String = _
var orders: List[Order] = Nil
def name = name
def name
=(name: String) = {
if (name == null) {
throw new NullPointerException("User.name cannot be null!")
}
_name = name
}

And you can still set the name like this:

user.name = "John Doe"

Note that this entirely removes the need to pre-configure method accessors.

Moreover, since Scala prefers immutability, I can write this in Scala even more concisely with case classes:

case class User(name: String, orders: List[Order])
case class Order(id: Int, products: List[Product])
case class Product(id: Int, category: String)

Pretty crazy how much less code I have to write.

Taking the Example a bit Further

Now consider a scenario with the above classes where I want to add a nifty little method in the User class that returns a list of all Products that the User has ordered:

In the verbose world of Java:

public List<Product> getProducts() {
List<Product> products = new ArrayList<Product>();
for (Order order : orders) {
products.addAll(order.getProducts());
}
return products;
}

Fortunately, java.util.List has an addAll method, or getProducts() would have been an even longer in Java.

In Scala, on the other hand, all we need is:

def products = orders.flatMap(o => o.products)

You can see just how much smaller the Scala language implementation is. Yes, it may seem more complex to the Scala newbie, but once you actually fully understand the concepts behind it, the Scala code will look far more simplistic than the Java code.

Let’s get even a bit more complicated here. What if we want to only get the Products within a specific Category?

In this case we aren’t able to take advantage of the addAll method in java.util.List, so things get uglier in Java:

public List<Product> getProductsByCategory(String category) {
List<Product> products = new ArrayList<Product>();
for (Order order : orders) {
for (Product product : order.getProducts()) {
if (category.equals(product.getCategory())) {
products.add(product);
}
}
}
return products;
}

In Scala, however, the code remains fairly straightforward. We simply use flatMap to combine the products lists from each Order flattened in a single list, then we filter to only include the ones that match the category:

def productsByCategory(category: String) = orders.flatMap(o => o.products).filter(p => p.category == category)
Dynamic vs. static

There has certainly been no shortage of new languages over the past few years, but whereas nearly all the others that have recently emerged are dynamic, Scala is statically-typed.

As a professional developer – though I know and use many dynamic languages – it is my opinion that compile-time checks are incredibly important to write solid code. In a dynamic language, you can never be sure that your code is sufficiently bug-free and robust until you actually run it in a wide range of scenarios. This can lead to potentially serious defects in code that never get realized until the code is in production.

Wrap-up

Hopefully, this article stacks up Java vs. Scala enough to give you a preliminary sense of the power and capabilities of Scala and whets your appetite for learning the language. Not only is it a great language that can make programming less tedious and more enjoyable, but it’s also being used by some of the largest companies in the world (LinkedIn, Twitter, FourSquare, The Guardian, to name just a few).

The popularity and usage of Scala is rapidly on the rise, as evidenced by the ever-increasing number of open positions for Scala developers. If you haven’t already done so, now would be a good time to begin riding the wave and stop asking “Why learn Scala?”

Thanks For Visiting, Keep Visiting. If you liked this post, share it with all of your programming buddies!

Further reading

A Scala tutorial for Java developers

The Scala Chronicles: The Beginning. 


Originally published on toptal.com

What I Did Not Know About Scala And Its Standard Library

I am working with Scala as my main programming language for about three years now. I recently went through some basic&nbsp;<a href="https://www.scala-exercises.org/std_lib" target="_blank">Scala language exercises</a>&nbsp;for fun and discovered some features and possibilities I did not know about.

Introduction

I am working with Scala as my main programming language for about three years now. I recently went through some basic Scala language exercises for fun and discovered some features and possibilities I did not know about.

Some of the things I find really useful. Others I am not sure whether I like them. In this blog posts we will talk about

  1. Removing tuples from a map
  2. Never-ending traversables
  3. Partial function domains
  4. Different usages of back-ticks
  5. Infix types
  6. Extractors

Let's take a look at them one by one. I did not put them in a particular order, so feel free to skip one or browse through until you find something that interests you!

1. Removing Tuples from a Map

"Removing tuples from a map? Sounds easy, how come you didn't know how to do that?" I agree. Sounds easy. In Scala you remove elements from a map by key using the - method.

Map(1 -> "a", 2 -> "b") - 1 == Map(2 -> "b")

Now let's consider a map where the key is a pair.

Map((1, 2) -> "a", (2, 3) -> "b") - (1, 2) == Map((2, 3) -> "b")
error: type mismatch;
 found   : Int(1)
 required: (Int, Int)
       Map((1, 2) -> 2, (2, 3) -> 3) - (1, 2)
                                        ^
error: type mismatch;
 found   : Int(2)
 required: (Int, Int)
       Map((1, 2) -> 2, (2, 3) -> 3) - (1, 2)     
                                           ^

Whoops! What is going on? Turns out that there is not only one - method, but two:

def -(elem: A) = ???

def -(elem1: A, elem2: A, elems: A*) =
this - elem1 - elem2 -- elems

This method allows you to remove multiple keys at once, similar to --, but with varargs. To make our above example work, we need to add an extra pair of parenthesis.

Map((1, 2) -> "a", (2, 3) -> "b") - ((1, 2)) == Map((2, 3) -> "b")

I don't know why this method exists and why it is called - and not -- as it clearly removes multiple elements at once. But I am certain that it can lead to confusion when working with tuples as keys.

2. Never-Ending Traversables

In Scala, every collection is a Traversable. Traverables have different operations, e.g. to add them (++), to transform their elements (map, flatMap, collect), and so on. They also give you ways to get information about their size (isEmpty, nonEmpty, size).

When asking about the size of a traversable, you expect an answer that corresponds to the number of elements in the collection, right? List(1, 2, 3).size should be 3 as there are three elements in the list. But what about Stream.from(1).size? A stream is a traversable that might not have a definite size. Actually this method will never return. It will keep traversing forever.

Luckily there is a method called hasDefiniteSize which tells you whether it is safe to call size on your traversable, e.g. Stream.from(1).hasDefiniteSizewill return false. Keep in mind though that if this method returns true, the collection will certainly be finite, but the other way around is not guaranteed:

  • Stream.from(1, 2).take(5).hasDefiniteSize returns false, but
  • Stream.from(1).take(5).size is 5.

I did not use the built-in Stream type that often and if I did I was aware what was inside, not calling size if it would not be appropriate. But if you want to offer an API that accepts any Traversable, make sure to check if it has a definite size before attempting to traverse to the end.

3. Partial Function Domains

In functional programming you treat your program as a composition of mathematical functions. Functions are pure, side-effect free transformations from input to output.

However given the standard types available in most programming languages (e.g. integers, floats, lists, etc.) not every method is a function. If you are dividing two integers it is actually not defined if the divisor is 0.

Scala gives you a way to express this by using a PartialFunction, indicating that the function is not total (which mathematically speaking makes it not a function but just a relation, as a function needs to be total by definition). Note that Scala does not really tell you that methods like Int./ and List.head are partial functions.

You can define a PartialFunction either directly or using a case statement:

val devide2 = new PartialFunction[Int, Int] {
override def isDefinedAt(x: Int): Boolean = x != 0
override def apply(x: Int): Int = 2 / x
}

val divide5: PartialFunction[Int, Int] = { case i if i != 0 => 5 / i }

What I did not know before is that there is this isDefinedAt method which you need to use and check whether the function can be applied to your input argument.

devide2.isDefinedAt(3) == true
devide5.isDefinedAt(0) == false

How can we deal with the situation in which our function is not defined for the input?

  • First of all, try fixing your domain. If you are working with a list and you want to call head safely because you want to be sure to receive a non-empty list, accept only inputs of type non-empty lists. This relates very much to what I was discussing in my previous blog post about choosing the right data model to make invalid state impossible. Let the compiler work for you!
  • If you cannot fix your domain, you can try to fix your partial function. Instead of defining division as (Int, Int) -> Int, define it as (Int, Int) -> Option[Int] and return None in case the divisor is 0. Now you no longer have a partial function. In case of head you can use headOption instead.
  • If don't want to touch your partial function, you can combine it with other partial functions to cover the full domain. You can combine two partial functions using orElse. If the first partial function cannot be applied, Scala will attempt to use the second one.
4. Different Usages of Back-ticks

So far I utilized back-ticks only if I needed to use a reserved keyword as a variable name, e.g. when working with Java methods like Thread.yield. But there is another use case for it when working with case statements.

When pattern matching inside a case statement, cases starting with small letters are locally bound variable names. Cases starting with a capital letter are used to match the variable name directly.

val A = "a"
val b = "b"

"a" match {
case A => println("A")
case b => println("b")
}
// prints 'A'

"b" match {
case A => println("A")
case b => println("b")
}
// prints 'b'

"c" match {
case A => println("A")
case b => println("b")
}
// prints 'b'

In the examples above we can see that in the last example case b matches also "c", because b is a locally bound variable and not the val b defined before. If you want to match on val b you can either rename it to val B, or what I didn't know before, put it in back-ticks inside the case.

val A = "a"
val b = "b"

"b" match {
case A => println("A")
case b => println("b")
}
// prints 'b'

"c" match {
case A => println("A")
case b => println("b")
case _ => println("")
}
// prints '
'

5. Infix Types

In Scala, type parameters can be used to express parametric polymorphism, e.g. in generic classes. This provides a way of abstraction, allowing us to implement functionality once that will work on different input types.

If your class has multiple type parameters you can separate them with a comma. Let's say we want to implement a class holding a pair of arbitrary values.

case class Pair[A, B](a: A, b: B)

Now we can create new pairs like so:

val p: Pair[String, Int] = Pair("Frank", 28)

With infix type notation however, you can also write:

val p: String Pair Int = Pair("Frank", 28)

I know that Scala wants to be a scalable, flexible, and extensible language. But in my opinion, giving the developer too many ways to do or express the same thing can make it very hard to read other peoples' code.

If you are lucky, different styles mean that you have to get used to the style when looking at the source code of a new project. If you are not, then different ways of expressing the same thing are mixed within one project, making it hard to read and understand what is going on.

I see that there are use cases where the infix type notation comes in handy but it is also very easy to make the code completely unreadable. Who would think that String ==>> Double is the type of an immutable map of key/value pairs implemented as a balanced binary tree?

6. Extractors

In order to pattern match an object it needs to have an unapply method. Objects with this method are called extractor objects.

When you define a case class the compiler automatically generates an extractor object for you so you can utilize pattern matching. However, it also possible to define unapply directly:

object Person {
def apply(internalId: String, name: String) = s"$internalId/$name"

def unapply(idAndName: String): Option[String] =
idAndName.split("/").lastOption
}

val p = Person(java.util.UUID.randomUUID.toString, "Carl")
p match {
case Person("Carl") => println("Hi Carl!")
case _ => println("Who are you?")
}
// prints 'Hi Carl!'

So far so good. What I did not know is that also instances of classes can be used to extract:

class NameExtractor(prefix: String) {
def unapply(name: String): Option[String] =
if (name.startsWith(prefix)) Some(name) else None
}

val e = new NameExtractor("Alex")
"Alexa" match {
case e(name) => println(s"Hi $name!")
case _ => println("I prefer other names!")
}

This allows you to customize the extractor objects.

Conclusion

Going through the Scala exercises was a lot of fun and although I already knew most of the topics, it was exciting to discover some new things as well. I think that even if you consider yourself to be a senior, expert, guru, rock star or whatever, there are always things you do not know and it never hurts to revisit the basics from time to time.

What do you think about the things we discussed in this post? Do you think that the - method with varargs is useful? Have you ever tried to compute the size of an infinite traversable because you did not check whether it has a definite size? Were you aware that before calling a partial function you need to check whether it is actually defined? Do you use back-ticks frequently in your code? Have you ever defined your own type which was supposed to be used in infix notation? Or did you use types in infix notation without realizing it? Can you think of a real world use case for extractor classes instead of objects?

Let me know your thoughts in the comments below!

A Scala tutorial for Java developers

A Scala tutorial for Java developers

A Scala tutorial for Java developers

Introduction

I was asked to prepare a 30-min presentation about the Scala programminglanguage. The target audience is a community of experienced Java developers in our organization. Taking into account the time limit and the audience type, I will go straight to the business an I will cover the core Scala features.

So, Scala was first introduced in January 2004 by Martin Odersky, it is JVM based and statically typed programming language. Scala supports both object-oriented and functional programming paradigms. The most well-known products written in Scala are Apache Spark, Apache Kafka, Apache Flink. And finally, Scala scores pretty well in programming language popularity rankings (13)

Scala pros: what makes it great

Concise syntax

Scala is designed to be concise, many of Scala’s design decisions aimed to address the verbosity of Java. For example here is the code that defines new class ***UserInfo. ***This class has two properties. The first one is read-write property ***Name ***and the second one is **BirthDate **which is read-only.

Java code:

class UserInfo {
    private String name;
    private LocalDate birthDate;

    public UserInfo(String name, LocalDate birthDate) {
        this.name = name;
        this.birthDate = birthDate;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public LocalDate getBirthDate() {
        return birthDate;
    }
}

Scala code:

class UserInfo(var name: String, val birthDate: LocalDate)

Just a bit about syntax, in Scala variable name, comes first and then comes variables type. A var is a variable. It’s a mutable reference to a value. On the other hand, val is a value, an immutable reference. In this single line, you can see the expressiveness of Scala.

Case Classes

When it comes to comparing objects in Java, it compares references. For example, the following code will return false.

LocalDate date = LocalDate.now();
UserInfo a = new UserInfo("John", date);
UserInfo b = new UserInfo("John", date);
return (a == b);

But sometimes we would like to compare objects by underlying values and not by reference. So in Java, we have to implement **equals **and hashcodemethods. In Scala, we have **Case Classes. **Case Class automatically defines **equals, hashcode **methods and getters for constructor arguments. And most important it can be used in pattern matching. So by implementing UserInfo as a Case Class, we will get the following result:

case class UserInfo(var name: String, birthDate: LocalDate)
val date = LocalDate.now()
val a = new UserInfo("John", date)
val b = new UserInfo("John", date)
a == b // returns True

Pattern matching

Pattern matching is a mechanism for checking a value against a pattern. You can think about Scala’s pattern matching as a more powerful version of **switch statement **in Java. A match expression has a value, the <strong>match</strong>keyword, and at least one <strong>case</strong>clause. Example:

def matchTest(x: Int): String = x match {
  case 1 => "one"
  case 2 => "two"
  case _ => "many"
}

In Scala it is possible to perform pattern matching on types:

def matchOnType(x: Any): String = x match {
  case x: Int => s"$x is integer"
  case x: String => s"$x is string"
  case _ => "unknown type"
}
matchOnType(1) // returns 1 is integer
matchOnType("1") // returns 1 is string

Let’s see the more powerful case. Let’s match integers sequence

def matchList(x: List[Int]): String = x match {
  case List(_) => "a single element list"
  case List(_, _) => "a two elements list"
  case List(1, _*) => "a list starting with 1"
}
matchList(List(3)) // returns a single elements list matchList(List(0, 1)) // returns a two elements list
matchList(List(1, 0, 0)) // returns a list starting with 1

And finally, let’s see the most powerful case: a pattern matching on case classes.

case class UserInfo(var name: String, birthDate: LocalDate)
def isUserJohn(x: Any): Boolean = x match {
  case UserInfo("John", _) => true
  case _ => false
}
val list = List(
  "wrong user type",
  UserInfo("Ben", LocalDate.now()),
  UserInfo("John", LocalDate.now()))
list.filter(isUserJohn) // list with one element UserInfo John

Implicit Classes

The implicit keyword makes the class’s primary constructor available for implicit conversions when the class is in scope.

Assume that you were asked to extend UserInfo class with a getAge method. So there are two options. Create a separate library of UserInfo utility methods, like an ***UserInfoUtil ***class or to create a subclass which inherits all attributes and methods of UserInfo and extends it with ***getAge. ***In Scala, you can add your own behavior(s) by using implicit class.

object Extensions {
  implicit class UserInfoExt(user: UserInfo) {
    def getAge(): Int = {
      Years.yearsBetween(LocalDate.now(), user.birthDate,).getYears
    }
  }
}

This will let you write the code like this

import Extensions._
val user = new UserInfo("John", LocalDate.now())
user.getAge()

Higher-order functions

Scala allows the definition of higher-order functions. These are functions that take other functions as parameters, or whose result is a function. The classic examples of higher-order functions are map and filter.

**Map **applies a function on all elements of a collection. For example, let’s multiply by 2 each element of a given list

def multiply(x: Int): Int = x * 2

List(1, 2, 3).map(multiply) // returns 2 4 6 

**Filter **creates a list of elements for which a function returns true. Here is a short and concise example:

def isEven(x: Int): Boolean = x % 2 == 0
List(1, 2, 3).filter(isEven) // returns 2

Let’s define our own higher-order function:

def apply(f: Int => String, x: Int): String = f(x)
def printInt(x: Int): String = s"Printing integer $x"
apply(printInt, 3)

Option Monad

Monad is a design pattern that allows structuring programs generically while automating away boilerplate code needed by the program logic and provides an easy way for composing and sequencing operations on some contained value(s).

I would like to mention that I am not going to go deep to Monad’s theory. My only point is to show how Scala Option Monad can help to deal with ‘coping with errors’ problem that is very common in many languages. Consider the following code:

class Document {
  def getActivePage: Page = ???
}
class Page {
  def getSelectedText: String = ???
}

The goal is to implement getSelectedTextLength method which returns the length of selected text on the active page, otherwise, it returns 0. The simple approach is to implement it as follows:

def getSelectedTextLength(doc: Document): Int = {
  if(doc != null) {
    val page = doc.getActivePage
    if(page != null){
      val text = page.getSelectedText
      if(text != null){
        text.length
      }
      else 0
    }
    else 0
  }
  else 0
}

Such implementation is OK, but it has nested indentation, aka pyramid of doom. There is another way to implement it:

def getSelectedTextLength(doc: Document): Int = {
  if(doc == null)
    return 0

  val page = doc.getActivePage
  if(page == null)
    return 0

  val text = page.getSelectedText
  if(text == null)
    return 0

  text.length
}

It looks flat and clean but has if (x == null) return 0 a pattern which appears many times. We can simplify it by using exceptions:

def getSelectedTextLength(doc: Document): Int = {
  try {
    doc.getActivePage.getSelectedText.length
  }
  catch {
    case _: NullPointerException => 0
    case e: Exception => throw e
  }
}

This version looks good but has some problem though. If NullPointerExceptionis thrown from getActivePage or getSelectedText it will be unintentionally handled by our code and by doing so, our code will hide the potential bug.

In Scala it can be solved by using Option Monad. Option monad wrappes value of any given type and have two specific implementations: None when a value does not exist (null) or Some for the existing value, plus it defines flatMap operation which allows composing operations sequence together.

trait Option[A] {
  def flatMap[B](f: A => Option[B]): Option[B]
}

case class None[A]() extends Option[A] {
  def flatMap[B](f: A => Option[B]): Option[B] = new None
}

case class Some[A](a: A) extends Option[A] {
  def flatMap[B](f: A => Option[B]): Option[B] = {
    f(a)
  }
}

So by using Option monad, we can reimplement the code as follows

class Document {
  def getActivePage: Option[Page] = ???
}
class Page {
  def getSelectedText: Option[String] = ???
}

def getSelectedTextLength(doc: Option[Document]): Int = {
  doc
    .flatMap(_.getActivePage)
    .flatMap(_.getSelectedText)
    .map(_.length).getOrElse(0)
}

Summary

Scala isn’t perfect, it comes with its own limitation and drawbacks. It has a steep learning curve because its principles are based on mathematical type theory which is hard to master. When not maintained carefully, the Scala source code is hard to read and understand. Some big tech companies like LinkedIn, Twitter, Yammer reported that they are abandoning or decreasing their dependency on Scala.

On the other hand, Scala is flexible, productive and comes with a pretty rich toolbox. Compatibility with Java allows Scala developers to enjoy of rich Java ecosystem of libraries, frameworks, and tools. All these facts make Scala my language of choice when it comes to developing Big Data pipelines or high load server backends.