The Haxial Programming Language
Variable/Attribute Types

The type of a variable or record attribute determines what type/kind of information it can store/contain. For example, if a variable is of an integer type, then it can contain numbers with no fractional portion. Or if the type of the variable is a text type, then it can contain a piece of text.

The precise type of a variable or record attribute is actually specified as an expression to be evaluated. For a simple variable, the type can be specified as simply the name of a type, but actually variable/attribute types are expressions. Type expressions obey the syntax rules described in the Expressions section of this documentation.

In some cases, a variable/attribute type expression may include an arithmetic calculation, but only if the result of the calculation can be determined at compile-time (as opposed to runtime).

Examples

Equivalent source code in the C++ language is also provided, for the benefit of people with knowledge of C++, and also for comparison purposes. If you have no knowledge of C++, then you can ignore the C++ snippets within the following.

Example:uint
C++:unsigned int pickles
Meaning:The variable/attribute stores an unsigned integer.
Example:TText
C++:string pickles
Meaning:The variable/attribute stores some text.
Example:Ref[uint]
Shortcut:Ref uint
C++:unsigned int& pickles
Meaning:A reference to an unsigned integer.
Example:Ref[TText]
Shortcut:Ref TText
C++:string& pickles
Meaning:Reference to text.
Example:Nullable[Ref[uint]]
Shortcut:RefN uint
C++:unsigned int* pickles
Meaning:A nullable reference to an unsigned integer.
Example:Ref[Ref[uint]]
C++:Unsupported in C++.
Meaning:A reference to a reference to an unsigned integer.
Example:Nullable[Ref[Nullable[Ref[uint]]]]
Shortcut:RefN RefN uint
C++:unsigned int** pickles
Meaning:A nullable reference to a nullable reference to an unsigned integer.
Example:Nullable[Ref[TAny]]
Shortcut:RefN TAny
C++:void* pickles
Meaning:A nullable reference to any type.
Example:Ref[ReadOnly[uint]]
Shortcut:Ref ReadOnly uint
C++:const unsigned int& pickles
Meaning:Reference to a read-only (modification prohibited) unsigned integer.
Example:Nullable[Ref[ReadOnly[uint]]]
Shortcut:RefN ReadOnly uint
C++:const unsigned int* pickles
Meaning:Nullable reference to a read-only unsigned integer.
Example:ReadOnly[Nullable[Ref[uint]]]
Shortcut:ReadOnly RefN uint
C++:unsigned int* const pickles
Meaning:Read-only nullable reference to non-read-only unsigned integer.
Example:ReadOnly[Nullable[Ref[ReadOnly[uint]]]]
Shortcut:ReadOnly RefN ReadOnly uint
C++:const unsigned int* const pickles
Meaning:Read-only nullable reference to read-only unsigned integer.
Example:TArray[uint]
C++:vector<unsigned int> pickles
Meaning:A varying-count array of unsigned integers.
Example:TArray[TRect]
C++:vector<Rect> pickles
Meaning:A varying-count array of rectangle tuples.
Example:TArray[Nullable[TRect]]
C++:Unsupported in C++.
Meaning:A varying-count array of nullable rectangle tuples.
Example:TArray[Nullable[Ref[TMyInfo]]]
Shortcut:TArray[RefN TMyInfo]
C++:vector<TMyInfo*> pickles
Meaning:A varying-count array of nullable references to a tuple type named "TMyInfo".
Example:TArray[RefN[uint]]
C++:vector<unsigned int*> pickles
Meaning:A varying-count array of nullable references to unsigned integer.
Example:TArray[RefN[ReadOnly[uint]]]
Shortcut:TArray[RefN ReadOnly uint]
C++:vector<const unsigned int*> pickles
Meaning:A varying-count array of nullable references to read-only unsigned integer.
Example:RefN[ReadOnly[TArray[uint]]]
C++:const vector<unsigned int>* pickles
Meaning:A nullable reference to a read-only (modification prohibited) varying-count array of unsigned integers.
Example:Ref[TArray[uint]]
C++:vector<unsigned int>& pickles
Meaning:An unnullable reference to a varying-count array of unsigned integers.
Example:ConstantSize[TArray[uint], 4]
Shortcut:TArrayCS[uint, 4]
C++:unsigned int pickles[4]
Meaning:A constant-size array of 4 unsigned integers (array count is 4).
Example:ConstantSize[TArray[uint], Mul[Add[6,3],2]]
Shortcut:TArrayCS[uint, 6+3*2]
C++:unsigned int pickles[(6+3)*2]
Meaning:A constant-size array of 18 (6+3*2) unsigned integers.
Example:ConstantSize[TArray[RefN[uint]], Mul[4,2]]
Shortcut:TArrayCS[RefN uint, 4*2]
C++:unsigned int* pickles[4*2]
Meaning:A constant-size array of 8 (4*2) nullable references to unsigned integer.
Example:Nullable[Ref[ConstantSize[TArray[uint], 8]]]
Shortcut:RefN[TArrayCS[uint,8]]
C++:typedef unsigned int MyNumbers[8];
MyNumbers* pickles
Meaning:A nullable reference to a constant-size array of 8 unsigned integers.
Example:Ref[ConstantSize[TArray[uint], 8]]
Shortcut:Ref[TArrayCS[uint,8]]
C++:typedef unsigned int MyNumbers[8];
MyNumbers& pickles
Meaning:An unnullable reference to a constant-size array of 8 unsigned integers.
Example:Nullable[Ref[ ConstantSize[TArray[Nullable[Ref[uint]]], 8] ]]
Shortcut:RefN TArrayCS[RefN uint, 8]
C++:typedef unsigned int* MyNumbers[8];
MyNumbers* pickles
Meaning:A nullable reference to a constant-size array of 8 nullable references to unsigned integer.
Example:TArrayCS[TArrayCS[uint,4], 4]
Shortcut:TMatrixCS[uint, 4, 4]
C++:unsigned int pickles[4][4]
Meaning:A constant-size array of 4 constant-size arrays of 4 unsigned integers. In other words, a 4x4 matrix of unsigned integers.
Example:Ref[TArray[TArrayCS[uint,4]]]
C++:typedef unsigned int MyNumbers[4];
vector<MyNumbers>& pickles
Meaning:A reference to a varying-count array of constant-size arrays of 4 unsigned integers each.
Example:Ref[TArray[TArray[uint]]]
C++:vector<vector<unsigned int> >& pickles
Meaning:Reference to an array of arrays of unsigned integers (varying-count arrays).
Example:Ref[TArray[TArray[TText]]]
C++:vector<vector<string> >& pickles
Meaning:Reference to an array of arrays of texts (varying-count arrays).
Functions

FunctionDescription
TArray[t]Returns a type that is an array of the specified type. Uses "Dynamic" storage method by default.
TText[fmt]Returns a text type, using the specified text format. The text format and square brackets can be omitted, and then it uses the default text format (usually UTF8). Uses "Dynamic" storage method by default.
 
Ref[t]Returns a type that is a reference to the specified type.
RefN[t]Returns a type that is a nullable reference to the specified type. Nullable meaning the reference can be set to a null value. Shortcut for Nullable[Ref[t]].
Ptr[t]Returns a type that is a pointer to the specified type. Pointers are much the same concept as references, except lower level and unchecked/unverified.
Nullable[t]Returns a nullable version of the specified type. Nullable meaning capable of being set to a null value distinct from all other values.
Unnullable[t]Returns an unnullable version of the specified type. Unnullable meaning incapable of being set to a null value.
ReadOnly[t]Returns the specified type with read access enabled, and modify access disabled. The value can be read, used, and copied, but it cannot be modified (can only serve as a source for data, not as a destination).
ModifyOnly[t]Returns the specified type with modify access enabled, and read access disabled. The value can be modified but cannot be read or copied (can only serve as a destination for data, not as a source).
Signed[t]Returns a signed version of the specified integer type. Signed meaning capable of storing both positive and negative numbers.
Unsigned[t]Returns a unsigned version of the specified integer type. Unsigned meaning capable of storing only positive (actually unsigned) numbers, and incapable of negative numbers.
Out[t]Returns the specified type as an output parameter. Can only be used on parameters. Cannot be used as an operand into another function, frex ReadOnly[Out[uint32]] and Ref[Out[uint32]] are invalid.
InOut[t]Returns the specified type as an input/output (bidirectional) parameter. Can only be used on parameters.
OutRet[t]Same as "Out" function except additionally specifies that the parameter should be compiled to use the return value as the method of outputting the parameter value. This is a low-level optimization. Can only be used for 1 parameter in a Command Implementation. Cannot be used in a Function Implementation.
 
ConstantSize[t, n]Returns a "Constant Size" version of the specified array or text type. "Constant Size" is a storage method. The second operand is the desired size (must be greater than zero). For an array, this means the count/number of items. For text, it means the count/number of bytes. It must be possible to determine this number at compile-time (as opposed to runtime).
Preallocated[t, n]Returns a "Preallocated" version of the specified array or text type. "Preallocated" is a storage method. The second operand is the desired maximum size (must be greater than zero). For an array, this means the maximum count/number of items. For text, it means the maximum count/number of bytes. It must be possible to determine this number at compile-time (as opposed to runtime).
Appended[t]Returns an "Appended" version of the specified array or text type. "Appended" is a storage method.
UnchangingSize[t]Returns an "Unchanging Size" version of the specified array or text type. "Unchanging Size" is a storage method.
Consolidated[t]Returns a "Consolidated" version of the specified array or text type. "Consolidated" is a storage method.
TArrayCS[t, n]Shortcut for ConstantSize[TArray[t], n]
TArrayPA[t, n]Shortcut for Preallocated[TArray[t], n]
TMatrixCS[t, w, h]Shortcut for TArrayCS[TArrayCS[t,w], h]
 
LittleEndian[t]For Load/Store commands. Use "Little Endian" byte-ordering, meaning the least-significant bytes are stored first (at lower offsets).
BigEndian[t]For Load/Store commands. Use "Big Endian" byte-ordering, meaning the most-significant bytes are stored first (at lower offsets).
LE[t]Shortcut for LittleEndian[t]
BE[t]Shortcut for BigEndian[t]
Aligned[t]For Load/Store commands. Assume that the location of the value in memory/RAM is aligned for speed (the address is a multiple of the size of the value).
Unaligned[t]For Load/Store commands. Assume that the location of the value in memory/RAM is NOT aligned (or not guaranteed to be aligned).
Storage Methods

An array can be stored using different methods. You can choose which method to use. The normal/default method is the "Dynamic" storage method, and it is the most powerful and least restrictive of the methods.

The purpose of using a different method in a particular situation is to improve the speed of the program, or to reduce the amount of memory used, or both (especially in situations where hundreds or thousands of record or attribute instances are being created).

These storage methods are described for arrays, but they are also applicable to text in the same manner.

Internally, there may be a difference between resizing an array, and resizing the memory allocated for the array. Only the first type of resizing changes the count of the array (the number of items in the array). Either type of resizing may or may not require the simultaneous use of the other type of resizing, depending on the situation.

Regarding the "Appended" method, when there exists more than 1 reference to the record, both types of resizing are prohibited and must generate an error if attempted. If resizing the array could succeed without resizing the allocated memory this time in this case but not in all cases, it is prohibited and will generate an error. This behavior improves reliability and gives a consistent response, and makes it easier to detect certain programming mistakes.

Specifying an Array Type

When specifying an array type, you are required to specify some other type. Each item in the array will be this other type that you specify. For example, the following means an array of uint8 (unsigned 8-bit integer) variables:

TArray[uint8]

Different storage methods can be used. If no storage method is specified (as in the above example), then the "Dynamic" method is assumed by default. See the "Storage Methods" section for a description. You can optionally use one of the functions that selects a different storage method. For example, the following means an array of uint8 variables, using the "Consolidated" storage method:

Consolidated[TArray[uint8]]

When using the "Constant Size" storage method, it is necessary to specify the count/number of items in the array. This count/number must be a constant number or an expression resulting in a constant number, that can be determined at compile-time (as opposed to runtime). For example, the following means an array of 100 uint variables.

ConstantSize[TArray[uint], 100]

Using the "Preallocated" storage method is similar to "Constant Size", except that the count/number of items is the maximum count of the array, meaning the maximum number of items that the array is capable of storing. For example, the following means an array capable of storing up to 100 uint variables:

Preallocated[TArray[uint], 100]

To make an array of text attributes:

TArray[TText]

It is possible to make an array of arrays. For the item type of the array, simply specify another array. For example:

TArray[TArray[uint]]
Specifying a Text Type

To specify that a variable be capable of storing a piece/chunk of text, it is as simple as this:

TText

A Unicode text format can optionally be specified:

TText[UTF16BE]

The default text format is usually UTF8. The following formats are supported:

NameDescription
UTF8Unicode Transformation Format 8-bit. Capable of storing all Unicode characters, but optimized for the Latin alphabet (at the expense of other alphabets). Backwards compatible with the ASCII standard. Uses 1 to 4 bytes per character.
UTF16BEUnicode Transformation Format 16-bit Big Endian. Uses 2 or 4 bytes per character. Not biased towards any particular alphabet. Uses 16-bit integers in "Big Endian" format (high byte first, then low byte).
UTF16LEUnicode Transformation Format 16-bit Little Endian. Same as UTF16BE except that the order of the 2 bytes within each 16-bit integer is the reverse (low byte first, then high byte).
UTF16HEHost Endian. This selects either UTF16BE or UTF16LE, depending on whether the host CPU natively uses Big Endian or Little Endian format integers.

Different storage methods can be used. If no storage method is specified, then the "Dynamic" method is assumed by default. See the "Storage Methods" section for a description. You can optionally use one of the functions that selects a different storage method. For example, the following means a text variable using the UTF16BE text format and the "Consolidated" storage method:

Consolidated[TText[UTF16BE]]

When using the "Preallocated" storage method, it is necessary to specify the maximum size (in bytes) of the text. This size must be a constant number or an expression resulting in a constant number, that can be determined at compile-time (as opposed to runtime). For example, the following means a text variable using the default text format and the "Preallocated" storage method with a maximum size of 100 bytes:

Preallocated[TText, 100]

The following means a text variable using the UTF16BE text format and the "Preallocated" storage method with a maximum size of 100 bytes:

Preallocated[TText[UTF16BE], 100]

When specifying sizes for storage methods for text, note that the size is the number of bytes, NOT the number of characters. It is necessary to specify it in bytes because the size of a character varies depending on the particular character (regardless of whether UTF8 or UTF16 is used).

Any Type

A reference to any type can be defined:

Ref[TAny]

Given such a reference, it is possible to check at runtime whether it is actually a reference to a specified type of variable/attribute, and safely typecast the reference to a reference of that type, and then the value can be accessed (read or modified). This is possible with any type, including primitive types (such as uint32) and records.

A "TAny" reference cannot be forcibly typecast to a specified type, because that could result in memory corruption and crashes. The typecast operation will only succeed if the type of the variable/attribute matches (or is directly compatible with) the specified type. If not, then an error is generated.

The "TAny" type cannot be used to circumvent, bypass, or cancel read-only protection. If a type is read-only, it cannot be typecast to a non-read-only "TAny". And a read-only "TAny" cannot be typecast to a non-read-only specific type.

Given a "TAny" reference, it is also possible to check at runtime whether it is a reference to any type of record that contains an attribute of the specified name and type, and to get a reference to that attribute. This allows the creation of a combined or compound "object" that contains various different components, with components being optional or interchangeable. For example, the functionality/behavior of the "object" may be determined by the particular combination of components that it contains.