Volume III · the gaps · binding, scoping, paradigms and translation

CMS 710 · Beyond the Four Modules

The class modules cover language definition, types, data structures and control flow. A Principles of Programming Languages paper also draws on binding times, static versus dynamic scoping, the full family of parameter-passing models, language paradigms and how translation actually works. This volume is that material, aligned to what the modules already say.
Prepared by Mbosinwa Awunor · www.mbosinwa.dev
Exam: Wednesday 12 Aug 2026 Time: 11:00 – 14:00 Venue: the exam hall Lecturers: the lecturers

Read this in the right order

§1 and §2 are direct extensions of the lecturer's own test questions · he asked about scope and lifetime, and the natural follow-up is binding times and static versus dynamic scoping; he asked about pass by value and reference, and the natural follow-up is the other three passing models. Learn those two sections first. §3–§6 are standard PPL topics the modules never reach; take them after Volumes I and II are secure.

1Names, bindings and the six attributes of a variable

Module 4 says a variable has a scope and a lifetime. In fact a variable is best understood as a six-tuple of attributes, and scope and lifetime are two of the six. This framing turns a two-item answer into a six-item one.

#AttributeWhat it is
1NameThe identifier used to refer to it in the source text
2AddressThe memory location it occupies · its l-value
3TypeThe set of values and permitted operations · Module 2's definition
4ValueThe contents of that location · its r-value
5LifetimeThe period during which it exists in memory · Module 4's definition
6ScopeWhere in the program it is visible · Module 4's definition
l-value and r-value · worth one line. In x = y, the l-value of x is used (its address, where the result goes) and the r-value of y is used (its contents). This is why 10 = x is illegal: a literal has an r-value but no l-value.

Aliases

Two names bound to the same memory address are aliases. Pass-by-reference creates one deliberately: inside void f(int &x), the name x and the caller's variable are aliases for one location. Aliasing is powerful but damages readability and reliability, because a change through one name silently changes the other · which is precisely the risk column in the pass-by-reference table.

Binding and binding time EXTENDS THE SCOPE QUESTION

A binding is an association between an attribute and an entity · between a name and a type, or a name and a memory address. Binding time is when that association is made.

Binding timeExample of what is bound then
Language design timeThe meaning of * as multiplication; the set of keywords
Language implementation timeThe range of int; how floating point is represented
Compile timeA variable's type in C++ · int x;
Link timeA call to a library function bound to its actual code
Load timeA global variable bound to its address when the program loads
Run timeA local variable bound to a stack address when its function is entered; a variable's value whenever it is assigned
KindDefinitionExample
Static bindingOccurs before run time and does not change during executionC++ int x = 10; · the type is fixed at compile time
Dynamic bindingOccurs during execution and may changePython x = 10 then x = "CMS710" · the type is rebound
This unifies Module 2 and Module 4. Static typing is early type binding; dynamic typing is late type binding. And the lifetime distinction in the lecturer's Q3 is a storage binding question: a global's address is bound at load time and never released, a local's at run time on entry and released on return. Saying it that way shows the two questions are one idea.

Storage bindings · the four categories

CategoryWhen storage is allocatedExampleAdvantage / disadvantage
StaticBefore execution begins, and kept for the whole programC++ static variables · globalsEfficient, direct addressing, values survive calls · but no memory reuse and no recursion support
Stack-dynamicWhen the declaration is elaborated, i.e. when the block is enteredOrdinary local variablesAllows recursion and shares memory between calls · but costs allocation time and indirect addressing
Explicit heap-dynamicBy an explicit instruction from the programmer at run timeC++ new / deleteFull flexibility · but unreliable and costly · leaks and dangling pointers
Implicit heap-dynamicAutomatically, on assignmentPython lists and objects; JavaScript arraysMaximum flexibility · but high run-time cost and errors are detected late

Why this matters for recursion: recursion is only possible because locals are stack-dynamic · each call gets a fresh set. If all variables were statically allocated, every recursive call would overwrite the previous one's data. That single sentence connects the lecturer's Q2 and Q3.

2Static vs dynamic scoping, and the other parameter-passing models

Static (lexical) vs dynamic scoping THE NATURAL FOLLOW-UP

Module 4 distinguishes global, local and block scope. A deeper question asks how a non-local name is resolved · and there are two answers.

BasisStatic (lexical) scopingDynamic scoping
RuleA name refers to the declaration in the nearest enclosing block in the program textA name refers to the declaration in the most recent active call at run time
ResolvedAt compile time, by reading the sourceAt run time, by searching the call chain
ReadabilityHigh · you can tell what a name means by readingLow · the meaning depends on who called
ReliabilityHighLow · a caller can accidentally capture a name
CostCheap · addresses known in advanceExpensive · a run-time search
Used byAlmost all modern languages · C++, Python, JavaScript, JavaEarly LISP, some shell languages, Perl's local
x = 10                     # global

def show():
    print(x)               # which x?

def caller():
    x = 99                 # local to caller
    show()

caller()

STATIC scoping  → prints 10   ← Python's answer
DYNAMIC scoping → prints 99   (would look up the caller)

The conclusion to write: languages overwhelmingly chose static scoping because it lets a reader · and a compiler · determine the meaning of every name from the program text alone, which serves the design goals of readability and reliability from Module 1.

Referencing environment

The referencing environment of a statement is the complete collection of names visible at that point. Under static scoping it is the local declarations plus those of all enclosing scopes; under dynamic scoping it is the locals of every active call. It is the formal way of saying "what is in scope here".

The five parameter-passing models EXTENDS TEST Q4

Module 4 gives by value and by reference. The full family, classified by direction of data flow, is:

ModelModeHow it works
Pass by valueinThe value is copied into the parameter; the caller's variable is never touched
Pass by resultoutNothing is passed in; the parameter's final value is copied back to the caller on return
Pass by value-resultin outCopied in and copied back on return · also called copy-restore
Pass by referencein outThe address is passed, so the function works directly on the caller's variable · no copying
Pass by name-The argument is textually substituted for the parameter and re-evaluated on every use · powerful, but confusing and now rare
Value-result vs reference · the classic exam distinction. Both let a function change the caller's variable, but value-result works on a copy and writes back at the end, while reference works on the original throughout. They differ if the same variable is passed twice, or if the function fails part-way: reference leaves partial changes behind, value-result does not.

Design considerations for parameter passing

  1. Efficiency · copying large objects is expensive, which argues for reference
  2. Safety · one-way (in mode) passing protects the caller's data
  3. Whether results should be returned through parameters at all, or only through return values

How the three course languages actually do it

LanguageMechanism
C++By value by default; by reference with &; by pointer with * and &. The programmer chooses explicitly · hence "parameter passing complexity: high"
PythonPass-by-object-reference · mutating the object affects the caller, rebinding the name does not
JavaScriptPrimitives by value; objects and arrays by reference to the object · the same split as Python

3Programming paradigms

Module 4 contrasts imperative and functional control flow. That is one cut through a larger classification, and "compare programming paradigms" is a standard question on this course.

ParadigmCore ideaLanguagesStrengths and weaknesses
Imperative / proceduralDescribes how a task is performed, as a sequence of statements that change program state. Built on the von Neumann architecture · variables model memory cells, assignment models storingC, C++, Pascal, Python, JavaScriptEfficient and close to the machine · but state changes make programs harder to reason about
Object-orientedPrograms are objects that combine data and behaviour, using encapsulation, inheritance and polymorphismC++, Java, Python, JavaScriptStrong modelling of real-world entities, reuse through inheritance · but added complexity and overhead
FunctionalDescribes what is to be computed by applying functions, avoiding changeable state and side effectsHaskell, Lisp, ML; supported in Python and JavaScriptSimpler code, easier reasoning, easier parallelism · but unfamiliar and sometimes less efficient
Logic / declarativePrograms are facts and rules; the system infers answers rather than following stepsProlog · the 4GL of Module 1Excellent for AI, reasoning and knowledge representation · but limited control over efficiency
ScriptingInterpreted, high-level languages for automating tasks and gluing components togetherPython, JavaScript, BashRapid development · but slower execution and late error detection
The von Neumann connection · a strong opening line. Imperative languages dominate because they mirror the von Neumann architecture, in which instructions and data share one memory and are processed sequentially. Variables correspond to memory cells, assignment to storing a value, and iteration to the efficient repetition of instructions already in memory. This is also why iteration is faster than recursion on such machines · a point that ties straight back to the lecturer's Q2.

Multi-paradigm languages. The three course languages are all multi-paradigm: C++ supports procedural, object-oriented and generic programming; Python supports procedural, object-oriented and functional; JavaScript supports procedural, object-oriented (prototype-based) and functional. A question asking which paradigm a language "is" is usually asking you to notice exactly that.

4Translation · compilation, interpretation and the phases

The three implementation methods

MethodHow it worksExample
CompilationThe whole program is translated to machine code before execution; the result runs directly on hardwareC++
Pure interpretationThe source is translated and executed statement by statement by an interpreter, with no machine-code outputEarly BASIC; Python conceptually
HybridThe source is compiled to an intermediate bytecode, which is then interpreted or JIT-compiled at run timeJava, JavaScript, Python's .pyc
BasisCompiledInterpreted
TranslationWhole program, before runningLine by line, during running
Execution speedFastSlower
Error detectionAll syntax errors found before executionFound only when the line is reached
PortabilityMachine-specific binaryPortable source
Development speedSlower · recompile to testFaster · run immediately
MemoryNeeds no translator at run timeInterpreter must be present

The phases of compilation · and where Module 3's trees live

Source code Lexical analysis Syntax analysis Semantic analysis Code generation Machine code → TOKENS → PARSE TREE → AST (optimization) scanner parser type checks
Module 3's parse trees and ASTs are the outputs of phases 2 and 3.
PhaseWhat it does
1. Lexical analysisGroups characters into tokens · keywords, identifiers, literals, operators. Catches illegal characters
2. Syntax analysisChecks tokens against the grammar (BNF) and builds the parse tree. Catches missing semicolons and mismatched brackets
3. Semantic analysisChecks meaning · type compatibility, undeclared variables · and produces the AST. This is where static semantics is enforced
4. OptimizationImproves the intermediate code without changing its meaning
5. Code generationEmits machine or object code from the AST

The symbol table runs alongside every phase, holding each identifier's name, type, scope and address · the six attributes of §1 in one data structure.

5Grammars and semantics in more depth

BNF and EBNF

BNF
<assign>  ::= <id> = <expr>
<expr>    ::= <expr> + <term> | <term>
<term>    ::= <term> * <factor> | <factor>
<factor>  ::= <id> | ( <expr> )

EBNF adds shorthand
  { }  zero or more repetitions
  [ ]  optional
  ( | ) choice
<expr> ::= <term> { (+ | -) <term> }
TermMeaning
TerminalA symbol that appears in the program itself · +, =, if
Non-terminalA named construct defined by a rule · <expr>
Start symbolThe non-terminal a whole program derives from
DerivationThe sequence of rule applications producing a sentence
Ambiguous grammarOne that allows two different parse trees for the same statement · a defect, because meaning becomes undefined

How a grammar encodes precedence: in the rules above, <term> handles * and sits below <expr>, which handles +. Because multiplication is generated deeper in the tree, it is evaluated first · exactly what Module 3's parse tree for a + b * c shows. That connection is worth a mark on its own.

Static and dynamic semantics

KindWhat it describes
Static semanticsRules that can be checked before execution but are not expressible in BNF · e.g. "a variable must be declared before use", "operand types must be compatible". Formalised with attribute grammars
Dynamic semanticsThe meaning of statements when executed

Three ways of describing dynamic semantics

MethodIdeaUsed for
OperationalDescribe meaning by the changes of state a statement causes on an abstract machineTeaching and language manuals
DenotationalMap each construct onto a mathematical object (a function) that denotes its meaningRigorous specification; hardest to read
AxiomaticDescribe meaning by logical assertions · preconditions and postconditionsProgram verification and correctness proofs
The one-line summary if asked: syntax is described by BNF, static semantics by attribute grammars, and dynamic semantics by operational, denotational or axiomatic methods. That sentence covers a whole question on language description.

Type checking, coercion and equivalence

6Language evaluation criteria, in the full form

Module 1 lists five design goals. The standard PPL treatment breaks the first three into the characteristics that cause them, which is what turns a five-line answer into a full-page one.

CriterionContributing characteristicWhat it means
Readability
the ease with which programs can be understood
SimplicityFew constructs, little feature multiplicity, minimal operator overloading. Too many ways to do one thing hurts the reader
OrthogonalityA small set of primitives combinable in a small number of ways, with few exceptions. High orthogonality means rules compose predictably
Data typesAdequate types and structures · a bool reads better than an int holding 0 or 1
Syntax designMeaningful keywords, clear form for compound statements, identifier rules
Control statementsWell-designed control structures · the argument against GOTO
Writability
the ease with which programs can be created
Simplicity and orthogonalityFewer constructs to remember, combined consistently
ExpressivityConvenient ways to specify computations · total = sum(numbers) over a written-out loop
Support for abstractionThe ability to define and use complex structures and operations while ignoring detail · Module 2's data abstraction
Reliability
performing to specification under all conditions
Type checkingTesting for type errors, ideally at compile time
Exception handlingIntercepting run-time errors and taking corrective action rather than crashing
Restricted aliasingLimiting the number of names bound to one address · see §1
Readability and writabilityBoth feed reliability: code that is hard to read or write is more likely to be wrong
CostTraining, writing, compiling, executing, maintainingThe total cost of ownership · maintenance often dominates, which is why Module 1 lists maintainability as a goal in its own right
Implementation system costThe cost and availability of compilers and tools, and the language's reliability record

Exception handling · worth knowing in outline

An exception is an unusual event, erroneous or not, detectable by hardware or software, that requires special processing. Exception handling lets a program intercept it and respond rather than terminate.

C++      try {
             risky();
         } catch (exception &e) {
             cout << "handled";
         }

Python   try:
             risky()
         except Exception:
             print("handled")

Its contribution: exception handling improves reliability, and Module 1 names it explicitly as one of the ways a language achieves that goal.

The trade-offs to quote in any design question

Trade-offThe tension
Simplicity vs expressivenessEasy to learn and read, versus powerful and concise
Efficiency vs safetyC++'s performance and explicit control, versus Python's productivity and protection
Flexibility vs reliabilityDynamic typing's rapid development, versus static typing's early error detection
Readability vs writabilityTerse constructs are quick to write and slow to read · the two goals genuinely conflict
Time vs spaceModule 3's data-structure principle: faster usually means more memory
The universal closing sentence for this course. No language optimises every criterion; language design is the deliberate selection of a point in these trade-offs to suit an intended domain · which is exactly why Python, JavaScript and C++ look so different while computing the same things.