Optional implementation. Nil in switch. And init with `Wrapper` type

I saw a question recently on StackOverflow that I attempted to answer... swift - How to declare an `enum` of `enum` that allows for "flattened" `switch` statement? - Stack Overflow

Initially my answer was no, you can't do this. But... as pointed out by the OP, it seems that Optional DOES do this. (To a certain degree).

I was looking through the implementation of Optional here... swift/Optional.swift at main · apple/swift · GitHub

And I tried to created my own enum that had the same behaviour...

enum Foo<Wrapped> {
  case no
  case yes(Wrapped)
}

I have a gist here that shows all of the code but I pretty much copy pasted all of the implementation I could from the Optional code (apart from a few Objective_C bridges and a couple of convenience functions). Trying to recreate the behaviour of Optional... · GitHub

Anyway...

With Optional I can create this and it's perfectly valid and I have a few questions about it because I could not do the same with my own enum and I wondered where this extra "magic" came from.

enum Bar {
  case a
}

let b: Bar? = .a

switch b {
case nil:
  print("nil")
case .a:
  print("Blah")
}

The three things in here that I don't understand where they come from are...

  1. let b: Bar? = .a this allows any Optional<T> to be instantiated from a direct T with no init method. There doesn't seem to be any code in the implementation that should allow this? Does this come from something baked into the compiler?

  2. case nil: seems to take away the switch requirement for case .none:. In my own implementation I could use case nil: and it would work. It would catch if I had done let f: Foo<String> = nil (for example). But... it would still complain that the switch wasn't exhaustive. Where does this come from?

  3. case .a: removes the requirement for case .some(_): in the switch. Again, I could make case .a: work for my own Foo enum but it wouldn't satisfy the exhaustive switch (even though all other possible cases were covered). Where does this come from?

Finally... a side question around Bool?.

If you create code like...

let b: Bool? = true

switch b {
case nil:
	print("nil")
case true:
	print("True")
case false:
	print("False")
}

Then the compiler will still complain that the switch is not exhaustive and require you to add a case for case .some(_): even though that will never happen. Is this a bug or is this some other fundamental impossibility around the fact that Bool is not an enum but some other type?

Thanks

1 Like

Yes, this is what we call (colloquially) “magic.” Optional<T> and T have a special subtyping relationship that is baked into the compiler and which cannot be implemented for user-defined custom types.

1 Like
Terms of Service

Privacy Policy

Cookie Policy