Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write Swift generic functions of enum types?

Using Swift, I want to write a protocol that specifies that implementing classes must have a function that takes an enum (which adheres to a given protocol), where that enum type is specified generically. I've tried this:

protocol Message {}

protocol Subscriber {
  func receive<T where T:Message>(message:T)
}

enum Greeting : Message {
  case Hello, Goodbye
}

class SomeObject : Subscriber {
  func receive<Greeting>(message: Greeting) {
    switch message {
    case .Hello:
      println("Hello")
    case .Goodbye:
      println("Goodbye")
    }
  }
}

This fails to compile with the message "Enum case pattern cannot match values of the non-enum type 'Greeting'" at each of the case lines. This would appear to be because the Subscriber protocol expects something that is no more specialized than Message, but I set things up in terms of Greeting, which though it implements Message, is more specialized. (Am I right?)

So, how do I do what I'm attempting to do, please?

like image 816
Chris Avatar asked Aug 14 '14 15:08

Chris


1 Answers

The generic type parameter T should still be generic in the implementation of Subscriber. You can do what you ask using a typealias in protocol Subscriber and enforce the Message superclass constraint on it:

protocol Message {}

protocol Subscriber {
    typealias MessageType: Message
    func receive (message: MessageType)
}

enum Greeting : Message {
    case Hello, Goodbye
}

class SomeObject : Subscriber {
    typealias MessageType = Greeting

    func receive (message: MessageType) {
        switch message {
        case .Hello:
            println("Hello")
        case .Goodbye:
            println("Goodbye")
        }
    }
}

Having a generic receive prevents you from switching on the enum fields:

protocol Message {}

protocol Subscriber {
    func receive <T: Message> (message: T)
}

enum Greeting : Message {
    case Hello, Goodbye
}

class SomeObject : Subscriber {
    func receive <T: Message> (message: T) {

    }
}

let obj = SomeObject()
obj.receive(Greeting.Hello)
like image 175
pNre Avatar answered Sep 28 '22 01:09

pNre