Two weird patterns that just might make your AL code faster?

In this video, I showcase two ways to get short-cut evaluations from AL without nested if statements. Check out the video:

https://youtu.be/AsxrylyfcTw

In this video, Erik revisits a topic he covered previously — the fact that AL is not a “lazy” language, meaning it doesn’t use short-circuit evaluation. He explores two unconventional patterns, originally highlighted by Natalie Karolak on Twitter, that can emulate short-circuit behavior and potentially speed up your AL code significantly.

The Problem: AL Doesn’t Short-Circuit

In most programming languages, if you write if A or B or C then and A evaluates to the matching condition, the runtime won’t bother evaluating B or C. This is called short-circuit evaluation. AL, however, evaluates all conditions regardless of whether the result is already determined.

To demonstrate, Erik sets up three condition functions. The first returns false instantly, while the second and third each sleep for 5 seconds before returning false:

procedure Condition1(): Boolean
begin
    exit(false);
end;

procedure Condition2(): Boolean
begin
    Sleep(5000);
    exit(False);
end;

procedure Condition3(): boolean
begin
    Sleep(5000);
    exit(false);
end;

When you write a standard if statement like if not Condition1() or not Condition2() or not Condition3() then, AL evaluates all three conditions even though Condition1() already returns false (meaning not Condition1() is true, which should be enough to satisfy the or). The result? A 10-second wait — 5 seconds for each unnecessary evaluation.

Weird Pattern #1: The in Statement

The first pattern uses AL’s in operator with a list of expressions:

if false in [Condition1(), Condition2(), Condition3()] then
    message('No!! (%1)', time() - starttime);

This looks strange at first glance, but it works — and it runs in about 1 millisecond instead of 10 seconds.

Here’s why: In Pascal, the in operator works with a list of constants. But in AL, these are expressions that get evaluated at runtime. The key difference is that when evaluating an in statement, if there’s a hit on one of the expressions, the runtime stops evaluating the rest. Since Condition1() returns false and we’re checking if false is in the list, it matches immediately — and Condition2() and Condition3() are never called.

Weird Pattern #2: The case Statement

The second pattern uses a case statement to achieve the same effect. You wrap your conditions in a case false of block:

procedure test(): boolean;
begin
    case false of
        Condition1():
            exit(true);
        Condition2():
            exit(true);
        Condition3():
            exit(true);
    end;
end;

This also runs nearly instantly because the case statement evaluates expressions sequentially. When Condition1() returns false and matches the case false of, it exits immediately without evaluating the remaining conditions.

However, order matters. If you put Condition3() first, it will be evaluated first — and that means a 5-second wait before moving on. So while the case approach can still be faster than the naive if/or approach (you might only hit one slow condition instead of all of them), the order of your conditions is critical.

Why Not Just Use Nested Ifs?

Erik points out that the classic nested if approach also works perfectly well:

if not Condition1() then
    if not Condition2() then
        if not Condition3() then
            message('No!!');

This gives you explicit short-circuit behavior since each condition is only evaluated if the previous one didn’t satisfy the overall check. Erik notes that there’s a general aversion to nested if statements in the programming world, but he doesn’t think they should be feared — sometimes they’re the clearest way to express the logic.

The Full Source Code

Here’s the complete page extension Erik used for the demonstration:

pageextension 50100 CustomerListExt extends "Customer List"
{
    trigger OnOpenPage();
    var
        starttime: Time;
    begin
        starttime := Time();

        if false in [Condition1(), Condition2(), Condition3()] then
            message('No!! (%1)', time() - starttime);
    end;

    procedure Condition1(): Boolean
    begin
        exit(false);
    end;

    procedure Condition2(): Boolean
    begin
        Sleep(5000);
        exit(False);
    end;

    procedure Condition3(): boolean
    begin
        Sleep(5000);
        exit(false);
    end;
}

AL Is Not Pascal

A recurring theme in this video is that while AL and Pascal share a great overlap in syntax, there are significant differences in execution and behavior. The in operator and case statement both accept expressions in AL, not just constants as in Pascal. This subtle difference is what makes these patterns possible. As Erik notes from his experience building an AL compiler/interpreter for his toolbox app, understanding how AL actually behaves — rather than assuming it works like Pascal — is essential.

Summary

If you have expensive conditions in your AL code connected by or operators, be aware that AL will evaluate all of them regardless of whether the result is already determined. Two patterns can help:

  1. The in pattern: if false in [Condition1(), Condition2(), Condition3()] — Erik’s preferred approach for readability.
  2. The case pattern: case false of Condition1(): ... Condition2(): ... — functional but feels less natural.

Both exploit the fact that AL evaluates expressions in these constructs sequentially and stops on a match. And of course, plain nested if statements remain a perfectly valid — and perhaps the most explicit — alternative. The key takeaway: put your fastest conditions first so the expensive ones are only evaluated when truly necessary.

And be sure to follow Natalie Karolak on Twitter — she has an amazing talent for spotting when Microsoft changes things in the documentation and is a constant source of useful information for the AL community.