0

I am defining a protocol that has certain functions and variables

protocol BaseListPresenter {
    associatedtype T
    var values: [T] {get}
}

extension BaseListPresenter {

    public func count() -> Int {
        return values.count
    }

    public func valueAtIndex(index: Int) -> T? {
        return values[index]
    }
}

Now, I want to use this in a class:

class X: UIViewController {
    var listPresenter: BaseListPresenter? // HERE it gives me error

    // some other functions and variables here
}

Got Error in above saying: Protocol 'BaseListPresenter' can only be used as a generic constraint because it has Self or associated type requirements

Now, I define sub-class of X:

class Y: X {
    func setPresenter() {
        self.listPresenter = UsersPresenter() // UsersPresenter confirms BaseListPresenter protocol with value's type "User"
    }
    // many more functions below
}

class Z: X {
    func setPresenter() {
        self.listPresenter = RoomsPresenter() // RoomsPresenter confirms BaseListPresenter protocol with value's type "Room"
    }
     // many more functions below
}

I have achieved solution from (Protocol can only be used as a generic constraint because it has Self or associatedType requirements) already by creating UsersPresenter and RoomsPresenter. However, I want to create BaseListPresenter type variable which will take different types of value in X (a UIViewController); once Room and next time User depending on subclass of X.

How can I solve this issue and use as I want?

Community
  • 1
  • 1
Bibek
  • 3,689
  • 3
  • 19
  • 28
  • Possible duplicate of [Protocol can only be used as a generic constraint because it has Self or associatedType requirements](http://stackoverflow.com/questions/36348061/protocol-can-only-be-used-as-a-generic-constraint-because-it-has-self-or-associa) – Scott Thompson May 03 '17 at 05:51
  • I have achieved that already by creating UsersPresenter and RoomsPresenter. However, I want to create BaseListPresenter type variable in X which will take different types of value once Room and next time User depending on subclass of X. – Bibek May 03 '17 at 06:10
  • I have an instance of Class Y. What data type is `my_y.listPresenter.values[0]`? If I had an instance of class Z, what would be the data type of `my_z.listPresenter.values[0]`? in Class X what is the type of self.listPresenter.values[0]? Even if its understood in Y an Z its still ambiguous associatedType in X. So the use of `BaseListPresenter` is ambiguous much as described in that other question. – Scott Thompson May 03 '17 at 06:18
  • its User for my_y its Room for my_z – Bibek May 03 '17 at 06:49
  • can I make X understand type of associatedType of BaseListPresenter from its subclass Y and Z? – Bibek May 03 '17 at 06:50
  • right. It's ambiguous for every potential use case in class X an therefore is not type safe and is an error. – Scott Thompson May 03 '17 at 06:51
  • So, I cant achieve what I want to? Is there any other alternative way? – Bibek May 03 '17 at 06:58

1 Answers1

0

Problem is, that the associated type of your protocol has to be determined when the protocol is used somewhere. In your implementation of class X, the compilator has no idea, what type the T is.

I would implement it this way:

class X<TPresenter : BaseListPresenter>: UIViewController {
    var listPresenter: TPresenter? // HERE it gives me error

    // some other functions and variables here
}

Then specialize X when derive:

class Y: X<UsersPresenter> {
    func setPresenter() {
        self.listPresenter = UsersPresenter() // UsersPresenter confirms BaseListPresenter protocol with value's type "User"
    }
    // many more functions below
}

class Z: X<RoomsPresenter> {
    func setPresenter() {
        self.listPresenter = RoomsPresenter() // RoomsPresenter confirms BaseListPresenter protocol with value's type "Room"
    }
     // many more functions below
}

This construct works.

Note: Using generics in UIViewController derived classes caused me some troubles about an year ago. Xcode/compiler was somehow unable to link the generic controller with the scene in storyboard. It did not cause compile errors, but it did not work during runtime - spent hours of diagnosing.

Štěpán
  • 328
  • 3
  • 12