You should be familiar with Borrowing and Escaping Use before reading this section.
The Language Reference & Guide
- Welcome to Emojicode
- Syntax
- The Basics
- Literals
- Variables and Assignment
- Control Flow
- Classes & Value Types
- Overloading
- Operators
- Optionals
- Errors
- Inheritance and Overriding
- Protocols
- Enumerations
- Types and Namespaces
- Types as Values
- Documentation
- Generics
- Callables
- Packages
- Threads
- Safe and Unsafe Code
- Memory Management
- References
- Appendix: The Emojicode Compiler
Callables
Emojicode supports a type called callables. Callables are like methods (or more generally functions) that can be passed like any other object.
Type
The type of a callable is denoted using this syntax:
callable-type βΆ π [type-list] [return-type] [error-type] π
type-list βΆ type | type type-list
Each of the types provided before the return type stands for one argument of that type. The return type is optional. If no return type is specified the callable does not return a value. An error-type can be specified.
Examples:
ππ’β‘οΈπ‘π π Takes an integer argument and returns a string
πβ‘οΈπ£π π Takes no arguments and returns a symbol
ππ π Takes no arguments and does not return a value.
ππ’β‘οΈπ‘π§π§π π May raise a π§
Calling a Callable
Callables are called using this syntax.
callable-call βΆ βοΈ expression [arguments] mood
The first expression must be a callable.
Example of calling a callable:
π greet is of type ππ‘π
βοΈ greet π€Bobπ€βοΈ
An error-prone callable must be handled like any error-prone call by using πΊ, πΊ or π.
Closure
Closures are blocks of code that are not immediately executed but remember the context in which they were created, i.e. the variables and the context of the method, and can be passed around. The type of a closure is, of course, a callable.
A closure is created by a block of code that appears when an expression is expected. This means that every code block that is not part of an βͺοΈ, π , or π βͺοΈ π or π statement or a method or initializer declaration, is a closure.
In contrast to a normal code block, a closure can define arguments and a return type similar to a method.
Formally, its syntax is:
closure βΆ π [ππ₯‘] [closure-parameters] [return-type] statements π
closure-parameters βΆ variable type [closure-parameters]
We can define a very simple closure that does not capture any context like this:
π name π‘
π π€It is a pleasure to welcome the honorable π§²nameπ§²π€ βοΈ
π β‘οΈ greet
βοΈ greet π€Lindaπ€βοΈ
Running this code would print:
It is a pleasure to welcome the honorable Linda
Capturing Variables and Context
Letβs take a look at this example:
π π€ π
πβοΈπ g ππ‘β‘οΈπ‘π π
π βοΈg π€DARTH VADERπ€βοΈβοΈ
π
π
π π
π€LUKEπ€ β‘οΈ ππvar
πππ€ π gπ‘ β‘οΈπ‘
β©οΈ var
πβοΈ
π
Running the above code will print LUKE
. In the above example the value var
was declared and assigned outside the closure. This is called a captured variable. Much the same, you can capture the π context in a closure.
Actually, however, we need to distinguish between escaping and non-escaping closures. By default, every closure is non-escaping and cannot be used as an escaping value. To define an escaping closure the π must be immediately followed by ππ₯‘. When creating a thread, for instance, an escaping closure is required:
π𧡠πππ₯‘
πβοΈ
Escaping closures can capture variables, just like non-escaping closures. However, in escaping closures, the captured variables are constant. In non-escaping closures, the captured variables can be modified, as seen in this example:
π π
π€LUKEπ€ β‘οΈ ππvar
π varβοΈ
πππ€ π gπ‘ β‘οΈπ‘
g β‘οΈ πvar
β©οΈ π€DEATH STARπ€
πβοΈ
π varβοΈ
π
The output of the above code (πππ€ is defined in a previous example) will be:
LUKE
DEATH STAR
DARTH VADER
var
was modified inside the closure and is set to the value g
passed into the closure, which in our case was βDARTH VADERβ. This does not work with an escaping closure.
The following example demonstrates capturing the π context and modifying an instance variable:
π π΅ π
ππ name π‘
π πΌ name π‘ ππ
β π β‘οΈ π‘ π
β©οΈ name
π
βοΈ π title π‘ β‘οΈ ππ‘π π
β©οΈ πππ₯‘ a π‘ π Returning lets the value escape
π€π§²title𧲠π§²aπ§²π€ β‘οΈ πname
π
π
π
π π
ππ΅ π€Arthur Lemmingπ€βοΈ β‘οΈ pi
πpi π€Drπ€βοΈ β‘οΈ nameSetterDr
βοΈnameSetterDr π€Jessica Jonesπ€ βοΈ
π πpiβ β
π
Note that you can capture the object context of a class type in both non-escaping and escaping closures and also modify its instance variables. The context of value types and enums, though, can only be captured in non-escaping closures. Thus the above sample would not compile if π΅ was a value type.
The example below shows how the instance variable of a value type can be captured in a non-escaping closure:
π πΌ π
ππ string π‘ β¬
οΈ π€YODAπ€
π ππ
πβοΈ βοΈ π
πππ€ π gπ‘ β‘οΈπ‘
g β‘οΈ πstring
β©οΈ π€STORMTROOPERπ€
πβοΈ
π
π