Search code examples
swiftenumsassociated-value

Avoiding `(())` to explicitly specify an enum's associated value of type Void


Let's say I have something similar to the standard Result type:

enum TestResult<SuccessData, FailureData> {
    case success(SuccessData)
    case failure(FailureData)
}

That's fine in general, when SuccessData and FailureData are 'real' types - not Void. You could use it like this:

let result: TestResult<TestData, FailureReport> = .success(someData)

All good.

But, for my purposes sometimes one or both of those will be void (e.g. very simple test types which have no additional information to convey, just whether they succeeded or failed). In that case I apparently have to write:

let result: TestData<Void, Void> = .success(())

That's pretty ugly. Is there a way to omit the (())?


Solution

  • This is a little better:

    extension TestResult where SuccessData == Void {
        static func success() -> Self {
            .success(())
        }
    }
    
    extension TestResult where FailureData == Void {
        static func failure() -> Self { 
            .failure(())
        }
    }
    
    
    let successfulResult: TestResult<Void, Void> = .success()
    let failedResult: TestResult<Void, Void> = .failure()
    

    The separate success() and failure() static functions are in separate extensions so that the other generic type can be anything:

    let successfulResult2: TestResult<Void, Error> = .success()
    let failedResult2: TestResult<Int, Void> = .failure()
    

    I tried to make them static properties rather than static functions so they could be used without the parenthesis, but that resulted in a compiler error “ Static stored properties not supported in generic types”.

    EDIT: I was trying to make static properties initialised with a value but I can see from the answer that @MartinR linked to it can be done with computed properties:

    extension TestResult where SuccessData == Void {
        static var success: Self {
            .success(())
        }
    }
    
    extension TestResult where FailureData == Void {
        static var failure: Self {
            .failure(())
        }
    }
    
    let successfulResult: TestResult<Void, Never> = .success
    let failedResult: TestResult<Void, Void> = .failure