Skip to content

Instantly share code, notes, and snippets.

@Dev1an
Last active June 10, 2022 09:12
Show Gist options
  • Save Dev1an/dfae2fb2d006898c0beab6dcc63a6c51 to your computer and use it in GitHub Desktop.
Save Dev1an/dfae2fb2d006898c0beab6dcc63a6c51 to your computer and use it in GitHub Desktop.
This is a workaround for the "Protocol 'Encodable' as a type cannot conform to the protocol itself" paradox. It provides a way to explicitly open up existential Encodable types and encode them using an encoder.
import Foundation
let someEncodableThing: Encodable = "Hello world"
#if swift(>=5.7)
let data = try JSONEncoder().encode(json)
#else
let data = try JSONEncoder().encode(existential: json)
#endif
//
// Encode Existentials.swift
//
// This is a workaround for the "Protocol 'Encodable' as a type cannot conform to the protocol itself" paradox.
// All the code in this file can be safely removed after upgrading to the swift 5.7 compiler.
// Calls to ``TopLevelEncoder/encode(existential: Encodable)`` can then safely be replaced
// with a call to the encoder's `encode(_:)` function
// due to the "Implicitly Opened Existentials" (SE-0352) feature implemented in swift 5.7: https://github.com/apple/swift-evolution/blob/main/proposals/0352-implicit-open-existentials.md
//
// Created by Damiaan Dufaux on 09/06/2022.
//
#if swift(<5.7)
import class Foundation.JSONEncoder
extension JSONEncoder: TopLevelEncoder {}
/// A type that defines methods for encoding.
protocol TopLevelEncoder {
/// The type this encoder produces.
associatedtype Output
/// Encodes an instance of the indicated type.
///
/// - Parameter value: The instance to encode.
func encode<T>(_ value: T) throws -> Self.Output where T : Encodable
}
extension TopLevelEncoder {
/// Explicitly opens an existential `Encodable` type and encodes it.
func encode(existential: Encodable) throws -> Output {
try existential.encode(using: self)
}
}
extension Encodable {
/// Explicitly opens a potential existential Encodable and encodes it using the specified TopLevelEncoder.
func encode<E: TopLevelEncoder>(using encoder: E) throws -> E.Output {
// `self` here, is a reference to the concrete 'underlying' type of a potential existential type.
try encoder.encode(self)
}
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment