Access enum associated value as optional - swift

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.

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)
}

I'm afraid this is the most you can get:
let error: String?
if case .failure(let e) = resultFailure {error = e}

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 }()

Related

Accessing Associated Values in an Array of Swift Enum in an Opaque Fashion

I haven't really found what I need in the associated questions. That may be because I'm a bit thick, and didn't see it, but here's my quandary:
I have a computed property that returns an Array of enums with associated values.
The values are all the same types (in my use case, the type is a "flag"), but the enums are different.
I'd like to see if there was some way to cycle through the Array, looking at only the associated values, regardless of the enum type. I am attaching a small playground that shows what I mean:
enum A {
case valueA(Int)
case valueB(Int)
case valueC(Int)
}
let a: [A] = [.valueA(0), .valueB(1), .valueC(2)]
for each in a {
print(String(describing: each))
}
print();
// This works:
for each in a {
if case let .valueA(value) = each {
print(value)
}
if case let .valueB(value) = each {
print(value)
}
if case let .valueC(value) = each {
print(value)
}
}
print();
// So does this:
for each in a {
var value: Int = 0
switch each {
case .valueA(let val):
value = val
case .valueB(let val):
value = val
case .valueC(let val):
value = val
}
print(value)
}
// What I want:
//for each in a {
// if case let A(value) = each {
// print(value)
// }
//}
I want to be able to treat each member of the collection, and extract its flag, and then make a decision, based on that flag.
I know that I could do it with a big ol' switch statement, with all the enum values (second go), but it would be nice if there were some generic way to just access all the values.
You would still have to test against the each case, but you could do
enum A {
case valueA(Int)
case valueB(Int)
case valueC(Int)
}
let a: [A] = [.valueA(0), .valueB(1), .valueC(2)]
for each in a {
switch each {
case .valueA(let val), .valueB(let val), .valueC(let val):
print(val)
}
}
This would still apply if you have cases with associated values of different types:
enum Cases {
case one(Int)
case two(Int)
case three(Int, String)
case four(String)
case five(String)
}
let testArray = [Cases.one(1), .two(2), .three(3, "three"),
.four("four"), .five("five")]
// Matching associated Ints
for value in testArray {
switch value {
case .one(let intVal), .two(let intVal), .three(let intVal, _):
print(intVal)
case .four(let strVal), .five(let strVal):
print(strVal)
}
}
// Matching associated Strings
for value in testArray {
switch value {
case .one(let intVal), .two(let intVal):
print(intVal)
case .three(_, let strVal), .four(let strVal), .five(let strVal):
print(strVal)
}
}
// Matching any type, cast to Any
for value in testArray {
switch value {
case .one(let anyVal as Any), .five(let anyVal as Any):
print(anyVal)
default:
continue // skipping these cases
}
}
The important takeaway is that you are binding the same var names in every statement whose value you are trying to match, meaning you can't match values that aren't available in ever statement:
switch ... {
// This won't work, because myInt is not defined in case .two
// and myOtherInt isn't defined in case .one
case .one(let myInt), .two(let myOtherInt):
...
}
To add to #Kiril's answer, if you wanted computed values for cases with different types of associated values, you can define optional computed vars to return those values:
extension Cases {
var intValue: Int? {
switch self {
case .one(let myInt), .two(let myInt), .three(let myInt, _):
return myInt
default:
return nil
}
}
var strValue: String? {
switch self {
case .three(_, let myStr), .four(let myStr), .five(let myStr):
return myStr
default:
return nil
}
}
}
I'd suggest a slight modification on your enum:
enum A {
case valueA(Int)
case valueB(Int)
case valueC(Int)
var flag: Int {
switch self {
case .valueA(let flag),
.valueB(let flag),
.valueC(let flag):
return flag
}
}
}
That makes any loop that just needs a flag trivial:
for each in a {
print(each.flag)
}

Enumeration on enums with associated values - Swift

I have an enum with associated values. In addition, every value has a String description. How can I get description of all the cases?
enum MyEnum {
case caseA(data: [DataOfTypeA])
case caseB(data: [DataOfTypeB])
case caseC(data: [DataOfTypeC])
case caseD(data: [DataOfTypeD])
var typeDescription: String {
switch self {
case .caseA:
return "caseA"
case .caseB:
return "caseB"
case .caseC:
return "caseC"
case .caseD:
return "caseD"
}
}
}
The thing I am looking for is:
"caseA, caseB, caseC, caseD"
You can make your enum conform to CaseIterable, then simply iterate through allCases to create typeDescription.
enum MyEnum: CaseIterable {
case caseA(data: [Int])
case caseB(data: [String])
case caseC(data: [Date])
case caseD(data: [Data])
static var allCases: [MyEnum] = [.caseA(data: []), .caseB(data: []), .caseC(data: []), .caseD(data: [])]
var caseDescription: String {
switch self {
case .caseA:
return "caseA"
case .caseB:
return "caseB"
case .caseC:
return "caseC"
case .caseD:
return "caseD"
}
}
static var typeDescription: String {
return allCases.map {$0.caseDescription}.joined(separator: ", ")
}
}
Imagine you have this variable:
let myEnum = MyEnum.caseA(data: [])
for accessing associated values:
switch myEnum {
case .caseA(let data): print(data)
case .caseB(let data): print(data)
case .caseC(let data): print(data)
case .caseD(let data): print(data)
}
for accessing typeDescription:
print(myEnum.typeDescription)
Or for any case without having a variable:
print(MyEnum.caseA(data: []).typeDescription)

How to write an extension for Result Enum

I have represented the results of my API requests using Result Enum with generic type as follow Result<T: Resource, Error>
In some cases I do not want to discuss whether the request has succeed or failed but I still need the returned resource as nullable value.
I tried to write the extension as the code below:
extension Result<T, Error> where T: Resource {
var value: Any? {
switch self {
case .success(let resource):
return resource.value
case .failure:
return null
}
}
}
However I got these compiler errors:
Constrained extension must be declared on the unspecialized generic type 'Result' with constraints specified by a 'where' clause
Use of undeclared type 'T'
You can simply create extension as below,
extension Result {
var value: Any? {
switch self {
case .success(let resource):
return resource
case .failure:
return nil
}
}
}
As in the enum definition, T is always Resource so you don't need to specify in the extension.
But if Resource is some protocol and you want to put a constraint on value variable in declaration then you can specify that in the extension using where clause as below,
extension Result where T == someSubTypeOfResource {
var value: Any? {
switch self {
case .success(let resource):
return resource
case .failure:
return nil
}
}
}
Write the type constraint as follows:
enum Result<T, Error> {
case success(T)
case failure(Error)
}
struct Resource {
let value: String
}
extension Result where T == Resource {
var value: Any? {
switch self {
case .success(let resource):
return resource.value
case .failure:
return nil
}
}
}
You can simply do it like,
enum Result<T> where T: Resource {
case success(T)
case failure(Error?)
}
Create the enum Result with case success accepting a generic associated value of type Resource and another case failure with Error? as its associated value.
Since you're using the generic param of type Resource, I assume Resource is a protocol having value as one of its properties.
protocol Resource {
var value: String {get set}
}
Now, the extension Result goes like,
extension Result {
var value: Any? {
switch self {
case let .success(resource):
return resource.value
case let .failure(error):
return error
}
}
}
Now return error in case failure and resource.value for case success.
There is no need to specify the generic parameter T with where clause in the extension again since you did that already while defining the enum Result.
Usage:
struct R1: Resource {
var value: String
}
let r1 = R1(value: "R1 is of type Resource")
let result = Result<R1>.success(r1)
print(result.value)

Extract value from enum using guard or if case in Swift

I have enum with cases:
case one(value: myClassOne)
case two(value: myClassTwo)
I want to check value of that enum. Now i ended with:
switch self.model! {
case .one:
// Great, my case here
default:
break
}
But i rather want to do something like:
if case self.model(let value) is myClassOne { // do smth } // Not compiling
Is there is easy way to simply extract enum value and check it for some condition or class equality?
This is the correct syntax:
if case .one(value: let value) = self.model {
// do something with `value`
}
guard case .one(value: let value) = self.model else {
//handle case where self.model != .one
}
// do something with `value`

What are the advantages/use cases of optional patterns introduced in swift 2?

For the simple cases like if let or guard I don't see the advantage,
if case let x? = someOptional where ... {
...
}
//I don't see the advantage over the original if let
if let x = someOptional where ... {
...
}
For the for-case-let case to simplify working with optional collections, I really hope swift can go one step further:
for case let x? in optionalArray {
...
}
//Wouldn't it be better if we could just write
for let x? in optionalArray {
...
}
After google it for a while the only case I find useful is this "Swift 2 Pattern Matching: Unwrapping Multiple Optionals" :
switch (username, password) {
case let (username?, password?):
print("Success!")
case let (username?, nil):
print("Password is missing")
...
So any other advantages of introducing optional patterns?
I believe you're conflating two different concepts. Admittedly, the syntax isn't immediately intuitive, but I hope their uses are clarified below.
(I recommend reading the page about Patterns in The Swift Programming Language.)
case conditions
The "case condition" refers to the ability to write:
if case «pattern» = «expr» { ... }
while case «pattern» = «expr» { ... }
for case «pattern» in «expr» { ... }
These are particularly useful because they let you extract enum values without using switch.
Your example, if case let x? = someOptional ..., is a valid example of this, however I believe it's most useful for enums besides Optional.
enum MyEnum {
case A
case B(Int)
case C(String)
}
func extractStringsFrom(values: [MyEnum]) -> String {
var result = ""
// Without case conditions, we have to use a switch
for value in values {
switch value {
case let .C(str):
result += str
default:
break
}
}
// With a case condition, it's much simpler:
for case let .C(str) in values {
result += str
}
return result
}
You can actually use case conditions with pretty much any pattern that you might normally use in a switch. It can be weird sometimes:
if case let str as String = value { ... } (equivalent to if let str = value as? String)
if case is String = value { ... } (equivalent to if value is String)
if case 1...3 = value { ... } (equivalent to if (1...3).contains(value) or if 1...3 ~= value)
The optional pattern, a.k.a. let x?
The optional pattern, on the other hand, is a pattern that lets you unwrap optionals in contexts besides a simple if let. It's particularly useful when used in a switch (similar to your username/password example):
func doSomething(value: Int?) {
switch value {
//case 2: // Not allowed
case 2?:
print("found two")
case nil:
print("found nil")
case let x:
print("found a different number: \(x)")
}
}