| bc-version |
domain |
keywords |
technologies |
countries |
application-area |
|
|
style |
| enum |
| option |
| integer |
| magic-number |
| variable-typing |
| field-typing |
|
|
|
|
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
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
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.