scalabeginner

Extension Methods and Type Enrichment

Add new methods to existing types with Scala 3 extension methods and type enrichment patterns.

scala
// Extension methods (Scala 3)
extension (s: String)
  def words: List[String] = s.split("\\s+").toList
  def isEmail: Boolean = s.matches(".+@.+\\..+")
  def truncate(maxLen: Int): String =
    if s.length <= maxLen then s
    else s.take(maxLen - 3) + "..."
  def slug: String =
    s.toLowerCase.replaceAll("[^a-z0-9\\s-]", "").replaceAll("\\s+", "-")

extension (n: Int)
  def times(f: => Unit): Unit = (1 to n).foreach(_ => f)
  def isEven: Boolean = n % 2 == 0
  def isOdd: Boolean = !n.isEven
  def factorial: BigInt = (1 to n).foldLeft(BigInt(1))(_ * _)
  def ordinal: String = n match
    case 1 => "1st"
    case 2 => "2nd"
    case 3 => "3rd"
    case _ => s"${n}th"

extension [A](list: List[A])
  def second: Option[A] = list.lift(1)
  def penultimate: Option[A] = list.lift(list.length - 2)
  def interleave(other: List[A]): List[A] =
    list.zip(other).flatMap((a, b) => List(a, b))
  def frequencies: Map[A, Int] =
    list.groupBy(identity).map((k, v) => k -> v.size)

// Extension with type class constraint
trait Summable[T]:
  def zero: T
  def add(a: T, b: T): T

given Summable[Int] with
  def zero: Int = 0
  def add(a: Int, b: Int): Int = a + b

given Summable[String] with
  def zero: String = ""
  def add(a: String, b: String): String = a + b

extension [T: Summable](list: List[T])
  def total: T =
    val s = summon[Summable[T]]
    list.foldLeft(s.zero)(s.add)

@main def run(): Unit =
  // String extensions
  println("Hello World Foo".words)
  println("alice@test.com".isEmail)
  println("not-email".isEmail)
  println("Hello World and more text".truncate(15))
  println("Hello World!".slug)

  // Int extensions
  3.times(print("*"))
  println()
  println(s"4 is even: ${4.isEven}")
  println(s"5! = ${5.factorial}")
  println(s"${3.ordinal} place")

  // List extensions
  val list = List(1, 2, 3, 4, 5)
  println(s"Second: ${list.second}")
  println(s"Penultimate: ${list.penultimate}")
  println(s"Interleave: ${list.interleave(List(10, 20, 30, 40, 50))}")
  println("banana apple cherry apple banana banana".words.frequencies)

  // Summable extension
  println(s"Total: ${List(1, 2, 3, 4, 5).total}")
  println(s"Concat: ${List("a", "b", "c").total}")

Use Cases

  • Adding utility methods to standard types
  • Domain-specific language extensions
  • Type-safe enrichment patterns

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.