5

I have the following swift code:

protocol Animal {
var name: String { get }
}

struct Bird: Animal {
    var name: String
    var canEat: [Animal]
}

struct Mammal: Animal {
    var name: String
}

extension Array where Element: Animal {
    func mammalsEatenByBirds() -> [Mammal] {
        var eatenMammals: [Mammal] = []
        self.forEach { animal in
            if let bird = animal as? Bird {
                bird.canEat.forEach { eatenAnimal in
                    if let eatenMammal = eatenAnimal as? Mammal {
                        eatenMammals.append(eatenMammal)
                    } else if let eatenBird = eatenAnimal as? Bird {
                        let innerMammals = eatenBird.canEat.mammalsEatenByBirds()
                        eatenMammals.append(contentsOf: innerMammals)
                    }
                }
            }
        }
        return eatenMammals
    }
}

The compiler does not let me compile complaining: Using 'Animal' as a concrete type conforming to protocol 'Animal' is not supported at the point where I recursively call the function mammalsEatenByBirds()

I have seen some other answers but could not relate my problem to any of those.

Hamish
  • 78,605
  • 19
  • 187
  • 280
Muhammad Ali
  • 599
  • 1
  • 7
  • 15
  • Please read the results of http://stackoverflow.com/search?q=Using++as+a+concrete+type+conforming+to+protocol+is+not+supported – vadian May 07 '17 at 18:56
  • 1
    Compare [Protocol doesn't conform to itself?](http://stackoverflow.com/a/43408193/2976878) – simple fix would just be to make the extension `extension Array where Element == Animal {...}`. Although that being said, given you're only working with the `Bird` elements, you may want to consider making it `extension Sequence where Iterator.Element == Bird`, and just doing a (lazy) `flatMap` before calling in order to filter only the `Bird` elements. – Hamish May 07 '17 at 20:01
  • Thanks it worked – Muhammad Ali Jun 02 '17 at 13:09

1 Answers1

8

Fix is replacing Element: Animal with Element == Animal.

Muhammad Ali
  • 599
  • 1
  • 7
  • 15
  • If you do it, you must cast explicitly `Bird` array to `Animal`. Like this: `let mammals = (birds as Animal).mammalsEatenByBirds()`. Thats dumb (not of you, but of Swift). – kelin Sep 27 '18 at 07:05