Opaque result types bug on definition?

When I trying to setup a type of opaque result types directly it shows en error. sample:

protocol P: Equatable { }
struct A: P { }

func a() -> some P { A() }

let aa = a()
let bb = a()

aa == bb // works fine and returns true
protocol P: Equatable { }
struct A: P { }

func a() -> some P { A() }

let aa: some P = a()
let bb = a()

aa == bb // error: Binary operator '==' cannot be applied to operands of type 'some P' (type of 'aa') and 'some P' (result of 'a()')

In both cases aa has the same type some P.
Is it a bug?

Screenshot 2020-01-11 at 19.13.40

This seems correct to me.

To review, an opaque type can be thought of as generics “in reverse.” It is not equivalent to an existential type, which is a kind of container that can store an instance of any conforming type. With generics, the caller gets to decide what type to use, and the callee can rely only on the generic constraints laid out beforehand. With opaque types, the callee gets to decide what type to use, and the caller can rely only on the guarantee that it conforms to the specified protocol. But underneath it all there is a type.

So, in other words, you cannot know if any two instances of type some P are of the same type merely from the fact that they are some P (hence why they are called opaque). One function could return an Int as some Hashable and another function could return a String as some Hashable.

Even if you can see with your own two eyes what the underlying types are, opaque types tell the compiler not to let you (the caller) rely on that—so that a future version of the function can be changed to return a value of a different type without affecting callers.

In the first example, the compiler knows that aa and bb are of the same type. This is because they both store a result of the same function; the function may change in the future, but then the underlying type of aa and bb would both change and still match.

In the second example, you have made the type of aa opaque to yourself. In other words, you explicitly told the compiler not to allow you to rely on the knowledge that the type of aa is the result of a(). That is what the diagnostic is telling you.

In the future, Swift might add a way to say, make this variable have an opaque type that’s the same as this other variable’s, but there is no way for you to express that today.

7 Likes