Chapter 11. Enumerated type

Description

An enumerated type defines a fixed set of values which are distinguished through a unique name.

Enumerated types are used whenever an object's value at runtime is a named value among a defined set of possible named values. For example:

  • enumerated type size defines the following possible named values: small, medium and large.

  • enumerated type quality defines the following possible named values: very_bad, bad, standard, good, and very_good.

Rules

Enumerated types are governed by the following rules:

  1. The name of an enumerated value consists of a prefixed identifier starting with en_ as prefix.

    As for all prefixed identifiers, writing the prefix in source code is optional, as long as there is no ambiguity detected by the compiler. Hence, writing small is equivalent to writing en_small.

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

    Table 11.1. Enumerated type

    ProductionSyntaxLinks
    enumerated_type

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

    Chapter 11, Enumerated type

    Example:

    type SML_size 
    
       enumerated small; medium; large end
    
    end
  3. No factory needs to be created for an enumerated type.

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

  4. If the type of an object reference (attribute, input argument, output argument, constant or variable) is an enumerated type, then the syntax used to declare the object reference's type is: enumerated_type_identifier.enumerated, and a value of an enumerated type is accessed with the syntax enumerated_type_identifier.enumerated_value_identifier.

    Example:

    service enumerated_examples
    
       command example_1
          script
    
             // declare variable 'size' of enumerated type 'SML_size'
             var SML_size.enumerated size
    
             // assign value 'large' to variable 'size'
             size = SML_size.large
    
             // same instruction with prefixed identifiers:
             v_size = ty_SML_size.en_large
          end
       end
    
    end
  5. All objects of an enumerated type are themselves instances of type enumerated.

    Type enumerated is defined as follows:

    type enumerated
    
    	inherit !extended_comparable<other:enumerated; min_max_result:enumerated> end
    
    	inherit hashable end
    	
    	attribute a_id type:enumerated_id end
    
    	attribute a_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.

    • objects of type enumerated can be used for keys in maps, because type enumerated inherits from type hashable.

    • attribute id provides the prefixed identifier for an enumerated value.

    • attribute index provides a numeric integer value that is assigned to each enumerated value. 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.

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

Rationale

In some programming languages it is common to define enumerated values with integer or string constants.

An example of using integers in C is:

typedef enum {SMALL, MEDIUM, LARGE} size;

And an example of using strings in Java is shown below. (Note that Java also provides type-safe enum values since version 1.5)

public class Quality {
   public static final String BAD      = "bad";
   public static final String STANDARD = "standard";
   public static final String GOOD     = "good";
}

The above way of defining enumerated values always have a severe drawback: there is no type safety. This opens the door for many possible programming errors which can be difficult to detect, because the effect of a semantically incompatible value assigned to an enumerated object might be detected long after the wrong assignment took place. Therefore, the above way to work with enumerated values should never be used in Obix. Instead, an enumerated type should be used, in order to ensure compile-time and run-time type safety.

Example

Suppose the following type has been defined:

type SML_size 

   enumerated small; medium; large end

end

For each one of the above defined enumerated values, the following table shows the two attribute values of type enumerated:

Table 11.2. Attribute values of enumerated values

Enumerated valueValue of attribute idValue of attribute index
smallen_small1
mediumen_medium2
largeen_large3

The following code demonstrates the rules explained above:

service enumerated_examples

   command example_2
      script

         // declare and initialize some variables

         var SML_size.enumerated size_small = SML_size.small
         var SML_size.enumerated size_medium = SML_size.medium
         var SML_size.enumerated size_large = SML_size.large

         var SML_size.enumerated size_earth = SML_size.large

         // check attribute 'id' of type 'enumerated'

         check script size_small.id.to_string =v "en_small"
         check script size_small.id.suffix.to_string =v "small"

         check script size_earth.id.to_string =v "en_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_earth.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_earth // compare values
         check script size_large =r size_earth // compare references

         // unequal
         check script size_small #v size_large // compare values
         check script size_small #r size_large // compare references
      end
   end

end