Simple types
In Rell, there are several simple data types to represent different kinds of data. They're not composed of other data types and serve as the building blocks for more complex data structures.
Boolean
A simple data type that represents two values: true and false. Booleans are often used for logical operations and
decision-making.
val using_rell = true;
function foo() {
  if (using_rell) print("Awesome!");
}
Integer
A data type for representing whole numbers without fractional parts. Integers are typically used for counting, indexing, and mathematical operations.
val user_age: integer = 26;
| Field | Description | 
|---|---|
| integer.MIN_VALUE | Minimum value (-2^63) | 
| integer.MAX_VALUE | Maximum value (2^63-1) | 
| integer(s: text, radix: integer = 10) | Parse a signed string representation of an integer, fails if invalid | 
| integer(decimal) | Converts a decimal to an integer, rounding towards 0 (5.99 becomes 5, -5.99 becomes -5), throws an exception if the resulting value is out of range | 
| integer.from_text(s: text, radix: integer = 10) | Same as integer(text, integer) | 
| integer.from_hex(text) | Parse an unsigned HEX representation | 
| .abs() | Absolute value | 
| .max(integer) | Maximum of two values | 
| .max(decimal) | Maximum of two values (converts this integer to decimal) | 
| .min(integer) | Minimum of two values | 
| .min(decimal) | Minimum of two values (converts this integer to decimal) | 
| .to_text(radix: integer = 10) | Convert to a signed string representation | 
| .to_hex() | Convert to an unsigned HEX representation | 
| .sign() | Returns -1, 0, or 1 depending on the sign | 
| .signum() | Returns the sign of the integer: -1 if negative, 0 if zero, and 1 if positive. | 
| .pow(exponent: integer) | Raises a number to the power of an exponent. | 
| .hex() | Converts this integer to a hexadecimal string. | 
| .parseHex() | Parses an unsigned hexadecimal representation of an integer. | 
| .str() | Converts this integer to a text string. | 
| .to_big_integer() | Converts this integer to a big integer. | 
| .to_decimal() | Converts this integer to a decimal. | 
Big integer
A data type that represents large integers with high precision, capable of handling very large numbers.
val bi: big_integer = 9223372036854775832L;
You must add
Lto the value to specify that the value must be interpreted and treated as abig_integer.
Internally, the type java.lang.BigInteger gets used in the interpreter, and NUMERIC in SQL.
| Field | Description | 
|---|---|
| big_integer.PRECISION | The maximum number of digits (131072) | 
| big_integer.MIN_VALUE | Minimum value ( -(10^131072)+1) | 
| big_integer.MAX_VALUE | Maximum value ( (10^131072)-1) | 
| big_integer(integer) | Creates a big_integerfrominteger | 
| big_integer(text) | Creates a big_integerfrom adecimalstring representation, possibly with a sign. It fails if the string is not valid. | 
| big_integer.to_integer() | Converts big_integertointeger. Fails if the value is out of range. | 
| integer.to_big_integer() | Converts integertobig_integer | 
| big_integer.to_decimal() | Converts big_integertodecimal | 
| decimal.to_big_integer() | Converts decimaltobig_integer. Truncates the fractional part. | 
| big_integer.to_bytes() | Converts a signed (positive or negative) big_integerto abyte_array. | 
| big_integer.from_bytes(byte_array) | Converts a byte_arrayproduced by.to_bytes()back tobig_integer. | 
| big_integer.to_bytes_unsigned() | Converts a positive big_integerto abyte_array. Fails if a negative value is provided. | 
| big_integer.from_bytes_unsigned(byte_array) | Converts a byte_arrayproduced by.to_bytes_unsigned()back tobig_integer. | 
| .abs() | Absolute value of the big_integer | 
| .max(big_integer) | Maximum of two values | 
| .max(decimal) | Maximum of two values (converts this big_integertodecimal) | 
| .min(big_integer) | Minimum of two values | 
| .min(decimal) | Minimum of two values (converts this big_integertodecimal) | 
| .to_text() | Converts to a decimal string representation. | 
| .from_text(text) | Converts from a decimal string representation. | 
| .to_text(radix: integer) | Converts to a string representation with a specific base (radix, from 2 to 36) | 
| .from_text(text, radix: integer) | Converts from a string representation with a specific base (radix, from 2 to 36) | 
| .to_hex() | Convert to an unsigned HEX representation. Supports positive and negative numbers. | 
| .from_hex(text) | Parse an unsigned HEX representation. Supports positive and negative numbers. | 
| .sign() | Returns -1,0, or1depending on the sign. | 
| .pow() | Raises a number to the power of an exponent. | 
Decimal
A data type for representing real numbers with high precision.
val approx_pi: decimal = 3.14159;
val scientific_value: decimal = 55.77e-5;
It's not a normal floating-point type found in many other languages (like float and double in C/C++/Java):
- 
decimaltype is accurate when working with numbers within its range. All decimal numbers (results of decimal operations) are implicitly rounded to 20 decimal places. For instance,decimal('1E-20')returns a non-zero, whiledecimal('1E-21')returns a zero value.
- 
Numbers get stored in a decimal form, not binary form, so conversions to and from a string are lossless (except when rounding occurs if there are more than 20 digits after the point). 
- 
Floating-point types allow storing much smaller numbers, like 1E-300;decimalcan only store1E-20, but not a smaller nonzero number.
- 
Operations on decimal numbers may be considerably slower than integer operations (at least ten times slower for the same integer numbers). 
- 
Large decimal numbers may require a lot of space: ~0.41 bytes per decimal digit (~54KiB for 1E+131071) in memory and ~0.5 bytes per digit in a database. 
- 
Internally, the type java.lang.BigDecimalgets used in the interpreter, andNUMERICin SQL.
- 
In the code, one can use decimal literals: 123.456
 0.123
 .456
 33E+10
 55.77e-5
Such numbers have a decimal type. Simple numbers without a decimal point and exponent, like 12345, have integer
type.
| Field | Description | 
|---|---|
| decimal.PRECISION | The maximum number of decimal digits (131072 + 20) | 
| decimal.SCALE | The maximum number of decimal digits after the decimal point (20) | 
| decimal.INT_DIGITS | The maximum number of digits before the decimal point (131072) | 
| decimal.MIN_VALUE | The smallest nonzero absolute value that a decimalcan store | 
| decimal.MAX_VALUE | The largest value that you can store in a decimal(1E+131072 - 1) | 
| decimal(integer) | Converts an integertodecimal | 
| decimal(big_integer) | Converts a big_integertodecimal | 
| decimal(text) | Converts a text representation of a number to decimal | 
| .abs() | Absolute value | 
| .ceil() | Ceiling value: rounds 1.0 to 1.0, 1.00001 to 2.0, -1.99999 to -1.0, etc. | 
| .floor() | Floor value: rounds 1.0 to 1.0, 1.9999 to 1.0, -1.0001 to -2.0, etc. | 
| .min(decimal) | Minimum of two values | 
| .max(decimal) | Maximum of two values | 
| .round(scale: integer = 0) | Rounds to a specific number of decimal places to a closer value. | 
| .sign() | Returns -1,0, or1depending on the sign | 
| .to_integer() | Converts a decimal to an integer, rounding towards 0. | 
| .to_text(scientific: boolean = false) | Convert to string. | 
| .from_text() | Creates a decimal from a text representation. | 
| .signum() | Returns -1, 0, or 1 depending on the sign. | 
| .to_big_integer() | Converts this decimal to a big_integer by truncating the fractional part. | 
In Rell, the equality comparison for decimal numbers (using the == and != operators) considers two decimal values equal if they represent the same numerical value, regardless of their specific representation or format.
Example: 1.0E+2 is considered equal to 10.0E+1 , thus, 1.0E+2 == 10.0E+1 returns true.
Text
A data type for representing textual information, such as strings of characters. Text data types allow for text
manipulation and processing. Same as string type in some other languages.
val placeholder = "Lorem ipsum donor sit amet";
function foo() {
  print(placeholder.size()); // 26
  print(placeholder.empty()); // false
}
| Field | Description | 
|---|---|
| text.from_bytes(byte_array, ignore_invalid: boolean = false) | If ignore_invalidisfalse, throws an exception when the byte array is not a valid UTF-8 encoded string, otherwise replaces invalid characters with a placeholder. | 
| .empty() | Returns true if the textis empty, otherwise returns false | 
| .size() | Returns the number of characters. | 
| .compare_to(text) | Returns 0 if texts match, otherwise a positive or negative value | 
| .starts_with(text) | Returns true if it starts with the input text, otherwise returns false | 
| .ends_with(text) | Returns true if it ends with the input text, otherwise returns false | 
| .contains(text) | Return true if contains the given substring, otherwise returns false | 
| .index_of(text) | Returns position of input text and -1 if a substring isn't found | 
| .index_of(text, integer) | Same as .index_of(text)but starting search from the given position | 
| .last_index_of(text[, start: integer]) | Returns -1if a substring isn't found | 
| .sub(start: integer[, end: integer]) | Get a substring (start-inclusive, end-exclusive) | 
| .repeat(n: integer) | Returns the text repeated "n" times | 
| .replace(old: text, new: text) | Replaces a substring with new text | 
| .reversed() | Returns a reversed copy of the text | 
| .upper_case() | Returns a new text with all characters converted to uppercase | 
| .lower_case() | Returns a new text with all characters converted to lowercase | 
| .split(text) | Strictly split by a separator (not a regular expression) | 
| .trim() | Remove leading and trailing whitespace | 
| .matches(text) | Returns true if it matches a regular expression | 
| .to_bytes() | Convert to a UTF-8 encoded byte array | 
| .char_at(integer) | Get a 16-bit code of a character | 
| .format(...) | Formats a string. For example, 'My name is <%s>'.format('Bob')- returns'My name is <Bob>' | 
| .charAt() | Gets a 16-bit code of a character. | 
| .compareTo() | Compares this text to another text. | 
| .encode() | Converts the text to UTF-8 encoded bytes. | 
| .len() | Returns the number of characters in the text. | 
| .like() | Returns true if this text matches the specified pattern using SQL LIKE syntax. | 
Here are the options available for the text.format() function in Rell:
| Format specifier | Data type | Output description | 
|---|---|---|
| %b | boolean | Formats booleanvalues as"true"or"false". | 
| %B | boolean | Formats booleanvalues as"TRUE"or"FALSE". | 
| %s | text | Represents a placeholder for textarguments. | 
| %f | decimal | Formats a decimalto 6 decimal places. | 
| %d | integer | Formats an integeras a base-10 number. | 
| %o | integer | Formats an integeras an octal number. | 
| %x | integer | Formats an integeras a hexadecimal number (with lowercase alphabetic characters). | 
| %X | integer | Formats an integeras a hexadecimal number (with uppercase alphabetic characters). | 
You can use most of these text functions within at-expressions where they're translated to their SQL equivalents.
Special operators:
- +: concatenation
- []: character access (returns single-character- text)
Byte array
Byte arrays are used to handle binary data, such as hexadecimal or Base64 representations. You can create byte arrays from text or lists of integers, convert them to different representations, and perform operations like concatenation and element access.
val user_pubkey: byte_array = x"0373599a61cc6b3bc02a78c34313e1737ae9cfd56b9bb24360b437d469efdf3b15";
function foo() {
  print(user_pubkey.to_base64()); //A3NZmmHMazvAKnjDQxPhc3rpz9Vrm7JDYLQ31Gnv3zsV
}
| Field | Description | 
|---|---|
| byte_array(text) | Creates a byte_arrayfrom a HEX string, for example,'1234abcd' | 
| byte_array.from_hex(text): byte_array | Same as byte_array(text) | 
| byte_array.from_base64(text): byte_array | Creates a byte_arrayfrom a Base64 string | 
| byte_array.from_list(list<integer>): byte_array | Converts list to a byte array; values must be 0 - 255 | 
| .empty() | Returns true if the byte_arrayis empty, otherwise returns false | 
| .repeat(n: integer): byte_array | Returns the byte array repeated "n" times | 
| .reversed() | Returns a reversed copy of the byte array | 
| .size() | Returns the number of bytes in the byte array | 
| .sub(start: integer[, end: integer]): byte_array | Sub-array (start-inclusive, end-exclusive) | 
| .to_hex() | Returns a HEX representation of the byte array, for example, '1234abcd' | 
| .to_base64() | Returns a Base64representation of the byte array | 
| .to_list() | Returns a list of values 0 - 255 | 
| .sha256() | Returns the SHA256 digest as a byte_array | 
| .len() | Returns the number of bytes. | 
| .join_to_text() | Creates a text from all the elements separated using separator and using the given prefix and postfix if supplied. If the iterable is large, you can specify a non-negative value of limit, in which case only the first limit of elements will be appended, followed by the truncated text (which defaults to "..."). | 
You can use most of these byte array functions within at-expressions, where they're translated to their SQL equivalents.
Special operators:
- +: concatenation
- []: element access
When working with text or byte_array, validate the length at the start of your operation. This ensures data integrity and improves performance.
val MAX_TEXT_LENGTH = 1000;
operation op(x: text) {
    require(x.size() <= MAX_TEXT_LENGTH);
}
ROWID
The primary key of a database record, a 64-bit integer, supports only comparison operations.
When an entity row is inserted into the database using the create expression, it gets a new unique rowid value from
the same sequence which is greater than the last allocated rowid in the same blockchain. Deleting an entity row
doesn't affect rowids generation. For example, let's assume we have 2 entities a and b:
create a () // rowid = N0
create b () // rowid N1, N1 > N0
create a () // rowid N2, N2 > N1
delete a { .rowid == N2 }
create b () // rowid N3, N3 > N2
rowid supports only comparison operations.
| Field | Description | 
|---|---|
| rowid(integer): rowid | Converts an integertorowid. The value must not be negative. | 
| rowid.to_integer(): integer | Returns the integer value of the rowid. | 
JSON
Stored in PostgreSQL as JSON type and gets parsed to text;
val json_text = '{ "name": "Alice" }';
val json_value: json = json(json_text);
function foo() {
  print(json_value);
}
| Field | Description | 
|---|---|
| json(text) | Create a jsonvalue from a string; fails if not a valid JSON string | 
| .to_text() | Convert the jsonvalue to a string | 
| .str() | Convert the jsonvalue to a string | 
Unit
No value; can't use it explicitly. Equivalent to [unit]{.title-ref} type in the Kotlin programming language.
Null
Type of null expression; can't use it explicitly.
Simple type aliases
- pubkey=- byte_array
- name=- text
- timestamp=- integer
- tuid=- text