Search code examples
swiftfunctionarguments

Understanding named vs positional function call in Swift


I'm encountering an issue with my code and I'm trying to understand why the initial call to add fails with a "Missing argument" error, while it runs successfully when passed to a different function where it is called without the argument labels.

I found a discussion on this topic at Why does Swift require parameter names if it also requires argument order?, but I'm having trouble grasping all the details and determining its relevance to my query.

func add(x: Int, y: Int) -> Int {
    x + y
}

func wrapper(function: (Int, Int) -> Int) -> Int {
    function(1, 2)  // Why does this not produce a "Missing argument" error?
}

// "Missing argument" error
// print(add(1, 2))

// No Error - I think I understand why this works
print(add(x: 1, y: 2))  // Outputs: 3

// How does this work?
print(wrapper(function: add))  // Outputs: 3

Solution

  • How does this work?

    print(wrapper(function: add))  // Outputs: 3
    

    Fact 1

    wrapper is a function which receives 1 argument with this type:

    (Int, Int) -> Int
    

    Fact 2

    The type of your add function is

    (Int, Int) -> Int
    

    You can confirm this with Xcode:

    1. Assign your function to a constant
    2. ctrl + click on the constant name

    enter image description here

    Conclusion

    Since the type of the argument of wrapper is the same of add, then this code compiles

    wrapper(function: add)
    

    Additional question from comment

    can you explain a bit more on why the arguments are needed when its called outside and no longer needed when it's called inside a function?

    Because:

    1. Closures in Swift don't have external parameter names.
    2. You can pass a function where a closure is required, as long the the input type and output type do match.

    So when you write

    wrapper(function: add)
    

    you are passing the add function to wrapper. This is allowed because the types do match.

    Then when you write

    func wrapper(function: (Int, Int) -> Int) -> Int {
        function(1, 2)  // Why does this not produce a "Missing argument" error?
    }
    

    In the second line you are now invoking a closure which does not have external parameter names.