Skip to content

Instantly share code, notes, and snippets.

@priteshshah1983
Last active November 29, 2017 22:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save priteshshah1983/a95e378f82b94614767bbfe0895ae4ac to your computer and use it in GitHub Desktop.
Save priteshshah1983/a95e378f82b94614767bbfe0895ae4ac to your computer and use it in GitHub Desktop.
Lenses - Re-imagined with Swift 4
// Motivation:
// http://chris.eidhof.nl/post/lenses-in-swift/
// https://www.youtube.com/watch?v=ofjehH9f-CU&feature=youtu.be
protocol Changeable {
func changed<A>(changes: [KeyPath<Self, A>: A]) -> Self
}
extension Changeable {
func changed<A>(changes: [KeyPath<Self, A>: A]) -> Self {
var modified = self
changes.forEach { readOnlyKeyPath, newValue in
// Will this continue to work or is this a bug in the compiler?
// https://bugs.swift.org/browse/SR-6502
guard let writeableKeyPath = readOnlyKeyPath as? WritableKeyPath<Self, A> else { return }
modified[keyPath: writeableKeyPath] = newValue
}
return modified
}
}
struct User: Changeable {
let firstName: String
let lastName: String
let age: Int
let someInt: Int
let address: Address
}
struct Address: Changeable {
let street: String
let zipCode: String
}
let oneMarketStreet = Address(street: "1 Market Street", zipCode: "94105")
let jane = User(firstName: "Jane", lastName: "Doe", age: 35, someInt: 123, address: oneMarketStreet)
let john = jane.changed(changes: [\.firstName: "John", \.lastName: "Poe"])
.changed(changes: [\.age: 40])
.changed(changes: [\.address.zipCode: "94103"])
print(jane) // User(firstName: "Jane", lastName: "Doe", age: 35, someInt: 123, address: __lldb_expr_244.Address(street: "1 Market Street", zipCode: "94105"))
print(john) // User(firstName: "John", lastName: "Poe", age: 40, someInt: 123, address: __lldb_expr_244.Address(street: "1 Market Street", zipCode: "94103"))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment