12. Typealias
Custom names for types can be defined using typealias. A type alias does
not introduce a new type: the alias name and the original type are the same
type by strong equivalence, and the two names may be used interchangeably
anywhere a type is expected. A typealias may be declared at global scope or inside a function or
procedure body. A local alias is scoped to the block that
contains it and shadows any outer alias or type of the same name for the
rest of that block, without affecting the outer name outside it (two aliases
sharing a name in the same scope remain a conflict; see below). A type alias
may use any valid identifier for the name of the type. After the type alias has
been defined, the new name may be used anywhere the original type could be used.
For instance:
typealias integer int;
const int a = 0;
procedure main() returns integer {
a -> std_output;
return 0;
}
Output
0
Note that these new type names can appear to conflict with symbol names. However, the compiler can use context to differentiate a type alias from a symbol. The following is therefore legal:
typealias character main;
typealias integer i;
const main A = 'A';
procedure main() returns i {
i i = 0; // <type> <id> = <expr>;
return i;
}
In addition to primitive types, typealias can be
used with any aggregate type (arrays, matrices,
vectors, tuples, and structs), as well as with string, itself a typealias
for vector<character>.
Using typealias on tuples, or on arrays with sizes helps reusability and
consistency:
typealias tuple(character[64], integer, real) student_id_grade;
typealias integer[2][3] two_by_three_matrix;
procedure main() returns integer {
student_id_grade chucky_cheese = ("C. Cheese", 123456, 77.0);
two_by_three_matrix m = [i in 1..2, j in 1..3 | i + j];
m -> std_output;
return 0;
}
Output
[[2 3 4] [3 4 5]]
Type aliases of arrays with inferred sizes ([*]) are allowed, but
declarations of variables using the type alias must be initialized
appropriately (see Sizing).
Because a typealias is an aliased name for a type, a typealias may
also be defined in terms of another typealias:
typealias integer int;
typealias int also_int;
procedure main() returns integer {
also_int x = 5;
x -> std_output;
return 0;
}
Output
5
The compiler must emit a SymbolError (see Errors) for two aliases
that share a name in the same scope. (A local alias that shares its name with
one in an enclosing scope is not a conflict – it shadows it, as above.)
typealias integer ty;
typealias character ty;
procedure main() returns integer { return 0; }
Errors
This program is ill-formed; the compiler must reject it (SymbolError).
Some type aliases may be parameterized with an expression, such as the size of
an array. Such size expressions must be valid
constant expressions. This permits not only constant
folding of scalar literals but also constant propagation through other
constexpr values, such as global constants.
typealias integer[1 + 3 - 2] vec_of_two;
procedure main() returns integer {
vec_of_two v = 1..3;
return 0;
}
The compiler must emit a SizeError (see Errors) on line 3
since the vec_of_two type has a size of 2 and an array of size 3 is
being assigned.
Because the size may be any constexpr, it can reference other constant
expressions rather than being limited to literals:
const WIDTH = 4;
typealias integer[WIDTH] row; // legal: WIDTH is a constexpr
procedure main() returns integer {
row r = [1, 2, 3, 4];
r -> std_output;
return 0;
}
Output
[1 2 3 4]