what does 'condition' mean here in swift tutorial ----function? - swift

I know that in the first line, we can use lessThanTen(number: Int) to replace (int), and contidion means a label, but in the third line: * why dont we use if condition : (item) to replace if condition(item), since condition is a label.

Condition is the method that you're receiving on that method, if you look at that method signature:
condition: (int) -> Bool
which means that you're receiving a condition that can be called using an argument of Int type and will return a bool. Anywhere, inside:
hasAnyMatches
you'll be able to use
condition(anyInt)
Now if you look at the method caller:
hasAnyMatches(list: numbers, condition: lessThanTen)
so, you're saying that the 'condition' on 'hasAnyMatches' will be 'lessThanTen'. Which means that in your
if condition(item)
What really is happening is:
if lessThanTen(item)
I hope it made it clearer!

condition is a Bool-returning closure supplied to hasAnyMatches that needs to be called to yield a boolean value. The closure takes a single argument of type Int, which is the same type as the elements of list. Hence, we call the supplied (Int) -> Bool closure on each item, and in case condition applied to an item returns true, we cut the traversal over the list items short and return true from the function.
Using functional programming tecniques, we could make use of a reduce operation on list to compress the implementation of hasAnyMatches:
func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
return list.reduce(false) { $0 || condition($1) }
}
Or, even better (allowing exit return as in the original loop), as described by #Hamish in the comments belows (thanks!), using contains
func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
return list.contains(where: condition)
}
Example usage:
func lessThanTen(number: Int) -> Bool {
return number < 10
}
var numbers = [20, 19, 7, 12]
print(hasAnyMatches(list: numbers, condition: lessThanTen)) // true

Related

Using "!" on contains

Given this code:
let a = [1, 2, 3, 4, 5]
let b = [5, 6, 7, 8, 9]
let result = a.filter(b.contains)
print(result) // [5]
But what if I want let result = a.filter { !b.contains($0) }? How can I do it the same way as the example above?
let result = a.filter { !b.contains($0) } // works
let result = a.filter(!b.contains) // fails
let result = a.filter { !b.contains($0) }
This is syntactic sugar for:
let result = a.filter({ !b.contains($0) })
filter takes a function value. {...} is a literal function value (a "closure"), just like 1 is a literal Int value. So that's fine. Inside the closure, you apply the ! prefix operator to the result of b.contains($0). That's also fine.
let result = a.filter(!b.contains) // fails
Again, filter takes a function value. b.contains is a function value, so that part is fine, which is why a.filter(b.contains) works. But the ! prefix operator can't be applied to a function value, so that fails.
Anurag demonstrates how you would write an implementation of ! that does take a function and return a function, which works, but would be confusing IMO because this is not a standard use of that operator, and these kinds of operator overloads tend to slow down the compiler (sometimes dramatically, because it has to chase more type possibilities). While there are various ways you might try to "make this work," the best Swift here would generally be the closure syntax because it's clear and standard.
That said, a reasonable approach if you were doing this kind of thing a lot, would be to create a not function that takes a function and returns a function, like Anurag's !, but without overloading the operator:
func not<T>(_ predicate: #escaping (T) -> Bool) -> (T) -> Bool {
return { !predicate($0) }
}
Then you could call a.filter(not(b.contains)). But again, I'd probably only do that if building up complex functions were an important part of your program.
You can always create a custom operator.
prefix func !<T>(_ predicate: #escaping (T) -> Bool) -> (T) -> Bool {
return { element in
return !predicate(element)
}
}
and then a.filter(!b.contains) will work.
Or if that feels like operator overloading abuse, then you could just extend Sequence and use it as a.filter(b.not(b.contains)) but it's kind of ugly:
extension Sequence {
func not(_ predicate: #escaping (Self.Iterator.Element) -> Bool) -> (Self.Iterator.Element) -> Bool {
return { element in
return !predicate(element)
}
}
}

In Swift,there's no way to get the returned function's argument names?

When a function's return value is another function,there's no way to get the returned function's argument names.Is this a pitfall of swift language?
For example:
func makeTownGrand(budget:Int,condition: (Int)->Bool) -> ((Int,Int)->Int)?
{
guard condition(budget) else {
return nil;
}
func buildRoads(lightsToAdd: Int, toLights: Int) -> Int
{
return toLights+lightsToAdd
}
return buildRoads
}
func evaluateBudget(budget:Int) -> Bool
{
return budget > 10000
}
var stopLights = 0
if let townPlan = makeTownGrand(budget: 30000, condition: evaluateBudget)
{
stopLights = townPlan(3, 8)
}
Be mindful of townPlan,townPlan(lightsToAdd: 3, toLights: 8) would be much more sensible to townPlan(3, 8), right?
You're correct. From the Swift 3 release notes:
Argument labels have been removed from Swift function types... Unapplied references to functions or initializers no longer carry argument labels.
Thus, the type of townPlan, i.e. the type returned from calling makeTownGrand, is (Int,Int) -> Int — and carries no external argument label information.
For a full discussion of the rationale, see https://github.com/apple/swift-evolution/blob/545e7bea606f87a7ff4decf656954b0219e037d3/proposals/0111-remove-arg-label-type-significance.md

swift code error page 21

Hi all I am learning Swift, just going through the book provided by Apple on the app store. On page 21 there is some code and for the life of me I cannot get it to work. Just wondered if anybody could shed light. I am pretty sure it's an update thing but if someone could point me or help that would be great. Here is the code taken from the book (yes I have re-typed exactly)
func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
for item in list {
if condition(item) {
return true
}
}
return false
}
func lessThanTen(number: Int) -> Bool {
return number < 10
}
var numbers = [20, 19, 7, 12]
hasAnyMatches(numbers, condition: lessThanTen)
However when I put the code in it changes it and shows the condition arg in the function call as shown below. I should point out that I have placed a question mark after condition: as I am not sure what data type Int -> Bool is asking for.
The type Int -> Bool is a function type that takes a single argument of type Int, and returns a value of type Bool. In this sense, hasAnyMatches is a higher order function, in that it expects, in addition to an integer array, a function as an argument. Hence, you can send e.g. a function reference (to an (Int) -> Bool function) or a closure as the second argument to hasAnyMatches).
An example follows below, calling hasAnyMatches with 1. a function reference; 2. an anonymous closure; 3. a pre-defined closure:
func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
for item in list {
if condition(item) {
return true
}
}
return false
}
func lessThanTen(number: Int) -> Bool {
return number < 10
}
var numbers = [20, 19, 7, 12]
/* 1. function reference: to 'lessThanTen' function */
hasAnyMatches(numbers, condition: lessThanTen)
/* 2. anonymous (trailing) closure: (Int) -> Bool: "integer less than 0?" */
hasAnyMatches(numbers) { myInteger in myInteger < 0 }
hasAnyMatches(numbers) { $0 < 0 } /* short form */
/* 3. pre-defined closure: (Int) -> Bool: "integer larger than 0?" */
let myIntToBoolClosure : (Int) -> Bool = {
myInteger in
return myInteger > 0
}
hasAnyMatches(numbers, condition: myIntToBoolClosure)

Swift, generic function: Why is one argument label needed, the other is not?

The Swift Playground has this function:
func repeatItem<Item>(item: Item, numberOfTimes: Int) -> [Item] {
var result = [Item]()
for _ in 0..<numberOfTimes {
result.append(item)
}
return result
}
let strArray: [String] = repeatItem("knock", numberOfTimes:4) //!!!!
Why is there a numberOfTimes: in the function call and why does removing it give me the error "missing argument label"? More confusingly, why does adding an argument label to "knock" give me "extraneous argument label"?
EDIT:
Also this piece of code has not arguments labels in the call:
func anyCommonElements <T: SequenceType, U: SequenceType where T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element> (lhs: T, _ rhs: U) -> Bool {
for lhsItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem {
return true
}
}
}
return false
}
anyCommonElements([1, 2, 3], [3])
Question 1
This is by construction of Swift. From Swift language guide for functions - Function Parameter Names:
By default, the first parameter omits its external name, and the
second and subsequent parameters use their local name as their
external name. All parameters must have unique local names. Although
it’s possible for multiple parameters to have the same external name,
unique external names help make your code more readable.
...
If you do not want to use an external name for the second or
subsequent parameters of a function, write an underscore (_) instead
of an explicit external name for that parameter.
Note from above that you can supersede this demand by placing an underscore _ in front of 2nd (and onward) parameter name. In your case:
func repeatItem<Item>(item: Item, _ numberOfTimes: Int) -> [Item] { ...
Finally note that this has nothing to do with generics, but with Swift functions in general.
Question 2
Try replacing your line
let strArray: [String] = repeatItem("knock", numberOfTimes:4) //!!!!
with
let strArray = [String](count: 4, repeatedValue: "knock")
This uses the initialiser for array objects with repeated entries.
func repeatItem<Item>(item: Item, numberOfTimes: Int) -> [Item]
is a method that takes two parameters, the first is item and the second is named numberOfTimes.
In Swift, when you call a method or a function you have to write the name of the parameters followed by ":" and the its value.
In Swift the name of the first parameter can be omitted.

Two returns in Closures

I'm New to swift here. Was reading closures on weheartswift. There is one section talking about capturing value. Two questions here:
How do I understand the two returns here?
Why this closure captures the previous value from variable, shouldn't i be initialized every time from the value of start, which is always 0?
Code :
func makeIterator(start: Int, step: Int) -> () -> Int {
var i = start
return {
i += step
return i
}
}
var iterator = makeIterator(0, 1)
iterator() // 1
iterator() // 2
iterator() // 3
Like this:
var i = start
return /*the following is a closure that returns an Int:*/{
i += step
return i
}/*< end of closure*/
What's being returned is a closure. { return i } is actually a function that returns the value of i.
You could also write it this way:
func makeIterator(start: Int, step: Int) -> () -> Int {
var i = start
func iterate() -> Int {
i += step
return i
}
return iterate
}
A closure is functionality + state. The "state" here is the local variable i.
The closure "closes over" i, meaning that each time the closure is executed it will be looking at the same i which it can modify. This is true even after the closure is returned from the function. When you call it multiple times, it updates its internal state and returns the new value.
It is seems like function returns function as its value. returned function doesn't take any argument and returns a integer value. I recommend you to have a look at Swift documentation.