Yes but making new classes map to default is what a default clause already does (which is basically what a base case in an abstract base class does with normal inheritance).
What I want is to make a new type added mean the code won't compile until it is explicitly handled in all pattern matches that do not have a default clause. Basically what I'm saying is that this:
bool HandlePayment(PaymentMethod pm) {
switch(pm) {
case Invoice(addr):
SendInvoice(addr);
return true;
case CreditCard(ccdetails)
return PrcessCreditcard(ccdetails);
default:
// What?
}
}
Would be a lot better if it didn't require the default, and the compiler could detect the error that occurs when someone adds a new case (BitCoin) to the types of payment method. Inheritance and abstract baseclass for the processing means that you'd do this
bool HandlePayment(PaymentMethod pm)
{
return pm.Process(order); // sends an invoice, charges credit card etc
}
and you simply have
abstract class PaymentMethod { abstract bool Process(order); }
class CreditCard : PaymentMethod { ... }
class Invoice : PaymentMethod { ... }
And this is of course the regular way of writing OO, but I find it unnatural and cumbersome in many cases. It's hard to define concise descriptions of what types are actually available, and you have to write a ton of boilerplate to ensure a closed hierarchy and complete matching in all scenarios where you can't enclose the logic inside each type.