1

Optional in Swift allows for magic where switch-ing over an optional enum flattens the cases into a single switch statement.

Given:

enum Foo {
    case bar, baz
}

You can:

let foo: Foo? = .bar
switch foo {
case .bar:
    break
case .baz:
    break
case nil:
    break

Here, Optional is an enum and Foo is an enum, but just one single statement is enough to cover all cases of both.

Question: can I declare my own enum inside another enum so that the cases can be handled in a flat way too?

So that I could:

enum Foo<Bar> {
    case nope
    case dope(Bar)
}

enum Baz {
    case yep
}

let b: Foo<Baz> = .dope(.yep)

switch b {
case .nope:
    break
case .yep:
    break
}

Maybe if I call the case Foo.dope as Foo.some? Maybe there is an annotation that I can use?

Isaaс Weisberg
  • 2,296
  • 2
  • 12
  • 28

1 Answers1

2

You could do this with …

switch b {
case .nope: // stuff
case .dope(.yep): // other stuff
case .dope(.someOtherCase): // more stuff
}

Responding to your comment…

Imagine you could flatten it like you said. How would you deal with…

enum Foo {
    case a
    case b(Bar)
    case c(Bar)
}

If you are allowed to exclude the .b from the switch then there is no way to differentiate between .b and .c.

Fogmeister
  • 76,236
  • 42
  • 207
  • 306
  • Yeah, I mean, okay, yeah, butttttt---- I wonder if I can get rid of `.dope` inside the switch entirely... :) – Isaaс Weisberg Oct 23 '21 at 14:01
  • No, as that is part of the enum that you’re switching on. To get rid of it would break the code. How would the compiler know what `.yep` is? Also, you’re not adding anything (except it’s shorter by 4 characters) by doing what you want? – Fogmeister Oct 23 '21 at 14:02
  • Imagine you could get rid of it… how would you deal with two cases that both take a Bar enum value? – Fogmeister Oct 23 '21 at 14:03
  • Hmmm... Yeah, these are valid points... – Isaaс Weisberg Oct 23 '21 at 14:04
  • Alright, you know what, I will gladly accept your answer if you will edit the answer, saying that this is impossible and this magical behavior is available exclusively to the `Optional`. – Isaaс Weisberg Oct 23 '21 at 14:14
  • The switch case uses pattern matching to determine whether your value is matched in the case. Let me have a look to see if I can find the actual implementation of this for Optional. – Fogmeister Oct 23 '21 at 14:44
  • Here is some reading for you about how Apple are able to make this work. https://github.com/apple/swift/blob/main/stdlib/public/core/Optional.swift – Fogmeister Oct 23 '21 at 15:08
  • Oh I'm terribly sorry, I'm afraid, this is just a misunderstanding - I have provided such specific instructions purely to make sure that your answer directly addresses the question I asked. I asked specifically about flattening, but writing `.dope(.yep)` does not flatten the switches, and I only wanted the answer to directly hit the nail on the head. I wasn't trying to be snarky or sarcastic, I was just suggesting to make it more direct, more obtuse - a direct answer to a direct question. – Isaaс Weisberg Oct 23 '21 at 22:00
  • Sorry once again and thank you for the help. @Fogmeister – Isaaс Weisberg Oct 23 '21 at 22:01
  • Alright, decidedly inspected the source code for Optional.swift and unfortunately there are no details on flattening the switch statement. I'm afraid for this one would need to inspect the Cpp code for AST building... Thank you for the link anyway. – Isaaс Weisberg Oct 23 '21 at 22:11
  • 1
    I managed to get as far with my own enum as allowing it to use `nil` and a wrapped value directly in the switch. But it still required me to add `.no` for the switch to be exhaustive. I pretty much created my own Foo enum with all the code from the Optional link I sent earlier. I couldn’t find anything about how they managing to remove the `.none` requirement from the switch when using `nil`. I’d still argue that what you’re trying is probably too much for too little benefit when you can still “flatten” the switch by using `.dope(.yes)` as the pattern. – Fogmeister Oct 24 '21 at 10:24
  • 1
    Damnit, now I'm interested in how this works myself. LOL! I created a gist to show where I got to... https://gist.github.com/oliverfoggin/697e9340a5705800adf6ec5ae4cac29d but couldn't get some of the features to work. I've added a swift forums question https://forums.swift.org/t/optional-implementation-nil-in-switch-and-init-with-wrapper-type/53028 – Fogmeister Oct 24 '21 at 19:09
  • 2
    Ok… this is from an ex apple engineer… https://twitter.com/txaiwieser/status/1452379958219788299?s=20 The way that Optional does all this fancy stuff is that they have baked a lot of it into the compiler so that the compiler gives it these “magic powers” that you referred to. So, as for writing your own, you definitely won’t be able to replicate everything yourself. – Fogmeister Oct 24 '21 at 21:05
  • oh my lord I am so thankful that you have continued delving deeper in this yourself! I'm actually embarrassed that neither have I shown the same amount of effort, nor have I made a good impression by being pushy and lazy... – Isaaс Weisberg Oct 25 '21 at 11:18
  • 1
    No worries man. It’s all good I actually got really interested in how it works. – Fogmeister Oct 25 '21 at 11:33