module Enums {
// ENUM BASICS
// enums define a new type and associated constant values of that type
enum Component {
RED = 1,
GREEN = 2,
BLUE = 3
}
// enums constants are accessed using the enum name
fn test1() {
let x : Component = Component.A;
let y = Component.B;
}
// CONTROLLING ENUM TYPE
// by default, enums are based on the int type. Use : to specify other types.
// for example, the following enum is represented using an unsigned 16-bit value (u16)
enum ByteOrderMark : u16 {
BIG_ENDIAN = 0xFEFF,
LITTLE_ENDIAN = 0xFFFE
}
// AUTO INCREMENTING ENUMS
// if the constant value is omitted, it's value is one more than the previous value.
// if not specified, the first value is 0.
enum TokenKind {
SPACE, // 0
DIGIT, // 1
PLUS, // 2
MINUS = 10, // 10
TIMES, // 11
DIVIDE // 12
}
// REFERRING TO ENUM CONSTANTS
// enum constant expressions can refer to other constants in the enum without qualification
enum ReadWrite {
READ = 0x1,
WRITE = 0x2,
READ_WRITE = READ | WRITE
}
// NON NUMERIC ENUMS
// enums can be based any type. if a non-integer type is used, then the constant
// values must be specified (there is no auto incrementing).
enum ColorName : string {
RED = "#ff0000",
GREEN = "#00ff00",
BLUE = "#0000ff"
}
// EXTENSIBLE VS NON-EXTENSIBLE ENUMS
// enums automatically coerce to and from their base type. when coercing/casting
// from the base type to the enum type, the cast may fail, however, due to the value
// being provided not being one of the specified constant values.
enum NonExtensible {
A = 1,
B = 2
}
fn test2() {
let x : int = NonExtensible.A; // ok
let y : NonExtensible = 1; // ok, since 1 is NonExtensible.A
let z : NonExtensible = 100; // throws, since 100 is not a valid value in NonExtensible
}
// enums can alternatively be defined as extensible, meaning additional values are
// allowed, within the constraint of the base type. use ... at the end
// to indicate that the enum is extensible.
enum Extensible {
A = 1,
B = 2,
... // enum is extensible, meaning it allows values other than those listed
}
fn test3() {
let x : int = Extensible.A; // ok, since Extensible enum is extensible
let y : Extensible = 1; // ok, since Extensible enum is extensible
let z : Extensible = 100; // ok, since Extensible enum is extensible
let q : Extensible = "hi"; // error, since "hi" is not an int
}
// PROVIDING ADDITIONAL CONSTANTS FOR EXTENSIBLE ENUMS
// extensible enums can be extended with additional constants separately from their definition
// the following URI scheme enum defines a few values but allows others
enum UriScheme : string {
HTTP = "http",
HTTPS = "https",
FTP = "ftp",
MAILTO = "mailto",
...
}
// add a constant to the UriScheme enum
enum ...UriScheme {
MONGODB = "mongodb",
}
// add a constant to the UriScheme enum
enum ...UriScheme {
CHROME = "chrome",
}
fn test4() {
let x : UriScheme;
x = UriScheme.HTTP;
x = UriScheme.CHROME;
x = UriScheme.MONGODB;
}
// AUTO NUMBERING AND EXTENSIBILITY
// Normally, if the value of an integer enum constant is not provided,
// then it is one greater than the previous value (or 0 if the first
// constant in the enum).
// For an enum extension, if a value is not provided, it will be the next available
// ascending value. A value is available if there is not another constant
// defined with that value. This allows extensions to have unique values from
// the base and from each other.
// The compiler is free to choose the ordering of the extensions when assigning
// the values, as illustrated in the following example: the compiler may choose
// the values from Order1 or Order2.
enum AutoNumber {
A, // 0
B, // 1
C = 4, // 4
D, // 5
...
}
enum ...AutoNumber {
E, // Order1: 2, Order2: 3
F = 4, // 4
}
enum ...AutoNumber {
G, // Order1: 3, Order2: 2
H // Order1: 6, Order2: 6
}
}