3
votes

I'm trying to create a protocol and a couple of classes that conform to it. The protocol has an property which conforms to another protocol so the classes each need to have a property that matches.

This is (something like) what I'm trying so far:

protocol Edible {
    func eat()
}

class Apple:Edible {
    func eat() {
        print("Crunch")
    }
}

class Banana:Edible {
    func eat() {
        print("Homph")
    }
}

protocol Delicious {
    func consume()

    var fruit: Edible? { get set }
}    

class ToffeeApple: Delicious {
    func consume() {
        print("I like toffee apples!")
        fruit.eat()
        // ...
    }

    var fruit: Apple?
}

class BananaSplit: Delicious {
    func consume() {
        print("Ah! A banana split!")
        fruit.eat()
        // ....
    }

    var fruit: Banana?
}

The (relevant) error I'm getting is "Type 'ToffeeApple' does not conform to protocol 'Delicious'" (and the same for Banana and BananaSplit too). I thought the properties Apple and Banana would satisfy the requirements as they both conform to Edible as as fruit does. Am I declaring one of these incorrectly or is this not possible?

Many thanks.

2

2 Answers

2
votes
import UIKit

protocol Edible {
    func eat()
}

class Apple: Edible {
    func eat() {
        print("Crunch")
    }
}

class Banana:Edible {
    func eat() {
        print("Homph")
    }
}

protocol Delicious {
    func consume()

    var fruit: Edible? { get set }
}

class ToffeeApple: Delicious {
    var fruit: Edible?

    func consume() {
        print("I like toffee apples!")
        fruit?.eat()
    }

}

class BananaSplit: Delicious {
    var fruit: Edible?

    func consume() {
        print("Ah! A banana split!")
        fruit?.eat()
    }
}

let bananaSplit = BananaSplit()
bananaSplit.consume() // Ah! A banana split!
2
votes

Simply change from:

protocol Delicious {
    func consume()

    var fruit: Edible? { get set }
}

to:

protocol Delicious {
    func consume()

    associatedtype EdibleType: Edible
    var fruit: EdibleType? { get set }
}

associatedtype EdibleType: Edible means:

protocol Delicious has an unprovided type EdibleType which confirm to protocol Edible.

And the type should be provided when something is confirm to Delicious.

So in:

class ToffeeApple: Delicious {
    func consume() {
        print("I like toffee apples!")
        fruit.eat()
        // ...
    }

    typealias EdibleType = Apple
    var fruit: Apple?
}

The EdibleType is filled with Type Apple,

And in:

class BananaSplit: Delicious {
    func consume() {
        print("Ah! A banana split!")
        fruit.eat()
        // ....
    }

    typealias EdibleType = Banana
    var fruit: Banana?
}

The EdibleType is filled with Type Banana,

If you want learn more about this you can search around Swift Generics.