What's the difference between Struct based and Class based singletons?

Swift

Swift Problem Overview


Are the two approaches the same or are there major differences/pitfalls to be aware of:

class MyClassSingleton {
  static let sharedInstance = MyClassSingleton()
  private init(){}

  func helloClass() { print("hello from class Singleton") }
}

struct MyStructSingleton {
  static let sharedInstance = MyStructSingleton()
  private init() {}

  func helloStruct() { print("hello from struct Singleton") }
}

Swift Solutions


Solution 1 - Swift

The main difference is that class-based mutable singleton works, while struct-based mutable "singleton" doesn't. Unless you want to make your singleton immutable (which is rare) you should stick to the class-based one.

Here is an illustration of how mutable struct-based "singleton" does not work. Consider adding a mutable member state to both singletons, like this:

class MyClassSingleton {
    static let sharedInstance = MyClassSingleton()
    private init(){}
    var state = 5
    func helloClass() { print("hello from class Singleton: \(state)") }
}

struct MyStructSingleton {
    static let sharedInstance = MyStructSingleton()
    private init() {}
    var state = 5
    func helloStruct() { print("hello from struct Singleton: \(state)") }
}

I made state a var, but I could expose it as a read-only property plus a mutating method; the essential thing is that both types are now mutable.

If I do this

let csi = MyClassSingleton.sharedInstance
csi.state = 42
MyClassSingleton.sharedInstance.helloClass()

42 gets printed, because csi is referencing the shared instance.

However, when I do the same thing with struct-based singleton

var ssi = MyStructSingleton.sharedInstance
ssi.state = 42
MyStructSingleton.sharedInstance.helloStruct()

5 gets printed instead, because ssi is a copy of the sharedInstance, which is, of course, an indication that our singleton is not actually a singleton.

Solution 2 - Swift

That depends on what you want to achieve and how you want to use your structure based on differences between class and struct. Most common thing that you will see is using class with singleton object.

Singletons are pretty much the same, they are only created once, but you will get different behaviors from the class and from struct because:

  • Classes are reference types, while structs are value types
  • Structs are used to define simple structures
  • Structs can't be inherited

There are several more differences but you get the idea from this.

Solution 3 - Swift

As already mentioned in another answer, classes and structs have different properties. Most importantly, classes have reference semantics whereas structs have value semantics.

Nonetheless, a global variable (or a static property) introduces reference semantics, even if it's defined in a struct, suggesting that you can indeed implement a (mutable) singleton with a struct.

The problem illustrated by Sergey Kalinichenko is that assigning the value of a struct to another variable will create a copy rather than a reference (remember, structs have value semantics). So the mutations on the copy won't apply to the original value. Should you mutate the static property of your struct directly, your singleton would indeed be modified.

struct Singleton {

  private init() {}
  var state = 5
  static var sharedInstance = MyStructSingleton()

}

Singleton.sharedInstance.state = 10
print(Singleton.sharedInstance.state) // 10

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
QuestionRunning TurtleView Question on Stackoverflow
Solution 1 - SwiftSergey KalinichenkoView Answer on Stackoverflow
Solution 2 - SwiftSaid SikiraView Answer on Stackoverflow
Solution 3 - SwiftAlvaeView Answer on Stackoverflow