[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Dynamic binding, cont.: modularity issues
Date: Fri, 8 Dec 89 10:16:09 -0800
From: Andy Freeman <andy@neon.stanford.edu>
>Now one can point out that the obvious fix is for the Chaosnet code to
>bind *PACKAGE* to some package known to be reasonable around the call to
>READ. But I contend that a system should be designed so that such bugs
>never happen in the first place. And it seems to me that the obvious
>mechanism for accomplishing this is only our old friend, lexical
>scoping.
I ran into a similar problem, but I think the correct solution lies in
print. In the situation described, the program was correct iff the
printer and reader were using compatible packages, [...]
You've missed the point. Certainly you can see this particular example
(and all the others I could come up with) as a special case, but I claim
that it is not one; that the use of dynamic binding to control various
parameters of a system is inherently destructive to modularity, and for
just the reason that this example shows.
Let me state the issue more generally. Consider any two functions A
and B such that A calls B, either directly or indirectly through a chain
of other functions. Suppose that B references special variable *X*, and
that *X* is not bound anywhere between A and the reference to it in B.
Then the value of *X* when A is called affects the computation A
performs; so *X* is really a parameter of A, albeit a hidden one: one
that does not appear in A's parameter list.
I understand that this is precisely what people who want special
variables think they want: parameters to procedures that they don't have
to supply a value for in every call. That's a perfectly fine goal; the
argument we are having is over where those values should come from. The
usual pattern of Lisp thought is that they should be supplied by the
*dynamic* environment at the point of the procedure call. What I am
trying, perhaps clumsily as yet, to say is that while that approach
works well enough for programming in the small, it starts to cause
problems in large systems; but that supplying them *lexically*, in a
manner such as I have described, avoids those problems.
While not everyone is used to thinking in terms of the demands of
programming in the large, and so perhaps not everyone will readily
understand my argument, I did have the impression that Pavel in
particular (whose dynamic binding proposal we are considering) is
sensitive to the kind of issues I am raising. I recall him being an
outspoken opponent of first-class environments, for instance, on grounds
of the dangers they pose to modularity. I hope he will take the time to
consider carefully what I am saying. In fact, Pavel, as strongly as I
feel that R^nRS Scheme should not have dynamic binding, I feel even more
strongly that Scheme Cedar should not have it, or I would anyhow if I
were involved in your project.
By the way, I consider it not an accidental but actually quite a deep
property of my proposed substitute for special variables that it is part
of a (hypothesized) module system, and that its use in a program will
require appropriate organization of that program into modules. That's
part of the point.
I should add that these modularity issues are not the sole kind of
reason I have for objecting to the inclusion of any sort of dynamic
binding. I don't like the consequences for the implementation either.
I suppose my biggest objection is that the mere existence of dynamic
binding, even when I'm not using it, still adds a certain amount of
overhead to CALL/CC and invocation of the resulting continuations: the
system, at the very least, has to check to see that there are no dynamic
bindings to be saved or restored. In practice, an implementation will
probably allocate a 0-length vector in the heap to store these 0
bindings in. Aha, what's worse, if I write program X and never use
dynamic binding, so I assume that continuation capture and invocation is
fast and I use it heavily, and then someone installs program X in a
Scheme along with somebody else's program Y that binds 100 dynamics (for
its own reasons) and then calls X, every continuation X captures will be
loaded down with these 100 dynamic bindings, which will be waste both
CPU and memory. Even if it's 10 instead of 100, the effect could be
substantial.
-- Scott