101

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.

koen
  • 5,383
  • 7
  • 50
  • 89
Paixsn
  • 1,256
  • 3
  • 12
  • 22
  • 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." – Martin R Jul 26 '16 at 09: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? – Paixsn Jul 26 '16 at 09: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. – Sulthan Jul 26 '16 at 09: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. – Paixsn Jul 26 '16 at 09: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. – Sulthan Jul 26 '16 at 09:37
  • @Sulthan I do not want to put all together in one framework, enum or struct. It is actually more concerned to build certain structures. For example, there could be a framework that storage colors, or something like that, of a company. And these should be the same in all applications. – Paixsn Jul 26 '16 at 09:47

5 Answers5

164

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
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • There is one particular case involving switch statements where you can't use caseless enums. See my answer for discussion and possible workarounds. – Tim Fuqua Aug 17 '16 at 20:17
  • 8
    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). – dfrib Nov 07 '16 at 14:01
  • ... 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). – dfrib Nov 07 '16 at 14:06
  • 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? – mfaani Nov 07 '18 at 16:31
  • @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. – Martin R Nov 07 '18 at 19:18
  • I wasn't able to find another one. Do you if there is another question about that? Or do I need to write a new one? – mfaani Nov 07 '18 at 19:37
  • @Honey: What about this one: https://stackoverflow.com/q/49427144/1187415, or this https://stackoverflow.com/q/35931213/1187415 ? – Martin R Nov 07 '18 at 19:39
25

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.

jglasse
  • 1,188
  • 12
  • 23
  • 3
    I think he would not use individual cases since then he would always need to write `StaticVars.pi.rawValue` – Michael Oct 26 '19 at 14:56
17

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.

SilentK
  • 587
  • 7
  • 20
13

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.

Tim Fuqua
  • 1,635
  • 1
  • 16
  • 25
  • 4
    Apparently this problem has been fixed. The "caseless enum version" compiles and runs as expected in Xcode 8 beta 6. – Martin R Aug 17 '16 at 20:26
  • 2
    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. – Tim Fuqua Aug 17 '16 at 20:46
  • @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 Sep 21 '16 at 09:07
  • @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. – Martin R Sep 21 '16 at 09:11
  • @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. – G.Abhisek Sep 21 '16 at 09:16
  • @G.Abhisek: No. The only difference is what I wrote at the end of my answer. – Martin R Sep 21 '16 at 09:17
13

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.

Community
  • 1
  • 1
Ryan
  • 1,053
  • 12
  • 21