Using subclass-constrained protocols

I recently discovered the subclass-constrained protocols thanks to the RealityKit framework. A feature obviously implemented in Swift 5:

class Entity: HasSynchronization {}

protocol HasSynchronization : Entity {}

Is there a clear guide on how to use such patterns? I could not find any documentation or articles related to it.

In RealityKit, HasSynchronization inherits from Entity and the base class Entity adopts it. So it could be implemented as simple methods and properties of the Entity base class, couldn't it?

Furthermore, what's the difference between

protocol HasSynchronization : Entity {}

And

protocol HasSynchronization {}
typealias HasSynchronizationClassConstrained = Entity & HasSynchronization

?

This is not what is happening. HasSynchronization does not inherit from Entity. It simply requires that any type which conforms to HasSynchronization must inherit from Entity.

Therefore, the examples that you provided are not equivalent.

Furthermore, your alternative can quickly become very cumbersome once you have an entity that you'd like to have many components, for example:

protocol HasCustomComponentA {}

typealias HasCustomComponentAClassConstrained = Entity & HasCustomComponentA

protocol HasCustomComponentB {}

typealias HasCustomComponentBClassConstrained = Entity & HasCustomComponentB

class CustomEntity: HasCustomComponentAClassConstrained, HasCustomComponentBClassConstrained {}

This will not compile because now CustomEntity has a duplicate inheritance from Entity. Of course you could define another typealias like this:

typealias HasCustomComponentAHasCustomComponentBClassConstrained = Entity & HasCustomComponentA & HasCustomComponentB

But again, this is already cumbersome with just two components...

In addition to being cumbersome when dealing with many components, the alternative example you provided is not functionally equivalent to the first example, because in the alternative any class or struct can still conform to HasSynchronization.

So, we have established the difference here, so now we have to ask, what is the point of constraining HasCustomComponent to Entity at all? Well, the answer is, it allows you to add components to an Entity which can add to the functionality of the Entity, for example:

class BaseEntity {
    var someProperty = true
}

protocol HasCustomComponent: BaseEntity {}

extension HasCustomComponent {
    func doSomethingWithSomeProperty() {
        if self.someProperty == true {
            print("do something")
        }
    }
}

class CustomEntity: BaseEntity, HasCustomComponent {
    override init() {
        super.init()
        doSomethingWithSomeProperty()
    }
}

The only reason that this works is because HasCustomComponent knows for certain that self must conform to BaseEntity because of the type constraint on the protocol.

Thanks for your answer! You're right I didn't use the right terms and the typealias alternative can be very cumbersome, thanks for pointing me that out. Do you know something about this RealityKit particular pattern?

HasSynchronization inherits from requires a Entity and the base class Entity adopts it. So it could be implemented as simple methods and properties of the Entity base class, couldn't it?

Terms of Service

Privacy Policy

Cookie Policy