1
votes

When I work on the opaque types, I read this section in the official documents of Swift.

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 the protoFlip(:) function takes an argument of some type that conforms to the Shape protocol. However, a value of a protocol type doesn’t conform to that protocol; the value returned by protoFlip(:) doesn’t conform to Shape. This means code like protoFlip(protoFlip(smallTriange)) that applies multiple transformations is invalid because the flipped shape isn’t a valid argument to protoFlip(_:).

This part made me consider about nested functions whose return type is protocol and I wanted to play about the protocol return types in the playground. As a result, I created a protocol called Example and also, a non generic and generic concrete types that conform to Example protocol. I kept "sample" method implementations which is protocol requirement as simple as possible because of focusing return types.

protocol Example {
    func sample(text: String) -> String
}

struct ExampleStruct: Example {
    func sample(text: String) -> String {
        return text
    }
}

struct ExampleGenericStruct<T: Example>: Example {
    var t: T
    func sample(text: String) -> String {
        return t.sample(text: "\n")
    }
}

After that, I created a generic function which has an argument constraint by Example protocol and returns Example protocol. Then, I tested my function as nested.

func genericTestExample<T: Example>(example: T) -> Example {
    return ExampleGenericStruct(t: example)
}

genericTestExample(example: genericTestExample(example: ExampleStruct()))

I got this error:

Value of protocol type 'Example' cannot conform to 'Example'; only struct/enum/class types can conform to protocols

This is what I expected. Function returns the protocol itself, not the concrete type that conforms it.

Finally, I wrote an another function.

func testExample(example: Example) -> Example {
    if example is ExampleStruct {
        return example
    }
    return ExampleGenericStruct(t: ExampleStruct())
}

When I run the code, I could nest this function successfully.

testExample(example: testExample(example: ExampleStruct()))

I can pass any value to both genericTestExample and testExample functions as long as it conforms to Example protocol. Also, they have the same protocol return type. I don't know why I could nest testExample function while I could not nest genericTestExample function or vise versa.

1
testExample accepts a parameter of type Example, which is also its return value - that's why it works here. genericTestExample, on the other hand, accept a parameter of type T: Example, but returns Example - which, as you noted, is not accepted because Example doesn't conform to Example - a requirement of T - New Dev

1 Answers

0
votes

swift 5.4 2021-09-27 08:36 UTC

@ceylanburak

you should use the Opaque Types in swift.


// some Example is **Opaque Types** !!!
func genericTestExample<T: Example>(example: T) -> some Example {
    return ExampleGenericStruct(t: example)
}

now follow your previous mind

genericTestExample(example: genericTestExample(example: ExampleStruct()))

and it equals to

let e1: some Example = genericTestExample(example: ExampleStruct())
genericTestExample(example: e1)