About differentiating async/non-async versions of a function by name

UPDATE: See this comment below what the problem actually is: The await call very well tells the compiler what version of a function to take as specified there, but it does not know which version to take in the case without await.

If one needs to have two versions of a function, one allowing async calls, and one being used in the synchronous case, those two functions need to be differentiated by different function signatures (name + argument names), like in the following example with forEachAsync: I cannot just name it forEach.

Question: Why is this needed, wouldn't it be possible that the compiler could know which function to choose? I think it is quite ugly not to be able to use the "usual" function names (that is also true for your own APIs).

Something else: I thought that when calling any function that is marked with throws a possible error has to be handled, which is not the case with forEachAsync as defined in the example. I would have thought that I need the out-commented version of forEachAsync in the line with the call to showAsync.

...Which brings me back to the original topic: The compiler seems to be able to differentiate between a throwing and a non-throwing version of a function (just in-comment the other version of forEachAsync and check via "Jump to definition" which version is used in each case). So if the compiler can hold apart a throwing and a non-throwing version, why is the compiler not able to choose an appropriate version regarding async/non-async?

So I wish I would be able to use the same signature (name + name of the arguments) for both an async and non-async version of a function.

public extension Sequence {
    
    /*func forEachAsync (
        _ operation: (Element) async -> Void
    ) async {
        for element in self {
            await operation(element)
        }
    }*/
    
    func forEachAsync (
        _ operation: (Element) async throws -> Void
    ) async rethrows {
        for element in self {
            try await operation(element)
        }
    }
    
}

@main
struct App {
    static func main() async {
        
        func show(_ n: Int) {
            print(n)
        }
        
        func showAsync(_ n: Int) async {
            print(n)
        }
        
        func showAsyncThrowing(_ n: Int) async throws {
            print(n)
        }
    
        [1,2,3].forEach { n in show(n) }
        await [1,2,3].forEachAsync { n in await showAsync(n) }
        
        do {
            try await [1,2,3].forEachAsync { n in try await showAsyncThrowing(n) }
        }
        catch {}
    }
}

The compile can distinguish between async and non-async versions of a function:

Then why is it not possible to name the function forEachAsync just forEach in my example above?

They look to me to be both marked async. The difference is whether they throw, so I though you were illustrating that that distinction worked.

Strange... The following code (without the "...Async" postfix in the function name) actually does function when now trying at another computer. I will have to try again on the original computer (not available here to me at the moment). Very strange, both systems and Xcode being up-to-date. Do I have a running Swift <5.5 on the other system for some reasons? The command line tells otherwise. So I am sorry if I opened a misguiding topic her.... Will update it tomorrow after a new test.

public extension Sequence {
    
    func forEach (
        _ operation: (Element) async throws -> Void
    ) async rethrows {
        for element in self {
            try await operation(element)
        }
    }
    
}

@main
struct App {
    static func main() async {
        
        func show(_ n: Int) {
            print(n)
        }
        
        func showAsync(_ n: Int) async {
            print(n)
        }
        
        func showAsyncThrowing(_ n: Int) async throws {
            print(n)
        }
    
        [1,2,3].forEach { n in show(n) }
        await [1,2,3].forEach { n in await showAsync(n) }
        
        do {
            try await [1,2,3].forEach { n in try await showAsyncThrowing(n) }
        }
        catch {}
    }
}

...Ah, OK, the code below gives the error "Ambiguous use of 'forEach'" at the line with [1,2,3].forEach { n in show(n) }, so the does not know which forEach to take if no await is used in the call. Compare this to this example: declarating somethin async means that it you might use an async or non-async thing at that place. The compiler is not able to differentiate between the too.

In the previous example above the codes used throws and this helped the comoiler to differentiate.

public extension Sequence {
    
    func forEach (
        _ operation: (Element) async -> Void
    ) async {
        for element in self {
            await operation(element)
        }
    }
    
}

@main
struct App {
    static func main() async {
        
        func show(_ n: Int) {
            print(n)
        }
        
        func showAsync(_ n: Int) async {
            print(n)
        }
        
        func showAsyncThrowing(_ n: Int) async throws {
            print(n)
        }
    
        [1,2,3].forEach { n in show(n) }
        await [1,2,3].forEach { n in await showAsync(n) }
        
    }
}

Bug report: Compiler does not know how to choose between an async and a non-async version of a function · Issue #60469 · apple/swift · GitHub