Hello! Welcome back to your accelerated training for the Senior Dataflow & Integration Engineer role.
In our first session, you successfully set up a professional Scala development environment using Helix and Metals. You're now equipped with the essential tooling.
This lesson builds directly on that foundation. Our goal is to translate core Python concepts (variables, functions, collections) to their idiomatic Scala equivalents (val/var, def, List/Map). By the end of this session, you'll be able to read and write basic Scala code by mapping it to concepts you're already an expert in from Python and Go. This is the crucial first step into the language before we start building data pipelines.
From Python to Scala: A Quick Orientation
Before we dive into syntax, it's useful to understand the philosophical similarities and differences that will shape our journey. Python is dynamically typed and interpreted, offering great flexibility. Scala is statically typed and compiled to run on the JVM, providing compile-time safety and performance. However, as you'll see, Scala's powerful type inference often makes it feel as concise as a dynamic language.
The most significant mindset shift will be embracing immutability by default, a core tenet of functional programming that is central to building robust, parallelizable data pipelines in Beam.
Let's start by translating the most fundamental building block: variables.
1. Declaring Data: val, var, and Type Inference
In Python, you declare a variable and can freely change its type and value. Scala is more explicit, forcing a distinction between mutable and immutable variables right at declaration. This is one of the most important concepts in idiomatic Scala.
val(from "value"): Declares an immutable variable, similar to a constant. Once assigned, it cannot be reassigned. This is the preferred way to declare variables in Scala.var(from "variable"): Declares a mutable variable. Its value can be changed after assignment. You should only usevarwhen you have a specific reason for mutation.
The article below provides excellent side-by-side comparisons for a Python developer.
Please read the following sections from the 'Scala for Python Developers' documentation. It provides a direct translation of familiar Python syntax for variables and collections.
Focus on the 'Variable assignment' section. Note the syntax for creating integer/string variables and the distinction between val and var.
Now, let's see this in action and also touch on data types. The video below demonstrates this in a REPL (Read-Eval-Print-Loop), which is a great way to experiment.
(12) - Scala for Data Engineering
This video from 'Scala for Data Engineering' provides a practical demonstration of declaring variables and Scala's type system.
Watch from 06:14 to 11:28 to understand Scala's type hierarchy (Any, AnyVal, AnyRef). Then, watch from 13:32 to 19:34 to see a demonstration of val, var, and type inference. Notice how Scala infers the type (Int, Double) from the assigned value, much like Python, but enforces that type at compile time.
Hands-on Practice:
Open the scala-beam-kickstart project from our last lesson in Helix. Create a new file, src/main/scala/Basics.scala. Inside this file, add a main method and experiment with the concepts above.
@main def basics(): Unit = {
// 1. Declare an immutable integer 'x' with value 10
val x = 10
println(s"The value of x is: $x")
// 2. Try to reassign x. This will cause a compiler error in Helix!
// x = 20
// 3. Declare a mutable string 'y'
var y = "Hello"
println(s"y is: $y")
// 4. Reassign y. This is allowed.
y = "Hello, Scala!"
println(s"y is now: $y")
// 5. Let type inference work for you
val pi = 3.14159 // Inferred as Double
val isReady = true // Inferred as Boolean
}
2. Defining Behavior: Functions with def
Defining functions in Scala is syntactically similar to Python's def, but with some key differences that stem from its static typing and functional nature.

Key differences from Python:
- Type Annotations: You must specify the type of each parameter.
- Return Type: The function's return type is declared after the parameter list. While the compiler can often infer it, explicitly stating it is good practice for clarity.
- Implicit Return: The value of the last expression in the function body is automatically the return value. The
returnkeyword is rarely used and is often considered unidiomatic. - No
self: For methods inside classes, there is no explicitselfparameter like in Python.
Let's see a demonstration.
(12) - Scala for Data Engineering
The following clip demonstrates how to define and call functions in Scala. Pay close attention to the explanation of why the last statement is the return value and the common error of accidentally returning Unit.
Watch from 39:53 to 45:10. This covers the basic syntax, parameter and return types, and the crucial concept of implicit returns.
Hands-on Practice:
Add the following functions to your Basics.scala file and call them from your @main method.
def add(a: Int, b: Int): Int = a + b
def greet(name: String, language: String): String = {
// A multi-line function with an if/else expression
val greeting = if (language == "scala") {
"Greetings,"
} else {
"Hello,"
}
// The last expression is the concatenation, which is returned
s"$greeting $name"
}
// In your @main method:
println(add(5, 7)) // Expected: 12
println(greet("Learner", "scala")) // Expected: Greetings, Learner
A Deeper Look: def vs. val functions
In Scala, functions are first-class citizens. You can define them as named methods with def, but you can also treat them as objects assigned to a val. This is analogous to Python's lambda. Understanding this distinction is vital for functional programming and for passing logic into Beam transforms.
Ch01 Ep01: Val vs Def functions in Scala
This short, focused video clarifies the important difference between a method (def) and a function object (val).
Watch from 00:19 to 03:39 to understand val functions as objects, and then from 07:28 to 09:59 to see how def functions are the more idiomatic way to define reusable methods. This will be very useful later on.
3. Core Collections: List, Map, Set, Tuple
This is where the "immutability by default" philosophy becomes most apparent. While Python's standard list, dict, and set are mutable, Scala's default collections are immutable. When you "add" an element to a Scala List, you get a new list with the added element; the original remains untouched.
This is a critical feature for distributed computing, as immutable data structures are inherently thread-safe and prevent side effects, eliminating a whole class of bugs that can occur in parallel processing.
Let's return to the 'Scala for Python Developers' guide for a direct comparison of collection syntax.
Read the 'Collections classes' section. Pay close attention to the creation syntax for List, Map, Set, and Tuple, and how element access differs (using parentheses () instead of square brackets []).
Let's reinforce this with a live coding session that covers the same ground.
(12) - Scala for Data Engineering
This video walks through creating and using Scala's main collections. It's a good way to see the syntax in a real-time coding context.
Watch these four segments back-to-back. Tuples (23:28 - 28:32): Note the 1-based indexing (_1, _2). Maps (28:44 - 33:16): Note the -> syntax for key-value pairs. Sets (33:16 - 35:55): Note how duplicates are automatically handled. Arrays (35:55 - 39:37): An Array is Scala's primary mutable sequence, analogous to a Java array. It's useful to know but we'll prefer immutable collections.
Hands-on Practice:
Add these examples to your Basics.scala file to solidify your understanding.
// A List of integers (immutable)
val numbers = List(1, 2, 3, 4, 5)
// "Adding" an element returns a NEW list
val newNumbers = 0 :: numbers // `::` is the "cons" operator to prepend
println(s"Original list: $numbers")
println(s"New list: $newNumbers")
println(s"Accessing an element: ${numbers(2)}") // 0-indexed access, prints 3
// A Map from String to Double (immutable)
val cryptoPrices = Map("BTC" -> 60000.0, "ETH" -> 3000.0)
println(s"Price of ETH: ${cryptoPrices("ETH")}")
// A Tuple holding heterogeneous data
val trade = ("BTC/USD", 1.5, 61500.25, "long")
println(s"Accessing the trade size: ${trade._2}") // 1-indexed access
Conclusion
In this lesson, we bridged the gap between your Python expertise and the fundamentals of Scala. We saw how Scala's static types and preference for immutability differ from Python's dynamic, mutable-by-default world.
Key Takeaways:
- Variables: Use
valfor immutable data (preferred) andvarfor mutable data. - Functions: Defined with
def, require type annotations, and the last expression is the return value. - Collections:
List,Map, andSetare immutable by default. This is a deliberate design choice that promotes safety in concurrent systems like Dataflow. - Syntax: Accessing collection elements uses parentheses
()not brackets[]. Tuples are 1-indexed (_1,_2, ...).
You now have the foundational vocabulary to understand and write simple Scala programs.
In our next lesson, "Apply common transformations on the Scala Collections API (map, flatMap, filter, fold)," we will explore how to manipulate these immutable collections. This will directly mirror the kind of data transformation logic you'll write in Apache Beam and will feel very similar to using list comprehensions or tools like itertools in Python.