Supplementary Notes on Exceptions

Similar documents
Lecture Notes on Aggregate Data Structures

Category Item Abstract Concrete

Part VI. Imperative Functional Programming

Type Safety. Java and ML are type safe, or strongly typed, languages. C and C++ are often described as weakly typed languages.

Lecture Notes on Induction and Recursion

CS-XXX: Graduate Programming Languages. Lecture 9 Simply Typed Lambda Calculus. Dan Grossman 2012

1 Introduction. 3 Syntax

Programming Languages

Assignment 4: Evaluation in the E Machine

Types for References, Exceptions and Continuations. Review of Subtyping. Γ e:τ τ <:σ Γ e:σ. Annoucements. How s the midterm going?

CS 6110 S11 Lecture 25 Typed λ-calculus 6 April 2011

Lecture Notes on Static and Dynamic Semantics

Operational Semantics. One-Slide Summary. Lecture Outline

At build time, not application time. Types serve as statically checkable invariants.

15 212: Principles of Programming. Some Notes on Induction

CSE505, Fall 2012, Midterm Examination October 30, 2012

Programming Languages Lecture 15: Recursive Types & Subtyping

Lecture Notes on Static Semantics

CS558 Programming Languages

Programs as data first-order functional language type checking

Harvard School of Engineering and Applied Sciences Computer Science 152

Modal Logic: Implications for Design of a Language for Distributed Computation p.1/53

Lecture Notes on Program Equivalence

Type Checking and Type Inference

Programming Languages Lecture 14: Sum, Product, Recursive Types

CSE341: Programming Languages Lecture 17 Implementing Languages Including Closures. Dan Grossman Autumn 2018

CVO103: Programming Languages. Lecture 5 Design and Implementation of PLs (1) Expressions

We defined congruence rules that determine the order of evaluation, using the following evaluation

Programming Languages Assignment #7

CS152: Programming Languages. Lecture 11 STLC Extensions and Related Topics. Dan Grossman Spring 2011

CS4215 Programming Language Implementation. Martin Henz

Harvard School of Engineering and Applied Sciences CS 152: Programming Languages

Lecture 3: Recursion; Structural Induction

A Type System for Object Initialization In the Java TM Bytecode Language

CSE 413 Languages & Implementation. Hal Perkins Winter 2019 Structs, Implementing Languages (credits: Dan Grossman, CSE 341)

Harvard School of Engineering and Applied Sciences CS 152: Programming Languages

Lecture Outline. COOL operational semantics. Operational Semantics of Cool. Motivation. Notation. The rules. Evaluation Rules So Far.

15 212: Principles of Programming. Some Notes on Continuations

Agenda. CS301 Session 9. Abstract syntax: top level. Abstract syntax: expressions. The uscheme interpreter. Approaches to solving the homework problem

3.7 Denotational Semantics

CSE 505: Concepts of Programming Languages

Mutable References. Chapter 1

Lecture 3 Notes Arrays

Note that in this definition, n + m denotes the syntactic expression with three symbols n, +, and m, not to the number that is the sum of n and m.

Assignment 4: Semantics

CS558 Programming Languages

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

Lists. Michael P. Fourman. February 2, 2010

Harvard School of Engineering and Applied Sciences CS 152: Programming Languages

Where is ML type inference headed?

Runtime Behavior of Conversion Interpretation of Subtyping

On the Logical Foundations of Staged Computation

Konzepte von Programmiersprachen

CS 565: Programming Languages. Spring 2008 Tu, Th: 16:30-17:45 Room LWSN 1106

Boolean expressions. Elements of Programming Languages. Conditionals. What use is this?

Fall Lecture 3 September 4. Stephen Brookes

Type Systems for Concurrent Programs

COS 320. Compiling Techniques

References and Exceptions. CS 565 Lecture 14 4/1/08

Lecture 1 Contracts. 1 A Mysterious Program : Principles of Imperative Computation (Spring 2018) Frank Pfenning

1. Abstract syntax: deep structure and binding. 2. Static semantics: typing rules. 3. Dynamic semantics: execution rules.

Lecture Notes on Computational Interpretations of Modalities

Operational Semantics

The Substitution Model

Lecture Notes on Data Representation

Lecture Outline. COOL operational semantics. Operational Semantics of Cool. Motivation. Lecture 13. Notation. The rules. Evaluation Rules So Far

CSCI B522 Lecture 11 Naming and Scope 8 Oct, 2009

Review. CS152: Programming Languages. Lecture 11 STLC Extensions and Related Topics. Let bindings (CBV) Adding Stuff. Booleans and Conditionals

Recitation 8: Dynamic and Unityped Languages : Foundations of Programming Languages

Simply-Typed Lambda Calculus

Compiler Construction Lent Term 2015 Lectures 10, 11 (of 16)

Featherweight Java (FJ)

Operational Semantics of Cool

Static Program Analysis

CSE 341, Autumn 2005, Assignment 3 ML - MiniML Interpreter

Lecture 1 Contracts : Principles of Imperative Computation (Fall 2018) Frank Pfenning

Variables. Substitution

Semantic Analysis and Type Checking

Subtyping. Lecture 13 CS 565 3/27/06

Type-directed Syntax Transformations for ATS-style Programs with Proofs

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

Supplementary Notes on Abstract Syntax

Typed Lambda Calculus and Exception Handling

CA Compiler Construction

Introduction to SML Getting Started

Overview. finally and resource cleanup

Typical workflow. CSE341: Programming Languages. Lecture 17 Implementing Languages Including Closures. Reality more complicated

Lecture Notes on Ints

CS421 Spring 2014 Midterm 1

Pierce Ch. 3, 8, 11, 15. Type Systems

Outline. Introduction Concepts and terminology The case for static typing. Implementing a static type system Basic typing relations Adding context

Abstract Interpretation

Lecture Notes on Contracts

` e : T. Gradual Typing. ` e X. Ronald Garcia University of British Columbia

CSE 341, Spring 2011, Final Examination 9 June Please do not turn the page until everyone is ready.

CS 6110 S11 Lecture 12 Naming and Scope 21 February 2011

CSE413: Programming Languages and Implementation Racket structs Implementing languages with interpreters Implementing closures

Documentation for LISP in BASIC

Type Inference Systems. Type Judgments. Deriving a Type Judgment. Deriving a Judgment. Hypothetical Type Judgments CS412/CS413

Chapter 13: Reference. Why reference Typing Evaluation Store Typings Safety Notes

Transcription:

Supplementary Notes on Exceptions 15-312: Foundations of Programming Languages Frank Pfenning Lecture 9 September 25, 2002 In this lecture we first give an implementation of the C-machine for the fragment containing integers, booleans, and functions using higher-order functions. We then discuss exceptions as an extension of the C-machine [Ch. 13] The implementation of the C-machine is to represent the stack as a continuation that encapsulates the rest of the computation to be performed. 1 First, in our implementation, both expressions and value have type exp. We nonetheless use different names to track our intuition, even though the type system of ML does not help use verify the correctness of this intuition. type value = exp e : exp v : value Next, the stack k is represented by an ML function k : value -> value Applying this function to a value v will carry out the rest of the computation of the machine, returning the final answer. Finally, we have two functions 1 We give some code excerpts here; the full code can be found at http://www.cs.cmu.edu/ fp/courses/312/code/09-exceptions/.

L9.2 Exceptions eval : exp -> (value -> value) -> value return : value -> (value -> value) -> value satisfying the specification: (i) eval e k a iff k > e c < a (ii) return v k a iff k < v c < a In order to implement stacks as ML functions, it is useful to introduce some new auxiliary functions to represent the frames. We give in the table below the association between forms of the stack and the corresponding ML function. We omit only the case for primops which requires a simple treatment of lists. k if(, e 2, e 3 ) (fn v1 => ifframe (v1, e2, e3) k) k apply(, e 2 ) (fn v1 => applyframe1 (v1, e2) k) k apply(v 1, ) (fn v2 => applyframe2 (v1, v2) k) k let(, x.e 2 ) (fn v1 => letframe (v1, ((), e2)) k) (fn v => v) The case of the empty stack corresponds to the initial continuation, which simply returns the value passed to it as the result of the overal computation Now we can piece together the whole code elegantly, as advertised. We have elided only the case for primitive operations, which can be found with the complete code at the address given above.

Exceptions L9.3 fun eval (v as Int ) k = return v k (* elided primops *) eval (v as Bool ) k = return v k eval (If(e1, e2, e3)) k = eval e1 (fn v1 => ifframe (v1, e2, e3) k) eval (v as Fun ) k = return v k eval (Apply(e1, e2)) k = eval e1 (fn v1 => applyframe1 (v1, e2) k) eval (Let(e1, ((), e2))) k = eval e1 (fn v1 => letframe (v1, ((), e2)) k) (* eval (Var ) k impossible by MinML typing *) and ifframe (Bool(true), e2, e3) k = eval e2 k ifframe (Bool(false), e2, e3) k = eval e3 k (* other expressions impossible by MinML typing *) and applyframe1 (v1, e2) k = eval e2 (fn v2 => applyframe2 (v1, v2) k) and applyframe2 (v1 as Fun(,, ((), (), e1 )), v2) k = eval (Subst.subst (v1, 2, Subst.subst (v2, 1, e1 ))) k (* other expressions impossible by MinML typing *) and letframe (v1, ((), e2)) k = eval (Subst.subst (v1, 1, e2)) k and return v k = k v The overall evaluation just starts with the initial continuation which corresponds to the empty stack. fun evaluate e = eval e (fn v => v) This style of writing an interpreter is also refered to as continuationpassing style. It is quite flexible and elegant, and will be exercised in Assignment 4. Next we come to exceptions. We introduce a new form of state k fail which signals that we are propagation an exception upwards in the control stack k, looking for a handler or stopping at the empty stack. This uncaught exception is a particularly common form of implementing runtime errors. We do not distinguish different exceptions, only failure. For more complex variations of exceptions, see [Ch. 13] and Assignment 4. We have two new forms of expressions fail(τ) (with concrete syntax

L9.4 Exceptions fail[τ]) 2 and try(e 1, e 2 ) (with concrete syntax try e 1 ow e 2 ). Informally, try(e 1, e 2 ) evaluates e 1 and returns its value. If the evaluation of e 1 fails, that is, an exception is raised, then we evaluate e 2 instead and returns its value (or propagate its exception). These rules are formalized in the C- machine as follows. k > try(e 1, e 2 ) c k try(, e 2 ) > e 1 k try(, e 2 ) < v 1 c k < v 1 k > fail(τ) c k fail k f fail c k fail for f try(, ) k try(, e 2 ) fail c k > e 2 In order to verify that these rules are sensible, we should prove appropriate progress and preservation theorems. In order to do this, we need to introduce some typing judgments for machine states and the new forms of expressions. First, expressions: Γ fail(τ) : τ Γ e 1 : τ Γ e 2 : τ Γ try(e 1, e 1 ) : τ The new judgment for typing states depends on a typing for stacks. A stack is characterized by the type of the argument it expects and the type of the final answer it returns. We write ρ for the type of the final answer. Note that during the whole computation of a machine, this never changes. The new judgments are s OK ρ k : τ stack ρ state s is well-formed with final answer type ρ stack k accepts a value of type τ and returns a final answer of type ρ Since ρ never changes for any run of the machine, we omit the subcript in some of the rules below. However, keep in mind that it is implicitly present. Note also that judgments on states and stacks do not need to be hypothetical judgments, since they never contain free variables. First, the rules for states which ensure that the type expected by a stack matches the type of the expression to be evaluated, or value being returned. 2 The type is written here in order to preserve the property that every well-typed expression has a unique type.

Exceptions L9.5 k : τ stack ρ e : τ k > e OK ρ k : τ stack ρ v : τ v value k < v OK ρ k : τ stack ρ k fail OK ρ The rules for stacks are straightforward, given a few examples below. : ρ stack ρ k : τ 1 stack e 2 : τ 2 k apply(, e 2 ) : τ 2 τ 1 stack k : τ 1 stack v 1 : τ 2 τ 1 v 1 value k apply(v 1, ) : τ 2 stack k : τ stack e 2 : τ e 3 : τ k if(, e 2, e 3 ) : bool stack k : τ stack e 2 : τ k try(, e 2 ) : τ stack k : τ 2 stack x:τ 1 e 2 : τ 2 k let(, x.e 2 ) : τ 1 stack We can now state (without proof) the preservation and progress properties. The proofs follow previous patterns (see [Ch. 13]) and Lecture 5 on Type Safety. 1. (Preservation) If s OK ρ and s s then s OK ρ. 2. (Progress) If s OK ρ then either (i) s s for some s, or (ii) s = < v with v value, or (iii) s = fail.

L9.6 Exceptions The manner in which the C-machine operates with respect to exceptions may seem a bit unrealistic, since the stack is unwound frame by frame. However, in languages like Java this is not an unusual implementation method. In ML, there is more frequently a second stack containing only handlers for exceptions. The handler at the top of the stack is innermost and a fail expression can jump to it directly. Overall, this machine should be equivalent to the specification of exceptions above, but potentially more efficient. Often, we want to describe several aspects of execution behavior of a language constructs in several different machines, keeping the first as high-level as possible. In our simple language, the handler stack h contains only frames ow(k, e 2 ) while the control stack contains the usual frames, and try( ) (the otherwise clause has moved to the handler stack). All the usual rules are augmented to carry a control stack and a handler stack, and leave the handler unchanged. (h, k) > apply(e 1, e 2 ) c (h, k apply(, e 2 )) > e 1 (h, k) > try(e 1, e 2 ) c (h ow(k, e 2 ), k try( )) > e 1 (h ow(k, e 2 ), k try( )) < v 1 c (h, k) < v 1 (h ow(k, e 2 ), k) > fail(τ) c (h, k ) > e 2 Note that we do not unwind the control stack explicilty, but jump directly to the handler when an exception is raised. This handler must story a copy of the control stack in effect at the time the try expression was executed. Fortunately, this can be implemented without the apparent copying of the stack in the rule for try, because we can just keep a pointer to the right frame in the control stack [Ch. 13]. Note also in case of a regular return for the subject of a try expression, we need to pop the corresponding handler off the handler stack.