Swift Generics Type Inference Extensions
I'm trying to build my understanding of Generics in Swift by creating a Min and Max extension for the Array class (similar to the Min and Max Extension methods in C #). There might be a better way to do this, but as I said, it just helps me understand Generics.
I created the following code:
extension Array {
func max<T, U : Comparable>(f: T -> U ) -> U? {
var maxSoFar : U? = nil
for i in self {
var itemValue = f(i as T)
if(maxSoFar == nil) {
maxSoFar = itemValue
}
if itemValue > maxSoFar {
maxSoFar = itemValue
}
}
return maxSoFar
}
func min<T, U : Comparable>(f: T -> U ) -> U? {
var minSoFar : U? = nil
for i in self {
var itemValue = f(i as T)
if(minSoFar == nil) {
minSoFar = itemValue
}
if itemValue < minSoFar {
minSoFar = itemValue
}
}
return minSoFar
}
}
To test, I created a base Person class:
class Person {
var name : String
var age : Float
init(name: String, age: Float) {
self.name = name
self.age = age
}
}
This seems to work well for these cases when I am explicit in the closure:
var maximumAge = [Person(name: "Bob", age: 42), Person(name:"Mary", age:40)]
.max{ (p: Person) in p.age }! // Gives 42
var min = [100, 101].min{ (i: Int) in i }! // Gives 100
However, I cannot get it to deduce the types to use the edge-shorthand case:
var maximumAge = [Person(name: "Bob", age: 42), Person(name:"Mary", age:40)]
.max{ $0.age }! // Error
var min = [100, 101].min{ $0 }! // Error
Or medium length:
var maximumAge = [Person(name: "Bob", age: 42), Person(name:"Mary", age:40)]
.max{p in p.age }! // Error
var min = [100, 101].min{ i in i }! // Error
If anyone else is an expert on this subject, can you let me know what I am doing wrong? I must admit it took quite a bit of reading and hacking for me to get to this!
Thanks for any answers
source to share
When you define max
(s min
) like this:
func max<T, U : Comparable>(f: T -> U ) -> U?
In fact, you are saying that the closure f
can be of a different type than the elements in Array
. Since it is Array
already a generic structure Array<T>
, you can reuse an element type T
that it has already defined. From the Swift Language Guide :
When extending a generic type, you do not specify the type parameter as part of the extension definition. Instead, the type parameter list from the original type definition is available within the body of the extension, and the parameter names of the original type are used to denote the type parameters from the original type definition.
So, since the element type is T
already available to you, just take T
out the type parameters from the list, for example:
func max<U : Comparable>(f: T -> U ) -> U?
This ensures that the closure f
is of the same type T
as the elements in Array
. The compiler can then correctly identify the types you are using in your test cases and fix the errors you see.
source to share