Scope
- Run this Python code
x = 3
def fun1():
x = 4
fun2()
def fun2():
print(x)
fun1()
- Static scoping, aka lexical scoping: The rules you already know.
- Typically applies to functions. In some languages, it may apply to blocks.
- “Whole block” vs. “rest of the block”.
- So what happens if a variable is used before it is declared?
- May be illegal (if variable must be defined before used.
- Variable may just be undefined.
- So what happens if a variable is used before it is declared?
- “Inner” variables typically hide or “shadow” outer variables.
- “global” variable: Variables declared outside a function or class.
- How to access variables hidden by a narrower scope?
- Some languages have a scope operator (e.g.,
::
) - PHP has a special global variable that is a hash containing all globals.
- Sometimes you just can’t.
- Some languages have a scope operator (e.g.,
- Dynamic scoping
function big() {
function sub1() {
var x = 7;
}
function sub2() {
var y = x;
var z = 3;
}
var x = 3;
}
- Consider what value of
x
would be used ifbig
calledsub1
which calledsub2
vs. ifbig
just calledsub2
. - Although dynamic scoping is easier to implement, most people find it more difficult to deal with. No modern languages have dynamic scoping as a default. To the best of my knowledge, only Perl and Common Lisp even offer it as an option.
-
Tex (the typesetting system) does use dynamic scoping. Knuth chose dynamic scoping for TeX because he wanted style settings such as font and size to be inherited from the caller when a macro is called without having to give these as explicit parameters or using global variables for these. Explicit parameters would be far too cumbersome, as there are a lot of style settings, and using global variables would mean that you would explicitly have to set a style back to what it was before after temporarily changing it. So instead of
\it{italic text \bf{boldface text} italic text}
if Tex used static scoping, you would have to do this
\it italic text \bf boldface text \it normal text
- Referencing Environment is the collection of all visible variables.
Closure
- Examine
closures.scm
- Imagine, if you will, a silly carnival- or pinball-like game where you collect points then get lots of bonus points for a variety of reasons.
- Look at the
apply-bonuses
function. It takes an array of lambdas. Each lambda examines the points and decides how much of a bonus to add. The output is the point total after applying the bonuses. (Bonuses are applied based on the original point total. Bonus A does not affect Bonus B for this example.) - In
bonus-set1
, we write a separate lambda for each bonus. Notice, however, that some of these lambdas are quite similar. - These “similar” rules could be abstracted into functions like
bonus-if-above
; but, they can’t be used directly byapply-bonuses
because the interface/signature isn’t right: It doesn’t have the correct number of parameters. - We could write a lambda to call these methods; but, that would save us much typing.
- Another idea is to change
bonus-if-above
slightly so that it constructs a lambda based on parameters. - We can then crate our list of bonus rules as shown with
bonus-set2
. - Where do the parameters get stored between the time the rule lambda is “constructed” and when it is applied? (Notice that in a language like C, the storage for the parameters to
make-*
are reclaimed when the function exits.)- In the “closure” around the lambda.
- When a lambda is created, it contains more than just code: It contains it’s entire referencing environment. k
Lifetime
- Lifetime is how long the storage for a variable is available.
- In other words, the time between the storage is allocated and de-allocated.
- “static” means storage is allocated before the program begins and remains for the entire program.
- Advantages?
- Speed: memory address can be hard-coded throughout the program.
- Disadvantages?
- Can’t be used for recursion
- May use extra memory (space is committed even when unnecessary – space can’t be shared. Two functions that are never active at the same time can’t take turns using space)
- Advantages?
- “stack-dynamic”
- Local variables that use the stack.
- Space is allocated on the stack when variable is declared.
- Advantages
- Space only consumed while function is active.
- Necessary for recursion (when multiple copies of a given function may be active)
- Disadvantages
- Access time is slightly slower because of indirection (Need to compute address using stack pointer before accessing data)
- Note: There is a difference between where a local variable is declared and when it is allocated.
- Variables declared in the middle of a function may be allocated at the beginning of the function for efficiency reasons.
- Variables declared in the middle of a function may or may not be accessible (in scope) at the beginning of the function.
- “Explicit heap dynamic”: Allocated with
malloc
/new
or something similar.- Advantages:
- Needed when newly created storage must last longer than the function.
- Allow data structures to grow and shrink
- Disadvantages:
- Requires indirection (which can be slower)
- Heap can get fragmented.
- Deallocation can be challenging. Explicit deallocation is error-prone. Garbage collection can be expensive.
- Advantages:
- “Implicit heap dynamic”: Allocated automatically
- e.g.,
var x = [1, 2, 3, 4, 5]
// array in JavaScript - Many of the same disadvantages as explicit heap dynamic
- e.g.,