Functions are portions of code that may take some input and produce an output. They are used to subdivide your program code into logical components.
Clarity features a plethora of built-in functions. We have already seen a few of these in the chapters leading up to this one. Providing a full reference for all of them is out of the scope of this book (for now), but you can refer to the official Clarity Language Reference to find a detailed list. Instead, we will focus on defining custom functions and examining what different kinds of functions exist; namely, public functions, private functions, and read-only functions.
- Public functions can be called externally. That means that another standard principal or contract principal can invoke the function. Public function calls require sending a transaction. The sender thus need to pay transaction fees.
- Private functions can only be called by the current contract—there is no outside access. (Although the source code can obviously still be inspected by reading the blockchain.)
- Read-only functions can be called externally but may not change the chain state. Sending a transaction is not necessary to call a read-only function.
Defining a custom function takes the following general form:
(define-public function-signature function-body)
If you count the input parameters for the
define-public function, you will see that there are only two: the function signature and the function body.
The function signature defines the name of the function and any input parameters. The input parameters themselves contain type signatures.
The pattern of function signatures is such:
(function-name (param1-name param1-type) (param2-name param2-type) ...)
It makes more sense if we look at a few examples. Here is a "hello world" function that takes no parameters:
(define-public (hello-world) (ok "Hello World!") ) (print (hello-world))
A multiplication function that takes two parameters:
(define-public (multiply (a uint) (b uint)) (ok (* a b)) ) (print (multiply u5 u10))
A "hello [name]" function that takes one string parameter:
(define-public (hello (name (string-ascii 30))) (ok (concat "Hello " name)) ) (print (hello "Clarity"))
The expressions that define functions take exactly one expression for the function body. The function body is what is executed when the function is called. If the body is limited to one expression only, then how can you create more complex functions that require multiple expression? For this, a special form exists. The variadic
begin function takes an arbitrary amount of inputs and will return the result of the last expression.
(begin 3 4 5)
A multi-expression function may therefore be put together as follows:
(define-public (print-twice (first (string-ascii 40)) (second (string-ascii 40))) (begin (print first) (print second) (ok true) ) ) (print-twice "Hello world!" "Multiple prints!")
Continue to the next section to understand why that
ok is there at the end.