16

I'd like to share some enum properties. Something like:

enum State {
  case started
  case succeeded
  case failed
}

enum ActionState {
  include State // what could that be?
  case cancelled
}

class Action {
  var state: ActionState = .started

  func set(state: State) {
    self.state = state
  }

  func cancel() {
    self.state = .cancelled
  }
}

I see why ActionState can not inherit from State (because the state cancelled has no representation in State) but I want to still be able to say "ActionState is like State with more options, and ActionState can get inputs that are of type State, because they are also of type ActionState"

I see how I could get the above logic to work with copying the cases in ActionState and having a switch in the set function. But I'm looking for a better way.

I know enum can't inherit in Swift, and I've read the protocol answer of swift-enum-inheritance. It doesn't address the need for "inheriting" or including cases from another enum, but only properties and variables.

Community
  • 1
  • 1
Guig
  • 9,891
  • 7
  • 64
  • 126
  • Possible duplicate of [Swift enum inheritance](http://stackoverflow.com/questions/33191532/swift-enum-inheritance) – Jim Stewart Nov 17 '16 at 21:41
  • 1
    Read a bit down in the answers. There's a decent workaround for the lack of a direct way. – Jim Stewart Nov 17 '16 at 21:42
  • Not sure. The workaround uses a protocol to make the enum inherit properties / functions from the protocol, but I can't see how to use that to have the enum inherit cases (whatever inherit would be here) from another enum – Guig Nov 17 '16 at 21:53
  • It looks like ultimately the answer is no. To me this sounds very much like a clear case of needing to use a class instead of enum - when you truly need inheritance. –  Nov 17 '16 at 23:52
  • I don't need inheritance as much as inclusion, whatever that might be. Inheritance would actually not make sense because, assuming those were classes, the `cancelled` state would have no equivalent in the `State` scope. In other words `ActionState` is not always representable as `State`, while the contrary is true (but it'd be really weird to have `State` inherit from `ActionState`) I take your point that the ultimate answer is probably no – Guig Nov 18 '16 at 21:41

2 Answers2

29

Details

  • Swift 4, 3
  • Xcode 10.2.1 (10E1001), Swift 5 (Last revision of this post)

Solution

enum State {
    case started, succeeded, failed
}

enum ActionState {
    case state(value: State), cancelled
}

class Action {
    var state: ActionState = .state(value: .started)
    func set(state: State) { self.state = .state(value: state) }
    func cancel() { state = .cancelled }
}

Full Sample

Do not to forget to paste the solution code

import Foundation

extension Action: CustomStringConvertible {
    var description: String {
        var result = "Action - "
        switch state {
            case .state(let value): result += "State.\(value)"
            case .cancelled: result += "cancelled"
        }
        return result
    }
}

let obj = Action()
print(obj)
obj.set(state: .failed)
print(obj)
obj.set(state: .succeeded)
print(obj)
obj.cancel()
print(obj)

Result

//Action - State.started
//Action - State.failed
//Action - State.succeeded
//Action - cancelled
Vasily Bodnarchuk
  • 24,482
  • 9
  • 132
  • 127
8

I had to validate the User License document. Which had two side - front and back. Depending upon the validation document could either be valid or invalid. Also UX was such that it would be active state or inactive state with corresponding colors to display. I ended up making following enum.

public enum Validity {
    case pending(_ selectState: SelectState)
    case valid(_ selectState: SelectState)
    case invalid(_ selectState: SelectState)
    
    enum SelectState {
      case active(_ side: Side)
      case inactive(_ side: Side)
      
      enum Side {
        case front
        case back
      }
    }
  }

Which can be referred as -

public var validity: Validity = Validity.pending(.active(.front))

I wish it could have been more clean like - Validity.pending.active.front but this is so far the solution for Enum inside of another enum can be.

Swift 5.1, Xcode 11.4.1

Caleb
  • 124,013
  • 19
  • 183
  • 272
Bishal Ghimire
  • 2,580
  • 22
  • 37