The Scala programming language for TypeScript & Python developers in a nutshell

Niklas Klein
6 min readApr 1, 2023

--

The staircase at EPFL, the inspiration for Scala’s logo

Twitter’s recommendation algorithm has just been released, and to the surprise of many, it is largely written in Scala and Java. The reactions to it are varied: some are turned off by the first sight of the language, but many seem positively surprised.

Scala is a disruptive and innovative language and continues to have significant impact on the development of all modern languages, especially Java, Kotlin, Javascript/TypeScript and Python.

Scala 3 was released not too long ago and brought countless new goodies for the language. So in this post I want to walk through and highlight Scala’s most important and innovative features. Some of them might already be available in your language, others might make it in the next years (-;

Strong, statically-typed language

“TypeScript won”, and I’m so glad it did and showed the effectiveness of a strong type system to the big majority of developers out there. Much like TypeScript, Scala is statically typed, but feels dynamic, modern and lightweight thanks to type inference.

def wordCount(value: String) =
val words = value.split(' ').toList
val wordsWithCharacterCount = words.map(word => (word, word.length))
val totalWordsCount = words.length
(wordsWithCharacterCount, totalWordsCount)

In this example, the types are derived by the compiler. Of course, we are free to explicitly specify types where we deem necessary.

def wordCount(value: String): (List[(String, Int)], Int) =
val words: List[String] = value.split(' ').toList
val wordsWithCharacterCount: List[(String, Int)] =
words.map(word => (word, word.length))
val totalWordsCount: Int = words.length
(wordsWithCharacterCount, totalWordsCount)

Concise syntax

Now this is a sharp knife and much of the reason why Scala is sometimes perceived as unreadable and arcane. But the Twitter codebase does a nice job of showing how readable the language can be when you minimize the noise and focus on the important pieces of code.

Verbose and unnecessarily noisy:

(1 to 10).map(value => value * 2)

Just right:

(1 to 10).map(_ * 2)

The greatest power of Scala is its expressiveness. The greatest weakness of Scala is its expressiveness.

Expressions Expressions Expressions

This is probably the single most annoying thing I encounter when dealing with other languages, and hopefully also the biggest contender to be adopted by mainstream languages soon. In Scala, everything is an expression as opposed to statements. This means that every code block evaluates to a value.

val x: String = if value % 2 == 0 then "Even" else "Odd"

val y: String | Unit = if value % 2 == 0 then "Even"

val z: String | Unit = value match
case 0 => "Zero"
case 1 => "One"
case _ => ()

Scala does not have a ternary expression, since if/else can handle this use-case just as well. However, the language is powerful enough that you could define a ternary operator yourself.

Clean data modelling with products & sums

These are the two fundamental building block one needs to model the complexity of the world in data. Scala excels at data modelling, yet some mainstream languages still struggle to get this right (I’m looking at you, Java).

A product type is a collection of fields:

case class Pet(name: String, age: Int)

A sum type is a representation of one out of several types:

enum Animal:
case Bird(pet: Option[Pet], migrating: Boolean)
case Cat(pet: Pet, remainingLives: Int)
case Dog(pet: Pet, goodBoy: Boolean = true)

Pattern matching

Think of if/else on steroids: pattern matching is especially useful in combination with product & sum types.

val animal: Animal = Animal.Cat(
Pet(name = "Lenny", age = 3),
remainingLives = 6
)

val message = animal match
case Animal.Bird(Some(_), _) => "I'm a pet bird"
case Animal.Bird(None, true) => "I'm a wild bird, not staying for the cold"
case Animal.Cat(_, remainingLives) =>
s"I'm a cat, and I have $remainingLives tries left to get this right"
case Animal.Dog(_, true) => "HELLO YES, THIS IS DOG"
case Animal.Dog(_, false) =>
throw new IllegalArgumentException("Data corrupted?")

println(message)
> "I'm a cat, and I have 6 tries left to get this right"

Now, the sample above should hopefully be easily readable. However, there is an error. It misses a case for Animal.Bird(_, false), but the Scala compiler will catch that and protect you from runtime crashes.

match may not be exhaustive.

It would fail on pattern case: Animal.Bird(None, false)

Opaque types

A small goodie I decided to include into this list, because recently “Branded types” are all the rave in TypeScript land.

Scala comes with first class support for this concept, and it’s a great addition to your data modelling.

opaque type Name = String
object Name:
def from(value: String): Either[String, Name] =
if(value.isEmpty) Left("Required")
else if(value.length > 100) Left("Max 100 characters")
else Right(value)

extension (self: Name) def raw: String = self

val x: Either[String, Name] = Name.from("")
val y: Either[String, Name] = Name.from("Lenny")
val z: Either[String, Int] = Name.from("Lenny").map(_.raw.length)

The trick is that you can only rely on the Name == String property in the scope of object Name. For code that is not within this scope, the underlying type String is invisible. Only the builders and extensions that you care to define in the object can be used to interact with the type. This brings great compile-time safety at no runtime cost.

val x: Name = "Lenny"
Found: ("Lenny" : String)
Required: Name

JVM and beyond

The JVM (Java Virtual Machine) has a bad reputation for slow startup times and high memory consumption. And rightly so. It shines in long-running server applications and provides constant innovation in the field by pushing the boundaries of what is possible.

But that’s not the end of the story, and it doesn’t mean that Scala is limited to long-running backend applications. Quite the opposite, actually. There is a lot of fascinating development happening in this area, and we’re moving fast:

  • With Scala.js you can target the browser and node as runtime environments. Its been around for 10 years and is an incredible piece of technology. In my experience, my Scala code “just works” without friction.
  • With Scala Native you can compile Scala code to a native executable. The project is not as mature as Scala.js, but is shaping up nicely. It has strong competition, though.
  • With GraalVM Native Image you can compile any JVM application to a native executable, the ideal solution for short-lived applications without startup overhead, such as CLIs (command line interfaces) and cloud functions.

Ecosystem

The community is small, but the ecosystem is huge and vibrant. On the one hand, you have access to the entire world of Java libraries that Scala can consume seamlessly. On the other hand, there is an entire universe of Scala libraries, which are the preferred choice, as they feel more natural to use. And this is very subjective, but the quality of these libraries is incredible (especially with the Typelevel and ZIO ecosystems in mind). They are made with incredible attention to detail and are a marvel of open source development. I feel like standing on the shoulders of giants, as I write my application code on these rock solid foundations.

But that’s not all. With GraalVM Polyglot, you can even integrate JavaScript, Ruby or Python code quite nicely.

Concurrency powerhouse

Concurrency is hard, and a lot of developers hardly ever have to deal with it, which is a good thing. But to use compute resources efficiently, there is sometimes no other way around it. The JVM has strong support for concurrency and is just rolling out its virtual threads with “Project Loom” to take it to the next level. This makes the JVM a great deployment target for high throughput applications.

I struggled to write concurrent code in Java and avoided it like the plague, because it’s so difficult to get right. When I came to Scala and tried the functional programming Kool-Aid, this drastically changed. Suddenly, writing highly concurrent code became the go-to, because it’s just as easy as executing sequentially.

There’s so much more

This was just a quick overview over some aspects of Scala, that I care about. But there is so much more:

Scala has a fantastic REPL and online tool “Scastie” to play with the language. You should give it a try.

--

--