I'm modeling a owner/ownee scheme on Swift:
class Owner<T: Ownee> { // ... } protocol Ownee { var owner: Owner<Self> { get } }
Then I have a pair of classes professor/student that adhere to the modeled types above:
class Professor: Owner<Student> { // ... } class Student: Ownee { let professor: Professor var owner: Owner<Student> { // error here (see below) return professor } init(professor: Professor) { self.professor = professor } }
However I get the following error on the definition of var owner
in the Student
class:
Protocol 'Ownee' requirement 'owner' cannot be satisfied by a non-final class ('Student') because it uses 'Self' in a non-parameter, non-result type position
I'm trying to understand what's the cause for this error, why making the class Student
final would fix it, and if there's some workaround to be able to model this differently, without making this class final. I've googled about that error, but haven't found much so far.
Protocol is a very powerful feature of the Swift programming language. Protocols are used to define a “blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality.”
It is just described as a methods or properties skeleton instead of implementation. Methods and properties implementation can further be done by defining classes, functions and enumerations. Conformance of a protocol is defined as the methods or properties satisfying the requirements of the protocol.
You can create objects from classes, whereas protocols are just type definitions. Try to think of protocols as being abstract definitions, whereas classes and structs are real things you can create.
Swift protocols on their side do not allow optional methods. But if you are making an app for macOS, iOS, tvOS or watchOS you can add the @objc keyword at the beginning of the implementation of your protocol and add @objc follow by optional keyword before each methods you want to be optional.
The Error is correct. You have to make your class final, since no subclasses could conform your protocol Ownee
.
Consider this subclass:
class FirstGradeStudent: Student { // inherited from parent // var owner: Owner<Student> { // return professor // } }
As you can see, it would have to implement var owner: Owner<Student>
because of his parent, but it should be implementing var owner: Owner<FirstGradeStudent>
instead, because the protocol contains var owner: Owner<Self> { get }
and in this case Self
would be FirstGradeStudent
.
Workaround
1: Define a superclass to Ownee
, it should be used by Owner
:
class Owner<T: OwneeSuper> { // ... } protocol OwneeSuper {} protocol Ownee: OwneeSuper { associatedtype T: OwneeSuper var owner: Owner<T> { get } }
OwneeSuper
is just a workaround to overcome this problem, otherwise we would just be using:
protocol Ownee { associatedtype T: Ownee var owner: Owner<T> { get } }
2. In classes that conform to Ownee
, you must turn the abstract type of the associatedtype
into a concrete class by defining a typealias
:
class Student: Ownee { typealias T = Student // <<-- define the property to be Owner<Student> let professor: Professor var owner: Owner<T> { return professor } init(professor: Professor) { self.professor = professor } }
3. Subclasses can now make use of the property, which will be of your defined type:
class FirstGradeStudent: Student { func checkOwnerType() { if self.owner is Owner<Student> { //warning: 'is' test is always true print("yeah!") } } }
What happens if Student
is subclassed? The owner property remains Owner<Student>
, but Student != StudentSubclass
.
By making your Student
class conform to the Ownee
protocol, you must satisfy the contract of the protocol. The Ownee
protocol states that Owner
has type constraint, such that the Owner
generic type is the type that's conforming to Ownee
(Student
, in this case).
If the compiler were to allow subclassing (i.e. by allowing you to not make Student
final), then it would be possible for a StudentSubclass
to exist. Such a subclass would inherit the Owner
property, of type Owner<Student>
, but Student
is not the same as StudentSubclass
. The Ownee
protocol's contract has been breached, thus, such a subclass cannot be allowed to exist.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With