OO can be hard to un-learn! #FFTW
I was trying to build an library for OpenFlow, where there are about two dozen request/response paired message types. I came up with a whole bunch of "typeclass trickery" to handle them so that could be called with a single function request
, ensuring the types match, and the "magic message number" constants are all automatic. But this made the call sites in client code inscrutable:
descrip <- request h
portStats <- request h AllPorts
echoResp <- request h "yo"
_ <- request h Barrier
The only way you can tell what is happening is by figuring out the types of those variables, or hoping they are well named...
I settled on a much simpler design:
d <- requestDesc h
ps <- requestPortStats h AllPorts
er <- requestEcho h "yo"
Now the function names are self-documenting, and client code can be free to use short variable names. Furthermore, the functions are non-polymorphic, which improves type inference in cases where the user doesn't need the request or the response type (there are several). Also, in those cases where there is no request body the request argument doesn't have to be a useless () supplied! Similarly, when there is no response body, the result can now be IO ().
The implementation can still use polymorphic functions (so that I don't have to duplicate the complex, type directed serializations needed), but turns out I can do less of it.Functional-For-The-Win! #FFTW