3

I am trying to migrate the Visitor pattern from my (old) java code to swift. So far I have a generic FIFO (working fine).

protocol FiFo {
    associatedtype U
    func enqueue(_ : U)
    func dequeue() -> U
}

I also want to tell the instance of the FIFO only to accept an instance of a visitor that uses the same type for the generic as the instance of the FIFO.

protocol Visitor {
    associatedtype T
    func processValue(_ value : T)
}
protocol FiFo {
    associatedtype U
    func enqueue(_ : U)
    func dequeue() -> U
    func visit(_ visitor : Visitor<U>)
}

Here I am facing:

Cannot specialize non-generic type 'Visitor'

Any hints? Thanks!

RTXGamer
  • 3,215
  • 6
  • 20
  • 29
Thomas
  • 35
  • 5
  • 2
    Generics and associated types are two different things. – vadian Aug 19 '21 at 16:10
  • Thanks for your answers - I would love to mark both helpful. And thanks for the general hint that there is a difference between generics vs associated types (in swift). – Thomas Aug 19 '21 at 16:50
  • Does this answer your question? [How to create generic protocols in Swift?](https://stackoverflow.com/questions/24469913/how-to-create-generic-protocols-in-swift) – pkamb Aug 19 '21 at 17:30
  • 1
    @RTXGamer: Re your edit: The backticks are for `code`, not for general emphasis. “Visitor pattern” or ”fifo” is not code. – Martin R Aug 19 '21 at 17:32
  • @pkamb: I've found that other question, but I wasn't sure at all how to apply that solution to the problem of two protocols. The part when `where` comes in was not that clear to me in the other post. – Thomas Aug 19 '21 at 17:53

2 Answers2

3

You can add a constraint to an associated type:

protocol Visitor {
    associatedtype T
    func processValue(_ value : T)
}

protocol FiFo {
    associatedtype U
    associatedtype V: Visitor where V.T == U
    func enqueue(_ : U)
    func dequeue() -> U
    func visit(_ visitor: V)
}
Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • Sorry, I had not seen your answer appearing. Now I wonder if there is a difference between our suggestions or if they are equivalent. – Martin R Aug 19 '21 at 16:17
  • 3
    @MartinR - No worries. Re differences b/w generic and associated type, it is the standard homogeneous vs heterogeneous issues: E.g., should there be more than one `FiFo` method that takes a `Visitor`, having multiple methods with `where V.T == U`, they don’t necessarily need to be the same type, whereas associated type can enforce that). If it really is only one generic method with `Visitor`, your generic pattern is more concise. – Rob Aug 19 '21 at 16:32
3

You can make the visit method generic: Accept any visitor whose associated type T is the fifo's type U:

protocol FiFo {
    associatedtype U
    func enqueue(_ : U)
    func dequeue() -> U
    func visit<V: Visitor>(_ visitor : V) where V.T == U
}
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382