My understanding of opaque types is that if a function returns an opaque type, the compiler knows what type is being returned even though it's not explicitly defined in the return type itself.
Since it does give us the guarantee that it knows what the type is, then why does it pretend like it doesn't know what the type is?
In the below example, this Combine publisher clearly publishes a value of type Int
, and the compiler knows it, because if I try to make a condition where sometimes it publishes a String
then the compiler won't allow it.
However despite the fact that the compiler knows this publisher's value is Int
, when we try to treat it as an Int
in our subscriber, it doesn't let us do that because it says the type is simply '(some Publisher).Output'
.
The only alternative seems to be, use the (partially) type-erased AnyPublisher as a return type, and make the generic constraints explicit like AnyPublisher<Int, Never>
. But then we have to resort to arcane stuff like appending .eraseToAnyPublisher
which does not feel like nice, clean, Swifty code.
So is this a compiler bug or is some Publisher
supposed to hide the exact type from the subscriber?
If it is supposed to hide it, then could I humbly request that we also add a feature to the Swift language called "transparent types", which acts just like "opaque types" except without the loss of type information?
Maybe the syntax for "transparent types" could be somePublic
?
Or is there a reason why information loss had to be coupled to this new ability of the compiler to infer the precise return type?
import Foundation
import Combine
/// Sends a single value and then completes.
func sendsSingleValueThenCompletes() -> some Publisher {
Just(1)
}
sendsSingleValueThenCompletes()
.sink(
receiveCompletion: {
print("Completion: \($0)")
},
receiveValue: {
print("Value: \($0.bitWidth)")
// error: Combine Lab - Solutions.xcplaygroundpage:16:32: error: value of type '(some Publisher).Output' has no member 'bitWidth'
}
)