Reputation: 2701
Today, I saw some sample Swift 2.0 (Xcode 7.2) code that can be summarised as:
let colours = ["red", "green", "blue"]
let r1 = colours.contains("The red one.".containsString) // true
let y1 = colours.contains("The yellow one.".containsString) // false
I would have expected a compilation error due to the lack of parenthesis on the containsString()
function. In fact, I'm not even sure how the recursion is working. Are the Strings recursing through each item in the colours
array or vice versa?
Any explanation appreciated.
Upvotes: 4
Views: 181
Reputation: 32782
In Swift, functions can be considered as named closures. Quoting from Apple documentation on closures:
Global and nested functions, as introduced in Functions, are actually special cases of closures
However containsString()
is an instance method (thanks Martin R for your observation). The code works, because instance methods in Swift are actually curried functions, which fall into the named closure category.
What happens is that "The red one.".containsString
gets translated to a global function like this:
String.containsString("The red one.")
which returns a function (String) -> Bool
, that ends up being called by contains
like this:
String.containsString("The red one.")("red")
String.containsString("The red one.")("green")
String.containsString("The red one.")("blue")
Now, considering the signature of contains
:
public func contains(@noescape predicate: (Self.Generator.Element) throws -> Bool) rethrows -> Bool
and signature of containsString
:
public func containsString(other: String) -> Bool
we can see that on an array of strings the predicate
parameter and the result of String.containsString("The red one.")
are compatible: both expect a String
as argument and return a Bool
. So the compiler can happily call the curried function.
Upvotes: 5
Reputation: 14260
What you are actually doing is calling the method .contains(predicate: String -> Bool)
(the actual method can throw, but that's not relevant here)
This means that you are asking the array colours
if it contains an element that conforms to that predicate, which is "The red one.".containsString
. So the array is checking its elements one by one and checking it against that predicate. If it finds one, it will return true, otherwise it will return false.
The code above does this:
"The red one.".containsString("red")
"The red one.".containsString("green")
"The red one.".containsString("blue")
"The yellow one.".containsString("red")
"The yellow one.".containsString("green")
"The yellow one.".containsString("blue")
And it checks if it got true
somewhere.
Upvotes: 6