Home > Software design >  How to work around swift switch statement idiocy
How to work around swift switch statement idiocy

Time:07-20

A typical code that used to work fine in all C variants but somehow is no longer good enough in the brave new world of swift:

@Environment(\.colorScheme) var colorScheme
var body: some View
{
    var multiplier: CGFloat
    switch(colorScheme)
    {
    @unknown default:
        assertionFailure()
        fallthrough
    case .light:
        multiplier = 0.3
    case .dark:
        multiplier = 0.1
        fallthrough
    }

How would I rewrite this in such a fashion that swift compiler won't complain about?

As a stop gap measure I did

    switch(colorScheme)
    {
    case .light:
        multiplier = 0.3
    case .dark:
        multiplier = 0.1
    @unknown default:
        preconditionFailure()
    }

to satisfy the requirement that default comes last but this is obviously NOT the semantics that I want.

I want the code to bomb in debug builds and fallback onto dark o light case in release cases so that the code works in the field.

CodePudding user response:

You might try:

switch colorScheme {
case .dark:
    multiplier = 0.1
case .light:
    fallthrough
@unknown default:
    assertionFailure("unknown colorScheme \(colorScheme)")
    multiplier = 0.3
}

Although I personally think it would be more clear to use:

switch colorScheme {
case .dark:
    multiplier = 0.1
case .light:
    multiplier = 0.3
@unknown default:
    assertionFailure("unknown colorScheme \(colorScheme)")
    multiplier = 0.3
}

In the second example you don't use a fallthrough and thus break any dependency between what the .light state does and what the default future unknown colorScheme does (even though as of now it uses the same multiplier as the light scheme).

In the shop I work at it would be considered "Swiftier" (i.e. more expressive of intent and thus coded in the spirit with which Swift is designed) to write it in this latter fashion.

CodePudding user response:

Because defaults come last, common logic has to come afterwards…

let multiplier: Double = {
  switch colorScheme {
  case .light:
    break
  case .dark:
    return 0.1
  @unknown default:
    assertionFailure()
  }

  return 0.3
} ()

…or be defined early and referred to in later usage.

let multiplier: Double
let lightMultiplier = 0.3
switch colorScheme {
case .light:
  multiplier = lightMultiplier
case .dark:
  multiplier = 0.1
@unknown default:
  assertionFailure()
  multiplier = lightMultiplier
}
  • Related