swiftopaque-types

Unable to compare two instances of opaque types


It's interesting to see that we can now declare return values that are protocols with associated types.

The following throws an error and I don't understand the error.

protocol Plant: Equatable {
    var maintenance: String { get }
}

struct Rose: Plant {
    let height: Float // inches
    let maintenance = "Water once a day."
}

struct Orchid: Plant {
    let height: Float // inches
    let maintenance = "Water once a month."
}

func makePlant1() -> some Plant {
    Rose(height: 4)
}

func makePlant2() -> some Plant {
    Orchid(height: 8)
}

let plant1: some Plant = makePlant1()
let plant2: some Plant = makePlant2()

func asdf() {
    let condition: Bool = (plant1 == plant2) // error: ambiguous without more context
    print(condition)
}

Solution

  • When you declare a function to return some Plant then the compiler will look at the content of the function to see what real type is returned and in your example you are returning different types, Rose and Orchid.

    This breaks the requirement from Equatable that Self must be the same, that you use some doesn't mean that this requirement disappears.

    The error message you get is a bit confusing but if you change it to

    print(plant1 == plant2)
    

    the error is more informative

    Cannot convert value of type 'some Plant' (result of 'makePlant2()') to expected argument type 'some Plant' (result of 'makePlant1')

    To be able to use == here you need to use objects created by the same function

    func makePlant1(_ value: Float) -> some Plant {
        Rose(height: value)
    }
    
    let plant1 = makePlant1(4)
    let plant2 = makePlant1(4)
    let plant3 = makePlant1(6)
    
    print(plant1 == plant2) // true
    print(plant1 == plant3) // false
    

    Here is an informative article on the topic from hackingwithswift.com