
2008/5/17 Kaveh Shahbazian
3 - What is the logical implementation of pattern matching in C#? (For example using structures with indicator fields or using interfaces and inheritance and dynamically dispatch in calling overloaded methods. Also this question contain a hidden one...GADTs!)
C# is missing ADT's, so the most straightforward way to do it is using open derived classes. (Forgive if my syntax is a bit wrong, you get the idea) class Thing { } class ThisWay : Thing { public a value; } class ThatWay : Thing { public b value; } class NoWay : Thing { } Annoyances include having to parameterize the, ahem, "constructors" on all type parameters, and the openness of the cases. That is, there is nothing stopping someone from adding "class TwoWay" later and making your pattern-matches partial. Scala is very much like C#, but gets this point right, FWIW. A more subtle trick is to use the fold of the ADT as its representation. delegate c Thing(Func thisWay, Func thatWay, c noWay) Then your constructors look like this (if I remember C#'s lambda syntax correctly): ThisWay thisWay(a value) { return new ThisWay((thisC, thatC, noC) => thisC(value)); } ... And a pattern match looks like this: String desc = thing( x => "ThisWay " + x.toString(), x => "ThatWay " + x.toString(), () => "NoWay"); Which isn't all that bad, actually. An advantage is that this approach does in fact keep the data type closed: you can be sure that the thing() pattern match does in fact cover all cases of the data type. A disadvantage is that there is rather a lot of plumbing (not really in comparison to the open derived approach though, I suppose). After those C# guys went to all the trouble to add lambdas and half-assed type-inference (not that "full-assed" was possible in their type system, but there are more complete strategies than the one they took), they could have at least added some half-assed (read: non-G) ADTs for us too :-). Luke