Extend Int enum with comparison operators - swift

Very often you have Int enums like this:
enum Difficulty: Int {
case Easy = 0
case Normal
case Hard
}
Difficulty values have a certain meaning and we may want to introduce order for them. For example, somewhere we need to compare:
let isBonusAvailable = level.difficulty.rawVAlue <= Difficulty.Hard.rawValue
I want to make this code a little bit shorter:
let isBonusAvailable = level.difficulty <= .Hard
It can be easily achieved if I add <= directly to the Difficulty. But I wanted to solve this problem in general, so I tried this super-tricky way:
protocol RawRepresentableByInt {
var rawValue: Int { get }
}
extension RawRepresentableByInt {
static func <(lhs: RawRepresentableByInt, rhs: RawRepresentableByInt) -> Bool {
return lhs.rawValue < rhs.rawValue
}
static func >(lhs: RawRepresentableByInt, rhs: RawRepresentableByInt) -> Bool {
return lhs.rawValue > rhs.rawValue
}
static func <=(lhs: RawRepresentableByInt, rhs: RawRepresentableByInt) -> Bool {
return lhs.rawValue <= rhs.rawValue
}
static func >=(lhs: RawRepresentableByInt, rhs: RawRepresentableByInt) -> Bool {
return lhs.rawValue >= rhs.rawValue
}
}
// Error: Extension of protocol 'RawRepresentable' cannot have an inheritance clause
extension RawRepresentable: RawRepresentableByInt where RawValue == Int {
}
It produces a compiler error:
Error: Extension of protocol 'RawRepresentable' cannot have an inheritance clause
I think there is nothing unimplementable in comparison of Int enum in term of logic. Please, help me to trick the Swift compiler. Anyone, who also need such extensions may participate.

It was easier than I thought. So, basically you can use Self instead of creating an additional protocol.
enum Difficulty: Int {
case Easy = 0
case Normal
case Hard
}
extension RawRepresentable where RawValue: Comparable {
static func <(lhs: Self, rhs: Self) -> Bool {
return lhs.rawValue < rhs.rawValue
}
static func >(lhs: Self, rhs: Self) -> Bool {
return lhs.rawValue > rhs.rawValue
}
static func <=(lhs: Self, rhs: Self) -> Bool {
return lhs.rawValue <= rhs.rawValue
}
static func >=(lhs: Self, rhs: Self) -> Bool {
return lhs.rawValue >= rhs.rawValue
}
}
let easy = Difficulty.Easy
print(easy > .Hard) // false

Related

operator '<' declared in type 'XXX' must be 'static'

I have the following implementation and also added Comparable extension as follows. But I am getting the following error. I wonder how I could able to fix it.
error: operator '<' declared in type 'Item' must be 'static'
func < (lhs: Item, rhs: Item) -> Bool {
^
static
class Item
{
var timeStamp : Date
var value : Int
init(_ value: Int)
{
self.value = value
self.timeStamp = Date()
}
}
extension Item: Comparable
{
func < (lhs: Item, rhs: Item) -> Bool {
return lhs.timeStamp < rhs.timeStamp
}
func == (lhs: Item, rhs: Item) -> Bool {
return lhs.timeStamp == rhs.timeStamp
}
}
The Comparable protocol requires that the < operator implementation is static. It is documented here. You could fix your code by adding the static keyword like so:
static func < (lhs: Item, rhs: Item) -> Bool {
return lhs.timeStamp < rhs.timeStamp
}

generics struct implementing protocol with associated type

I am a bit stuck trying to define a container for my ui elements.
As I wanted something that encapsulates a non unique label, a value that can be any comparable object and a concept of being the preferred option I came up with the following protocol:
protocol OptionProtocol:Comparable {
associatedtype Key:Comparable
associatedtype Value:Comparable
var key:Key { get set }
var value:Value { get set }
var main:Bool { get set }
static func <(lhs: Self, rhs: Self) -> Bool
static func ==(lhs: Self, rhs: Self) -> Bool
}
extension OptionProtocol {
static func <(lhs: Self, rhs: Self) -> Bool {
let equalKeys = lhs.key == rhs.key
return equalKeys ? lhs.value < rhs.value : lhs.key < rhs.key
}
static func ==(lhs: Self, rhs: Self) -> Bool{
return (lhs.value == rhs.value) && (lhs.key == rhs.key)
}
}
Now I want to implement the protocol in a generic struct and I cant figure out how. What I want to do is
struct Option<Key, Value>: OptionProtocol {
var key:Key
var value:Value
var main:Bool
}
But the compiler complains that Type 'Option<Key, Value>' does not conform to protocol 'OptionProtocol'
Any pointer would be helpful
The answer was pretty simple. I needed to constraint Key and Value in the struct.
The following struct compiles as expected
struct Option<Key, Value>:OptionProtocol where Key:Comparable, Value:Comparable {
var key:Key
var value:Value
var main:Bool
}

The right way to extend OptionSet with a constrained RawValue

I have an OptionSet for which I wanted to be able to perform bitwise operations (the operations in the BitwiseOperation protocol). I wrote an extension to my type, then realized I should make it reusable code. It took a while to figure out a way, and what I did was make a protocol that inherits from both protocols and adds a constraint on the associated type, then a protocol extension providing default implementations.
It works, but my question is this: Is this the best way to accomplish this?
protocol BitwiseOptionSet : BitwiseOperations, OptionSet {
associatedtype RawValue : BitwiseOperations, ExpressibleByIntegerLiteral
}
extension BitwiseOptionSet {
static var allZeros : Self {
return Self(rawValue: 0)
}
prefix static func ~(x: Self) -> Self {
return Self(rawValue: ~x.rawValue)
}
static func ^(lhs: Self, rhs: Self) -> Self {
return Self(rawValue: lhs.rawValue ^ rhs.rawValue)
}
static func &(lhs: Self, rhs: Self) -> Self {
return Self(rawValue: lhs.rawValue & rhs.rawValue)
}
static func |(lhs: Self, rhs: Self) -> Self {
return Self(rawValue: lhs.rawValue | rhs.rawValue)
}
}
You can extend OptionSet with a constraint on its RawValue:
extension OptionSet where RawValue: BitwiseOperations {
static var allZeros : Self {
return Self(rawValue: .allZeros)
}
prefix static func ~(x: Self) -> Self {
return Self(rawValue: ~x.rawValue)
}
static func ^(lhs: Self, rhs: Self) -> Self {
return Self(rawValue: lhs.rawValue ^ rhs.rawValue)
}
static func &(lhs: Self, rhs: Self) -> Self {
return Self(rawValue: lhs.rawValue & rhs.rawValue)
}
static func |(lhs: Self, rhs: Self) -> Self {
return Self(rawValue: lhs.rawValue | rhs.rawValue)
}
}
Note that requiring a conformance to ExpressibleByIntegerLiteral
can be avoided by using Self(rawValue: .allZeros) instead of
Self(rawValue: 0).
Example:
struct MyOptionSet: OptionSet {
let rawValue: UInt16
init(rawValue: UInt16) {
self.rawValue = rawValue
}
}
let a = MyOptionSet(rawValue: 3)
let b = MyOptionSet(rawValue: 5)
let c = a & b
print(c.rawValue) // 1

Using a generic protocol type inside of another generic protocol type

I'm trying to figure out how to use a protocol that has a Self or associated type requirement inside of another protocol. Consider the following example:
protocol SortBy {
static var values: [Self] { get }
var title: String { get }
}
protocol Filter {
var sortBy: SortBy { get set }
init(_ filter: Self)
static func == (lhs: Self, rhs: Self) -> Bool
static func != (lhs: Self, rhs: Self) -> Bool
}
I know that since SortBy contains a reference to Self, I can only use it as a generic constraint. What I don't know is if there is any Swift magic I can do to allow what I'm trying to achieve?
Ultimately I want to use the protocols for an example as follows:
enum Sort: SortBy {
case sort1
case sort2
static var values: [Sort] {
return [
.sort1,
.sort2
]
}
var title: String {
switch self {
case .sort1:
return "Sort 1"
case .sort2:
return "Sort 2"
}
}
}
struct FilterExample: Filter {
var sortBy: SortBy
init(_ filter: FilterExample) {
...
}
static func == (lhs: FilterExample, rhs: FilterExample) -> Bool {
...
}
static func != (lhs: FilterExample, rhs: FilterExample) -> Bool {
...
}
}
And in case it matters, I'm using Swift 3.
Thanks for the help in advance.
associatedTypes and generics should be able to get what you want. That said, you should take a look at the Equatable and Comparable protocols. It looks like you're trying to do something related and adoption of those may help you. E.g. adoption of Equatable means you only have to implement == and you get != for free.
protocol SortBy {
static var values: [Self] { get }
var title: String { get }
}
protocol Filter {
associatedtype SortByType: SortBy
var sortBy: SortByType { get set }
init(_ filter: Self)
static func == (lhs: Self, rhs: Self) -> Bool
static func != (lhs: Self, rhs: Self) -> Bool
}
struct FilterExample<T: SortBy>: Filter {
var sortBy: T
init(_ filter: FilterExample<T>) {
self.sortBy = filter.sortBy
}
static func == (lhs: FilterExample, rhs: FilterExample) -> Bool {
return true
}
static func != (lhs: FilterExample, rhs: FilterExample) -> Bool {
return true
}
}

Nested Swift class can't conform to Comparable

I am trying to implement a simple array based heap but running into issues with the nested Node class. I would like my nodes to be comparable, however, the compiler is complaining that the node class doesn't conform.
import Foundation
class Heap<E:Comparable> {
var heap = Array<Node<E>>()
init() { }
class Node<E:Comparable >:Comparable {
var key:E!
init(key:E) { self.key = key }
}
}
func < <E> (lhs:Heap<E>.Node<E>, rhs:Heap<E>.Node<E>) -> Bool {
return lhs.key < rhs.key }
func == <E> (lhs:Heap<E>.Node<E>, rhs:Heap<E>.Node<E>) -> Bool {
return lhs.key == rhs.key }
It complains because of the Node class doesn't conform the Comparable protocol.
protocol Comparable : _Comparable, Equatable {
func <=(lhs: Self, rhs: Self) -> Bool
func >=(lhs: Self, rhs: Self) -> Bool
func >(lhs: Self, rhs: Self) -> Bool
}
And one more thing, if you want to use the self.key to compare, then the type should conform Comparable protocol as well. Here's the sample:
class Node<E where E:Comparable>:Comparable {
var key:E!
init(key:E) { self.key = key }
}
func ==<E>(lhs: Node<E>, rhs: Node<E>) -> Bool {
return lhs.key == rhs.key
}
func <<E>(lhs: Node<E>, rhs: Node<E>) -> Bool {
return lhs.key < rhs.key
}