Scala
Functional Programming
Imperative Code
Idiomatic Scala
Code Optimization

Idiomatic Scala solution to imperative code

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Scala supports imperative code, but idiomatic Scala usually favors immutable data, expression-oriented transformations, and library combinators over manual mutation. The goal is not to remove every var out of ideology. The goal is to make data flow and intent obvious enough that the code becomes easier to test and reason about.

Start by Preserving Behavior

The safest way to turn imperative Scala into idiomatic Scala is to preserve the original behavior first and then improve the mechanics. For example, this imperative loop adds only even numbers:

scala
1val nums = List(1, 2, 3, 4, 5, 6)
2var total = 0
3
4for (n <- nums) {
5  if (n % 2 == 0) {
6    total += n
7  }
8}
9
10println(total) // 12

The idiomatic version is shorter because the collection API already expresses the intent:

scala
1val nums = List(1, 2, 3, 4, 5, 6)
2val total = nums.filter(_ % 2 == 0).sum
3
4println(total) // 12

That is not just shorter. It says what the code means: keep even numbers, then sum them.

Translate Common Imperative Patterns

A lot of imperative code can be mapped directly to standard collection operations:

  • 'map for transforming each element'
  • 'filter for keeping matching elements'
  • 'collect for filter-plus-transform cases'
  • 'foldLeft for explicit accumulation'
  • 'exists and forall for boolean checks'

Here is a small domain example using collect:

scala
1case class Order(id: String, amount: BigDecimal, paid: Boolean)
2
3val orders = List(
4  Order("a1", BigDecimal(20), paid = true),
5  Order("a2", BigDecimal(15), paid = false),
6  Order("a3", BigDecimal(40), paid = true)
7)
8
9val paidTotal = orders.collect {
10  case Order(_, amount, true) => amount
11}.sum
12
13println(paidTotal) // 60

collect is useful here because it combines selection and transformation cleanly.

Use foldLeft for Stateful Logic

Not every loop turns into map and filter. When the imperative version carries state through the iteration, foldLeft is often the idiomatic replacement.

scala
1case class Stats(count: Int, sum: Int)
2
3val values = List(4, 7, 9, 2)
4
5val stats = values.foldLeft(Stats(0, 0)) { (acc, v) =>
6  Stats(count = acc.count + 1, sum = acc.sum + v)
7}
8
9val average =
10  if (stats.count == 0) 0.0
11  else stats.sum.toDouble / stats.count
12
13println(average)

This keeps the state transition explicit while avoiding mutable accumulators.

Replace null and Sentinel Values

Idiomatic Scala also prefers types that express absence or failure directly. Use Option instead of null, and use Either when you need a typed success-or-error result.

scala
1def lookupUserName(id: Int): Option[String] =
2  if (id == 1) Some("Ari") else None
3
4val label = lookupUserName(2).map(_.toUpperCase).getOrElse("UNKNOWN")
5println(label)

For recoverable parsing:

scala
1def parsePositiveInt(raw: String): Either[String, Int] =
2  raw.toIntOption match {
3    case Some(n) if n > 0 => Right(n)
4    case Some(_)          => Left("value must be positive")
5    case None             => Left("not an integer")
6  }

These types force the caller to acknowledge missing or invalid cases instead of relying on hidden conventions.

Readability Still Matters More Than Cleverness

Scala becomes unidiomatic when a transformation chain becomes harder to understand than the original loop. It is perfectly fine to introduce intermediate values.

scala
val valid = rows.filter(_.isValid)
val normalized = valid.map(_.normalize)
val grouped = normalized.groupBy(_.category)

That is often clearer than one long chain with several lambdas and nested pattern matches. Idiomatic Scala is about clarity and correctness, not just compactness.

Favor the Standard Library Before Reaching for Abstractions

Many “imperative to Scala” refactors are solved with collection methods you already have. You often do not need a custom abstraction, a new type class, or a large functional library to make the code better. Start with the standard library, then add abstraction only when repeated patterns justify it.

That habit keeps the code accessible to more Scala developers.

Common Pitfalls

  • Rewriting the syntax without first checking that the original behavior is preserved.
  • Replacing a simple loop with a chain that is harder to read than the original.
  • Using unsafe methods such as head, tail, or .get and losing Scala’s safety benefits.
  • Treating “no var allowed” as a rule even when a small local mutation would be clearer.
  • Reaching for advanced abstractions before the standard collection methods have been considered.

Summary

  • Idiomatic Scala usually favors immutable, expression-oriented transformations.
  • Many imperative loops translate naturally to map, filter, collect, or foldLeft.
  • Use Option and Either instead of null and sentinel values.
  • Preserve behavior first, then improve the structure.
  • Prefer readable transformations over clever but dense pipelines.

Course illustration
Course illustration