Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementation conflicts between protocols

I've stumbled upon an issue, and I can not figure out how am I going to solve it.

Let's suppose we have a base class (that may comes from FrameworkA), with a property named subject:

public class MyClass {
    public var subject: String
}

And we have a protocol (that may comes from FrameworkB), with another property but with the same name:

public protocol MyProtocol {
    var subject: String { get }
}

Those two properties represent totally different things.

How can I create a class that inherits from MyClass and implements MyProtocol? And how can I use these properties?

public class SecondClass: MyClass, MyProtocol {
    var MyProcotol.name: String { // <==== Obviously not allowed
        return "something"
    }
    var MyClass.name: String { // <==== Obviously not allowed
        return "something else"
    }
}

I think that C# allows some kind of declaration like this, but I'm not 100% sure...

like image 669
BPCorp Avatar asked Apr 30 '15 11:04

BPCorp


2 Answers

If you have control over this base class and/or the protocol, you can give the properties unique names and that solves the problem.

If you cannot do that, the question becomes whether SecondClass really has to fulfill these two conflicting responsibilities itself. Specifically, what is MyProtocol? Some delegate protocol? You could instead have SecondClass vend a separate object that conforms to that protocol, eliminating the conflicting dual roles.

Bottom line, rather than having a single object attempt serve two conflicting purposes, split the responsibilities into separate objects resolving any such conflict.

like image 57
Rob Avatar answered Sep 27 '22 20:09

Rob


Ok, for a moment let's look at the problem from the point of view of the code that does use these classes and let's ignore how they are implemented.

Fact 1

If secondClass : SecondClass extends MyClass then I expect to be able to write:

secondClass.subject

Fact 2

If secondClass conforms to MyProtocol then I expect to be able to write

secondClass.subject

If we create a different way for secondClass to expose MyClass.subject and MyProtocol.subject we are breaking the Object Oriented Paradigm.

Infact

  1. When you extend a class, you implicitly inherit the all non private properties and methods, you cannot (and this is a good thing) rename them.
  2. When you conform to a protocol you expose all the non optional declared properties and methods exactly as they are described in the protocol

If SecondClass renamed the 2 properties like in your pseudo-code, we would not be able to write something like this.

let list : [MyClass] = [MyClass(), SecondClass()]

for elm in list {
    println(elm.subject)
}

A possible (partial) solution

You should avoid the is-a approach in favor of the has-a.

class SecondClass {
    let myClass : MyClass
    let somethingElse : MyProtocol

    init(myClass : MyClass, somethingElse:MyProtocol) {
        self.myClass = myClass
        self.somethingElse = somethingElse
    }

    var myClassSubject : String { get { return myClass.subject } }
    var myProtocolSubject : String { get { return somethingElse.subject } }
}

Now since

  1. SecondClass is not a MyClass and
  2. SecondClass is not a MyProtocol

It has not the subject property removing any risk of confusion.

Hope this helps.

like image 41
Luca Angeletti Avatar answered Sep 27 '22 21:09

Luca Angeletti