Hi Mark,

In Clojuratica I make what I think is "good, clean, compelling use" of
dynamic vars. I rewrote the code to use dynamic vars after I found that
doing it the other way became unwieldy and inelegant.

To simplify a little, the API consists of just one main function, let's call
it math-evaluate.

Every time the user calls math-evaluate, he or she can specify any of a
number of flags. Just for illustration, let's say two of these flags are
:flag1 and :flag2.

The math-evaluate function parses the flags and places them in a map called
*options* (or options before I was using dynamic vars). It then calls into
the core functions of the code base and returns the result. The core
functions call one another in complex ways. There are scores of core
functions. All of them have need to have access to the options map, if not
for their own consumption then for passing to other core functions.

Without dynamic vars, every single function in my code base would need to
have an options argument. Moreover, every mutual call between these scores
of functions would need to include the options map as an argument. I did it
this way for a while, and it was painful.

Moreover, if in the future I decided that every core function needed access
to *two* of these global-within-the-dynamic-scope vars instead of one, I
would need to edit the signature of every function and edit every mutual
call between the functions.

It turned out that this actually happened: I decided I needed another map to
store a few I/O bindings (it's called *kernel*). Because I was using dynamic
vars, I was able to change just one location in my code---the namespace
where the dynamics are interned---instead of several hundred locations.

The trade-off is the following. When I need to return a function or lazy seq
I need to close over the *options* and *kernel* vars by jumping through the
hoops Meikel has documented. There are only five or six such places in the
code, so I'm more than happy to do this. It feels quite elegant to me,
although I'd like a little more syntactic sugar.

Note that the dynamic vars are solely for my convenience as a programmer,
not part of the API of the software. I shield them from the user, so if the
user tried to bind *options* him- or herself it would have no effect on the
code. Every call to math-evaluate binds the dynamic vars anew on the basis
of the flags passed. My use of dynamics is an implementation detail.

The source is on github. The "real-laziness" branch is the newest and uses
bound lazy-seqs the most, particularly in clojuratica.base.parse.

Comments on this usage welcome.

Garth

On Tue, Nov 24, 2009 at 1:43 AM, Mark Engelberg <mark.engelb...@gmail.com>wrote:

> Meikel's blog post quotes:
> "running into a lot of such trouble is a sign, that you misuse dynamic
> variables. Use them wisely."
>
> I'd like to see examples of what you think is a good, clean,
> compelling use of dynamic variables that are properly used wisely.
>
> My own experience is that if the code is simple enough for you to
> analyze the use of binding and be sure it is correct, then the code is
> also simple enough to have easily written in another way (perhaps
> using explicit parameter passing).  On the other hand, if the use of
> binding is complex enough to really matter, it is also sufficiently
> complex you can't be 100% sure binding will do what you expect.
>
> I even somewhat question the places where Clojure internally uses
> bindings.  For example, if you use with-precision to try to control
> floating point behavior within a structure that potentially has some
> deep laziness (like a tree) that can't easily be forced with a doall,
> you're in for a surprise.
>
> I would like to be proven wrong, so I'm serious about wanting to see
> good examples of dynamic binding.
>
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with
> your first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com<clojure%2bunsubscr...@googlegroups.com>
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to