Generics functions are great at reducing code duplication, but there's a silly caveat that you must overload such functions to disambiguate literals (like 123
or "abc"
). Additionally, the number of overloads scales poorly with the number of generic arguments. Here's an example of this disambiguation strategy:
Given the following context.
protocol Abstraction: ExpressibleByIntegerLiteral { }
struct Foo: Abstraction { ... }
struct Bar: Abstraction { ... }
func silly(_ first: Foo, _ second: Foo) {
print(first, second)
}
func silly(_ first: Foo, _ second: some Abstraction) {
print(first, second)
}
func silly(_ first: some Abstraction, _ second: Foo) {
print(first, second)
}
func silly(_ first: some Abstraction, _ second: some Abstraction) {
print(first, second)
}
The maintenance burden isn't terrible when you only need to disambiguate one generic type. Still, even that case is a testing headache since generic tests won't take the more specific overloads just because their types match. I think it would be great if it were possible to annotate generic type parameters with a preferred (or favored) type. Imagine something like this instead:
func silly(
_ first: @favoring(Foo) some Abstraction,
_ second: @favoring(Foo) some Abstraction
) {
print(first, second)
}
This hypothetical syntax would be equivalent to the following procedure: "Try interpreting first
as an instance of Foo
if first
doesn't match some Abstraction
then repeat this process with the second
argument."