Overview
Scala is a modern multi-paradigm programming language designed to express common programming patterns in a concise, elegant, and type-safe way. It seamlessly integrates features of object-oriented and functional languages, running on the Java Virtual Machine (JVM) with full Java interoperability. Scala’s powerful type system, pattern matching, and immutable data structures make it ideal for building complex, concurrent systems.
Created by Martin Odersky at EPFL in 2003, Scala has become a cornerstone of big data processing (Apache Spark, Kafka, Flink) and distributed systems (Akka). Scala 3 (Dotty) introduced significant improvements including a simplified syntax, union types, opaque types, and an overhauled macro system. The language strikes a balance between academic rigor and practical software engineering.
Installation
Using Coursier (Recommended)
# Install Coursier (Scala installer)
curl -fL https://github.com/coursier/coursier/releases/latest/download/cs-x86_64-pc-linux.gz | gzip -d > cs
chmod +x cs && ./cs setup
# macOS
brew install coursier/formulas/coursier && cs setup
# Verify
scala --version
scalac --version
sbt --version
Using SDKMAN
sdk install scala 3.4.0
sdk install sbt 1.9.8
Core Language
Variables and Types
// Immutable (preferred)
val name: String = "Scala"
val age = 42 // Type inference
// Mutable
var counter: Int = 0
counter += 1
// Lazy evaluation
lazy val expensive = computeExpensiveValue()
// Type aliases
type UserId = Long
type Result[A] = Either[String, A]
Basic Types
| Type | Description | Example |
|---|
Int | 32-bit integer | 42 |
Long | 64-bit integer | 42L |
Double | 64-bit floating point | 3.14 |
Float | 32-bit floating point | 3.14f |
Boolean | True/false | true |
Char | Unicode character | 'A' |
String | Character sequence | "hello" |
Unit | No value (like void) | () |
Nothing | No instances exist | Bottom type |
Any | Supertype of everything | Top type |
Functions
// Function definition
def add(x: Int, y: Int): Int = x + y
// Default and named parameters
def greet(name: String, greeting: String = "Hello"): String =
s"$greeting, $name!"
greet("World") // "Hello, World!"
greet("World", greeting = "Hi") // "Hi, World!"
// Anonymous functions
val double = (x: Int) => x * 2
val nums = List(1, 2, 3).map(_ * 2)
// Higher-order functions
def apply(f: Int => Int, x: Int): Int = f(x)
apply(double, 5) // 10
// Curried functions
def multiply(x: Int)(y: Int): Int = x * y
val triple = multiply(3)(_)
triple(5) // 15
// By-name parameters (lazy evaluation)
def logIf(condition: Boolean)(message: => String): Unit =
if (condition) println(message)
Pattern Matching
// Basic matching
val result = x match
case 0 => "zero"
case 1 => "one"
case n if n > 0 => s"positive: $n"
case _ => "negative"
// Type matching
def process(any: Any): String = any match
case s: String => s"String: $s"
case i: Int if i > 0 => s"Positive Int: $i"
case list: List[_] => s"List of ${list.length}"
case _ => "Unknown"
// Case class matching
case class User(name: String, age: Int)
user match
case User("Admin", _) => "admin user"
case User(name, age) if age >= 18 => s"adult: $name"
case User(name, _) => s"minor: $name"
// Sealed trait matching (exhaustive)
enum Color:
case Red, Green, Blue
color match
case Color.Red => "#FF0000"
case Color.Green => "#00FF00"
case Color.Blue => "#0000FF"
Collections
// Immutable collections (default)
val list = List(1, 2, 3)
val set = Set("a", "b", "c")
val map = Map("name" -> "Scala", "version" -> "3")
val vec = Vector(1, 2, 3) // Efficient random access
// Operations
list.map(_ * 2) // List(2, 4, 6)
list.filter(_ > 1) // List(2, 3)
list.foldLeft(0)(_ + _) // 6
list.flatMap(x => List(x, x)) // List(1, 1, 2, 2, 3, 3)
list.zip(List("a", "b", "c")) // List((1,"a"), (2,"b"), (3,"c"))
list.grouped(2).toList // List(List(1, 2), List(3))
list.sliding(2).toList // List(List(1, 2), List(2, 3))
list.forall(_ > 0) // true
list.exists(_ > 2) // true
// For comprehensions
val result = for
x <- 1 to 10
if x % 2 == 0
y <- 1 to 3
yield x * y
Object-Oriented Features
// Class
class Animal(val name: String, val sound: String):
def speak(): String = s"$name says $sound"
// Case class (immutable data holder)
case class Point(x: Double, y: Double):
def distanceTo(other: Point): Double =
math.sqrt(math.pow(x - other.x, 2) + math.pow(y - other.y, 2))
// Trait (interface + implementation)
trait Printable:
def format: String
def print(): Unit = println(format)
// Enum (Scala 3)
enum Planet(val mass: Double, val radius: Double):
case Mercury extends Planet(3.303e+23, 2.4397e6)
case Venus extends Planet(4.869e+24, 6.0518e6)
case Earth extends Planet(5.976e+24, 6.37814e6)
// Object (singleton)
object Config:
val maxRetries = 3
def load(): Config = ???
// Extension methods (Scala 3)
extension (s: String)
def greet: String = s"Hello, $s!"
"World".greet // "Hello, World!"
Common Commands
| Command | Description |
|---|
sbt new scala/scala3.g8 | Create new Scala 3 project |
sbt compile | Compile project |
sbt run | Run main class |
sbt test | Run tests |
sbt console | Start Scala REPL with project |
sbt ~compile | Watch mode (auto-recompile) |
sbt assembly | Create fat JAR |
sbt clean | Clean build artifacts |
build.sbt
ThisBuild / version := "0.1.0"
ThisBuild / scalaVersion := "3.4.0"
lazy val root = (project in file("."))
.settings(
name := "my-project",
libraryDependencies ++= Seq(
"org.typelevel" %% "cats-core" % "2.10.0",
"com.typesafe.akka" %% "akka-actor-typed" % "2.8.5",
"org.scalatest" %% "scalatest" % "3.2.17" % Test
)
)
Configuration
Typesafe Config
// src/main/resources/application.conf
app {
name = "MyService"
port = 8080
database {
url = "jdbc:postgresql://localhost/mydb"
pool-size = 10
}
}
import com.typesafe.config.ConfigFactory
val config = ConfigFactory.load()
val port = config.getInt("app.port")
val dbUrl = config.getString("app.database.url")
Advanced Usage
Given/Using (Scala 3 Implicits)
trait JsonEncoder[A]:
def encode(value: A): String
given JsonEncoder[Int] with
def encode(value: Int): String = value.toString
given JsonEncoder[String] with
def encode(value: String): String = s""""$value""""
def toJson[A](value: A)(using encoder: JsonEncoder[A]): String =
encoder.encode(value)
toJson(42) // "42"
toJson("hello") // "\"hello\""
Futures and Concurrent Programming
import scala.concurrent.{Future, ExecutionContext}
import scala.concurrent.ExecutionContext.Implicits.global
val future = Future {
Thread.sleep(1000)
42
}
future.map(_ * 2).foreach(println)
// Combining futures
val combined = for
a <- Future(computeA())
b <- Future(computeB())
yield a + b
Troubleshooting
| Problem | Solution |
|---|
ClassNotFoundException | Check classpath; ensure sbt assembly includes deps |
| Implicit not found | Import givens; check scope and type parameters |
| Type mismatch errors | Use explicit type annotations to debug inference |
| Slow compilation | Use sbt ~compile for incremental; split into subprojects |
| Java interop issues | Use @BeanProperty for getters/setters; handle null with Option |
| Stack overflow in recursion | Use @tailrec annotation or trampolining |
| Binary compatibility | Use %% in sbt for cross-versioned deps |
| Out of memory in sbt | Set SBT_OPTS="-Xmx4G" in environment |