| 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).* |
| 1 | + | #REDIRECT [[Enum type]] |