Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Parameters and defaults

Parameters

Every parameter has a name and a type:

macro show_sum(a: int, b: int) {
    @emit a + b
}

show_sum 2, 3
5

Arguments are matched to parameters by position. Named arguments like f(b = 1) are only for constructing structs, not for calling macros.

Arguments are type-checked

Each argument must already have its parameter’s type. Nothing is converted automatically, even when a conversion exists:

from std.binary import bits

macro emit_byte(b: bits<8>) {
    @emit b
}

emit_byte 65
type mismatch for `b`: expected `bits<8>`, found `int`

Convert explicitly with as:

from std.binary import bits

macro emit_byte(b: bits<8>) {
    @emit b
}

emit_byte 65 as bits<8>
bits<8> { value: 65 }

Defaults

Parameters at the end of the list can have a default value, used when the call leaves them out:

macro encode(value: int, width: int = 8, mask: int = (1 << width) - 1) {
    @emit value & mask
}

encode 0x1ff
encode 0x1ff, 4
255 15
  • A default can use earlier parameters. Defaults are evaluated left to right at each call, so mask above sees whichever width the call ended up with.
  • Once one parameter has a default, every parameter after it needs one too.

Unused parameters

An unused parameter triggers the unused_parameter warning. If it’s unused on purpose, for example because only its type matters for overloading, start its name with an underscore:

macro kind(_value: int) {
    @emit 1
}

kind 42
1