Recently, I have been working on implementing some non-trivial data structures 
in Swift (its about storing polygons in a space-partitioning tree). I am using 
enums to represent different types of parent nodes and leafs and I had some 
ideas to make them more fit for this kind of work. I expect that I will write 
multiple enum-related emails, each one concentrating on one particular feature. 
A usual disclaimer: these are random, quite rough ideas that might or not make 
sense, but I’d like to get some feedback  from the community. 

Case-based dispatch for enum methods

Often, behaviour of enum method depends on the enum value. For instance, 
imagine a tree structure with an insert(value:) method: the way how the 
inserting is handled depends on the type of the node. Usually, you’d implement 
it as a switch operation:

func insert(value:T) {
  switch self {
    case let Leaf1(a, b, c): …
    case let Leaf2(a, b): …
    case let Parent1(x, y): …
  }
}

If the insert operation is non-trivial, this becomes quite convoluted. You can 
of course define private helper methods or functions that perform the specific 
functionality, but I don’t find it to be a very satisfying solution: there is 
still the switch boilerplate + you need to be careful to call the correct 
helper, so there are some safety issues. 

Now, suppose there was a way to add a method implementation that is 
case-specific:

enum MyTree {
  case Leaf1(Float, Float) {
    mutating  func insert(value: T) {
       let (a, b) = self.Leaf1 // or something like that
       // handle insert for the case that node is of type Parent1

       ...
     }
  }

 case Parent1(Int, Float) {
     mutating func insert(value: T) {
       let (x, y) = self.Parent1 // or something like that
       // handle insert for the case that node is of type Parent1
       ...
     }
  }

default {
   mutating func insert(value: T) {
      // handle insert for all other cases 
       ...
     }
}
}

etc. The case method specification needs to be exhaustive and adhere to the 
same signature. It is a compile-time error to specify a method or property only 
in some cases but not in the other ones (that is why we have the default 
implementation). Outer scope definitions apply to all cases and cannot be 
overridden by a case-specific implementation. 

Basically, the compiler would synthesise an outer-scope method that does a 
switch operator to dispatch to the particular implementation. This is thus 
mostly syntactic sugar which also promotes safety (as it becomes impossible to 
call the wrong implementation). These would make the case-specific methods 
fully compatible with protocols etc. (e.g. a protocol Insertable { mutating 
func insert(value:) }

Looking forward to your thoughts on this!

Best, 

 Taras


_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to