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

macros.mddocs/

0

# Macro and Metaprogramming

1

2

The `scala.quoted` package provides Scala 3's powerful macro system using quotes and splices for compile-time code generation and analysis.

3

4

## Core Types

5

6

### Quotes Context

7

8

```scala { .api }

9

trait Quotes:

10

// Provides access to compiler internals and reflection API

11

type reflect: Reflection

12

```

13

14

The main context object providing access to the compiler's reflection API and utilities needed for macro programming.

15

16

### Quoted Expressions

17

18

```scala { .api }

19

abstract class Expr[+T]:

20

def show(using Quotes): String

21

def value(using Quotes): T // Only works for constant expressions

22

def asTerm(using Quotes): reflect.Term

23

```

24

25

Represents quoted expressions that can be spliced into code. `Expr[T]` contains code that, when executed, produces a value of type `T`.

26

27

### Quoted Types

28

29

```scala { .api }

30

abstract class Type[T <: AnyKind]:

31

def show(using Quotes): String

32

def asTerm(using Quotes): reflect.Term

33

```

34

35

Represents quoted types that can be used in type-level computations and spliced into contexts expecting types.

36

37

## Conversion Type Classes

38

39

### ToExpr - Value to Expression

40

41

```scala { .api }

42

trait ToExpr[T]:

43

def apply(x: T)(using Quotes): Expr[T]

44

45

object ToExpr:

46

given ToExpr[Boolean]

47

given ToExpr[Byte]

48

given ToExpr[Short]

49

given ToExpr[Int]

50

given ToExpr[Long]

51

given ToExpr[Float]

52

given ToExpr[Double]

53

given ToExpr[Char]

54

given ToExpr[String]

55

given [T: ToExpr]: ToExpr[List[T]]

56

given [T: ToExpr]: ToExpr[Seq[T]]

57

given [T: ToExpr]: ToExpr[Option[T]]

58

// ... and many more standard types

59

```

60

61

Type class for converting runtime values to quoted expressions.

62

63

### FromExpr - Expression to Value

64

65

```scala { .api }

66

trait FromExpr[T]:

67

def apply(expr: Expr[T])(using Quotes): Option[T]

68

69

object FromExpr:

70

given FromExpr[Boolean]

71

given FromExpr[Byte]

72

given FromExpr[Short]

73

given FromExpr[Int]

74

given FromExpr[Long]

75

given FromExpr[Float]

76

given FromExpr[Double]

77

given FromExpr[Char]

78

given FromExpr[String]

79

given [T: FromExpr]: FromExpr[List[T]]

80

given [T: FromExpr]: FromExpr[Option[T]]

81

// ... and many more standard types

82

```

83

84

Type class for extracting constant values from quoted expressions (when possible).

85

86

## Utility Types

87

88

### Variable Arguments

89

90

```scala { .api }

91

abstract class Varargs[T]:

92

def apply(using Quotes): Seq[Expr[T]]

93

```

94

95

Handles variable arguments in macro contexts, providing access to a sequence of expressions.

96

97

### Expression Transformation

98

99

```scala { .api }

100

class ExprMap(using Quotes):

101

def apply[T](expr: Expr[T]): Expr[T]

102

def transformChildren[T](expr: Expr[T]): Expr[T]

103

```

104

105

Utility class for recursively transforming expressions in macro code.

106

107

## Quote and Splice Syntax

108

109

### Basic Quote/Splice

110

111

```scala

112

import scala.quoted.*

113

114

// Quoting expressions - creates Expr[T]

115

'{ 1 + 2 } // Expr[Int]

116

'{ "hello" + "world" } // Expr[String]

117

'{ List(1, 2, 3) } // Expr[List[Int]]

118

119

// Splicing expressions - injects Expr[T] into quoted context

120

val expr: Expr[Int] = '{ 42 }

121

'{ $expr + 1 } // Expr[Int] representing 42 + 1

122

123

// Quoting types - creates Type[T]

124

'[Int] // Type[Int]

125

'[List[String]] // Type[List[String]]

126

```

127

128

### Nested Quotes and Splices

129

130

```scala

131

def makeAddition(x: Expr[Int], y: Expr[Int])(using Quotes): Expr[Int] =

132

'{ $x + $y }

133

134

def makeList[T: Type](elements: Expr[T]*)(using Quotes): Expr[List[T]] =

135

'{ List(${ Varargs(elements.toSeq) }*) }

136

```

137

138

## Usage Examples

139

140

### Simple Macro Definition

141

142

```scala

143

import scala.quoted.*

144

145

inline def debug[T](inline x: T): T =

146

${ debugImpl('x) }

147

148

def debugImpl[T: Type](x: Expr[T])(using Quotes): Expr[T] =

149

val code = x.show

150

'{

151

println(s"Debug: ${ Expr(code) } = ${$x}")

152

$x

153

}

154

155

// Usage

156

val result = debug(2 + 3 * 4)

157

// Prints: Debug: 2.+(3.*(4)) = 14

158

// Returns: 14

159

```

160

161

### Conditional Code Generation

162

163

```scala

164

import scala.quoted.*

165

166

inline def optimizedOperation[T](inline x: T, inline y: T): T =

167

${ optimizedOperationImpl('x, 'y) }

168

169

def optimizedOperationImpl[T: Type](x: Expr[T], y: Expr[T])(using Quotes): Expr[T] =

170

(x.value, y.value) match

171

case (Some(0), _) => y // 0 + y = y

172

case (_, Some(0)) => x // x + 0 = x

173

case (Some(a), Some(b)) => Expr(a + b) // Constant folding

174

case _ => '{ $x + $y } // Runtime addition

175

176

val result1 = optimizedOperation(0, 42) // Optimized to just 42

177

val result2 = optimizedOperation(10, 20) // Optimized to 30

178

val result3 = optimizedOperation(x, y) // Runtime addition

179

```

180

181

### Working with Types

182

183

```scala

184

import scala.quoted.*

185

186

inline def typeInfo[T]: String =

187

${ typeInfoImpl[T] }

188

189

def typeInfoImpl[T: Type](using Quotes): Expr[String] =

190

import quotes.reflect.*

191

192

val tpe = TypeRepr.of[T]

193

val typeName = tpe.show

194

val isGeneric = tpe.typeArgs.nonEmpty

195

val info = s"Type: $typeName, Generic: $isGeneric"

196

197

Expr(info)

198

199

val info1 = typeInfo[Int] // "Type: Int, Generic: false"

200

val info2 = typeInfo[List[String]] // "Type: List[String], Generic: true"

201

```

202

203

### Expression Analysis

204

205

```scala

206

import scala.quoted.*

207

208

inline def analyzeExpression[T](inline expr: T): String =

209

${ analyzeExpressionImpl('expr) }

210

211

def analyzeExpressionImpl[T: Type](expr: Expr[T])(using Quotes): Expr[String] =

212

import quotes.reflect.*

213

214

val term = expr.asTerm

215

val analysis = term match

216

case Literal(constant) => s"Literal: ${constant.show}"

217

case Ident(name) => s"Identifier: $name"

218

case Apply(fun, args) => s"Application: ${fun.show} with ${args.length} arguments"

219

case Select(qualifier, name) => s"Selection: $name from ${qualifier.show}"

220

case _ => s"Complex expression: ${term.show}"

221

222

Expr(analysis)

223

224

val analysis1 = analyzeExpression(42) // "Literal: 42"

225

val analysis2 = analyzeExpression("hello".length) // Complex analysis

226

val analysis3 = analyzeExpression(List(1, 2, 3)) // "Application: List with 3 arguments"

227

```

228

229

### Code Transformation

230

231

```scala

232

import scala.quoted.*

233

234

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

235

${ logCallsImpl('expr) }

236

237

def logCallsImpl[T: Type](expr: Expr[T])(using Quotes): Expr[T] =

238

import quotes.reflect.*

239

240

def transform(term: Term): Term = term match

241

case Apply(fun, args) =>

242

val transformedArgs = args.map(transform)

243

val loggedCall = '{

244

println(s"Calling: ${${Expr(fun.show)}}")

245

${Apply(fun, transformedArgs).asExprOf[Any]}

246

}.asTerm

247

loggedCall

248

case _ => term.changeOwner(Symbol.spliceOwner)

249

250

transform(expr.asTerm).asExprOf[T]

251

252

// Usage logs all method calls

253

val result = logCalls {

254

val x = List(1, 2, 3)

255

x.map(_ + 1).filter(_ > 2)

256

}

257

```

258

259

### Compile-Time Validation

260

261

```scala

262

import scala.quoted.*

263

264

inline def validateJson(inline json: String): String =

265

${ validateJsonImpl('json) }

266

267

def validateJsonImpl(json: Expr[String])(using Quotes): Expr[String] =

268

json.value match

269

case Some(jsonString) =>

270

// Validate JSON at compile time

271

try

272

// Assuming some JSON parser

273

parseJson(jsonString) // Throws if invalid

274

json

275

catch

276

case e: Exception =>

277

quotes.reflect.report.errorAndAbort(s"Invalid JSON: ${e.getMessage}")

278

case None =>

279

quotes.reflect.report.errorAndAbort("JSON string must be a compile-time constant")

280

281

val validJson = validateJson("""{"name": "Alice", "age": 30}""") // Compiles

282

// val invalidJson = validateJson("""{"name": "Alice", "age":}""") // Compile error

283

```

284

285

### Generic Macro Programming

286

287

```scala

288

import scala.quoted.*

289

290

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

291

${ showStructureImpl('value) }

292

293

def showStructureImpl[T: Type](value: Expr[T])(using Quotes): Expr[String] =

294

import quotes.reflect.*

295

296

def analyzeType(tpe: TypeRepr): String = tpe match

297

case AppliedType(base, args) =>

298

s"${base.show}[${args.map(analyzeType).mkString(", ")}]"

299

case _ => tpe.show

300

301

def analyzeTerm(term: Term): String = term match

302

case Literal(constant) => s"Literal(${constant.show})"

303

case Ident(name) => s"Ident($name)"

304

case Apply(fun, args) =>

305

s"Apply(${analyzeTerm(fun)}, [${args.map(analyzeTerm).mkString(", ")}])"

306

case Select(qualifier, name) =>

307

s"Select(${analyzeTerm(qualifier)}, $name)"

308

case _ => s"Term(${term.show})"

309

310

val typeAnalysis = analyzeType(TypeRepr.of[T])

311

val termAnalysis = analyzeTerm(value.asTerm)

312

313

Expr(s"Type: $typeAnalysis, Structure: $termAnalysis")

314

315

val structure = showStructure(List(1, 2, 3).map(_ + 1))

316

// Detailed compile-time analysis of expression structure

317

```

318

319

### Macro with Multiple Expression Arguments

320

321

```scala

322

import scala.quoted.*

323

324

inline def benchmark[T](inline iterations: Int, inline code: T): (T, Long) =

325

${ benchmarkImpl('iterations, 'code) }

326

327

def benchmarkImpl[T: Type](iterations: Expr[Int], code: Expr[T])(using Quotes): Expr[(T, Long)] =

328

'{

329

val startTime = System.nanoTime()

330

var result: T = null.asInstanceOf[T]

331

var i = 0

332

while i < $iterations do

333

result = $code

334

i += 1

335

val endTime = System.nanoTime()

336

(result, endTime - startTime)

337

}

338

339

val (result, timeNanos) = benchmark(1000000, math.sqrt(42.0))

340

println(s"Result: $result, Time: ${timeNanos}ns")

341

```

342

343

### Advanced Type Manipulation

344

345

```scala

346

import scala.quoted.*

347

348

inline def createTuple[T, U](x: T, y: U): (T, U) =

349

${ createTupleImpl('x, 'y) }

350

351

def createTupleImpl[T: Type, U: Type](x: Expr[T], y: Expr[U])(using Quotes): Expr[(T, U)] =

352

import quotes.reflect.*

353

354

// Get type representations

355

val tType = TypeRepr.of[T]

356

val uType = TypeRepr.of[U]

357

358

// Create tuple type

359

val tupleType = AppliedType(TypeRepr.of[(_, _)].typeSymbol.typeRef, List(tType, uType))

360

361

'{ ($x, $y) }

362

363

// Advanced: Generate code based on type structure

364

inline def processType[T]: String =

365

${ processTypeImpl[T] }

366

367

def processTypeImpl[T: Type](using Quotes): Expr[String] =

368

import quotes.reflect.*

369

370

val tpe = TypeRepr.of[T]

371

val processing = tpe match

372

case AppliedType(base, List(arg)) if base <:< TypeRepr.of[List[_]] =>

373

s"List processing for element type: ${arg.show}"

374

case AppliedType(base, List(k, v)) if base <:< TypeRepr.of[Map[_, _]] =>

375

s"Map processing for key: ${k.show}, value: ${v.show}"

376

case tpe if tpe <:< TypeRepr.of[Product] =>

377

s"Product type processing: ${tpe.show}"

378

case _ =>

379

s"Generic processing: ${tpe.show}"

380

381

Expr(processing)

382

383

val process1 = processType[List[Int]] // "List processing for element type: Int"

384

val process2 = processType[Map[String, Boolean]] // "Map processing for key: String, value: Boolean"

385

```

386

387

The macro system in Scala 3 provides powerful compile-time metaprogramming capabilities, allowing developers to generate code, perform static analysis, and create domain-specific languages while maintaining type safety and performance.