Conditionals: if, else, and select
WebAssembly’s if construct is both a control-flow branch and an expression. It pops an i32 condition from the stack, executes one of two arms, and — if given a result type — leaves a value on the stack. This makes if feel more like a ternary operator than a traditional if statement.
The if construct
Section titled “The if construct”if pops the top i32. A non-zero value executes the then arm; zero executes the optional else arm. The construct ends with end.
(module (func (export "sign") (param $x i32) (result i32) local.get $x i32.const 0 i32.gt_s ;; x > 0? if (result i32) i32.const 1 ;; then: return 1 else i32.const -1 ;; else: return -1 end))The (result i32) annotation declares that the if expression leaves one i32 on the stack regardless of which arm executes. Both arms must leave the same number and types of values.
if without a result
Section titled “if without a result”When the condition is purely for side effects — for example calling an imported function — you can omit the result type:
(module (func (export "clampNeg") (param $x i32) (result i32) local.get $x i32.const 0 i32.lt_s if i32.const 0 local.set $x ;; clamp $x to 0 if negative end local.get $x))Here the if has no result; it just conditionally updates a local.
select: branchless ternary
Section titled “select: branchless ternary”select is a compact alternative to if for simple value choices. It pops three values: condition, val_if_false, val_if_true (in push order: push true-val, push false-val, push condition). It pushes the chosen value. No branch is taken — the CPU evaluates both values before the select.
(module (func (export "minVal") (param $a i32) (param $b i32) (result i32) local.get $a ;; val if condition is true ($a <= $b) local.get $b ;; val if condition is false local.get $a local.get $b i32.le_s ;; condition: a <= b? select)) ;; choose $a if true, $b if false