Matth
Matth

Reputation: 148

How to cast an typed array to one of the types protocols?

I have this in my playground:

func foo(printables: [Printable]) {
    // do something
}

enum MenuOptions: String, Printable {
    case ChangePickup = "Change Pickup Time"
    case RequestSupport = "Request Support"

    var description: String {
        get {
            return self.rawValue
        }
    }
}
var menuOptions: [MenuOptions] = [.ChangePickup]
foo(menuOptions)
let printables = menuOptions as [Printable]    

Both last lines give a compiler error. I would expect menuOptions to be implicitly casted to [Printable] but the compiler complains with a [MenuOptions] is not convertible to [Printable] error. Am I missing something?

If I do menuOptions as! AnyObject as! [Printable] the compiler doesn't complain and the code works properly, but this seems dirty. Funnily enough, doing foo(menuOptions.map { $0 }) also works! Is this just a compiler bug?

Upvotes: 0

Views: 56

Answers (2)

justinpawela
justinpawela

Reputation: 1978

You are trying to create a generic function constrained to objects that conform to the Printable protocol. Just define it differently:

func foo<T: Printable>(printables: [T]) {
    // do something
}

The function will now work in your context. It will take an array of any object type that conforms to Printable.

Here are the relevant docs on Generics, specifically Type Constraints.

As to why this works, but your definition doesn't - this is just the Swift syntax. Printable is a protocol, but T is a type (generic, but still a type). You want your function to accept any type (T) that conforms to a protocol (<T: Protocol>). This is just how the language has been designed.

Using menuOptions as! AnyObject as! [Printable] may work in this example, but it is a bad practice. Using as! is like telling the compiler "trust me, this will work." This is fine in limited cases, but sets you up for trouble in the long run. Using as! turns off the compiler's type checking, which means if there is a problem it will happen at runtime, and your app will crash.

Again, I highly suggest reading the docs on Type Constraints, which I linked above. It explains it in detail.

Upvotes: 1

Wonjung Kim
Wonjung Kim

Reputation: 1933

I found that this is working. It seems that Swift compiler is not that smart.

var menuOptions: [MenuOptions] = [MenuOptions.ChangePickup]
let printables:[Printable] =  menuOptions as! [Printable]
foo(printables)    

I don't know why these are not working

foo(menuOptions)
foo(menuOptions as! [Printable])

Upvotes: 0

Related Questions