2011-03-27

Use case for Restart-Bind

It's always a good day when you find a perfect use case for one Common
Lisp's less used operators. Lately I had the pleasure to find a good
opportunity for RESTART-BIND.

I've written a network simulator in a couple of hundreds lines of
Common Lisp (not counting our basic protocol and miscanellous stack)
to emulate mobile IP networks. We use it to review that our mobile
broadband accelerator
is behaving the way we want it to behave. We
also use it in a complete virtual setup using UML instances for our
test suite as well as for the lab in our office.

For determinism purposes I wanted to be able to reseed the
*RANDOM-STATE* to its initial value by some means. And it turned out
that RESTART-BIND is just the right thing for that job:
(defun simulator (... &key (seed #xDEADBEEF) ...)
(let ((*random-state* (sb-ext:seed-random-state seed)))
(restart-bind
((reseed #'(lambda ()
(setf *random-state* (sb-ext:seed-random-state seed)))
:report-function
(formatter "Reseed *RANDOM-STATE* with initial :SEED value.")))
...)))
You can reseed manually by interrupting the network simulator and
using the RESEED restart, or you can reseed programmatically (e.g.
periodically after a certain time of inactivity) by

(invoke-restart 'reseed)

Can you feel that warm and fuzzy feeling? Just the right thing. :-)

PS.

Other fun note about restarts and RESTART-BIND. If you squint your
eyes, you will discover that restarts are essentially nothing else
than dynamically scoped local functions, and RESTART-BIND is basically
DYNAMIC-FLET.