What Is Scala and When Should We Use It?

Learn about the pros and cons of the Scala language.

What is Scala?

Scala is short for “scalable language.” It’s a programming language specifically designed to grow with the demands of the programmers using it. The meaning of “scalable” here is twofold. On one hand, the syntax can scale to model different domain-specific languages (DSLs) suitable for various tasks. In addition, Scala scales down for small tasks and scripts and scales up when we employ it for large software projects.

The legend goes that Scala’s logo resembles a spiral staircase at the École Polytechnique Fédérale de Lausanne (EPFL), where Martin Odersky started his work on the program. The etymology of Scala can also be traced to the Latin word scāla, meaning “ladder” or “staircase.”

Although we can use Scala to write small scripts, it unleashes its full power when employed to develop large systems or reusable components. Technically speaking, Scala blends the object-oriented and functional programming paradigms in a statically typed language.

The three programming paradigms supported by Scala
The three programming paradigms supported by Scala

The functional paradigm in Scala comes in handy when writing small, reusable components and composing them from the ground up. The object-oriented paradigm helps us design large systems that are easily extendable. The two paradigms have many other strengths that have proven very useful when writing complex applications.

  • Object-oriented programming (OOP): Objects give us a great recipe to organize our code, letting us put data and functions in the same place. With objects we can decide where to put our data and which operations to allow. Thanks to its diffusion, OOP is now taught in schools and used by developers around the world. It’s so widespread that a large number of patterns have been theorized (and put into practice) to solve common design issues and mistakes. In Scala everything is an object. This allows us to structure very clean code. Additionally, thanks to the expressiveness of the language, we can choose from a variety of constructs to design our architecture. For example, the case classes in Scala let us define simple containers that are immutable by default and suitable to hold data with few to no methods manipulating it.

  • Functional programming: Based on lambda calculus, the functional programming paradigm has two fundamental pillars. First, functions are first-class citizens that can be passed in as method arguments, returned as return values, and defined inside other functions. Second, they’re functions in the mathematical sense; rather than mutating data (i.e., having side effects), they communicate with the enclosing world only by means of their input and output. This makes it easier to define immutable data structures that are easier to understand, especially when it comes to writing concurrent and distributed programs.

We can also write imperative code in Scala. This is often considered wrong, but functional code isn’t always the way to go. Sometimes imperative programming is just clearer and more readable. In these cases, it’s helpful to use a language in which seamless functional and imperative programming exist in cooperation. For example, in Scala, we can write a class that behaves like a function but whose internal implementation is completely imperative. Scala lets us find our coding style, leveraging all three major programming paradigms.

Pros of Scala

The fusion of imperative, object-oriented, and functional programming is not Scala’s only strong point. The sections below show a few reasons why Scala programmers are often enthusiastic about the language.

Compatibility with Java

Scala programs compile to Java Virtual Machine (JVM) bytecodes with a runtime performance similar to Java-based programs. We can easily use Java libraries in a Scala codebase. This is very important since Java has more libraries than Scala does. Furthermore, we can use Java collections when writing Scala code simply by importing conversion methods. This gives us full interoperability.

// scala.jdk.CollectionConverters.* from Scala 2.13 onwards
import collection.JavaConverters._
import collection.mutable._
object Main extends App {
val jul: java.util.List[Int] = Seq(1, 2, 3).asJava
val buf: Seq[Int] = jul.asScala
println(jul)
println(buf)
}

Additionally, Scala reuses Java types, such as String, Int, and Boolean. More importantly, it defines built-in wrappers of these types to enrich them with functionality not available in Java. Without going too deep into the details, the Scala compiler does this by relying heavily on implicit conversions.

object RichIntImplicits {
implicit class SimpleRichInt(value: Int) {
val incremented: Int = value + 1
}
}
object Main extends App {
import RichIntImplicits.SimpleRichInt
println(1.incremented)
}

Concise syntax

Scala programs are usually much shorter than those in Java. This is mainly because the Scala compiler is more powerful and can infer more information about our intentions.

Java code

class Person {
    private String firstName;
    private String lastName;

    public Person(String name, String surname) {
        firstName = name;
        lastName = surname;
    }
}

Scala code

class Person(String firstName, String lastname)

As you can see, the code in Scala is much more readable. This is because the Scala compiler is more powerful than Java’s, generating many things for us. In Java we have to write everything explicitly.

Boilerplate aside, Scala code tends to be much more declarative. Once you’re accustomed to the coding style, programs written in Scala are usually easier to understand. However, even if the language lets us write very short snippets of code, it’s important to prioritize clarity over conciseness to avoid ending up with cryptic one-liners that no one understands.

Type system

The Scala compiler assigns a type to every value or expression, and that type never changes during the execution of the program. On the other end of the spectrum, we have dynamic type systems, which compute the type of the values at runtime. Historically, many programmers have preferred dynamically typed over statically typed languages. The main reason is that static type systems are often considered too verbose and inflexible.

While this is true for some languages, Scala stands out. The compiler can infer the types at stake most of the time, making the code much less verbose. Additionally, pattern matching and type composition make the type system flexible enough to write concise yet expressive and readable code.

Scala 3

In the past 20 years, Scala has evolved to eliminate frustrating edge cases and counterintuitive features. The most recent evolution is Scala 3, a complete overhaul of the language that changes many aspects of the type system. Furthermore, Scala 3 has simplified the syntax to reduce the boilerplate code even more, as we can see in the following comparison:

object Main extends App {
  // main code of the application here
}
@main def main() = 
  // main code of the application here

In this course, we’ll mainly use Scala 3 syntax and features. Here are some of the new syntax simplifications:

  • There’s no need to use new to instantiate classes.

  • The @main annotation can be used to specify the main method.

  • Scopes can be defined using indentation (similar to Python and Haskell) instead of curly brackets.

Even though it has many advantages over Java, Scala is not a perfect language. For example, it still needs a virtual machine to run, with all the related pros and cons (type erasure in generics, garbage collection, need for just-in-time compilation, and so on). Furthermore, the richness of the type system makes Scala a language with a steeper learning curve and many caveats.

In this lesson, we take a brief look at the most important pros and cons of Scala to try to answer the question “When and why should we use it?”

Pros and cons of Scala
Pros and cons of Scala

Generally speaking, we can use Scala when we want to write modular software, leveraging all the help (and property checking) the compiler can give. It’s not always about the size of the application; we can write small programs or even scripts using Scala. The main point is to use it when we want to structure the code in small modules, composing them from the ground up to build a full-fledged application.

Because it’s functional, Scala has many features aimed at simplifying the way we think about our code. It’s almost like math, where we usually define small functions and use them to build complex formulas. In Scala we can write small components and then compose them to build complex applications. Scala’s functional programming capabilities allow developers to write code that is concise, expressive, and easy to understand.