Data Types in CTL2
For basic information about data types used in metadata, see Data Types in Metadata.
In any program, you can use some variables. Data types in CTL are the following:
- boolean
- byte
- cbyte
- date
- decimal
- integer
- long
- number (double)
- string
- list
- map
- variant
- record
boolean
The boolean
data type contains values of logical expressions.
The default value is false
.
It can be either true
or false
.
Its declaration looks like this: boolean identifier;
.
Example 54. Declaration of boolean variable
boolean b; // declaration
boolean b = true; // declaration with assignment
byte
This data type stores binary data of a length that can be up to Integer.MAX_VALUE
as a maximum.
The default value is null
.
Its declaration looks like this: byte identifier;
.
Example 55. Declaration of byte variable
byte b;
// declaration of variable with assignment
byte b = hex2byte("414243");
cbyte
This data type is a compressed representation of byte data type to reduce runtime memory footprint. Compressed size of the data can be up to Integer.MAX_VALUE
as a maximum.
The default value is null
.
Its declaration looks like this: cbyte identifier;
.
Example 56. Declaration of cbyte variable
cbyte c1;
cbyte c2 = hex2byte("61"); // declaration with assignment
date
The date data type contains date and time.
The default value is 1970-01-01 00:00:00 GMT
.
Its declaration looks like this: date identifier;
Example 57. Declaration of date variable
// declaration of variable
date d;
// declaration of variable with assignment from function
date d = str2date("1600-01-31", "yyyy-MM-dd");
If you work withdate
, you should be aware of time zone of the data.
decimal
The decimal
data type serves to store decimal numbers.
Calculations with the decimal
data type are performed in fixed point arithmetic. It makes decimal
data type suitable for calculations with money.
The default value is 0
.
Its declaration looks like this: decimal identifier;
.
By default, any decimal may have up to 32 significant digits. If you want to have different Length or Scale, you need to set these properties of decimal
field in metadata.
Example 58. Usage of decimal data type in CTL2
If you assign 100.0 / 3
to a decimal variable, its value might for example be 33.333333333333335701809119200333
. As 100.0
is double and 3
is integer, the both operands were firstly converted to double, then the value has been calculated and finally the result value has been converted to decimal. Assigning it to a decimal field (with default Length and Scale, which are 12 and 2, respectively), it will be converted to 33.33D
.
You can cast any float number to the decimal data type by appending the d
letter to its end.
Any numeric data type (integer, long, number/double) can be converted to decimal
.
Example 59. Declaration of decimal variable
decimal d;
decimal d2 = 4.56D; // declaration of variable with assignment
integer
The integer
data type can contain integral values.
CTL2 integer
can store values from -2147483648
to 2147483647
.
The integer
data type can overflow (i.e. adding 1 to the maximum value returns -2147483648
; similarly, subtracting 1 from the minimum value returns 2147483647
) which may lead to errors and/or incorrect results.
The default value is 0
.
Its declaration looks like this: integer identifier;
The value-2147483648
can be stored in CTL2 variable but cannot be stored in an integer field of record metadata (value of the field would be null). If the value-2147483648
is expected to arise, consider usage of data type with wider range of values in metadata; e.g.long
.
If you append the L
letter to the end of any integer number, you can cast it to the long data type.
Integer
can be converted to long, double
or decimal
using automatic conversions.
Example 60. Declaration of integer variable
integeri1;
integer i2 = 1241;
long
long
is an integral data type allowing to store greater values than the integer
data type.
CTL2 long
can store values from -9223372036854775808
to 9223372036854775807
.
The long
data type can overflow (i.e. adding 1 to the maximum value returns -92233720368547758088
; similarly, subtracting 1 from the minimum value returns 9223372036854775807
) which may lead to errors and/or incorrect results.
The default value is 0
.
Its declaration looks like this: long identifier;
The value-9223372036854775808
can be stored in CTL2 variable but the value is used in long field in record metadata fornull
value. If the value-9223372036854775808
is expected to arise, consider usage of data type with wider range of values in metadata; e.g.decimal
.
Any integer number can be cast to long
data type by appending the l
letter to its end.
Long
data type can be converted to number/double
or decimal
without explicit casting.
Example 61. Declaration of long variable
long myLong;
long myLong2 = 2141L;
number (double)
The number
data type is used for floating point number.
The default value is 0.0
.
Its declaration looks like this: number identifier;
If you need a data type for money amount, we advise using decimal
instead of number (double)
.
The integer
and long
data types can be converted to double
using automatic conversions. If long
is being converted to number (double)
, lost of precision may occur.
Number(double)
can be converted to decimal
without explicit casting.
Example 62. Declaration of number (double) variable
double d;
double d2 = 1.5e2;
string
This data type serves to store sequences of characters.
The default value is empty string.
The declaration looks like this:string identifier;
Example 63. Declaration of string variable
string s;
string s2 = "Hello world!";
list
The type of elements of a list may be any other data type, including nested lists or maps.
The elements of a list are indexed by integers starting from 0.
Its declaration can look like this: string[] identifier;
For nested lists or maps, use the following syntax instead: listtype of elements>] identifier;
The default list is an empty list.
Example 64. List
integer[] myIntegerList;
myIntegerList[5] = 123;
// Customer is metadata record name
Customer JohnSmith;
Customer PeterBrown;
Customer[] CompanyCustomers;
CompanyCustomers[0] = JohnSmith;
CompanyCustomers[1] = PeterBrown;
// Nested lists and maps:
list[list[string]] listOfLists;
list[map[string, integer]] listOfMaps;
Assignments
-
myStringList[3] = "abc";
The string"abc"
is put to the fourth position in the string list. The preceding items are filled withnull
as follows:
myStringList is [null,null,null,"abc"]
-
myList1 = myList2;
Assigns a copy ofmyList2
tomyList1
. It means that both lists will contain the same elements. -
myList1 = myList1 + myList2;
Adds all elements ofmyList2
to the end ofmyList1
.
Both lists must be based on the same primitive data type. -
myList = [];
Assigns an empty list tomyList
. -
myList = ["a", "b", "c"];
Assigns a list containing three strings tomyList
. -
myList = null;
Discards the previous value ofmyList
.
map
This data type is a container of pairs of a key and a value.
Its declaration looks like this: maptype of key>,
The Value
can be any of the other data types, including records, nested lists or other maps, but the Key
can only be a primitive data type: boolean, date, decimal, integer, long, number
or string
.
The default map is an empty map.
Example 65. Map
map[string, boolean] map1;
map1["abc"] = true;
// Customer is the name of record
Customer JohnSmith;
Customer PeterBrown;
map[integer, Customer] CompanyCustomersMap;
CompanyCustomersMap[JohnSmith.ID] = JohnSmith;
CompanyCustomersMap[PeterBrown.ID] = PeterBrown;
// Nested maps and lists:
map[string, map[string, integer]] mapOfMaps;
map[integer, list[string]] mapOfLists;
myMap["abc"] = 7;
Puts the value7
intomyMap
under the key"abc"
.myMap2 = myMap1;
Assigns a copy ofmyMap1
tomyMap2
.myMap = {};
Assigns an empty map tomyMap
.myMap = { "a" -> 20, "b" -> 10, "c" -> 30 };
Assigns a map containing three key-value pairs tomyMap
.myMap = null;
Discards the previous value ofmyMap
.
variant
Variables of this type can be assigned values of any other type - no type checking is performed. In particular, variant can contain nested lists and maps, so it can be used for tree-like data with unknown structure, such as JSON.
Its declaration looks like this: variant identifier;
variant data type is supported in data records too.
$out.0.myVariantField = myVariantVariable;
Variant can be used like lists and maps, allowing to access inner values using square brackets [ ]. The operation will fail unless the variable contains a list or a map at runtime.
The default value is null
, so the variable must be initialized to an empty list or map before inserting inner values.
Functions with arguments of type variant can be passed any value. However, they may throw runtime exceptions if the value is not valid for the function. For example, "append(variant list, variant element)" can be passed any value as the first argument, but it will throw an exception unless the value really is a list.
The type supports only a few basic operations (== and != comparison, toString, etc.). In order to perform type-specific operations, the values must be explicitly type-cast to a more specific type. See typeof operator and cast and getType functions.
Example 66. Variant
variant myVariant = {};
myVariant["one"] = 1;
myVariant["string"] = "not a number";
myVariant["two"] = 2;
// working with unknown structures:
integer sum = 0;
if ( myVariant typeof list ) {
for ( integer index = 0; index < length(myVariant); index++) { // iterate through the list
variant element = myVariant[index]; // get list element by the index
string type = getType(element); // get the type of the element
printLog(info, "List element " + index + ": " + element + " " + type);
if (element typeof integer) { // test the type of the element
sum += cast(element, integer); // cast to integer and add to the sum
}
}
} else if ( myVariant typeof map ) {
variant keys = getKeys(myVariant); // returns the keys as a list
for ( integer i = 0; i < length(keys); i++) { // iterate through the list of keys
variant key = keys[i]; // get the key by the index
variant value = myVariant[key]; // get the value by the key
string type = getType(value); // get the type of the value
printLog(info, "Map entry " + key + " = " + value + " " + type);
if (value typeof integer) { // test the type of the value
sum += cast(value, integer); // cast to integer and add to the sum
}
}
}
printLog(info, "Sum: " + sum);
The assignments are similar to those valid for a list or a map:
variant varMap = {};
Assigns an empty map tovarMap
.varMap["abc"] = 7;
IfvarMap
contains a map, puts the value7
intovarMap
under the key"abc"
. Throws an exception otherwise.variant varList = [];
Assigns an empty list tovarList
.varList[5] = "abc"
IfvarList
contains a list with at least 6 elements, sets the list element at index5
to"abc"
. Unlike withList
data type,variant
is not expanded automatically, so ifvarList
contains fewer than 6 elements, the assignment fails. Use append to expand the list. IfvarList
is actually a map, puts"abc"
into the map under the key5
. Otherwise, throws an exception.var2 = var1;
Assigns a copy ofvar1
tovar2
.varMap = {
"name" -> "John Doe",
"weight" -> 75.3,
"valid" -> true
};
Assigns a JSON-like map containing three key-value pairs tovarMap
. Note that the values are of mixed types:string
,number
andboolean
, respectively.varMap = null;
Discards the previous value ofvarMap
.
record
Record is a container that can contain different primitive data types.
The structure of record is based on metadata. Any metadata item represents a data type.
Declaration of a record looks like this: identifier;
Metadata names must be unique in a graph. Different metadata must have different names.
For more detailed information about possible expressions and records usage, see Accessing Data Records and Fields.
Record does not have a default value.
It can be indexed by both integer numbers and strings (field names). If indexed by numbers, fields are indexed starting from 0.
Updated 12 months ago