Closures and dynamic scope?
Asked Answered
Z

2

9

I think I understand why there is a danger in allowing closures in a language using dynamic scope. That is, it seems you will be able to close the variable OK, but when trying to read it you will only get the value at the top of global stack. This might be dangerous if other functions use same name in the interim.

Have I missed some other subtlety?

Zug answered 10/9, 2010 at 1:17 Comment(0)
D
7

Yes, that's the basic problem. The term "closure" is short for "lexical closure", though, which by definition captures its lexical scope. I'd call the things in a dynamically scoped language something else, like LAMBDA. Lambdas are perfectly safe in a dynamically scoped language as long as you don't try to return them.

(For an interesting thought experiment, compare the problem of returning a dynamically scoped lambda in Emacs Lisp to the problem of returning a reference to a stack-allocated variable in C, and how both are impossible in Scheme.)

A long time ago, back when languages with dynamic scope were much less rare than today, this was known as the funargs problem. The problem you mention is the upward funargs problem.

Disembarrass answered 10/9, 2010 at 1:42 Comment(4)
I won't edit the answer but: "Usually" is wrong -- closures are always "lexical closure", named this way because they close the expression over its lexical environment. As for lambdas being safe -- not being able to use lambdas as closures is hugely diminishing their value, but even without that, dynamic scope is inherently bad for your program's health since you can't be sure of the meaning of any binding.Zoroaster
Thank you for the funargs link. I did never learn of this before.Zug
@Eli Barzilay: You are right, I was being overly wishy-washy. I will remove 'usually'. As for general program health, I completely agree, but the question is not general. Like I said, dynamically scoped lambdas are about as safe as unrestricted pointers...Disembarrass
@Eli: Probably the reason you never heard of the funargs problem is that it's quite old and almost all languages now use lexical scope in order to solve it. (Among other reasons.)Disembarrass
S
9

I realize I'm years late answering this, but I just ran across this question while doing a web search and I wanted to correct some misinformation that is posted here.

"Closure" just means a callable object that contains both code and an environment that provides bindings for free variables within that code. That environment is usually a lexical environment, but there is no technical reason why it can't be a dynamic environment.

The trick is to close the code over the environment and not the particular values. This is what Lisp 1.5 did, and also what MACLisp did for "downward funargs."

You can see how Lisp 1.5 did this by reading the Lisp 1.5 manual at http://www.softwarepreservation.org/projects/LISP/book

Pay particular attention in Appendix B to how eval handles FUNCTION and how apply handles FUNARG.

You can get the basic flavor of programming using dynamic closures from http://c2.com/cgi/wiki?DynamicClosure

You can get an in depth introduction to the implementation issues from ftp://publications.ai.mit.edu/ai-publications/pdf/AIM-199.pdf

Modern dynamically scoped languages generally use shallow binding, where the current value of each variable is kept in one global location, and function calls save old values away on the stack. One way of implementing dynamic closures with shallow binding is described at http://www.pipeline.com/~hbaker1/ShallowBinding.html

Spartacus answered 1/6, 2012 at 22:39 Comment(3)
I realize I might be years late asking this :P, but would you mind explaining what are make-adder, addx, and do-test form this link you referenced? Telling from the Lisp 1.5 manual, they are not function closures though defined with lambda. They seem more like macros and are substituted with mere expressions (i.e. without environments associated).Gipsy
They are just normal, dynamically scoped functions. When called, they have access to variables within their dynamic scope. The only closure/funarg in this program is the one created by FUNCTION.Spartacus
Alright, maybe this is just a matter of nomenclature, but I prefer to say that there is no such thing called "dynamic closures" (which I personally think is confusing than clarifying). The referenced AIM-199.pdf paper actually gives the origin of the word closure, which suggests that it was first used only for "closed" lambda expressions. Dynamically scoped functions, whose free variables escape to the current run-time environment, are not closed in this sense, thus termed "open lambda expressions" in that paper.Gipsy
D
7

Yes, that's the basic problem. The term "closure" is short for "lexical closure", though, which by definition captures its lexical scope. I'd call the things in a dynamically scoped language something else, like LAMBDA. Lambdas are perfectly safe in a dynamically scoped language as long as you don't try to return them.

(For an interesting thought experiment, compare the problem of returning a dynamically scoped lambda in Emacs Lisp to the problem of returning a reference to a stack-allocated variable in C, and how both are impossible in Scheme.)

A long time ago, back when languages with dynamic scope were much less rare than today, this was known as the funargs problem. The problem you mention is the upward funargs problem.

Disembarrass answered 10/9, 2010 at 1:42 Comment(4)
I won't edit the answer but: "Usually" is wrong -- closures are always "lexical closure", named this way because they close the expression over its lexical environment. As for lambdas being safe -- not being able to use lambdas as closures is hugely diminishing their value, but even without that, dynamic scope is inherently bad for your program's health since you can't be sure of the meaning of any binding.Zoroaster
Thank you for the funargs link. I did never learn of this before.Zug
@Eli Barzilay: You are right, I was being overly wishy-washy. I will remove 'usually'. As for general program health, I completely agree, but the question is not general. Like I said, dynamically scoped lambdas are about as safe as unrestricted pointers...Disembarrass
@Eli: Probably the reason you never heard of the funargs problem is that it's quite old and almost all languages now use lexical scope in order to solve it. (Among other reasons.)Disembarrass

© 2022 - 2024 — McMap. All rights reserved.