nburk nburk - 4 months ago 11
iOS Question

Is it possible to implement a bidirectional relatioship between two structs using only constant properties?

My use case is based on the following model:

struct Person {
let name: String
let houses: [House]
}

struct House {
let owner: Person
}


Now, ideally I would like to maintain a bidirectional relationship that requires every house to have exactly one owner where an owner should also know all its houses.

Using the above data structures, is it possible to create instances of
House
and
Person
such that there is a relationship between the two and the objects are essentially pointing at each other?

I guess the phrasing of this already is somewhat misleading, because due to the value semantics of
struct
s, they don't really point anywhere but are only holding copies of values. It seems to be like it should be obvious that it's not possible to create these two objects with a bidirectional relationship, but I still wanted to be sure and ask this questions here!

An obvious solution would also be to make
houses
and
owner
variables using
var
instead of
let
when declaring them, then the relationship could be maintained in the initializer of each
struct
:

struct Person {
let name: String
var houses: [House]

init(name: String, houses: [House]) {
self.name = name
self.houses = houses
self.houses = houses.map { (house: House) in
var newHouse = house
newHouse.owner = self
return newHouse
}
}
}


struct House {
var owner: Person

init(owner: Person) {
self.owner = owner
var newHouses = self.owner.houses
newHouses.append(self)
self.owner = Person(name: owner.name, houses: newHouses)
}
}


However, what if I want to keep
houses
and
owner
constant? As I said, it seems to be obvious that it's not possible, but I'm wondering if there's some fancy (maybe functional) way to achieve this? I was thinking about lenses, which can be used as getters and setters when dealing with immutable models.

Answer

What you're describing sounds more like an ORM than a language feature, and also doesn't sound appropriate to handle with value types like structs. How do you expect the language to know that owner is the inverse relationship property of houses and needs to be maintained accordingly? This is something that needs to be enforced with code is not possible with the Swift language alone.

It sounds like you're trying to maintain some kind of model object graph, which is a problem that's been solved many times over. You should take a look at Realm DB and Core Data both of which offer managed bidirectional relationships. You'll find however that neither of these are implemented with structs. The problem with using value types is that they are copy-on-write. As soon as you mutate one struct in the object graph, you'd need to reassign all of it's related things to the new, mutated copy, which then in turn are mutated and would need to update all of their related structs. Reference semantics (classes) make maintaining an object graph much easier as mutations don't produce new instances.

Comments