Enums: not always the right tool
Enums are a way of encoding a set of ordinal values in a type system. That is, they formalise the notion that a value may be one of a small set of specific values. We’ve had them since at least the 1970s. They’re really useful. So why might they not always be the right tool?
Network protocols often use tags to differentiate things. For instance, SIP responses may have a return code anywhere from 100 through to 699. RFC 3261 defines a bunch of specific status codes, many of which will be familiar – 200 OK, 400 Bad Request, 401 Unauthorized – and some not – 482 Loop Detected, 603 Decline.</>
It seems quite natural to define these return codes as an enum; after all, the status codes are ordinal, and there aren’t that many of them.
But network protocols live for a long time. People extend them. Sometimes these extensions need response codes that aren’t as yet defined. If you, oh library author, have used enums to define your status codes, what am I, lowly library user, to do when I need to use one of these non-standard response codes?
And here’s the rub: without hacking your source (and I may not even be able to do that – C#’s System.Net.HttpStatusCode, anyone?) how can I handle the craziness of real life, when someone sends me a response with an unknown status code? Sure, most protocols have rules that say “well, if it’s a 2xx that you don’t understand, treat it as a 200.” That’s a sound rule… but what if I actually need to react differently to a 299 than to a 200? Or what if I want to send a non-standard status code? Case in point: a client wanted to return a 2xx class code for an HTTP RPC call that failed, because they wanted to distinguish between the RPC call failing because of a problem with the container (JBoss) or failing because of a bug in their service. For the Java servers using RESTEasy that’s easy:
. For the C# servers (using WCF), that can’t be done: a
So, mighty library author, what are you to do to allow for unanticipated uses of the protocol? Here’s a hint: protocols like SIP and HTTP don’t say “these status codes are the only status codes you will ever need”. They provide ranges: 100-199 means “a provisional response; not the end of the conversation”, 400-499 means “you made a mistake in your request”, and so on. And so should you. Don’t limit users of your library to only those constants specifically defined in the base RFC of the protocol. Instead, permit any valid value.
If you’re lucky enough to work in one of the Pascal-like languages, your work is easy:
TSipStatusCode = 100..699
lets you use any standard status code while still preventing ungrammatical constructs like a status code of 1000. If you’re using Java or C#, please don’t use an enum: you prevent anyone being able to use non-standard response codes. If you’re feeling all OO, go ahead and make special OkResponse objects, as long as you expose the original status code. Or if you’re feeling lightweight, just use whatever
-like facilities your language of choice provides so that readers can see
and know what you mean.