How come that if I have a struct
:
struct Book {
var pages = 10
}
var books = [Book()]
I cannot mutate it by a computed property:
var bookWithTenPages {
books.first { $0.pages == 10}!
}
bookWithTenPages.pages = 5 // will not work!
How come that if I have a struct
:
struct Book {
var pages = 10
}
var books = [Book()]
I cannot mutate it by a computed property:
var bookWithTenPages {
books.first { $0.pages == 10}!
}
bookWithTenPages.pages = 5 // will not work!
you can, if you declare a computed property setter:
var bookWithTenPages:Book
{
get
{
books.first { $0.pages == 10}!
}
set(value) { ... }
}
Thanks @taylorswift !
I find it interesting that the value in the setter is a book, since Iām only changing a single property on the book, the pages
property.
I guess this is so because structs are immutable?
Yep, if it was a class you could mutate it. But for data like Book it's best to use a struct
The mutation of a struct value "in place" actually behaves like you've read it, changed the copy, and assigned the copy back.
So your snippet:
bookWithTenPages.pages = 5
Behaves pretty much like:
var localCopy = bookWithTenPages
localCopy.pages = 5
bookWithTenPages = localCopy
This makes sense. Structs are a value type, whose identity is defined by their value. Mutating a struct gives it a new identity, so it makes sense to have that hit your setters, didSet
observers, etc.
Constrast this with classes, whose identity is based off their in-memory address.
mutating those objects in-place doesn't change their memory address (only the values at that address), so their identity doesn't change.
var bookWithTenPages: Book {
get {
books.first { $0.pages == 10}!
}
set {
print("\(#function): \(newValue)")
bookWithTenPages = newValue // Attempting to modify 'bookWithTenPages' within its own setter, Function call causes an infinite recursion
// š¤š©š„ŗ?? what to put here to make the change "stick"?
}
}
you would need to find the index of the first ten-page book in books
, and assign to that, since bookWithTenPages
is just an accessor.
alternatively, you can compute the index, and yield
a reference to self.books[index]
inside a _modify
.
var bookWithTenPages: Book
{
...
_modify
{
let index:Books.Index = self.books.firstIndex { $0.pages == 10 }!
yield &self.books[index]
}
}