/
06.05.2025 at 05:13 pm
Cuttings

Nim / Exercise - `assertPositive(expr)` macro

Check if the expression is > 0.

Check for a positive value.

If not positive, fail at runtime with a helpful message.

let x = -5    
 assertPositive(x + 3)  
# Runtime error: expected x + 3 to be > 0

Hint: Inside the macro, build an if block using quote do (with when or if).

  1. The insight for you: quote do generates the if-code, but does not run it.

  2. When you write quote do, it builds the code and inserts it where the macro is called. if only runs when the program runs - not when the macro is expanding.

  3. While the macro appears to be evaluating a runtime if-check, it isn't:

    • Instead, the macro injects an if statement into the place where the macro is used (by the quote do part).

    • The macro does not evaluate the expression at compile time.

    • The if check is evaluated later, at runtime - because x is not known at compile time.

  4. Don't use when to check if the expression is > 0 at runtime - use if inside the quote do. Why not when?

    • if works for runtime evaluation.

    • when only works for things known at compile time.

    • Thus something like this:

      `when `expr` <= 0:`
      

      will fail unless expr is a compile-time constant (like const y = -2). > 0. Here's when when would be appropriate:

      const y = 3

      when y > 0: echo "Compile-time check: y is positive" else:

    (The {.error: "text".} part above is a compile-time pragma in Nim, which triggers a compile-time error.)

  5. Be mindful of the difference between quote do: and just result = quote do:.

Code (SolutiON)
     import macros

macro assertPositive(expr: untyped): untyped =
  # GENERATE the code, not do an evaluation
  quote do:
    if `expr` <= 0:
      raise newException(
        ValueError,
        "expected " & astToStr(`expr`) & " to be > 0, got instead: " & $`expr`,
      )
    # echo astToStr(`expr`) # Shows the expression
    # echo `expr` # Shows the evaluated expression

# macro assertPositiveWhen(expr: untyped): untyped = 
# NOT POSSIBLE with problem

let x = -5
assertPositive(x + 9)
# assertPositive(x + 2) # Compare to this

                    
Source: Nim Macros - Beginner & Intermediate Exercises
Filed under:
#
#
Words: 244 words approx.
Time to read: 0.98 mins (at 250 wpm)
Keywords:
, , , , , , , , ,

Potentially related:
  1. A Basic Nim Workflow To Metaprogramming/Macros
  2. Nim / Exercise - `timed(expr)` macro
  3. Nim / Exercise - `swap(a, b)` macro
  4. Nim / Exercise - Make a `logvars(a, b, c)` macro

Latest Comments

© Wan Zafran. See disclaimer.