1

I have a generic protocol, TwoWayBindDelegate, that uses the generic associated type to determine the parameters of the function twoWayBind()

protocol TwoWayBindDelegate: class {

    associatedtype BindType

    func twoWayBind(to observable: Observable<BindType>?, observableChanged: ((BindType) -> ())?)
}

I then created a class, Reactive<Base: UIView, Type> (which conforms to TwoWayBindDelegate) where you have to initialize it with the generic Base. For eg: let reactiveSlider = Reacive<UISlider>(slider).

My issue is when I am extending Reactive and conforming to TwoWayBindDelegate, I get an error Invalid redeclaration of 'BindType' because I am declaring BindType and twoWayBind() in both my extensions. Is there a way I can have both extensions provide different implementations for TwoWayBindDelegate

class Reactive<Base: UIView>: TwoWayBindDelegate {

    public var base: Base

    init(base: Base) {
        self.base = base
    }
}

extension Reactive where Base == UISlider {

    typealias BindType = Float        

    func twoWayBind(to observable: Observable<Float>?, observableChanged: ((Float) -> ())?) {
        // implement two way bind for UISlider
    }
}

extension Reactive where Base == UITextField {

    typealias BindType = String        

    func twoWayBind(to observable: Observable<String>?, observableChanged: ((String) -> ())?) {
        // implement two way bind for UITextField
    }
}

I did some research and found out that it may be a bug https://bugs.swift.org/browse/SR-5392. Does there happen to be a workaround

Nader
  • 1,120
  • 1
  • 9
  • 22
  • I'm using `BindType` so that the parameter in `twoWayBind()` can be of type `BindType`. So if `BindType` a String the parameter will be Observable. If I get rid of the associated type what would the parameters of the protocol function be of type? I don't have a whole lot of experience with generics so I correct me if i am wrong. – Nader May 31 '18 at 00:43
  • 1
    It seems to me that you have it backwards. If you say `Observable` in the declaration, we _know_ that BindType must be String; the generic is resolved. See my answer below and please correct _me_ if _I'm_ wrong. – matt May 31 '18 at 00:44

1 Answers1

2

I don't quite see what the typealias is for. The function declaration alone is sufficient to tell the compiler what BindType must be.

The problem I found with your code (apart from the missing Observable declaration, of course) is that the Reactive class itself doesn't conform to TwoWayBindDelegate. To get around that, I threw in an arbitrary implementation of twoWayBind. When I did, and when I deleted the unnecessary typealias declarations, your code compiled for me:

struct Observable<T> {}

protocol TwoWayBindDelegate: class {
    associatedtype BindType
    func twoWayBind(to observable: Observable<BindType>?, observableChanged: ((BindType) -> ())?)
}

class Reactive<Base: UIView>: TwoWayBindDelegate {
    public var base: Base
    init(base: Base) {
        self.base = base
    }
    func twoWayBind(to observable: Observable<Int>?, observableChanged: ((Int) -> ())?) {
    }
}

extension Reactive where Base == UISlider {
    func twoWayBind(to observable: Observable<Float>?, observableChanged: ((Float) -> ())?) {
    }
}

extension Reactive where Base == UITextField {
    func twoWayBind(to observable: Observable<String>?, observableChanged: ((String) -> ())?) {
    }
}


matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Thanks, works great! Just to be clear, the `twoWayBind()` declared in the base class only runs if `Base` is not a `UISlider` or `UITextField` right? – Nader May 31 '18 at 00:49
  • 1
    Try it and see! – matt May 31 '18 at 00:50
  • 1
    By the way, I should add that the problem you're having is in no small part due to the (in my opinion) extremely unfortunate secondary use of the reserved word `typealias` as a way to resolve explicitly a protocol generic `associatedtype`. I filed a bug report on this (rdar://24792823) but made no headway. – matt May 31 '18 at 01:13
  • @matt Hey Matt, can you give a look to this https://stackoverflow.com/q/66154789/1404324 maybe you can help me out. It seems my problem is relevant to this solution somehow. – Faruk Feb 12 '21 at 08:42