Jonathan.
Jonathan.

Reputation: 55544

Optional parameter in enum case in swift

In swift a function can have a optional parameters that have default values such as:

func f(a:Int, b:Int?=nil) {}

f(1);
f(1,2);

I'd like to do this with associated values with an enum. Following from this post about type safe url routes, I'd like to have a route which can take an optional parameter, such as:

enum StopPoint {
    case Search(query:String, limit:Int?=nil)
}

However it says I can't have an default value for a parameter in a tuple. However it is possible to have a case such as case Arrivals(stopId:Int), yet it is not possible in general to have a tuple with one named parameter.

So is it possible to have an enum with a default parameter, and is the associated value a tuple or not?

Upvotes: 20

Views: 17104

Answers (4)

Linus Unnebäck
Linus Unnebäck

Reputation: 24291

You can do this by creating static functions on the enum that matches the enum case that you want to allow optional parameters for.

enum StopPoint {
    case search(query: String, limit: Int?)

    static func search(query: String) -> StopPoint {
        return .search(query: query, limit: nil)
    }
}

This makes it so that you can both provide the limit, or not, using the expected syntax:

let a = StopPoint.search(query: "Foobar")
let b = StopPoint.search(query: "Foobar", limit: 5)
let c = StopPoint.search(query: "Foobar", limit: nil)

func foo(_ stop: StopPoint) { /* ... */ }

foo(.search(query: "Foobar"))
foo(.search(query: "Foobar", limit: 5))
foo(.search(query: "Foobar", limit: nil))

Tested and confirmed working with Swift 4.2

Upvotes: 14

0x416e746f6e
0x416e746f6e

Reputation: 10136

What you can do is:

enum StopPoint {
    case Search(query: String, limit: Int?)

    init(query: String, limit: Int? = nil) {
        self = .Search(query: query, limit: limit)
    }
}

let foo = StopPoint(query: "default")             // Search("default", nil)
let bar = StopPoint(query: "special", limit:  42) // Search("special", Optional(42))

Upvotes: 14

Michael Welch
Michael Welch

Reputation: 1784

Perhaps you have already considered this and discounted it: You can come close to the convenience of what you are looking for by creating a static func on the enum:

enum StopPoint {
    case Search(query:String, limit:Int?)

    static func createSearch(query:String, limit:Int?=nil) -> StopPoint {
        return .Search(query: query, limit: limit)
    }
}

let myStopPoint = StopPoint.createSearch("my query")

Upvotes: 3

luk2302
luk2302

Reputation: 57114

I do not think that is possible. It is simply a neat feature of functions. Nothing that the actual tuple underneath supports. The docs for Default Parameter Values state:

You can define a default value for any parameter in a function by assigning a value to the parameter after that parameter’s type. If a default value is defined, you can omit that parameter when calling the function.

Enums simply do not to have that feature. You have to explicitly use a different enum element for including optional additional parameters:

enum StopPoint {
    case Search(String)
    case SearchLimit(String, Int)
}

Enums are quite powerful but not thaaaat powerful. You cannot use default values, you can for example not use a variadic type (maybe even more "restrictions"):

enum StopPoint {
    case SearchMult(String...) // causes compile error
}

As to the potentially interesting of the "why"-question: no idea, I am not that deeply involved in the language architecture.

Upvotes: 5

Related Questions