2

I am trying to implement the chain of responsibility pattern in Swift.

public class Chain<T, U> {
    private var command: (T?, (U?) -> Void) -> Void
    private var runCommand: (() -> Void)?
    private var nextCommand: ((U?) -> Void)?

    private init(command: (T?, (U?) -> Void) -> Void) {
        self.command = command
    }

    private func next(u: U?) {
        self.nextCommand?(u)
    }

    func then<V>(command: (U?, (V?) -> Void) -> Void) -> Chain<U, V> {
        let c = Chain<U, V>(command: command)

        self.nextCommand = { command($0, c.next) }
        c.runCommand = self.runCommand

        return c
    }

    func endWith(command: (U?) -> Void) {
        self.nextCommand = command
        self.runCommand!()
    }

    static func build<V>(command: ((V?) -> Void) -> Void) -> Chain<AnyObject, V> {
        let c = Chain<AnyObject, V>(command: { _, next in command(next) })
        c.runCommand = { command(c.next) }
        return c
    }
}

My class does not raise any compilation error but a simple use case (such as the one below) does not work. It raises the following error: error: cannot invoke 'endWith' with an argument list of type '((_?) -> ()) ; expected an argument list of type '((U?) -> Void)'

Any thought?

Chain.build { next in
    print("Foo")
    next("Bar")
}
.then { o, next in
    print(o)
    next(15)
}
.endWith { o in
    print(o)
}

I know it is an edge case of generics usage in Swift. However, as it is not possible to explicitly specialize a generic type, I have not found any solution so far.

Adrien Cadet
  • 1,311
  • 2
  • 15
  • 21

1 Answers1

3

The compiler isn't able to infer the types in your example. You just need to specify them where they're ambiguous:

Chain<String,Int>.build { next in
  print("Foo")
  next("Bar")
  }
  .then { (o: String?, next: Int? -> Void) in
    print(o)
    next(15)
  }
  .endWith { o in
    print(o)
}
oisdk
  • 9,763
  • 4
  • 18
  • 36
  • Thanks for you reply oisdk! Actually I found out typing the closures' arguments does not help at all. It was only due to the `build` method, for, in Swift, typing a generic is mandatory. Here is my full class, for people who are interested in: https://gist.github.com/acadet/dee9287e70c061a358b1 – Adrien Cadet Dec 08 '15 at 00:28