In one of Joe Marshall's posts on ways to accidentally break an abstraction, there are several top-level definitions which close over a lexical variable, like this:
(define lib-mapcar
(let ((calls-to-f 0))
(add-counter! 'calls-to-f (lambda () calls-to-f))
(lambda (f list)
...)))
I know this isn't supposed to be an example of good style, but I wince to see functions defined this way. lib-mapcar
's argument list is several lines away from its name, hidden behind some unrelated profiling code and a lambda
. This sort of thing is distressingly common in Scheme, and is even presented as good style sometimes. The usual justification is to keep the variable private, so you don't have to worry about name collisions or unexpected dependencies. But the cost in clarity far exceeds the tiny benefit in privacy.
I guess this is what happens when you don't have (or aren't accustomed to having) a module system. You start to think of top-level define
s as "globals", to be avoided whenever possible, and look for some alternative. Some languages provide convenient alternatives, such as C's static
(in all three of its senses), but in Scheme the only obvious alternative is to abuse lexical scope. And since everyone knows lexical scope is an unequivocal Good Thing, it's easy to overlook how awkward it is as an access-control tool.