Enumerations
Enumeration Syntax and Semantics
A Slice enumerated type definition looks identical to C++:
module M
{
enum Fruit { Apple, Pear, Orange }
}
This definition introduces a type named Fruit
that becomes a new type in its own right. Slice guarantees that the values of enumerators increase from left to right, so Apple
compares less than Pear
in every language mapping. By default, the first enumerator has a value of zero, with sequentially increasing values for subsequent enumerators.
A Slice enum type introduces a new namespace scope, so the following is legal:
module M
{
enum Fruit { Apple, Pear, Orange }
enum ComputerBrands { Apple, Dell, HP, Lenovo }
}
The example below shows how to refer to an enumerator from a different scope:
module M
{
enum Color { Red, Green, Blue }
}
module N
{
struct Pixel
{
M::Color c = Blue;
}
}
Slice does not permit empty enumerations.
In Ice releases prior to Ice 3.7, an enum type did not create a new namespace and its enumerators were in the same namespace as the enum type itself. With these releases, you had to select longer enumerator names to avoid a naming clash.
Custom Enumerator Values
Slice also permits you to assign custom values to enumerators:
const int PearValue = 7;
enum Fruit { Apple = 0, Pear = PearValue, Orange }
Custom values must be unique and non-negative, and may refer to Slice constants of integer types. If no custom value is specified for an enumerator, its value is one greater than the enumerator that immediately precedes it. In the example above, Orange
has the value 8.
The maximum value for an enumerator value is the same as the maximum value for int
, 2 31 - 1.
Slice does not require custom enumerator values to be declared in increasing order:
enum Fruit { Apple = 5, Pear = 3, Orange = 1 } // Legal
Note however that when there is an inconsistency between the declaration order and the numerical order of the enumerators, the behavior of comparison operations may vary between language mappings.
For an application that is still using version 1.0 of the Ice encoding, changing the definition of an enumerated type may break backward compatibility with existing applications. For more information, please refer to the encoding rules for enumerators.
Language Mapping
A Slice enumeration is emulated using a Ruby class: the name of the Slice enumeration becomes the name of the Ruby class; for each enumerator, the class contains a constant with the same name as the enumerator. For example:
enum Fruit { Apple, Pear, Orange }
The generated Ruby class looks as follows:
class Fruit
include Comparable
Apple = # ...
Pear = # ...
Orange = # ...
def Fruit.from_int(val)
def to_i
def to_s
def <=>(other)
def hash
# ...
end
The compiler generates a class constant for each enumerator that holds a corresponding instance of Fruit
. The from_int
class method returns an instance given its Slice value, while to_i
returns the Slice value of an enumerator and to_s
returns its Slice identifier.
Given the above definitions, we can use enumerated values as follows:
f1 = Fruit::Apple
f2 = Fruit::Orange
if f1 == Fruit::Apple # Compare for equality
# ...
if f1 < f2 # Compare two enums
# ...
case f2
when Fruit::Orange
puts "found Orange"
else
puts "found #{f2.to_s}"
end
Comparison operators are available as a result of including Comparable
, which means a program can compare enumerators according to their Slice values. Note that, when using custom enumerator values, the order of enumerators by their Slice values may not match their order of declaration.
Suppose we modify the Slice definition to include a custom enumerator value:
enum Fruit { Apple, Pear = 3, Orange }
We can use from_int
to examine the Slice values of the enumerators:
Fruit::from_int(0) # Apple
Fruit::from_int(1) # nil
Fruit::from_int(3) # Pear
Fruit::from_int(4) # Orange