Closure vs Function

In this article, we will talk about ‘Closure vs Function’. It is not incorrect to claim that closure and function are the same. Closure, however, offers a few more features. We can state that functions are just named closures.

Global and nested functions are special cases of closures. Closures take one of three forms:

  1. Global functions are closures that have a name and don’t capture any values.
  2. Nested functions are closures that have a name and can capture values from their enclosing function.
  3. Closure expressions are unnamed closures written in a lightweight syntax that can capture values from their surrounding context.

Difference between Function and Closure – 

  1. The function is declared using the func keyword whereas Closure doesn’t have the func keyword. Closure is similar to functions but can be written more concisely. Closures don’t require a separate name and can be written inline using a lightweight syntax.
  2. The Function has always a name but Closure doesn’t.
  3. The function doesn’t have in keyword but closure has in the keyword.

The above three are very simple differences, But now discuss the actual differences (Closure vs Function)-

4. Shorthand argument name –

Swift automatically provides shorthand argument names to inline closures. This feature is in only with closure not in function. Example –

let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella”].

We sort it by swift standard library function sorted(by:). The sorted(by:) method accepts a closure that takes two arguments of the same type as the array’s contents.

func backward(_ s1: String, _ s2: String) -> Bool {
    return s1 > s2
}

var reversedNames = names.sorted(by: backward)
// reversedNames is equal to ["Ewa", "Daniella", "Chris", "Barry", "Alex"]

We are sending a lengthy backward function in the example above. Thus, we use the Shorthand form to send a closure here. This is the additional factor that distinguishes closure from function.

reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )

We may sort it out with the following level.

Swift automatically provides shorthand argument names to inline closures, which can be used to refer to the values of the closure’s arguments by the names $0, $1, $2, and so on.

reversedNames = names.sorted(by: { $0 > $1 } )

We can make it one more level short with the help of the ‘Operator’ method

reversedNames = names.sorted(by: >)

These shortened levels are possible in closure not in function. Here, we can say that closure is useful for writing shorter versions of function-like constructs without a full declaration and name.

5. Trailing Closure is a feature that makes closure different from function –

If you need to pass a closure expression to a function as the function’s final argument and the closure expression is long, it can be useful to write it as a trailing closure instead. You write a trailing closure after the function call’s parentheses.

Example:

func someFunctionThatTakesAClosure(closure: () -> Void) {
    // function body goes here
}

// Here's how you call this function without using a trailing closure:
someFunctionThatTakesAClosure(closure: {
    // closure's body goes here
})


// Here's how you call this function with a trailing closure instead:
someFunctionThatTakesAClosure() {
    // trailing closure's body goes here
}

In the below example – We are passing the ‘completion’ parameter as function/closure. 

    func executeClosure(completion: (Bool) -> Void) {
        completion(true)
        print("Function completed")
    }

If we call the execute Closure function like below, then the ‘completion’ parameter is passed as closure.

        executeClosure { success in
            print(success)
        }

//Here, we are utilizing it as a trailing closure, which makes it easy to use within the body of a function.

We can pass it as a function with the below code-

  func completionFunction(success: Bool) {
        print(success) // true
   }

    override func viewDidLoad() {
        super.viewDidLoad()
        executeClosure(completion: completionFunction)
    }

Here, we can say that closure enables developers to write flexible, dynamic code that is easy and convenient both to write and to understand.

6. @autoclosure and @escaping are other types that closure only provides. Not function.

This is also the main difference between closures and functions-

By default, functions are non-escaping, which means that they are executed within the scope where they are defined.

  • Functions: By default, functions are non-escaping, They are executed immediately and synchronously within the scope where they are called. They are limited by the enclosing scope.
  • Closures: By default, closures are also non-escaping, But They can be declared as @escaping or @nonescaping. An escaping closure can be stored outside the function’s scope and executed later, allowing it to outlive the function that received it as an argument.
func executeOperation(completion: @escaping () -> Void) {
    // Escaping closure passed as an argument
    DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
        completion()
    }
}

func performTask() {
    executeOperation {
        // This closure is executed after 1 second
        print("Operation completed")
    }
    // Code here might continue executing before the closure above executes
}

In the above example, executeOperation takes an escaping closure as an argument named is ‘completion’. It schedules the closure to execute after a delay. ‘completion’ will be called after the function returns, it is because of @escaping.

If we don’t use @escaping, ‘completion’ can be called after some delay. It will throw the error, as in below example.

Closure vs Function

Conclusion – (Closure vs Function)

Closure is similar to functions but can be written more concisely. Closures don’t require a separate name and can be written inline using a lightweight syntax.

The key differences between functions and closures lie in their syntax and usage. Functions have a more formal structure and are defined with the func keyword, while closures have a shorter syntax, often used for shorter, more compact operations.

Depending on the readability and context of your code, you can decide between a function and a closure. Closures are useful for quick, one-time tasks like sorting or filtering collections, but functions are preferred for intricate, reusable code blocks. The decision to use a closure or a function in Swift ultimately comes down to the particular needs and coding style of your project.

Closure can be @escaping but function doesn’t.

References –

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/closures/

After reading this ‘Closure vs Function’ post, you can get more details about closures.

https://codegeekworld.com/closure-in-swift-all-about-the-closure

Leave a Reply

Your email address will not be published. Required fields are marked *