Mark A. Donohoe
Mark A. Donohoe

Reputation: 30348

Can you combine a type and a protocol and use that as the base type for an enum?

I have a particular pattern of using enums which are always of type String and which the enum (not its raw value) also adheres to a particular protocol. Written normally, this is like so...

private enum IndicatorA : String, IndicatorProtocol
{
    case X
    case Y
    case Z
}

What I'm trying to do is to find out if there's anything I can do to make the string implied so all I have to type is this...

private enum IndicatorA : Indicator
{
    case X
    case Y
    case Z
}

... where Indicator dictates the raw value is of type String and the enum itself also adheres to the IndicatorProtocol protocol.

I've tried both of these to come up with something to use as the raw value's type, but neither compiles. Plus, technically that puts the protocol on the string, not the enum, so that isn't what I'm after anyway. (Again, I want the protocol on the enum, not the raw value.)

class Indicator : String, IndicatorProtocol
{
}

struct Indicator : String, IndicatorProtocol
{
}

So is there any way to do what I'm trying to achieve in either Swift 2.x or 3.x? Perhaps with constraints on the protocol somehow?

Upvotes: 1

Views: 462

Answers (1)

Daniel Hall
Daniel Hall

Reputation: 13679

A couple thoughts on this:

Assuming it's possible to make the enum contain an Indicator as its raw value, it's important to note that this would not actually make the enum itself conform to the IndicatorProtocol, only its rawValue would conform. In other words:

enum IndicatorA : String, IndicatorProtocol

is not the same thing as:

enum IndicatorA : StringThatConformsToIndicatorProtocol

For the first example, you could access the protocol like this:

let example:IndicatorA = IndicatorA(rawValue:"Test")
example.someProtocolMethod()

For the second example, you would have to access the protocol like this:

let example:IndicatorA = IndicatorA(rawValue:"Test")
example.rawValue.someProtocolMethod()

because in the first example the enum itself is conforming to the protocol, but in the second example, the enum's raw value is conforming to the protocol.

All that said, you could sort of make the second example work by create an Indicator struct that conforms to StringLiteralConvertible, Equatable and your own IndicatorProtocol. Example:

protocol IndicatorProtocol {
    func printHello()
}

struct Indicator: IndicatorProtocol, StringLiteralConvertible, Equatable {
    let string: String
    init(name value: String) {
        self.string = value
    }

    init(stringLiteral value: String) {
        self.string = value
    }

    init(extendedGraphemeClusterLiteral value: String) {
        self.string = value
    }

    init(unicodeScalarLiteral value: String) {
        self.string = value
    }

    func printHello() {
        print("Hello from \(string)")
    }
}

func ==(left:Indicator, right:Indicator) -> Bool {
    return left.string == right.string

}

enum IndicatorA : Indicator {
    case One = "One", Two = "Two"
}

let test = IndicatorA.One

print(test.rawValue.printHello())   // prints "Hello from One

But that's a good bit of extra work to achieve a result that is not what I think you were hoping for in the first place!

Upvotes: 1

Related Questions