# Extract Payload for enum cases having associated value

**URL:** <https://forums.swift.org/t/extract-payload-for-enum-cases-having-associated-value/27606>\
**Category:** Pitches\
**Tags:** enums, associatedvalue\
**Created:** [August 4, 2019, 4:16pm UTC](https://forums.swift.org/t/extract-payload-for-enum-cases-having-associated-value/27606 "2019-08-04T16:16:24Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![GLanza](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/glanza/32/3827_2.png) [@GLanza](https://forums.swift.org/u/GLanza)\
**Post date:** [August 4, 2019, 4:16pm UTC](https://forums.swift.org/t/extract-payload-for-enum-cases-having-associated-value/27606/1 "2019-08-04T16:16:25Z")

</div>

This is a long requested feature that never saw the light. We have memories of other proposals pitched with [Automatically derive properties for enum cases](https://forums.swift.org/t/automatically-derive-properties-for-enum-cases/10843) and before with [Pitch: Even Smarter KeyPaths? - #2 by Joe\_Groff](https://forums.swift.org/t/pitch-even-smarter-keypaths/5923/2) from @stephencelis

How to access an associated value of an enum case is a very recurring question on stackOverflow:

> <https://stackoverflow.com/questions/24263539/accessing-an-enumeration-association-value-in-swift>

> <https://stackoverflow.com/questions/47659168/swift-get-associated-value-in-enums-without-switch/47659303#47659303>

> <https://stackoverflow.com/questions/31359142/how-to-access-a-swift-enum-associated-value-outside-of-a-switch-statement/32154586#32154586>

Also on this forum the question appeared with a specific and more than valid use case by @zoul :

> [@Accessing the associated value of an enum](https://forums.swift.org/t/accessing-the-associated-value-of-an-enum/11717):
>
> I have an enum like this: enum AppModel { case loading case onboarding(OnboardingModel) case signedOut(SignInModel) } Now I have a Signal\<AppModel\> (CwlSignal in this case, but I don’t think it matters). The signal supports the usual map method that takes (A) -\> B and turns a Signal\<A\> to Signal\<B\>. To create an “onboarding signal”, I currently use this: let subSignal = appSignal.map { (appModel: AppModel) -\> OnboardingModel? in guard case let .onboarding(model) = appModel els…

With the arrival of Combine I feel it's the right moment to pitch the proposal again, offering a different approach than the already proposed synthesised vars and smarter KeyPaths.

I personally liked what was alternatively proposed [in this answer](https://forums.swift.org/t/automatically-derive-properties-for-enum-cases/10843/49) from the previously mentioned pitch, I in fact used this approach in my reactive framework [MERLin](https://github.com/gringoireDM/MERLin/blob/master/MERLin/MERLin/Events/EventProtocol.swift) to define an [Event](https://github.com/gringoireDM/MERLin/wiki/Events) as enum and extract its associated value (if any) in a stream of events.

This allows me to do something like

```swift
// Given an Event Type
enum HomeEvent {
    case loaded
    case selectedProduct(Product)
    case favoritedProduct(Product)
}

// And an Observable of events
let homeEvent: Observable<HomeEvent> { return _homeEvent.asObservable() }
let _homeEvent = PublishSubject<HomeEvent>()

...
func didSelect(item: Int) {
    let product = products[item]
    _homeEvent.onNext(.selectedProduct(product))
}
...

```

Observing the occurrences of an event would be as simple as

```swift
homeEvent
    .capture(event: HomeEvent.selectedProduct) // custom operator using `associatedValue(matching:)` 
    .subscribe(onNext: { product in //product is of type Product
        ...
    }.disposed(by: disposeBag) 
// While this is RxSwift, this use case applies to any reactive framework
// including Combine

```

In MERLin I use `Mirror` to extract the payload of any enum conforming `EventProtocol`.

I believe that similarly to `CaseIterable`, these functionalities should be accessible on conformance to a protocol.

# CaseAccessible

```swift
public protocol CaseAccessible {
    var label: String { get }
    
    func associatedValue<AssociatedValue>(mathing pattern: (AssociatedValue) -> Self) -> AssociatedValue?
    
    mutating func update<AssociatedValue>(value: AssociatedValue, matching pattern: (AssociatedValue) -> Self)
}

```

Just like it happen for `CaseIterable`, a default implementation of these functions should be synthesised by the compiler for enums with at least one case having `associatedValue`.

It is currently possible to try this solution in a playground using Mirroring:

```swift
public extension CaseAccessible {
    var label: String {
        return Mirror(reflecting: self).children.first?.label ?? String(describing: self)
    }
        
    func associatedValue<AssociatedValue>(mathing pattern: (AssociatedValue) -> Self) -> AssociatedValue? {
        guard let decomposed: (String, AssociatedValue) = decompose(),
            let patternLabel = Mirror(reflecting: pattern(decomposed.1)).children.first?.label,
            decomposed.0 == patternLabel else { return nil }
        
        return decomposed.1
    }
    
    mutating func update<AssociatedValue>(value: AssociatedValue, matching pattern: (AssociatedValue) -> Self) {
        guard associatedValue(mathing: pattern) != nil else { return }
        self = pattern(value)
    }
    
    private func decompose<AssociatedValue>() -> (label: String, value: AssociatedValue)? {
        for case let (label?, value) in Mirror(reflecting: self).children {
            if let result = (value as? AssociatedValue) ?? (Mirror(reflecting: value).children.first?.value as? AssociatedValue) {
                return (label, result)
            }
        }
        return nil
    }
    
    subscript<AssociatedValue>(case pattern: (AssociatedValue) -> Self) -> AssociatedValue? {
        get {
            return associatedValue(mathing: pattern)
        } set {
            guard let value = newValue else { return }
            update(value: value, matching: pattern)
        }
    }

    subscript<AssociatedValue>(case pattern: (AssociatedValue) -> Self, default value: AssociatedValue) -> AssociatedValue {
        get {
            return associatedValue(mathing: pattern) ?? value
        } set {
            update(value: newValue, matching: pattern)
        }
    }

}

```

Overloading cases are currently correctly handled by the compiler that gives an error asking for more context, if needed.

```swift
enum Foo: CaseAccessible {
    case bar(int: Int)
    case bar(str: String)
}

let baz = Foo.bar(int: 10)
let value = baz.associatedValue(matching: Foo.bar) // ERROR: Ambiguous use of 'bar'
let value: String? = baz.associatedValue(matching: Foo.bar) // nil
let value: Int? = baz.associatedValue(matching: Foo.bar) // Optional(10)

// or with subscripts

let value: Int? = baz[case: Foo.bar] // Optional(10)
let value: Int = baz[case: Foo.bar, default: 0] // 10

```

The compiler presently works well also when the overloaded case has same type

```swift
enum Foo: CaseAccessible {
    case bar(int: Int)
    case bar(int2: Int)
}

let baz = Foo.bar(int: 10)
let value = baz.associatedValue(matching: Foo.bar) // ERROR: Ambiguous use of 'bar'
let value: String? = baz.associatedValue(matching: Foo.bar) // ERROR: Cannot invoke 'associatedValue' with an argument list of type '(matching: _)' (because there is no bar having a String as payload
let value = baz.associatedValue(matching: Foo.bar(int:)) // Optional(10)
let value = baz[case: Foo.bar(int:)] // Optional(10)
let value = baz[case: Foo.bar(int:), default: 0] // 10

```

Working with array or observables of enums then becomes really simple

```swift
enum Foo: CaseAccessible {
    case bar(String)
    case baz(String)
    case bla(Int)
}

let events: [Foo] = [
    .bar("David"),
    .baz("Freddy"),
    .bar("Bowie"),
    .baz("Mercury"),
    .bla(10)
]

```

Then to compactMap through associated values is as simple as

```swift
let davidBowie = events
    .compactMap { $0[case: Foo.bar] }
    .joined(separator: " ") //"David Bowie"

let freddyMercury = events
    .compactMap { $0[case: Foo.baz] }
    .joined(separator: " ") //"Freddy Mercury"

```

Today this is already possible with pattern matching, but readability is not the best

```swift
let davidBowie = events
    .compactMap { 
        guard case let .bar(value) = $0 else { return nil }
        return value
    }
    .joined(separator: " ") //"David Bowie"

let freddyMercury = events
    .compactMap { 
        guard case let .baz(value) = $0 else { return nil }
        return value
    }
    .joined(separator: " ") //"Freddy Mercury"

```

# Mutability

`CaseAccessible` has also an update function that will update the associated value of an enum case, if the pattern is matching

```swift
enum State: CaseAccessible {
    case count(Int)
    case error(String)
}

var currentState: State

currentState.update(value: 10, case: State.count)
// or by using subscripts
currentState[case: State.count] = 10
currentState[case: State.count, default: 0] += 1

```

# Extensions

`CaseAccessible` would open the way to new extensions for Collection, Observable (RxSwift), Signal (ReactiveSwift) and AnyPublisher (Combine) for filtering and mapping:

```swift
extension Collection where Element: CaseAccessible {
    func filter<AssociatedValue>(case pattern: (AssociatedValue) -> Element) -> [Element] {
        return filter {
            $0[case: pattern] != nil
        }
    }
    
    func compactMap<AssociatedValue>(case pattern: (AssociatedValue) -> Element) -> [AssociatedValue] {
        return compactMap { $0[case: pattern] }
    }
    
    func exclude<AssociatedValue>(case pattern: (AssociatedValue) -> Element) -> [Element] {
        return filter {
            $0[case: pattern] == nil
        }
    }
}

enum ProductDetailEvent: CaseAccessible {
    case loaded(Product)
    ...
}

let events: [ProductDetailEvent] = ...

let selectedEvent = events.filter(case: ProductDetailEvent.loaded) // [ProductDetailEvent]
let loadedProducts = events.compactMap(case: ProductDetailEvent.loaded) // [Product]

```

What does the swift community think?

---

<div class="post-metadata">

**Author:** ![Nevin](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nevin/32/617_2.png) [@Nevin](https://forums.swift.org/u/Nevin)\
**Post date:** [August 4, 2019, 4:19pm UTC](https://forums.swift.org/t/extract-payload-for-enum-cases-having-associated-value/27606/2 "2019-08-04T16:19:44Z")

</div>

Could you please provide a summary of exactly what you intend for the compiler to synthesize, preferably with examples showing how we can achieve the same thing manually?

---

<div class="post-metadata">

**Author:** ![GLanza](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/glanza/32/3827_2.png) [@GLanza](https://forums.swift.org/u/GLanza)\
**Post date:** [August 4, 2019, 4:21pm UTC](https://forums.swift.org/t/extract-payload-for-enum-cases-having-associated-value/27606/3 "2019-08-04T16:21:43Z")

</div>

> [@Nevin](#):
>
> Could you please provide a summary of exactly what you intend for the compiler to synthesize, preferably with examples showing how we can achieve the same thing manually?

You can copy paste in a Playground my `EventProtocol` example in the post, and make your enum conform `EventProtocol`

---

<div class="post-metadata">

**Author:** ![Nevin](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nevin/32/617_2.png) [@Nevin](https://forums.swift.org/u/Nevin)\
**Post date:** [August 4, 2019, 5:47pm UTC](https://forums.swift.org/t/extract-payload-for-enum-cases-having-associated-value/27606/4 "2019-08-04T17:47:24Z")

</div>

I repeat my question.

---

<div class="post-metadata">

**Author:** ![GLanza](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/glanza/32/3827_2.png) [@GLanza](https://forums.swift.org/u/GLanza)\
**Post date:** [August 4, 2019, 7:12pm UTC](https://forums.swift.org/t/extract-payload-for-enum-cases-having-associated-value/27606/5 "2019-08-04T19:12:09Z")

</div>

> [@Nevin](#):
>
> Could you please provide a summary of exactly what you intend for the compiler to synthesize

`CaseIterable`, `Codable`, `PropertyWrapper`: There is "compiler magic" behind these features for you not to write code and have certain behaviours for free, if you comply to certain constraints.

`CaseIterable`: enum with purely sum types cases, otherwise you'll have to write which are "allCases"  
`Codable`: all the variables must be Codable, otherwise you'll have to conform the CodableProtocol yourself

For these functions I'm proposing, all enums having at least one case with associated values will have them.

> [@Nevin](#):
>
> preferably with examples showing how we can achieve the same thing manually

You can copy paste in a Playground my `EventProtocol` example in the post, and make your enum conform `EventProtocol`

```swift
public protocol EventProtocol {}

public extension EventProtocol {
    var label: String {
        return Mirror(reflecting: self).children.first?.label ?? String(describing: self)
    }
    
    func extractPayload<Payload>() -> Payload? {
        return decompose()?.payload
    }
    
    func extractPayload<Payload>(ifMatches pattern: (Payload) -> Self) -> Payload? {
        guard let decomposed: (String, Payload) = decompose(),
            let patternLabel = Mirror(reflecting: pattern(decomposed.1)).children.first?.label,
            decomposed.0 == patternLabel else { return nil }
        
        return decomposed.1
    }
    
    private func decompose<Payload>() -> (label: String, payload: Payload)? {
        for case let (label?, value) in Mirror(reflecting: self).children {
            if let result = (value as? Payload) ?? (Mirror(reflecting: value).children.first?.value as? Payload) {
                return (label, result)
            }
        }
        return nil
    }
}

enum HomeEvent: EventProtocol {
    case loaded
    case selectedProduct(Product)
    case favoritedProduct(Product)
}

```

I hope I solved your doubts

---

<div class="post-metadata">

**Author:** ![Nevin](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nevin/32/617_2.png) [@Nevin](https://forums.swift.org/u/Nevin)\
**Post date:** [August 4, 2019, 7:50pm UTC](https://forums.swift.org/t/extract-payload-for-enum-cases-having-associated-value/27606/6 "2019-08-04T19:50:40Z")

</div>

I am asking you to provide an example, here in this thread where everyone can see it, that shows both what an enum looks like with all the functionality you want implemented manually, and what that same enum looks like with the feature you are proposing.

---

<div class="post-metadata">

**Author:** ![wadetregaskis](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/wadetregaskis/32/8494_2.png) [@wadetregaskis](https://forums.swift.org/u/wadetregaskis)\
**Post date:** [August 4, 2019, 9:35pm UTC](https://forums.swift.org/t/extract-payload-for-enum-cases-having-associated-value/27606/7 "2019-08-04T21:35:13Z")

</div>

At least some cases can already be accomplished today via e.g.:

```
let davidBowie = events
  .compactMap { if case .bar(let name) = $0 { return name } else { return nil } }
  .joined(separator: " ") //"David Bowie"

```

This pitch proposes a slightly more terse syntax the applies to such cases as:

```
let davidBowie = events
  .compactMap { $0.extractPayload(ifMatches: Foo.bar) }
  .joined(separator: " ") //"David Bowie"

```

Fixing the inability of Swift to match cases concisely - because case matching cannot be used outside of a full `if` or `switch` statement - would seemingly make the former even shorter again, and be a much broader win for the language.

For that scenario.

The other that this pitch is considering is to allow for extracting associated values ‘blindly’ based on type alone. My first instinct is that this might not be a good thing, actually. Swift seems to have made a fairly deliberate choice w.r.t. how its enums work - you’re _expected_ to work centric to the cases, and any associated values only make sense if taken in the context of their case. Otherwise, you might as well and logically probably should just have properties on the enum itself, e.g.:

```
enum Foo {
  case bar
  case baz
  case bla

  var stringValue: String?
  var intValue: Int?
}

```

Swift doesn’t support this today, of course, but maybe it’s a better alternative _iff_ language changes are necessary?

Though, are they?… today you already can add _computed_ properties to any enum - including in extensions - that will seemingly do what you want, e.g.:

```
enum Foo {
  case bar(String)
  case baz(String)
  case bla(Int)

  var artistName: String? {
    switch self {
      case .bar(let name): return name
      case .baz(let name): return name
      default: return nil
    }
  }
}

```

Would that not be cleaner & sufficient, since not every enum wants this functionality? That reads much better when you want to fetch across multiple cases, e.g.:

```
let davidBowie = events
  .compactMap { $0.artistName }
  .joined(separator: " ")

```

---

<div class="post-metadata">

**Author:** ![GLanza](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/glanza/32/3827_2.png) [@GLanza](https://forums.swift.org/u/GLanza)\
**Post date:** [August 5, 2019, 7:59am UTC](https://forums.swift.org/t/extract-payload-for-enum-cases-having-associated-value/27606/8 "2019-08-05T07:59:32Z")

</div>

> [@Nevin](#):
>
> I am asking you to provide an example, here in this thread where everyone can see it, that shows both what an enum looks like with all the functionality you want implemented manually, and what that same enum looks like with the feature you are proposing.

I apologise. I misunderstood the first time you asked me this.

Here is an example:

```swift

enum Foo {
    case baz(str: String)
    case baz(int: Int)
    case bla(int: Int)
    
    var label: String {
        return Mirror(reflecting: self).children.first?.label ?? String(describing: self)
    }
    
    func extractPayload<Payload>() -> Payload? {
        return decompose()?.payload
    }
    
    func extractPayload<Payload>(ifMatches pattern: (Payload) -> Foo) -> Payload? {
        guard let decomposed: (String, Payload) = decompose(),
            let patternLabel = Mirror(reflecting: pattern(decomposed.1)).children.first?.label,
            decomposed.0 == patternLabel else { return nil }
        
        return decomposed.1
    }
    
    private func decompose<Payload>() -> (label: String, payload: Payload)? {
        for case let (label?, value) in Mirror(reflecting: self).children {
            if let result = (value as? Payload) ?? (Mirror(reflecting: value).children.first?.value as? Payload) {
                return (label, result)
            }
        }
        return nil
    }
}

let intBaz = Foo.baz(int: 10)
let strBaz = Foo.baz(str: "baz")
let bla = Foo.bla(int: 20)

// indistinct extractPayload

let intBazValue: Int? = intBaz.extractPayload() // Optional(10)
let strBazValue: String? = strBaz.extractPayload() // Optional("baz")
let blaValue: Int? = bla.extractPayload() // Optional(20)

let all = [
    intBaz,
    strBaz,
    bla
]

let allStr: [String] = all.compactMap { $0.extractPayload() } // ["baz"]
let allInt: [Int] = all.compactMap { $0.extractPayload() } // [10, 20]

// pattern matching extraction

let intBazValue2 = intBaz.extractPayload(ifMatches: Foo.baz(int:)) //Optional(10)
let strBazValue2 = intBaz.extractPayload(ifMatches: Foo.baz(str:)) //Optional("baz")
let blaValue2 = bla.extractPayload(ifMatches: Foo.bla)// Optional(20)

let allRepeated = [
    intBaz,
    intBaz,
    intBaz,
    strBaz,
    strBaz,
    strBaz,
    bla
]

let allStrBaz = allRepeated.compactMap { $0.extractPayload(ifMatches: Foo.baz(str:)) } // ["baz", "baz", "baz"]
let allIntBaz: [Int] = allRepeated.compactMap { $0.extractPayload(ifMatches: Foo.baz(int:)) } // [10, 10, 10]

```

> [@wadetregaskis](#):
>
> The other that this pitch is considering is to allow for extracting associated values ‘blindly’ based on type alone. My first instinct is that this might not be a good thing, actually

There are use cases for this choice. Consider an enum in which each case associated value is representing the same thing.

```swift
enum ItemUnion {
    case featuredImageItem(Item)
    case featuredTextItem(Item)
    case newArrivalsItem(Item)
    case imageItem(Item)
    case productItem(Item)
    case textItem(Item)
    case designersItem(Item)
    case shopsItem(Item)
    case videoItem(Item)
    case textOnlyPromoItem(Item)
    case imageWithTitleItem(Item)
    case individualSaleItem(Item)
    case feedProductItem(Item)
}

```

In this use case, there are areas of the app that might be interested in knowing the exact case and cases that can deal with Any `Item` indistinctly, hence the unconditioned `extractPayload`

While we can argue that the union can have a computed var, or that the whole thing can be wrote in a different way, the point of this pitch is to support this feature natively without requiring to write computed vars ourselves, and without giving these computed vars automatically to who doesn't want them

---

<div class="post-metadata">

**Author:** ![stephencelis](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/stephencelis/32/2675_2.png) [@stephencelis](https://forums.swift.org/u/stephencelis)\
**Post date:** [August 5, 2019, 12:30pm UTC](https://forums.swift.org/t/extract-payload-for-enum-cases-having-associated-value/27606/9 "2019-08-05T12:30:36Z")

</div>

There are 2 important things to solve here:

1. Ergonomic access to associated values (ideally as ergonomic as struct field access).
2. Key path-like support for enum payloads.

Key paths have unlocked a ton of possibilities in library code, and we've seen a proliferation of their use even in Apple's latest Combine and SwiftUI frameworks, but enums are completely left behind because they don't have such a mechanism.

---

<div class="post-metadata">

**Author:** ![GLanza](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/glanza/32/3827_2.png) [@GLanza](https://forums.swift.org/u/GLanza)\
**Post date:** [August 5, 2019, 1:25pm UTC](https://forums.swift.org/t/extract-payload-for-enum-cases-having-associated-value/27606/10 "2019-08-05T13:25:40Z")

</div>

I honestly don't believe that keypaths are the way to handle this. That's the reason this proposal is different than the previous ones. If you match a specific pattern you get a tuple that you know how to handle. Today is already possible to extract a payload from an enum case, and I proved it in my code examples in my initial post. I believe we should just make it official. If one day keypaths will handle tuples, from this proposal enums will benefit as well

---

<div class="post-metadata">

**Author:** ![Karl](https://avatars.discourse-cdn.com/v4/letter/k/34f0e0/32.png) [@Karl](https://forums.swift.org/u/Karl)\
**Post date:** [August 5, 2019, 1:36pm UTC](https://forums.swift.org/t/extract-payload-for-enum-cases-having-associated-value/27606/11 "2019-08-05T13:36:30Z")

</div>

> [@GLanza](#):
>
> There are use cases for this choice. Consider an enum in which each case associated value is representing the same thing.
> 
> ```swift
> enum ItemUnion {
> case featuredImageItem(Item)
> case featuredTextItem(Item)
> case newArrivalsItem(Item)
> case imageItem(Item)
> case productItem(Item)
> case textItem(Item)
> case designersItem(Item)
> case shopsItem(Item)
> case videoItem(Item)
> case textOnlyPromoItem(Item)
> case imageWithTitleItem(Item)
> case individualSaleItem(Item)
> case feedProductItem(Item)
> }
> 
> ```
> 
> While we can argue that the union can have a computed var, or that the whole thing can be wrote in a different way, the point of this pitch is to support this feature natively without requiring to write computed vars ourselves, and without giving these computed vars automatically to who doesn't want them

OK, well then I disagree with the pitch. This should quite obviously be written in a different way.

```swift
struct TaggedItem {
  enum Kind {
    case featuredImage
    case featuredText
    //...
  }

  var kind: Kind
  var item: Item
}

```

An enum where all the payloads have the same type is better expressed as a struct, simple as that. Associated values for enums are most useful when different cases have different types. That makes it difficult to have a magic "extract payload" function; it doesn't fit the type system because the cases all have the same type (which is... you know, kind of the point of the enum in the first place).

This seems to me like you are writing the thing in the most awkward way possible, then complaining that it's awkward.

---

<div class="post-metadata">

**Author:** ![GLanza](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/glanza/32/3827_2.png) [@GLanza](https://forums.swift.org/u/GLanza)\
**Post date:** [August 5, 2019, 1:59pm UTC](https://forums.swift.org/t/extract-payload-for-enum-cases-having-associated-value/27606/12 "2019-08-05T13:59:30Z")

</div>

I'll not get in specific implementation details. There are cases where it is useful to get the payload if there is a pattern matching and cases where the pattern is not as important as the type. The pitch try to address both use cases. You can write anything without enums. To discard the whole proposal just for one use case that you don't like maybe it's too much, don't you think?

---

<div class="post-metadata">

**Author:** ![GLanza](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/glanza/32/3827_2.png) [@GLanza](https://forums.swift.org/u/GLanza)\
**Post date:** [August 5, 2019, 2:04pm UTC](https://forums.swift.org/t/extract-payload-for-enum-cases-having-associated-value/27606/13 "2019-08-05T14:04:25Z")

</div>

> [@Karl](#):
>
> This seems to me like you are writing the thing in the most awkward way possible, then complaining that it's awkward.

I'm not complaining about anything. There are at least three more use cases I described before that you cannot address easily with structs.

`extractPayload(ifMatches: )` is a more concise way to do

```swift
if case let .foo(payload) = yourCase { return payload }
else return nil

```

and the `extractPayload()` function is a better way to extract a payload than having to write a computed var in your enum to get the value of the payload in your enum cases

---

<div class="post-metadata">

**Author:** ![Karl](https://avatars.discourse-cdn.com/v4/letter/k/34f0e0/32.png) [@Karl](https://forums.swift.org/u/Karl)\
**Post date:** [August 5, 2019, 2:35pm UTC](https://forums.swift.org/t/extract-payload-for-enum-cases-having-associated-value/27606/14 "2019-08-05T14:35:24Z")

</div>

> [@GLanza](#):
>
> You can write anything without enums. To discard the whole proposal just for one use case that you don't like maybe it's too much, don't you think?

But a major part of enginering is to use the correct tool for the job. I don't feel that you're using enums properly in any of your examples.

Just blindly extracting a string from an enum payload, without knowing its case, is not a good way to model your problem. If you really want to treat them as independent pieces of data (which, again, is not really the proper use-case for enums), you should split them and make them truly independent. Note that you can still ensure tags and payloads have the correct corresponding types in your initialisers. For example:

```swift
struct Foo {
  enum Tag { case bar, baz }
  enum Payload { case string(String), integer(Int) }

  var tag: Tag
  var payload: Payload

  private init(_ tag: Tag, _ payload: Payload) { ... }
  public static func bar(_ payload: String) -> Foo { return Foo(.bar, .string(payload)) } 
  public static func baz(_ payload: Int) -> Foo { return Foo(.baz, .integer(payload)) } 
}

```

With a structure like this, you can easily extract either the tag or payload and handle them independently.

---

<div class="post-metadata">

**Author:** ![GLanza](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/glanza/32/3827_2.png) [@GLanza](https://forums.swift.org/u/GLanza)\
**Post date:** [August 5, 2019, 2:53pm UTC](https://forums.swift.org/t/extract-payload-for-enum-cases-having-associated-value/27606/15 "2019-08-05T14:53:15Z")

</div>

This are not sum types tough.

In my example of the `ItemUnion` I recognised that it could be wrote in a different way, but in the other examples, I believe that enums are a better way to describe events. Your `Foo` struct has many combinations of tag - Payload than the enum with associated value, and it is not self documenting at all.

```swift
struct Foo {
  enum Tag { case bar, baz }
  enum Payload { case string(String), integer(Int) }

  var tag: Tag
  var payload: Payload

  private init(_ tag: Tag, _ payload: Payload) { ... }
  public static func bar(_ payload: String) -> Foo { return Foo(.bar, .string(payload)) } 
  public static func baz(_ payload: Int) -> Foo { return Foo(.baz, .integer(payload)) } 
}

```

bar can have both `String` and `Int`, just like baz, while

```swift
enum Foo {
 case bar(Int)
 case baz(str: String)
 case baz(int: Int)
}

```

the combinations are limited to the ones defined in the enum. A switch can easily be exhaustive.  
Without counting the easiness to add a new case in the enum versus the counterpart using struct (add two cases, plus the static function. Last, but not least, with the struct you'll have to switch over the payload to get the value. the whole code gets much more verbose.

You are reasoning on enums limitations that I'm trying to overcome with this proposal. If you get `extractPayload` they do become the right tool for the job.

The main use case I would like to see this pass is this one:

```swift
enum HomeEvent: EventProtocol {
    case loaded
    case selectedProduct(Product)
    case favoritedProduct(Product)
}

let homeEvent: Observable<HomeEvent> { return _homeEvent.asObservable() }
let _homeEvent = PublishSubject<HomeEvent>()

...
func didSelect(item: Int) {
    let product = products[item]
    _homeEvent.onNext(.selectedProduct(product))
}
...

homeEvent
    .capture(event: HomeEvent.selectedProduct) // custom defined using `extractPayload(ifMatches:)`
    .subscribe(onNext: { product in //product is of type Product
        ...
    }.disposed(by: disposeBag) 
// While this is RxSwift, this use case applies to any reactive framework
// including Combine

```

---

<div class="post-metadata">

**Author:** ![stephencelis](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/stephencelis/32/2675_2.png) [@stephencelis](https://forums.swift.org/u/stephencelis)\
**Post date:** [August 5, 2019, 4:11pm UTC](https://forums.swift.org/t/extract-payload-for-enum-cases-having-associated-value/27606/16 "2019-08-05T16:11:29Z")

</div>

Key paths already handle tuples but your proposal would miss half of the story if tuples were returned: the "writable" mechanism of the key path would be completely missing. Key paths are compiler-generated code for handling getting and setting of sub-state on a value. It allows us to write powerful library code that can not only access data (as in Foundation's KVO), but _manipulate_ it (as in the Combine and SwiftUI frameworks, and many third party libraries).

Enums are currently completely left out of the key path story, even though they can contain sub-state: their associated values. This means it's currently impossible to write library code providing hooks to manipulating enums in a generic way. I think as long as we're talking about enum data access, we need to also consider data manipulation. So I think it's very important to consider the larger picture and include the discussion of a key path-like mechanism for enums.

---

<div class="post-metadata">

**Author:** ![GLanza](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/glanza/32/3827_2.png) [@GLanza](https://forums.swift.org/u/GLanza)\
**Post date:** [August 5, 2019, 4:19pm UTC](https://forums.swift.org/t/extract-payload-for-enum-cases-having-associated-value/27606/17 "2019-08-05T16:19:03Z")

</div>

@Karl, Consider the following example

```swift
enum ProductDetailEvent {
    case loaded(Product)
    case selectedSku(String, forProduct: Product)
    case changedSize(Size)
    case changedColor(Color)
}

```

with your approach of using a struct would become

```swift
struct ProductDetailEvent {
    enum Tag { case loaded, selectedSku, changedSize, changedColor }
    enum Payload { case product(Product), skuAndProduct(String, Product), size(Size, color(Color) }
    
    var tag: Tag
    var payload: Payload
    
    private init(_ tag: Tag, _ payload: Payload) { ... }
    public static func loaded(_ payload: Product) { ... }
    public static func selectedSku(String, forProduct: Product) { ... }
    public static func changedSize(_ size: Size) { ... }
    public static func changedColor(_ color: Color) { ... }
}

```

First you see how much work I had to do just to define `ProductDetailEvent`.

```swift
let event: ProductDetailEvent = .selectedSku("1234", product: Product())

guard case . selectedSku = event.tag, 
    case let . skuAndProduct(sky, product) = event.payload else { ... }
...

```

To access the payload I must do even more job than having to handle the enum the standard way.  
With this proposal

```swift
let event = ProductDetailEvent.selectedSku("1234", forProduct: Product())
let payload = event.extractPayload(ifMatches: ProductDetailEvent.selectedSku)

```

and you can move on.

You can use it stream of events, to filter an array, and even to write array extensions and in case of reactive frameworks to write new operators to filter events. (like I did with `capture(event:)`)

From the point of view of readability, within those 5 lines of the enum it's clear which events ProductDetail can emit, and what to expect as payload in those events. From the struct, not really and the matching is manual (see the guard in the example). `extractPayload` exploits the compiler to give precise and typeSafe extraction, where the compiler will stop from extracting payloads that are not possible given your cases. Mistakes are blocked by the compiler, the struct approach will just be error prone.

```swift
// with Struct
let event: ProductDetailEvent = .selectedSku("1234", product: Product())

guard case .selectedSku = event.tag, 
    case let .product(product) = event.payload else { ... }
 //Will compile but never work. it's a bug

//with enums
let payload: Product? = event.extractPayload(ifMatches: ProductDetailEvent.selectedSku)
//Will just not compile, and the compiler will also tell you why

```

---

<div class="post-metadata">

**Author:** ![GLanza](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/glanza/32/3827_2.png) [@GLanza](https://forums.swift.org/u/GLanza)\
**Post date:** [August 5, 2019, 4:22pm UTC](https://forums.swift.org/t/extract-payload-for-enum-cases-having-associated-value/27606/18 "2019-08-05T16:22:54Z")

</div>

> [@stephencelis](#):
>
> Key paths already handle tuples but your proposal would miss half of the story if tuples were returned: the "writable" mechanism of the key path would be completely missing. Key paths are compiler-generated code for handling getting and setting of sub-state on a value. It allows us to write powerful library code that can not only access data (as in Foundation's KVO), but _manipulate_ it (as in the Combine and SwiftUI frameworks, and many third party libraries).

But this is not the point of the proposal. I don't want enums to be writeable. I just want to access the payload, and this is all this proposal is about. This works well with tuples too. If you check on MERLin, these functions are 100% unit tested. they work with tuples, with optionals, with closures as associated types and with overloading cases. It is not my intention to manipulate enum instances, and in fact I think it would even be wrong.

---

<div class="post-metadata">

**Author:** ![stephencelis](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/stephencelis/32/2675_2.png) [@stephencelis](https://forums.swift.org/u/stephencelis)\
**Post date:** [August 5, 2019, 4:33pm UTC](https://forums.swift.org/t/extract-payload-for-enum-cases-having-associated-value/27606/19 "2019-08-05T16:33:04Z")

</div>

> [@GLanza](#):
>
> I don't want enums to be writeable. […] It is not my intention to manipulate enum instances, and in fact I think it would even be wrong.

Can you elaborate why you think it is wrong? Enums and structs are two sides of the same coin. Can you imagine if we couldn't manipulate struct data?

---

<div class="post-metadata">

**Author:** ![GLanza](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/glanza/32/3827_2.png) [@GLanza](https://forums.swift.org/u/GLanza)\
**Post date:** [August 5, 2019, 4:46pm UTC](https://forums.swift.org/t/extract-payload-for-enum-cases-having-associated-value/27606/20 "2019-08-05T16:46:31Z")

</div>

> [@stephencelis](#):
>
> Can you elaborate why you think it is wrong? Enums and structs are two sides of the same coin. Can you imagine if we couldn't manipulate struct data?

Enums are not same as structs, or they would have no reasons to exist. You just use them for different purposes. If you need to alter their value, maybe you need a struct.

Usually you use enums to define a state, an action, an event. Associated values of an enum should be strictly tied with the logic that actually generated the instance of the enum. Making it mutable would open the use of enums to side effects and unpredictability that you usually don't want if you decided to use an enum in the first place.

If you need a mutable payload, you just don't need an enum. I would prefer to stay on topic tough. We could discuss about this, but I feel like this is not the place. The proposal of having enum payload accessible via KeyPaths got rejected and I would prefer to discuss an eventual re-post in that Pitch topic. Here I'm proposing just to access the payload, using a more concise and flexible way than pattern matching in if and guards.

[Next page](https://forums.swift.org/t/extract-payload-for-enum-cases-having-associated-value/27606.md?page=2)
