What are lexical scope and dynamic scope and what are their main differences?
What are lexical scope and dynamic scope and what are their main differences?
The scope of a variable determines in which parts of the program that variable can be accessed. The simplest (and best known) example of scope is the global scope and local scope :
var x = 10; // Escopo global - pode ser acessada em qualquer lugar, inclusive em f
function f() {
var y = 20; // Escopo local - pode ser acessada somente dentro de f
}
Modern programming languages support the concept of nested structures . That is, a code structure contained in another code structure (rather than at the top-level):
class Foo {
int x;
void bar() {
int y;
}
class Baz { ... }
}
It is at this moment that a doubt arises: do the "inside" structures have access to "outside" structures or not? Each language implements this in a way.
var x = 0;
function foo() {
var x = 10;
return function() {
return x;
}
}
var bar = foo();
function baz() {
var x = 20;
bar();
}
baz(); // O que é retornado?
In dynamic-scoped languages, functions can access any variable present in the execution stack >. In the example above, as baz
set x = 20
and then called bar
, bar
can access that x
, and its value will be 20
.
Thistypeofscopeisdeprecated,sinceitisdifficulttokeeptrackofwhichvariablesarevisibleatanygiventime,aswellasharmingtheencapsulation(i.e.anyfunctioncallcouldatfirstmodifyanylocalcallingfunctionvariable).Thevastmajorityofmodernlanguagesdonotusethiskindofscope.
Inlexical-scopedlanguages,whatcountsisthe"grammatical" structure of the program, that is, if in the source code one structure is nested in another, the one inside can access variables in the outside. In the example, bar
is nested to foo
, so it can access its x
variable - even though foo
has already returned and is no longer in the stack.
Theabovefigureisasimplificationofthe Abstract Synthetic Tree > ( Abstract Syntax Tree - AST) of the sample code. Notice that - in a well-coded code - the level of each instruction in that tree corresponds to its identation level in the source code. In the anonymous function nested to foo
, the variable x
corresponds to the closest definition in the scopes hierarchy (in green).
The anonymous function does not define variables, foo
defines a x
, and the top-level defines x
, foo
, bar
and baz
. Since% w / w% of% w / w is "closer" than% w / w of top-level , it is who is accessible in the anonymous function. The x
of foo
is not considered - since it is not part of the lexical hierarchy - even though it is the caller anonymous function (saved in x
).
That is, you can precisely determine which variables are accessible by simple reading source code , without having to mentally visualize who calls what and in what order.
This type of scope is most commonly used in modern languages. In those that allow nested functions (as in the example above, in JavaScript), the access of an internal function to the local variables of the external function is called closure (cloister) , and requires a "spaghetti stack " to be possible. Others, which do not allow nested functions (such as Java), still use lexical scope to determine that inner classes have access to the fields of the outer classes (in the second example of this response, class x
has access to the baz
field of the bar
class).
From the text of Wikipedia
( Lexical scope vs dynamic scope ):
In Computer Science, scope is a bounding context to which values and expressions are associated. Programming languages have several types of scopes. The type of scope will determine what types of entities it can contain and how they are affected, in other words, its semantics. Typically, the scope is used to define the degree of information concealment, ie visibility and accessibility to variables in different parts of the program.
The lexical scope defines the scope in terms of the lexical structure of the program. With lexical scope, a name always refers to its lexical (more or less) local environment. This is a property of program text and is made independent of the call stack at runtime by the implementation of the language. That is, the lexical scope of a statement is the part of the text of the program, where the use of the identifier is a reference to that particular statement of the identifier.
Because this correspondence only requires analysis of the text of the static program, this type of scope delimitation is also called a static scope. Static scope is standard in all languages based on ALGOL, such as Pascal, ADA and C, because it allows the programmer to elaborate reasoning on values, parameters and object references (ie variables, constants, functions etc.). ), such as simple name substitutions. This makes it much easier to make the modular code and to reason about it, since the local naming structure can be understood in isolation. Because of the understanding that static scoping makes programming more reliable, there is a tendency to reject dynamic scoping.In contrast, dynamic scope forces the programmer to anticipate all possible dynamic contexts in which module code can be invoked.
With dynamic scope, each identifier has a global stack of bindings. Entering a local variable with the name of x
stacks a binding on the global heap x
in> which may be empty ), which will be unstacked when the control flow leaves the scope. Evaluating x
in any context always produces the top binding.
In other words, a global identifier refers to the identifier associated with the most recent environment. Note that this can not be done at compile time, because the binding stack only exists at runtime, which is why this type of delimitation is called dynamic scope .
Consider this example made in Pascal:
program A;
var I:integer; // Variável global
K:char; --------------------------
|
procedure B; |
var K:real; -----------------------
L:integer; |
|
procedure C; |
var M:real; |
begin |
(*escopo A+B+C*) |
end; |
|
procedure D; |
var K:integer; ----------------
begin
(*escopo A+B+D*)
end;
begin
(*escopo A+B*)
end;
begin
(*escopo A*)
end.
The variable I
is visible at all points, because it is never overturned by another variable of the same name. The variable char K
is visible only in the main program , because it is hidden by the variable K
B , C , and D only.
The L
variable is also visible only in procedures B , C and D , but not hides any other variable.
The M
variable is visible only in the C process and therefore is not accessible either from the B procedure, > D , or the main program.
In addition, the C and D procedures are only visible in procedures B , C , and D ( C and D are procedures with the same static parent and therefore see each other ), and therefore can not be called from the main program. >
In addition, there could still be another C procedure declared in the program, out of process B . The exact place in the program where C is called then determines which C procedure is called, and this is precisely analogous to the scope of variables.
What does a variable scope mean?
The scope of a variable represents the area of the program where it is visible.
Binding the data type of a variable can be specified in a static lexical or dynamic form.
Static scope (lexicon)
In programming languages with static scope (or lexicon), the scope is determined through the textual structure of the program. Using static scope (lexicon), the binding of a name in the environment is determined by the following algorithm:
It can be informally stated that the code snippet where a name is visible is the block where it was declared and all nested blocks within it, and for this reason it is often used "lexical scope" strong> as synonymous with "static scope" .
Dynamic Scope
In dynamic-scoped programming languages, the scope is determined through the program execution line, and therefore depends on the order of execution of the routines. Using dynamic scope, the valid binding for a name is the one most recently created during program execution, based on program unit call sequences, not on textual layout.
Example
x: integer
procedure print_x()
begin
print(x);
end
procedure p2
x: integer;
begin
x= 4;
print_x();
end
begin
x = 3;
p2();
end
If the scope is dynamic, the program prints 4. If the scope is static, the program prints 3.
Source: link