Is it wrong to define a enum instance as optional?

Is it wrong to define an enum instance as optional?

What do you think?

I asked about this and received responses like:

enum Optional {
case none
case some(Wrapped)
}

So, when you make an enum optional, it’s like you’re wrapping an enum inside another enum. It’s a bit overkill, right?

i always held the opposite opinion, that having a none case in an enum was a smell, and indicated that things that hold the enum should be holding an optional of the enum instead.

2 Likes

I think the same as you.

However, I think this is a controversial topic because some developers recommend avoiding optional enumeration instances.

Some previous discussion here: Should you ever have a `.none` case in an enum?
(A question posed by @taylorswift themselves!)

My personal opinion: Optional<T> communicates different meaning than T.none. Should you ever have a `.none` case in an enum? - #4 by itaiferber

1 Like

It's similar to having an Optional inside an Optional, in that there are some cases where that makes sense semantically. But, it's uncommon so indeed it's always wise to ask yourself if you really need it.

But there are simple expressivity benefits to an explicit none case as opposed to using optionality. You can distinguish between "unspecified" and "none" for example, which are sometimes different things.

1 Like

I don't see an issue here, e.g. enum size is not affected, neither is the runtime.

If you do go with your none enumeration value I'd strongly recommend to name it somehow differently, e.g. "nought".

There’s nothing wrong with an enumeration holding another enumeration. An optional indicates that there is either a wrapped value or no value. If you want to express either a wrapped enumeration or no value, then an optional enumeration is a perfectly fine way to express that.

Can you show an example of a developer recommending avoiding this? I’m interested in seeing their reasoning.


Personally, I’ve found that nested optionals are actually something to avoid. The concept of “either a wrapped value, or no value, or no value” doesn’t really make sense. Often, when a double optional is used, there is a more expressive alternative (for example, an enumeration with a “wrapped value” case, a “no value” case, and a “value not yet calculated” case).

Additionally, many of Swift’s features interact awkwardly with nested optionals. For example:

let doubleOptional0: Int?? = Optional(nil)
print(doubleOptional0 as Any) // prints nil

let optional1: Int? = nil
let doubleOptional1: Int?? = Optional(optional1)
print(doubleOptional1 as Any) // prints Optional(nil)

This aversion to nested optionals isn’t limited to me, either: there are many features in Swift that are designed to avoid nesting optionals by flattening them, such as optional chaining, as? casting, the nil-coalescing operator ??, and the try? operator.

I see nothing wrong with either alternative.

I would prefer Wrapped + Optional if Wrapped is used on it's own, and Wrapped with extra case, if otherwise Wrapped would always be used inside Optional.

And sometimes it is helpful to have both:

enum ValidUseCase {
    case a
    case b
}
enum UseCase {
    case a
    case b
    case invalid

    init(valid: ValidUseCase) {
        switch valid {
            case .a: self = .a
            case .b: self = .b
        }
    }

    var asValid: ValidUseCase? {
        switch self {
            case .a: return .some(.a)
            case .b: return .some(.b)
            case .invalid: return .none
        }
    }
}