Enum type: what changed
Revision 2 to 3. Removed lines have a minus sign; added lines have a plus sign.
Title: Enum Type Enum type
| Old | New | Line | |
|---|---|---|---|
| 1 | - | ||
| 1 | + | An **enumeration** is a custom [[Data type|data type]] in [[Pascal]]. It is a discrete value that can be referred to by a unique [[Identifier|identifier]]. | |
| 2 | + | ||
| 3 | + | ## Definition | |
| 4 | + | ||
| 5 | + | ### Basic | |
| 6 | + | ||
| 7 | + | An enumeration is defined by surrounding a non-empty [[Comma|comma]]-separated list of identifiers that were not yet defined in the current [[Scope|scope]] with parentheses: | |
| 8 | + | ||
| 9 | + | ``` pascal | |
| 10 | + | program enumerationDemo(input, output, stdErr); | |
| 11 | + | type | |
| 12 | + | fruit = (apple, banana, citrus); | |
| 13 | + | ``` | |
| 14 | + | ||
| 15 | + | Thus, a variable of the [[Type|type]] `fruit` may assume the values `apple`, `banana`, or `citrus`. | |
| 16 | + | ||
| 17 | + | ``` pascal | |
| 18 | + | var | |
| 19 | + | snack: fruit; | |
| 20 | + | begin | |
| 21 | + | snack := apple; | |
| 22 | + | end. | |
| 23 | + | ``` | |
| 24 | + | ||
| 25 | + | ### Indices | |
| 26 | + | ||
| 27 | + | Every member of an enumerated type has an ordinal value which can be obtained using the [[Ord|standard function ord]]. The first member of any enumeration has the ordinal value zero, and every following member is enumerated with consecutive numbers. | |
| 28 | + | ||
| 29 | + | #### Override | |
| 30 | + | ||
| 31 | + | In some cases, however, it would be quite useful if the ordinal values were different. The [[FPC]] allows [[Delphi]]-style explicit definition of indices by following member identifiers with an [[=|equal sign]] and an [[Integer|integer]] value: | |
| 32 | + | ||
| 33 | + | ``` pascal | |
| 34 | + | type | |
| 35 | + | sign = (negative = -1, none = 0, positive = 1); | |
| 36 | + | ``` | |
| 37 | + | ||
| 38 | + | It is not necessary to define *all* members with an explicit ordinal value, this example *just happens* to define all of them. If the ordinal value is unspecified, the automatic enumeration mechanism applies again. | |
| 39 | + | ||
| 40 | + | #### Properties | |
| 41 | + | ||
| 42 | + | - An enumeration data type definition is *ascending* if the difference in ordinal value to every right-hand member is ≥ 1. Currently, non-ascending definitions merely [emit a note](https://gitlab.com/freepascal.org/fpc/source/-/tree/release_3_2_2/compiler/ptype.pas#L1700-1706). A `set` literal using two enumeration values having the *same* ordinal value, albeit represented by *different* symbols, will not be accepted. | |
| 43 | + | - An enumeration data type is *contiguous* if the ordinal value of every (named) member has an absolute difference of *one* to its neighbors. Using a `set` constructor on a non-contiguous enumeration data type may produce unexpected results. | |
| 44 | + | - An enumeration data type is *normal* if it is ascending and contiguous and the first member has an ordinal value of (strictly speaking) *zero*, or, in the broad sense (as implemented by the FPC), ≤ 0. The compiler intrinsic `typeInfo` is *only* available for *those* enumeration data types. | |
| 45 | + | ||
| 46 | + | ### Prefixing | |
| 47 | + | ||
| 48 | + | FPC prefixes all members of enumeration type definitions in the `type` section with their corresponding type name. By default, the short name *without* a prefix is inserted into the symbol table as an *alias* in order to meet Pascal standards. | |
| 49 | + | ||
| 50 | + | [[FPC New Features 2.6.0|Since version 2.6.0 FPC]] supports disabling member identifiers from being aliased by using the `{$scopedEnums on}` [[local compiler directives|local compiler directive]], thus requiring users to always specify the type name as a prefix: | |
| 51 | + | ||
| 52 | + | ``` pascal | |
| 53 | + | program scopedEnumerationDemo(input, output, stdErr); | |
| 54 | + | type | |
| 55 | + | {$scopedEnums on} | |
| 56 | + | logLevel = (error, warning, info, debug); | |
| 57 | + | var | |
| 58 | + | verbosity: logLevel; | |
| 59 | + | begin | |
| 60 | + | verbosity := logLevel.debug; | |
| 61 | + | end. | |
| 62 | + | ``` | |
| 63 | + | ||
| 64 | + | This setting only affects definition of *new* enumeration data types. If the compiler switch `{$scopedEnums …}` was *on* during definition of a enumeration type, you have to precede any values of that enumeration type with the data type’s name and a dot (in the example above this means `logLevel.`). | |
| 65 | + | ||
| 66 | + | This is useful if names are likely to clash with other identifiers, for example [`sysUtils.tUseBoolStrs`](https://www.freepascal.org/docs-html/rtl/sysutils/tuseboolstrs.html) is defined in that way (with `{$scopedEnums on}`), or if isolate identifiers would be meaningless or confusing like in [`objPas.tEndian`](https://www.freepascal.org/docs-html/rtl/objpas/tendian.html). Usage introduces some incompatibility to other compilers though. | |
| 67 | + | ||
| 68 | + | ## Size | |
| 69 | + | ||
| 70 | + | The size an enumeration type occupies depends on | |
| 71 | + | ||
| 72 | + | 1. the *minimum enumeration size* compiler configuration, and | |
| 73 | + | 2. the range, that is `ord(high(enumeration)) - ord(low(enumeration))`. | |
| 74 | + | ||
| 75 | + | The local compiler directive `{$minEnumSize n}` determines the minimum size in [[Byte|Bytes]] of an enumeration data type. `{$minEnumSize n}` is (for Delphi compatibility) an alias for `{$packEnum n}`/`{$Z}`. | |
| 76 | + | ||
| 77 | + | - `{$minEnumSize 1}`, `{$packEnum 1}`, `{$Z1}` or `{$Z‑}` instructs the compiler to use just one Byte (at least) for the enumeration type in question. | |
| 78 | + | - `{$minEnumSize 2}`, `{$packEnum 2}` and `{$Z2}`: 2 Bytes minimum. | |
| 79 | + | - `{$minEnumSize 4}`, `{$packEnum 4}`, `{$Z4}` or `{$Z+}`: use at least 4 Bytes. | |
| 80 | + | ||
| 81 | + | Furthermore, `{$minEnumSize normal}`, `{$minEnumSize default}` and `{$minEnumSize 0}` restores the default value. In [[Mode TP|{$mode TP}]] the default value is `1` whereas in all other modes it is `4`. Such a “large” minimum size aids quick read/write access. | |
| 82 | + | ||
| 83 | + | It stands to reason that an enumeration data type has to occupy at least as much space as all discrete values require to be stored. When there are 2<sup>8</sup> (256) or fewer elements to be stored, the compiler may store a variable of this kind as a single Byte. A range of 2<sup>16</sup> elements will be stored in two Bytes if a single Byte is insufficient. More than 2<sup>16</sup> members will be stored in four Bytes. These rules may, of course, be superseded by the previously mentioned `{$minEnumSize}` setting. | |
| 84 | + | ||
| 85 | + | ## Application | |
| 86 | + | ||
| 87 | + | ### Out-of-the-box functionality | |
| 88 | + | ||
| 89 | + | - The pre-defined data type [[Boolean]] is an enumeration data type. | |
| 90 | + | - The functions `low` and `high` will give the lowest or highest available *named* item of an enumeration data type. | |
| 91 | + | - The standard functions `pred` and `succ` return the predecessor and successor of a value. In non-Delphi modes this functionality is disabled if the enumeration data type is non-contiguous. Note that range checks may trigger [[runtime error|run-time errors]]. | |
| 92 | + | ||
| 93 | + | ### Masks | |
| 94 | + | ||
| 95 | + | Enumeration data types are particularly useful for implementing “masks”: By defining a [[Set|set of …]] you have a neat data type fulfilling certain nice properties. | |
| 96 | + | ||
| 97 | + | ## Comparative remarks | |
| 98 | + | ||
| 99 | + | In some programming languages enumeration type definitions become “synonyms” to certain integer values. In Pascal, however, this is not the case. You may not mix a symbol referring to a member of an enumeration with other integer values. You will have to utilize `ord` or an [[Typecast|explicit typecast]] to the enumeration data type. | |
| 100 | + | ||
| 101 | + | ## See also | |
| 102 | + | ||
| 103 | + | - [[Basic Pascal Tutorial/Chapter 5/Enumerated types|Enumerated types]] in the [[Basic Pascal Tutorial]] series | |
| 104 | + | ||
| 105 | + | --- | |
| 106 | + | *From the Free Pascal wiki, page "Enum type", as it stood on 2023-12-22 after a change by Alextpp, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).* |
