Can swift function return different types conforming to same protocol?

38 Views Asked by At

For example, imagine a pizzeria with two different types of pizza:

struct SmallPizza {
    var radius: Int
}
struct LargePizza {
    var diameter: Int
}

Lets say they want to create different pizzas using the above types, both conforming to a same protocol. You would do:

protocol Pizza {
    associatedtype PizzaType

    var pizzaType: PizzaType { get set }
    var name: String { get set }
}

struct PizzaOne: Pizza {
    var pizzaType: SmallPizza
    var name: String
}

struct PizzaTwo: Pizza {
    var pizzaType: LargePizza
    var name: String
}

Until here everything works seamlessly. Now they would like to create a PizzaManager which can get a pizza for a certain ID:

struct PizzaManager {
    let pizzaOne = PizzaOne(pizzaType: SmallPizza(radius: 5), name: "Margherita")
    let pizzaTwo = PizzaTwo(pizzaType: LargePizza(diameter: 30), name: "Quattro Formaggi")
    
    // This functions shows the concept I would like to achieve, also if it doesn't work.
    func getPizza(forID id: Int) -> Pizza {
        if id == 1 {
            return pizzaOne
        } else {
            return pizzaTwo
        }
    }
}

Using this approach throws an error which is understandable: Protocol 'Pizza' can only be used as a generic constraint because it has Self or associated type requirements.

Other things I tried:

  • Using a generic type, like the error message suggests: func getPizza<T: Pizza>(forID: identifier) -> T {...}. This throws no errors but it is also no solution, as the caller would then need to specify the exact type like let result: PizzaOne = pizzaManager.getPizza(forID: 1). This doesn't solve the problem because I don't want to specify the actual type.
  • I would very much like to avoid Any. If I understand correctly, using Any would also move the problem from the function to the caller when needing to unpack.
  • Using opaque return types: func getPizza(forID: identifier) -> some Pizza {...}. They actually sound like the perfect solution, however opaques only allow one single return type (so either PizzaOne or PizzaTwo).

Question:

I want to return either PizzaOne or PizzaTwo from a function, as them being "some" type conforming to Pizza. So after that, just access attributes defined by the Pizza protocol and thus contained in types conforming to the Pizza protocol.

I'm pretty sure this can't be done with opaque return types as they only allow one type to be returned. Maybe this is also no feature in Swift yet, or I'm misunderstanding something? Is there any other way to solve this problem?

Hope you didn't get too hungry while reading about pizzas ;). Any help would be greatly appreciated!

0

There are 0 best solutions below