Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift closure: Cannot convert value of type '(_) -> Bool' to expected argument type

Tags:

xcode

swift

I'm working with the filter() method in Swift, but encountering a problem I can't seem to reproduce in a playground.

Edit: Uploaded an example project here: https://www.dropbox.com/s/5ce5uyxnpb0mndf/WeirdSwifty.zip?dl=0

I have a Card struct which contains a CardType enum:

struct Card {
    var name = ""
    var type : CardType

    enum CardType {
        case Red
        case Black
    }
}

And a Player class which maintains an array of these Card items:

class Player {
    var hand : [Card]

    init() {
        hand = ...
    }

    func redCards() -> [Card] {
        return hand.filter({ (card) -> Bool in
            return card.type == .Red
        })
    }
}

However, Xcode is throwing an error no matter how I try to format this closure. I even let Xcode autocomplete the closure signature/body, thinking I had a syntax error, but it keeps recreating it the same (correct?) way:

enter image description here

I've also tried editing what Xcode automatically generates and providing a simpler version, to no avail:

enter image description here

Similarly:

enter image description here

As I mention I'm unable to reproduce this in a simple playground example, but I can't narrow down what's actually causing the issue in my primary project.

This is the only error in my project, and if I comment out the method containing the filter() call, it builds properly.

Is this error a common red herring for some other actual issue?

Note: Using Xcode 7.3.1 (7D1014)

like image 629
Craig Otis Avatar asked Jun 12 '16 13:06

Craig Otis


1 Answers

Something flakey is happening with Swift's type inference. Give card an explicit type and it will work.

return hand.filter({ (card: Card) -> Bool in return card.type == .Red })

You don't need the return type or the return:

return hand.filter({ (card: Card) in card.type == .Red })

Note: this works also:

return hand.filter({ ($0 as Card).type == .Red })

Fully specifying the .Red enum value resolves the issue as well:

return hand.filter({ $0.type == Card.CardType.Red })

It was mentioned in the comments that if you move the definition of Card into the same file as the filter, that it works. In fact, if you split the definition of the CardType enum out from Card and just move CardType into the file with the filter, it works.

like image 176
vacawama Avatar answered Oct 23 '22 08:10

vacawama