iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
🔡

Unique Syntax Features in Scala

に公開

This article is for Day 16 of the Programming Language Specific Syntax Advent Calendar 2025.

I will introduce them based on my personal preferences.
Since I'm currently studying Scala, this content is at an introductory level.

Sample code for binary search

I've implemented it while intentionally utilizing the language's features.

// Scala - Pattern matching + Option + Infix notation
def binarySearch[T: Ordering](arr: IndexedSeq[T], target: T): Option[Int] = {
  import Ordering.Implicits._

  @annotation.tailrec
  def go(left: Int, right: Int): Option[Int] = {
    if (left > right) None
    else {
      val mid = left + (right - left) / 2
      arr(mid) match {
        case x if x == target => Some(mid)
        case x if x < target  => go(mid + 1, right)
        case _                => go(left, mid - 1)
      }
    }
  }
  go(0, arr.length - 1)
}

@main def run(): Unit =
  println(binarySearch(Vector(1, 3, 5, 7, 9), 5).getOrElse(-1))  // 2

Pickup Syntax

implicit parameter (given/using in Scala 3)

You can implicitly pass parameters or define instances of type classes.

// Implicit arguments
def sort[T](list: List[T])(implicit ord: Ordering[T]) = list.sorted

// Scala 3
def sort[T](list: List[T])(using ord: Ordering[T]) = list.sorted

// Type class instance
given Ordering[Person] with
  def compare(a: Person, b: Person) = a.age - b.age

It's convenient, but it looks like it might make the code hard to follow.

for-comprehension

You can combine multiple collections to generate a new collection.

// List comprehension
val doubled = for (x <- 1 to 10 if x % 2 == 0) yield x * 2

// Multiple generators
for {
  x <- 1 to 3
  y <- 1 to 3
  if x != y
} yield (x, y)

// Syntactic sugar for flatMap/map
for {
  a <- Future(1)
  b <- Future(2)
} yield a + b

Extension Methods (Scala 3)

You can add new methods to existing types.

extension (s: String)
  def greet: String = s"Hello, $s!"
  def times(n: Int): String = s * n

"World".greet      // "Hello, World!"
"ab".times(3)      // "ababab"

It's good because it allows for concise writing.

Infix Notation

You can call a method with a single argument using infix notation.

// Calling a method using infix notation
1 to 10        // 1.to(10)
list map f     // list.map(f)
a :: b :: Nil  // Nil.::(b).::(a)

// Custom infix method
case class Vec(x: Int, y: Int) {
  def +(other: Vec) = Vec(x + other.x, y + other.y)
}
Vec(1, 2) + Vec(3, 4)  // Vec(4, 6)

Pattern Matching

You can perform powerful branching based on types and values using match expressions.

// match expression
val result = value match {
  case 0 => "zero"
  case 1 | 2 => "one or two"
  case n if n < 0 => s"negative: $n"
  case _ => "other"
}

// Decomposition of case class
case class Person(name: String, age: Int)
person match {
  case Person("Alice", age) => s"Alice is $age"
  case Person(name, age) if age >= 18 => s"$name is adult"
  case _ => "unknown"
}

I feel that pattern matching expressions are richer compared to other languages.

Option

You can represent the presence or absence of a value in a type-safe manner using Some and None.

// Some or None
val opt: Option[Int] = Some(42)

// Pattern matching
opt match {
  case Some(x) => println(x)
  case None => println("empty")
}

// Method chain
opt.map(_ * 2).filter(_ > 50).getOrElse(0)

// for-comprehension
for {
  x <- Some(10)
  y <- Some(20)
} yield x + y  // Some(30)
GitHubで編集を提案

Discussion