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 |
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
L
to 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_integer from integer |
big_integer(text) | Creates a big_integer from a decimal string representation, possibly with a sign. It fails if the string is not valid. |
big_integer.to_integer() | Converts big_integer to integer . Fails if the value is out of range. |
integer.to_big_integer() | Converts integer to big_integer |
big_integer.to_decimal() | Converts big_integer to decimal |
decimal.to_big_integer() | Converts decimal to big_integer . Truncates the fractional part. |
big_integer.to_bytes() | Converts a signed (positive or negative) big_integer to a byte_array . |
big_integer.from_bytes(byte_array) | Converts a byte_array produced by .to_bytes() back to big_integer . |
big_integer.to_bytes_unsigned() | Converts a positive big_integer to a byte_array . Fails if a negative value is provided. |
big_integer.from_bytes_unsigned(byte_array) | Converts a byte_array produced by .to_bytes_unsigned() back to big_integer . |
.abs() | Absolute value of the big_integer |
.max(big_integer) | Maximum of two values |
.max(decimal) | Maximum of two values (converts this big_integer to decimal ) |
.min(big_integer) | Minimum of two values |
.min(decimal) | Minimum of two values (converts this big_integer to decimal ) |
.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 , or 1 depending on the sign. |
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):
-
decimal
type 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
;decimal
can 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.BigDecimal
gets used in the interpreter, andNUMERIC
in 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 decimal can store |
decimal.MAX_VALUE | The largest value that you can store in a decimal (1E+131072 - 1) |
decimal(integer) | Converts an integer to decimal |
decimal(big_integer) | Converts a big_integer to decimal |
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 , or 1 depending on the sign |
.to_integer() | Converts a decimal to an integer, rounding towards 0. |
.to_text(scientific: boolean = false) | Convert to string |
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_invalid is false , 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 text is 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 -1 if 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>' |
Here are the options available for the text.format()
function in Rell:
Format specifier | Data type | Output description |
---|---|---|
%b | general | Formats boolean values as "true" or "false". null is also formatted as "false". |
%h | general | Format an object's hash code as a hexadecimal string. |
%s | general | Represents a placeholder for string arguments. |
%c | character | Produces a Unicode character as the result. |
%d | integer | Formats an integer as a decimal number. |
%o | integer | Formats an integer as an octal number. |
%x | integer | Formats an integer as a hexadecimal number (lowercase or uppercase). |
%n | line separator | Inserts the platform-specific line separator. |
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-charactertext
)
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_array from 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_array from 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_array is 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 characters 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 Base64 representation of the byte array |
.to_list() | Returns a list of values 0 - 255 |
.sha256() | Returns the SHA256 digest as a byte_array |
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
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 integer to rowid . 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 json value from a string; fails if not a valid JSON string |
.to_text() | Convert the json value 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