Convenience member on Result when when Success is Void

This is a tiny refinement to the std lib that to provide a convenience member on Result when when Success is Void.

Result types with a success type of Void are commonly used when no further information about the result of the operation are required – other than to know it was successful. In these cases, it is necessary to return a Result via Result.success(()).

The double parentheses can sometimes become an impediment to legibility – especially if wrapped within another set of parentheses, e.g. as an argument within a function call.

 someHandler(.success(()))

I propose a tiny addition to the std-lib to iron out the kink:

extension Result where Success == Void {
    public static var success: Result { .success(()) }
}

Which smoothes out the above example to:

 someHandler(.success)

Whilst I can't think of elsewhere in the Swift std-lib where this kind of specialisation of types with Void type arguments exists, there is prior history elsewhere in the Apple eco-system. Specifically Combine's PassthroughSubject.send() which presumably added the syntactic sugar to clean-up the SwiftUI api.

11 Likes

I understand the pitch, but isnβ€˜t the usage of SomeError? preferred over Result<Void, SomeError>?

Often it makes sense for your API to consistently return Results over chopping and changing between Optionals and Results. That's because Results are composable with flatMap, etc.

7 Likes

In lieu of an addition to the standard library, why not use the spelling that's preferred in Swift: .success(Void)? This is not the only circumstance in which ()-as-Void is less than readable, and it's precisely for that reason that Void is preferred.

1 Like

Hmmm, I thought it was the other way round: Void should be used as the return type and '()' as the argument type?

In any case, I get the following error with that approach: 'Cannot convert value of type 'Void.Type' to expected argument type '()''

2 Likes

That won't even compile here as Void is a type, while () is a value of type Void (or the typealias Void = (), which you refer as less readable).

5 Likes

Whoops, brainfart. :slight_smile:

3 Likes

+1 I have been reaching for .success(()) personally when facing this. One of my coworkers prefers the more verbose .success(Void()). I would prefer to just use this extension instead. I might even consider adding this extension in the meantime.

1 Like

This extension would make .success ambiguous absent any type context (such as a call).

1 Like

Yes, that’s true – I'd missed that.

So instead:

extension Result where Success == Void {
    public static func success() -> Self { .success(()) }
}

Which hopefully is still a big improvement on ergonomics/legibility.

 someHandler(.success())

Side note: maybe there is eventually room for a more wide-ranging, complex proposal: any function with Void parameters would have a counterpart function generated where the default ()s are specified/provided.

e.g. with Combine's PassthroughSubject.send(_:), this would automatically derive PassthroughSubject.send() when PassthroughSubject's Output type is Void. For enums, it would automatically generate the appropriate counterpart static var (as described above for Result.) Of course, if a user-defined equivalent already exists – that would take precedence.

3 Likes

This is a pretty common issue with generics and PATs, and can be hard to work around; I’d really like to see a language-level solution if one is feasible.

One way to think of it would be that for value parameters of a generic/associated type that resolve to Void, there should be a synthesized default value of ().

5 Likes

There is already this pull request but missing a proposal.

I started writing a proposal, including more improvements to the Result type.

@tcldr feel free to contribute :slight_smile:

What's the issue with having .success ambiguous without any type context?
i.e. can you provide an example that twists the programmer's arm while coding, in order to favor .success() over .success?

Thanks John!

Terms of Service

Privacy Policy

Cookie Policy