Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I easily copy an immutable struct in swift, varying only some fields [Like kotlin dataclass copy method]?

I have a swift struct somewhat like this:

struct LogicalState {
  let a: String?
  let b: Bool
  let c: Int
}

and a mutable instance of this state. Note the properties within the state are all let, so the struct itself is immutable.

var _state: LogicalState

What I'd like to do is enforce a pattern where updating the state is allowed, but all updates must be atomic - I do NOT want to simply make a, b, and c mutable, as that would allow a and b to change independently. I need to control the updates and apply validation (for example, to enforce that if you change a, you also must change b at the same time)

I can do this by simply overwriting the whole struct

_state = LogicalState(a: "newA", b: false, c: _state.c)

However, as you can see, having to explicitly reference the old state for the properties that don't change (_state.c) is annoying and problematic, especially when you have more properties. My real-world example has something like 10.

In kotlin, they have "data classes" which expose a "copy" method, which lets you change only the parameters you want. If swift supported such a thing, the syntax would look like this

func copy(a: String? = self.a, b:Bool = self.b, c:Int = self.c) ...

The problem is, the = self.a syntax doesn't exist in swift, and I'm not sure of what other options I have?

Any solution on how to solve this would be much appreciated

like image 499
Orion Edwards Avatar asked May 13 '18 23:05

Orion Edwards


People also ask

Are structs immutable in Swift?

Yep, you're right, structs are not immutable. The thing about structs is that they are values. That means every variable is considered a copy, and its members are isolated from changes made to other variables. Structs are not copied on mutation.

Are Swift structs copy on write?

Copy-on-Write is a computing technique available in the Swift standard library for value types such as collections and structs . Essentially, it defers the copying of collections and structures until when it's actually needed.

How do you create a structure in Swift?

Unlike other programming languages, Swift doesn't require you to create separate interface and implementation files for custom structures and classes. In Swift, you define a structure or class in a single file, and the external interface to that class or structure is automatically made available for other code to use.

What is class and struct in Swift?

In Swift, structs are value types whereas classes are reference types. When you copy a struct, you end up with two unique copies of the data. When you copy a class, you end up with two references to one instance of the data. It's a crucial difference, and it affects your choice between classes or structs.


1 Answers

Think, you can extend the struct with a copy(...) method taking nil values as default and replacing them with instance ones while using non-nil otherwise. E.g. something like this:

extension LogicalState {
    func copy(a: String? = nil, b: Bool? = nil, c: Int? = nil) -> LogicalState {
        return LogicalState(a: a ?? self.a, b: b ?? self.b, c: c ?? self.c)
    }
}

So you can use it to copy instance while varying the needed params:

let state = LogicalState(a: "A", b: false, c: 10)
let stateCopy1 = state.copy(c: 30)
let stateCopy2 = state.copy(a: "copy 2")
like image 57
Mikhail Churbanov Avatar answered Sep 28 '22 07:09

Mikhail Churbanov