# Inconsistent function overload resolution between top level call vs call inside generic imp

**URL:** <https://forums.swift.org/t/inconsistent-function-overload-resolution-between-top-level-call-vs-call-inside-generic-imp/36575>\
**Category:** Using Swift\
**Created:** [May 17, 2020, 2:46pm UTC](https://forums.swift.org/t/inconsistent-function-overload-resolution-between-top-level-call-vs-call-inside-generic-imp/36575 "2020-05-17T14:46:20Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![t0rst](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/t0rst/32/11733_2.png) [@t0rst](https://forums.swift.org/u/t0rst)\
**Post date:** [May 17, 2020, 2:46pm UTC](https://forums.swift.org/t/inconsistent-function-overload-resolution-between-top-level-call-vs-call-inside-generic-imp/36575/1 "2020-05-17T14:46:20Z")

</div>

Calls at top-level invoke the overloaded functions I would expect, but same calls from generic implementation fail to differentiate by type.

Using this code in a playground...

```nohighlight
import Foundation

protocol P {}
extension String : P {}

func f(_ o: Any) { print("f(:Any) arg=\(type(of: o)):\(o)") }
func f<T:P>(_ o: T) { print("f<T:P>(:T) arg=\(type(of: o)):\(o)") }

struct Wrapper<T>{
	private let key: String
	private let defaultValue: T
	private var storedValue: T

	init(wrappedValue v: T, key k: String) { defaultValue = v ; storedValue = v ; key = k }

	var wrappedValue: T {
		get { print("get \(key) (\(String(reflecting: type(of: storedValue))))..."); let t = storedValue ; f(t) ; return t }
		set { print("set \(key) (\(String(reflecting: type(of: newValue))))..."); let t = newValue ; f(t) ; storedValue = t	}
	}
}

let i = 1, i2 = 2
let s = "str", s2 = "str2"

f(i) // 1.
f(s) // 2.

var wi = Wrapper(wrappedValue: i, key: "wi")
let i1 = wi.wrappedValue // 3.
wi.wrappedValue = i2 // 4.

var ws = Wrapper(wrappedValue: s, key: "ws")
let s1 = ws.wrappedValue // 5.
ws.wrappedValue = s2 // 6.

```

...I get...

```swift
f(:Any) arg=Int:1 // [1]
f<T:P>(:T) arg=String:str // [2] ok
get wi (Swift.Int)...
f(:Any) arg=Int:1 // [3]
set wi (Swift.Int)...
f(:Any) arg=Int:2 // [4]
get ws (Swift.String)...
f(:Any) arg=String:str // [5] 🤔
set ws (Swift.String)...
f(:Any) arg=String:str2 // [6] 🤔

```

I expected `f<T:P>(:T)` to be invoked where argument is compliant with protocol P, and and `f<T:Any>(:T)` to be invoked for all other types of argument.

I made String adopt P. Call 2 invokes `f<T:P>(:T)` as expect, but the calls embedded in the Wrapper.wrappedValue setter and getter in 5 and 6 do not.

What am I not understanding, or is this a bug?  
Swift 5.1 and 5.2

---

<div class="post-metadata">

**Author:** ![Nevin](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nevin/32/617_2.png) [@Nevin](https://forums.swift.org/u/Nevin)\
**Post date:** [May 17, 2020, 3:03pm UTC](https://forums.swift.org/t/inconsistent-function-overload-resolution-between-top-level-call-vs-call-inside-generic-imp/36575/2 "2020-05-17T15:03:47Z")

</div>

> [@t0rst](#):
>
> What am I not understanding, or is this a bug?

It is not a bug. The calls to `f` within `wrappedValue` are resolved statically at compile-time using the information known about `T`. There are no constraints on `T`, so the `Any` overload is used.

If you want dynamic dispatch at runtime, then constrain `T` to some protocol and call a requirement of that protocol.

---

<div class="post-metadata">

**Author:** ![t0rst](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/t0rst/32/11733_2.png) [@t0rst](https://forums.swift.org/u/t0rst)\
**Post date:** [May 17, 2020, 3:47pm UTC](https://forums.swift.org/t/inconsistent-function-overload-resolution-between-top-level-call-vs-call-inside-generic-imp/36575/3 "2020-05-17T15:47:04Z")

</div>

> The calls to `f` within `wrappedValue` are resolved statically at compile-time using the information known about `T` .

...which is what I want. Dynamic dispatch not needed.

> There are no constraints on `T` , so the `Any` overload is used.

...which is surprising - given all the information known at compile time, why not make the same selection, as in the top level calls - I don't see the difference. I'd appreciate a pointer to where this behaviour is documented - the language guide and reference does not seem to reach the deeper nuances.

The background to this is trying out a UserDefault property wrapper where there isn't a single constrain on T that I can use: there are three trees of T - native plist types (string, number, date, data, dictionary, array) which I make conform to a `PlistPersistable` protocol which can yield and reanimate from a plist-native object, codable types that can be stored as data, and the rest, which can't be supported. I don't see how I could make a constraint on T that is effectively either `PlistPersistable` or `Codable`, and I don't know how to express that an extension to `Codable` could implement the requirements of `PlistCompatible`. (And two flavours of UserDefault is clunky.) Have you solved this kind of problem before, and if so, how?

---

<div class="post-metadata">

**Author:** ![Lantua](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/lantua/32/8868_2.png) [@Lantua](https://forums.swift.org/u/Lantua)\
**Post date:** [May 17, 2020, 4:07pm UTC](https://forums.swift.org/t/inconsistent-function-overload-resolution-between-top-level-call-vs-call-inside-generic-imp/36575/4 "2020-05-17T16:07:51Z")

</div>

> [@t0rst](#):
>
> given all the information known at compile time, why not make the same selection, as in the top level calls

IIRC, the compiler also has an option to use generic implementation of `Wrapper<T>`, as opposed to specialised implementation of `Wrapper<String>`. So the only consistent compile-time choice would be to not use the fact that `T` conforms to `P` even if the specialisation causes it to be so.

> [@t0rst](#):
>
> I don't see how I could make a constraint on T that is effectively either `PlistPersistable` or `Codable`

You could create a new protocol, and provide default implementation for `Codable`, as well as `PlistPersistable`. It may have some problem if a type conform to both, though.

Alternatively you could use `as?`:

```swift
if let value = value as? PlistPersistable {
  ...
} else if let value = value as? Codable {
  ...
}

```

---

<div class="post-metadata">

**Author:** ![t0rst](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/t0rst/32/11733_2.png) [@t0rst](https://forums.swift.org/u/t0rst)\
**Post date:** [May 17, 2020, 6:58pm UTC](https://forums.swift.org/t/inconsistent-function-overload-resolution-between-top-level-call-vs-call-inside-generic-imp/36575/5 "2020-05-17T18:58:49Z")

</div>

> You could create a new protocol, and provide default implementation for `Codable` , as well as `PlistPersistable` . It may have some problem if a type conform to both, though.

I originally wanted any `Codable` to be acceptable as-is as a `T`, but couldn't express this. I've tried a default implementation in `extension `PlistPersistable` where Self : Codable` as you suggested, and this now works, but at the price of requiring an explicit declaration that the `Codable` argument is also `PlistPersistable`. I had hoped that the compiler would automagically recognise that I've provided the glue to make any `Codable` acceptable as `PlistPersistable` without any extra declaration.

Finally, is there anywhere the behaviour at this level is documented?

---

<div class="post-metadata">

**Author:** ![xwu](https://avatars.discourse-cdn.com/v4/letter/x/b487fb/32.png) [@xwu](https://forums.swift.org/u/xwu)\
**Post date:** [May 17, 2020, 8:45pm UTC](https://forums.swift.org/t/inconsistent-function-overload-resolution-between-top-level-call-vs-call-inside-generic-imp/36575/6 "2020-05-17T20:45:43Z")

</div>

> [@t0rst](#):
>
> ...which is surprising - given all the information known at compile time, why not make the same selection, as in the top level calls - I don't see the difference.

Again, this decision is made at compile time. You must think like the compiler. Then, it becomes self-evident. The compiler must determine what `f` means (i.e., which function to call) in the context where it is written.

Where you write `f(s) // 2.`, the compiler knows the static type of `s` to be `String` and knows the conformance of `S` to `P`; therefore, it can determine that you meant to call `f<T: P>(_: T)` at the time that `f(s)` is compiled.

Where you write `let t = storedValue; f(t)`, the compiler knows the static type of `t` to be `T`, which has no constraints. Therefore, it can determine that you meant to call `f(_: Any)` at the time that `f(t)` is compiled. What else could it choose? It cannot choose the other overload, because `T` is not constrained to conform to `P`. It must make a choice, because it must compile the code, and Swift says that `f(t)` must be statically dispatched.

---

<div class="post-metadata">

**Author:** ![Lantua](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/lantua/32/8868_2.png) [@Lantua](https://forums.swift.org/u/Lantua)\
**Post date:** [May 17, 2020, 9:44pm UTC](https://forums.swift.org/t/inconsistent-function-overload-resolution-between-top-level-call-vs-call-inside-generic-imp/36575/7 "2020-05-17T21:44:00Z")

</div>

> [@t0rst](#):
>
> I originally wanted any `Codable` to be acceptable as-is as a `T`

There are two possible designs, whether you want to accept or reject types that don't conform to either `PlistPersistable` or `Codable`.

If you want to accept the _otherwise_ case (and maybe reject it at runtime), you can just use unconstraint `T`, then use the if-else block as shown above.

If you want to reject _otherwise_ case, you'd need to define a commonality between `Codable` and `PlistPersistable`, and so you'd need a protocol. You could create two `Wrapper`s, one for `Codable`, one for `PlistPersistable`, but that gets unyieldy very quickly.

> [@t0rst](#):
>
> Finally, is there anywhere the behaviour at this level is documented?

Unfortunately, I don't know of any such thing. I remember what I wrote because this topic comes up relatively frequently.

The rule of thumb is to consider the conformance of `T` to be limited to what's being declared, and _never_ think about the actual concrete type (because your code may not be specialized).

---

<div class="post-metadata">

**Author:** ![Jens](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jens/32/12903_2.png) [@Jens](https://forums.swift.org/u/Jens)\
**Post date:** [May 17, 2020, 9:53pm UTC](https://forums.swift.org/t/inconsistent-function-overload-resolution-between-top-level-call-vs-call-inside-generic-imp/36575/8 "2020-05-17T21:53:17Z")

</div>

The thing to realize (which I remember took a while to get used to) is that Swift's generics is not like C++ templates. Think of the generic function as being compiled totally independent of any call site, not knowing anything more about a type parameter than the constraints you've put on it.

---

<div class="post-metadata">

**Author:** ![t0rst](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/t0rst/32/11733_2.png) [@t0rst](https://forums.swift.org/u/t0rst)\
**Post date:** [May 18, 2020, 5:41am UTC](https://forums.swift.org/t/inconsistent-function-overload-resolution-between-top-level-call-vs-call-inside-generic-imp/36575/9 "2020-05-18T05:41:53Z")

</div>

> The thing to realize (which I remember took a while to get used to) is that Swift's generics is not like C++ templates. Think of the generic function as being compiled totally independent of any call site, not knowing anything more about a type parameter than the constraints you've put on it.

This does help (and I was into C++ templates 15 years ago). Yet it also seems slightly at odds with the compiler doing as much static optimisation as possible — it seems like it misses a few tricks, but probably good reasons, etc.

---

<div class="post-metadata">

**Author:** ![t0rst](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/t0rst/32/11733_2.png) [@t0rst](https://forums.swift.org/u/t0rst)\
**Post date:** [May 18, 2020, 5:42am UTC](https://forums.swift.org/t/inconsistent-function-overload-resolution-between-top-level-call-vs-call-inside-generic-imp/36575/10 "2020-05-18T05:42:37Z")

</div>

> [@xwu](#):
>
> You must think like the compiler.

I'm too stupid for that. 😊

---

<div class="post-metadata">

**Author:** ![t0rst](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/t0rst/32/11733_2.png) [@t0rst](https://forums.swift.org/u/t0rst)\
**Post date:** [May 18, 2020, 5:57am UTC](https://forums.swift.org/t/inconsistent-function-overload-resolution-between-top-level-call-vs-call-inside-generic-imp/36575/11 "2020-05-18T05:57:04Z")

</div>

I repeat the request: where is the behaviour documented?

This is not about documentation as courtesy and kindness. Its about the vendor committing to make a contract for behaviour rather than avoiding the issue and being vague and ambivalent.

(I suppose if I really want to know the contract, I could digest and memorise everything here: [swift/test at main · apple/swift · GitHub](https://github.com/apple/swift/tree/master/test) but 🤢)

The procedure at the moment is use up a lot of time without success, call for help, use up a lot of your time on questions that have been asked many times before.

(By the way, many thanks you for your help @Nevin, @Lantua, @xwu, @Jens 👍)

So... contract?

---

<div class="post-metadata">

**Author:** ![xwu](https://avatars.discourse-cdn.com/v4/letter/x/b487fb/32.png) [@xwu](https://forums.swift.org/u/xwu)\
**Post date:** [May 18, 2020, 6:16am UTC](https://forums.swift.org/t/inconsistent-function-overload-resolution-between-top-level-call-vs-call-inside-generic-imp/36575/12 "2020-05-18T06:16:46Z")

</div>

The behavior is widely discussed; a simple Google search would give you many results. But if you want to read the most original statement, you can find it in the [original design document](https://github.com/apple/swift/blob/master/docs/Generics.rst#overloading) for generics; the particular section on overloading dates back to at least 2012.

---

<div class="post-metadata">

**Author:** ![t0rst](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/t0rst/32/11733_2.png) [@t0rst](https://forums.swift.org/u/t0rst)\
**Post date:** [May 18, 2020, 7:12am UTC](https://forums.swift.org/t/inconsistent-function-overload-resolution-between-top-level-call-vs-call-inside-generic-imp/36575/13 "2020-05-18T07:12:44Z")

</div>

> [@xwu](#):
>
> The behavior is widely discussed; a simple Google search would give you many results. But if you want to read the most original statement, you can find it in the [original design document](https://github.com/apple/swift/blob/master/docs/Generics.rst#overloading) for generics; the particular section on overloading dates back to at least 2012.

Missing the point. It's not the same thing as the vendors _taking responsibility_ to make a clear statement, a clear commitment and a contract, and putting that in a place where it will definitely be found by those looking to understand and use Swift.
