Data types
The following table describes the different data types available in APL. The second column states if the data type is a primitive, or an object. The third column indicates the default value that an uninitialized variable will obtain.
Data type | P/O | Def val | Range | Description | Example |
---|---|---|---|---|---|
boolean | P | false | 1 Byte | Boolean value (true|false). | boolean aBool=true; |
byte | P | 0 | 1 Byte, -128 to +127 | Single byte integer value. | byte aNumber=127; |
char | P | '\0' | 1 Byte | A single character value. | char aCharacter='a'; |
short | P | 0 | 2 Bytes, -32,768 to +32,767 | Short integer value. | short aNumber=31000; |
int | P | 0 | 4 Bytes, -2,147,483,648 to +2,147,483,647 | Integer values have normal Java syntax, for instance: 42, 0x2A An integer literal is always of the most narrow integer type that can contain the value. This normally works as expected, since numeric types can be implicitly converted to any wider numeric type. | int aNumber=2147483640; |
float | P | 0/0 | 4 Bytes, 1.40129846432481707e-45 to 3.40282346638528860e+38 (positive or negative) | Single-precision floating point. | float aValue=0.5; |
double | P | 0/0 | 8 Bytes, 4.94065645841246544e-324d to 1.79769313486231570e+308d (positive or negative). | Double-precision floating point. When using floating-point literals, (that is, float (f) or double (d) values) all floating-point literals without trailing d is considered float literals. Note! For instance 0.5 and 0.5d will not give identical values Double types may contain positive or negative infinity. | double aValue=432482943.1; double POS_INFINITY=1.0/0.0; double NEG_INFINITY=-1.0/0.0; |
long | P | 0 | 8 Bytes, -2^63 to +(2^63 -1) | Long integer value. | long aNumber=92233720368547; |
bigint | O | 0 | Unlimited | Provides storage for any integer value. | bigint aNumber; |
bigdec | O | 0 | Unlimited | Provides storage for any integer value with a decimal point. Values assigned to bigdecimal variables in APL must be suffixed with b. Example bigdec aNumber = 123.4567b; | bigdec aNumber; |
string | O | null | Unlimited | Values assigned to string variables in APL must be surrounded with double quotes. A character preceded by a backslash (\) is an escape sequence and has a special meaning to the compiler. The following sequences are available:
Some string comparison functions use regular expressions. If special characters such as "*", "?" are to be used as characters in the regular expression, they must be escaped with two backslashes in the APL since these strings will be parsed twice. For instance, the following function will return the index of the question mark in the string: String values surrounded with triple double quotes are referred to as multiline strings. You can span the content of these string across line boundaries. Multiline strings does not support, or need, escape characters. All characters, including double quotes, are assigned as they appear. | string aString = "foobar"; string mlString = """{ "key1": "value 1", "key2": "value 2" }"""; |
any | O | null | Can be assigned any value of any type. | any aVar; aVar = 1; aVar = "foobar"; | |
bitset | O | null | Represents a bit string that grows as needed. The bits are indexed by non-negative integers. | bitset aBitset; | |
bytearray | O | null | Bytearray type. | bytearray anArray; | |
date | O | null | Holds date and time, including the timezone. | date aDate; | |
ipaddress | O | null | Holds IP address information. Both IPv4 and IPv6 are supported. | ipaddress anIp = ipLocalHost(); | |
list <type> | O | null | List of objects of the specified type. If a list of lists is to be declared the ">" characters must be separated by at least one space, not to conflict with the ">>" operator. That is, | list<int>intList; | |
map | O | null | Hash maps allowing key/value pairs to be defined. | map<string, int> aMap = mapCreate(string, int); | |
table | O | null | Special type used to hold table data used by the table commands. | table aTable = tableCreate("Default", anSQL); | |
UDRType | O | null | Holds a reference to a UDR. The UDRType must be a defined format or compilation will fail. There is also a special format available for generic UDRs called drudr and is of drudr type. | MyDefinedType aUDR; drudr anyUDR; | |
uuid | O | null | 128 bits | Immutable universally unique identifier (UUID). | uuid u=uuidCreateRandom(); |
The variable types follow Java standard regarding object reference vs. value semantics. All types use value semantics when compared through the '==' and '!=' boolean operators and objects use reference semantics for all other operators, like assignments '='.
Example - Reference Semantics
Two date variables (objects) and two long variables (primitives) are used to illustrate the reference semantics. In the case of date variables, they will always contain the same value regardless of being updated via myDate_A
or myDate_B
since they point to the same object.
date myDate_A = dateCreateNow(); date myDate_B = myDate_A; long myLong_A = 10; long myLong_B = myLong_A; if (myDate_A == myDate_B ) { // true } if (myLong_A == myLong_B) { // true } // Change value on A variables dateAddHours(myDate_A, 22); if (myDate_A == myDate_B) { // still true, points to same object } myLong_A = 55; if (myLong_A == myLong_B) { // false, primitives always hold their own values }
Type Casting
It is possible to cast between different types with regular Java syntax. The instanceOf
function is used to evaluate dynamic types since an incorrect type conversion will cause the workflow to abort with a runtime error.
Example - Type casting
/* APL code for two UDR types */ consume { if( instanceOf( input, UDRType1 ) ) { UDRType1 udr1 = (UDRType1) input; // Handle UDRType1 ... } else { UDRType2 udr2 = (UDRType2) input; // Handle UDRType2 ... } }
As an extension to the regular conversions, all types may be casted to string type.
Note that some types are subtypes of other types and can be directly assigned. Examples are:
All types are subtypes of the any type.
int is a subtype (narrowing) of long.
All UDR types are subtypes of the general base type
drudr
.Some UDR types are subtypes of other UDR types (depending on Ultra definitions).
There is also a number of built-in type conversion functions (refer to the section below, Access of UDR Fields).
Access of UDR Fields
UDR fields are accessed with the '.' separator. For instance, to access the field myField
within the UDR type variable theUDR
, the syntax would be:
theUDR.myField = 5; debug( theUDR.myField );
If the field name is a variable instead of a string, udrGetValue/udrSetValue
can be used to set/get field values dynamically.
Access of non-present fields will return the default value for the specific type. Field presence is evaluated with udrIsPresent.
When writing to a UDR field on a null object, a NullPointerException will be thrown, see example:
Example - Access UDR fields
myUDR theUDR = null; int a = theUDR.myField // Will Not throw NullPointerException theUDR.myField = 0; // Will throw NullPointerException
To avoid exceptions, first make sure that the UDR is not a null object:
Example - Check for null value
if( theUDR != null ) { theUDR.myField = 0; }
For further information about UDR related functions, see UDR Functions.
Access of Input UDR
Within the consume
block, the incoming UDR can be accessed using the special variable input
. The instanceOf
function may be useful in case of dealing with several UDR types.