Genericitzing closures based on paramter-list/return type


(G B) #1

Is there a way to make a generic type signature for a closure such that I can later call it generically? In particular my question is how to deal with an unknown number of arguments.

I have an object that I’d like to call a series of closures on an update, and I’d like other objects to be able to register closures that they’d like to be called with that first object.

Closures aren’t hashable, but I’d like to be able to also unregister a closure, so I wound up creating a custom type to handle this based on a dictionary:

//T is the closure signature such as Double->()
struct BlockCollection<T> : SequenceType {
    private var idx=0
    var blockDict:[Int:T]=[:]

    mutating func addBlock(b:T) -> Int {
        blockDict[idx]=b
        idx+=1
        return idx-1
    }

    mutating func dropBlock(k:Int) {
        blockDict.removeValueForKey(k)
    }

    func generate() -> AnyGenerator<T> {
        var dgen=blockDict.generate()
        return AnyGenerator {
            return dgen.next()?.1
        }
    }
}

This was some of the earliest Swift code I’d written, so looking back at it I can see room for improvement (including the type name), but it gets the job done.

This lets me use the collection in code like this:

Declare it:

private var stateCallbacks=BlockCollection<State<EngineType> -> ()> ()

Use it:

for b in stateCallbacks {
    b(newValue!)
}

So far, all’s good. Now, I’d like to extend this idea to where I can ask the collection to run the for loop itself using syntax something like

stateCallbacks.runAllWith(newValue!)

I suspect that can be done if I know the blocks accept one argument and return one argument by using two type placeholders, say T for the argument and U for the return value.

What I don’t seem able to do is make this generic across an unknown number of parameters. The type I’m creating doesn’t care what the structure of the block is, it just wants to accept closures with a certain signature and then provide a mechanism to call them by exposing an API that depends on the closure signature.

For example, if I had a collection of closures with a signature such as `(Double, Double) -> ()`, I would want to be able to call the elements with `callbacks.runAllWith(d1,d2)`.

I don’t think there’s support for variadic generic parameters, so I can’t go down that road.

Is there a way to do this without requiring the caller to bundle arguments into a tuple and then requiring a wrapper around each closure to unwrap a tuple of arguments and do a hand-crafted tuple splat?

Thanks—
Greg