Note: Icaro's answer would still be the accepted answer, I am just extending his explanation.
TL;DR : Check Icaro's answer.
About the usage of AnyObject
Icaro rightly puts:
Don't worry about this variable, no need to enforce any type here let
me do whatever I want to.
What does this mean? Let's take the code example in the question (I've gone a step up and changed AnyObject
to Any
without changing the meaning of the question):
func myFilter(source: [Any], predicate:(Any) -> Bool) -> [Any] {
var result = [Any]()
for i in source {
if predicate(i) {
result.append(i)
}
}
return result
}
This means, the myFilter
function takes in two arguments one source
and a closure predicate
. If you look closely, the contents of the source array can be ANYTHING. And the argument of the closure predicate
can be ANYTHING as well. If we were to name these "ANYTHING"s -- say ANYTHING1 and ANYTHING2 -- this approach doesn't require ANYTHING1 to be equal to ANYTHING2.
Let's sit back and ponder over the implications of this...
Say, we want to filter out evens from an array of integers and let's use our Any
filter for this
var ints = [1,2,3,4,5] as [Any]
var predicate = { (a : Any) -> Bool in
return (a as! Int) % 2 == 0
}
let evens = myFilter(source: ints, predicate:predicate)
Wow, that worked, didn't it? All smiles? No.
Notice how in the line :
return (a as! Int) % 2 == 0
I'm forcefully down-casting a
. This line would crash if a
was anything other than an Int
. But its usage is justified; after all, we want to just filter out the Int
s and I am smart enough to use just an array of Int
s.
But, because say, I am a naive programmer, I do this :
var ints = [1,2,3,4,5,"6"] as [Any]
var predicate = { (a : Any) -> Bool in
return (a as! Int) % 2 == 0
}
let evens = myFilter(source: ints, predicate:predicate)
This happily compiles, but crashes in the runtime. If only there was a way, where the compiler would tell me that this line...
var ints = [1,2,3,4,5,"6"]
... was faulty, we would not have had a crash. I would have fixed it right away!
Turns out, there is. Generics. To quote Icaro again,
I am going to give you a type later and I want you to enforce that
type everywhere I specify.
func myFilter<T>(source: [T], predicate:(T) -> Bool) -> [T] {
var result = [T]()
for i in source {
if predicate(i) {
result.append(i)
}
}
return result
}
var ints = [1,2,3,4,5,6]
var predicate = { (a : Int) -> Bool in
return a % 2 == 0
}
let evens = myFilter(source: ints, predicate:predicate)
This new filter is awesome. It won't let me do :
let evens = myFilter(source: ints, predicate:predicate)
because, the types of the predicate
and source
don't match. Compile time error.
Generics is generic in this way : in this specific example -- while at the point of writing the myFilter
function, you do not need to give a type of the source
or the argument that predicate
takes, it's T, it's ANYTHING. But once I say that source
is an array of ANYTHING, you HAVE to make sure the argument that the predicate
accepts is the same ANYTHING. With the background of our previous ANYTHING1, ANYTHING2 nomenclature, we can say that generics forces ANYTHING1 to be equal to ANYTHING2