From f7a00bf0b6be33d88230d3e0e2b1d119270590ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B3nio=20Silva?= Date: Tue, 25 Aug 2026 12:05:29 +0100 Subject: [PATCH] Comma-group the pure value sets in the case false of sample MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review feedback: the five value sets sharing exit(false) should be comma separated. Applied to the three that are pure field reads with no order dependency. The Get and the Blocked read keep their own value sets. The documentation guarantees that the first matching value set executes, which orders matching across separate value sets; it says nothing about evaluation within one comma-separated set, and the natural lowering of that is an equality-or chain — where AL's or does not short-circuit. Grouping the Get with the checks that must precede it would rest the sample's correctness on undocumented behaviour, which is the defect these two articles exist to prevent. Encodes the boundary in the Best Practice section so the grouping is applied where it is safe and not where it is not, and scopes the repeated-exit detection signal explicitly to nested chains so the case sample does not read as its own anti-pattern. Co-Authored-By: Claude Opus 5 --- ...ase-true-of-for-long-condition-chains.good.al | 16 ++++++++++------ .../case-true-of-for-long-condition-chains.md | 4 ++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/community/knowledge/performance/case-true-of-for-long-condition-chains.good.al b/community/knowledge/performance/case-true-of-for-long-condition-chains.good.al index 61b2f09..57d7f5a 100644 --- a/community/knowledge/performance/case-true-of-for-long-condition-chains.good.al +++ b/community/knowledge/performance/case-true-of-for-long-condition-chains.good.al @@ -4,16 +4,20 @@ codeunit 50542 "Perf Sample CaseChain Good" var Item: Record Item; begin - // 'case false of' evaluates the value sets in order and stops at the first - // match, so each condition is reached only when the previous one passed — + // 'case false of' matches the value sets in order and stops at the first + // match, so each value set is reached only when the previous one passed — // and Item.Get is never called for a non-item line. case false of - (SalesLine.Type = SalesLine.Type::Item): - exit(false); - (SalesLine."No." <> ''): - exit(false); + // Pure field reads with no side effects and no order dependency, so + // they share one value set and one action. + (SalesLine.Type = SalesLine.Type::Item), + (SalesLine."No." <> ''), (SalesLine."Qty. to Ship" > 0): exit(false); + // These two keep their own value sets even though the action repeats: + // ordering across separate value sets is what the documentation + // guarantees. The Get must not run until the checks above pass, and + // Blocked must not be read until the Get succeeded. Item.Get(SalesLine."No."): exit(false); (not Item.Blocked): diff --git a/community/knowledge/performance/case-true-of-for-long-condition-chains.md b/community/knowledge/performance/case-true-of-for-long-condition-chains.md index ecaabc9..0304e14 100644 --- a/community/knowledge/performance/case-true-of-for-long-condition-chains.md +++ b/community/knowledge/performance/case-true-of-for-long-condition-chains.md @@ -15,13 +15,13 @@ Because AL gives no short-circuit guarantee for `and` and `or`, a chain of condi ## Best Practice -Sequence two or three dependent conditions with nested `if`. Beyond that, switch to `case`: use `case false of` for a chain of guards where every condition must hold, listing the failure action per condition and letting control fall past `end` when all pass; use `case true of` for first-match dispatch, where each later probe runs only if the earlier ones did not match. This keeps every condition at one indentation level, makes evaluation order explicit rather than implied by nesting, and preserves the stop-at-first-match behaviour. It also aligns with the AL programming convention that more than two alternatives belong in a `case` statement rather than an `if-then-else`. +Sequence two or three dependent conditions with nested `if`. Beyond that, switch to `case`: use `case false of` for a chain of guards where every condition must hold, listing the failure action per condition and letting control fall past `end` when all pass; use `case true of` for first-match dispatch, where each later probe runs only if the earlier ones did not match. Value sets that share an action may be comma-separated into one value set, but only when each is a pure, order-independent test — a field comparison or an enum check. A condition with a side effect, or one that is only safe after an earlier condition passed, keeps its own value set even when its action repeats, because ordered matching is guaranteed *across* value sets, not within one. This keeps every condition at one indentation level, makes evaluation order explicit rather than implied by nesting, and preserves the stop-at-first-match behaviour. It also aligns with the AL programming convention that more than two alternatives belong in a `case` statement rather than an `if-then-else`. See sample: `case-true-of-for-long-condition-chains.good.al`. ## Anti Pattern -An `if` ladder four or more levels deep whose only purpose is sequencing guards. Detection: a chain of nested `if` statements with no `else`, each condition guarding the one below it, terminating in a single action or `exit`; or the same `exit`/`error` duplicated at every level of such a chain. The second, worse form is collapsing that ladder into one `and` chain to escape the nesting — that trades indentation for a real defect, because the operands are still all evaluated. Reach for `case` instead of either. +An `if` ladder four or more levels deep whose only purpose is sequencing guards. Detection: a chain of nested `if` statements with no `else`, each condition guarding the one below it, terminating in a single action or `exit`; or the same `exit`/`error` duplicated at every level of such a nested chain, purely to escape it. The second, worse form is collapsing that ladder into one `and` chain to escape the nesting — that trades indentation for a real defect, because the operands are still all evaluated. Reach for `case` instead of either. See sample: `case-true-of-for-long-condition-chains.bad.al`.