Swift constants: Struct or Enum

SwiftStructEnumsConstants

Swift Problem Overview


I'm not sure which of both are better to define constants. A struct or a enum. A struct will be copied every time i use it or not? When i think about a struct with static let constants it makes no sense that it will copied all the time, in my opinion. But if it won't copied then it doesn't matter what I take?

What advantages does the choice of a struct or enum?

Francisco say use Struct's.

Ray Wenderlich say use Enum's. But I lack the justification.

Swift Solutions


Solution 1 - Swift

Both structs and enumerations work. As an example, both

struct PhysicalConstants {
    static let speedOfLight = 299_792_458
    // ...
}

and

enum PhysicalConstants {
    static let speedOfLight = 299_792_458
    // ...
}

work and define a static property PhysicalConstants.speedOfLight.

Re: A struct will be copied every time i use it or not?

Both struct and enum are value types so that would apply to enumerations as well. But that is irrelevant here because you don't have to create a value at all: Static properties (also called type properties) are properties of the type itself, not of an instance of that type.

Re: What advantages has the choice of a struct or enum?

As mentioned in the linked-to article:

> The advantage of using a case-less enumeration is that it can't accidentally be instantiated and works as a pure namespace.

So for a structure,

let foo = PhysicalConstants()

creates a (useless) value of type PhysicalConstants , but for a case-less enumeration it fails to compile:

let foo = PhysicalConstants()
// error: 'PhysicalConstants' cannot be constructed because it has no accessible initializers

Solution 2 - Swift

Here's a short answer: Do your constants need to be unique? Then use an enum, which enforces this.

Want to use several different constants to contain the same value (often useful for clarity)? Then use a struct, which allows this.

Solution 3 - Swift

One difference between the two is that structs can be instantiated where as enums cannot. So in most scenarios where you just need to use constants, it's probably best to use enums to avoid confusion.

For example:

struct Constants {
    static let someValue = "someValue"
}

let _ = Constants()

The above code would still be valid.

If we use an enum:

enum Constants {
    static let someValue = "someValue"
}

let _ = Constants() // error

The above code will be invalid and therefor avoid confusion.

Solution 4 - Swift

Using Xcode 7.3.1 and Swift 2.2

While I agree with Martin R, and the Ray Wenderlich style guide makes a good point that enums are better in almost all use cases due to it being a pure namespace, there is one place where using a struct trumps enums.

Switch statements

Let's start with the struct version:

struct StaticVars {
    static let someString = "someString"
}

switch "someString" {
case StaticVars.someString: print("Matched StaticVars.someString")
default: print("Didn't match StaticVars.someString")
}

Using a struct, this will match and print out Matched StaticVars.someString.

Now lets consider the caseless enum version (by only changing the keyword struct to enum):

enum StaticVars {
    static let someString = "someString"
}

switch "someString" {
case StaticVars.someString: print("Matched StaticVars.someString")
default: print("Didn't match StaticVars.someString")
}

You'll notice that you get a compile time error in the switch statement on the case StaticVars.someString: line. The error is Enum case 'someString' not found in type 'String'.

There's a pseudo-workaround by converting the static property to a closure that returns the type instead.

So you would change it like this:

enum StaticVars {
    static let someString = { return "someString" }
}

switch "someString" {
case StaticVars.someString(): print("Matched StaticVars.someString")
default: print("Didn't match StaticVars.someString")
}

Note the need for parentheses in the case statement because it's now a function.

The downside is that now that we've made it a function, it gets executed every time it's invoked. So if it's just a simple primitive type like String or Int, this isn't so bad. It's essentially a computed property. If it's a constant that needs to be computed and you only want to compute it once, consider computing it into a different property and returning that already computed value in the closure.

You could also override the default initializer with a private one, and then you'll get the same kind of compile time error goodness as with the caseless enum.

struct StaticVars {
    static let someString = "someString"
    private init() {}
}

But with this, you'd want to put the declaration of the struct in its own file, because if you declared it in the same file as, say, a View Controller class, that class's file would still be able to accidentally instantiate a useless instance of StaticVars, but outside the class's file it would work as intended. But it's your call.

Solution 5 - Swift

In the Combine framework, Apple has chosen to prefer enums for namespaces.

> enum Publishers > A namespace for types that serve as publishers. > > enum Subscribers > A namespace for types that serve as subscribers. > > enum Subscriptions > A namespace for symbols related to subscriptions.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPaixsnView Question on Stackoverflow
Solution 1 - SwiftMartin RView Answer on Stackoverflow
Solution 2 - SwiftjglasseView Answer on Stackoverflow
Solution 3 - SwiftSilentKView Answer on Stackoverflow
Solution 4 - SwiftTim FuquaView Answer on Stackoverflow
Solution 5 - SwiftRyanView Answer on Stackoverflow