update: as of Swift 1.2, there is another way to do this, as you can now defer assignment to let
.
Ever find yourself having to use var
when a let
would be better, because you’re having to choose between multiple options?
var direction: Direction switch (char) { case "a": direction = .Left case "s": direction = .Right default: direction = .Forward } var cry: String if direction == .Forward { cry = "To glory!" } else { cry = "Tum-tee-tum" }
Often you’ll see people declaring those var
s as optionals set to nil
, because they think you have to give it a value. This isn’t actually necessary – so long as the compiler can tell it will always be assigned to before it is used, as it is here, it’ll let you defer setting the value. But you still can’t use let
instead of var
.
Most people are aware of the ternary operator, that means you can replace the if
version with this:
let cry = direction == .Forward ? "To glory!" : "Tum-tee-tum"
But this doesn’t scale at all well with multiple choices:
// hours of code formatting enjoyment available making this look sensible let direction: Direction = char == "a" ? .Left : char == "s" ? .Right : .Forward
But don’t despair, there’s a better way! Just wrap your switch in a closure expression:
let direction: Direction = { // you could put "_ -> Direction in" here instead of // typing the let, if you prefer switch (char) { case "a": return .Left case "s": return .Right default: return .Forward } }() // call the expression immediately
There, both sanity and let
preserved.
Of course, it’d be nice if there were a version of switch
(and maybe even if
) that was an expression, so you didn’t need the closure. Especially if it meant Swift could fully infer the type for you (with the closure trick, you have to give the type).
So that’s on my letter to Father Christmas. What would be really nice would be something like this:
let direction = case(char) { when "a" { .Left } when "s" { .Right } otherwise { .Forward } }
Calling the outer keyword case
(and the default otherwise
) is lifted from LISP. This would help differentiate it from the switch
statement format, to avoid confusion and backwards-compatibility troubles. Ditching the :
and replacing it with braces seems more consistent with the rest of Swift syntax rather than sticking with a hangover from C.1 The blocks against the when
clauses could follow the same pattern as closures, i.e. automatically return if they’re single expressions.2 The compiler would need to detect when the clauses returned incompatible types and throw an error (the ternary operator behaves similarly).
Anyway, there’s a glass of sherry waiting for Santa if he visits.3 In the meantime, give the closure trick a go.
- This idea courtesy of @OldManKris ↩
- Maybe they should even be closures (and you could pass function names instead), not sure about this one. ↩
- I think the Swift dev team have posted on the forums acknowledging switches-as-expressions would be useful and that they’ll probably get to it some time. ↩