I'm new to Swift and I've been going thru some tutorials and many of them define a function more than once with the same name.
I'm used to other programming languages where this cannot be done otherwise it throws an error.
Therefore I've checked the official Swift Manual and also checked the override keyword to see what I could get out of it, but still I cannot understand the following code:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestCell")
cell.textLabel?.text = "Row #\(indexPath.row)"
cell.detailTextLabel?.text = "Subtitle #\(indexPath.row)"
return cell
}
From what I can see the function tableView is set in line #1 as well as in line #5, the only difference I noticed is that the first tableView function returns an Int and the second one returns an Object (UITableViewCell).
In this case I see from the result the second function is NOT overriding the first one.
What does this mean and why is it possible to define a function more than once with the same name without overriding it?
You are allowed to define two functions with the same name if they have different Types, or if they can be distinguished by their external parameter argument labels. The Type of a function is composed of the parameter Types in parentheses, followed by ->, followed by the return Type. Note that the argument labels are NOT a part of the function's Type. (But see UPDATE below.)
For example, the following functions both have the same name and are of Type (Int, Int) -> Int:
// This:
func add(a: Int, b: Int) -> Int {
return a + b
}
// Is the same Type as this:
func add(x: Int, y: Int) -> Int {
return x + y
}
This will produce a compile-time error - changing the labels from a:b: to x:y: does not distinguish the two functions. (But see UPDATE below.)
Using Mr. Web's functions as examples:
// Function A: This function has the Type (UITableView, Int) -> Int
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { ... }
// Function B: This function has the Type (UITableView, NSIndexPath) -> UITableViewCell
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { ... }
// Function C: This made up function will produce a compile-time error because
// it has the same name and Type as Function A, (UITableView, Int) -> Int:
func tableView(arg1: UITableView, arg2: Int) -> Int { ... }
Function A and Function B above do not conflict because they are of different Types. Function A and Function C above do conflict because they have the same Type. Changing the parameter labels does not resolve the conflict if the Types remain the same. (See UPDATE below.)
override is a different concept altogether, and I think some of the other answers cover it, so I'll skip it.
UPDATE: Some of what I wrote above is incorrect. It is true that a function's parameter labels are not a part of it's Type definition, but they can be used to distinguish two functions that have the same Type, so long as the function has external labels that are different such that the compiler can tell which function you are trying to call when you invoke it. Example:
func add(a: Int, to b: Int) -> Int { // called with add(1, to: 3)
println("This is in the first function defintion.")
return a + b
}
func add(a: Int, and b: Int) -> Int { // called with add(1, and: 3)
println("This is in the second function definition")
return a + b
}
let answer1 = add(1, to: 3) // prints "This is in the first function definition"
let answer2 = add(1, and: 3) // prints "This is in the second function definition"
So, the use of external labels in a function definition will allow functions with the same name and of the same type to compile. So, it appears that you can write multiple functions with the same name so long as the compiler can distinguish them by their types or by their external signature labels. I don't think internal labels matter. (But I hope someone will correct me if I'm wrong.)
In Swift, as in Objective-C, the parameters of a function form part of the definition. There aren't two functions called tableView, there is one function called tableView(tableView:, numberOfRowsInSection:) and one called tableView(tableView:, cellForRowAtIndexPath:)
You're thinking of function overloading.
An excerpt from the Apple documentation here:
You can overload a generic function or initializer by providing
different constraints, requirements, or both on the type parameters in
the generic parameter clause. When you call an overloaded generic
function or initializer, the compiler uses these constraints to
resolve which overloaded function or initializer to invoke.
For example:
protocol A { }
protocol B { }
class A1: A { }
class A2: A { }
class B1: B { }
class B2: B { }
func process<T: A>(value: T)
{
// process values conforming to protocol A
}
func process<T: B>(value: T)
{
// process values conforming to protocol B
}
or:
func process(value: Int)
{
// process integer value
}
func process(value: Float)
{
// process float value
}
This confusion is common especially if you're migrating from Objective-C to Swift for the first time. You should read about parameter names here.
The functions aren't the same they are different . Because they don't take the same arguments and return different things . This is the simple explanation if you don't understand generics.
Related
While I was learning about "Functions", I met an issue showing "Extraneous argument label 'number:' in call" error msg for my code. I wonder why I shouldn't place "number" in argument?
func makeIncrementer() -> ((Int) -> Int) {
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
}
var increment = makeIncrementer()
increment(number: 7)
enter image description here
The problem is that you're returning a (Int) -> Int, which doesn't specify a name for its argument. Ideally, you'd want to write
func makeIncrementer() -> ((number: Int) -> Int)
but that isn't allowed in Swift:
function types cannot have argument labels; use '_' before 'number'
The best you can do is
func makeIncrementer() -> ((_ number: Int) -> Int)
This strategy might make your code a little clearer because giving the argument a name makes its purpose more obvious. Unfortunately, you still have to omit the number: label when you call the returned function:
let increment = makeIncrementer()
increment(7) // <- no `number:` label
What's the rationale?
Specifying argument labels for function types was possible before Swift 3. The problem was that you could write
func add(numToAdd: Int) -> Int { ... }
func subtract(numToSubtract: Int) -> Int { ... }
let f: ((numToAdd: Int) -> Int) = subtract
and then calling f(numToAdd: 3) would actually call subtract(numToSubtract: 3), which is quite surprising and can cause confusion.
Check out this proposal for the full rationale behind removing this feature.
After converting from Swift 2.2 to 3.0 my Array extension does not compile anymore, because it contains a call to global standard library function min<T>(T,T) and shows compiler error extra argument in call.
Here's a simple way to reproduce the error:
extension Array {
func smallestInt(first: Int, second: Int) -> Int {
return min(first, second) // compiler error: "Extra argument in call"
}
}
I get the same error when adding the same function to an extension of Dictionary, while the exact same code compiles just fine in an extension of other types (e.g. String or AudioBuffer):
Looking at the documentation of Array and Dictionary, I find that there are instance methods on Sequence named public func min() -> Element? and public func min(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> Element?. While both String and AudioBuffer do not have any kind of min(...) function.
Is it possible that this is the reason why I can't call the global function? The compiler can't distinguish between global func min<T>(T,T) and self.min(...) although they have completely different signatures?
Is this a bug or a feature? What am I doing wrong? How can I call min(T,T) correctly inside an Array extension?
I see no reason why the compiler shouldn't be able to resolve this function call, therefore I would consider it a bug (it has already been filed – see SR-2450).
It seems to occur whenever attempting to call a top-level function with the same name, but unambiguously different signature to a method or property that's accessible from the same scope in a given type (instance or static).
An even simpler example would be:
func foo(_ a: Int) {}
struct Foo {
func foo() {} // or static func foo() {}, var foo = 0, static var foo = 0
func bar() {
foo(2) // error: argument passed to call that takes no arguments
}
}
Until fixed, a simple solution would be to prefix the call with the name of the module in which it resides in order to disambiguate that you're referring to the top-level function, rather than the instance one. For the standard library, that's Swift:
extension Array {
func smallestInt(first: Int, second: Int) -> Int {
return Swift.min(first, second)
}
}
In Swift 4, the compiler has a better diagnostic for this error (though the fact that it's still an error is a bug IMO):
extension Array {
func smallestInt(first: Int, second: Int) -> Int {
// Use of 'min' refers to instance method 'min(by:)'
// rather than global function 'min' in module 'Swift'
// - Use 'Swift.' to reference the global function in module 'Swift'
return min(first, second)
}
}
Although what's interesting is that the compiler will now also warn on attempting to call a standard library method with the same name as a stdlib top-level function:
extension Array where Element : Comparable {
func smallest() -> Element? {
// Use of 'min' treated as a reference to instance method in protocol 'Sequence'
// - Use 'self.' to silence this warning
// - Use 'Swift.' to reference the global function
return min()
}
}
In this case, as the warning says, you can silence it by using an explicit self.:
extension Array where Element : Comparable {
func smallest() -> Element? {
return self.min()
}
}
Although what's really curious about this warning is it doesn't appear to extend to non-stdlib defined functions:
func foo(_ a: Int) {}
struct Foo {
func foo() {}
func bar() {
foo() // no warning...
}
}
The following piece of code are erroneous in Swift.
func foo(closure: (Int, Int) -> Int) -> Int {
return closure(1, 2)
}
print(foo(closure: {$0}))
func foo(closure: (Int, Int) -> Int) -> Int {
return closure(1, 2)
}
print(foo(closure: {return $0}))
The error given by XCode playground is Cannot convert value of type '(Int, Int)' to closure result type 'Int'.
While the following pieces of code are completely fine.
func foo(closure: (Int, Int) -> Int) -> Int {
return closure(1, 2)
}
print(foo(closure: {$0 + $1}))
func foo(closure: (Int, Int) -> Int) -> Int {
return closure(1, 2)
}
print(foo(closure: {$1; return $0}))
func foo(closure: (Int, Int) -> Int) -> Int {
return closure(1, 2)
}
print(foo(closure: {a, b in a}))
It seems that in a situation where arguments to a closure are referred to by shorthand argument names, they must be used exhaustively if the the body of the closure only consists of the return expression. Why?
If you just use $0, the closure arguments are assumed to be a tuple instead of multiple variables $0, $1 etc. So you should be able to work around this by extracting the first value of that tuple:
print(foo(closure: {$0.0}))
Your "why" is like asking "why is an American football field 100 yards long?" It's because those are the rules. An anonymous function body that takes parameters must explicitly acknowledge all parameters. It can do this in any of three ways:
Represent them using $0, $1, ... notation.
Represent them using parameter names in an in line.
Explicitly discard them by using _ in an in line.
So, let's take a much simpler example than yours:
func f(_ ff:(Int)->(Void)) {}
As you can see, the function f takes one parameter, which is a function taking one parameter.
Well then, let's try handing some anonymous functions to f.
This is legal because we name the parameter in an in line:
f {
myParam in
}
And this is legal because we accept the parameter using $0 notation:
f {
$0
}
And this is legal because we explicitly throw away the parameter using _ in the in line:
f {
_ in
}
But this is not legal:
f {
1 // error: contextual type for closure argument list expects 1 argument,
// which cannot be implicitly ignored
}
After converting from Swift 2.2 to 3.0 my Array extension does not compile anymore, because it contains a call to global standard library function min<T>(T,T) and shows compiler error extra argument in call.
Here's a simple way to reproduce the error:
extension Array {
func smallestInt(first: Int, second: Int) -> Int {
return min(first, second) // compiler error: "Extra argument in call"
}
}
I get the same error when adding the same function to an extension of Dictionary, while the exact same code compiles just fine in an extension of other types (e.g. String or AudioBuffer):
Looking at the documentation of Array and Dictionary, I find that there are instance methods on Sequence named public func min() -> Element? and public func min(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> Element?. While both String and AudioBuffer do not have any kind of min(...) function.
Is it possible that this is the reason why I can't call the global function? The compiler can't distinguish between global func min<T>(T,T) and self.min(...) although they have completely different signatures?
Is this a bug or a feature? What am I doing wrong? How can I call min(T,T) correctly inside an Array extension?
I see no reason why the compiler shouldn't be able to resolve this function call, therefore I would consider it a bug (it has already been filed – see SR-2450).
It seems to occur whenever attempting to call a top-level function with the same name, but unambiguously different signature to a method or property that's accessible from the same scope in a given type (instance or static).
An even simpler example would be:
func foo(_ a: Int) {}
struct Foo {
func foo() {} // or static func foo() {}, var foo = 0, static var foo = 0
func bar() {
foo(2) // error: argument passed to call that takes no arguments
}
}
Until fixed, a simple solution would be to prefix the call with the name of the module in which it resides in order to disambiguate that you're referring to the top-level function, rather than the instance one. For the standard library, that's Swift:
extension Array {
func smallestInt(first: Int, second: Int) -> Int {
return Swift.min(first, second)
}
}
In Swift 4, the compiler has a better diagnostic for this error (though the fact that it's still an error is a bug IMO):
extension Array {
func smallestInt(first: Int, second: Int) -> Int {
// Use of 'min' refers to instance method 'min(by:)'
// rather than global function 'min' in module 'Swift'
// - Use 'Swift.' to reference the global function in module 'Swift'
return min(first, second)
}
}
Although what's interesting is that the compiler will now also warn on attempting to call a standard library method with the same name as a stdlib top-level function:
extension Array where Element : Comparable {
func smallest() -> Element? {
// Use of 'min' treated as a reference to instance method in protocol 'Sequence'
// - Use 'self.' to silence this warning
// - Use 'Swift.' to reference the global function
return min()
}
}
In this case, as the warning says, you can silence it by using an explicit self.:
extension Array where Element : Comparable {
func smallest() -> Element? {
return self.min()
}
}
Although what's really curious about this warning is it doesn't appear to extend to non-stdlib defined functions:
func foo(_ a: Int) {}
struct Foo {
func foo() {}
func bar() {
foo() // no warning...
}
}
What is the best approach to distinguish several functions purposes with the same name in Swift.
For example I have the following code:
protocol SomeProtocol {
func simpleFunc() -> Bool
func simpleFunc() -> Int
func simpleFunc(type: SomeType, x: Int, y: Int) -> [SomeModel]
func simpleFunc(type: SomeType, z: String) -> [String]
}
When I will use these functions it will be not clear what is the purpose of any of this functions. I want to do something like is done with default tableView functions.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
When I select this function I understand that it is used for didSelectRowAt
So I've done something like this:
protocol SomeProtocol {
func simpleFunc() -> Bool /* purpose1 */
func simpleFunc() -> Int /* purpose2 */
func simpleFunc(purpose3 type: SomeType, x: Int, y: Int) -> [SomeModel]
func simpleFunc(purpose4 type: SomeType, z: String) -> [String]
}
Unfortunately if function doesn't have parameters this approach will not work. What is the best practices here?
The last two functions don't really have the same name from a practical point of view. In your first group of code, the last two need to be called as:
simpleFunc(type: whatever, x: 5, y: 42)
simpleFunc(type: whatever, z: "Hi")
and in your second group of code, the last two change to:
simpleFunc(purpose3: whatever, x: 5, y: 42)
simpleFunc(purpose4: whatever, z: "Hi")
Either way, the caller doesn't simply use simpleFunc. All of the parameters are involved too.
Given this, there is no reason why the first two functions can't simply be named appropriately such as:
func simpleFuncPurpose1() -> Bool
func simpleFuncPurpose2() -> Int
Then they are called, as expected:
simpleFuncPurpose1()
simpleFuncPurpose2()
All together, combined with your second group of code, the four methods are now called as follows:
simpleFuncPurpose1()
simpleFuncPurpose2()
simpleFunc(purpose3: whatever, x: 5, y: 42)
simpleFunc(purpose4: whatever, z: "Hi")