Developer Resources
How Does Candid Work?
Find out how the Internet Computer’s interface description language works
Candid’s Functionality
Understanding how Candid works
Candid helps developers to connect programs written in a given host language, such as Motoko, Rust, or JavaScript, with the Internet Computer. For this reason, developers do not have to treat their program data as Candid values. Instead, Candid is used to transparently transport the values of the host language to a canister on the Internet Computer. The canister will then treat the receipt values as native Motoko or Rust values.
Candid Service Descriptions
In our introduction to Candid, we have explored what Candid is and covered the set of types available to developers. You can use these Candid types to describe a service once you are familiar with them.
To help you better understand how Candid service descriptions are created, let’s have a look at their structure and their constituent parts in the following.
The most basic service description simply specifies a service that has no public methods:
A simple ping
method is added to the service description to give it a single public method:
The method names you choose can be arbitrary strings. If a method name is not a plain identifier, you can quote it via "method with spaces"
.
With a method, you can declare a given sequence of arguments and their result types. The ping
method above does not pass arguments and does not return results. For this reason, ()
is used as an empty sequence for both arguments and results.
A more complex service description would consist of two or more methods. Let’s have a look at a service with a reverse and divMod method that both contain a specific sequence of argument as well as result types:
With the reverse
method, you can set the service to expect a single parameter of type text
. It will then return one value of type text
.
The divMod method expects and returns two nat
type values.
Naming Arguments and Results
The identification of arguments and results happens based on their position and does not depend on their name. The name for a method’s arguments or results is used for documentation purposes only and does not change a method’s type or the passed values.
For example, you can change the type the following way which is not prohibited by Candid:
Similarly, you can also pass divMod
to a service that expects the method to return mod
first.
Reusing Complex Types
Candid enables developers to name and reuse a type multiple times. In such a case, multiple methods may be referring to the same complex type. Here is an example of this:
The type definitions in the above abbreviate existing types but are not defining a new type. You can choose between writing out the records or using address
in the function signature. If two abbreviations have equivalent definitions, they are interchangeable and describe the same type – even if they have different names.
Specifying a Query Method
In the previous example, the query
annotation was used for the get_address
methods. Here’s another example:
We can see from this that the get_address method is invoked as a query call on the Internet Computer. By using a query, developers can utilize an efficient way to retrieve a canister’s information without having to go through consensus.
Encoding and Decoding
Candid allows developers to seamlessly invoke service methods, pass binary-encoded arguments, transfer these arguments via underlying transportation methods, and decode these on the other end. You can find more information about this binary format in the Candid Specification. Here are more properties of the format:
- The Candid binary format prefix is
DIDL...
(and4449444c...
in hex) - Methods results and parameters are sequences of types. As a result, Candid’s binary format always encodes sequences of values
- Compact binary format: 125,000 entries of a (vec nat64) take 1 000 007 bytes
Self-describing binary: the binary format includes condensed type descriptions detailing the type of the values in the description. With this information, the receiving side can detect whether or not a different, non-compatible type was used to send the message
- Deserialization of the arguments succeeds as long as the receiving side expects the type that was being used to serialize the arguments
Service upgrades
The underlying formalism used to ensure upgrades of Candid do not break existing clients is that of subtyping. This formalism ensures that precise rules are defined to indicate how long new service types can communicate with parties that are still using the previous interface description.
Here is an overview of the safe ways services can evolve:
- Adding new methods
- Extending sequence of results, i.e. additional values are returned by existing methods, additional values will be ignored by old clients
- Shortening the parameter list, i.e. extra arguments may be sent by old clients but will be ignored
Extending the parameter list via optional arguments (type
opt...
). Anull
value is assumed if message from old client does not pass the argument when reading- Changing existing parameter types with the restriction that a supertype of the previous type has to be chosen
- Changing existing result types with the restriction that a subtype of the previous type is chosen
Generating service descriptions
Developers can choose between writing their own Candid service description or generating one from their code. When compiling a program, the Motoko compiler is used to automatically generate a Candid service description file.