A long-ish reply to Brian's comments ....
> The point is that with dynamic scope you automatically have access to
> the "deeper" bindings, unless they're shadowed. There is no need for
> any special mechanism to allow explicit moving around between environments.
I'd like this clarified, since it seems to me that the situation is
identical for lexical binding. If we neglect shadowing, then when we
ask for the value of a variable inside a break loop we get the same
value both with lexical and dynamic binding. The only issue is that
getting access to variables in the fashion is easier to implement with
dynamic binding.
> No, I don't think this is simply a matter of notation. The square
> bracket syntax in Logo doesn't represent a nullary procedure; it just
> represents a literal list.
It doesn't matter whether its a list of symbols or a procedure the key
difference is notational convenience. The obvious comparison is
with Smalltalk which uses [ ... ] to denote a nullary procedure with
lexical binding. In Smalltalk the control contructs are indeed
implemented in the suggested way.
> When you make a list, Logo doesn't create
> a closure or anything.
One point made here concerns efficiency. Making a list is likely to
be less efficient than a closure construction in a wide range of
cases. But this wasn't the main issue.
> And a list can be constructed from pieces,
> not only typed directly in brackets.
This is a new point -- that dynamic binding allows you to treat
a few privileged data structures (i.e. lists) as procedural objects.
This is presumably claimed to be an advantage since the programmer
has considerable skill in manipulating lists AND writing programs.
Such a programmer can write programs to write programs using this
limited skill-base.
I agree that this is a feature of dynamic binding; I don't
agree that it is an advantage. But this is quite a complex
argument and so I shaln't contest it properly, in order to be brief.
> It's only confusing if you use the same name for different purposes,
> a practice that should be avoided no matter what scoping rules you have.
> The human reader will be confused even if the computer isn't. The
> natural way to program is to give every variable a unique name, for
> ease of documentation, except maybe for the really locally used ones
> like "list" inside a list utility function, which you don't expect to
> be able to use elsewhere.
To me, this reads as a strong criticism of dynamic binding -- you have
to invent endlessly new names even for local variables because of
the issue of name shadowing. In short, a needless and dangerous practice
created because of a abused binding policy. Why inflict it on anyone,
let alone beginners who have the least sophistication.
> I think the fact that you get screwed if you
> use the same name for different purposes is natural, whereas the fact
> that you *can't* use a perfectly unambiguous name because you happen to
> be in a different procedure is confusing.
I don't understand this point. Firstly, I don't want to be messed around
by a program because I've forgotten I used the same name 4 days ago. And
nor does anyone else. Secondly, I don't see what Brian is referring to
as (what I take to be) a restriction of lexical binding.
> The proof of the pudding is that lexically scoped languages always end up
> either nesting procedures inside each other, which I find completely
> unreadable (Pascal and Scheme), or else forcing the programmer to resort
> to global variables half the time because it's just too inconvenient
> otherwise (C).
This is another new point. This suggests that dynamic binding makes
programs more understandable because they neither require nested
procedures or excessive global variables. This presumably implies that
dlocalised-global variables (i.e. dynamic variables) are more attractive
than non-localised global variables.
To be honest, I regard Brian's observation as one about programming
style rather than binding policy. Naturally, you cannot use nested
procedures in a useful sense in a dynamic language. So the only
times you will see nested procedures is in lexical languages. C doesn't
syntactically support nested procedures -- so communication must be
performed through global variables or procedure-parameters.
It is part and parcel of most C programmer's style to use many
global variables. This is obviously a stylistic issue since it is
perfectly possible to use formal arguments in preference on many]
occasions.
I am inclined to agree with Brian that nested procedures reduce
readability -- for two reasons. Firstly, they capture lexical
variables which requires careful reading of the text. Secondly,
they tend to expand procedure definitions a great deal. And,
in case it isn't clear, I equate visually "big" definitions with
unreadable definitions.
However, I'm sure we disagree in our assessment of the readability of
programs using dynamic binding that accomplish the same task. In order
to understand a collection of procedures it is now important to
inspect every localisation of a variable and check whether or not
it is accessed non-locally in another procedure -- after all, that's
how one achieves the effect of nested procedures.
My own judgement is that this is a task far beyond beginners and
somewhat beyond the ability of experienced programmers. And my
observations of programmers confirm this.
> By the way, here's my favorite serious example of a program that's
> easier to write with dynamic scope: a recursive descent Pascal compiler.
One might see it as easier. The obvious alternative is to add an
extra parameter to each compiler procedure that passes on vital
information about the context (e.g. tall-call, next-label to transfer to,
symbol-table, etc). Since you have to do this (or similar) anyway to perform
elimination of intermediate jumps, it hardly complicates life to add
a more detail to the context parameter. And this works independent
of lexical or dynamic binding.
But, this is nitpicking, because I agree with Brian's core thesis
that there are some things that are elegantly done with dynamic binding.
Just not very much. And unlike Brian, I would be quite unhappy teaching
beginners a binding policy which is so simple but so problematic. But
then again, unlike Brian, I don't teach children ... and quite possibly this
is a Good Thing (tm).
Steve
|