Make Result expressible by literals when its Success type conforms to expressible by literal protocols

Is it a good idea to make Result conform to ExpressibleBy*Literal when its Success type conforms to the same protocol? Something like:


extension Result: ExpressibleByIntegerLiteral
    where Success: ExpressibleByIntegerLiteral
{

    public init(integerLiteral value: Success.IntegerLiteralType) {
        self = .success(Success.init(integerLiteral: value))
    }

}

Example usage:


let result: Result<Int, Error> = 42 // == Result<Int, Error>.success(42)

If this does seem like a good idea, is it good enough to include in the standard library?

1 Like

I don't think this accords with the general direction of Swift, which emphasizes clarity over brevity, and it seems to be an oddly specific case.

If you'd like to add this to your own code base, then by all means, but the core team specifically declined to add additional sugar or compiler support to the Result type.

(One discussion, for example, was giving Optional<T> a subtyping relationship with Result<T, Error>, just as T has a subtyping relationship with Optional<T>; that would have yielded a similar result but with more generality.)

In the meantime, everyone else can write .success(42), which has no problems.

4 Likes

I could see a case for giving an enum a "default case" that auto-wraps its payload, much like Optional.some does:

enum Foo<Bar> {
  default case typical(Bar)
  case exceptional(Bar, Baz)
}

var foo: Foo<String, Int>
foo = "hello"                // automatically promoted to .typical("hello") because of `default`
foo = .typical("hello")      // also works
foo = .exceptional("hello")  // .exceptional(…) required here

Not sure what havoc that wreaks on type resolution, or whether it's worth it….

3 Likes

Custom subtyping relationships would be very nice. But forget generalizing to one case of any enum; as I mention above, the core team did not want to consider even having it built-in specifically for Result.success. One day...

I have been tinkering around with extending Result with protocols like Encodable and Decodable separately and felt that making Result more powerful would be a nice addition to the standard library. I thought that conforming to expressible by literal protocols would be a good place to start.

Could you please give more detail about this decision? It seems my thought process behind this suggestion was in the exact opposite direction of the core team’s.

Whether to add the Result type at all was a point of contention. The core team reasoned as follows:

The core team agrees that async / await is likely to greatly diminish the importance of this type, but not so much as to make it completely useless

The principal purpose of adding this type to the standard library, then, was that:

the type will help standardize existing practice in ways that are likely to be useful for async / await

Ultimately, the core team deleted a number of proposed methods from the approved version and chose a limited API on purpose; they also declined the addition of more features like chaining or subtyping relationships, given their view that the type serves a major transitional purpose and will not be much used after async/await.

(The addition of additional APIs in the future was not ruled out, of course, since the core team almost never rules out new features preemptively before they're proposed. Given their articulated view on the role of the Result type, though, it's unlikely that major changes to the type will be made until we see what residual role it has after async/await.)

2 Likes