To provide a wiki editing mechanism for repositories in Patch-Tag — which should eventually work for both darcs and git repos — we are adopting Gitit to our purposes by adding a security model with read and edit permissions for wikis, and making it posible for gitit to host more than one wiki at a time.
Overall development is proceeding smoothly, but one decision I regret is having used ImplicitParams for global-ish variables in the first version of our tweak.
ImplicitParams are evil!
They are evil in the same way that global variables are evil. It’s tempting to use them, because they seem to reduce some types of boilerplate. But it just takes a very few steps along that path before understandability becomes seriously impacted.
In fact, one of the best explanations i have seen of ImplicitParams (which actually argues for their goodness) is that IPs make it possible to have global variable-like behavior in haskell without using IOrefs, or other less tractable haskell98 solutions.
But when I look at the way we are using ImplicitParams in our gitit tweak, I am concluding that we shouldn’t be using IORefs *or* ImplicitParams, and basically should be staying away from globals altogether.
The bits of our program that are global-ish — basically configuration information for wiki requests and template key-value information for wiki display — should just be passed as a normal argument to the functions that need it. It’s a bit more wordy, but it tags every function that uses “global-ish” variables clearly, and I’ll take a big increase in understandability for a slight decrease in conciseness.
Exhibit A:
type ParamsHandler = (?params :: Params) => Handler
withMessages :: [String] -> ParamsHandler -> ParamsHandler
withMessages msgs val =
let ?params = ?params { pMessages = msgs ++ pMessages ?params }
in val
I look at this, notice that val doesn’t use anything defined in the let clause, and my brain shuts down.
Without implicit params:
withMessages :: Params -> [String] -> (Params -> Handler) -> Handler
withMessages params' msgs hndlr =
let params = params' { pMessages = msgs ++ pMessages params' }
in hndlr params
Maybe it’s just me, but I find the latter version much easier to understand.