Move Combine's TopLevelEncoder and TopLevelDecoder protocols into the standard library

Combine introduced two Codable-related protocols to represent top level encoders and decoders. The TopLevelEncoder is used to abstract JSONEncoder and PropertyListEncoder for use in the encode(encoder:) operator. Decodable counterparts are also provided.

I think these protocols would be useful in the standard library for two main reasons:

  • Vendors of custom encoding/decoding packages wanting to participate in this environment would need to import Combine to do so, which may be undesirable.

  • Packages that want to provide functionality that is agnostic to the specific encoder/decoders being used, would also have to import Combine.

The requirement of Combine limits its use, especially as data manipulation packages would generally be cross-platform, where Combine is not available.


It might be possible for packages to do something like this:

#if canImport(Combine)
import Combine
protocol TopLevelEncoder {...}
protocol TopLevelDecoder {...}

extension MyEncoder: TopLevelEncoder {}
extension MyDecoder: TopLevelDecoder {}

to at least expose some form of top level encoding/decoding to non-combine-compatible code, but that won't be very scalable if multiple packages want to use or enable this sort of functionality, as this would have to be repeated in every package that makes their own encoder/decoder.

Are there any ABI/module stability considerations with this? I presume that now that combine is public it will still need to provide this protocol to ensure compatibility, but if this can be done with minimal invasiveness we should definitely try.

I've always been somewhat surprised that there doesn't appear to be a protocol that JSONEncoder (or a property list encoder) conforms to in the standard lib. So this definitely gets a +1 from me.


Yeah, it's trivial for packages to supply their own version of the protocols. More than just the annoyance of repetition though, the protocols may look the same, but they actually aren't, so you would still need to provide conformance as a user of two independent packages.

I think for ABI stability reasons, Combine will still need to provide these types. Also, because users could have already explicitly specified Combine.TopLevelEncoder in existing code. However, I believe Combine could re-define TopLevelEncoder to be a typealias for the swift standard library's protocol, which would allow them to interoperate.

I'm totally not an expert in this, so I'd love to understand how much of a bother these new standard library protocols would cause for the existing Combine types.

1 Like

Thanks to work by @Xi_Ge, we now have (unofficial, compiler-internal, no-user-serviceable-parts-inside, offer-void-in-Nebraska) support for moving declarations from one library "up" into another library that the original imports. Since every Swift library imports the standard library, I think this would make it possible to move these protocols into the standard library without breaking ABI.

A typealias would preserve source stability, but not ABI stability.


Is the source code for the Combine framework publicly available?


Nope, I meant publicly available to use, aka not in a beta OS/Xcode

I think I replied to this in a thread a while ago, but for what it's worth: we (Combine authors) did intend for TopLevelEncoder and TopLevelDecoder to be standard library types if possible. I support moving them down, especially now that we have the compiler feature to let us do it.


This would be great. Alamofire 5 will ship with a DataDecoder protocol to support our responseDecodable feature with arbitrary decoders, so it would be nice to have an official replacement.

Sounds very positive! Will this change require a Swift Evolution proposal? I'm happy to draft one up if so.

1 Like

Yes, I believe so since it would be a change to the Swift standard library.

1 Like
Terms of Service

Privacy Policy

Cookie Policy