📖 Learn Scala — From Toolchain to Production

A code-first engineering reference for Scala 3. Every chapter is structured around annotated production code — anti-patterns, edge cases, compiler internals, and JVM-level reality. No tutorial fluff.

Scala is a statically-typed, JVM-compiled language blending object-oriented and functional programming. Used in data engineering (Spark, Kafka), distributed systems (Akka, ZIO), and backend services (Twitter, LinkedIn, Databricks). This curriculum targets Scala 3.x with notes on Scala 2 interop.

How to Use This Reference

  1. Read sequentially (01 → 11) for a structured progression from toolchain to production interop.
  2. Jump to a chapter when you hit a concept in the wild — each is self-contained.
  3. Run examples with scala-cli (single files) or sbt (multi-module projects).
  4. Debug type errors with -Xprint:typer and -explain — see 01 for compiler introspection.
  5. Every code block is annotated — inline comments explain under-the-hood behavior, allocation, and bytecode mapping.

Prerequisites

  • Java 17+ installed (java -version).
  • Scala 3 via Coursier: cs install scala3 (preferred) or brew install scala3.
  • sbt: brew install sbt or cs install sbt.
  • IntelliJ IDEA with Scala plugin or VS Code with Metals.
  • Comfort with JVM concepts (classloaders, bytecode, garbage collection) and functional programming basics.

Curriculum

Part I — Foundations & Execution Model

#TopicWhy It Matters
01Toolchain & JVM Execution ModelCompiler phases, bytecode mapping, sbt/scala-cli, project layout. Without this, you can't debug type errors or perf.
02Value Semantics & Type Hierarchyval/var/lazy val init semantics, primitive boxing, opaque types, AnyVal/AnyRef, IEEE 754 gotchas.
03Functions & ClosuresFunction1 JVM representation, closure capture, @tailrec, by-name vs by-need, currying, inline def.
04Pattern Matching & ExhaustivenessSealed exhaustiveness, type erasure traps, custom extractors, match types, Either/Try/Option as error values.

Part II — Collections & Object Model

#TopicWhy It Matters
05Collections: Persistent Data StructuresVector RRB-trees, structural sharing, lazy views, fusion, performance characteristics, streaming patterns.
06Classes, Traits & Object ModelTrait linearization, self types, open/sealed, universal equality, companion objects, path-dependent types.
07Case Classes & ADTsGenerated code, ADT design, recursive types, regex patterns, custom extractors, copy and lens patterns.

Part III — Type System & Concurrency

#TopicWhy It Matters
08Type System: Variance & Phantom TypesVariance constraints, type classes (given/using), higher-kinded types, phantom types for state machines, match types.
09Concurrency: Futures & BackpressureExecutionContext tuning, parallel vs sequential, retry with backoff, race conditions, Promise, Try, atomic operations.

Part IV — Production

#TopicWhy It Matters
10Testing: ScalaTest & ScalaCheckFixtures, property-based testing with shrinking, mock-free design with fakes, tagged integration tests, async testing.
11Java InteroperabilityCollection views vs copies, null safety bridges, SAM conversion, @targetName, Java-friendly API design, boxing overhead.

Learning Path Suggestions

If you're coming from Java

  1. Read 01 closely — the compiler pipeline and bytecode mapping differ from javac.
  2. Skim 02–03 — val/var and lambdas map to Java concepts but with different init semantics.
  3. Read 04 & 07 — sealed exhaustiveness and pattern matching are Scala's biggest wins over Java.
  4. Read 08 — variance, type classes, and phantom types are concepts Java doesn't have.
  5. Read 11 — interop has subtle traps (views vs copies, boxing, checked exceptions).

If you're coming from Python/Ruby

  1. Read 02 — static types, type inference, and the Any hierarchy are fundamentally different.
  2. Read 03–04 — closures, tail recursion, and pattern matching replace dynamic dispatch.
  3. Read 05 — persistent data structures and structural sharing replace mutable defaults.
  4. Read 08 — the type system (variance, type classes) is the biggest paradigm shift.
  5. Read 09 — Future and ExecutionContext replace asyncio with a thread-pool model.

If you're coming from Haskell/OCaml

  1. Skim 01–05 — most concepts are familiar; focus on JVM-specific details (boxing, erasure).
  2. Read 07 — ADTs and pattern matching are similar but with different ergonomics.
  3. Read 08 closely — variance annotations and type classes (given/using) differ from typeclass instances.
  4. Read 09 — Future is eager (not lazy like IO); consider ZIO or Cats Effect for laziness.
  5. Read 11 — Java interop is unique to Scala and has real production consequences.

If you're a senior engineer using Scala in production

  1. Read 01 — compiler phases and bytecode mapping for debugging production issues.
  2. Read 05 & 08 — collection performance and type system design for API/library design.
  3. Read 09 — ExecutionContext tuning and backpressure for high-throughput services.
  4. Read 10 — property-based testing and mock-free design for maintainable test suites.
  5. Use 11 as a reference for cross-language team boundaries.

Key Differences from Java (Quick Reference)

JavaScala 3
public static void main(String[] args)@main def run(): Unit = ...
int x = 5;val x = 5 (immutable) or var x = 5 (mutable)
Optional<T>Option[T] — Some(v) / None
switch (fallthrough, no exhaustiveness)match — expression, exhaustiveness-checked on sealed
Checked exceptionsNo checked exceptions — use Try/Either
instanceof + castPattern match: case s: String => ...
ArrayList<T> (mutable, covariant arrays)Vector[T] (immutable, persistent) or ArrayBuffer[T]
Function<T,R> (single interface)T => R (Function1, with 22 arities + specialized variants)
synchronized blockssynchronized + AtomicLong + Future + Promise
Getter/setter conventionsProperties (direct field access, no getX()/setX())