That's one way to see it. But does the programmer want "lexical
scoping", or something else, with lexical scoping just being the Algol
60 and Scheme way to provide it?
In 2018 I wrote up a draft of a paper on closures for Forth, and I
started with lexical scoping. This might look as follows for the
example above:
: +field ( n "name" -- )
{: n :} [: n + ;] alias ;
To make it easier to implement I required explicitly listing the
locals at the start of the closure that are referenced inside the
closure, and passing the allocation word:
: +field ( n "name" -- )
{: n :}
['] alloth <[{: : n :} n + ;] alias ;
Interestingly, the example I gave in the draft is even longer; I don't
remember what the ":" after the <[{: is intended for. With the
allocation being part of the closure start word and without the extra
":", it could look as follows:
: +field ( n "name" -- )
{: n :} d[{: n :} n + ;] alias ;
Bernd Paysan had the idea to make the implementation even simpler by
passing the data to the closure on the stack, resulting in the syntax
in the published paper (but again, the examples in the paper are more
complex):
: +field ( n "name" -- )
[{: n :}d n + ;] alias ;
This new idea required me to rewrite most of the paper
[ertl&paysan18], in particular, the examples. One thing I noticed is
that many of the examples became simpler (sometimes even simpler than
lexical scoping without the additional requirement), because I no
longer had to put the value into a local in order to pass it to the
closure. I could just leave it on the stack, and inside the closure
it would be a local. This shows IMO that what we want as programmers
is not lexical scoping, but a way to pass data to the closure.
In my EuroForth talk I then outlined that it can be done in a
pure-stack way, without locals. This was intended to be mainly food
for thought, but some time later Bernd Paysan told me that he found
that useful for passing single values, and that he had implemented it,
so one could now write
: +field ( n "name" -- )
[n:d + ;] alias ;
In this case the code is shorter, and once you know what [N:D means, I
think it's easier to understand. For passing multiple values to the
closure, this tends to become cumbersome, so for that you still have
to use the version with locals.
But of course, purists might prefer passing multiple values from the
stack(s) at closure-creation time to closure run-time. That is
certainly possible, and shows that what programmers do with closures
in most cases does not require lexical scoping.
Of course, one might say that those who practice point-free functional
programming have shown that long ago, but that's a different approach.
>Second big step would be do this with named locals i.e. put the burden on
>compiler's shoulders and let programmers enjoy more readable code.
As outlined above, Gforth has had that before it had [N:D, but it's
not lexical scoping.
Last year I wrote a paper [ertl21] about transplanting the ideas I
learned here to an Algol-family language (C).
@InProceedings{ertl&paysan18,
author = {M. Anton Ertl and Bernd Paysan},
title = {Closures --- the {Forth} way},
crossref = {euroforth18},
pages = {17--30},
url = {
http://www.complang.tuwien.ac.at/papers/ertl%26paysan.pdf},
url2 = {
http://www.euroforth.org/ef18/papers/ertl.pdf},
slides-url = {
http://www.euroforth.org/ef18/papers/ertl-slides.pdf},
video = {
https://wiki.forth-ev.de/doku.php/events:ef2018:closures},
OPTnote = {refereed},
abstract = {In Forth 200x, a quotation cannot access a local
defined outside it, and therefore cannot be
parameterized in the definition that produces its
execution token. We present Forth closures; they
lift this restriction with minimal implementation
complexity. They are based on passing parameters on
the stack when producing the execution token. The
programmer has to explicitly manage the memory of
the closure. We show a number of usage examples.
We also present the current implementation, which
takes 109~source lines of code (including some extra
features). The programmer can mechanically convert
lexical scoping (accessing a local defined outside)
into code using our closures, by applying assignment
conversion and flat-closure conversion. The result
can do everything one expects from closures,
including passing Knuth's man-or-boy test and living
beyond the end of their enclosing definitions.}
}
@Proceedings{euroforth18,
title = {34th EuroForth Conference},
booktitle = {34th EuroForth Conference},
year = {2018},
key = {EuroForth'18},
url = {
http://www.euroforth.org/ef18/papers/proceedings.pdf}
}
@InProceedings{ertl21-kps,
author = {M. Anton Ertl},
crossref = {kps21},
title = {The Essence of Closures---A language design
perspective},
year = {2021},
pages = {26--33},
url = {
http://www.complang.tuwien.ac.at/papers/ertl21-kps.pdf},
url-slides = {
http://www.complang.tuwien.ac.at/papers/ertl21-kps-slides.pdf},
abstract = {Closures are originally associated with lexically
scoped name binding. However, in the course of
implementing closures in Gforth, it turned out that
the actual function (the essence) of closures is to
communicate data between closure creation and the
closure execution (with the closure call usually
being far from the closure creation). This paper
presents a simple language extension for C:
two-stage parameter passing, implemented with flat
closures; the first stage creates a closure, the
second stage calls it. Nested functions and access
to outer locals are not needed.}
}
@Misc{kps21,
author = {{KPS 2021}},
editor = {Hanus, Michael
and Prott, Kai-Oliver
and von Hanxleden, Reinhard
and Domr{\"o}s, S{\"o}ren},
title = {Tagungsband zum 21. Kolloquium Programmiersprachen und Grundlagen der Programmierung},
booktitle = {Tagungsband zum 21. Kolloquium Programmiersprachen und Grundlagen der Programmierung},
year = {2021},
publisher = {Self-Publishing of Department of Computer Science, Kiel},
address = {Kiel},
volume = {2021/7},
issn = {2194-6639},
doi = {10.21941/kcss/2021/7},
url = {
https://macau.uni-kiel.de/receive/macau_mods_00002282},
url2 = {
https://doi.org/10.21941/kcss/2021/7},
file = {:
https://macau.uni-kiel.de/servlets/MCRFileNodeServlet/macau_derivate_00003380/kcss_2021_07.pdf:PDF},
language = {en}