Skip to content

Instantly share code, notes, and snippets.

@vasarhelyia
Created December 12, 2019 19:59
Show Gist options
  • Save vasarhelyia/2609a22915a0c63cde6ea492cda178ce to your computer and use it in GitHub Desktop.
Save vasarhelyia/2609a22915a0c63cde6ea492cda178ce to your computer and use it in GitHub Desktop.
Trying to find a way to "update" properties of immutable objects without losing their type information
import Foundation
class A {
let bool: Bool
let string: String
init(bool: Bool = false, string: String = "A") {
self.bool = bool
self.string = string
}
}
class B: A {
let int: Int
init(bool: Bool, string: String, int: Int) {
self.int = int
super.init(bool: bool, string: string)
}
}
class C: A {
let float: Float
init(bool: Bool, string: String, float: Float) {
self.float = float
super.init(bool: bool, string: string)
}
}
class D: A {
let float1: Float
let float2: Float
init(bool: Bool, string: String, float1: Float, float2: Float) {
self.float1 = float1
self.float2 = float2
super.init(bool: bool, string: string)
}
}
func updateFlag(objects: [A]) -> [A] {
return objects.map { A(bool: true, string: $0.string) }
}
let objects: [A] = [
B(bool: false, string: "B", int: 1),
C(bool: false, string: "C", float: 1.0),
D(bool: false, string: "D", float1: 1.0, float2: 1.0)
]
print("1. \(updateFlag(objects: objects).map { "name: \($0.string), type: \($0.self)"})")
// ["1. name: B, type: A", "name: C, type: A", "name: D, type: A"]
// 2. Adding a lens for "updating" the flag
struct Lens<T, P> {
let from : (T) -> P
let to : (P, T) -> T
}
let flag: Lens<A, Bool> = Lens( from: { $0.bool }, to: { A(bool: $0, string: $1.string) })
func lensUpdateFlag(objects: [A]) -> [A] {
return objects.map { return flag.to(false, $0) }
}
print("2. \(lensUpdateFlag(objects: objects).map { "name: \($0.string), type: \($0.self)"})")
// ["2. name: B, type: A", "name: C, type: A", "name: D, type: A"]
// 3. Adding one lens per type for "updating" the flag
let flagB: Lens<B, Bool> = Lens( from: { $0.bool }, to: { B(bool: $0, string: $1.string, int: $1.int) })
let flagC: Lens<C, Bool> = Lens( from: { $0.bool }, to: { C(bool: $0, string: $1.string, float: $1.float) })
let flagD: Lens<D, Bool> = Lens( from: { $0.bool }, to: { D(bool: $0, string: $1.string, float1: $1.float1, float2: $1.float2) })
// Have to switch over types to update
func lensTypeSpecificUpdateFlag(objects: [A]) -> [A] {
return objects.map {
switch $0 {
case let b as B:
return flagB.to(false, b)
case let c as C:
return flagC.to(false, c)
case let d as D:
return flagD.to(false, d)
default: return $0
}
}
}
print("3. \(lensTypeSpecificUpdateFlag(objects: objects).map { "name: \($0.string), type: \($0.self)"})")
// ["3. name: B, type: B", "name: C, type: C", "name: D, type: D"]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment