Assert and Catch

BQN provides some simple facilities for dealing with errors. Errors are an unusual sort of control flow; if possible, prefer to work with functions that return normally.

Assert

BQN takes the position that errors exist to indicate exceptional conditions that the developer of a given program didn't expect. However, the types of errors that BQN naturally checks for, such as mismatched shapes in Couple (≍), aren't always enough to detect exceptional conditions. Issues like numeric values that don't make physical sense will slip right through. BQN makes it easy for a programmer to check for these sorts of problems by building in the primitive Assert, written !. This function checks whether 𝕩 matches 1: if it does, then it does nothing and returns 𝕩, and otherwise it gives an error.

↗️
    ! 2=2  # Passed
1

    ! 2=3  # Failed
Error: Assertion error

To pass, the right argument must be exactly the number 1; any other value causes an error. For example, an array of 1s still causes an error; use ∧´⥊ to convert a boolean array to a single boolean that indicates whether all of its values are true.

↗️
    ! (∧=∨⌾¬)⌜˜ ↕2
Error: 2‿2⥊1‿1‿1‿1

    ! ∧´⥊ (∧=∨⌾¬)⌜˜ ↕2
1

Assert can take a left argument, which gives a message to be associated with the error. It's typical to use a string for 𝕨 in order to display it to the programmer, but 𝕨 can be any value.

↗️
    "Message" ! 0
Error: Message

    ⟨∘,"abc",˜⟩ ! '0'
Error: ⟨∘,"abc",˜⟩

In the 1-argument case, 𝕩 is used for the error message if it's not 1. So an unconditional error can also be written this way:

↗️
    ! "Message"
Error: Message

Computing the error message on demand

Because the left argument to a function is always computed before the function is called, Assert doesn't let you compute the error message only if there's an error. This might be a problem if the error message computation is slow or has side effects. There are a few ways to work around the issue:

Catch

The Catch modifier allows you to handle errors in BQN (at present, it's the only way to do so). It evaluates the function 𝔽 normally. If this function completes without an error, Catch just returns that result. If not, it stops the error, and calls 𝔾 with the original arguments instead.

↗️
    ⌽⎊'x' "abcd"  # No error
"dcba"

    ⌽⎊'x' 2       # Can't reverse a unit
'x'

    0.5 ⌽⎊⊣ ↕6    # A two-argument example
0.5

Catch doesn't know anything about what an error is, just whether there was one or not. In fact, the idea of an error message doesn't feature at all in core BQN: it's purely part of the language environment. So you need a system value to access information about the error. Right now the only one is •CurrentError, which is a function that returns a message for the error currently caught (if any).

↗️
    ⌽⎊•CurrentError 2
"⌽: Argument cannot be a unit"