Higher order functions and function types in Swift

A simple [x].map(f) is enough:

func f(_ x: Int, _ y: Int, _ z: Int) {
    print(x * y * z)
}

let x = (1, 2, 3)

_ = [x].map(f) // Prints 6

Or we can make a tuple splat operator:

infix operator •
func •<I, O>(lhs: (I) -> O, rhs: I) -> O { return lhs(rhs) }

func f(_ x: Int, _ y: Int, _ z: Int) {
    print(x * y * z)
}

let x = (1, 2, 3)

f • x // Prints 6

I would say it's more of an inconsistency than a feature. And, now that we have explicit tuple splatting, can we please remove the implicit conversion? :wink:

Your "tuple splat operator" relies on this implicit conversion. Otherwise you would not be able to pass a (Int, Int, Int) -> () where a (U) -> () is expected (try it in a context where you cannot convert types, for example as a generic argument; it won't work).

Yes, I know, hence the wink smiley.

The point I was trying to make is that this implicit conversion is a lot more than the little “convenience/feature” it was accepted as.

It's a source of confusion and leads to further inconsistencies.

Would a change to the solution ranking really cause source compatibility issues here? In my case, I've had to distinguish between generic function args with a different function name or param labels.

// need "testN" (not just "test") function names or this example is currently ambiguous
func test1<T, U>(_ fn: (T) -> U) {
    
}

func test2<T, U, V>(_ fn: (T, U) -> V) {
    
}

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

test2(add)

If we update the ranking to prefer the function that is not implicitly being converted to having a tuple arg, the ambiguity between unary and n-arity generic function args disappears but the code above still works fine. Basically, that change would allow the compiler to disambiguate where users had to manually disambiguate before (as I've done in my example). Is there another example where that isn't true?

1 Like