From SE-0192: Handling Future Enum Cases (emphasis mine):
When switching over a non-frozen
enum
, theswitch
statement that
matches against it must include a catch-all case (usuallydefault
or
an “ignore”_
pattern).switch excuse { case .eatenByPet: // … case .thoughtItWasDueNextWeek: // … }
Failure to do so will produce a warning in Swift 5. A program will
trap at run time if an unknown enum case is actually encountered.All other uses of enums (
if case
, creation, accessing members, etc)
do not change. Only the exhaustiveness checking of switches is
affected by the frozen/non-frozen distinction. Non-exhaustive switches
over frozen enums (and boolean values) will continue to be invalid in
all language modes.Here’s a more complicated example:
switch (excuse, notifiedTeacherBeforeDeadline) { case (.eatenByPet, true): // … case (.thoughtItWasDueNextWeek, true): // … case (_, false): // … }
This switch handles all known patterns, but still doesn’t account for
the possibility of a new enum case when the second tuple element is
true
. This should result in a warning in Swift 5, like the first
example.
@unknown
The downside of using a default case is that the compiler can no
longer alert a developer that a particular enum has elements that
aren’t explicitly handled in the switch. To remedy this,switch
cases will gain a new attribute,@unknown
.switch excuse { case .eatenByPet: // … case .thoughtItWasDueNextWeek: // … @unknown default: // … }
Like the regular default,
@unknown
default matches any value; it is
a “catch-all” case. However, the compiler will produce a warning if
all known elements of the enum have not already been matched. This is
a warning rather than an error so that adding new elements to the enum
remains a source-compatible change. (This is also why @unknown default
matches any value rather than just those not seen at compile-time.)
@unknown
may only be applied to default or a case consisting of the
single pattern _. Even in the latter case,@unknown
must be used
with the last case in a switch. This restriction is discussed further
in the “unknown patterns” section under “Future directions”.The compiler will warn if all enums in the pattern being matched by
@unknown are explicitly annotated as frozen, or if there are no enums
in the pattern at all. This is a warning rather than an error so that
annotating an enum as frozen remains a source-compatible change. If
the pattern contains any enums that are implicitly frozen (i.e.
because it is a user-defined Swift enum), @unknown is permitted, in
order to make it easier to adapt to newly-added cases.
@unknown
has a downside that it is not testable, since there is
no way to create anenum
value that does not match any known cases,
and there wouldn’t be a safe way to use it if there was one. However,
combining@unknown
with other cases using fallthrough can get the
effect of following another case’s behavior while still getting
compiler warnings for new cases.switch excuse { case .eatenByPet: showCutePicturesOfPet() case .thoughtItWasDueNextWeek: fallthrough @unknown default: askForDueDateExtension() }