Note: This is basically the same question as the other I posted yesterday on Stackoverflow. However, I thought I was using a bad example in this matter, which did not quite shift it to the point of what I had in mind. Since all the answers to this original post relate to this first question, I thought it would be better to introduce a new example in a separate question - no duplication is needed.
Model characters that can move
Define an enumeration of directions for use in a simple game:
enum Direction { case up case down case left case right }
Now in the game I need two types of characters:
- A
HorizontalMover that can only move left and right.
β β - A
VerticalMover that can only move up and down.
β β
They can move, so they both implement
protocol Movable { func move(direction: Direction) }
So, let's define two structures:
struct HorizontalMover: Movable { func move(direction: Direction) let allowedDirections: [Direction] = [.left, .right] } struct VerticalMover: Movable { func move(direction: Direction) let allowedDirections: [Direction] = [.up, .down] }
Problem
... with this approach is that I can pass invalid values to the move() function, for example. the following call will be made:
let horizontalMover = HorizontalMover() horizontalMover.move(up)
Of course, I can check inside the move() funtion whether the passed direction allowed for this Mover type and otherwise throw an error. But since I have information that is allowed at compile time , I also want the check to be performed at compile time .
So I really want this:
struct HorizontalMover: Movable { func move(direction: HorizontalDirection) } struct VerticalMover: Movable { func move(direction: VerticalDirection) }
where HorizontalDirection and VerticalDirection are subsets of the direction enumeration.
It makes no sense to simply define two types of directions independently of each other, without any common βancestorβ:
enum HorizontalDirection { case left case right } enum VerticalDirection { case up case down }
because then I will have to redefine the same cases over and over, which are semantically the same for each listing representing directions. For example. if I add another character that can move in any direction, I will also have to implement a common direction jumper (as shown above). Then I would have a case of left in the HorizontalDirection enum enumeration and a left in the general enumeration of direction , which does not know about each other, which is not only ugly, but also becomes a real problem when assigning and using the original values ββthat I would have to reassign in each listing.
So is there a way out of this?
Can I define an enumeration as a subset of cases of another enumeration like this?
enum HorizontalDirection: Direction { allowedCases: .left .right }