Parameterized Procedures for Testing, Mocking, Plumbing
By Artyom Bologov
I'm about to suggest a simple solution to the problem of
- Mocking a procedure for testing.
- Inserting pre-computed results into computation.
- Temporarily overriding a procedure.
From this list, it's more or less evident why one might need this. But I'll explain my context anyway:
The Problem
Biological computations are fun:
- They are hard to read on paper.
- They are even harder to read in code.
- And they take an awful lot of resources to compute.
So I ran one computation piece that took several hours. It wasn't nice waiting for so long. (Even though I got some delicious cherry ice cream while waiting for it.) I've sworn to optimize it, or otherwise make it bearable to debug.
There was this one function, mph-em
, that was taking most of the time.
Especially so on first run.
It was an important one and there were no corners to cut.
I tried:
- Memoization/caching.
- Micro-optimizations.
- Rewriting parts of it in C.
It wasn't enough.
I needed to somehow avoid the long-running computation altogether.
And just get the result.
I needed to pre-compute the results of mph-em
and plug them into the program.
But what if it's too deep into the program and I can't feasibly pass anything from outside?
The Solution: Parameterize
Lisps have a long tradition of dynamic vs. lexical binding wars. Lexical bindings won, but there are uses for dynamic bindings. Like temporary procedure/value overriding! So I reached for Scheme's take on dynamic bindings, SRFI-39 Parameter objects and came up with this macro:
So now I can define-parameterized
my mph-em
and plug (via parameterize
) it in whenever I need it:
I was unsure whether this post should've been written altogether. It's quite obvious, right? But it might be just my knowledge bias, so here goes nothing! Tell me whether it's obvious or not, in the feedback form below ↓
And hey, give this macro a go! SRFI 39 is the only dependency and is pretty well supported, so no trouble in trying!