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

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

Lecture08: Scope and Lexical Address

CA Compiler Construction

LECTURE 14. Names, Scopes, and Bindings: Scopes

Closures. Mooly Sagiv. Michael Clarkson, Cornell CS 3110 Data Structures and Functional Programming

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

Programming Language Concepts Scoping. Janyl Jumadinova January 31, 2017

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

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

What about Object-Oriented Languages?

Lecture 16: Static Semantics Overview 1

Closures. Mooly Sagiv. Michael Clarkson, Cornell CS 3110 Data Structures and Functional Programming

Evaluating Scheme Expressions

Today's Topics. CISC 458 Winter J.R. Cordy

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

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

CS 415 Midterm Exam Spring 2002

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 Front-End

Chapter 3:: Names, Scopes, and Bindings

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

Concepts Introduced in Chapter 7

CSE 307: Principles of Programming Languages

Chapter 5. Names, Bindings, and Scopes

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

CSCI312 Principles of Programming Languages!

CS 314 Principles of Programming Languages

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

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

Lecture #5 Kenneth W. Flynn RPI CS

Names, Bindings, Scopes

Iterative Languages. Scoping

Fundamental Concepts and Definitions

CMSC 330: Organization of Programming Languages. Closures (Implementing Higher Order Functions)

Late Binding; OOP as a Racket Pattern

Syntax Errors; Static Semantics

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

Parsing Scheme (+ (* 2 3) 1) * 1


The role of semantic analysis in a compiler

Functional Programming

Topics Covered Thus Far CMSC 330: Organization of Programming Languages

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

CMSC 330: Organization of Programming Languages

Programming Languages

Weeks 6&7: Procedures and Parameter Passing

Run-time Environments - 3

Functions and Recursion. Dr. Philip Cannata 1

PL Recitation 9/21/2010

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

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

Scope, Functions, and Storage Management

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

CS450: Structure of Higher Level Languages Spring 2018 Assignment 7 Due: Wednesday, April 18, 2018

Lecture 5: Methods CS2301

Semantic Analysis and Type Checking

Lexical Considerations

INF4820. Common Lisp: Closures and Macros

Special Topics: Programming Languages

Array Basics: Outline. Creating and Accessing Arrays. Creating and Accessing Arrays. Arrays (Savitch, Chapter 7)

JavaScript: Sort of a Big Deal,

Control Abstraction. Hwansoo Han

Dispatch techniques and closure representations

INDEX. A SIMPLE JAVA PROGRAM Class Declaration The Main Line. The Line Contains Three Keywords The Output Line

Chapter 5 Names, Binding, Type Checking and Scopes

The compilation process is driven by the syntactic structure of the program as discovered by the parser

Types and Type Inference

Administration CS 412/413. Advanced Language Support. First-class vs. Second-class. First-class functions. Function Types

CS 314 Principles of Programming Languages. Lecture 13

1 Lexical Considerations

Tail Calls. CMSC 330: Organization of Programming Languages. Tail Recursion. Tail Recursion (cont d) Names and Binding. Tail Recursion (cont d)

CS 415 Midterm Exam Spring SOLUTION

Properties of an identifier (and the object it represents) may be set at

Semantic Analysis. Lecture 9. February 7, 2018

The Environment Model

Classes and Objects 3/28/2017. How can multiple methods within a Java class read and write the same variable?

COMPILER DESIGN - RUN-TIME ENVIRONMENT

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

Anonymous Functions CMSC 330: Organization of Programming Languages

Nested Loops. A loop can be nested inside another loop.

Lexical Considerations

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

CMSC 330: Organization of Programming Languages. Closures (Implementing Higher Order Functions)

One Ring to rule them all, One Ring to bring them all,

Programming Languages

TAIL RECURSION, SCOPE, AND PROJECT 4 11

Class, Variable, Constructor, Object, Method Questions

Chap. 8 :: Subroutines and Control Abstraction

CSC 148 Lecture 3. Dynamic Typing, Scoping, and Namespaces. Recursion

Project 2: Scheme Interpreter

CS 314 Principles of Programming Languages. Lecture 11

Functional Programming. Pure Functional Programming

SEMANTIC ANALYSIS TYPES AND DECLARATIONS

The Environment Model. Nate Foster Spring 2018

The SPL Programming Language Reference Manual

Variables and Java vs C++

Final CSE 131B Spring 2004

Implementing Abstractions

Chapter 5 Names, Bindings, Type Checking, and Scopes

April 2 to April 4, 2018

Transcription:

Lexical Binding There are two ways a variable can be used in a program: As a declaration As a "reference" or use of the variable Scheme has two kinds of variable "declarations" -- the bindings of a let-expression and the parameters of a lambdaexpression. The scope of a declaration is the portion of the expression or program to which that declaration applies. Like Java and C, but unlike classic Lisp, Scheme uses lexical binding (sometimes called static binding), which means that the scope of a variable is determined by the textual layout of the program.

Every language has its own scoping rules. For example, what is the scope of variable j in this Java program? public static void main(string[] args) { int i; i = 1; while (i < 10) { int j; j = i; System.out.write(i); i += 1; } System.out.write(j); }

In Scheme it is tempting to say that the scope of a variable declared in the bindings of a let-expression is the body of the expression, but this isn't the case. For example (let ([x 5]) (* ((lambda (x) (+ x 3) ) 7) x ) ) the scope of the [x 5] declaration is only the second operand of the *-expression. It is more accurate to say that the scope of a variable declared in a let-expression or lambda-expression is the body of that expression unless that variable also occurs bound in the body.

If the variable occurs bound in the body, we say that the inner binding shadows the outer binding. To determine the appropriate binding to which a bound variable refers: Start at the reference (usage of the variable). Search the enclosing regions starting with the innermost and working outward, looking for a declaration of the variable. The first declaration you find is the appropriate binding. If you don't find such a binding the variable is free.

Contour diagrams draw the boundaries of the regions in which variable declarations are in effect: (lambda (x) (lambda (y) ((lambda (x) (x y) ) x) ) ) The body of a let or lambda expression determines a contour. Each variable refers to the innermost declaration outside its contour.

The lexical depth of a variable reference is 1 less than the number of contours crossed between the reference and the declaration it refers to. For example (lambda (x) (lambda (y) (+ x y) ) ) In the (+ x y) portion of this expression x has lexical depth 1, while y has lexical depth 0.

(lambda ( x y) ( (lambda (a) (+ x (* a y ) ) ) x ) Here x has lexical depth 1 Here x has lexical depth 0

The lexical address of a variable reference consist of a pair: a) The lexical depth of the reference b) The 0-based position of the variable in its declaration. We might write this as [depth:position]

For example, consider the expression (let ([x 3] [y 4]) (lambda (a b) (lambda (c) (a ( + ( b x) c) ) ) ) [1:0] [1:1] [2:0] [0:0]

We could use lexical addresses to completely replace variable names: (let ([3] [4]) (lambda 2 (lambda 1 ([1:0] ( + ( [1:1] [2:0]) [0:2) ) ) ) The lexical address is essentially a pointer to where the variable can be found on the runtime stack.

Dynamic Binding What is the value of the following expression? (let ([y 3]) (let ([f (lambda (x) (+ x y) ) ]) (let ([y 17]) (f 2) ) ) ) The real question, of course, is What is the value of y in the body of f when we call (f 2)? a) Scheme, Java and C use static binding, also called lexical binding. They connect the reference of y to the nearest surrounding declaration of y, which in this case is [y 3]. b) Early Lisp used dynamic binding, which connects a reference of y to the most recent declaration of y, which in this case is [y 17].

We have talked before about how to evaluate lambda expressions and applications (function calls) in Scheme, which is lexically scoped -- a lambda expression evaluates to a closure, which is a pair containing the environment at the time the lambda is evaluated (the surrounding environment) and the parameters and body of the lambda expression. When we apply this closure to argument expressions we evaluate the arguments in the current environment, make a new environment that extends the closure's environment with the new bindings, and evaluate the closure's body within this new environment.

In Java and C, which are also lexically scoped but without lambda expressions, the environments are much more static. At the time a program is compiled the compiler can keep track of the environments and link each variable reference to its declaration and its location on the runtime stack.

Think back to this example: (let ([y 3]) (let ([f (lambda (x) (+ x y) ) ]) (let ([y 17]) (f 2) ) ) ) In dynamic scoping the binding of y that applies in the application (f 2) is [y 17], and the whole expression returns 19. How would you evaluate lambdas and applications in a dynamically scoped language?

a) There is no need for closures; they maintain the lexical environment, which dynamic binding does not use. b) The value of a lambda expression is just its parameters and body. c) To apply a procedure to a list of arguments, we extend the current environment with the bindings of the parameters to their argument values and evaluate the body in this environment.

Why do (or did) people use dynamic binding? It was easy to implement. Indeed, dynamic binding was understood several years before static binding. It made sense to some people; the function (lambda (x) (+ x y) should use whatever the latest version of y. Why do we now use lexical binding? Most languages we use today are derived from Algol- 60, which used lexical binding. Compilers can use lexical addresses, known at compile time, for all variable references. Code from lexically-bound languages is easier to verify. It makes more sense to most people.