Skip to content

Instantly share code, notes, and snippets.

@benrimmington
Last active March 8, 2023 10:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save benrimmington/e45b003f4d342a05602547aefbbf3aec to your computer and use it in GitHub Desktop.
Save benrimmington/e45b003f4d342a05602547aefbbf3aec to your computer and use it in GitHub Desktop.

Simplify internals of Codable-related APIs

Introduction

This proposal aims to simplify the internals of some Codable-related APIs, by adding two primary associated types and a non-failable initializer to the standard library.

Motivation

Proposed solution

  • The public structures cannot be removed, but the internal classes can be replaced by constrained existential types:

     public struct KeyedEncodingContainer<K: CodingKey> :
       KeyedEncodingContainerProtocol
     {
       public typealias Key = K
    
       // Use a constrained existential type.
    -  internal var _box: _KeyedEncodingContainerBase
    +  internal var _box: any KeyedEncodingContainerProtocol<Key>
    
       // Use a constrained opaque parameter type?
    -  public init<Container: KeyedEncodingContainerProtocol>(
    -    _ container: Container
    -  ) where Container.Key == Key {
    +  public init(_ container: some KeyedEncodingContainerProtocol<Key>) {
    
         // Remove the internal subclass and its base class.
    -    _box = _KeyedEncodingContainerBox(container)
    +    _box = container
       }

    (And likewise for the KeyedDecodingContainer structure.)

  • The existing initializer cannot be made non-failable, but another initializer (without an argument label) can be used instead:

     extension CodingUserInfoKey {
    -  public static let actorSystemKey = CodingUserInfoKey(rawValue: "$distributed_actor_system")!
    +  public static let actorSystemKey = CodingUserInfoKey("$distributed_actor_system")
     }

Detailed design

  • Two primary associated types will be added:

    -public protocol KeyedEncodingContainerProtocol {
    +public protocol KeyedEncodingContainerProtocol<Key> {
       associatedtype Key: CodingKey
    -public protocol KeyedDecodingContainerProtocol {
    +public protocol KeyedDecodingContainerProtocol<Key> {
       associatedtype Key: CodingKey
  • A non-failable initializer will be added:

     public struct CodingUserInfoKey: RawRepresentable, Equatable, Hashable, Sendable {
       public let rawValue: String
       public init?(rawValue: String)
    +  public init(_ rawValue: String)

Source compatibility

The primary associated types and non-failable initializer are source-compatible additions.

ABI compatibility

The type-erased wrappers are ABI-public resilient structures, and ABI-private classes. The opaque parameter type is (assumed to be) syntactic sugar for the existing generic parameter and constraint.

Implications on adoption

The non-failable initializer can always be emitted into the client.

Future directions

None.

Alternatives considered

None.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment