103

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?

Francescu says use structs.

Ray Wenderlich says use enums. But I lack the justification.

6
  • 7
    A justification is in the linked article: "The advantage of using a case-less enumeration is that it can't accidentally be instantiated and works as a pure namespace." Commented Jul 26, 2016 at 9:01
  • OK that sounds logical. So I should use enums in 90% of my cases. And as soon as something need to be instantiated or to be variable, I use a struct. Correct? Commented Jul 26, 2016 at 9:23
  • 2
    Why don't you define them in classes which are using them? Why do you need to place all constants into one structure? You can still have them in one file if you use extensions. If you are deciding between enum and struct I say neither from architecture point of view. Commented Jul 26, 2016 at 9:28
  • Because I need a framework that I can include in a large part of my projects. I'm going to need the same constants in all of them. So i don't want to write it multiple times. Commented Jul 26, 2016 at 9:33
  • 2
    @SnowN I am not against constants but I am telling you that there is no need to put them all into one common structure/enum if they have nothing in common. Commented Jul 26, 2016 at 9:37

5 Answers 5

167

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
Sign up to request clarification or add additional context in comments.

7 Comments

There is one particular case involving switch statements where you can't use caseless enums. See my answer for discussion and possible workarounds.
Minor addition: if we add private init() {} to the Struct example, it will also hold the "advantage" of not being able to be accidentally instantiated on-the-fly. (Naturally this "advantage" could be circumvented by some dev-user by including a initializer in an extension to the Struct: but if we'd for some reason prefer to use a Struct in a "pure namespace" fashion, rather than an enum, then the private initializer could be a good do-not-use-as-instance-safeguard to include).
... and I just realized this very point was (kind of) mentioned in the other answer below (although the same-file private issue mentioned there is no longer present in Swift 3).
that's a very un-useful advantage. I actually came here for a comparison between struct Constants static let speedOfLight = 300 vs enum Constants enum Light : Int case speed = 300 Can you compare those in your answer as well? Or is there another answer for that comparison?
@Honey: That is a different question. This one (as I understood it) is about providing a namespace. Static constants can be defined inside a struct or inside an enum. They can have different types, and you can have multiple constants with the same value. – The cases of an enumeration define (mutually distinct) values of the same type.
|
26

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.

1 Comment

I think he would not use individual cases since then he would always need to write StaticVars.pi.rawValue
20

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.

1 Comment

Struct cannot be instantiated if you make all of its init methods explicitly private, as I understand
17

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.

Comments

14

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.

6 Comments

Apparently this problem has been fixed. The "caseless enum version" compiles and runs as expected in Xcode 8 beta 6.
Right on! I really like using caseless enums for the "no instantiation" benefit. And I'm also glad I started my post with the Xcode version info, otherwise there could have been the "works on my machine" issue.
@MartinR As you pointed out that in Xcode 8 the case of "baseless enum" is sorted, So now what is the difference of declaring static let in "struct" and that in "enum".
@G.Abhisek: I tried to answer that in my answer. Using a caseless enum prevents you from creating a (useless) instance of that type. For the constant itself, it makes no difference at all.
@MartinR So that means that when we are accessing via a struct we are unnecessarily creating an instance whereas in case of enum it acts as a namespace.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.