Swift Enumeration order and comparison
So long as you give your enum an underlying type, it’ll conform to the protocol RawRepresentable
.
This means you can write a generic comparison operator for any type that is raw representable, and has a raw type that is comparable, like so:
func <<T: RawRepresentable where T.RawValue: Comparable>(a: T, b: T) -> Bool {
return a.rawValue < b.rawValue
}
which will mean your enum will automatically have a <
operator:
enum E: Int { // this would work with Double and String also
// btw, no need to give a seed value of 0,
// that happens automatically for Ints
case A, B, C, D, E
}
E.A < E.C // returns true
The only bit of boilerplate you’ll still have to do is tag your enum as Comparable
in case you want to use it with generic algorithms that require that:
extension E: Comparable { }
// (no need for anything else - requirements are already fulfilled)
let a: [E] = [.C, .E, .A]
let b = sorted(a)
// b will now be [.A, .C, .E]
Making it conform to Comparable
will also give it <=
, >
, and >=
operators automatically (supplied by the standard library).
This is to some extent the same answer as the OP proposed himself. It does involve a bit of boilerplate code for every enum that you want to be comparable, but I prefer this than having some external magic function that provides comparable to all enums. That can cause problems if you do a quick copy-and-paste from one program to another, and then the enum doesn't work and you can't remember why.
public enum LogLevel: Int, Comparable {
case verbose
case debug
case info
case warning
case error
case severe
// Implement Comparable
public static func < (a: LogLevel, b: LogLevel) -> Bool {
return a.rawValue < b.rawValue
}
}
EDIT:
This is in response to a comment by @JasonMoore.
Comparable does not require ==. That is required by Equatable, and the Swift standard library automatically provides Equatable for most kinds of enums.
http://www.jessesquires.com/blog/swift-enumerations-and-equatable/
As for >, <= and >=, the Apple documentation says that they are required by Comparable, but that a default implementation is provided (based on use of == and <, I assume).
https://developer.apple.com/documentation/swift/comparable
Here's a bit of code that I ran in the IBM Swift Sandbox - it compiles and runs fine with the above definition.
let a : LogLevel = LogLevel.verbose
let b : LogLevel = LogLevel.verbose
let c : LogLevel = LogLevel.warning
print(a == b) // prints true
print(a > c) // prints false
print(a <= c) // prints true
In newer versions of Swift you can create a protocol to achieve this, without the need for generic globals. This also gives you the ability to choose which enums this affects.
/// Allows a raw enum type to be compared by the underlying comparable RawValue
public protocol RawComparable : Comparable where Self : RawRepresentable, RawValue: Comparable {
}
extension RawComparable {
public static func < (lhs: Self, rhs: Self) -> Bool {
return lhs.rawValue < rhs.rawValue
}
}
To use this it's as simple as adding the RawComparable protocol to the enum type:
enum EnumType : Int, RawComparable {
case First = 0, Second, Third
}