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")
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.
I am trying to learn Swift and I have bought a book to help me learn the language.
I can't understand why the following does not work:
func sum(_a: Int, _b: Int) -> Int {
return a + b
}
func subtract(_a: Int, _b: Int) -> Int{
return a - b
}
var someFunc: (Int, Int) -> Int
someFunc = sum
print(someFunc(5, 4))
someFunc = subtract
print(someFunc (5, 4))
The error I get is Cannot find 'a' (or 'b') in scope.
If I remove the underscores it does give the right answer.
I thought the point of the underscore was that the underscore meant that nothing is assigned to it and the function you want to call that returns a result but you don't care about the returned value.
Can somebody explain in simple language why this does not work.
You have to put a space between _ a, _ b. Like this:
func sum(_ a: Int, _ b: Int) -> Int {
return a + b
}
func subtract(_ a: Int, _ b: Int) -> Int{
return a - b
}
var someFunc: (Int, Int) -> Int
someFunc = sum
print(someFunc(5, 4))
someFunc = subtract
print(someFunc (5, 4))
You can learn these functions in a Playground. You will see there errors, etc...
The underscore means that the parameter will not have a label when calling then function making it more compact.
Below is 3 different ways to use labels for parameters when creating a function
Function with anonymous (no label) parameters
func example1(_ a: Int, _ b: Int) -> Int {
a + b
}
let sum = example1(3, 5)
Function with parameters as labels
func example2(a: Int, b: Int) -> Int {
a + b
}
let sum = example2(a: 3, b: 5)
Function with different parameter names and labels
func example3(first a: Int, second b: Int) -> Int {
a + b
}
let sum = example3(first: 3, second: 5)
When declaring functions in Swift, you can provide names for parameters passed to a function. It is handy to make your functions more readable when using in code. E.g. you can declare it like so:
func move(from startPoint: Int, to endPoint: Int) -> Int {
return startPoint + endPoint
}
In your function's body you can use variables' names, which is quite understandable for you. And usage of your functions will look like:
res = move(from: 1, to: 2)
I this way it will be more readable for any person who will read or use your code. It will be more clear even for you, when you'll return to this code some time later.
You can also declare the function in the way not to show any variables' names at all. For this you can use "_" as a variable's name. And this is the case from your learning book.
Guys have already answered your question. I just wanted to give you a bit deeper understanding.
I have these two functions:
func random() -> CGFloat {
return CGFloat(Float(arc4random()) / 0xFFFFFFFF)
}
// here
func random(min min: CGFloat, max: CGFloat) -> CGFloat {
return random() % (max - min) + min
}
Why I should write min two times in the second function in order to call it like this:
random(min: 1, max: 5);
Prior to Swift 3, this was necessary. Declaring a function like this:
func foo(bar: Baz)
implicitly changed it to this:
func foo(_ bar: Baz)
which would make it be called like this:
foo(Baz())
so one would have to declare it like this:
func foo(bar bar: Baz)
in order to call it like this:
foo(bar: Baz())
Since Swift 3, this is no longer necessary. Now, declaring a function like this:
func foo(bar: Baz)
implicitly changes it to this:
func foo(bar bar: Baz)
which would make it be called like this:
foo(bar: Baz())
so one now must declare it like this:
func foo(_ bar: Baz)
in order to call it like this:
foo(Baz())
Why?
The idea is that each non-self-documenting parameter must have an explicit label so that someone reading the code immediately knows that's going on. For simple methods like setWidth(5), it's obvious you're setting the width to 5, so the first parameter needs no label (setWidth(width: 5) would be redundant). However, for more nuanced methods like wait(forSeconds: 5), it would be unclear what the 5 means without the forSeconds: label (wait(5) could easily be seen as 5 milliseconds).
Remove second min from function. By the way when you call a function, skip the first variable name and just put the value. It's the swift syntax for calling a function
func random(min: CGFloat, max: CGFloat) -> CGFloat {
return random() % (max - min) + min
}
func random() -> CGFloat {
return CGFloat(Float(arc4random()) / 0xFFFFFFFF)
}
random(1, max: 5)
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.
Is it possible to call a function as a parameter of another function in Swift??
I am making a sound effects app in Swift which uses different effects like AVAudioUnitReverb() and AVAudioUnitDistortion() etc. I wanted to create a single function and just be able to call which effects I wanted to do.
Because in Swift functions are first-class types, you can pass it as an argument to another function.
Example:
func testA() {
print("Test A")
}
func testB(function: () -> Void) {
function()
}
testB(testA)
You can pass in functions as parameter my typing the parameter with the same signature.
As sunshine's example just deals with Void parameters and return types, I want to add another example
func plus(x:Int, y:Int) -> Int {
return x + y
}
func minus(x:Int, y:Int) -> Int {
return x - y
}
func performOperation (x:Int, _ y:Int, op:(x:Int,y: Int) -> Int) -> Int {
return op(x: x, y: y)
}
let resultplus = performOperation(1, 2, op: plus) // -> 3
let resultminus = performOperation(1, 2, op: minus) // -> -1
note: Of course you should consider dynamic typed parameters. For simplicity here just Ints
this is called Higher Order Functions and in many languages this is the way of doing it. But often you don't won't to explicitly create functionss for it. Here Closures are a perfect tool:
The function performOperation stays untouched, but the operations are implemented differently:
let plus = { (x:Int, y:Int) -> Int in
return x + y
}
let minus = { (x:Int, y:Int) -> Int in
return x - y
}
let resultplus = performOperation(1, 2, op: plus)
let resultminus = performOperation(1, 2, op: minus)
Often this would be preferred as it doesn't need methods to be added to a class, pretty much like anonymous functions in other languages.
More on this and how it is used in the swift standard library: https://www.weheartswift.com/higher-order-functions-map-filter-reduce-and-more/
I would recommend book "IOS 9 Programming Fundamentals with Swift" by Matt Neuburg, especially subchapter "Functions".
You should not only find the answer for your question:
func imageOfSize(size:CGSize, _ whatToDraw:() -> ()) -> UIImage {
...
}
But also how to construct function that returns the function:
func makeRoundedRectangleMaker(sz:CGSize) -> () -> UIImage {
...
}
As well as brief introduction to Curried Functions.