Generic Extension for Array in Swift

Jignesh Fadadu picture Jignesh Fadadu · Apr 18, 2017 · Viewed 10.4k times · Source

To be very frank, I am totally new to learn Extension creation and usage.

I wanted to create a category (Extension in swift 3.0) which can be used throughout an application to perform repeated operations for Array.

Sample Link 1

This is what I have seen and understand while doing research, I wanted to create an extension with various methods which should be generic, and not on the basis of datatype needed to create separate extensions.

Here in above example, we will need to create single extension if we will go for particular datatype wise extension. I wanted to have a guidance if any way is there to create the generic category (Extension in swift).

  1. extension _ArrayType where Generator.Element == Int
  2. extension Array where Element: Equatable
  3. extension Array where Element == Int
  4. extension _ArrayType where Generator.Element == Float
  5. extension SequenceType where Self.Generator.Element: FloatingPointType
  6. extension Array where Element: DoubleValue
  7. extension Sequence where Iterator.Element == String

,etc...

Sample Link 2

Note : In short, we can consider that I want to perform actions based on Array in single extension instead of just creating the single extension for each of the datatypes as per above requirement.

Answer

BHendricks picture BHendricks · Apr 22, 2017

As mentioned in the comments, one way to accomplish this is to create your own protocol that the types you want to cover adopt (in the comments someone called it Content, used below for this example) (from first source):

protocol Content {
    var hash: String { get }
}
extension Array where Element : Content {

    func filterWithId(id : String) -> [Element] {
        return self.filter { (item) -> Bool in
            return item.id == id
        }
    }
}

It seems, though, that the original question is mainly asking about generic extensions for arrays, which one comment says are not possible but 100% are possible in Swift (it's a big Swift feature, actually) (from second source).

For example, if you want to define a specific extension method for Ints only, you can do that:

extension Sequence where Iterator.Element == Int {
    var sum: Int {
        return reduce(0, +)
    }
}

It seems like the question's original requirements are extension methods that could be agnostic to data type and therefore should be kept in common. If I understand correctly, seems though that these data types in general have some conformance to Equatable and/or Hashable, which is the minimum requirement for this kind of generic-stuff to work. With this element conformance, though, this is possible as such:

extension Sequence where Iterator.Element is Equatable {
    func extensionMethodName<T: Equatable>(_ input: [T], singleElement: T) -> [T] {
        // T is now a generic array of equatable items. You can implement whatever extension logic you need with these. 
        // I added different ways of passing in and returning this generic type, but the only thing that is likely going to be consistent is the `<T: Equatable>` which is Swift standard syntax for declaring generic type parameters for a method.
    }
}

The Swift syntax changes quickly, and what's here can quickly go out of date, but this guide is kept fairly up-to-date by Apple and shows the most up to date syntax for Generics used above ^.

My answer pulls from a couple StackOverflow questions/answers, used for example/syntax above ^. Source: (SO Source) (SO Source 2)

In summary, all the methods above can be combined, for a fully custom extension solution that has both generic functions/vars for all your Array types, while still having type-specific extension overrides.