Underused expanded types

by Colin LeMahieu (modified: 2010 Oct 07)

Using expanded types for enumerations or aliased type names:

expanded class MY_ENUMERATION convert value: {INTEGER_32} feature make (value_a: INTEGER_32) do value := value_a end feature value: INTEGER_32 end

It's as simple as that. Pass around MY_ENUMERATION and you have an efficient type that can be used like an enumeration or an aliased type name.

Using expanded types for constants:

expanded class MY_CONSTANTS feature red: INTEGER_32 = 1 blue: INTEGER_32 = 2 green: INTEGER_32 = 3 end

The class MY_CONSTANTS has no members, so it has no size and therefore no state. It can be used in a local or as a class attribute such as the following:

feature constants: MY_CONSTANTS test local constants_2: MY_CONSTANTS do if constants.blue = constants_2.blue then io.put_string ("The same") end end

This is an alternative to using inheritance to pull in constants.

A small modification on the above to provide functions

expanded class NATURAL_32_FACILITIES feature rotate_right (value: NATURAL_32; count: INTEGER_32): NATURAL_32 do Result := (value |>> count).bit_or (value |<< (32 - count)) end end

These facilities can be used like:

feature rotation: NATURAL_32_FACILITIES test local rotation_2: NATURAL_32_FACILITIES do if rotation.rotate_right (0x3, 1) = rotation_2.rotate_right (0x6, 2) then io.put_string ("Successful") end end

Expanded types can be used for output variables by creating an ADT out of the output variables. Take a division function that does a 2 machine word numerator and denominator and gives a 2 machine word quotient and remainder. A c-style way to represent this is:

div (unsigned n, unsigned d, unsigned * q, unsigned * r)

By translating the output variables in to an ADT and making the routine a creation procedure you get an Eiffel equivalent:

expanded class DIVISION_RESULT feature make (n: NATURAL_32; d: NATURAL_32) do --... end q: NATURAL_32 r: NATURAL_32 end

In general if you have a C routine with input parameters pi_1 ... pi_j and output parameters po_1 ... po_j. Move parameters po_1 ... po_j in to attributes of your new expanded class E. Move the C routine in to E as a creation procedure taking in input parameters pi_1 ... pi_j and writing outputs to attributes of the expanded class.

Creation procedures on expanded types can be called statically by the compiler and static calls can be inlined. Using this expanded class ADT method, expanded classes can behave identically to C routines with output parameters when not inlined, or even C macros when the creation procedure is inlined.

Using this pattern allows one to have output parameters that are attached, via CAPs applied in the expanded type's creation procedures. Since this type is expanded it has a performance equivalent to output parameters.

Note: In the current Eiffel Studio compiler implementation, expanded types have a header which isn't really needed. This means expanded types have some size and initialization when they really shouldn't have to; this is an optimization that could be applied.

The current ECMA language specification requires a default_create procedure to be defined. This restriction could be loosened to be: "expanded types must have a default_create creation procedure, or be initialized on creation as class attributes" "expanded types must have a default_create creation procedure or be initialized prior to use as feature locals". This gives backwards compatibility to expanded objects created with default_create and doesn't force a default value of an expanded type which is restrictive especially in void-safe environments.