First Class Functions in Swift

In computer science, functional programming is a programming paradigm where programs are constructed by applying and composing functions. Swift is not purely a functional language, but it does combine multiple programming paradigms to give you flexibility for app development. Even though Swift is not 100% functional language, it does support the first class functions. In this post, we’ll go through different ways of using the first class functions in Swift.
What Are First-Class Functions?
Before jumping in the first class function usage in Swift, lets get the bigger picture of the First Class Functions.
First Class Functions are:
- functions that can be stored in constants and variables
- functions that can be passed as arguments to other functions
- functions that can be returned by other functions
First-Class Functions are also known as first-class citizen in Swift. In a nutshell, having a first class functions means that those functions can be treated and store in different forms throughout the Swift Project.
Another language that uses First Class Functions is Javascript. The functions can be assigned to any other variable or passed as an argument or can be returned by another function. JavaScript treat function as a first-class-citizens. This means that functions are simply a value and are just another type of object.
Storing Functions in Variables and Constants
As mentioned in the paragraph above, the first class functions can be stored in variables and constants. In the example below, NameofClass declares a property check() which has an optional type. The type of the property is a function that accepts no arguments and returns Void.
The nameofFunction() method invokes the function the check() property references. It uses optional chaining to safely access the value of the check() property. In this case the check() function is the first-class function.
internal final class NameofClass{
// MARK: - Properties
var check: (() -> Void)?
// MARK: - Helper Methods
private func NameofFunction() {
check?()
}
}If we want to call the first-class function in a different part of the project, firstly make sure you have declared the function globally or initiate the path where the function is located in the project.
NameofClass.check = { [weak self] in
self?.HomeView() //this is the view we are calling the check function in.
}In this example, we set the value of the check property of a NameoClass instance by assigning a closure to it. A closure is a function. We use the term closure if the function captures constants and variables from the surrounding context in which it is defined. The closure we assign to the check property of the NameofClass captures a reference to self. That is why we use the term closure.
You can use such example to in the Sessions of login in or signing up. This helps with keeping a session or destroying it based on the users flow.
Passing a Function As an Argument
The best way to explain this example of passing the first class function as an argument is through the animations in UIView class. Check more in Apple’s documentation for animate(withDuration:anumations)
Declaration
class func animate(
withDuration duration: TimeInterval,
animations: @escaping () -> Void
)Parameters
duration
The total duration of the animations, measured in seconds. If you specify a negative value or 0, the changes are made without animating them.
animations
A block object containing the changes to commit to the views. This is where you programmatically change any animatable properties of the views in your view hierarchy. This block takes no parameters and has no return value. This parameter must not be NULL.
Example
We call animate(withDuration:animations:) on UIView to animate the alpha property of likeButton.
// Hide Like Button
UIView.animate(withDuration: 1.0) {
self.likeButton.alpha = 0.0
}The first argument is the duration of the animation and the second argument is a closure. Passing a closure as the second argument of the animate(withDuration:animations) method is only possible because functions are first-class citizens in Swift.
Return a Function From a Function
Returning a Function from a Function can be confusing but take a minute to understand what we are trying to do here. There will be a function in which the return type will be another function. Think of reverse functions; you call the return the current function within the function. We are trying to apply the same logic here but not in revers manner (it will just keep getting complicated).
This is without a doubt the most complex code snippet of this episode. But let’s break the function definition up into smaller pieces that make more sense.
func decrement(by decrement: Int) -> (Int) -> Int {
{ (value) in value - decrement }
}We define a function decrement(by:) that accepts an argument of type Int. The return type of the decrement(by:) function is a function type. The function that is returned accepts an argument of type Int and returns a value of type Int. That is why the return arrow appears twice in the function definition. We can make this more explicit by wrapping the return type in parentheses.
func decrement(by decrement: Int) -> ((Int) -> Int) {
{ (value) in value - decrement }
}The body of the decrement(by:) function isn't that complex. We create a closure that accepts one argument and returns a value of type Int. We could make this example more explict:
func decrement(by decrement: Int) -> ((Int) -> Int) {
{ (value) -> Int in
value - decrement
}
}Let’s put the decrement(by:) function to use. We invoke the decrement(by:) function, passing it a value, 10. The function the decrement(by:) function returns is stored in a constant with name decrementByTen.
func decrement(by decrement: Int) -> ((Int) -> Int) {
{ (value) -> Int in
value - decrement
}
}
let decrementByTen = decrement(by: 10)As we explored earlier, first-class functions can be stored in variables and constants. ThedecrementByTen constant holds a reference to a function. This means that we can call the function stored in decrementByTen.
decrementByTen(20) // 10Conclusion
First class functions is a very powerful feature. By being able to use functions and methods in a much more dynamic way we can achieve some pretty interesting results, and it can be really useful when implementing certain kinds of APIs.
While learning about these kinds of features and how they work is super useful, exercising some restraint when using them is also essential. The goal should always be to create APIs that are easy to use, as well as to write code that is both easy to read and maintain. Having first class functions can definitely help us accomplish that goal, but if taken too far, it can also lead to quite the opposite outcome. You should experiment, try out these features, and see for yourself how and if you can incorporate them into your own code.
