Two overloaded generic func: one general case takes a Collection, one special case takes Collection where Element == Character: when parameter is Collection of Character, is there anyway to force call to general overload version?

// AAA: this is a general case that take a Collection
func foo<C: Collection>(_ a: C) -> C {
    print("foo AAA")
    return a

// bbb: special case for collection of Character's element to return String
func foo<C: Collection>(_ a: C) -> String where C.Element == Character {
    print("foo bbb")
    return String(a)

foo([1, 2, 3])          // calls AAA

foo(["X", "Y", "Z"])    // calls bbb
foo("abc")              // calls bbb

// 👆👆👆  is there anyway to force the above two to call AAA instead?

Edit: the reason to want to call the general one when the input is Collection of Character is to get the result in a Collection of Character instead of [String] in case when you need to.

1 Like

You can use a result type annotation to influence overload resolution, e.g.

let result: [Character] = foo(["X", "Y", "Z"])

// or

foo(["X", "Y", "Z"]) as [Character]

I know two ways:

func forceGeneral<C: Collection>(_ a: C) -> C {
forceGeneral("abc") // calls AAA
let s: some Collection = "abc"
foo(s) // calls AAA

This still call bbb. It make sense as some Collection is still a Collection where Element == Character, which match the constraint of bbb. So I guess adding a func forceGeneral(...) is the only way.

or convert the String to [Character] and use @hborla 's method:

foo("abc".map { $0 }) as [Character]

to avoid any unnecessary conversion, it's best to just provide a func forceGeneral(...)

Edit: oh, sorry, you are right, it's calling "AAA", it's just return the passing in value, so its result is"abc"!


1 Like