How does Swift choose between 2 functions that are exactly the same but only different generic constraints?

Hi guys. Sorry about the confusing title.

Here is the situation.

I have a protocol defining two methods about encoding.

  • One for Codable objects:
func set<Object: Codable>(_ object: Object?, by key: Key) throws
  • The other one for NSObjects that are NSCoding:
func set<Object: NSObject & NSCoding>(_ object: Object?, by key: Key) throws

When I pass in an object that is an NSObject, Codable and NSCoding, it prefers the Codable function:

class Annoying: NSObject, Codable, NSCoding {
    func encode(with coder: NSCoder) { }
    required init?(coder: NSCoder) { }
    override init() { }
}

cache.set(Annoying(), by: "key")

My questions are

Why won't this cause ambiguity error?

Is this a defined behavior? Is this guaranteed in future Swift versions?

You can use @​_disfavoredOverload to demote the first overload.

Do not do this. It is not a supported attribute and can break at any time. If you need to favor a particular overload in “tie-breaking,” consider creating a separate overload with a clearly more specific set of constraints (e.g., NSObject & NSCoding & Codable).

2 Likes