# \[Pre-Pitch\] Codable Customization using PropertyWrappers

**URL:** <https://forums.swift.org/t/pre-pitch-codable-customization-using-propertywrappers/30244>\
**Category:** Pitches\
**Created:** [October 28, 2019, 2:31pm UTC](https://forums.swift.org/t/pre-pitch-codable-customization-using-propertywrappers/30244 "2019-10-28T14:31:49Z")\
**Posts on this page:** 20\
**Page:** 3

<div class="post-metadata">

**Author:** ![mattpolzin](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/mattpolzin/32/6041_2.png) [@mattpolzin](https://forums.swift.org/u/mattpolzin)\
**Post date:** [October 30, 2019, 9:10pm UTC](https://forums.swift.org/t/pre-pitch-codable-customization-using-propertywrappers/30244/41 "2019-10-30T21:10:07Z")

</div>

I actually find the problem of property-wrapped optional values not being decodable from omitted keys to be satisfactorily addressed by the forthcoming property wrapper composition feature and a property wrapper like `@Omittable` whose only purpose is to trigger a decoder overload that populates it’s wrapped value with `nil` if the respective key is not found. The nice thing about this is that you no longer have ambiguity by default (that an optional property can be decoded from null or from an omitted key/value).

[EDIT] I am not talking about overriding `init(from: Decoder)`

---

<div class="post-metadata">

**Author:** ![GetSwifty](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/getswifty/32/39108_2.png) [@GetSwifty](https://forums.swift.org/u/GetSwifty)\
**Post date:** [October 30, 2019, 9:41pm UTC](https://forums.swift.org/t/pre-pitch-codable-customization-using-propertywrappers/30244/42 "2019-10-30T21:41:31Z")

</div>

> [@mattpolzin](#):
>
> a property wrapper like `@Omittable` whose only purpose is to trigger a decoder overload

Another property wrapper doesn't solve the feature by itself (See [@gwendal.roue's example](https://forums.swift.org/t/pre-pitch-codable-customization-using-propertywrappers/30244/29)). Changing `Decoder` would work, but a believe any change would require support be added to each individual decoder implementation. That would be a source breaking change which is not ideal. 😞

Since code generation is already being used for Codable conformance and Property Wrapper I don't see I reason why it can't be used to solve this problem as well.

---

<div class="post-metadata">

**Author:** ![mattpolzin](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/mattpolzin/32/6041_2.png) [@mattpolzin](https://forums.swift.org/u/mattpolzin)\
**Post date:** [October 30, 2019, 10:10pm UTC](https://forums.swift.org/t/pre-pitch-codable-customization-using-propertywrappers/30244/43 "2019-10-30T22:10:11Z")

</div>

I’ve implemented `@Omittable` before, it just was not of much use to me without property wrapper composition. The key bit of machinery is

```swift
public protocol OmittableType {
    static var nilValue: Self { get }
}

extension KeyedDecodingContainer {
    public func decode<T>(_ type: T.Type, forKey key: KeyedDecodingContainer<K>.Key) throws -> T where T : Decodable, T: OmittableType {
        return try decodeIfPresent(T.self, forKey: key) ?? T.nilValue
    }
}

```

The rest is contained within a very thin

```swift
@propertyWrapper
public struct Omittable<T>: OmittableType { ... }

```

---

<div class="post-metadata">

**Author:** ![gwendal.roue](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/gwendal.roue/32/13992_2.png) [@gwendal.roue](https://forums.swift.org/u/gwendal.roue)\
**Post date:** [October 31, 2019, 3:24am UTC](https://forums.swift.org/t/pre-pitch-codable-customization-using-propertywrappers/30244/44 "2019-10-31T03:24:12Z")

</div>

> [@mattpolzin](#):
>
> I’ve implemented `@Omittable` before, it just was not of much use to me without property wrapper composition.

TIL that code synthesized for Codable is as malleable as other pieces of code. Thanks!

I've rewritten my sample code above, with full support for missing values:

> **It works!**
>
> ```swift
> import Foundation
> 
> // A basic property wrapper
> @propertyWrapper struct Wrapped<T> {
> var wrappedValue: T
> }
> 
> // Make Wrapped support Decodable
> extension Wrapped: Decodable where T: Decodable {
> init(from decoder: Decoder) throws {
> let container = try decoder.singleValueContainer()
> wrappedValue = try container.decode(T.self)
> }
> }
> 
> // Make Wrapped support decoding nil and missing values
> protocol OmittableType {
> static var nilValue: Self { get }
> }
> extension Wrapped: OmittableType where T: ExpressibleByNilLiteral {
> static var nilValue: Self { .init(wrappedValue: nil)}
> }
> extension KeyedDecodingContainer {
> func decode<T>(_ type: T.Type, forKey key: KeyedDecodingContainer<K>.Key) throws -> T where T : Decodable, T: OmittableType {
> return try decodeIfPresent(T.self, forKey: key) ?? T.nilValue
> }
> }
> 
> // Setup
> let decoder = JSONDecoder()
> let jsonWithValue = #"{"property":"Hello"}"#.data(using: .utf8)!
> let jsonWithNull = #"{"property":null}"#.data(using: .utf8)!
> let jsonEmpty = #"{}"#.data(using: .utf8)!
> 
> // A regular decodable struct: full success
> struct Struct: Decodable {
> var property: String?
> }
> try! decoder.decode(Struct.self, from: jsonWithValue).property // "Hello"
> try! decoder.decode(Struct.self, from: jsonWithNull).property // nil
> try! decoder.decode(Struct.self, from: jsonEmpty).property // nil
> 
> // A decodable struct with wrapped property: full success
> struct WrappedStruct: Decodable {
> @Wrapped var property: String?
> }
> try! decoder.decode(WrappedStruct.self, from: jsonWithValue).property // "Hello"
> try! decoder.decode(WrappedStruct.self, from: jsonWithNull).property // nil
> try! decoder.decode(WrappedStruct.self, from: jsonEmpty).property // nil
> 
> ```

---

<div class="post-metadata">

**Author:** ![GetSwifty](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/getswifty/32/39108_2.png) [@GetSwifty](https://forums.swift.org/u/GetSwifty)\
**Post date:** [October 31, 2019, 3:25am UTC](https://forums.swift.org/t/pre-pitch-codable-customization-using-propertywrappers/30244/45 "2019-10-31T03:25:21Z")

</div>

> [@mattpolzin](#):
>
> ```swift
> public protocol OmittableType {
> static var nilValue: Self { get }
> }
> 
> extension KeyedDecodingContainer {
> public func decode<T>(_ type: T.Type, forKey key: KeyedDecodingContainer<K>.Key) throws -> T where T : Decodable, T: OmittableType {
> return try decodeIfPresent(T.self, forKey: key) ?? T.nilValue
> }
> }
> 
> ```

😲 That works! I didn't realize specialized functions diverted code from outside your own code...makes sense though. Thank you! I would still like a more "official" way to handle this, but this at least gives me the workaround I need!

---

<div class="post-metadata">

**Author:** ![Ilias\_Karim](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ilias_karim/32/2339_2.png) [@Ilias\_Karim](https://forums.swift.org/u/Ilias_Karim)\
**Post date:** [November 8, 2019, 3:45pm UTC](https://forums.swift.org/t/pre-pitch-codable-customization-using-propertywrappers/30244/46 "2019-11-08T15:45:36Z")

</div>

Looks like a nifty library only not sure we need a pitch to add it to Swift's.

---

<div class="post-metadata">

**Author:** ![andrewayres](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/andrewayres/32/6071_2.png) [@andrewayres](https://forums.swift.org/u/andrewayres)\
**Post date:** [November 14, 2019, 12:53pm UTC](https://forums.swift.org/t/pre-pitch-codable-customization-using-propertywrappers/30244/47 "2019-11-14T12:53:20Z")

</div>

This workaround - could it be used to wrap an optional Bool property, so that it's serialized in JSON as an Int (1=true, 0=false or null if nil or missing) and decoded as a Bool?

I have a case where an external API, over which I have no control, returns a property as a JSON number (1 or 0) meaning true or false, and I want to treat it as an optional Bool in my Codable Swift class (I'm using a class, not a struct, as I'm integrating Codable with CoreData classes).

In Kotlin, I achieved this very easily using GSON's @JsonAdapter annotation;

> data class MyDataClass (  
> @JsonAdapter(CustomTypeAdapterFactory::class) @SerializedName("my\_optional\_bool") val myOptionalBool: Boolean?  
> )

But I'm not sure of the best way to achieve this in Swift. I have a similar issue, where I need to encode a Date into a custom JSON format, that I would like to achieve in a similar way.

Customizing Codable with PropertyWrappers seems to me like the closest thing I've seen so far, but it would be good to get guidance on whether this is the case.

---

<div class="post-metadata">

**Author:** ![GetSwifty](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/getswifty/32/39108_2.png) [@GetSwifty](https://forums.swift.org/u/GetSwifty)\
**Post date:** [November 14, 2019, 5:39pm UTC](https://forums.swift.org/t/pre-pitch-codable-customization-using-propertywrappers/30244/48 "2019-11-14T17:39:26Z")

</div>

Yes, it should be possible. I'm planning on pushing the nullable wrappers this weekend to make it easier, but the non-null version would be something like this:

```swift
struct IntAsBoolStaticCoder: StaticCoder {

    static func decode(from decoder: Decoder) throws -> Bool {
        let intValue = try Int(from: decoder)
        return intValue > 0 ? true : false
    }

    static func encode(value: Bool, to encoder: Encoder) throws {
        (value ? 1 : 0).encode(to: encoder
    }
}

struct MyType: Codable {
    @CodingUses<IntAsBoolStaticCoder>
    var myBool: Bool
}

```

I'll add it as a custom example [here](https://github.com/GottaGetSwifty/CodableWrappers/blob/master/CustomExamples.md) as well when it's finished.

---

<div class="post-metadata">

**Author:** ![andrewayres](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/andrewayres/32/6071_2.png) [@andrewayres](https://forums.swift.org/u/andrewayres)\
**Post date:** [November 15, 2019, 9:10am UTC](https://forums.swift.org/t/pre-pitch-codable-customization-using-propertywrappers/30244/49 "2019-11-15T09:10:04Z")

</div>

Thanks for this. Your library is excellent, exactly the kind of thing I was looking for! I look forward to the update to nullable wrappers.

Another useful concept in my Kotlin-based data classes, that use Android's Room library, is the @Expose annotation - ie. that can be used for deciding which properties get serialized to JSON.

At the moment, I'm planning to handle this in Swift by omitting CodingKeys for the properties I don't want serialized (I understand this is currently the standard way to do this) - but I find this a bit ugly and non-intuitive. It seems to me it would be better handled by property wrappers, either by exposing or ignoring the property where it's declared, e.g.;

```swift
struct MyType: Codable {
    @CodingUses<IntAsBoolStaticCoder>
    var myBool: Bool
    @Ignore
    var myStringNotToBeSerialized: String
}

```

Whether this should be handled by a library like yours, or whether this should be doable in standard Swift as part of customizing Codable, I don't know - it's just something I'd like to be able to do, along with using a GSON-like @SerializedName 'annotation' instead of, again, defining it within the CodingKeys enum, although I understand a property can only have one property wrapper (?), so I guess it's not doable to use multiple property wrappers to achieve something like;

```swift
 struct MyType: Codable {
    @SerializedName("my_date") @SecondsSince1970DateCoding
    var myDate: Date
 }

```

---

<div class="post-metadata">

**Author:** ![CTMacUser](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ctmacuser/32/1802_2.png) [@CTMacUser](https://forums.swift.org/u/CTMacUser)\
**Post date:** [November 15, 2019, 9:24pm UTC](https://forums.swift.org/t/pre-pitch-codable-customization-using-propertywrappers/30244/50 "2019-11-15T21:24:18Z")

</div>

> [@GetSwifty](#):
>
> I'll add it as a custom example [here](https://github.com/GottaGetSwifty/CodableWrappers/blob/master/CustomExamples.md) as well when it's finished.

Should it be more generalized:

```
struct IntegerAsBoolStaticCoder<Integer: BinaryInteger & Codable>: StaticCoder {

    static func decode(from decoder: Decoder) throws -> Bool {
        let intValue = try Integer(from: decoder)
        return intValue != 0
    }

    static func encode(value: Bool, to encoder: Encoder) throws {
        try Integer(value ? 1 : 0).encode(to: encoder)
    }

}

```

> [@andrewayres](#):
>
> Whether this should be handled by a library like yours, or whether this should be doable in standard Swift as part of customizing Codable, I don't know - it's just something I'd like to be able to do, along with using a GSON-like @SerializedName 'annotation' instead of, again, defining it within the CodingKeys enum, although I understand a property can only have one property wrapper (?), so I guess it's not doable to use multiple property wrappers to achieve something like;
> 
> ```
> struct MyType: Codable {
> @SerializedName("my_date") @SecondsSince1970DateCoding
> var myDate: Date
> }
> 
> ```

I wonder if it's possible for a property wrapper to have a generic parameter for another PW so the outer one channels both. Hmm, but how would initializations work (if the inner one needs to)?

---

<div class="post-metadata">

**Author:** ![GetSwifty](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/getswifty/32/39108_2.png) [@GetSwifty](https://forums.swift.org/u/GetSwifty)\
**Post date:** [November 15, 2019, 9:41pm UTC](https://forums.swift.org/t/pre-pitch-codable-customization-using-propertywrappers/30244/51 "2019-11-15T21:41:31Z")

</div>

Thanks for encouragement!

> [@CTMacUser](#):
>
> I wonder if it's possible for a property wrapper to have a generic parameter for another PW so the outer one channels both. Hmm, but how would initializations work (if the inner one needs to)?

That's what composition is supposed to handle ([see proposal](https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md)) but as it's missing from Swift 5.1 even though the proposal says "implemented", I'm unsure when/if that's coming.

---

<div class="post-metadata">

**Author:** ![Morten\_Bek\_Ditlevsen](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/morten_bek_ditlevsen/32/28133_2.png) [@Morten\_Bek\_Ditlevsen](https://forums.swift.org/u/Morten_Bek_Ditlevsen)\
**Post date:** [November 16, 2019, 8:48am UTC](https://forums.swift.org/t/pre-pitch-codable-customization-using-propertywrappers/30244/52 "2019-11-16T08:48:57Z")

</div>

Property wrapper composition is available on the master branch tool chain. 😊

---

<div class="post-metadata">

**Author:** ![GetSwifty](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/getswifty/32/39108_2.png) [@GetSwifty](https://forums.swift.org/u/GetSwifty)\
**Post date:** [November 18, 2019, 5:20am UTC](https://forums.swift.org/t/pre-pitch-codable-customization-using-propertywrappers/30244/53 "2019-11-18T05:20:18Z")

</div>

> [@Morten\_Bek\_Ditlevsen](#):
>
> Property wrapper composition is available on the master branch tool chain. 😊

Niiice! Hopefully a release with it will happen soon 🙂

---

<div class="post-metadata">

**Author:** ![GetSwifty](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/getswifty/32/39108_2.png) [@GetSwifty](https://forums.swift.org/u/GetSwifty)\
**Post date:** [November 18, 2019, 6:44am UTC](https://forums.swift.org/t/pre-pitch-codable-customization-using-propertywrappers/30244/54 "2019-11-18T06:44:27Z")

</div>

> [@andrewayres](#):
>
> ```swift
> struct MyType: Codable {
> @CodingUses<IntAsBoolStaticCoder>
> var myBool: Bool
> @Ignore
> var myStringNotToBeSerialized: String
> }
> 
> ```

@andrewayres I've now released [v1.1.0](https://github.com/GottaGetSwifty/CodableWrappers/releases/tag/1.1.0).

With this we can now easily implement your use case (also tested it as a class just to make sure)

```swift
struct IntAsBoolStaticCoder: StaticCoder {

    static func decode(from decoder: Decoder) throws -> Bool {
        let intValue = try Int(from: decoder)
        return intValue > 0 ? true : false
    }

    static func encode(value: Bool, to encoder: Encoder) throws {
        try (value ? 1 : 0).encode(to: encoder)
    }
}

typealias IntAsBoolOptionalCoding = CodingUses<OptionalStaticCoder<IntAsBoolStaticCoder>>

struct MyType: Codable {
    @IntAsBoolOptionalCoding
    var myBool: Bool?
    @OmitCoding
    var myStringNotToBeSerialized: String?
}

```

I'm also thinking it makes sense to add some similar Bool wrappers next time I get chance.

---

<div class="post-metadata">

**Author:** ![andrewayres](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/andrewayres/32/6071_2.png) [@andrewayres](https://forums.swift.org/u/andrewayres)\
**Post date:** [November 19, 2019, 11:46am UTC](https://forums.swift.org/t/pre-pitch-codable-customization-using-propertywrappers/30244/55 "2019-11-19T11:46:43Z")

</div>

@GetSwifty - That's awesome! Thanks for releasing v.1.1.0, including @OmitCoding, and testing with a class too.

---

<div class="post-metadata">

**Author:** ![andrewayres](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/andrewayres/32/6071_2.png) [@andrewayres](https://forums.swift.org/u/andrewayres)\
**Post date:** [November 19, 2019, 2:59pm UTC](https://forums.swift.org/t/pre-pitch-codable-customization-using-propertywrappers/30244/56 "2019-11-19T14:59:19Z")

</div>

However, I've run into an issue with CoreData class properties that use the `@NSManaged` attribute

```swift
public class MyCoreDataClass: NSManagedObject {   
    ...
    @NSManaged public var myString: String?
}

```

Trying to add a Property Wrapper (either before or after @NSManaged), e.g.;

`@OmitCoding @NSManaged public var myString: String?`  
or  
`@NSManaged @OmitCoding public var myString: String?`

results in the Xcode error;

> Property 'myString' with a wrapper cannot also be @NSManaged.

I'm currently looking for a workaround to this.

---

<div class="post-metadata">

**Author:** ![GetSwifty](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/getswifty/32/39108_2.png) [@GetSwifty](https://forums.swift.org/u/GetSwifty)\
**Post date:** [November 19, 2019, 4:08pm UTC](https://forums.swift.org/t/pre-pitch-codable-customization-using-propertywrappers/30244/57 "2019-11-19T16:08:01Z")

</div>

> [@andrewayres](#):
>
> Property 'myString' with a wrapper cannot also be @NSManaged.

That's not too surprising. There are a lot of Swift features that don't work well with Core Data. That's why I tend to use separate models for the Codable part of a codebase.

---

<div class="post-metadata">

**Author:** ![rnantes](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/rnantes/32/5653_2.png) [@rnantes](https://forums.swift.org/u/rnantes)\
**Post date:** [December 2, 2019, 6:49pm UTC](https://forums.swift.org/t/pre-pitch-codable-customization-using-propertywrappers/30244/58 "2019-12-02T18:49:00Z")

</div>

@GetSwifty have you looked further into the `@CodingKey("first-name")` syntax? I'd be interested in this for decoding JSON that does not exactly match my codable struct.

Additionally, though this is more out of your proposal's realm, it would be interesting if we could define multiple decoding strategies so that we could decode our objects from different JSON sources for example. My use case is I have one model that I'd like to decode from some seed data and then decode the same model from a different api.

---

<div class="post-metadata">

**Author:** ![GetSwifty](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/getswifty/32/39108_2.png) [@GetSwifty](https://forums.swift.org/u/GetSwifty)\
**Post date:** [December 2, 2019, 7:55pm UTC](https://forums.swift.org/t/pre-pitch-codable-customization-using-propertywrappers/30244/59 "2019-12-02T19:55:30Z")

</div>

I don't believe it's currently possible to use a PropertyWrapper and get that syntax. What I'm currently working on is trying to find a way to do this generically, e.g. `@SnakeCaseCodingKey`, and a `@FlattenCoding` wrapper that encodes to the previous level. I've made a bit of progress but I'm not sure if it's possible, it's certainly not straightforward or intended to be possible. 😬

> [@rnantes](#):
>
> decode from some seed data and then decode the same model from a different api.

What's the primary difference in how you want to seed vs store the data? It would be hard to do this generically, but specific differences seem possible.

---

<div class="post-metadata">

**Author:** ![rnantes](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/rnantes/32/5653_2.png) [@rnantes](https://forums.swift.org/u/rnantes)\
**Post date:** [December 2, 2019, 8:12pm UTC](https://forums.swift.org/t/pre-pitch-codable-customization-using-propertywrappers/30244/60 "2019-12-02T20:12:12Z")

</div>

@GetSwifty the difference between the two is that one is using older JSON data that doesn't match my model. For example the seed data is like this:

```nohighlight
{
    name: "New York City"
    state_id: 5
}

```

VS the api

```nohighlight
{
    name: "New York City"
    parent_id: 5
}

```

It would be nice if I could easily say for my model's property `parentID` decode from `"state_id"` or `"parent_id"`. Or at least somehow define a decoding strategy `SeedDecodingStrategy` and `APIDecodingStrategy` and do something like

```nohighlight
let decoder = JSONDecoder()
decoder.decode(City.self, from: mySeedData, using: City.SeedDecodingStrategy)

```

Just a thought though

[Previous page](https://forums.swift.org/t/pre-pitch-codable-customization-using-propertywrappers/30244.md?page=2)

[Next page](https://forums.swift.org/t/pre-pitch-codable-customization-using-propertywrappers/30244.md?page=4)
