1

How can I access an enum value for a specific case without having to implement an enum function for each case?

I'm thinking something like this:

enum Result<S, F> {

    case success(S)
    case failure(F)

}

let resultSuccess = Result<Int, String>.success(1)
let resultFailure = Result<Int, String>.failure("Error")

let error: String? = case let .failure(error) = resultFailure

Something like this would also be acceptable:

let error: String? = (case let .failure(error) = resultFailure) ? error : ""

Obviously this doesn't even compile, but that's the gist of what I want.

Is that possible?

EDIT: explaining why my question is not the same as Extract associated value of enum case into a tuple

It's very simple, that answer access the values inside the if statement, rather than as an Optional like in my question. To specify a little more, imagine I have to extract values from multiple enums, and maybe enums inside enums, for that I'd need nested if's, or guard's, but with guard I wouldn't be able to continue the flow, since it forces a return.

Rodrigo Ruiz
  • 4,248
  • 6
  • 43
  • 75
  • 1
    Possible duplicate of [Accessing an Enumeration association value in Swift](https://stackoverflow.com/questions/24263539/accessing-an-enumeration-association-value-in-swift) – Vojta Rujbr Aug 23 '17 at 22:00
  • 1
    I saw that one, but I don't think it's a duplicate, because that guy is trying to access the associated value regardless of the enum case, so there would be the type issue, which should not happen in my case, since I'm accepting an Optional. – Rodrigo Ruiz Aug 23 '17 at 22:14
  • Possible duplicate of [Extract associated value of enum case into a tuple](https://stackoverflow.com/questions/40416274/extract-associated-value-of-enum-case-into-a-tuple) –  Aug 23 '17 at 22:48
  • @VojtaRujbr 's link has an answer which was not accepted for that question but does answer the question posed above: https://stackoverflow.com/a/37159851/887210 –  Aug 23 '17 at 22:58

3 Answers3

1

Add two computed properties for success case and failure case respectively.

enum Result<S, F> {
  case success(S)
  case failure(F)

  var successValue: S? {
    switch self {
    case .success(let value):
      return value
    case .failure:
      return nil
    }
  }

  var failureValue: F? {
    switch self {
    case .failure(let value):
      return value
    case .success:
      return nil
    }
  }
}


let resultSuccess = Result<Int, String>.success(1)
let resultFailure = Result<Int, String>.failure("Error")

if let error = resultFailure.failureValue {
  // do something
  print(error)
}
  • Yep, that works, but as I said before, this will force me to implement that same logic for every enum and every case with a value. – Rodrigo Ruiz Aug 24 '17 at 13:24
0

I'm afraid this is the most you can get:

    let error: String?
    if case .failure(let e) = resultFailure {error = e}
Vojta Rujbr
  • 325
  • 3
  • 11
  • That makes my error variable not be initialized, so I'd either have to add the `else` clause, or make my error a `var` instead of `let` which is also bad. – Rodrigo Ruiz Aug 23 '17 at 22:46
  • Check this: [SE-0043](https://github.com/apple/swift-evolution/blob/master/proposals/0043-declare-variables-in-case-labels-with-multiple-patterns.md) In "Alternatives considered" part there is a proposal of something like this: `let error: String? = (resultFailure case? Result.failure)` – Vojta Rujbr Aug 30 '17 at 06:32
0

This technique from the question "Accessing an Enumeration association value in Swift" will do it:

enum Result<S, F> {
  case success(S)
  case failure(F)
}

let resultFailure = Result<Int, String>.failure("Error")

var error: String?

if case let Result.failure(value) = resultFailure {
  error = value
}

print(error) // Optional("Error")

This will also work in place of the "if case let =" construct:

switch resultFailure {
case let Result.failure(value): error = value
default                       : error = nil
}

Here you go, 1 line and uses let:

let error: String? = { if case let .failure(value) = resultFailure { return value }; return nil }()
  • Yes, with `var` it works, but this is definitely not what I'm looking for, first because it uses 4 lines instead of 1, second, it uses `var`. – Rodrigo Ruiz Aug 23 '17 at 23:17
  • What's wrong with `var` and why are you limiting it to 1 line? These seem like awfully arbitrary reasons to not use this technique. –  Aug 23 '17 at 23:21
  • Because `var` makes it mutable and we know from FP that mutable stuff makes our lives harder. As for limiting to 1 line, I want my code to be declarative and simple, rather than having to specify steps like assigning to the error variable. – Rodrigo Ruiz Aug 23 '17 at 23:42
  • There are good practices and then there are real-world solutions. Yes, immutability and conciseness are great goals but if they get in the way of a solution then compromises must be made. To get rid of `var` you could always re-assign to a immutable variable or do a closure as I added to my answer. –  Aug 23 '17 at 23:48
  • Yeah, I thought of that last solution, and thank you for answering, but obviously that's not what I was looking for =). – Rodrigo Ruiz Aug 24 '17 at 00:35