Candid
All shared types and values in Motoko have a corresponding description in the 'outside world'. This description defines the types and values independently of Motoko or any other language. These alternative descriptions are written in a special Interface Description Language called Candid.
Shared Types
Candid has a slightly different notation (syntax) and keywords to represent shared types.
Primitive types
Primitive types in Candid are written without capital letters:
Motoko | Candid |
---|---|
Bool | bool |
Nat | nat |
Int | int |
Float | float64 |
Principal | principal |
Text | text |
Blob | blob |
Option types
Option types in Candid are written with the opt
keyword. An option type in Motoko like ?Principal
would be represented in Candid as:
opt principal
Tuple types
Tuple types in Candid have the same parenthesis notation ()
. A Motoko tuple (Nat, Text, Principal)
would be represented in Candid as:
(nat, text, principal)
Immutable array types
The immutable array type []
is represented in Candid with the vec
keyword.
A Motoko array type [Nat]
in candid looks like this:
vec nat
Variant types
Variant types in Candid are written with the variant
keyword and curly braces { }
. A Motoko variant like {#A : Nat; #B : Text}
would be represented in Candid like this:
variant {
A : nat;
B : text
};
The #
character is not used
Object types
Object types in Candid are written with the record
keyword and curly braces { }
. A Motoko object type like {name : Text; age : Nat}
in Candid looks like this:
record {
name : text;
age : nat
};
Public shared function types
Public shared function types in Candid have a slightly different notation. A shared public function type in Motoko like shared () -> async Nat
would be represented in Candid like this:
() -> (nat)
Parentheses ()
are used around the arguments and return types. The shared keyword is not used because all representable functions in Candid are by default only public shared functions.
Another example would be the Motoko public shared function type shared query Bool -> async Text
which in Candid would be represented as:
(bool) -> (text) query
Note that the query
keyword appears after the return types.
A Motoko oneway public shared function type shared Nat -> ()
in Candid would be represented as:
(nat) → () oneway
The type
keyword
Type aliases (custom names) in Candid are written with the type
keyword. A Motoko type alias like type MyType = Nat
would be represented in Candid like this:
type MyType = nat
Actor Interfaces
An actor running in a canister has a Candid description of its interface. An actor interface consists of the functions in the actor type and any possible types used within the actor type. Consider the following actor in a Motoko source file main.mo
:
// main.mo
import Principal "mo:base/Principal";
actor {
public type User = (Principal, Text);
public shared query ({ caller = id }) func getUser() : async User {
(id, Principal.toText(id));
};
public shared func doSomething() { () };
};
Only public types and public shared functions are included in the candid interface. This actor has a public type
and two public shared functions
. Both of these are part of its public interface.
The actor could have other fields, but they won't be included in the Candid Interface.
We describe this actor's interface in a Candid .did
file. A Candid Interface contains all the information an external user needs to interact with the actor from the "outside world". The Candid file for the actor above would be:
// candid.did
type User = record {
principal;
text;
};
service : {
getUser: () -> (User) query;
doSomething: () -> () oneway;
}
Our Candid Interface consists of two parts: a type
and a service
.
The service : { }
lists the names and types of the public shared functions of the actor. This is the information needed to interact with the actor from "the outside" by calling its functions. In fact, actors are sometimes referred to as services.
The type reflects the public Motoko type User
from our actor. Since this is a public Motoko type that is used as a return type in a public shared function, it is included in the Candid Interface.
NOTE
The type aliasUser
is a Motoko tuple(Principal, Text)
. In Candid a custom type alias for a tuple is translated intorecord { principal; text }
. Don't confuse it with the Candid tuple type(principal, text)
!
Candid Serialization
Another important use of Candid is data serialization of shared types. Data structures in Motoko, like in any other language, are not always stored as serial (contiguous) bytes in main memory. When we want to send shared data in and out of a canisters or store data in stable memory, we have to serialize the data before sending.
Motoko has built in support for serializing shared types into Candid format. A higher order data type like an object can be converted into a binary blob that would still have a shared type.
Consider the following relatively complex data structure:
type A = { #a : Nat; #b : Int };
type B = { #a : Int; #b : Nat };
type MyData = {
title : Text;
a : A;
b : B;
};
Our object type MyData
contains a Text
field and fields of variant types A
and B
. We could turn a value of type MyData
into a value of type Blob
by using the to_candid()
and from_candid()
functions in Motoko.
let data : MyData = {
title = "Motoko";
a = #a(1);
b = #a(-1);
};
let blob : Blob = to_candid (data);
We declared a variable of type MyData
and assigned it a value. Then we serialized that data into a Blob
by using to_candid()
.
This blob can now be sent or received in arguments or return types of public shared functions or stored in stable memory.
We could recover the original type by doing the opposite, namely deserializing the data back into a Motoko shared type by using from_candid()
.
let deserialized_data : ?MyData = from_candid (blob);
switch (deserialized_data) {
case null {};
case (?data) {};
};
We declare a variable with option type ?MyData
, because the from_candid()
function always returns an option of the original type. Type annotation is required for this function to work. We use a switch
statement after deserializing to handle both cases of the option type.