| Data type name | Ride keyword |
|---|---|
| Big Integer | BigInt |
| Boolean | Boolean |
| Byte array | ByteVector |
| Integer | Int |
| String | String |
| Empty value | Unit |
| List | List |
| Tuple | — |
| Union | — |
| Structure | — |
| Arbitrary type | Any |
For each value, depending on the data type, the weight is determined. The weight is used in limitations on creating and comparing values. For more information see the data weight.
Any is an arbitrary data type. It is a common supertype of all types: an Any type value can be a string, a number, unit, a structure, a list, a tuple, etc.
func findString(a: Any) = {
match a {
case a: String => a
case a: List[Any] =>
match a[0] {
case b: String => b
case _ => throw("Data is not a string")
}
case _ => throw("Data is not a string")
}
}BigInt is a special numeric data type designed to handle values outside the range of Int and to perform high accuracy calculations. BigInt variable has a size of 64 bytes (512 bits) and contains an integer between –2511 to 2511–1, inclusive. The weight of the value is 64. A BigInt variable can only be used inside a script. A callable function does not accept arguments of BigInt type and does not return a value of BigInt type. You can pass a big integer value as a string, then use the parseBigInt or parseBigIntValue functions.
The following operators support BigInt values:
The following functions operate BigInt values:
Boolean is a data type that can have only the values true or false.
ByteVector is a data type for byte array.
To assign a value to a ByteVector variable, you can use a string in Base16, Base58, or Base64 with the appropriate prefix:
let a = base16'52696465' let b = base58'8t38fWQhrYJsqxXtPpiRCEk1g5RJdq9bG5Rkr2N7mDFC' let c = base64'UmlkZQ=='
This method, unlike the fromBase16String, fromBase58String, and fromBase64String functions, does not increase the complexity of the script, since decoding is performed by the compiler. To convert integer, boolean and string values to a byte array use toBytes function:
let a = 42.toBytes() let b = true.toBytes() let c = "Ride".toBytes()
For more byte array functions, see the Built-in Functions.
The maximum size of a ByteVector variable is 32,767 bytes. Exception: the bodyBytes field of transaction structure. You can pass this value as an argument to the rsaVerify и sigVerify verification functions (but cannot concatenate with other byte arrays in case the limit is exceeded).
Int is an integer data type. The integer variable has the size of 8 bytes and stores an integer from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 inclusive.
let age = 42
let length = size("hello")Strings are denoted only using double quotes. They are immutable, and for that reason, the substring function is very efficient: no copying is performed and no extra allocations are required. Strings are UTF-8 encoded.
let name = "Bob" # use "double" quotes only
The maximum size of a String variable is 32,767 (1 character can take up to 4 bytes).
The built-in functions for working with strings are presented in the following articles:
Unit is an empty value data type. The empty value data type is similar to unit in Scala or to null in C#. Usually, built-in functions return unit value of type unit instead of null.
"String".indexOf("substring") == unit # trueNothing is the 'bottom type' of Ride’s type system. No value can be of type nothing, but an expression of type nothing can be used everywhere. In functional languages, this is essential for support for throwing an exception:
2 + throw() # the expression compiles because
# there's a defined function +(Int, Int).
# The type of the second operand is Nothing,
# which complies to any required typeThe list data type may contain elements of various types, including nested lists. The maximum number of list items is 1000. The nesting depth is not limited. A list doesn't have any fields, but there are functions and operators in the Standard library that make it easier to work with fields.
let list = [16, 10, 1997, "birthday"] let last = list[(list.size() - 1)] # "birthday", postfix call of size() function let initList = [16, 10] # init value let newList = cons(1997, initList) # [1997, 16, 10] let newList2 = 1997 :: initList # [1997, 16, 10] let newList2 = initList :+ 1 # [16, 10, 1] let newList2 = [4, 8, 15, 16] ++ [23, 42] # [4 8 15 16 23 42]
Lists support concatenation as well as adding items to the beginning and the end.
| Operation | Symbol | Complexity |
|---|---|---|
| Concatenation | ++ | 4 |
| Adding the element to the end of the list (the list is on the left, the element is on the right) | :+ | 1 |
| Adding the element to the beginning of the list (the element is on the left, the list is on the right) | :: | 2 |
Operation to be used:
nil :+ 1 :+ 2 :+ 3
Result: [1, 2, 3]
Operation to be used:
1 :: 2 :: 3 :: nil
Result: [1, 2, 3]
Operation to be used:
let intList = [1, 2] # List[Int] let strList = ["3", "4"] # List[String] let joined = intList ++ strList # List[Int|String] joined
Result: [1, 2, "3", "4"]
Operation to be used:
let appended = joined :+ true # List[Boolean|Int|String] appended
Result: [1, 2, "3", "4", true]
Operation to be used:
let nested = intList :: joined # List[Int|List[Int]|String] nested
Result: [[1, 2], 1, 2, "3", "4"]
The built-in list functions are presented in the list functions article. Operations on a list can be implemented via the FOLD macro. The size of the list must be known in advance.
A list, including nested one, can be a function argument:
func foo(arg: List[String|Unit]) = {
...
}
foo(["Ride","DecentralCoins",unit])func bar(arg: List[List[Int]]) = {
...
}
bar([[1],[],[5,7]])A callable function can take a list as an argument, but nested lists are not allowed. Here’s an example:
@Callable(i)
func join(strings: List[String|Int]) = {
let a = match strings[0] {
case n:Int => toString(n)
case s:String => s
}
let b = match strings[1] {
case n:Int => toString(n)
case s:String => s
}
let c = match strings[2] {
case n:Int => toString(n)
case t:String => t
}
[
StringEntry(toBase58String(i.caller.bytes), a + "_" + b + "_" + c)
]
}Invoke Script transaction example:
{
"type": 16,
...
"call": {
"function": "join",
"args": [
{
"type": "list",
"value": [
{
"type": "string",
"value": "Ride"
},
{
"type": "integer",
"value": 5
},
{
"type": "string",
"value": "DecentralCoins"
}
]
}
]
},
...
}A tuple is an ordered collection of elements. Elements can be of any type. The tuple can contain from 2 to 22 elements.
Let's see some tuples:
let x=("Hello DecentralChain",42,true)
x._2Result: 42
And this one also:
let (a,b,c)=x c
Result: true
Union is a data type that unites 2 or more data types. Union can combine primitive types, lists, tuples, structures. This type is a very convenient way to work with abstractions. Union(String | Unit) shows that the value is an intersection of these types.
To get a value of a particular type from a Union, you can use:
let valueFromBlockchain = getString("3PHHD7dsVqBFnZfUuDPLwbayJiQudQJ9Ngf", "someKey") # Union(String | Unit)The simplest example of Union types is given below (please bear in mind that defining custom user types in dApp code will be supported in future versions):
type Human : { firstName: String, lastName: String, age: Int}
type Cat : {name: String, age: Int }Let's see anoter example where each element of a List[Int|String] is a string or an integer.
let aList = [1, 2, "DecentralCoins"] # List[Int|String] let bList = [true,false] # List[Boolean] let joined = aList ++ bList # List[Boolean|Int|String]
Let’s revisit the example above:
type Human : { firstName: String, lastName: String, age: Int}
type Cat : {name: String, age: Int }
Union(Human | Cat) is an object with one field, age, but we can use pattern matching like this:Human | Cat => { age: Int }This is designed to check a value against value type:
let t = ... # Cat | Human
t.age # OK
t.name # Compiler error
let name = match t { # OK
case h: Human => h.firstName
case c: Cat => c.name
}This is a mechanism for knowing the type of a transaction:
let amount = match tx { # tx is a current outgoing transaction
case t: TransferTransaction => t.amount
case m: MassTransferTransaction => m.totalAmount
case _ => 0
}There are different types of transactions, if a transaction is TransferTransaction or MassTransferTransaction we use the corresponding field, while in all other cases, we will get 0.
Elsewhere on this site