How to assign the value of a switch statement to a variable

How many times have you written this kind of code?

  var ratingView: NSView = NSView()
  
  switch rating
  {
    case .zero:
      ratingView = self.ratingBox.zeroDot
    case .one:
      ratingView = self.ratingBox.oneStar
    case .two:
      ratingView = self.ratingBox.twoStar
    case .three:
      ratingView = self.ratingBox.threeStar
    case .four:
      ratingView = self.ratingBox.fourStar
    case .five:
      ratingView = self.ratingBox.fiveStar
  }
    
  // use ratingView

Having to declare a redundant default value before an exhaustive switch statement that is always going to overwrite it.

So, I thought, why not use an anonymous closure?

  let ratingView: NSView =
  {
    switch rating
    {
      case .zero:
        return self.ratingBox.zeroDot
      case .one:
        return self.ratingBox.oneStar
      case .two:
        return self.ratingBox.twoStar
      case .three:
        return self.ratingBox.threeStar
      case .four:
        return self.ratingBox.fourStar
      case .five:
        return self.ratingBox.fiveStar
    }
  }()
    
  // use ratingView

No more redundancy :grinning:

Note that, even without the closure, the initial value is unnecessary. You can write:

let ratingView: NSView

switch rating
  {
    case .zero:
      ratingView = self.ratingBox.zeroDot
    case .one:
      ratingView = self.ratingBox.oneStar
    case .two:
      ratingView = self.ratingBox.twoStar
    case .three:
      ratingView = self.ratingBox.threeStar
    case .four:
      ratingView = self.ratingBox.fourStar
    case .five:
      ratingView = self.ratingBox.fiveStar
  }

and the compiler will require that ratingView is bound before reading from it.

8 Likes

Well! You learn something new every day :grin:

Thanks Joe :smiling_face_with_three_hearts:

1 Like

There is a pitch for this: if/else expression, switch/case expression

You can reduce the redundancy even more by using a ResultBuilder:

let ratingView: NSView = eval {
    switch rating {
    case .zero:
        self.ratingBox.zeroDot
    case .one:
        self.ratingBox.oneStar
    case .two:
        self.ratingBox.twoStar
    case .three:
        self.ratingBox.threeStar
    case .four:
        self.ratingBox.fourStar
    case .five:
        self.ratingBox.fiveStar
    }
}

Doesn't work with dot-syntax unfortunately.

Implementation
func eval<V>(@SingleValueBuilder<V> _ value: () -> V) -> V {
    value()
}

@resultBuilder
enum SingleValueBuilder<V> {
    static func buildEither(first component: V) -> V {
        component
    }
    static func buildEither(second component: V) -> V {
        component
    }
    static func buildBlock(_ components: V) -> V {
        components
    }
}

13 Likes