Search code examples
swiftmap-function

What aren't these two ways of expressing map function equivalent?


I got a surprise today while looking at another SO question:

let s = "1,a"
let arr = s.split(separator: ",")
let result = arr.compactMap{Int($0)} // ok
let result2 = arr.compactMap(Int.init) // error

Why is line 3 legal but line 4 is not? I would have thought these two ways of saying "coerce the incoming parameter to Int if possible" would be completely equivalent.

I understand that line 4 is choking on the Subsequence, and I see how to get out of the difficulty:

let result2 = arr.map(String.init).compactMap(Int.init) // ok

What I don't understand is why they both don't choke in the same way.


Solution

  • Looks like the Int.init overload that accepts a Substring has the following signature:

    public init?<S>(_ text: S, radix: Int = 10) where S : StringProtocol
    

    So, Int($0) works because it uses the default radix, but there isn't an Int.init(_:) that accepts a Substring - there's only Int.init(_:radix:) that does - and so it fails.

    But if there was one:

    extension Int {
        public init?<S>(_ text: S) where S : StringProtocol {
            self.init(text, radix: 10)
        }
    }
    

    then this would work:

    let result1 = arr.compactMap(Int.init)