Array cannot be bridged from Objective-C

I've found the answer to this one myself, not that I understand why however.


Given a pure Swift object that conforms to a Swift protocol:


protocol P {
    var name: String { get }
}
class PImpl: P {
    let name: String
    init(name: String) {
        self.name = name
    }
}


Run the following testcases:


    func unbridgableArrayOfPs() -> [P] {
        let pees = [PImpl(name: "A"), PImpl(name: "B"), PImpl(name: "C")]
        return pees
    }

    func arrayOfPs() -> [P] {
        return [PImpl(name: "A"), PImpl(name: "B"), PImpl(name: "C")]
    }

    func testUnbridgableArrayOfPs() {
        let p = unbridgableArrayOfPs() // Fails with fatal error: array cannot be bridged from Objective-C
        let result = p.map{$0.name}.joinWithSeparator("")
        XCTAssertEqual(result, "ABC")
    }

    func testArrayOfPs() {
        let p = arrayOfPs() // We get our P's
        let result = p.map{$0.name}.joinWithSeparator("")
        XCTAssertEqual(result, "ABC")
    }


It would seem that returning the array directly without creating a temporary variable allows this to succeed, whereas the unbridgableArrayOfPs() function fails.


Any thoughts?


The other options are

1. Annotate the protocol with @objc

2. Change the return type of the array to the concrete implementation's type i.e PImpl


1 Isn't going to work I believe if there are things like Swift enums in the mix

2 From a design perspective, it's nice to keep things implementation agnostic where possible.

Accepted Reply

The fatal error is caused by this line:

        return pees

In your `unbridgableArrayOfPs` method, the type of `pees` is inferred as [PImpl], and unfortunately the current Swift cannot convert [PImpl] to [P] .

(If Swift runtime cannot handle this sort of conversion, Swift compiler should warn it. So, this issue should be considered as a bug.

You can find Report Bugs link in almost all pages of Apple's dev site.)

In your `arrayOfPs`, -- remember array literals are typeless in Swift --, the array literal is put as a return value, so its type is inferred from the return type of the method, the array literal is directly constructed as [P], no conversion occurs.

Thus, another options are:

- Annotate the type of `pees` explicitly

    let pees: [P] = [PImpl(name: "A"), PImpl(name: "B"), PImpl(name: "C")]

- Annotate the type of the array literal explicitly

    let pees = [PImpl(name: "A"), PImpl(name: "B"), PImpl(name: "C")] as [P]

- Convert [PImpl] to [P] manually

    let pees = [PImpl(name: "A"), PImpl(name: "B"), PImpl(name: "C")]
    let peesAsArrayP: [P] = pees.map{$0 as P}
    return peesAsArrayP

Replies

The fatal error is caused by this line:

        return pees

In your `unbridgableArrayOfPs` method, the type of `pees` is inferred as [PImpl], and unfortunately the current Swift cannot convert [PImpl] to [P] .

(If Swift runtime cannot handle this sort of conversion, Swift compiler should warn it. So, this issue should be considered as a bug.

You can find Report Bugs link in almost all pages of Apple's dev site.)

In your `arrayOfPs`, -- remember array literals are typeless in Swift --, the array literal is put as a return value, so its type is inferred from the return type of the method, the array literal is directly constructed as [P], no conversion occurs.

Thus, another options are:

- Annotate the type of `pees` explicitly

    let pees: [P] = [PImpl(name: "A"), PImpl(name: "B"), PImpl(name: "C")]

- Annotate the type of the array literal explicitly

    let pees = [PImpl(name: "A"), PImpl(name: "B"), PImpl(name: "C")] as [P]

- Convert [PImpl] to [P] manually

    let pees = [PImpl(name: "A"), PImpl(name: "B"), PImpl(name: "C")]
    let peesAsArrayP: [P] = pees.map{$0 as P}
    return peesAsArrayP

Thanks, I can confirm that both the following work (as would the third, I'm sure but the other two look neater)


let pees = [PImpl(name: "A"), PImpl(name: "B"), PImpl(name: "C")] as [P]


let pees: [P] = [PImpl(name: "A"), PImpl(name: "B"), PImpl(name: "C")]


I might file a bug anyway if I get a chance this week, even though the workaround is trivial.