Swift: method overloads that only differ in return type
Where is this documented?
As for subscript
:
Language Reference / Declarations / Subscript Declaration
You can overload a subscript declaration in the type in which it is declared, as long as the parameters or the return type differ from the one you’re overloading.
Language Guide / Subscripts / Subscript Options
A class or structure can provide as many subscript implementations as it needs, and the appropriate subscript to be used will be inferred based on the types of the value or values that are contained within the subscript braces at the point that the subscript is used.
I cannot find any official docs about overloading methods or functions. but in the Swift Blog:
Redefining Everything with the Swift REPL / Redefinition or Overload?
Keep in mind that Swift allows function overloading even when two signatures differ only in their return type.
Overloading generic functions in iOS Swift
You haven't quite focussed on the actual issue. Let's eliminate everything irrelevant from the example. This compiles and works as expected:
struct TestFinder {
func doSomething<T,U>(_ function: (T,U) -> Void) -> Void {
print("two")
}
func doSomething<T,U,V>(_ function: (T,U,V) -> Void) -> Void {
print("three")
}
func doSomething<T,U,V,W>(_ function: (T,U,V,W) -> Void) -> Void {
print("four")
}
}
And here we'll test it:
func f(_ s1: String, _ s2: String, _ s3: String, _ s4: String) -> Void {}
TestFinder().doSomething(f) // "four"
But if you add the version with one passed function parameter, everything breaks down:
struct TestFinder {
func doSomething<T>(_ function: (T) -> Void) -> Void {
print("one")
}
func doSomething<T,U>(_ function: (T,U) -> Void) -> Void {
print("two")
}
func doSomething<T,U,V>(_ function: (T,U,V) -> Void) -> Void {
print("three")
}
func doSomething<T,U,V,W>(_ function: (T,U,V,W) -> Void) -> Void {
print("four")
}
}
Now we can't compile, because the first version is seen as a candidate. And indeed, if we remove the other versions, we still compile!
struct TestFinder {
func doSomething<T>(_ function: (T) -> Void) -> Void {
print("one")
}
}
That's the weird part. We still compile, even though we are saying:
func f(_ s1: String, _ s2: String, _ s3: String, _ s4: String) -> Void {}
TestFinder().doSomething(f)
Evidently, this function with four parameters is seen by the compiler as "fitting" the declaration with just one generic parameter.
I regard this as a bug. I think I can guess what might cause it; it could have to do with the legacy of function parameter list as tuples. This function f
is "equivalent" to a function taking a single parameter consisting of a four-string tuple. Nevertheless, you cannot actually call the function
inside doSomething
with a four-string tuple; I cannot find a way to call it at all.
So, I would say, regard this as a bug, and work around it for now by removing the first version of your generic.
UPDATE: On the advice of the Swift team, I tested with the May 4, 2020 Swift 5.3 Development toolchain. With it, your code compiles and behaves as expected. This was indeed a bug, and it was fixed as part of
https://bugs.swift.org/browse/SR-8563
Returning for a moment to my version, my code, too, compiles and behaves as expected, with all four versions of doSomething
present. However, note that if you delete all but the first version of doSomething
, it still compiles and runs. Moreover, you can call function
with four parameters by bundling them into a tuple and force casting, like this:
struct TestFinder2 {
func doSomething<T>(_ function: (T) -> Void) -> Void {
print("one")
function(("manny", "moe", "jack", "henry") as! T)
}
}
That seems to confirm my guess that what you're seeing is a consequence of the hidden tuple-nature of a function's parameter list. One can draw the same conclusion from the discussion of the bug, which refers to "tuple-splatting".
function overloading in swift
It seems you may be running into the same problem mentioned in this reddit thread. It looks like the solution may just be to rename your functions, due to a clash with inherited with Objective C methods.
e.g.
func myPerformOperation(operation: Double -> Double){
func myPerformOperation(operation:(Double, Double)->Double){
(These aren't ideal names—they should be more descriptive—but you get the idea.)
Nested function overloading in Swift
IMHO this is clearer if you consider this variation:
func foo() {
let bar: (param: Int) -> () = { p in
// do stuff
}
func bar(param: Double) {
// do stuff
}
// call functions here
}
With your first bar
function definition you are just declaring a constant of type (param: Int) -> ()
.
Thus with your second declaration you are declaring another constant of different type (param: Double) -> ()
but having the same name as the already declared bar
.
In short it's just like you wrote:
let bar: Int = 0
let bar: Double = 0.0
In which case compiler will complain as well.
Hope this helps.
Precedence of Function Overloading Parameters in Swift
The keyword here is "specific". Swift always finds the most specific overload to call.
Swift first infers that value1
is of type Int
, so type(of: value1)
is of type Int.Type
.
Now we've got a Int.Type
as the parameter, Swift looks for an overload that accepts one parameter whose type is exactly Int.Type
. It finds one and calls that. The one that accepts a Fooable.Type
is not called because it can already call a more specific one that accepts exactly a Int.Type
. Here, "specific" means lower down the type hierarchy. Int
is considered more specific than Fooable
because Int
conforms to Fooable
.
value3
is inferred to be of type Bool.Type
. There is not overload that accepts a Bool.Type
, so Swift has to look up the type hierarchy and finds the one that accepts a Fooable.Type
. This is the most specific type that you can pass a Bool.Type
into.
Swift and params method default values
Your class A
has two functions, c(d:)
, and c(d:e:)
. In Swift, two functions can share the same “first name”, but be distinguished by their arguments. Hence, the “full name” of a function consists of its name and all of its parameter labels.
Replace the line
aaa.c()
with
aaa.c(d:e:)()
which calls the function c(d:e:)
by its full name, and (2)
will execute.
Note that aaa.c()
is equivalent to aaa.c(d:)()
. Swift appears to default to the function with the fewest parameters when the call is ambiguous; this may be the subject of a future Swift Evolution proposal, if it is not already.
How to call an overloaded function when you only have a variable conforming to a lesser type?
There are a couple of ways to go about this...
Use a switch
to reestablish the type
Swift needs to know at compile time which overloaded function it is calling. This can't happen if Swift doesn't know at compile time which type of the variable it has.
To get the type information back, you can use a switch
to reestablish the type:
func performCommand(_ command:Command) {
guard let todoCommand = command as? ToDoCommand else {
return
}
// Perform some tasks that are common to all ToDoCommands...
switch todoCommand {
case let command as AddToDoCommand:
performCommand(command)
case let command as EditToDoCommand:
performCommand(command)
default: break
}
}
Use polymorphism
A way to let Swift decide which performToDoCommand()
command to run at runtime is to use polymorphism.
Add the requirement to implement func performToDoCommand()
to the ToDoCommand
protocol, and then implement that for each struct
that conforms to ToDoCommand
. Calling the right one is then simple...
protocol Command {}
protocol ToDoCommand : Command {
func performToDoCommand()
}
protocol UserCommand : Command {}
struct AddToDoCommand : ToDoCommand {
func performToDoCommand() {
print("Add ToDo")
}
}
struct EditToDoCommand : ToDoCommand {
func performToDoCommand() {
print("Edit ToDo")
}
}
struct AddUserCommand : UserCommand {}
struct EditUserCommand : UserCommand {}
class ToDoManager {
func performCommand(_ command:Command) {
guard let todoCommand = command as? ToDoCommand else {
return
}
todoCommand.performToDoCommand()
}
}
Related Topics
How to Have a Searchbar Which Shows Suggestions with Different UItableview
How to Assign Elements of a Dictionary to JSON Object in Vapor 3
Swiftui Navigationview Starting Inside Itself
How to Drag a Working Slider Using Swiftui
How to Create Travelling Wave in Spritekit
Spritekit: Sprites Are Moving Through Each Other with a Physicsbody Already Set
How Make Polygon Without Intersection in Swift
Swift: How to Get Image Name from Assets
Nsdocumentcontroller.Opendocument Not Allowing Selection of Custom File Type
How to Remove The Fading Animation on .Ondelete Swiftui
Nssavepannel - How to Restrict User to Only Save One One Set Directory
Nsnumber/Nsdecimalnumber Bizarre Behavior
Understanding UIviewrepresentable
How to Set Local Notifications Between 8Am and 8Pm Every Day
How to Segue an Image to Another Viewcontroller and Display It Within an Imageview