Subclasses and cross-references

Hi everyone,

I have trouble finding the right model to design a class that has a parent-children relationship with another class. Both classes are generic and are intended to be subclassed.

This summary might not be very clear so let's start with a simple example : a database that holds a reference to all its objects and each object hold a weak reference to its database.

class Database {
	var objects: [DatabaseObject] {
		didSet {
			for object in objects {
				object.database = self
			}
		}
	}
}

class DatabaseObject {
	weak var database: Database?
}

Now in my app my goal is to define a subclass of Database and subclasses of DatabaseObject for every kind of object I need to deal with. Obviously I can start with something like that :

class MyAppDatabase: Database {
	
}

class SomeDatabaseObject: DatabaseObject {
	
}

let object = SomeDatabaseObject()

But problem is object.database returns a Database whereas it would be nice to return a MyAppDatabase. So let's get generic and change things a bit :

class DatabaseObject<D: Database> {
	weak var database: D?
}

class SomeDatabaseObject: DatabaseObject<MyAppDatabase> {
	
}

With that change object.database would return a MyAppDatabase as I want but the question is, how to define the Database class accordingly ? Something like that comes to mind but it doesn't compile.

class Database<O: DatabaseObject<Self>> {
	var objects: [O] {
		didSet {
			for object in objects {
				object.database = self
			}
		}
	}
}

So what would be the correct to way to design this ? Thanks for your advice.

What you're trying to do seems circular to me, so chances are, you'll need to give up on one side. Either to have object refer to base Database, or to have databases refer to base DatabaseObject.

I think the closest you can get is to have them genericize over a common class (which doesn't seem to apply to your case).

class Object<Value> {
    weak var database: Database<Value>?
}

class Database<Value> {
    var objects: [Object<Value>] = []
}

Then again, I'd need to urge you to reconsider if it's important to distinguish Database from MyDatabase at compile time. Most likely the logic will run just fine with Database, and mayhap dynamic cast under very special circumstances.