Name: A mnemonic character string representing something else
Names do not have inherent meaning, we have to bind them to objects.
In python, + is overloadable, aka we can define __add__ on anything and the + operator will work on it.
Binding: an association between two entities. Typically between a name and the thing it refers to. ex: name and memory location, or name and function, or name and type definition.
Scope of a binding: the region The question is: at the current place in the program, what are the bindings in effect for this item? From the POV of the binding, where in the program is it visible? the region where it is active is its SCOPE.
Referencing environment: a complete set of bindings active at a certain point
Scope: a maximal region of the program where no bindings are destroyed. Partition a program into regions where bindings are neither created or destroyed. a Maximal region of such nature is a scope.
Static Scoping vs Dynamic Scoping The difference is always that static is stuff that I can figure out before the program runs, and dynamic is stuff that I can only check at runtime. Very fiew current languages use dynamic scoping.
Questions about bindings: What rules are used to determine bindings? Scoping rules When is the binding established? Mostly at compiletime, sometimes things can only be figured out at runtime. This is a tradeoff between flexibility and efficiency. If you commit to a certain choice at compiletime you get less freedom for what you can do at runtime How long does the binding/object exist? A object may live longer than its binding. Ex. when a function stops executing, its arguments disappear (the bindings) but the actual object will still exist Where is the bound object stored? i didnt hear what he said
Binding times Compile-time: - the earliest establishment of a binding can happen here - map high level lanugage constructs to machine code. - layout static data in memory. Link time: - resolve references between objects in separately compiled modules - when a function in one object file wants to use something in anothr object file, the linker has to be able to know where in the executable the functions are stored so they can be referenced.
Load time: - Assign machine addresses to static data.
Runtime: - bind values to variables - allocate dynamic data and assign it to variables - allocate local variabels to the stack. - When you allocate room on the heap and store a pointer, youre binding that name/pointer to the object on the heap.
Importance of binding times: - Early binding (happen during compile, link, load time before it runs): → faster code → do not add to execution cost of program. → Anything you can do before running the prgram takes time away from execution time, thus making the proogram faster. → typical in compiled languages. → often want to figure out as much as we can at compile time. - Late binding (runtime) → greater flexibility → typical in interpreted languages, dynamically typed languages. → opinion: much more freedom to write the type of code you want to write. zeh's argument is if you have well designed dynamically typed code, its easy to translated to statically typed code. → You dont even need generics to write generically typed code if the code is dynamically typed. zeh thinks checking for type compatibility at compile time is the best way to do it tho
Object and binding lifetime - Object lifetime: period between the creation and detruction of the object. from the time you call ‘ new’ to whenever it g3ets deleted, either deliberately or by a garbage collector. - Binding lifetimes: time between birth and death of binding (name to object association) → at any point, a given name can only refer to one object - Dangling reference: when the binding outlives the object. → source of seg faults, trying to dereference a pointer thats no longer yours. → need to figure out who holds the last binding to a given heap allocated object. the one holding the last binding should be the one to free it. if the last holder doesnt free it, then it won't be freed. but if someone other than the last holder frees it, then it might cause problems if the last hodler tries to do anything with it. → garbage collection is not cheap. garbage collection languages are generally slower than others. - Memory leak: an object outlives its last binding - → object needs to exist before you can create a binding to it. the mismatch can only happen when one dies before the other. → in general, the binding dying before the object isnt really a big deal. it happens all the time.
Storage allocation: if you can guarantee an object will last the entire length of the program, static is the best place for it. Static - stored in a fixed address Object on Stack - Object on Heap - memory fragmentation occurs as things get freed and reallcoated. OS or runtime system's heap manager needs to keep track of fragments and help make decisions on which chunk to allocate etc.
Static and Dynamic Scoping - Lexical (static) scoping → bindings are based on the nesting of code blocks → can be determined at compiletime - Dynamic scoping: → binding → every binding has a certain lifetime. calling a function, it creates a variable X, when it returns, x is destroyed. functions that F calls can use x, because its the last defined x that hasnt been destryoed yet since f hasnt returned. → EMACS LISP → Perl using static by default but you can switch to dynamic scoping for individual variables. →
sub f { my$a= 1; print"f:$a\n"; &printa(); } sub printa { print"p:$a\n";}
prints: f:1 p:2
dynamic scoping: $a= 2; &f(); sub f { local$a= 1; print"f:$a\n"; &printa(); } sub printa { print"p:$a\n";}
$a= 2; &f(); prints: f:1 p:1
- Lexical units: → packages, module, src files → classes, records, structures → procedures, functions, nested subroutines → blocks - An important vairant of lexical scoping: → the current binding for a name is the one encountered in the smallest encolsing lexical unit and preceding the current point in the program text. youre allowed to access anything in your current scope and surrounding scope, but ONLY if its defined before you (C ,C++) → This variant supports single pass compilation (for speed)
f(){ int x = 5; z = x*y #x is bound, y and z are free. can't figure out what they reference from this scope alone. }
Shallow and Deep binding
Shallow binding: free vars are bound when the subroutine is called deep: free vars are bound when the function is first passed as a parameter.
int x = 10;
function f(int a) { x = x + a; }
function g(function h){ int x = 30; h (100) print(x) }
function main*){ g(f); print(x) }
what is the output of this program with deep binding? - at the time f is passed as a parameter, then at the closent surrounding scope (global scope) x in f is bound to the global x. - g defines its own x, but thats not what f changes. - this would print “30 110”
What is the ouptput with shallow binding? - when f is actually called, the smallest surrounding scope tht defines an x is g, so that x gets bound. - this prints “130 10”