SE-0280: Enum cases as protocol witnesses

I think this is a premise some people disagree with. Including me. I think that the current behaviour is inconsistent and confusing, and that this addition closes that hole, and makes the language more consistent and simple.

The argument goes like this: Enum case constructors are indistinguishable from static func/var in every way except one — The enum cannot be used to fulfil protocol requirements.

enum Foo {
    case bar
    case qux(Baz)
}

struct Foo {
    static var bar: Self { /* ... */ }
    static func qux(_: Baz) -> Self { /* ... */ }
}

At call site, these behave identically. The syntax is the same, and the semantics are the same. So why can only the latter be used as a protocol conformance? This seems inconsistent to me. The first time I realized this, I was baffled and confused.

As for motivating use cases, for me I have a protocol like this:

protocol Defaultable {
    static var default: Self { get }
}

I use this in generic code where I want to default to a trivial value, in case some predicate fails, a value is nil or whatever. I use it in a property wrapper that allows missing values in my Decodable types.

I can trivially make String, Int, Array etc conform by creating an extension that returns "", 0, [], etc. However, I also have a few enums that already have a default case. It is impossible to make that enum conform, even though T.default would return exactly what I need in generic code.

5 Likes