Swift Generics

In swift, Generics are the parameterized types. By using generics we can create flexible and reusable functions or methods that work with any type. In swift class, structure or any method that operates on parameterized types called a generics.

 

Generally in swift, by using generics we can avoid a duplicate code by writing reusable functions or methods in a clear and abstracted manner based on our requirements.

 

The concept of generics is powerful in swift and the standard libraries like arrays or dictionaries of swift built by using generic code. In swift, when we create an array, it can hold any type of data like integer, string or any other types same way dictionaries are also used to hold any type of data as a key-value pair.

 

Following is the simple non-generic function example which shows how generics will help in swift programming language.

 

func SwapInteger(_ a: inout Int, _ b: inout Int) {

let tempint = a

a = b

b = tempint

}

func SwapString(_ a: inout String, _ b: inout String) {

let tempstr = a

a = b

b = tempstr

}

var num1 = 445

var num2 = 3334

var str1 = "Trishika"

var str2 = "Rohini"

 

SwapInteger(&num1, &num2)

SwapString(&str1, &str2)

 

print("After Swapping Num1: \(num1), Num2: \(num2)")

print("After Swapping Str1: \(str1), Str2: \(str2)")

If you observe above example we defined a two functions SwapInteger, SwapString to swap integers and strings separately because SwapInteger function will work only for integers and SwapString function will work only for strings.

 

When we run above program in swift playground we will get a result like as shown below

 

After Swapping Num1: 3334, Num2: 445

After Swapping Str1: Rohini, Str2: Trishika

In swift, if we use non-generic code we need to create separate methods or functions based on the type of data due to that redundant code will increase in application.

 

If we use generics, we can create a single method or function that can accommodate any type of data.

Swift Generic Functions & Type Parameters

In swift, Generics will work with any type for that need to add <T> after the function name.

 

Now we will implement a generic version for the above example which we used to swap integers and strings.

 

Following is the example of using generics to avoid a redundant code in swift programming language.

 

func SwapValues<T>(_ a: inout T, _ b: inout T) {

let tempval = a

a = b

b = tempval

}

var num1 = 445

var num2 = 3334

var str1 = "Trishika"

var str2 = "Rohini"

SwapValues(&num1, &num2)

SwapValues(&str1, &str2)

 

print("After Swapping Num1: \(num1), Num2: \(num2)")

print("After Swapping Str1: \(str1), Str2: \(str2)")

If you observe above example we defined a single function SwapValues with generic placeholder type name called <T> to swap any type of values like integers, strings. 

 

In above example the placeholder T doesn’t say anything, but it does says that both a and b must be of the same type T, whatever T represents. The actual type to use in place of T is determined each time the SwapValues(_ :, _ : ) function calls.

 

Another difference between generic and non-generic functions is that the generic function name followed by a placeholder type name with angle brackets like <T>. It tells that T is a placeholder name and swift doesn’t look for an actual type called T.

 

We can call SwapValues() function by passing a two values of any type, as long as both of these values are of the same type as each other.

 

When we run the above program in swift playground we will get a result like as shown below

 

After Swapping Num1: 3334, Num2: 445

After Swapping Str1: Rohini, Str2: Trishika

Based on the above result we can clearly say that Generics will help us to write a flexible and reusable code to perform our operations in applications based on our requirements.

Swift Generics Types

Swift provides us more flexibility to define our own custom generics types in generic functions. The custom generic types are classes, enumerations and structures that can work with any type like arrays and dictionaries

 

The implementation of generics types is mostly in Data Structures and mainly use in stack. A Stack is an ordered collection of values similar to an array. Using generics, we can push or pop any item within our list or array.

 

Following is the example of defining generic types in a swift programming language.

 

struct Stack<T> {

var items = [T]()

mutating func push(item: T) {

items.append(item)

}

mutating func pop() -> T {

return items.removeLast()

}

}

var numstack = Stack<Int>()

numstack.push(item: 223)

numstack.push(item: 444)

numstack.push(item: 543)

numstack.push(item: 232)

print(numstack)

var numpop = numstack.pop()

print(numstack)

If you observe above example we defined a generic type Stack with a placeholder type T to accept any type of Integer or string values and we are pushing a values into numstack instance using push method and removing last inserted element using pop method.

 

When we run the above program in swift playground we will get a result like as shown below

 

Stack<Int>(items: [223, 444, 543, 232])

Stack<Int>(items: [223, 444, 543])

This how we can use generic types in a swift programming language to define our own custom generic types based on our requirements.

Swift Extending a Generic Types

In swift, we can extend the behavior of generic types using extension keyword. When we extend a generic type, we do not need to provide a parameter list type as part of the extension definition. The type parameter list is only available with original type definition within the body of extension and original type parameter names are used to refer parameter type.

 

Following is the example of extending the behavior of generic types in a swift programming language.

 

struct Stack<T> {

var items = [T]()

mutating func push(item: T) {

items.append(item)

}

mutating func pop() -> T {

return items.removeLast()

}

}

extension Stack {

var topItem: T? {

return items.isEmpty ? nil : items[items.count - 1]

}

}

var numstack = Stack<Int>()

numstack.push(item: 223)

numstack.push(item: 444)

numstack.push(item: 543)

numstack.push(item: 632)

if let topItem = numstack.topItem {

print("The top item in stack is \(topItem)")

}

If you observe above example we defined a new structure Stack and extending the behaviour of Stack using extension keyword to get the latest element which inserted in Stack.

 

When we run above example in swift playground we will get a result like as shown below

 

The top item in stack is 632

This is how we can extend the behavior of generic types based on our requirements in swift programming language.

Swift Generic Type Constraint

In Swift, type constraints specify that a type parameter must inherit from a specific class or always conform a protocol or to its protocol composition.

 

Following is the syntax of type constraint by writing a single class or protocol after parameter name separated with colon, as part of parameter list.

 

func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {

// function body

}

Following is the example of using type constraints in generics in swift programming language.

 

func findIndex<T: Equatable>(array: [T], _ valueToFind: T) -> Int? {

for (index, value) in array.enumerated() {

if value == valueToFind {

return index

}

}

return nil

}

let arrayofnumbers = [145, 446, 335, 3459]

print(findIndex(array: arrayofnumbers, 335))

If you observe above example we are using type constraints in generics to find the index position of elements in array list.

 

When we run above program in swift playground we will get a result like as shown below

 

2

This is how we can use type constraints in generics based on our requirements in swift programming language.

Swift Associated Types

Generally in swift, we use associated types along with protocols definition. Basically the associated types are the placeholders to specific type that is used as part of the protocols. The associated type is nothing until the protocol is adopted. Associated types are always declared using associatedtype keyword.

 

Following is the example of using associated types along with protocols definition in swift programming language.

 

protocol SampleProtocol{

associatedtype type

mutating func append (_ item: type)

var count: Int {get}

subscript(i: Int) -> type {get}

}

struct Stack<T> : SampleProtocol {

var items = [Int]()

mutating func push (_ item: Int){

items.append(item)

}

mutating func pop () -> Int {

return items.removeLast()

}

typealias alias = Int

mutating func append (_ item: Int){

self.push(item)

}

var count: Int {

return items.count

}

subscript (i: Int) -> Int {

return items[i]

}

}

var stk = Stack<Int>()

stk.push(223)

stk.push(444)

stk.push(543)

stk.push(232)

print(stk)

If you observe above example we used associated types with protocols and inserting values defined structure based on our requirements.

 

When we run the above example we will get a result like as shown below

 

Stack<Int>(items: [223, 444, 543, 232])

This is how we can use associated types with generics in swift programming language.

Swift Generic Where Clauses

A generic where clause enables us to confirm that a certain protocol must be associated type or not and where clause will check whether type parameter and associated types are matching or not and those must be the same. A generic where clause must start with where keyword followed by the associated type.

 

Following is the example of using generic where clause in swift programming language.

 

protocol ContainerOfItems {

associatedtype ItemType

mutating func append(item: ItemType)

var count: Int { get }

subscript(i: Int) -> ItemType { get }

}

struct Stack<T>: ContainerOfItems {

var items = [T]()

mutating func push(item: T) {

items.append(item)

}

mutating func pop() -> T {

return items.removeLast()

}

mutating func append(item: T) {

self.push(item: item)

}

var count: Int {

return items.count

}

subscript(i: Int) -> T {

return items[i]

}

}

func allItemsMatch<Container1: ContainerOfItems, Container2: ContainerOfItems

where Container1.ItemType == Container2.ItemType, Container1.ItemType: Equatable>

(someContainer: Container1, anotherContainer: Container2) -> Bool {

if someContainer.count != anotherContainer.count {

return false

}

for i in 0..<someContainer.count {

if someContainer[i] != anotherContainer[i] {

return false

}

}

return true

}

var itemlist = Stack<String>()

itemlist.push(item: "Trishika")

print(itemlist.items)

itemlist.push(item: "Suresh")

print(itemlist.items)

itemlist.push(item: "Rohini")

print(itemlist.items)

print(itemlist)

When we run above example in swift playground we will get a result like as shown below

 

["Trishika"]

["Trishika", "Suresh"]

["Trishika", "Suresh", "Rohini"]

Stack<String>(items: ["Trishika", "Suresh", "Rohini"])

This is how we can use generic where clause in a swift programming language based on our requirements.