Scope. COMP 524: Programming Language Concepts Björn B. Brandenburg. The University of North Carolina at Chapel Hill

Similar documents
Scope. CSC 4181 Compiler Construction. Static Scope. Static Scope Rules. Closest Nested Scope Rule

Binding and Storage. COMP 524: Programming Language Concepts Björn B. Brandenburg. The University of North Carolina at Chapel Hill

LECTURE 14. Names, Scopes, and Bindings: Scopes

CSE 307: Principles of Programming Languages

Names, Scopes, and Bindings II. Hwansoo Han

Semantic Analysis. Outline. The role of semantic analysis in a compiler. Scope. Types. Where we are. The Compiler so far

The role of semantic analysis in a compiler

Semantic Analysis. Outline. The role of semantic analysis in a compiler. Scope. Types. Where we are. The Compiler Front-End

Every language has its own scoping rules. For example, what is the scope of variable j in this Java program?

Programming Languages

Chapter 3:: Names, Scopes, and Bindings (cont.)

Chapter 3:: Names, Scopes, and Bindings (cont.)

Programming Languages Third Edition. Chapter 7 Basic Semantics

G Programming Languages - Fall 2012

Chapter 5. Names, Bindings, and Scopes

Lecture 16: Static Semantics Overview 1

Lecture 7: Binding Time and Storage

Names, Scopes, and Bindings. CSE 307 Principles of Programming Languages Stony Brook University

Anatomy of a Compiler. Overview of Semantic Analysis. The Compiler So Far. Why a Separate Semantic Analysis?

Informal Semantics of Data. semantic specification names (identifiers) attributes binding declarations scope rules visibility

Names, Scopes, and Bindings. CSE 307 Principles of Programming Languages Stony Brook University

6. Names, Scopes, and Bindings

Attributes, Bindings, and Semantic Functions Declarations, Blocks, Scope, and the Symbol Table Name Resolution and Overloading Allocation, Lifetimes,

Static Semantics. Lecture 15. (Notes by P. N. Hilfinger and R. Bodik) 2/29/08 Prof. Hilfinger, CS164 Lecture 15 1

CS 330 Lecture 18. Symbol table. C scope rules. Declarations. Chapter 5 Louden Outline

COP4020 Programming Languages. Names, Scopes, and Bindings Prof. Robert van Engelen

CSCI312 Principles of Programming Languages!

The basic operations defined on a symbol table include: free to remove all entries and free the storage of a symbol table

Lecture 9: Parameter Passing, Generics and Polymorphism, Exceptions

The Procedure Abstraction

Names, Bindings, Scopes

Functional Programming

G Programming Languages - Fall 2012

CSC 533: Organization of Programming Languages. Spring 2005

Binding and Variables

The Compiler So Far. CSC 4181 Compiler Construction. Semantic Analysis. Beyond Syntax. Goals of a Semantic Analyzer.

CSCE 314 Programming Languages. Type System

LECTURE 18. Control Flow

CS1622. Semantic Analysis. The Compiler So Far. Lecture 15 Semantic Analysis. How to build symbol tables How to use them to find

Programming Languages Third Edition. Chapter 10 Control II Procedures and Environments

CMSC 330: Organization of Programming Languages

Topics Covered Thus Far. CMSC 330: Organization of Programming Languages. Language Features Covered Thus Far. Programming Languages Revisited

Syntax Errors; Static Semantics

Topics Covered Thus Far CMSC 330: Organization of Programming Languages

What about Object-Oriented Languages?

Fundamental Concepts and Definitions

Outline. Java Models for variables Types and type checking, type safety Interpretation vs. compilation. Reasoning about code. CSCI 2600 Spring

2 ADT Programming User-defined abstract data types

Compilers. Type checking. Yannis Smaragdakis, U. Athens (original slides by Sam

Compiler Theory. (Semantic Analysis and Run-Time Environments)

The Compiler So Far. Lexical analysis Detects inputs with illegal tokens. Overview of Semantic Analysis

Run-Time Data Structures

Lecture 7: Type Systems and Symbol Tables. CS 540 George Mason University

Answer: Early binding generally leads to greater efficiency (compilation approach) Late binding general leads to greater flexibility

Programming Language Concepts Scoping. Janyl Jumadinova January 31, 2017

Static Semantics. Winter /3/ Hal Perkins & UW CSE I-1

Type Bindings. Static Type Binding

CS 415 Midterm Exam Spring 2002

QUIZ. What is wrong with this code that uses default arguments?

Principles of Programming Languages Topic: Scope and Memory Professor Louis Steinberg Fall 2004

QUIZ. What are 3 differences between C and C++ const variables?

Implementing Subprograms

SE352b: Roadmap. SE352b Software Engineering Design Tools. W3: Programming Paradigms

Evolution of Programming Languages

G Programming Languages Spring 2010 Lecture 4. Robert Grimm, New York University

Run-time Environments - 2

NOTE: Answer ANY FOUR of the following 6 sections:

CS 536 Introduction to Programming Languages and Compilers Charles N. Fischer Lecture 11

Scope. Chapter Ten Modern Programming Languages 1

Object-Oriented Programming for Scientific Computing

Functions and Recursion

Chapter 5 Names, Binding, Type Checking and Scopes

G Programming Languages - Fall 2012

Concepts Introduced in Chapter 7

Short Notes of CS201

QUIZ on Ch.5. Why is it sometimes not a good idea to place the private part of the interface in a header file?

Programmiersprachen (Programming Languages)

CSE 504: Compiler Design. Runtime Environments

CS201 - Introduction to Programming Glossary By

Compiler construction

Names and Abstractions: What s in a Name?

Data Types. (with Examples In Haskell) COMP 524: Programming Languages Srinivas Krishnan March 22, 2011

Chapter 5: Procedural abstraction. Function procedures. Function procedures. Proper procedures and function procedures

Imperative Programming

CS558 Programming Languages

Where do we go from here?

Weeks 6&7: Procedures and Parameter Passing

12/4/18. Outline. Implementing Subprograms. Semantics of a subroutine call. Storage of Information. Semantics of a subroutine return

Subroutines. Subroutine. Subroutine design. Control abstraction. If a subroutine does not fit on the screen, it is too long

Object Oriented Design

Iterative Languages. Scoping

Procedure and Object- Oriented Abstraction

Symbol Tables. For compile-time efficiency, compilers often use a symbol table: associates lexical names (symbols) with their attributes

Inheritance, and Polymorphism.

About this exam review


A Short Summary of Javali

COMP322 - Introduction to C++ Lecture 02 - Basics of C++

Names, Scope, and Bindings

Programming Languages & Paradigms PROP HT Course Council. Subprograms. Meeting on friday! Subprograms, abstractions, encapsulation, ADT

Transcription:

Scope Björn B. Brandenburg The University of North Carolina at Chapel Hill Based in part on slides and notes by S. Olivier, A. Block, N. Fisher, F. Hernandez-Campos, and D. Stotts.

Referencing Environment All currently known names. The set of active bindings. At any given point in time during execution. Can change: names become valid and invalid during execution in most programming languages. Exception: early versions of Basic had only a single, global, fixed namespace. How is the referencing environment defined? Scope rules. The scope of a binding is its lifetime. I.e., the textual region of the program in which a binding is active. 2

Scope of a Binding The (textual) region in which a binding is active. float entity int entity Name time t0 t1 t2 t3 t4 void method() { int name; // code executed in [t1-t2). { float name; // code executed in [t2-t3). // code executed in [t3-t4). 3

Scope of a Binding The (textual) region Scope in which of name-to-int-entity a binding is active. binding. float entity int entity Name time t0 t1 t2 t3 t4 void method() { int name; // code executed in [t1-t2). { float name; // code executed in [t2-t3). // code executed in [t3-t4). 4

Scope of a Binding Scope The of (textual) name-to-float-entity region in which binding. a binding is active. float entity int entity Name time t0 t1 t2 t3 t4 void method() { int name; // code executed in [t1-t2). { float name; // code executed in [t2-t3). // code executed in [t3-t4). 5

Scope of a Binding The (textual) region in which a binding is active. float entity int entity Name Terminology: the name-to-int-entity binding time is out of scope in this code fragment. t0 t1 t2 t3 t4 void method() { int name; // code executed in [t1-t2). { float name; // code executed in [t2-t3). // code executed in [t3-t4). The scope is said to have a hole. 6

Language Scope Rules a major language design choice void printx() { printf( x = + x); what does x refer to? Dynamically Scoped. Active bindings depend on control flow. Bindings are discovered during execution. E.g., meaning of a name Statically Scoped. All bindings determined a compile time. Bindings do not depend on call history. Also called lexically scoped. depends on call stack. 7

Dynamically vs. Statically Scoped Which bindings are active in subroutine body? Dynamically Scoped: Subroutine body is executed in the referencing environment of the subroutine caller. Statically Scoped: Subroutine body is executed in the referencing environment of the subroutine definition. 8

Dynamic Scope Example # This is dynamically scoped Perl. $x = 10; sub printx {! # $x is dynamically scoped.! $from = $_[0];! print "from $from: x = $x \n"; sub test0 {! local $x; # binding of $x is shadowed.! $x = 0;!printX "test0" sub test1 {! local $x; # binding $x is shadowed.! $x = 1;!test0;!printX "test1" test1; printx "main"; 9

Dynamic Scope Example # This is dynamically scoped Perl. $x = 10; sub printx {! # $x is dynamically scoped.! $from = $_[0];! print "from $from: x = $x \n"; sub test0 {! local $x; # binding of $x is shadowed.! $x = 0;!printX "test0" sub test1 {! local $x; # binding $x is shadowed.! $x = 1;!test0;!printX "test1" New binding created. Existing variable is not overwritten, rather, the existing binding (if any) is shadowed. test1; printx "main"; 10

Dynamic Scope Example # This is dynamically scoped Perl. $x = 10; sub printx {! # $x is dynamically scoped.! $from = $_[0];! print "from $from: x = $x \n"; sub test0 {! local $x; # binding of $x is shadowed.! $x = 0;!printX "test0" sub test1 {! local $x; # binding $x is shadowed.! $x = 1;!test0;!printX "test1" Dynamically scoped: the current binding of $x is the one encountered most recently during execution (that has not yet been destroyed). test1; printx "main"; 11

Dynamic Scope Example # This is dynamically scoped Perl. $x = 10; sub printx {! # $x is dynamically scoped.! $from = $_[0];! print "from $from: x = $x \n"; Output: from test0: x = 0 from test1: x = 1 from main: x = 10 sub test0 {! local $x; # binding of $x is shadowed.! $x = 0;!printX "test0" sub test1 {! local $x; # binding $x is shadowed.! $x = 1;!test0;!printX "test1" test1; printx "main"; 12

Dynamic Scope Example # This is dynamically scoped Perl. $x = 10; sub printx {! # $x is dynamically scoped.! $from = $_[0];! print "from $from: x = $x \n"; Output: from test0: x = 0 from test1: x = 1 from main: x = 10 sub test0 {! local $x; # binding of $x is shadowed.! $x = 0;!printX "test0" sub test1 {! local $x; # binding $x is shadowed.! $x = 1;!test0;!printX "test1" test1; printx "main"; 13

Dynamic Scope Example # This is dynamically scoped Perl. $x = 10; sub printx {! # $x is dynamically scoped.! $from = $_[0];! print "from $from: x = $x \n"; Output: from test0: x = 0 from test1: x = 1 from main: x = 10 sub test0 {! local $x; # binding of $x is shadowed.! $x = 0;!printX "test0" sub test1 {! local $x; # binding $x is shadowed.! $x = 1;!test0;!printX "test1" test1; printx "main"; 14

Dynamic Scope Example # This is dynamically scoped Perl. $x = 10; sub printx {! # $x is dynamically scoped.! $from = $_[0];! print "from $from: x = $x \n"; Output: from test0: x = 0 from test1: x = 1 from main: x = 10 sub test0 {! local $x; # binding of $x is shadowed.! $x = 0;!printX "test0" sub test1 {! local $x; # binding $x is shadowed.! $x = 1;!test0;!printX "test1" test1; printx "main"; 15

Dynamic Scope Origin. Most early Lisp versions were dynamically scoped. Scheme is lexically scoped and became highly influential; nowadays, dynamic scoping has fallen out of favor. Possible use. Customization of service routines. E.g., field width in output. As output parameters for methods (write to variables of caller). Limitations. Hard to reason about program: names could be bound to anything. Accidentally overwrite unrelated common variables (i, j, k, etc.). Scope management occurs at runtime; this creates overheads and thus limits implementation efficiency. 16

Static Scope Example public class Scope {! static int x = 10;!! static void printx(string from) {!! System.out.println("from " + from + ": x = " + x);!!! static void test0() {!! int x = 0;!! printx("test0");!!! static void test1() {!! int x = 1;!! test0();!! printx("test1");!!! public static void main(string... args) {!! test1();!! printx("main");! 17

Static Scope Example public class Scope {! static int x = 10;!! static void printx(string from) {!! System.out.println("from " + from + ": x = " + x);!!! static void test0() {!! int x = 0;!! printx("test0");!!! static void test1() {!! int x = 1;!! test0();!! printx("test1");!!! public static void main(string... args) {!! test1();!! printx("main");! New binding created. Existing variable is not overwritten, rather, the existing binding (if any) is shadowed. 18

Static Scope Example public class Scope {! static int x = 10;!! static void printx(string from) {!! System.out.println("from " + from + ": x = " + x);!!! static void test0() {!! int x = 0;!! printx("test0");!!! static void test1() {!! int x = 1;!! test0();!! printx("test1");!!! public static void main(string... args) {!! test1();!! printx("main");! Output: from test0: x = 10 from test1: x = 10 from main: x = 10 19

Static Scope Example public class Scope {! static int x = 10;!! static void printx(string from) {!! System.out.println("from " + from + ": x = " + x);!!! static void test0() {!! int x = 0;!! printx("test0");!!! static void test1() {!! int x = 1;!! test0();!! printx("test1");!!! public static void main(string... args) {!! test1();!! printx("main");! Output: from test0: x = 10 from test1: x = 10 from main: x = 10 Lexically scoped: the binding of x is determined at compile time and based on the enclosing scope of the method definition. 20

Static Scope Example public class Scope {! static int x = 10;!! static void printx(string from) {!! System.out.println("from " + from + ": x = " + x);!!! static void test0() {!! int x = 0;!! printx("test0");!!! static void test1() {!! int x = 1;!! test0();!! printx("test1");!! shadowed shadowed! public static void main(string... args) {!! test1();!! printx("main");! Output: from test0: x = 10 from test1: x = 10 from main: x = 10 Scope of the outermost binding of x. 21

Static/Lexical Scope Variants. Single, global scope: Early Basic. Just two, global + local: Early Fortran. Nested scopes: modern languages. Advantages. Names can be fully resolved at compile time. Allows generation of efficient code; code generator can compute offsets. Easier to reason about; there is only one applicable enclosing referencing environment. 22

Nested Scopes If there are multiple bindings for a name to choose from, which one should be chosen? // this is C++ #include <iostream> using namespace std; int aname = 10; class AClass { private: int aname; public: AClass(); void amethod(); void bmethod(); ; AClass::AClass() { aname = 1; // continued void AClass::aMethod() { int aname = 2; cout << "a: " << aname << " " << ::aname << endl; void AClass::bMethod() { cout << "b: " << aname << " " << ::aname << endl; int main() {! AClass obj;! obj.amethod();! obj.bmethod();! return 0; 23

Nested Scopes If there are multiple bindings for a name to choose from, which one should be chosen? // this is C++ #include <iostream> using namespace std; int aname = 10; class AClass { private: int aname; public: AClass(); void amethod(); void bmethod(); ; AClass::AClass() { aname = 1; // continued void AClass::aMethod() { int aname = 2; cout << "a: " << aname << " " << ::aname << endl; void AClass::bMethod() { cout << "b: " << aname << " " << ::aname << endl; int main() {! AClass obj;! obj.amethod();! obj.bmethod();! return 0; Output: a: 2 10 b: 1 10 24

Nested Scopes Closest nested scope rule: a binding is active in the scope in which it is declared and If there are multiple bindings for a name to in each nested scope, unless it is shadowed by another binding choose from, which one should be chosen? (of the same name). This is the standard in Algol descendants. // this is C++ #include <iostream> using namespace std; int aname = 10; class AClass { private: int aname; public: AClass(); void amethod(); void bmethod(); ; AClass::AClass() { aname = 1; // continued void AClass::aMethod() { int aname = 2; cout << "a: " << aname << " " << ::aname << endl; void AClass::bMethod() { cout << "b: " << aname << " " << ::aname << endl; int main() {! AClass obj;! obj.amethod();! obj.bmethod();! return 0; Output: a: 2 10 b: 1 10 25

Nested Scopes C++: Scope Resolution Operator :: If there are multiple bindings for a name to Some languages, such as C++, allow the closestnested-scope rule to be overridden by explicitly choose from, which one should be chosen? referring to shadowed entities by their full name. // this is C++ #include <iostream> using namespace std; int aname = 10; class AClass { private: int aname; public: AClass(); void amethod(); void bmethod(); ; AClass::AClass() { aname = 1; // continued void AClass::aMethod() { int aname = 2; cout << "a: " << aname << " " << ::aname << endl; void AClass::bMethod() { cout << "b: " << aname << " " << ::aname << endl; int main() {! AClass obj;! obj.amethod();! obj.bmethod();! return 0; Output: a: 2 10 b: 1 10 26

Implementing Scope Symbol table. Map Name (Entity: Address, data type, extra info) Keeps track of currently known names. One of two central data structures in compilers. (the other is the abstract syntax tree). Implementation. Any map-like abstract data type. E.g.: Association list. Hash map. Tree map. But how to keep track of scopes? Constantly entering and removing table entries is difficult and slow. 27

Entering & Exiting a Scope Idea: one table per scope/block. Called the environment. Referencing environment = stack of environments. Push a new environment onto the stack when entering a nested scope Pop environment off stack when leaving a nested scope. Enter new declarations into top-most environment. Implementation. Can be implemented easily with a enclosing scope pointer. This is called the static chain pointer. The resulting data structure (a list-based stack of maps) is called the static chain. O(n) lookup time (n = nesting level). Optimizations and alternate approaches exist, esp. for interpreters. 28

Entering & Exiting a Scope Idea: one table per scope/block. Called the environment. Implementing the Closest Nested Scope Rule Referencing environment = stack of environments. Push To lookup a new a environment name aname: onto the stack when entering a nested curenv = top-most environment scope Pop while environment curenv off does stack not when contain leaving a aname: nested scope. curenv = curenv.enclosingenvirontment Enter new declarations into top-most environment. if curenv == null: // reached top of stack Implementation. Can be implemented easily with a enclosing scope pointer. throw new SymbolNotFoundException(aName) return curenv.lookup(aname) This is called the static chain pointer. The resulting data structure (a list-based stack of maps) is called the static chain. O(n) lookup time (n = nesting level). Optimizations and alternate approaches exist, esp. for interpreters. 29

Scoping & Binding Issues Scoping & Binding: Name resolution. Simple concepts but surprisingly many design and implementation difficulties arise. A few examples. Shadowing and type conflicts. Declaration order: where exactly does a scope begin? Aliasing. An object by any other name int foo; while ( ) { float foo; // ok? 30

Declaration Order Scope vs. Blocks. Many languages (esp. Algol descendants) are block-structured. if { // a block while ( ) { // a nested block BEGIN // a block REPEAT BEGIN // a nested block END UNTIL END What is the scope of a declaration? Usually, the scope of a declaration ends with the block in which it was declared. But where does it begin? Does declaration order matter? 31

Declaration Order Scope vs. Blocks. Example: Algol 60 Many languages (esp. Algol descendants) are block-structured. Declarations must appear at beginning of block and are valid if { // a block from the point on where BEGIN they are declared. // a block Thus, scope and block are almost the same thing. REPEAT while ( ) { BEGIN But how // do a you nested declare blocka recursive structure // a nested like a block linked list? END UNTIL END What is the scope of a declaration? Usually, the scope of a declaration ends with the block in which it was declared. But where does it begin? Does declaration order matter? 32

Declaration Order Scope vs. Blocks. Example: Pascal Many languages (esp. Algol descendants) are block-structured. Names must be declared before they are used, but the scope is the entire surrounding block. BEGIN if { // a block // a block REPEAT while ( ) { BEGIN // a nested block // a nested block END UNTIL END What is the scope of a declaration? Usually, the scope of a declaration ends with the block in which it was declared. But where does it begin? Does declaration order matter? 33

Declaration Order Scope vs. Blocks. Example: Pascal Many languages (esp. Algol descendants) are block-structured. Names must be declared before they are used, if { // a block while ( ) { but the scope is the entire surrounding block. BEGIN // a block REPEAT Surprising interaction BEGIN // a nested block // a nested block const N = 10; END END UNTIL procedure foo; { procedure is new block const What is the M scope = N; of a { declaration? error; N used before decl. Usually, the scope of a declaration ends with the block in which it was declared. N = 20; { ok; outer N shadowed But where does it begin? Does declaration order matter? 34

Variable /Attribute Scope in Java 35

Variable /Attribute Scope in Java Error: bar cannot be resolved (Scope of bar ends with block.) 36

Error: Variable /Attribute Scope in Java Duplicate local variable foo (local fooʼs scope not shadowed!) 37

Variable /Attribute Scope in Java Ok: local foo shadows attribute 38

Declaration Order in Java 39

Declaration Order in Java Error: bar cannot be resolved (Must be declared before use, like Pascal.) 40

Declaration Order in Java Ok: attribute foo not yet shadowed (both bar and local foo initialized to 3.0; differs from Pascal) 41

Declaration vs. Definition C/C++: Name only valid after declaration. How to define a list type (recursive type)? Next pointer is of the type that is being defined! How to implement mutually-recursive functions? E.g., recursive-descent parser. Implicit declaration. Compiler guesses signature of unknown function. signature: return value and arguments. Guesses wrong; this causes an error when actual declaration is encountered. 42

Declaration vs. Definition Solution: split declaration from definition. C/C++: can declare name without defining it. Called a forward declaration. A promise: Iʼll shortly tell you what it means. Declare before use; define later. Recursive structures possible. Also used to support separate compilation in C/C++. Declaration in header file. Definition not available until linking. Compiles without errors. 43

Declaration vs. Definition Solution: split declaration from definition. C/C++: can declare name without defining it. Called a forward declaration. A promise: Iʼll shortly tell you what it means. Declare before use; define later. Recursive structures possible. Also used to support separate compilation in C/C++. Declaration in header file. Definition not available until linking. If not defined: linker reports symbol not found error. Compiles without errors. Forward declaration without definition. 44

Aliasing Objects with multiple names. Aliasing: seemingly independent variables refer to same object. Makes understanding programs more difficult (reduced readability). Hinders optimization. In general, compiler cannot decide whether an object can become aliased in languages with unrestricted pointers/references. To avoid corner cases: possible optimizations disabled. double sum, sum_of_squares; void acc(double &x){ sum += x; sum_of_squares += x * x; acc(sum); 45

Aliasing Objects with multiple names. Aliasing: seemingly independent variables refer to same object. Makes understanding programs more difficult (reduced readability). Hinders optimization. C++: x is passed by reference (Function doesnʼt get a copy of the value, In general, compiler cannot but decide the actual whether address an object of x). can become aliased in languages with unrestricted pointers/references. To avoid corner cases: possible optimizations disabled. double sum, sum_of_squares; void acc(double &x){ sum += x; sum_of_squares += x * x; acc(sum); 46

Aliasing Objects with multiple names. Aliasing: seemingly independent variables refer to same object. Makes understanding programs more difficult (reduced readability). In this case, x and sum refer to the same object! Hinders optimization. In general, compiler cannot decide whether an object can become aliased in languages with unrestricted pointers/references. To avoid corner cases: possible optimizations disabled. double sum, sum_of_squares; void acc(double &x){ sum += x; sum_of_squares += x * x; acc(sum); 47

Aliasing Objects with multiple names. Aliasing: seemingly independent variables refer to same object. Makes understanding programs more difficult (reduced readability). Thus, the value of x changes Hinders optimization. between the two additions: In general, compiler cannot decide whether an object can become not a proper sum of squares. aliased in languages with unrestricted pointers/references. To avoid corner cases: possible optimizations disabled. double sum, sum_of_squares; void acc(double &x){ sum += x; sum_squares += x * x; acc(sum); 48

Aliasing Objects with multiple names. Aliasing: seemingly independent variables refer to same object. Makes understanding programs more difficult (reduced readability). Desirable optimization: keep the value of x in a register between additions. However, with aliasing, this is not a correct optimization: semantics of program would be altered in corner case! Hinders optimization. In general, compiler cannot decide whether an object can become aliased in languages with unrestricted pointers/references. To avoid corner cases: possible optimizations disabled. double sum, sum_of_squares; void acc(double &x){ sum += x; sum_squares += x * x; acc(sum); 49

Aliasing Objects with multiple names. Aliasing: seemingly independent variables refer to same object. Makes understanding programs more difficult (reduced readability). Hinders optimization. In general, compiler cannot decide whether an object can become aliased in languages with unrestricted pointers/references. To avoid corner cases: possible optimizations disabled. double sum, sum_of_squares; void acc(double &x){ When runtime efficiency is favored over language safety: sum += x; Some languages disallow or restrict aliasing, sum_squares += x * x; e.g., Fortran (aliasing illegal) and C99 (type restrictions). acc(sum); 50

Bottom Line Languages designed for efficient compilation are usually statically scoped. Rules for scopes, nested scopes, and shadowing are crucial elements of language design. Seemingly simple rules can give rise difficult corner cases and inconsistent behavior. Carefully read your languageʼs specification! 51

The Need for Modules / Namespaces Unstructured names. So far we have only considered flat namespaces. Typical for language design before the mid ʻ70ies. Sometimes multiple flat namespaces: E.g., one each for subroutines, types, variables and constants. No shadowing between variable start and a subroutine start in this case. Too much complexity. Referencing environment often contains thousands of names. OS APIs, libraries, the actual program, etc. Significant cognitive load, i.e., too many names confuse programmers. 52

The Need for Modules / Namespaces Possibly including names for internal helpers. Unstructured names. So far we have only considered flat namespaces. Programmer should not have to worry about these. Typical for language design before the mid ʻ70ies. Sometimes multiple flat namespaces: E.g., one each for subroutines, types, variables and constants. No shadowing between variable start and a subroutine start in this case. Thus, weʼd like some way to encapsulate unnecessary details and expose only a narrow interface. Too much complexity. Referencing environment often contains thousands of names. OS APIs, libraries, the actual program, etc. Significant cognitive load, i.e., too many names confuse programmers. 53

Name Clash Example in C 54

Name Clash Example in C Name already taken by POSIX API! (as are thousands of other names) 55

Name Clash Example in C Name already taken by POSIX API! (as are thousands of other names) Common kludge: prefix all names with library name E.g., use db_open instead of just open. 56

Module / Namespace / Package A means to structure names and enable information hiding. Collection of named objects and concepts. Subroutines, variables, constants, types, etc. Module A open solve Encapsulation: constrained visibility. Objects in a module are visible to each other y helper z (i.e., all module-internal bindings are in scope). Outside objects (e.g., those defined in other modules) are not visible unless explicitly imported. Objects are only visible on the outside (i.e., their bindingʼs scope can extend beyond the module) if they are explicitly exported. Module B open a b x imports Module C hidden internal names Visibility vs. Lifetime. Lifetime of objects is unaffected. Visiblity just determines whether compiler will allow name to be used: a scope a rule. better_open Module E clever_trick 57

Module / Namespace / Package A means to structure names and enable information hiding. Collection of named objects and concepts. Subroutines, variables, constants, types, etc. Hide internal helper definitions: encourages decomposition of Encapsulation: constrained visibility. Objects in a module are visible to each other problems into simpler parts without littering the global namespace. (i.e., all module-internal bindings are in scope). Outside objects (e.g., those defined in other modules) are not visible unless explicitly imported. Objects are only visible on the outside (i.e., their bindingʼs scope can extend beyond the module) if they are explicitly exported. Visibility vs. Lifetime. Lifetime of objects is unaffected. Visiblity just determines whether compiler will allow name to be used: a scope a rule. y Module A open helper Module B open solve b a imports x Module C better_open Module E clever_trick z hidden internal names 58

Module / Namespace / Package A means to structure names and enable information hiding. Collection of named objects and concepts. Subroutines, variables, constants, types, etc. Encapsulation: constrained visibility. Objects in a module are visible to each other (i.e., all module-internal bindings are in scope). Outside objects (e.g., those defined in other modules) are not visible unless explicitly imported. Avoid unintentional name clashes. Objects are only visible on the outside (i.e., their bindingʼs scope can extend beyond the module) if they are explicitly exported. Visibility vs. Lifetime. Lifetime of objects is unaffected. Visiblity just determines whether compiler will allow name to be used: a scope a rule. Selectively import desired names Module A open solve y helper z Module B open a b x imports Module C better_open Module E clever_trick hidden internal names 59

Imports & Exports Scope permeability. closed: names only become available via imports. Anything not explicitly imported is not visible. open: exported names become automatically visible. Can hide internals, but referencing environment can be large. selectively open: automatically visible with fully-qualified name; visible with short name only if imported. Java package scopes are selectively-open. 60

Imports & Exports Scope permeability. Closed wrt. short names : closed: names only become available via imports. IOException becomes only Anything not explicitly imported is not visible. available after explicit import. open: exported names become automatically visible. Can hide internals, but referencing environment can be large. selectively open: automatically visible with fully-qualified name; visible with short name only if imported. Java package scopes are selectively-open. 61

Imports & Exports Scope permeability. Open wrt. fully-qualified names: closed: names only become available via imports. Anything not explicitly imported is not visible. java.io.ioexception is always visible and thus a valid name. open: exported names become automatically visible. Can hide internals, but referencing environment can be large. selectively open: automatically visible with fully-qualified name; visible with short name only if imported. Java package scopes are selectively-open. 62

Imports & Exports Scope permeability. closed: names only become available via imports. Anything not explicitly imported is not visible. open: exported names become automatically visible. Can hide internals, but referencing environment can be large. selectively open: automatically visible with fully-qualified name; visible with short name only if imported. In Algol-like languages, subroutine scopes are usually open, but module scopes are often closed or selectively-open. Java package scopes are selectively-open. 63

Opaque Exports Hide implementation detail. Export type without implementation detail. A map ADT could be a hashmap, a tree, a list, etc. Want to export the abstract concept, but not the realization (which could change and should be encapsulated). Opaque export. Compiler disallows any references to structure internals, including construction. Explicitly supported by many modern languages. Can be emulated. Emulating opaque exports in Java. 64

Module as a manager. Module exists only once. Basically, a collection of subroutines and possibly types. Possibly hidden, internal state. Java: packages. type. Module can be instantiated multiple times. Can have references to modules. Each instance has its private state. Precursor to object-orientation. Java: class. 65

Capturing Bindings / Scope Scope of a binding can be extended via closures. When a closure is defined, it captures all active bindings. Weʼll return to this when we look at nested subroutines and first-class functions. 66