Scala Syntax

Scala's syntax is clean and expressive. Once you learn the patterns, you can write highly readable, concise code.

String Interpolation

Scala
val name = "Alice"
val age = 28

// s-interpolation (most common)
println(s"Name: $name, Age: $age")
println(s"Next year: ${age + 1}")
println(s"Uppercase: ${name.toUpperCase}")

// f-interpolation (formatted)
println(f"Pi is $pi%1.4f")         // Pi is 3.1416
println(f"$name is $age%3d years old")  // Alice is 28 years old

// raw-interpolation (escape sequences)
println(raw"Newline: \n")  // Prints literal \n

Collections Operations

Scala
val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

// Transformations
numbers.map(_ * 2)              // List(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
numbers.flatMap(x => List(x, x * 10))  // List(1,10,2,20,...)
numbers.filter(_ % 2 == 0)      // List(2, 4, 6, 8, 10)
numbers.exists(_ > 5)           // true
numbers.forall(_ > 0)           // true

// Aggregations
numbers.sum                     // 55
numbers.product                 // 3628800
numbers.max                     // 10
numbers.min                     // 1

// Grouping
numbers.groupBy(_ % 3)          // Map(0 -> List(3,6,9), 1 -> List(1,4,7,10), 2 -> List(2,5,8))
numbers.partition(_ > 5)        // (List(6,7,8,9,10), List(1,2,3,4,5))

// Sorting
List(3, 1, 4, 1, 5).sorted      // List(1, 1, 3, 4, 5)
List("banana", "apple").sorted   // List("apple", "banana")

// Folding
numbers.foldLeft(0)(_ + _)      // 55 (same as sum)
numbers.foldRight("")((n, acc) => s"$n $acc")  // "10 9 8 7 6 5 4 3 2 1 "

// For comprehensions (syntactic sugar for map/flatMap/filter)
val result = for {
  x <- List(1, 2, 3)
  y <- List(10, 20)
  if x > 1
} yield x * y
// List(20, 40, 30, 60)

Option Type (Null Safety)

Scala
// Option replaces null — forces you to handle missing values
val maybeName: Option[String] = Some("Alice")
val emptyName: Option[String] = None

// Safe access
val length: Option[Int] = maybeName.map(_.length)  // Some(5)
val upper: Option[String] = emptyName.map(_.toUpperCase)  // None

// Unwrap with default
val name1 = maybeName.getOrElse("Anonymous")  // "Alice"
val name2 = emptyName.getOrElse("Anonymous")  // "Anonymous"

// Pattern matching
maybeName match {
  case Some(name) => println(s"Found: $name")
  case None => println("Not found")
}

// Chaining
def findUser(id: Int): Option[String] = 
  if (id == 1) Some("Alice") else None

val greeting: Option[String] = findUser(1).map(name => s"Hello, $name!")
// Some("Hello, Alice!")

Error Handling with Try/Either

Scala
import scala.util.{Try, Success, Failure}

// Try — wraps code that might throw
def parseAge(input: String): Try[Int] = Try(input.toInt)

parseAge("25") match {
  case Success(age) => println(s"Age: $age")
  case Failure(e) => println(s"Invalid: ${e.getMessage}")
}

// Either — explicit success/failure types
def divide(a: Int, b: Int): Either[String, Int] = 
  if (b == 0) Left("Division by zero")
  else Right(a / b)

divide(10, 3) match {
  case Right(result) => println(s"Result: $result")
  case Left(error) => println(s"Error: $error")
}

// Chaining with Either
val result: Either[String, Int] = for {
  a <- Right(10)
  b <- Right(3)
} yield a / b
// Right(3)

For Comprehensions (Advanced)

Scala
// For comprehensions work with Option, Either, Try, Future, List...
def validateUser(name: String, age: String): Either[String, Int] = for {
  n <- if (name.nonEmpty) Right(name) else Left("Name required")
  a <- Try(age.toInt).toOption.toRight("Invalid age number")
  _ <- if (a > 0 && a < 150) Right(()) else Left("Age out of range")
} yield a

validateUser("Alice", "28")   // Right(28)
validateUser("", "28")        // Left("Name required")
validateUser("Alice", "abc")  // Left("Invalid age number")

💡 Tip: Always use Option instead of null. Chain operations with .map, .flatMap, .filter instead of null checks. It makes code safer and more readable.

Next: Object-Oriented Scala