No, I'm using any
to refer to protocol types as the Swift Programming Language Guide calls them. Generics and protocol types are identical on the call site:
func foo<T: Protocol>(_ p: T) {}
func bar(_ p: any Protocol) {}
you can pass any Protocol
-conforming type to both foo
and bar
, but the difference lays in the possibility to specialize the former.
The caller doesn't know the underlying type which can be passed and that's the point, since that underlying type might be private
, therefore unreachable. However, based on the protocol interface, it can be guided to the "correct" opaque type.
private struct Private: Equatable {}
let p: some Equatable = Private()
let q: some Equatable = Private()
p == q // error: p and q may have different underlying types
The diagnostics can help: you can write p == p
, q == q
or even let p2 = p; p2 == p
, but you cannot use ==
on unrelated some Equatable
s.
Who decides which types == (lhs: some Equatable, rhs: some Equatable) -> Bool
can accept in argument position? It's the function ==
, not the caller:
protocol Equatable {
static func == (lhs: Self, rhs: Self) -> Bool
}
The declaration of ==
constrains both lhs
and rhs
to have the same type, which is the type Self
of the instance (in this case the instance is p
).
With this design in place, which I'd like to remark that it's just one of the possible designs that can extend the current status of opaque types consistently, would it make sense to allow declaration of functions having opaque types in argument position? No, it wouldn't. In the declaration of the following function
func == (lhs: some Equatable, rhs: some Equatable) -> Bool { ... }
the types of lhs
and rhs
cannot be inferred from the declaration context. You would need to use reverse generics explicitly if they were available
func == <^T: Equatable = Private>(lhs: T, rhs: T) -> Bool { ... }
but such a function would be almost useless. T
is known to conform to Equatable
, it is provided by the function but it is unrelated to any other Equatable
-conforming type, so you cannot have an instance of the "correct" opaque type to pass as argument.
An example in which the function can still be called has been provided by @ensan-hcl:
but it would be quite unusual to provide such a function in a module for the sake of making the parameter type private
. If you want the parameter type to be private, then the function declaration should most likely be private too.