Difference between revisions of "Enum type"

From Free Pascal wiki
Jump to navigationJump to search
(→‎Memory requirement: Added table)
m (Alextpp moved page Enum Type to Enum type: proper casing)
 
(16 intermediate revisions by 4 users not shown)
Line 1: Line 1:
{{Enum_Type}}
+
{{Enum Type}}
  
 +
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]].
  
Back to [[Data_type|data types]].
+
== Definition ==
 +
=== Basic ===
 +
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:
 +
<syntaxhighlight lang="pascal" highlight="3" line>
 +
program enumerationDemo(input, output, stdErr);
 +
type
 +
fruit = (apple, banana, citrus);
 +
</syntaxhighlight>
 +
Thus, a variable of the [[Type|type]] <syntaxhighlight lang="pascal" inline>fruit</syntaxhighlight> may assume the values <syntaxhighlight lang="pascal" inline>apple</syntaxhighlight>, <syntaxhighlight lang="pascal" inline>banana</syntaxhighlight>, or <syntaxhighlight lang="pascal" inline>citrus</syntaxhighlight>.
 +
<syntaxhighlight lang="pascal" highlight="4" line start="4">
 +
var
 +
snack: fruit;
 +
begin
 +
snack := apple;
 +
end.
 +
</syntaxhighlight>
  
 +
=== Indices ===
 +
Every member of an enumerated type has an ordinal value which can be obtained using the [[Ord|standard function <syntaxhighlight lang="pascal" inline>ord</syntaxhighlight>]].
 +
The first member of any enumeration has the ordinal value zero, and every following member is enumerated with consecutive numbers.
  
== Range ==
+
==== Override ====
 
+
In some cases, however, it would be quite useful if the ordinal values were different.
* with 0 .. 255 characters, the data type is automatically [[Byte]]
+
The [[FPC]] allows [[Delphi]]-style explicit definition of indices by following member identifiers with an [[=|equal sign]] and an [[Integer|integer]] value:
* with 255 .. 65,535 characters, the data type is automatically [[Word]]
+
<syntaxhighlight lang="pascal" highlight="2">
* over 65,535 characters, the data type is automatically [[Longword]]
+
type
 
+
sign = (negative = -1, none = 0, positive = 1);
== Memory requirement ==
+
</syntaxhighlight>
 
+
It is not necessary to define ''all'' members with an explicit ordinal value, this example ''just happens'' to define all of them.
This depends on the [[Data type|data type]] and the number of elements. By default, an enumeration is stored in a Longword and requires 4 bytes. Depending on if a switch is used, {$PACKENUM x} (abbreviated {$Zx}) and the value range of the data type, it can be adjusted.
+
If the ordinal value is unspecified, the automatic enumeration mechanism applies again.
 
 
{| class="wikitable"
 
|+Memory requirements
 
|-
 
| Maximum value range
 
| <= 255
 
| <= 65,535
 
| > 65,535
 
|-
 
| No switch or {$PACKENUM DEFAULT}<br/> or {$PACKENUM 4} or {$Z4}
 
| 4
 
| 4
 
| 4
 
|-
 
|{$PACKENUM 2} or {$Z2}
 
| 2
 
| 2
 
| 4
 
|-
 
|{$PACKENUM 1} or {$Z1}
 
| 1
 
| 2
 
| 4
 
|}
 
 
 
== Properties ==
 
 
 
The data type '''Enum Type''' is an enumeration of unsigned constants.  
 
 
 
In addition, the unsigned integer data type to be used can be specified for the data type using a switch.
 
 
 
* at 0 .. 255 characters the switch for the byte data type:
 
** {$Z1} or {$ PACKENUM 1}
 
 
 
* at 255 .. 65535 characters the switch for the Word data type:
 
** {$Z2} or {$ PACKENUM 2}
 
 
 
* at 65535 .. 4294967295 characters the switch for the LongWord data type:
 
** {$Z4} or {$ PACKENUM 4}
 
 
 
The values ​​of the enumeration always increase by 1 to the next element.
 
 
 
== Examples ==
 
  
=== Examples of declaring the Enum data type ===
+
==== Properties ====
 +
* An enumeration data type definition is ''ascending'' if the difference in ordinal value to every right-hand member is&nbsp;≥&nbsp;1. Currently, non-ascending definitions merely {{gitlab|repository|FPC|release_3_2_2/compiler/ptype.pas#L1700-1706|emit a note}}. A <syntaxhighlight lang="pascal" inline>set</syntaxhighlight> literal using two enumeration values having the ''same'' ordinal value, albeit represented by ''different'' symbols, will not be accepted.
 +
* 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 <syntaxhighlight lang="pascal" inline>set</syntaxhighlight> constructor on a non-contiguous enumeration data type may produce unexpected results.
 +
* 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),&nbsp;≤&nbsp;0. The compiler intrinsic <syntaxhighlight lang="delphi" inline>typeInfo</syntaxhighlight> is ''only'' available for ''those'' enumeration data types.
  
The values ​​of the enumeration start at 0 by default:
+
=== Prefixing ===
 +
FPC prefixes all members of enumeration type definitions in the <syntaxhighlight lang="pascal" inline>type</syntaxhighlight> 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.
  
<syntaxhighlight lang=pascal>
+
[[FPC New Features 2.6.0#Scoped enumerations|Since version 2.6.0 FPC]] supports disabling member identifiers from being aliased by using the <syntaxhighlight lang="pascal" inline>{$scopedEnums on}</syntaxhighlight> [[local compiler directives|local compiler directive]], thus requiring users to always specify the type name as a prefix:
  Type
+
<syntaxhighlight lang="pascal" highlight="3,4,8">
  {$PACKENUM 2}
+
program scopedEnumerationDemo(input, output, stdErr);
  LargeEnum = (zero, one, two);
+
type
 +
{$scopedEnums on}
 +
logLevel = (error, warning, info, debug);
 +
var
 +
verbosity: logLevel;
 +
begin
 +
verbosity := logLevel.debug;
 +
end.
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
This setting only affects definition of ''new'' enumeration data types.
 +
If the compiler switch <syntaxhighlight lang="pascal" inline>{$scopedEnums …}</syntaxhighlight> 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 <syntaxhighlight lang="pascal" inline>logLevel.</syntaxhighlight>).
  
By default, the values ​​of the enumeration start at 0, unless the enumeration is assigned a different starting value. Then the count starts with the assigned initial value.
+
This is useful if names are likely to clash with other identifiers, for example {{Doc|package=RTL|unit=sysutils|identifier=tuseboolstrs|text=<syntaxhighlight lang="pascal" inline>sysUtils.tUseBoolStrs</syntaxhighlight>}} is defined in that way (with <syntaxhighlight lang="pascal" inline>{$scopedEnums on}</syntaxhighlight>), or if isolate identifiers would be meaningless or confusing like in {{Doc|package=RTL|unit=objpas|identifier=tendian|text=<syntaxhighlight lang="pascal" inline>objPas.tEndian</syntaxhighlight>}}.
 +
Usage introduces some incompatibility to other compilers though.
  
<syntaxhighlight lang=pascal>
+
== Size ==
  Type
+
The size an enumeration type occupies depends on
  {$PACKENUM 4}
+
# the ''minimum enumeration size'' compiler configuration, and
  SmallEnum = (Six := 6, Seven, Eight);
+
# the range, that is <syntaxhighlight lang="pascal" inline>ord(high(enumeration)) - ord(low(enumeration))</syntaxhighlight>.
</syntaxhighlight>
 
  
If a higher value is assigned to an element in the middle of the enumeration, counting continues from this value.
+
The local compiler directive <syntaxhighlight lang="pascal" inline>{$minEnumSize n}</syntaxhighlight> determines the minimum size in [[Byte|Bytes]] of an enumeration data type.
 +
<syntaxhighlight lang="pascal" inline>{$minEnumSize n}</syntaxhighlight> is (for Delphi compatibility) an alias for <syntaxhighlight lang="pascal" inline>{$packEnum n}</syntaxhighlight>/<syntaxhighlight lang="pascal" inline>{$Z}</syntaxhighlight>.
  
<syntaxhighlight lang=pascal>
+
* <syntaxhighlight lang="pascal" inline>{$minEnumSize 1}</syntaxhighlight>, <syntaxhighlight lang="pascal" inline>{$packEnum 1}</syntaxhighlight>, <syntaxhighlight lang="pascal" inline>{$Z1}</syntaxhighlight> or <syntaxhighlight lang="pascal" inline>{$Z‑}</syntaxhighlight> instructs the compiler to use just one Byte (at least) for the enumeration type in question.
  Type
+
* <syntaxhighlight lang="pascal" inline>{$minEnumSize 2}</syntaxhighlight>, <syntaxhighlight lang="pascal" inline>{$packEnum 2}</syntaxhighlight> and <syntaxhighlight lang="pascal" inline>{$Z2}</syntaxhighlight>: 2 Bytes minimum.
  {$ PACKENUM 1}
+
* <syntaxhighlight lang="pascal" inline>{$minEnumSize 4}</syntaxhighlight>, <syntaxhighlight lang="pascal" inline>{$packEnum 4}</syntaxhighlight>, <syntaxhighlight lang="pascal" inline>{$Z4}</syntaxhighlight> or <syntaxhighlight lang="pascal" inline>{$Z+}</syntaxhighlight>: use at least 4 Bytes.
  MiddleEnum = (zero, ten := 10, eleven, twelve);
 
</syntaxhighlight>
 
  
Explicit use of the byte data type for the enumeration.
+
Furthermore, <syntaxhighlight lang="pascal" inline>{$minEnumSize normal}</syntaxhighlight>, <syntaxhighlight lang="pascal" inline>{$minEnumSize default}</syntaxhighlight> and <syntaxhighlight lang="pascal" inline>{$minEnumSize 0}</syntaxhighlight> restores the default value.
 +
In [[Mode TP|<syntaxhighlight lang="pascal" inline>{$mode TP}</syntaxhighlight>]] the default value is <syntaxhighlight lang="pascal" inline>1</syntaxhighlight> whereas in all other modes it is <syntaxhighlight lang="pascal" inline>4</syntaxhighlight>.
 +
Such a “large” minimum size aids quick read/write access.
  
<syntaxhighlight lang=pascal>
+
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.
  Type
+
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.
  byte = (zero, one, two);
+
A range of 2<sup>16</sup> elements will be stored in two Bytes if a single Byte is insufficient.
</syntaxhighlight>
+
More than 2<sup>16</sup> members will be stored in four Bytes.
 +
These rules may, of course, be superseded by the previously mentioned <syntaxhighlight lang="pascal" inline>{$minEnumSize}</syntaxhighlight> setting.
  
=== Examples of assigning the Enum data type ===
+
== Application ==
 +
=== Out-of-the-box functionality ===
 +
* The pre-defined data type [[Boolean|<syntaxhighlight lang="pascal" inline>Boolean</syntaxhighlight>]] is an enumeration data type.
 +
* The functions <syntaxhighlight lang="pascal" inline>low</syntaxhighlight> and <syntaxhighlight lang="pascal" inline>high</syntaxhighlight> will give the lowest or highest available ''named'' item of an enumeration data type.
 +
* The standard functions <syntaxhighlight lang="pascal" inline>pred</syntaxhighlight> and <syntaxhighlight lang="pascal" inline>succ</syntaxhighlight> 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]].
  
<syntaxhighlight lang=pascal>
+
=== Masks ===
var
+
Enumeration data types are particularly useful for implementing “masks”:
  S : SmallEnum;
+
By defining a [[Set|<syntaxhighlight lang="pascal" inline>set of …</syntaxhighlight>]] you have a neat data type fulfilling certain nice properties.
  M : MiddleEnum;
+
<!-- to be continued -->
  L : LargeEnum;
 
</syntaxhighlight>
 
  
=== Examples for the conversion of the data type Enum ===
+
== Comparative remarks ==
 +
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 <syntaxhighlight lang="pascal" inline>ord</syntaxhighlight> or an [[Typecast|explicit typecast]] to the enumeration data type.
  
<syntaxhighlight lang=pascal>
+
== See also ==
  Application.MessageBox(PChar(IntToStr(Qword(Ord(Six)))), 'Conversion' , MB_OK);
+
* [[Basic Pascal Tutorial/Chapter 5/Enumerated types|Enumerated types]] in the [[Basic Pascal Tutorial]] series
  Application.MessageBox(PChar(IntToStr(Qword(Ord(p.Six)))), 'Conversion' , MB_OK);
 
</syntaxhighlight>
 

Latest revision as of 13:26, 22 December 2023

English (en)

An enumeration is a custom data type in Pascal. It is a discrete value that can be referred to by a unique identifier.

Definition

Basic

An enumeration is defined by surrounding a non-empty comma-separated list of identifiers that were not yet defined in the current scope with parentheses:

1program enumerationDemo(input, output, stdErr);
2type
3	fruit = (apple, banana, citrus);

Thus, a variable of the type fruit may assume the values apple, banana, or citrus.

4var
5	snack: fruit;
6begin
7	snack := apple;
8end.

Indices

Every member of an enumerated type has an ordinal value which can be obtained using the standard function ord. The first member of any enumeration has the ordinal value zero, and every following member is enumerated with consecutive numbers.

Override

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 value:

type
	sign = (negative = -1, none = 0, positive = 1);

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.

Properties

  • 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. A set literal using two enumeration values having the same ordinal value, albeit represented by different symbols, will not be accepted.
  • 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.
  • 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.

Prefixing

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.

Since version 2.6.0 FPC supports disabling member identifiers from being aliased by using the {$scopedEnums on} local compiler directive, thus requiring users to always specify the type name as a prefix:

program scopedEnumerationDemo(input, output, stdErr);
type
	{$scopedEnums on}
	logLevel = (error, warning, info, debug);
var
	verbosity: logLevel;
begin
	verbosity := logLevel.debug;
end.

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

This is useful if names are likely to clash with other identifiers, for example sysUtils.tUseBoolStrs is defined in that way (with {$scopedEnums on}), or if isolate identifiers would be meaningless or confusing like in objPas.tEndian. Usage introduces some incompatibility to other compilers though.

Size

The size an enumeration type occupies depends on

  1. the minimum enumeration size compiler configuration, and
  2. the range, that is ord(high(enumeration)) - ord(low(enumeration)).

The local compiler directive {$minEnumSize n} determines the minimum size in Bytes of an enumeration data type. {$minEnumSize n} is (for Delphi compatibility) an alias for {$packEnum n}/{$Z}.

  • {$minEnumSize 1}, {$packEnum 1}, {$Z1} or {$Z‑} instructs the compiler to use just one Byte (at least) for the enumeration type in question.
  • {$minEnumSize 2}, {$packEnum 2} and {$Z2}: 2 Bytes minimum.
  • {$minEnumSize 4}, {$packEnum 4}, {$Z4} or {$Z+}: use at least 4 Bytes.

Furthermore, {$minEnumSize normal}, {$minEnumSize default} and {$minEnumSize 0} restores the default value. In {$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.

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 28 (256) or fewer elements to be stored, the compiler may store a variable of this kind as a single Byte. A range of 216 elements will be stored in two Bytes if a single Byte is insufficient. More than 216 members will be stored in four Bytes. These rules may, of course, be superseded by the previously mentioned {$minEnumSize} setting.

Application

Out-of-the-box functionality

  • The pre-defined data type Boolean is an enumeration data type.
  • The functions low and high will give the lowest or highest available named item of an enumeration data type.
  • 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 run-time errors.

Masks

Enumeration data types are particularly useful for implementing “masks”: By defining a set of  you have a neat data type fulfilling certain nice properties.

Comparative remarks

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 explicit typecast to the enumeration data type.

See also