Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Default arguments in Swift enums

I make SnapOperationQueue which is an operation queue with a few extensions I like. One of them is reprioritisation of groups of operations. An operation is added with one of these four priorities (SnapOperationQueuePriority):

case Highest
case High
case Normal
case Low

In the current implementation I have it so that .Low and .Highest will not change, but .High and .Normal will.

I would like to change this so that I can have upper and lower thresholds on priorities. I.e, I can say that this operation that we might as well do now (.Low) can become super-important in a bit (.High) i.e. when pre-caching images and that image is all the sudden needed on screen. These thresholds should also be able to say that some operations, even in a group that is reprioritised, will not be reprioritised lower than something, i.e. a login operation (.Highest) should remain .Highest

To do this, I wanted to modify my enum like this:

case Highest(lowerThreshold: SnapOperationQueuePriority = .Highest)
case High(lowerThreshold: SnapOperationQueuePriority = .Low, higherThreshold: SnapOperationQueuePriority = .High)
case Normal(lowerThreshold: SnapOperationQueuePriority = .Low, higherThreshold: SnapOperationQueuePriority = .High)
case Low(higherThreshold: SnapOperationQueuePriority = .Low)

However, I get "Default argument not permitted in a touple type". The reason I want to have default arguments here is so that this change won't break or change behaviour of any code that is already using the existing implementation.

Can you suggest a way in which I can get my new priorities yet don't change the API for code that depends on the current API?

like image 912
niklassaers Avatar asked Mar 18 '16 08:03

niklassaers


People also ask

Can enums have default value?

The default value of an enum E is the value produced by the expression (E)0 . Without overriding the default values, printing default(E) returns Foo since it's the first-occurring element.

What is raw value in enum Swift?

Each raw value for our enum case must be a unique string, character, or value of any integer or floating-point type. This means the value for the two case statements cannot be the same.

Is enum value type in Swift?

Types in Swift fall into one of two categories: first, “value types”, where each instance keeps a unique copy of its data, usually defined as a struct, enum, or tuple. The second, “reference types”, where instances share a single copy of the data, and the type is usually defined as a class.

Can Swift enums have methods?

Swift's Enum can have methods. It can have instance methods and you can use it to return expression value for the UI. Let's look at the code above.


2 Answers

FYI: Default parameter values are now allowed after Swift 5.1. This answer only applies to versions of Swift before that.


This is a tricky one because you cannot have default values, you cannot have stored properties and you cannot repeat case names in enums. The best thing I can think to do is to create an init() and some semi-private cases.

enum SnapOperationQueuePriority {
    case Highest, High, Low, Default
}

enum SnapOperationQueue {
    case Highest, High, Normal, Low

    case _Highest(lowerThreshold: SnapOperationQueuePriority)
    case _High(lowerThreshold: SnapOperationQueuePriority, higherThreshold: SnapOperationQueuePriority)
    case _Normal(lowerThreshold: SnapOperationQueuePriority, higherThreshold: SnapOperationQueuePriority)
    case _Low(higherThreshold: SnapOperationQueuePriority)

    init(queue:SnapOperationQueue, lowerThreshold:SnapOperationQueuePriority = .Default, higherThreshold:SnapOperationQueuePriority = .Default) {
        switch queue {
        case .Highest:
            self = ._Highest(lowerThreshold: lowerThreshold == .Default ? .Highest : lowerThreshold)
        case .High:
            self = ._High(lowerThreshold: lowerThreshold == .Default ? .Low : lowerThreshold, higherThreshold: higherThreshold == .Default ? .High : higherThreshold)
        case .Normal:
            self = ._Normal(lowerThreshold: lowerThreshold == .Default ? .Low : lowerThreshold, higherThreshold: higherThreshold == .Default ? .High : higherThreshold)
        case Low:
            self = ._Low(higherThreshold: higherThreshold == .Default ? .Low : higherThreshold)
        default:
            self = queue

        }
    }
}

SnapOperationQueue.Normal
SnapOperationQueue(queue: .Normal)
SnapOperationQueue(queue: .High, lowerThreshold: .High, higherThreshold: .Highest)

This keeps old implementations valid and catches new ones made using init. In addition you might add a method like this to the enum:

func queue() -> SnapOperationQueue {
    switch self {
    case .Highest:
        return SnapOperationQueue(queue: .Highest)
    case .High:
        return SnapOperationQueue(queue: .High)
    case .Normal:
        return SnapOperationQueue(queue: .Normal)
    case Low:
        return SnapOperationQueue(queue: .Low)
    default:
        return self

    }

}

So that you can transform the old types of enum cases into the new, e.g. SnapOperationQueue.Normal.queue()

like image 152
sketchyTech Avatar answered Oct 20 '22 19:10

sketchyTech


This is now possible starting with Swift 5.1 (Xcode 11)

See the feature proposal.

like image 30
Gobe Avatar answered Oct 20 '22 19:10

Gobe