Search code examples
iosswiftgenericscurryingpartial-application

Partial function application with generics


I'm working with an Observer API (ObserverSet) which have the following function :

public func add<T: AnyObject>(object: T, _ f: T -> Parameters -> Void) -> ObserverSetEntry<Parameters>

It simply register an object then call the instance method f on the object when notification triggers

In one of my manager, I need to hide the previous function with one of mine so I can force an observer to call a predefine function implemented via a protocol.

Here's what I've done so far :

@objc protocol Observer : NSObjectProtocol {
    func observe(param: String) -> Void
}

func addObserver<T: AnyObject where T: Observer>(observer: T) {
    let f: T -> String -> Void = observer.dynamicType.observe
    entries.addObserver(observer, f)
}

Unfortunately, I have the following error showing up Partial application of generic method is not allowed

I've found a possible workaround somewhere on SO which look like that :

let f: T -> String -> Void = { (obs: T) in obs.dynamicType.observe(obs) }

But this line of code drives my XCode crazy with some Segmentation Fault: 11 on compilation (and Communication interrupted with Playground ..)

Is there any workaround for what I'm trying to do ?


Solution

  • I haven't tested but you can try:

    @objc protocol Observer : NSObjectProtocol {
        func observe(param: String) -> Void
    }
    
    func addObserver<T: AnyObject where T: Observer>(observer: T) {
        let f: T -> String -> Void = { ($0 as AnyObject).observe }
        entries.addObserver(observer, f)
    }
    

    At least, this compiles because AnyObject has all methods from ObjC - including @objc - classes/protocols, as ImplicitlyUnwrappedOptional.

    So, this compiles:

    let str = NSString(string: "test")
    (str as AnyObject).observe("foo")
    

    Of course this causes runtime error because NSString has no observe(_:) method. But, in your case, T is guaranteed to be Observer, it should works.