Chapter 14. Enumerated data type

Abstract

Enumerated data types are integrated in the Obix programming language because their type safety helps to catch bugs at compile-time.

... in a picture

Enumerated data type

An enumerated data type is used to distinguish a fixed set of constants, such as:

  • small
  • medium
  • large

... in a nutshell

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

... in a simple example

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

Benefits of using enumerated data types in your applications

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

Implementation of enumerated types in Obix

Enumerated types are governed by the following rules:

  1. The name of each enumerated value consists of an identifier (e.g. small, medium, large).

  2. The syntax to define an enumerated type is as follows:

    Table 14.1. Enumerated type

    ProductionSyntaxLinks
    enumerated_type

    "type" ( "id" ":" ) ? type_id
       "enumerated" identifier ( ";" identifier ) * "end"
    "end" "type" ?

    Chapter 14, Enumerated data type

    Example:

    type size 
    
       enumerated small; medium; large end
    
    end
  3. The syntax to declare an object reference of type enumerated is:

    enumerated_type_identifier.enumerated
  4. 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
  5. No factory needs to be defined for an enumerated type.

    A unique object for each value is automatically created at runtime.

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

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

Example

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 valueAttribute 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