10

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...

Luca Angeletti
  • 58,465
  • 13
  • 121
  • 148
BPCorp
  • 780
  • 2
  • 6
  • 16
  • 3
    You need to name things accordingly. If they are different you need different names. – qwerty_so Apr 30 '15 at 12:03
  • Yes, of course :) But, what if I can't do anything about it, for example, the base class and the protocol are part of some frameworks (even separate frameworks) ? – BPCorp Apr 30 '15 at 13:02
  • 1
    @ThomasKilian I disagree with you, it is a very good question, the solution isn't set the name of the things accordingly always, things like this can be happen and the language(compiler) must be have a solution – Victor Sigler Apr 30 '15 at 13:11
  • Ok, so to fix the problem you send a bug report to Apple and wait a few years. That's not helping. What helps is if anyone declaring a protocol uses sensible names, and then you name your methods accordingly. – gnasher729 Apr 30 '15 at 14:00
  • Yep, framework developers should use sensible names. But app developers also should stop having single classes trying to achieve too many disparate (and in this case conflicting) purposes. – Rob Apr 30 '15 at 14:21
  • @VictorSigler I did not say it's a bad question. I was just telling it's not possible with Swift. – qwerty_so Apr 30 '15 at 14:22

2 Answers2

3

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.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
1

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.

Luca Angeletti
  • 58,465
  • 13
  • 121
  • 148
  • @Victor Sigler: thank you for the better formatting! – Luca Angeletti Apr 30 '15 at 14:12
  • I like your answer, but I think Apple need to correct this in future releases of Swift, because the compiler must be know how to deal with this kind of situations. – Victor Sigler Apr 30 '15 at 14:15
  • 2
    The problem here is that we are dealing with a conceptual constraint related to OOP. I really don't how the language itself could be changed to manage this kind of scenario. – Luca Angeletti Apr 30 '15 at 18:12
  • The original proposal for traits [Traits: Composable Units of Behaviour](http://scg.unibe.ch/archive/papers/Scha03aTraits.pdf) describes tools for such conflict resolutions which include *alias* and *exclusion* of methods (see 3.5 Conflict Resolution). Might be interested to you ;) – kean Dec 18 '15 at 14:03