swift-book
swift-book copied to clipboard
Nesting Functions returning Protocol Types aren’t “Invalid”
Location
https://docs.swift.org/swift-book/documentation/the-swift-programming-language/opaquetypes#Differences-Between-Opaque-Types-and-Protocol-Types
Description
In the document, the Chapter "Opaque Types" describes the difference between protocol types and opaque types as function return types as follows:
Another problem with this approach is that the shape transformations don’t nest. The result of flipping a triangle is a value of type
Shape
, and theprotoFlip(_:)
function takes an argument of some type that conforms to theShape
protocol. However, a value of a protocol type doesn’t conform to that protocol; the value returned byprotoFlip(_:)
doesn’t conform toShape
. This means code likeprotoFlip(protoFlip(smallTriangle))
that applies multiple transformations is invalid because the flipped shape isn’t a valid argument toprotoFlip(_:)
.
However, in practice, unlikely, it is valid as proven by the following example:
#if swift(>=5.8)
print("hello swift 5.8+")
#endif
protocol Shape {
func draw() -> String
}
struct Triangle: Shape {
var size: Int
func draw() -> String {
var result: [String] = []
for length in 1...size {
result.append(String(repeating: "*", count: length))
}
return result.joined(separator: "\n")
}
}
struct FlippedShape<T: Shape>: Shape {
var shape: T
func draw() -> String {
if shape is Square {
return shape.draw()
}
let lines = shape.draw().split(separator: "\n")
return lines.reversed().joined(separator: "\n")
}
}
struct Square: Shape {
var size: Int
func draw() -> String {
let line = String(repeating: "*", count: size)
let result = Array<String>(repeating: line, count: size)
return result.joined(separator: "\n")
}
}
func flip<T: Shape>(_ shape: T) -> some Shape {
return FlippedShape(shape: shape)
}
func protoFlip<T: Shape>(_ shape: T) -> Shape {
if shape is Square {
return shape
}
return FlippedShape(shape: shape)
}
let smallTriangle = Triangle(size: 3)
let nestedThing = protoFlip(protoFlip(smallTriangle))
print(nestedThing.draw())
// hello swift 5.8+
// *
// **
// ***
Discussion in here: https://forums.swift.org/t/nesting-functions-returning-protocol-types-arent-invalid-in-swift-5-8/64366
Correction
The following phrase sounds confusing: "However, a value of a protocol type doesn’t conform to that protocol."
And it should prompt a compile error.