
Ask HN: What makes dynamic scoping different from all variables being global? - kqr
In light of the recent discussion on JS and Scheme, this is something that&#x27;s been annoying me for a while. I can not think of a single experiment that will let me tell apart languages that have dynamic scoping from languages in which all variables are global, i.e. there being no such thing as many scopes.<p>Is dynamic scoping really a nicer word for &quot;no scoping&quot;? (Puns about first person shooter games aside.)
======
brudgers
No, dynamic scope and global scope are two different things...and can exist
within a language alongside lexical scope. Common Lisp (unsurprisingly given
its development as a consensus standard among working programmers and Lisp
system vendors) is an example. The macros defvar and defparameter [1]
accompany lexical scope (and package/namespace scope). For my money, Common
Lisp is a great language to study when trying to get a handle on language
design because it does so much. YMMV.

[http://www.lispworks.com/documentation/HyperSpec/Body/m_defp...](http://www.lispworks.com/documentation/HyperSpec/Body/m_defpar.htm)

~~~
kqr
I have been learning a lot about OOP while studying CLOS, so I am not
surprised. Will look into scoping in CL too. Thanks!

~~~
brudgers
My favorite OOP language is Smalltalk. I'd say it helped me make more sense of
CLOS and Javascript and Ruby Objects.

------
kbp
Here's a Javascript program:

    
    
        const x = 'lexically scoped';
    
        const f = () => x;
    
        const g = () => {
            const x = 'dynamically scoped';
            return f();
        };
    
        console.log(g());
    

It prints which scoping Javascript uses. When `f` is executed, `x` isn't
defined in that scope (the body of `f`), but `x` is used in that scope: does
the language look in the scope that `f` itself was defined in (the top-level
in this case, but you can have nested scopes), or does it look, at run-time,
at the scope that `f` was _called from_ (the body of `g`)? That's the
difference. The local-to-`g` `x` that dynamic scoping would use when `f` is
called is not a global; it's an entirely different variable from the other `x`
(even in a dynamically scoped language, calling `g` won't change the outer
`x`'s value).

Dynamic scoping can be useful: for example, in Common Lisp (which supports
both lexical and dynamic variables), _STANDARD-INPUT_ is a dynamically scoped
variable, so you can temporarily redirect stdin like:

    
    
        (with-open-file (*standard-input* (open "file.txt"))
          (function-that-reads-from-stdin))
    

And not have to worry about setting _STANDARD-INPUT_ back to its old value
when you're done. Scala's implicits are also often used to produce the same
effect as dynamic scope.

As an aside, you could argue that `this` is dynamically scoped in Javascript
(outside of new lambdas).

~~~
kbp
Wasn't thinking when I wrote that Lisp example; obviously you don't use OPEN
alongside WITH-OPEN-FILE, it just takes the filename.

------
kazinator
Lexical scoping means that a variable expression X refers to the innermost
binding which is in the program text that encloses the references.

Dynamic scoping means that the expression X refers to the innermost binding of
X in the entire activation chain ("call stack") leading up to that point (or
possibly to a global, top-level X if there is no such binding).

Global means that X refers to a single instance in a top-level environment.

Dynamic scoping can be faked with global variables plus a hidden
saving/restoring mechanism. That is to say, the local binding of a dynamic
variable can be simulated by saving the current value in a hidden local
location associated with the activation frame, then simply assigning to the
global variable, and finally restoring the prior value (with unwind
protection, so it is guaranteed). However, the ruse will be exposed under any
sort of concurrency (threads, coroutines, continuations) which will make it
apparent that there is only one instance of the variable. Under a true
implementation of dynamic scoping, the local binding of the dynamic variable
actually has a separate local location from the fall-back global one.

Note that the scoping classification of bindings is not sufficiently nuanced
to capture what is possible. Words like "lexical" refers to visibility but
"binding" is what happens at run-time: the establishment of the life of the
thing that the name refers to, through to its termination. In Common Lisp
parlance, the run-time lifetime of a binding is called its "extent".

If a language supports lexical closures, then lexical variables never "go
away" while it is possible for a closure to be invoked which refers to their
values. This situation is called "indefinite extent".

"Dynamic scope" is an informal term for "indefinite scope, dynamic extent".
See here:
[https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node43.html](https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node43.html)
[cltl2, 3 Scope and Extent]

This terminology lets us distinguish nuanced situations such as:

\- C non-static local variables: lexical scope, dynamic extent (go away when
block scope terminates).

\- C static locals: lexical scope, indefinite extent

\- Common Lisp blocks: lexical scope, dynamic extent

------
lispm
Dynamic Scope let's you run code portions with their own variable bindings -
without the need to pass arguments into the function and without the need to
rebind the variables lexically in surrounding code. The scope is dynamic, that
means that the bindings are only active while the code is actually active -
different from lexical binding, where closures capture bindings even then the
closure generating code is no longer active.

Dynamic binding is usually called 'fluids' in Scheme. There are constructs
like fluid-let which create dynamic bindings.

In Common Lisp the normal LET creates dynamic bindings when the variable is
declared to be special. Variables defined by DEFVAR or DEFVARAMETER are
declared special by definition.

------
eschutte2
Check whether you get the outer scope's value back when the inner scope
terminates.

~~~
kqr
With no scoping you don't, because there is no inner scope.

With dynamic scoping you also don't, because there is no lexical scope.

What am I misunderstanding?

~~~
eschutte2
I don't understand your point 2. Here's an example of what I meant:

    
    
      > (defvar somevar 3)
      > (defun printvar () (format t "somevar is ~D~%" somevar))
      > (printvar)
      somevar is 3
      > (let ((somevar 5)) (printvar))
      somevar is 5
      > (printvar)
      somevar is 3
    

If you only have global variables, you wouldn't get 3 back the third time,
right?

~~~
kqr
YES!! Thank you!

This made it click with me, finally. I can't yet put it into words nicely, but
I do have an intuition for the concept now.

