An enumerated type defines a fixed set of constants (or constant value objects) distinguished through a unique name and an integer index.
Because they are type-safe, incompatible assignment errors are immediately caught at compile-time (see explanation below).
enumerated type size defines the constants: small, medium and large.
enumerated type quality_level defines the constants: very_bad, bad, standard, good, and very_good.
It is a common practice to define enumerated values with integer or string constants.
An example of using integers in C is:
typedef enum {SMALL, MEDIUM, LARGE} size;The following Java example is extracted from the package java.awt.Transparency (Note that Java also provides type-safe enum values since version 1.5):
public final static int OPAQUE = 1; public final static int BITMASK = 2; public final static int TRANSLUCENT = 3;
The problem with this approach is a lack of type safety. The following assignment is correct:
int transparency = Transparency.OPAQUE;
But because variable transparency is of type int, any incorrect assignments such as the following ones are not detected by the compiler and don't generate runtime errors:
transparency = 120; int temperature = -13; transparency = temperature;
The indirect effects of these errors appear later, sometimes long after the wrong assignment took place, and this can make such errors difficult to detect. Therefore integer or string constants should not be used to denote enumerated values. Instead, an enumerated type should be used in order to catch incorrect assignments immediately at compile-time.
Besides the type safety, enumerated types provide other benefits:
The risk of code duplication for a given value (and the related maintenance headache) doesn't exist. Suppose, for instance, a programmer writes transparency = 3 instead of transparency = Transparency.TRANSLUCENT. In this case the application runs correctly. However if a new value is inserted later in Transparency the instruction becomes erroneous, but there won't be a compile-time or runtime error. The instruction needs to be adapted manually. The same would happen if a value is deleted or if the order of values is changed.
A meaningful text (instead of a number) can easily be displayed on output devices (e.g. size: medium is more meaningful than size: 2.
There are no name clashes when different enumerated types use the same values (e.g. size.medium and quality.medium can coexist peacefully).
Enumerated types are governed by the following rules:
The name of each enumerated value consists of an identifier (e.g. small, medium, large).
The syntax to define an enumerated type is as follows:
Table 14.1. Enumerated type
| Production | Syntax | Links |
|---|---|---|
enumerated_type |
| Chapter 14, Enumerated data type |
Example:
type size enumerated small; medium; large end end
The syntax to declare an object reference of type enumerated is:
enumerated_type_identifier.enumerated
The syntax to access the value of an enumerated type is:
enumerated_type_identifier.enumerated_value_identifier
Example:
// declare variable 'size_of_drink' of enumerated type 'size' var size.enumerated size_of_drink // assign the value 'large' to variable 'size_of_drink' size_of_drink = ty_size.large
No factory needs to be defined for an enumerated type.
A unique object for each value is automatically created at runtime.
The values of an enumerated type are all objects of type enumerated.
Type enumerated is defined as follows:
/// Copyright (C) 2009-2012 Christian Neumanns (www.rps-obix.com) This code can be used under the terms of the 'GNU Afero General Public License version 3' The full text of this license can be found at http://www.gnu.org/licenses/agpl.html THIS CODE IS DISTRIBUTED WITHOUT ANY WARRANTY. See the license for details. end /// type enumerated inherit !extended_comparable<other:enumerated; min_max_result:enumerated> end inherit simple_non_empty_string end attribute index type:positive32 end end type
It follows from the above type definition that:
two enumerated values can be compared (equal, greater than, less than), because type enumerated inherits from type extended_comparable. The magnitude of each value is determined through the order in which the values appear in the declaring type. Each value has a higher magnitude than its preceding value. Source code examples are given below.
objects of type enumerated can be used for keys in maps, because type enumerated inherits from type simple_non_empty_string.
attribute value (inherited from type simple_non_empty_string) provides the identifier of the enumerated value as an object of type string_value.
attribute index provides the index (position) of the enumerated value as an object of type positive32. The first enumerated value appearing in the declaring type starts with index 1, and the index is then incremented by one for each subsequent value.
Enumerated types are compile-time and run-time type-safe.
For example, suppose that:
enumerated type size defines the values small, medium and large.
enumerated type quality defines the values bad, medium and good.
In this case, an object of type size.enumerated cannot be assigned to an object of type quality.enumerated, and vice versa. Moreover, the values medium of type size and medium of type quality are semantically different, and thus incompatible, although their identifiers and indexes are the same.
Suppose the following type exists:
type size enumerated small; medium; large end end
Then the values (which are objects of type enumerated) contain the following data:
Table 14.2. Data of enumerated values
| Enumerated value | Attribute value(of type string_value) | Attribute index(of type positive32) |
|---|---|---|
small | "small"~ | 1 |
medium | "medium"~ | 2 |
large | "large"~ | 3 |
The following code demonstrates the rules explained above:
// declare and initialize some variables var size.enumerated size_small = size.small var size.enumerated size_medium = size.medium var size.enumerated size_large = size.large var size.enumerated size_of_drink = size.large // check values check script size_small.value =v "small"~ check script size_of_drink.value =v "large"~ // check attribute 'index' of type 'enumerated' check script size_small.index =v 1 check script size_medium.index =v 2 check script size_large.index =v 3 check script size_of_drink.index =v 3 // compare values // greater than check script size_medium > size_small check script size_large > size_medium // less than check script size_small < size_large // equal check script size_large =v size_of_drink // compare values check script size_large =r size_of_drink // compare references // unequal check script size_small #v size_large // compare values check script size_small #r size_large // compare references