I'm trying to write a library that uses templated/generic type dispatch, but I can't figure out how overload resolution works in Swift. (Is there a more technical reference than The Swift Programming Language?)
The following works exactly as I'd hope:
func f(_ v: String) { print(v) }
func f(_ v: String?) { f(v!) }
func f(_ v: Int) { print(v) }
func f(_ v: Int?) { f(v!) }
f("foo")
f(Optional("bar"))
f(2)
f(Optional(3))
And this code also works the same way:
func g<T>(_ v: T) { print(v) }
func g<T>(_ v: T?) { g(v!) }
g("foo")
g(Optional("bar"))
g(2)
g(Optional(3))
But when I compile this:
func h(_ v: String) { print(v) }
func h(_ v: Int) { print(v) }
func h<T>(_ v: T?) { h(v!) }
h("foo")
h(Optional("bar"))
h(2)
h(Optional(3))
I get the warning
all paths through this function will call itself
func h<T>(_ v: T?) { h(v!) }
And sure enough executing it with an optional parameter blows the stack.
My first zany theory was that maybe generics don't participate in overload resolution with non-generics, but this:
func i<T: StringProtocol>(_ v: T) { print(v) }
func i<T>(_ v: T?) { i(v!) }
i("foo")
i(Optional("bar"))
gives me the same warning, and the second invocation blows the stack.
If v
is of type Optional(String)
, I don't even understand how v!
can be passed to a generic expecting a T?
.
This is happening because in your generic implementation there won't be any type inference happening. You could solve this by doing some optional casting (to avoid crashes) and sending it to the correct method, which will actually happen automatically anyway. So something like:
Maybe kinda defeats the purpose, but I can tell you as a Swift developer with several years of experience this type of generic handling doesn't/shouldn't really come up all that often in a real application if the rest of your code is written in a Swift-friendly way. I suppose that's a bit opinion-based, but there it is.
As for this comment:
Based on your implementation you are declaring that
v: T?
, which means that v must be either of typeT
or it isnil
. Thereforev!
is just you (as a developer) guaranteeing that v will be of typeT
, and notnil
, and if you're wrong the program will crash.I assume you are doing this just for learning purposes, but that is the biggest thing I notice in your example code - there would never be any point of having a method accept an Optional argument if you are going to immediately use ! to force unwrap.