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`.