Languages that lack dynamic scoping typically propagate a reference to a "context" through the B function. One can see this common pattern in threading libraries such as pthreads, for example. The A function creates a data structure that contains everything C needs, passes it to B as the "context" parameter and it is then forwarded to C.
It's more verbose but also more explicit.
- Callable objects that store `FOO`, and
- Closures that capture `FOO`.
I'm pretty leery of argumentum ad populum. I think we went with lexical scoping for a few clear reasons, and I don't know if the reasons for dynamic scoping are compelling. I would love to hear more of them, though.
It has been a while since I worked with dynamically-scoped programs, but I found it harder to reason about how they worked. Maybe it was just because I was less familiar with the technique.
It might be that all forms of beyond-local scoping multiply the difficulty in reasoning about programs (especially in the presence of mutable data), and dynamic scoping is a more powerful form of it, increasing the opportunity for setting up difficult-to-follow situations.
The issue of ease of understanding is a different one than ease of extending, and I would judge the former to be more important, all else being equal.