Search code examples
swiftclosures

Error combining an element and an array in Swift Array Extension - Works in Xcode but not in LeetCode


I've been trying to implement a function inside an Array extension in Swift that returns all the permutations of an array. When I run this code in Xcode, it seems to work just fine. However, when I tried the same code in LeetCode, I encountered the following error:

Line 10: Char 24: error: cannot convert value of type 'Array<Element>' to closure result type 'Element'
[tar]  +  ac

Here's a snippet of my code:

extension Array  {
    func permute() -> [[ Element ]] {
        guard !isEmpty else { return [[]] }

        return (0...count-1).flatMap { i in
            var dup = self
            let tar = dup.remove(at: i)

            return dup.permute().map { ac in
                [tar]  +  ac
            }
        }
    }
}

The line causing the issue is [tar] + ac. I'm puzzled because of the inconsistency in behavior between Xcode and LeetCode. How can I resolve this so that it works on both platforms?

What I tried: I implemented an Array extension in Swift to generate all permutations of an array. The approach I took was to recursively break down the problem, removing each element and getting permutations of the rest. Then I would combine the removed element with these permutations.

Expected Outcome: I expected my permute() function to return all possible permutations of the input array. When tested in Xcode, it provided the correct results, with each permutation being a separate array.

Actual Result: When I transferred the code to LeetCode and attempted to run it, I encountered a compile-time error on the line [tar] + ac. The error stated:

This was surprising as there was no such issue in Xcode.


Solution

  • It seems Leetcode is using an older version of Swift, probably Swift 5.6, since the error is reproducible on Swiftfiddle as well using the 5.6 compiler.

    You simply need to type annotate the return values of the closures and your code will compile fine using Swift 5.6 as well. See this Swiftfiddle playground. The reason you don't need to do this in Swift 5.7 and later is SE-0326, which was implemented in Swift 5.7 and enabled multi-statement closure return type inference.

    extension Array  {
        func permute() -> [[ Element ]] {
            guard !isEmpty else { return [[]] }
    
            return (0...count-1).flatMap { i -> [[Element]] in
                var dup = self
                let tar = dup.remove(at: i)
    
                return dup.permute().map { ac -> [Element] in
                    [tar]  +  ac
                }
            }
        }
    }