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)
}
CodePudding user response:
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
CodePudding user response:
The protocol Plant
conforms to Equatable
. This means that the types that conform to Plant
also conform to Equatable
.
Rose
conforms to Plant
, so it's also Equatable
: you can differentiate two Roses.
Same for Orchid
: you can differentiate two Orchids.
But you can't equate a Rose
to an Orchid
: they both conform to the same protocol, but they don't inherit from the same class.
If you try to equate two of the same type, it works - see examples below.
1) Equating instances that follow the same protocol
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 makePlant2() -> some Plant {
Orchid(height: 8)
}
func makePlant3() -> some Plant {
Orchid(height: 10)
}
func compare() {
let plant2: Orchid = makePlant2() as! Orchid
let plant3: Orchid = makePlant3() as! Orchid
let conditionPlant: Bool = (plant3 == plant2) // both are Equatable of the same type
print(conditionPlant)
}
2) Equating classes that inherit from the same type
protocol Plant: Equatable {
var maintenance: String { get }
}
class Tree: Plant {
static func == (lhs: Tree, rhs: Tree) -> Bool {
lhs.name == rhs.name
}
let name: String
var maintenance = "Never"
init(name: String) {
self.name = name
}
}
class Oak: Tree { }
class Sequoia: Tree { }
func makeTree1() -> Tree {
Oak(name: "Shady oasis")
}
func makeTree2() -> Tree {
Sequoia(name: "Old woody")
}
func compare() {
let tree1 = makeTree1()
let tree2 = makeTree2()
let conditionTree: Bool = (tree1 == tree2) // both are Equatable, inherit from the same type
print(conditionTree)
}