1

There's similar questions out there, but this one is on the latest Swift 2.2 version. Hopefully there's a solution by now because this seems like a big obstacle to Protocol-Oriented Programming in my mind.

The below fails on assigning to let results with an error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0X0).

protocol P: class {
    var value:Int {get}
}

class X: P {
    var value = 0

    init(_ value:Int) {
        self.value = value
    }
}

func getItems() -> [P] {
    let items: [X] = [X(1), X(2), X(3)]
    return items
}

let results: [P] = getItems()

Is there any way to treat an array of classes as an array of protocols that it conforms to? This seems like a really simple and natural request for a language especially one that is heavily protocol-oriented.

I don't want to use @objc or flatMap because of vast implications on the dependency chain and performance - this would be a hack. I'd like this to work natively or it's a bug that we can hopefully formulate and present to Apple / Swift open-source team.

1 Answer 1

0

may be i don't understand your question, but this works

protocol P: class {
    var value:Int {get}
}

class X: P {
    var value = 0

    init(_ value:Int) {
        self.value = value
    }
}

func getItems() -> [P] {
    let items: [P] = [X(1), X(2), X(3)]
    return items
}

let results = getItems()
results.forEach { (p) in
    print(p.value)
}
/*
 1
 2
 3
 */

why casting [X] as [P] doesn't work? See the next example!

protocol P: class {
    var value:Int {get}
}
protocol P1: class {
    var value: Double { get }
}
protocol Z {}
class X: P,Z {
    var value = 0

    init(_ value:Int) {
        self.value = value
    }
}
class X1: P1,Z {
    var value = 0.0

    init(_ value:Double) {
        self.value = value
    }
}

func getItems() -> [Z] {
    // the only common type of all items is protocol Z  !!!!
    let items: [Z] = [X(1), X(2), X(3), X1(1), X1(2)]
    return items
}

let results = getItems()
print(results.dynamicType)
results.forEach { (p) in
    if let p = p as? P {
        print("P:", p.value)
    }
    if let p = p as? P1 {
        print("P1:", p.value)
    }
}
/*
 Array<Z>
 P: 1
 P: 2
 P: 3
 P1: 1.0
 P1: 2.0
*/

that is the reason, why using flatMap is good idea, if you would like to separate X and X1 type items from results

let arrX = results.flatMap { $0 as? P }
let arrX1 = results.flatMap { $0 as? P1 }
print(arrX, arrX1) // [X, X, X] [X1, X1]
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.