scalaadvanced

Inline and Compile-Time Metaprogramming

Use Scala 3 inline, transparent inline, and compiletime for compile-time computation and code generation.

scala
import scala.compiletime.*
import scala.compiletime.ops.int.*

// inline: guaranteed inlined at call site
inline def assertPositive(n: Int): Int =
  inline if n <= 0 then
    error("Value must be positive")
  else n

// transparent inline: return type is narrowed
transparent inline def toNumber(inline s: String): Any =
  inline s match
    case "one"   => 1
    case "two"   => 2
    case "three" => 3
    case _       => s

// Compile-time string operations
inline def compileTimeConcat(inline a: String, inline b: String): String =
  constValue[a.type + b.type]

// Type-level assertions
inline def requirePositive[N <: Int]: Unit =
  inline constValue[N > 0] match
    case true  => ()
    case false => error("Type parameter must be positive")

// Inline match for type-based branching
inline def defaultValue[T]: T =
  inline erasedValue[T] match
    case _: Int     => 0.asInstanceOf[T]
    case _: String  => "".asInstanceOf[T]
    case _: Boolean => false.asInstanceOf[T]
    case _: Double  => 0.0.asInstanceOf[T]
    case _: List[?] => Nil.asInstanceOf[T]

// summonInline: summon at compile time
trait DefaultProvider[T]:
  def default: T

given DefaultProvider[Int] with
  def default: Int = 0

given DefaultProvider[String] with
  def default: String = ""

given DefaultProvider[Boolean] with
  def default: Boolean = false

inline def getDefault[T]: T =
  summonInline[DefaultProvider[T]].default

// Compile-time tuple operations
inline def tupleSize[T <: Tuple]: Int =
  inline erasedValue[T] match
    case _: EmptyTuple => 0
    case _: (h *: t)   => 1 + tupleSize[t]

// Inline conditional logging
inline val DEBUG = true

inline def debugLog(inline msg: String): Unit =
  inline if DEBUG then println(s"[DEBUG] $msg")

// Power at compile time
inline def power(inline base: Double, inline exp: Int): Double =
  inline if exp == 0 then 1.0
  else if exp == 1 then base
  else base * power(base, exp - 1)

@main def run(): Unit =
  // transparent inline narrows return type
  val one: Int = toNumber("one")      // type is Int, not Any
  val two: Int = toNumber("two")
  println(s"one=$one, two=$two")

  // Default values
  println(s"Int default: ${defaultValue[Int]}")
  println(s"String default: ${defaultValue[String]}")
  println(s"Boolean default: ${defaultValue[Boolean]}")

  // summonInline
  println(s"Default Int: ${getDefault[Int]}")
  println(s"Default String: '${getDefault[String]}'")

  // Debug logging (compiled away if DEBUG=false)
  debugLog("This is a debug message")

  // Compile-time power
  val result = power(2.0, 10)
  println(s"2^10 = $result")

  // Tuple size
  println(s"Tuple3 size: ${tupleSize[(Int, String, Boolean)]}")

Use Cases

  • Compile-time computation
  • Zero-overhead abstractions
  • Type-safe code generation

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.