or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

annotations.mdcompile-time.mdgeneric-programming.mdimmutable-arrays.mdindex.mdmacros.mdstructural-types.mdtuples.mdtype-safe-equality.md

compile-time.mddocs/

0

# Compile-Time Programming

1

2

The `scala.compiletime` package provides comprehensive utilities for compile-time metaprogramming, type-level computation, and constexpr-style programming in Scala 3.

3

4

## Core Compile-Time Functions

5

6

### Value Extraction and Constants

7

8

```scala { .api }

9

def erasedValue[T]: T

10

transparent inline def constValue[T]: T

11

transparent inline def constValueOpt[T]: Option[T]

12

inline def constValueTuple[T <: Tuple]: T

13

```

14

15

- **`erasedValue[T]`**: Pattern match on types without having actual values (used in inline matches)

16

- **`constValue[T]`**: Convert singleton types to their corresponding values at compile time

17

- **`constValueOpt[T]`**: Safe version of `constValue` that returns `None` if conversion fails

18

- **`constValueTuple[T]`**: Extract tuple of constant values from tuple type

19

20

### Given Summoning

21

22

```scala { .api }

23

transparent inline def summonFrom[T](f: Nothing => T): T

24

transparent inline def summonInline[T]: T

25

inline def summonAll[T <: Tuple]: T

26

```

27

28

- **`summonFrom[T]`**: Pattern match on available given instances

29

- **`summonInline[T]`**: Summon given value with delayed resolution until full inlining

30

- **`summonAll[T]`**: Summon all elements of a tuple type as a tuple of given instances

31

32

### Compile-Time Assertions and Debugging

33

34

```scala { .api }

35

inline def error(inline msg: String): Nothing

36

transparent inline def codeOf(arg: Any): String

37

inline def requireConst(inline x: Boolean | Byte | Short | Int | Long | Float | Double | Char | String): Unit

38

```

39

40

- **`error`**: Produce user-defined compile errors during inline expansion

41

- **`codeOf`**: Get string representation of code (for debugging and error messages)

42

- **`requireConst`**: Assert that a value is constant after inlining and constant folding

43

44

### Initialization and Deferred Values

45

46

```scala { .api }

47

def uninitialized: Nothing

48

def deferred: Nothing

49

def byName[T](x: => T): T

50

```

51

52

- **`uninitialized`**: Marker for uninitialized mutable fields (compile-time only)

53

- **`deferred`**: Marker for deferred given definitions in traits

54

- **`byName`**: Assertion for by-name parameters (used in nullability checking)

55

56

### Type Conversion

57

58

```scala { .api }

59

extension [T](x: T) transparent inline def asMatchable: x.type & Matchable

60

```

61

62

Cast values to be `Matchable` for pattern matching with unconstrained type parameters.

63

64

## Type-Level Operations

65

66

### Integer Type Operations

67

68

```scala { .api }

69

// Arithmetic operations

70

type +[X <: Int, Y <: Int] <: Int

71

type -[X <: Int, Y <: Int] <: Int

72

type *[X <: Int, Y <: Int] <: Int

73

type /[X <: Int, Y <: Int] <: Int

74

type %[X <: Int, Y <: Int] <: Int

75

76

// Comparison operations

77

type <[X <: Int, Y <: Int] <: Boolean

78

type <=[X <: Int, Y <: Int] <: Boolean

79

type >[X <: Int, Y <: Int] <: Boolean

80

type >=[X <: Int, Y <: Int] <: Boolean

81

82

// Utility operations

83

type S[X <: Int] <: Int // Successor (X + 1)

84

type Abs[X <: Int] <: Int // Absolute value

85

type Min[X <: Int, Y <: Int] <: Int // Minimum

86

type Max[X <: Int, Y <: Int] <: Int // Maximum

87

```

88

89

### Boolean Type Operations

90

91

```scala { .api }

92

type ![X <: Boolean] <: Boolean // Negation

93

type &&[X <: Boolean, Y <: Boolean] <: Boolean // Logical AND

94

type ||[X <: Boolean, Y <: Boolean] <: Boolean // Logical OR

95

type XOR[X <: Boolean, Y <: Boolean] <: Boolean // Exclusive OR

96

```

97

98

### String Type Operations

99

100

```scala { .api }

101

type +[X <: String, Y <: String] <: String // Concatenation

102

type Length[X <: String] <: Int // String length

103

type Substring[S <: String, IBeg <: Int, IEnd <: Int] <: String // Substring

104

type CharAt[S <: String, I <: Int] <: Char // Character at index

105

type Matches[S <: String, Regex <: String] <: Boolean // Regex matching

106

```

107

108

## Usage Examples

109

110

### Pattern Matching on Types

111

112

```scala

113

import scala.compiletime.*

114

115

inline def typeDescription[T]: String =

116

inline erasedValue[T] match

117

case _: String => "text"

118

case _: Int => "integer"

119

case _: Boolean => "boolean"

120

case _: EmptyTuple => "empty tuple"

121

case _: (h *: t) => s"tuple starting with ${typeDescription[h]}"

122

case _ => "unknown type"

123

124

// Usage

125

val desc1 = typeDescription[String] // "text"

126

val desc2 = typeDescription[Int *: String *: EmptyTuple] // "tuple starting with integer"

127

```

128

129

### Working with Constant Values

130

131

```scala

132

import scala.compiletime.*

133

134

// Convert singleton types to values

135

type Three = 3

136

type Hello = "hello"

137

138

val three: 3 = constValue[Three] // 3

139

val hello: "hello" = constValue[Hello] // "hello"

140

141

// Safe constant extraction

142

inline def safeConstant[T]: String =

143

constValueOpt[T] match

144

case Some(value) => s"Constant: $value"

145

case None => "Not a constant type"

146

147

val result1 = safeConstant[42] // "Constant: 42"

148

val result2 = safeConstant[String] // "Not a constant type"

149

150

// Working with tuple constants

151

type Numbers = (1, 2, 3)

152

val numbers: (1, 2, 3) = constValueTuple[Numbers]

153

```

154

155

### Compile-Time Assertions

156

157

```scala

158

import scala.compiletime.*

159

160

inline def safeDivision(inline numerator: Int, inline denominator: Int): Double =

161

requireConst(denominator) // Ensure denominator is known at compile time

162

163

inline if constValue[denominator.type] == 0 then

164

error("Division by zero detected at compile time")

165

else

166

numerator.toDouble / denominator.toDouble

167

168

// Usage

169

val result1 = safeDivision(10, 2) // Compiles: 5.0

170

// val result2 = safeDivision(10, 0) // Compile error: "Division by zero detected at compile time"

171

172

val x = 5

173

// val result3 = safeDivision(10, x) // Compile error: x is not constant

174

```

175

176

### Summoning Given Instances

177

178

```scala

179

import scala.compiletime.*

180

181

trait Show[T]:

182

def show(value: T): String

183

184

given Show[Int] with

185

def show(value: Int) = value.toString

186

187

given Show[String] with

188

def show(value: String) = s"\"$value\""

189

190

given Show[Boolean] with

191

def show(value: Boolean) = value.toString

192

193

// Summon specific instance

194

inline def showValue[T](value: T): String =

195

summonInline[Show[T]].show(value)

196

197

// Pattern match on available instances

198

inline def showAny[T](value: T): String =

199

summonFrom {

200

case given Show[T] => summon[Show[T]].show(value)

201

case _ => "No Show instance available"

202

}

203

204

// Summon multiple instances

205

inline def showTuple[T <: Tuple](tuple: T): List[String] =

206

summonAll[Tuple.Map[T, Show]].toList.zip(tuple.toList).map {

207

case (showInstance, value) => showInstance.asInstanceOf[Show[Any]].show(value)

208

}

209

210

val result1 = showValue(42) // "42"

211

val result2 = showAny("hello") // "\"hello\""

212

val result3 = showTuple((42, "world", true)) // List("42", "\"world\"", "true")

213

```

214

215

### Type-Level Arithmetic

216

217

```scala

218

import scala.compiletime.ops.int.*

219

220

type Two = 2

221

type Three = 3

222

type Five = Two + Three

223

type Six = Two * Three

224

type IsLess = Two < Three // true

225

type Successor = S[Two] // 3

226

227

// Compile-time computation

228

inline def factorial[N <: Int]: Int =

229

inline constValue[N] match

230

case 0 => 1

231

case 1 => 1

232

case n => n * factorial[N - 1]

233

234

val fact5: Int = factorial[5] // 120 (computed at compile time)

235

236

// Type-level validation

237

inline def validateArrayIndex[Size <: Int, Index <: Int]: Unit =

238

inline if constValue[Index >= Size] then

239

error("Array index out of bounds")

240

else if constValue[Index < 0] then

241

error("Negative array index")

242

243

validateArrayIndex[5, 2] // Compiles

244

// validateArrayIndex[5, 7] // Compile error: "Array index out of bounds"

245

```

246

247

### String Type Operations

248

249

```scala

250

import scala.compiletime.ops.string.*

251

252

type Hello = "Hello"

253

type World = "World"

254

type HelloWorld = Hello + " " + World // "Hello World"

255

type HelloLength = Length[Hello] // 5

256

type FirstChar = CharAt[Hello, 0] // 'H'

257

258

inline def greet[Name <: String]: String =

259

"Hello, " + constValue[Name] + "!"

260

261

val greeting = greet["Alice"] // "Hello, Alice!"

262

263

// Compile-time string validation

264

inline def validateEmail[Email <: String]: Unit =

265

inline if !constValue[Matches[Email, ".*@.*\\..*"]] then

266

error("Invalid email format")

267

268

validateEmail["user@example.com"] // Compiles

269

// validateEmail["invalid-email"] // Compile error: "Invalid email format"

270

```

271

272

### Code Generation and Debugging

273

274

```scala

275

import scala.compiletime.*

276

277

inline def logged[T](inline expr: T): T =

278

println(s"Evaluating: ${codeOf(expr)}")

279

expr

280

281

val result = logged(2 + 3 * 4)

282

// Prints: "Evaluating: 2.+(3.*(4))"

283

// Returns: 14

284

285

// Debug macro expansion

286

inline def debugType[T]: String =

287

inline erasedValue[T] match

288

case _: Int => s"Int type with code: ${codeOf(42)}"

289

case _: String => s"String type with code: ${codeOf("hello")}"

290

case _ => s"Other type"

291

```

292

293

### Advanced Generic Programming

294

295

```scala

296

import scala.compiletime.*

297

298

// Compile-time list processing

299

type NestedTuple = ((Int, String), (Boolean, Double), (Char, Float))

300

301

inline def processTuple[T <: Tuple]: String =

302

inline erasedValue[T] match

303

case _: EmptyTuple => "empty"

304

case _: (h *: t) =>

305

s"head: ${typeDescription[h]}, tail: ${processTuple[t]}"

306

307

inline def tupleSize[T <: Tuple]: Int =

308

inline erasedValue[T] match

309

case _: EmptyTuple => 0

310

case _: (h *: t) => 1 + tupleSize[t]

311

312

val description = processTuple[NestedTuple]

313

val size = tupleSize[NestedTuple] // 3

314

315

// Compile-time validation for type classes

316

inline def requireShow[T]: Unit =

317

summonFrom {

318

case given Show[T] => ()

319

case _ => error(s"No Show instance for type ${codeOf(??? : T)}")

320

}

321

322

inline def showIfPossible[T](value: T): String =

323

requireShow[T]

324

summon[Show[T]].show(value)

325

```

326

327

### Conditional Compilation

328

329

```scala

330

import scala.compiletime.*

331

332

inline def platformSpecific[T](value: T): String =

333

inline if constValue[scala.util.Properties.isWin] then

334

s"Windows: $value"

335

else if constValue[scala.util.Properties.isLinux] then

336

s"Linux: $value"

337

else

338

s"Other OS: $value"

339

340

// Feature flags at compile time

341

inline val FEATURE_ENABLED = true

342

343

inline def withFeature[T](inline enabled: T, inline disabled: T): T =

344

inline if FEATURE_ENABLED then enabled else disabled

345

346

val result = withFeature("Feature is on", "Feature is off")

347

```

348

349

The compile-time programming capabilities in Scala 3 enable powerful metaprogramming techniques, allowing developers to move computations and validations from runtime to compile time, resulting in better performance and stronger type safety guarantees.