By definition, dynamic typing and dynamic scoping have different purposes. But some cases make me wonder if they can lead to each other sometimes.
-
Dynamic typing allows a name i.e. identifier to refer to objects of
different types at different points at run time, e.g.x = 1 x = 'abc'
When dynamic typing changes the type of the object that a name
refers to, does it lead to change of the scope of the name? In the
above example, does the scope of the namex
change when reaching
the second assignment? - Dynamic scoping allows a name to refer to different objects at
different points in run time. When the different objects that a name
refers to have different types, does it lead to dynamic typing?
Thanks.
Best Answer
Dynamic scoping and dynamic typing have two things in common:
What does “dynamic” mean here? Something is dynamic if changes with time.
With dynamic typing, the type of a variable may change with time. That means it is no longer meaningful to talk about the type of a variable. Instead, we should talk about the type of the value referenced by a variable. When we reassign a variable to a different value, we still have the same variable. Because it is the same variable, how the variable is scoped does not change.
With dynamic scoping, the visibility of a variable changes with time, or more precisely, with the control flow. Consider the following two functions:
With lexical scoping, the variable
x
in thef()
function will never refer to a value. Usually, a compiler would reject this program sincex
was never declared within a scope off()
.With dynamic scoping, this depends on how
f()
was invoked. If we invokef()
directly, nox
variable was assigned. If we invokeg()
, a dynamically scopedx
variable is assigned. This variable is then still visible during the execution off()
.All of this is complicated and error prone. In fact, dynamic scoping is very similar to a global variable that's visible everywhere. In early programming languages (e.g. many Lisp dialects), dynamic scoping was more common since it's easier to implement that lexical scoping. However, it is avoided by more recent languages.
The only common programming languages I know which support dynamic scoping are Perl and Bash, both through the
local
keyword. Thelocal
keyword creates a new dynamic variable with the given name, which is destroyed when the lexical scope or the current function is left. Consider this Bash program:What happens here? The
print_x
andassign_x
function will always access the currentx
variable. Whenassign_x
assigns tox
, it changes the current variable. Theouter
function creates anx
variable, reassigns it throughassign_x
, then invokes the inner function. Here, we still have access to the currentx
from theouter
function, before we create anotherx
variable. Whatever we do tox
now affects this newx
, but leaves the oldx
alone. Only when we leave theinner
function is the temporaryx
deleted, and the previousx
becomes visible again.This is important: there are two distinct
x
variables in this program. Changing (the type of) on variable does not affect the other.If the effect of dynamic typing is needed in a language that does not support it, we must pass the data as function arguments instead. For the variable to be reassignable, we must pass it by reference, or as a pointer. However, dynamic scoping allows us to pass data through multiple function calls that do not include this parameter, so this is not a perfect solution.
Dynamic typing and dynamic scoping do not lead to each other. Dynamic scoping is rarely seen, and even less rarely without dynamic typing. However, there are many dynamically typed languages without dynamic scoping (e.g. Python), and even some languages with dynamic scoping but without dynamic typing (e.g. Bash: variables do have types, but it's complicated).
Appendix: Dynamic scoping with static typing
There is a statically typed mainstream language with a feature similar to dynamic scoping: Java with its checked exceptions.
In a statically typed language, a function would have to declare the types of the dynamically scoped variables it uses, as they form a part of its interface. I'll now imagine a version of Java extended with dynamic scoping. A dynamic variable is declared with
implicit
. Every method has an optionalimplicit
-specification clause, similar to athrows
-specification. I will also assume this feature is somehow integrated with the generics system, and that sufficient type inference is available to not make this feature completely unwieldy.The bash example would then translate:
As with checked exceptions, each method that calls a function with checked exceptions or with implicit variables must also declare those exceptions or implicit variables, which makes it more difficult to write generic functions. However, this is by no means impossible if the type system is sufficiently expressive. Assuming a C-style syntax for higher-order functions and generic parameters for implicit variables, we would have to express a
map
operation aswhere
f
could require any implicit variables. This requirement is then inherited by themap
function. Note that part of the problem with checked exceptions in Java is that Java does not allow a similar forwarding of thethrows
declaration.