A very personal introduction to Scala Programming

Pavlo Melnyk
4 min readAug 15, 2023

--

Image to gently draw attention (source)

Recently I have got an urgent need to familiarize myself with Scala, in order to use Spark without proxy of PySpark. What sometimes could the best way to learn something? Right, to write an article about it! So here I am, learning Scala by writing an article, paying attention to details and thoroughly extracting the most important aspects of this programming language.

Someone could claim that if you already know PySpark, you don’t actually need to bother learning many aspects of coding in Scala as the majority of popular classes and methods are named in the same fashion, just learn how to define variables, import assets and voilà. Yes, it could be the case in many tasks, but it is wonderful to learn something new, and I have got just right amount motivation to begin.

Scala is a powerful and versatile programming language that seamlessly blends functional and object-oriented programming paradigms. In this article, we’ll take a dive into the world of Scala, exploring its key features and concepts through a series of code examples and their corresponding outputs.

Step 0: Embed Scala within Notebook in Google Colab

I am huge fan of Notebooks, unfortunately Google Colab doesn’t support Scala on default, so we need to go through some preparations in order to use it to execute Scala code. To run Scala in Jupyter Notebook we need to install Almond — a Scala kernel for Jupyter. The code below installs Almond kernel into the global Jupyter kernels.

%%shell
SCALA_VERSION=3.3.0 ALMOND_VERSION=0.3.0+16-548dc10f-SNAPSHOT
curl -Lo coursier https://git.io/coursier-cli
chmod +x coursier
./coursier bootstrap \
-r jitpack -r sonatype:snapshots \
-i user -I user:sh.almond:scala-kernel-api_$SCALA_VERSION:$ALMOND_VERSION \
sh.almond:scala-kernel_$SCALA_VERSION:$ALMOND_VERSION \
--sources --default=true \
-o almond-snapshot --embed-files=false
rm coursier
./almond-snapshot --install --global --force
rm almond-snapshot
%%shell
echo "{
\"language\" : \"scala\",
\"display_name\" : \"Scala\",
\"argv\" : [
\"bash\",
\"-c\",
\"env LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libpython3.6m.so:\$LD_PRELOAD java -jar /usr/local/share/jupyter/kernels/scala/launcher.jar --connection-file {connection_file}\"
]
}" > /usr/local/share/jupyter/kernels/scala/kernel.json

Once you have run this code please restart the kernel or terminate existing session of Colab and then start a new one.

The very first program in any languague in this cases is "Hello, World!". In my case I would like to amend this tradition a little and begin with "Hello, Scala!"

object HelloWorld {
def main(args: Array[String]): Unit = {
println("Hello, Scala!")
}
}

In this example, we define an object named HelloWorld with a main method, similar to Java. The println function is used to output the string “Hello, Scala!” to the console.

Variables and Data Types

Scala provides a robust type system, allowing you to define variables with explicit types or let the compiler infer them. Here’s an example:

val greeting: String = "Hello"
val age = 25
var x: Float = 3.14

In this code snippet, val declares an immutable variable. The String type annotation is optional, as Scala can infer the type from the assigned value. The variable age is assigned an integer value without explicitly mentioning the type. The mutable variables are declared with var key.

Functions and Expressions

Scala makes it easy to create functions and work with expressions. Let’s define a function to calculate the square of a number:

def square(x: Int): Int = {
x * x
}

You can also use concise one-liners for simple functions:

def cube(x: Int): Int = x * x * x

Calling these functions produces the following outputs:

println(square(3)) // Output: 9
println(cube(2)) // Output: 8

Pattern Matching

Pattern matching is a powerful feature in Scala that allows you to structure and match values against patterns. Consider a simple example of pattern matching on a list:

val numbers = List(1, 2, 3, 4, 5)

numbers.foreach {
case even if even % 2 == 0 => println(s"$even is even")
case odd => println(s"$odd is odd")
}

The output will be:

1 is odd

2 is even

3 is odd

4 is even

5 is odd

Collections and Higher-Order Functions

Scala provides a rich set of collection classes and higher-order functions to work with data. Let’s explore an example using map and filter:

val numbers = List(1, 2, 3, 4, 5)

val squaredNumbers = numbers.map(square)
val evenNumbers = numbers.filter(_ % 2 == 0)

println(s"Squared numbers: $squaredNumbers") // Output: Squared numbers: List(1, 4, 9, 16, 25)
println(s"Even numbers: $evenNumbers") // Output: Even numbers: List(2, 4)

Object-Oriented Programming

class Person(name: String, age: Int) {
def greet(): Unit = {
println(s"Hello, my name is $name and I'm $age years old.")
}
}

val person1 = new Person("Alice", 30)
val person2 = new Person("Bob", 25)

person1.greet()
person2.greet()

The output will be:

Hello, my name is Alice and I'm 30 years old.

Hello, my name is Bob and I'm 25 years old.

Summary

Scala is a programming language that combines functional and object-oriented programming paradigms, allowing developers to write concise and expressive code. In this article, I’ve shortly covered a variety of Scala features and concepts, from basic syntax to advanced pattern matching and higher-order functions along with its usage within Google Colab.

Armed with this introduction, you’re well-equipped to dive deeper into Scala and explore its full potential in building robust and scalable applications.

Happy Scaling! ;)

--

--

Pavlo Melnyk

I'm a data engineer with a passion for building scalable and robust data pipelines.