Skip to content

Compile Time Evaluation

Chris Michael edited this page Sep 2, 2026 · 2 revisions

Pudu

Compile-Time Evaluation

const requires a value during compilation. comptime fn names code permitted to participate in that evaluation under a restricted effect boundary.

comptime fn square(value: Int) -> Int {
  value * value
}

const AREA = square(6)

AREA is computed while the module is compiled. A failure in its initializer is a compile diagnostic, not a deferred runtime event.

One evaluator, fewer effects

Compile-time execution uses the ordinary Pudu evaluator with a restricted context. It denies IO, environment access, time, randomness, unsafe operations, and tasks. Arithmetic, control flow, local data, and approved pure operations retain their ordinary language meaning.

This arrangement avoids a second expression language for constants. It also means that an operation's availability at compile time is a checked property; it is not inferred from whether a particular run happened to avoid an effect.

Declaration rules

A compile-time function cannot also be async or unsafe. The static call check permits direct unqualified calls to named comptime functions and approved built-ins.

comptime fn triangular(value: Int) -> Int {
  var index = 0
  var total = 0
  while index <= value {
    total = total + index
    index = index + 1
  }
  total
}

const TEN = triangular(4)

A comptime fn remains callable from ordinary runtime code. The marker adds permission for the restricted evaluator; it does not confine the function to compilation.

Order and failure

Module constants are evaluated in declaration order. An initializer that reads a later constant is diagnosed. Arithmetic failure, invalid operations, explicit panic, and exhausted evaluation limits are likewise reported during compilation.

The evaluator currently limits loop steps and call depth. There is no compile-time memory budget. Documentation and diagnostics should name the implemented limits precisely because “resource limited” does not imply accounting that does not exist.

Higher-order boundary

Ordinary function types retain async shape but do not retain comptime metadata. The static checker therefore recognizes direct named calls only; an alias or higher-order call is not checked transitively as a compile-time capability.

The restricted evaluator still denies runtime effects if an indirect call reaches one during constant folding. That runtime denial is a useful backstop, but it does not replace capability- bearing function types or transitive static checking. Those are not implemented.

Constants and macros

Constants compute values. Macros transform parsed syntax before ordinary checking. Use a constant or compile-time function when the result is a value in the language; use a macro only when the result must be a new syntactic form.

Related

Clone this wiki locally