So... which function?

Weird conundrum… paste this into an Xcode Playground and run it - all should be valid. Then comment out either function and run it, still valid (!?!). So if the one call is valid for either function, then there is a problem. Yeah, you can print(“this one”) in a func to find out which is called for your particular setup, but there is a deeper issue when a single call works for either function.


//
// Problem in Swift or Xcode?
//
// So... which function?
//

func whichFunction( a: Int, _: Int = 9 ) { /* diabolical code to destroy the world */ }
func whichFunction( a: Int, _: Int? ) { /* silly code to print out "Hello, World!" */ }

// Which func of the above two does the following call?
//
whichFunction(a: 6, 7)
//
// Not obvious, even more, the above call works (no complaints by
// Xcode) if you comment out either whichFunction and run it, so
// the single call is capable of envoking either side-by-side function !?
//
// So... which function?
//
//
print("So was it \"Hello World!\"... or \"Goodbye, World!\"?")
//
// Just sayin'...

Hi @lglb

Welcome to the community.

A function can have different signatures and that’s quite normal in Swift (and likely other languages).

In the case of the two functions you have listed the first and second versions require at least the first parameter. The second parameter is optional for the first case but required in the second case.

If you comment out either function definition, the call you make will work in either case as long as you pass the required parameters.

It’s not good programming to have ambiguous functions like that. Where did you find this “conundrum”?

I just started learning Swift (but programming back to FORTRAN punch cards), saw some CWC+ videos (Good job, Chris!), and was just reading through the swift.org language documentation and found a bunch of possible errors/conflicts, so I just now scribbled this snippet out to confirm, and thought I’d ask y’all. And, ‘Yes’, ambiguous functions are bad, but that’s why I’m raising my hand here, right?

Chris Ching has done great job of producing these courses. I’m one of a number of moderators on this site and some folks have got me confused with Chris Ching and even someone thought I was Chris Lattner (the creator of the Swift Language).

FORTRAN???, jeepers man you are going back a few decades. I’ve seen punchcards fed into a reader in my early years but never tried coding FORTRAN ugh!

That Swift Language Guide can be hard work. There are huge amounts of free Swift tutorials out there and one that I do recommend, apart from the courses by Chris Ching here, is those by Paul Hudson. His site hackingwithswift.com has couple of 100 Days of Swift courses that are well worth doing. One covers the UIKit framework and the other covers the new SwiftUI framework that was introduced in 2019.

Thanks.

And, no, I didn’t confuse any Chris’s, was just hurling a shout-out to Master Ching for his work and patience in making all the intro videos [I would have committed hari-kari halfway through the first one].

… but you might really be Steve Wozniak, for all I know :wink:

Yes… No… Hahaha

When faced with overloaded functions, Swift chooses the one with the more specific signature. In this case, that means your first whichFunction, since its parameters are an Int and another Int, versus the second function which takes an Int and an Optional<Int>. An Int is a more specific type than Optional<Int> so it sees the 7 you have passed in and interprets that as a Int rather than an unwrapped optional.

If you comment out the first function, Swift will still call the second one because 7 is a valid Int? value, which represents either an Int or nil.

found a bunch of possible errors/conflicts

I’m curious…

Yeah, I deduced that, which is why I put the ‘diabolical code’ up there so that it would mean ‘Goodbye, World!’

And, no, I don’t believe a modern language could allow two functions to have identical signatures/footprints/parameters. I see it as: myFunc(: Int) and myFunc(: Int) side-by-side which should throw an exception/error by any compiler - could cost lives, shouldn’t happen, and actually doesn’t - that, specifically, will throw an exception. The trick here is in the use of the ‘?’ operator; remove it and the compiler catches the problem.

… well, actually, a second Int parameter is optional ONLY to the first whichFunction (!?). Try calling whichFunction(a: 6) and you’ll see that it is valid only to the first function - which adds to this conundrum. Even more, I submit that it may be entirely impossible here to EVER call the second whichFunction !! [found a way in later]

Sure, I’m new to Swift, but logic and I go way back - this shouldn’t happen, it’s a conundrum. Just sayin’…

The first function assigns a value to the second Int in the event that you don’t pass a second parameter. If you do pass a second parameter then that overrides the default value specified in the function signature.

The only reason there is a problem for the compiler to catch is the removal of the ?. Otherwise, the two functions have different type signatures and there is no conflict.

You can see the difference here:

func whichFunction( a: Int, _: Int = 9 ) { /* diabolical code to destroy the world */ }
let f1 = whichFunction
print(type(of: f1))
//prints (Int, Int) -> ()

versus:

func whichFunction( a: Int, _: Int? ) { /* silly code to print out "Hello, World!" */ }
let f2 = whichFunction
print(type(of: f2))
//prints (Int, Optional<Int>) -> ()

Removing the ? from the second param of the second function makes its type also (Int, Int) -> (), which is why the compiler now sees a conflict.

No. The second param in the first function is optional in the sense that you don’t have to pass a value for it because a default value of 9 is provided in the declaration. But it is not an Optional, i.e., a data type that can either have a value or be nil. The second param in the second function is an Optional, as indicated by the ? symbol.

func whichFunction( a: Int, _: Int = 9 ) { /* diabolical code to destroy the world */ }

The second parameter here is optional for the caller to supply but it will always have a value: either whatever the caller passes in, or the default of 9.

func whichFunction( a: Int, _: Int? ) { /* silly code to print out "Hello, World!" */ }

The second parameter here is an Optional (specifically, an Optional<Int>) and may or may not have a value, depending on what is passed to it. But the caller has to supply something, either a value or nil; the second param is not optional in that sense.

For instance:

let x: Int? //implicitly initializes an Optional<Int> to nil
whichFunction(a: 6, x) //passes a nil value in the second param
1 Like

Have you tried that?

Xcode won’t allow it for me.

I did find a way into the second whichFunction though. Still…

Use var x: Int? instead.

whichFunction(a: 6, nil ) is shortest and clearest.

Sorry, I should have used:

let x: Int? = nil
whichFunction(a: 6, x)

That’s what I get for writing posts at night in bed on my iPad without testing everything first.

That works too.

We’ve all been there. It’s all good.