Dynamic Scoping in C++
blog.dokucode.de
Dynamic Scoping in C++
1–10 of 64 posts
Re: Dynamic Scoping in C++
#2Re: Dynamic Scoping in C++
#3Re: Dynamic Scoping in C++
#4This isn't dynamic scoping; this is just a global variable with a stack of values. I appreciate the syntax is sort of the same (though the * makes it different in a very important way) but the meaning isn't. You should at least implement this with thread local storage, though, if you are going to do this.
Re: Dynamic Scoping in C++
#5Practically, dynamic scoping is more confusing than context objects.
void main() {
int x = 2;
fn();
}
Does fn access or change x? You need to inspect the body of fn to know.I would call dynamic scoping a poor form of coupling. Instead of bundling your coupling wires in a neat little set of in/out arguments and a return value (the format of which only needs the function’s declaration, not its definition), you are instead reaching out of and into the function’s body, like sprawling tendrils, as your function has free pickings of your variables.
It also strangely couples the names together. The outer function and the inner function may see the variable in completely different lights, yet dynamic scoping requires the outer use the name prescribed by the inner.
Optimization would be hard without WPO. You’d essentially need to keep a run-time “scope” object for every function. Though, the author’s proposed design for dynamic scoping in C++ means you don’t need it for every function; however that design has its own issues: how would you optimize such a design? It would a puzzling challenge.
Re: Dynamic Scoping in C++
#6I don’t see how this is functionally different to passing an object that contains references to the relate to variables; which I’ll call a context object. Practically, dynamic scoping is more confusing than context objects. void main() { int x = 2; fn(); } Does fn access or change x? You need to inspect the body of fn to know. I would call dynamic scoping a poor form of coupling. Instead of bundling your coupling wir…
You would normally use dynamic scoping for certain global parameters that apply to a lot of operations.
Unix shell scripts provide something similar to dynamic scoping with environment variables: If you write a shell script that sets LD_LIBRARY_PATH or TMPDIR, then all programs invoked from that shell script will inherit the values. And if your shell script calls another shell script, then that shell script can again set environment variables, and those are visible until it returns.
I would say that environment variables have been a great success story, and folks aren't too confused.
Re: Dynamic Scoping in C++
#7I don’t see how this is functionally different to passing an object that contains references to the relate to variables; which I’ll call a context object. Practically, dynamic scoping is more confusing than context objects. void main() { int x = 2; fn(); } Does fn access or change x? You need to inspect the body of fn to know. I would call dynamic scoping a poor form of coupling. Instead of bundling your coupling wir…
It's the same difference as using environment variables vs command line arguments. Imagine all programs having to pass TERM, DISPLAY, HOME, etc. as arguments in case some descendant process wants to use it and the user override. Like passing TERM, DISPLAY to git in case you want to override them for the configured pager or editor.
In other words, the issue is that when you have project A using project B using project C, project A has to manually carry around the context of B, and C in case the user wants to override them.
Re: Dynamic Scoping in C++
#8With coroutines, implementing dynamic scope becomes a lot more interesting, because switching to different coroutines requires switching which dynamic bindings are active.
The correct implementation is somewhat subtle and not immediately obvious if you haven't thought about it a lot. http://okmij.org/ftp/papers/DDBinding.pdf lays it out formally, but in the end the correct implementation is for each coroutine to have its own stack of dynamic bindings, and when you resume a coroutine in some context, you extend the bindings in that context with the coroutine's set of bindings while the coroutine is running, and remove those bindings again when the coroutine is done running. This preserves the intuitive behavior that one expects from dynamic scope - see the paper for more justification.
Others have got this wrong too, so you're in good company. Python, for example, added contextvars with https://www.python.org/dev/peps/pep-0567/, which have semantics which are usually identical to dynamic scope. But they chose an excessively-simple implementation, so the behavior diverges from proper dynamic scope when using coroutines in unusual ways, or using generators at all: https://www.python.org/dev/peps/pep-0568/
Re: Dynamic Scoping in C++
#9This isn't dynamic scoping; this is just a global variable with a stack of values. I appreciate the syntax is sort of the same (though the * makes it different in a very important way) but the meaning isn't. You should at least implement this with thread local storage, though, if you are going to do this.
I think best practice among languages that support dynamic scoping is to only make use of it for global variables. As I understand it, one should only read or shadow, not modify, these variables. Since that's the case, besides the thread issue you mentioned, I'm not sure this solution is lacking. I don't know much C++, though, so I might be missing something.
In this implementation, the threads will corrupt the data structure and result in undefined behavior.
Re: Dynamic Scoping in C++
#10Earlier quoted context omitted.
I think best practice among languages that support dynamic scoping is to only make use of it for global variables. As I understand it, one should only read or shadow, not modify, these variables. Since that's the case, besides the thread issue you mentioned, I'm not sure this solution is lacking. I don't know much C++, though, so I might be missing something.
If you have multiple threads which try to bind the dynamically scoped variable to a new value, that should work fine and result in different values for the variable in each thread. In this implementation, the threads will corrupt the data structure and result in undefined behavior.
> besides the thread issue you mentioned