Write an extension function for abstract type aggregates

Allen
Allen
Jul 24, 2017 · 3 min read

Swift itself is a statically typed language

For statically typed languages, the compiler must have all information about classes and functions at compile time. That means all variables, constants, and functions must have their types declared in advance. However, having one function or one method that can act on different types is still possible. For that purpose, Swift provides a powerful feature, Generic.

Generic code enables functions and types that can work with different types

In general, a function is usually a piece of codes to be reusable and used to perform a single related action; therefore, an ordinary form of a function is common as follows:

func function_name(parameters: declared_type) -> return_type {
//... Code here
return typed_constants
}

Traditionally, we could create functions for the same purpose individually to work with different types. However, it means that we produce codes based on similar patterns for each unique type declaration. And it somehow violates coding in a clean way and maintenance-free which is always a goal and principle to programmers. In view of that, we want a manner which is abstracted and able to expresses its intention in a clear form. And that’s what we called Generic.

Let’s start from a generic entity that can be reused with different types

A generic entity must have a type parameter. The “T” below stands for whatever type will eventually be used in the generic entity.

struct GenericStruct<T> {
var someThing: T
}

// After above manner, GenericStruct can be constructed and parameterized over different types by adding type parameters in a pair of angle-brackets.
let a = GenericStruct<Int>(someThing: 1)
let b = GenericStruct<Float>(someThing: 2.5)
let c = GenericStruct<String>(someThing: "Hello, world!")

Then, what if we put a generic entity in a collection?

It looks like that defining a generic entity is easy and straightforward. However, story will not that simple always. If we do want to put our generic entity in a collection type, like Set, we need to have some more decoration and adopt Hashable protocol for that purpose. The snippet below is a revised version.

struct GenericStruct<T: Hashable>: Hashable {
var someThing: T

var hashValue: Int {
get {
// Hashable in angle-brackets is a constraint to tell compiler that type T must have .hashValue
return someThing.hashValue
}
}

static func ==(lhs: GenericStruct, rhs: GenericStruct) -> Bool {
return lhs.hashValue == rhs.hashValue
}
}

let set: Set = [
GenericStruct<String>(someThing: "Watermelon"),
GenericStruct<String>(someThing: "Orange"),
GenericStruct<String>(someThing: "Banana")
]

Extension function is the last thing that can’t be missed

Back to our topic, the purpose is to write an extension function for abstract type aggregates. There is no doubt that the story is not finished yet. Thelast piece of having an extension function is still missing. We need a third revision of the snippet to have our extension function work with GenericStruct.

extension Set {
func getFirstWith<T: Hashable>(value: T) -> Element? {
return filter({$0.hashValue == value.hashValue}).first
}
}

let set: Set = [
GenericStruct<String>(someThing: "Watermelon"),
GenericStruct<String>(someThing: "Orange"),
GenericStruct<String>(someThing: "Banana")
]

let output = set.getFirstWith(value: "Orange")
print(output!)

Certainly, other type like Int works too. Cheers!

let set: Set = [
GenericStruct<Int>(someThing: 226),
GenericStruct<Int>(someThing: 603),
GenericStruct<Int>(someThing: 818)
]
let output = set.getFirstWith(value: 818)
print(output!)
Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade