Skip to main content

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;
FieldDescription
integer.MIN_VALUEMinimum value (-2^63)
integer.MAX_VALUEMaximum 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 a big_integer.

Internally, the type java.lang.BigInteger gets used in the interpreter, and NUMERIC in SQL.

FieldDescription
big_integer.PRECISIONThe maximum number of digits (131072)
big_integer.MIN_VALUEMinimum value (-(10^131072)+1)
big_integer.MAX_VALUEMaximum 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, while decimal('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 store 1E-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, and NUMERIC 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.

FieldDescription
decimal.PRECISIONThe maximum number of decimal digits (131072 + 20)
decimal.SCALEThe maximum number of decimal digits after the decimal point (20)
decimal.INT_DIGITSThe maximum number of digits before the decimal point (131072)
decimal.MIN_VALUEThe smallest nonzero absolute value that a decimal can store
decimal.MAX_VALUEThe 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
note

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
}
FieldDescription
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 specifierData typeOutput description
%bgeneralFormats boolean values as "true" or "false". null is also formatted as "false".
%hgeneralFormat an object's hash code as a hexadecimal string.
%sgeneralRepresents a placeholder for string arguments.
%ccharacterProduces a Unicode character as the result.
%dintegerFormats an integer as a decimal number.
%ointegerFormats an integer as an octal number.
%xintegerFormats an integer as a hexadecimal number (lowercase or uppercase).
%nline separatorInserts 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-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
}
FieldDescription
byte_array(text)Creates a byte_array from a HEX string, for example, '1234abcd'
byte_array.from_hex(text): byte_arraySame as byte_array(text)
byte_array.from_base64(text): byte_arrayCreates a byte_array from a Base64 string
byte_array.from_list(list<integer>): byte_arrayConverts 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_arrayReturns 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_arraySub-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.

FieldDescription
rowid(integer): rowidConverts an integer to rowid. The value must not be negative.
rowid.to_integer(): integerReturns 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);
}
FieldDescription
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