Title: CS412/413
1CS412/413
- Introduction to
- Compilers and Translators
- April 23, 1999
- Lecture 31 First-class functions
2Administration
- Programming Assignment 4due on Wednesday
- Reading Appel 15.1-15.6
3Advanced Language Support
- So far have considered one advanced language
feature objects - Next three lectures more useful language
features - first-class functions
- parametric polymorphism
- dynamic typing and meta-object protocols
- May 3, 5 applying compiler techniques to
compiler-like systems (interpreters, JITs,
source-to-source translators)
4First-class functions
- Many languages allow functions to be used in a
more first-class manner than in Iota or Java C,
C, ML, Modula-3, Pascal, Scheme,... - Passed as arguments to functions/methods
- Nested within containing functions (exc. C, C)
- Used as return values (exc. Modula-3, Pascal)
5Function Types
- Iota-F0 Iota with function values that can be
passed as arguments - Need to declare type of argument will use
program notation function(T1, T2) T3 to denote
the type T1 ?T2 ?T3. - Example sorting with a user-specified ordering
- sort(a arrayint, order function(int,
int)bool) - if (order(ai, aj)) ...
6Passing a Function Value
- leq(x int, y int) bool x lt y
- geq(x int, yint) bool x gt y
- sort(a arrayint, order function(int,
int)bool) sort(a1, leq) - sort(a2, geq)
- Allow abstraction over choice of functions
7Objects subsume functions!
- interface comparer
- compare(x int, yint) bool
-
- sort(a arrayint, cmp comparer)
- if (cmp.compare(ai, aj))
- class leq compare(x int, yint) x lt y
- sort(a1, new leq)
8Type-checking functions
- Same rules as in Iota static semantics, but
function invoked in function call may be a
general expression - Most general subtyping rule for functions uses
the same contravariance/covariance restrictions
on arguments/results can pass a function where
a function with different signature is expected
9Representing functions
- For Iota-F0, a function may be represented as a
pointer to its code (cheaper than an object) - Old translationT?id(E1,,En)? CALL(NAME(id),
T ?E1?,,T?En?) - New T?E0(E1,,En)? CALL(T?E0?,
T?E1?,,T?En?) T?id? NAME(id) (if id
is a global fcn)
10Nested Functions
- Provided by functional languages (Scheme, ML) and
Pascal, Modula-3 - Nested function able to access variables of the
containing lexical scope - Useful for implementing iterators
- interface set
- add(o object)
- contains(o object) bool
- members(f function(o object))
-
11Iteration in Iota-F1 (nested fcns)
- countAnimals(s set)
- count int 0
- loop_body(o object)
- if (o instanceof Animal) count
-
- s.members(loop_body)
- return count
-
- Nested functions may access, update variables
from containing scopes! Must change rep.
12Closure
- Representation of a function value is a closure
-- A pointer to the code plus a static link to
allow access to outer scopes. Static link is
implicit argument to code.
countAnimals(s set) count int
0 loop_body(o object) if (o instanceof
Animal) count s.members(loop_body) re
turn count
loop_bodycode
countAnimalsactivation
loop_body
members activation
code ptr
loop_body activation
static link
static link
13Supporting Closures
- T?E0(E1,,En)?
- ESEQ(MOVE(t1, T?E0?),
- CALL(t1, MEM(t14), T?E1?,, T?En?)
- T?id(..ai Ti..) Tr E?
- t1 malloc(8)
- Mt1 NAME(id)
- Mt14 FP
-
- What about variableaccesses?
countAnimalsstack frame
loop_body
loop_bodycode
members stack frame
loop_body stack frame
static link
14Static Link Chains
- f() int a
- g() int b
- h()
- c a b
-
-
f stack frame
a
...other function stack frames...
g stack frame
b
...other function stack frames...
h stack frame
15Progress Report
- Passed as arguments to functions/methods
- Nested within containing functions as local
variables - Used as return values
- If no nested functions, functions are just
pointers to code can be used as return values - Problem interaction with nested fcns
16Iota-F2 (function return)
- Augment Iota-F1 to allow the return type of a
function to be a function itself. Example - make_counter( ) function( ) int
- // returns a counter function
- int count
- inc( ) int count
- return inc
17Dangling static link!
make_counter( ) function( ) int //
returns a counter function int count inc( )
int count return inc
make_counterstack frame
count
inc
inc code
- Must heap-allocate the make_counter activation
record so that it persists after the call returns
18Heap allocation
make_counter( ) function( ) int //
returns a counter function int count inc( )
int count return inc
stack frame
activation record
count
inc
inc code
- Activation record ? stack frame
- Even local variable accesses indirected
19The GC side-effect
- If activation records are heap-allocated, every
function call creates an object that must be
garbage collected eventually -- increases rate of
garbage generation - Activation records of all lexically enclosing
functions are reachable from a closure via stack
link chains - Putting entire activation record in heap means a
lot of garbage is not collectable
20Escape analysis
- Variables only need to be stored on heap if they
can escape and be accessed after this function
returns - Only happens if
- variable is referenced from within some nested
function - the nested function is either returned or passed
to some function that might store it in a data
structure - This determination escape analysis
21Benefits of escape analysis
- Variables that dont escape are allocated on
stack frame instead of heap cheap to access - Closures dont hold down as much garbage
- One problem precise escape analysis is a global
analysis, expensive. Escape analysis must be
conservative.
22Summary
- Looked at 3 languages progressively making
functions more first-class - No lexical nesting (F0) fast. Represent as
pointer to code - Lexical nesting, no upward function values or
storage in data structures (F1) function value
is closure - Fully first-class (F2) heap-allocation of some
variables, some escape analysis needed to avoid
significant GC, performance hit - Functions become as expensive as objects (but are
more convenient for some coding)