Swift: The 😎 Case of An Enum With No Cases

Earlier today, I wrote about all the unconventional ways I use extensions in Swift to make my code more readable. This somehow triggered an interesting discussion on Twitter around Swift naming conventions. I won’t go into detail on that here – you can read the full discussion yourself if you’d like. But I did learn something super cool:

Whoa! Apparently 1. you can have an enum with no cases! And 2. an enum with no cases is perfect for namespaced constants!

My favorite example of namespaced constants comes from @jesse_squires:

But the problem is that another developer might not know much about ColorPalette and easily instantiate it like this:

Which can get confusing… 🤔

Making ColorPalette an enum with no cases instead of a struct solves this problem!

An enum with no cases cannot be initialized, so now when you try to instantiate the enum version of ColorPallete, you get this error!

Enum no cases error swift

Love this simple trick! Thanks @jl_hfl!

Enjoy the article? Join over 14,500+ Swift developers and enthusiasts who get my weekly updates.

  • Couldn’t Gray be another enum or is that just not possible?

  • John Estropia

    Agreed. We also discussed this in our team’s best practices ranking here (rank 9 about singletons): https://developers.eure.jp/tech/10-tips-when-moving-from-objective-c-to-swift-en/

    • Torbold

      Wow, thanks, the tips are pure gold!

  • I don’t see the point of this. Struct feels like a cleaner way to namespace a bunch of constants. What’s the risk of instantiating your empty struct? Even if you did, you’d get a warning that the constant is unused.

    • fans

      I somehow agree with u. I think new developers only might make mistakes when using ColorPalette before they actually see what the ColorPalette struct looks like.

    • themacolyte

      I agree. It seems like this is taking an unintentional artifact of the swift compiler and building on top of it for insignificant gain. I think an enum without cases should cause a compile time error. I wouldn’t expect this capability to stick around. Using enums for non enum behavior like this (or “phantom types”) smells bad to me.

    • Aaron Bratcher

      To me a struct is used to hold various elements of an object-like entity that is of a value type, not reference. An enum is something to use when encapsulating different entries of the same type. Known error codes, segues, and colors. The idea that you could have an enum without being able to instantiate is a great thing if it is only needed for getting the enum values themselves. I have no problem using this.

    • I agree. Misuse of an API by instantiating an object that you can’t do anything with shouldn’t be something to worry about too much. If one really wanted to make their struct fool-proof, one could add to the struct: init() throws { throw NSCocoaError.featureUnsupportedError }, or soft-warn at runtime with something like: init() { NSLog("Instantiating (self.dynamicType) is not allowed; this is instended as a static-only struct.") }

    • Better still; a failable initializer can be used to prevent instantiation: init()? { return nil }. It might make sense to NSLog a warning; or a comment may suffice. Your call.

  • Scott

    This is not an enum, don’t use it like one. Your whole argument here is you don’t want them to initialize it. OK, just put a private empty init method, just like in a singleton, and they can’t initialize.

    • fans

      I somehow agree with u. But not sure.

    • This doesn’t work; Swift happily lets you instantiate a struct with a private init() (checked in Swift 3; test code is here: https://gist.github.com/capnslipp/c166e3fb51112f0c6551d5ea3626b2bb ).

      • Denis

        This happens because you declare private init method and use it in same source file. From documentation: “Private access in Swift differs from private access in most other languages, as it’s scoped to the enclosing source file rather than to the enclosing declaration.”

        • Yep, you’re absolutely correct; I had forgotten that Swift private works that way. Updated my gist; now produces error “’GlobalsStruct’ initializer is inaccessible due to ‘private’ protection level” as expected.

          • Minor update: This has changed in the final Xcode 8.0 release of Swift 3. private now works as it does in other languages; fileprivate is a new access level modifier that does what private did in Swift 2.0— “ scoped to the enclosing source file rather than to the enclosing declaration”.

    • I’m totally agree with you

  • edgecase

    This is just for namespacing the leaf colors, right? Why not just use class methods like UIColor.redColor() does? What is the advantage of the fancy tricks?

    • Because Natasha’s constants don’t apply universally to a built-in data type. It’s clear to see from her example that her Red isn’t a standard RGB red; it’s instead a shade of red specific to her app’s color palette. Extending standard library stuff is cool when it’s universally applicable, but trouble-borne when it infuses app-specifics logic or data.