Search code examples
swiftoverloadingextension-methods

Calling an overloaded function in recursive function in Swift


I was doing an online exercise for learing Swift. The following code is a test case singled out to show the issue with calling an overloaded version of a function that is called in a recursive situation.

import Foundation

//Solution goes in Sources
extension Array where Element: Comparable {
    func accumulate (_ acc: (Element) throws -> Element) rethrows -> [Element] {
        var newArray : [Element]?
        
        try self.forEach{try newArray?.append(acc($0))}
        
        return newArray!
    }
    func accumulate (_ acc: (Element) throws -> [Element]) rethrows -> [[Element]] {
        var newArray : [[Element]]?
        
        try self.forEach{try newArray?.append(acc($0))}
        
        return newArray!
    }
}
let input =   ["a", "b", "c"]
let expected = [
    ["a1", "a2", "a3"],
    ["b1", "b2", "b3"],
    ["c1", "c2", "c3"]
] // The expected result of the statement on the bottom of this code
func recurse(_ input: String) -> [String] {
    func appendTo(_ innerInput: String) -> String {
        return input+innerInput
    }
    let result = ["1", "2", "3"].accumulate(appendTo)
    print("3")
    return result
}
let result = input.accumulate(recurse)

When run, the compiler didn't complain, but the runtime showed the following error message:

Fatal error: Unexpectedly found nil while unwrapping an Optional value
Current stack trace:
0    libswiftCore.so                    0x00007fa0d799c920 _swift_stdlib_reportFatalError + 69
1    libswiftCore.so                    0x00007fa0d78aaa06 <unavailable> + 3279366
2    libswiftCore.so                    0x00007fa0d78aad85 <unavailable> + 3280261
3    libswiftCore.so                    0x00007fa0d76d2810 _fatalErrorMessage(_:_:file:line:flags:) + 19
4    main                               0x000055df0a54ef3a <unavailable> + 7994
5    main                               0x000055df0a54e63e <unavailable> + 5694
6    libc.so.6                          0x00007fa0d6052ab0 __libc_start_main + 231
7    main                               0x000055df0a54e09a <unavailable> + 4250
exited, illegal instruction

Please kindly tell me what wrong there is with my code and explain the reason.

Thank you very much!


Solution

  • The issue you're experiencing has nothing to do with overloading per se. You just have newArray = nil in every variant that you try to force unwrap, for example:

    func accumulate (_ acc: (Element) throws -> Element) rethrows -> [Element] {
        var newArray : [Element]? // here, newArray = nil
        
        // newArray is still nil, and newArray?.append does nothing
        try self.forEach{try newArray?.append(acc($0))}
        
        // new array is still nil, and you force unwrap nil, hence Unexpectedly found nil while unwrapping an Optional value
        return newArray!
    }
    

    To fix that you can just assign some value to newArray in the beginning:

    var newArray : [Element] = []
    

    If you're still learning swift, I would suggest to adopt the "never force unwrap (unless completely necessary)" rule. Additionally, I would suggest to never force cast as well. You can almost always rewrite your code without force unwrap/cast.