diff --git a/custom/knowledge/style/fixed-choice-set-must-use-enum-not-integer.md b/custom/knowledge/style/fixed-choice-set-must-use-enum-not-integer.md new file mode 100644 index 0000000..04bc6a4 --- /dev/null +++ b/custom/knowledge/style/fixed-choice-set-must-use-enum-not-integer.md @@ -0,0 +1,74 @@ +--- +bc-version: [all] +domain: style +keywords: [enum, option, integer, magic-number, variable-typing, field-typing] +technologies: [al] +countries: [w1] +application-area: [all] +--- + +# A fixed set of named choices must use Enum, not a raw Integer + +## Description + +When a variable or field can only take on a fixed set of more than two +named, mutually exclusive states — a difficulty level, a document type, a +processing status — it must be typed as `Enum` (or `Option` when extending +an object that still uses the legacy type). Representing that same state +as a plain `Integer` and tracking the meaning of each value in a comment or +in the developer's head (`1 = Beginner, 2 = Intermediate, 3 = Advanced`) is a +magic-number anti-pattern: the compiler cannot catch an out-of-range value, +`CASE`/`IF` branches read as opaque numbers instead of names, and every call +site must either duplicate the numbering or trust a comment that can go +stale. + +This is distinct from a true two-state choice — see +[[binary-choice-must-be-boolean]] — which should be `Boolean`, not an +`Enum`/`Option` with two members. The line is the state count: more than +two named states is an enumeration question, not a Boolean one. + +## Best Practice + +```al +enum 50100 "Course Difficulty" +{ + Extensible = true; + value(0; Beginner) { } + value(1; Intermediate) { } + value(2; Advanced) { } +} + +field(50; Difficulty; Enum "Course Difficulty") +{ +} +... +case Difficulty of + "Course Difficulty"::Beginner: + Level := 'Beginner'; + "Course Difficulty"::Intermediate: + Level := 'Intermediate'; + "Course Difficulty"::Advanced: + Level := 'Advanced'; +end; +``` + +## Anti Pattern + +```al +field(50; Difficulty; Integer) +{ +} +... +// 1 = Beginner, 2..5 = Intermediate boundary is fuzzy, 6+ = Advanced? +case Difficulty of + 1: + Level := 'Beginner'; + 2, 3: + Level := 'Intermediate'; +end; +``` + +A raw `Integer` standing in for a named set of states pushes the +documentation of what each value means into a comment, a wiki page, or a +developer's memory — none of which the compiler or a future maintainer can +rely on.