Extending Typed Array by Conforming to a Protocol in Swift 2

Extending typed array by conforming to a protocol in Swift 2

You can't apply a lot of logic to conformance. It either does or does not conform. You can however apply a little bit of logic to extensions. The code below makes it easy to set specific implementations of conformance. Which is the important part.

This is used as a typed constraint later.

class SomeType { }

This is your protocol

protocol SomeProtocol {

func foo()

}

This is an extension of the protocol. The implementation of foo() in an extension of SomeProtocol creates a default.

extension SomeProtocol {

func foo() {
print("general")
}
}

Now Array conforms to SomeProtocol using the default implementation of foo(). All arrays will now have foo() as a method, which is not super elegant. But it doesn't do anything, so it's not hurting anyone.

extension Array : SomeProtocol {}

Now the cool stuff:
If we create an extension to Array with a type constraint for Element we can override the default implementation of foo()

extension Array where Element : SomeType {
func foo() {
print("specific")
}
}

Tests:

let arrayOfInt = [1,2,3]
arrayOfInt.foo() // prints "general"

let arrayOfSome = [SomeType()]
arrayOfSome.foo() // prints "specific"

How can I extend typed Arrays in Swift?

For extending typed arrays with classes, the below works for me (Swift 2.2). For example, sorting a typed array:

class HighScoreEntry {
let score:Int
}

extension Array where Element == HighScoreEntry {
func sort() -> [HighScoreEntry] {
return sort { $0.score < $1.score }
}
}

Trying to do this with a struct or typealias will give an error:

Type 'Element' constrained to a non-protocol type 'HighScoreEntry'

Update:

To extend typed arrays with non-classes use the following approach:

typealias HighScoreEntry = (Int)

extension SequenceType where Generator.Element == HighScoreEntry {
func sort() -> [HighScoreEntry] {
return sort { $0 < $1 }
}
}

In Swift 3 some types have been renamed:

extension Sequence where Iterator.Element == HighScoreEntry 
{
// ...
}

Extension of array with Elements conforming a protocol in swift 2.0

Ok, looks like it is a well known behavior... for someone is a bug.

Actually, no, this is just a known limitation of the compiler. Unfortunately, today, the protocol type (or "existential" as we compiler weenies call it) doesn't conform to the protocol:

protocol P {}  
func g<T: P>(_: T) {}
struct X : P {}
struct Y<T: P> {}
Y<P>() // error: type 'P' does not conform to protocol 'P'

source: https://forums.developer.apple.com/message/15955#15955

Extend Array to conform to protocol if Element conforms to given protocol

Swift 4.2

In Swift 4.2 I was able to extend an array with the elements conforming to a protocol like this:

public extension Array where Element: CustomStringConvertible{
public var customDescription: String{
var description = ""
for element in self{
description += element.description + "\n"
}

return description
}
}

How do I create an extension to allow an array of a custom type to conform to a protocol?

Short answer: no.

You can constrain an extension, but a constrained extension can't contain an inheritance clause (the Swift proposal @Code Different linked above is exactly what you're looking for).

One workaround would be to make the constrained extension, but just add your own property, rather than having it conform to CustomStringConvertible.

class Banana : CustomStringConvertible {
var description: String {
return "a banana"
}
}

let aBanana = Banana()
aBanana.description // "a banana"

extension Array where Element: Banana {
var bananaDescription: String {
return "a bunch of bananas"
}
}

let bananas = [Banana(), Banana(), Banana()]
bananas.bananaDescription // "a bunch of bananas"

Worth noting, too, that Array already conforms to CustomStringConvertible.

let bananas = [Banana(), Banana(), Banana()]
bananas.description // "[a banana, a banana, a banana]"

Heterogeneous array that conforms to protocol with associated type in Swift

See if this fits your needs.

Approach:

Remove the associated type

Implementation:

protocol BProtocol {
func aFunc(parameter: BProtocol) -> Bool
}

extension String : BProtocol {
func aFunc(parameter: BProtocol) -> Bool {
return true
}
}

extension Int : BProtocol {
func aFunc(parameter: BProtocol) -> Bool {
return false
}
}

extension Array : BProtocol where Element == BProtocol {

func aFunc(parameter: BProtocol) -> Bool {
return self.reduce(true, { r,e in r || e.aFunc(parameter: parameter) })
}
}

Invoking:

let a1 : [BProtocol] = [1, 2, 3, "Hi"]

let boolean = a1.aFunc(parameter: 1)


Related Topics



Leave a reply



Submit