A Fix for Dynamic Scope

50
A Fix for Dynamic Scope Ravi Chugh U. of California, San Diego

description

A Fix for Dynamic Scope. Ravi Chugh U. of California, San Diego. Backstory. Goal: Types for “Dynamic” Languages. Syntax and Semantics of JavaScript. Translation à la Guha et al. (ECOOP 2010). Core λ -Calculus + Extensions. Backstory. Goal: Types for “Dynamic” Languages. - PowerPoint PPT Presentation

Transcript of A Fix for Dynamic Scope

Page 1: A Fix for Dynamic Scope

A Fix for Dynamic Scope

Ravi ChughU. of California, San Diego

Page 2: A Fix for Dynamic Scope

2

BackstoryGoal: Types for “Dynamic” Languages

Core λ-Calculus+ Extensions

Syntax and Semanticsof JavaScript

Translation à la Guha et al.

(ECOOP 2010)

Page 3: A Fix for Dynamic Scope

3

BackstoryGoal: Types for “Dynamic” Languages

Core λ-Calculus+ Extensions

Approach: Type Check Desugared Programs

Simple Imperative, RecursiveFunctions are Difficult to Verify

Page 4: A Fix for Dynamic Scope

4

Translate to statically typed calculus?

var fact = function(n) { if (n <= 1) { return 1; } else { return n * fact(n-1); }};

Page 5: A Fix for Dynamic Scope

5

let fact = λn. if n <= 1 then 1 else n * fact(n-1)

Option 1: λ-Calculus (λ)

Translate to statically typed calculus?

var fact = function(n) { if (n <= 1) { return 1; } else { return n * fact(n-1); }};

fact is not bound yet…

Page 6: A Fix for Dynamic Scope

6

let fact = fix (λfact. λn. if n <= 1 then 1 else n * fact(n-1)) Desugared fact should be

mutable…

Option 2: λ-Calculus + Fix (λfix)

Translate to statically typed calculus?

var fact = function(n) { if (n <= 1) { return 1; } else { return n * fact(n-1); }};

Page 7: A Fix for Dynamic Scope

7

let fact = ref (fix (λfact. λn. if n <= 1 then 1 else n * fact(n-1)))Recursive call doesn’t go through

reference…Okay here, but prevents mutual recursion

Option 3: λ-Calculus + Fix + Refs (λfix,ref)

Translate to statically typed calculus?

var fact = function(n) { if (n <= 1) { return 1; } else { return n * fact(n-1); }};

Page 8: A Fix for Dynamic Scope

8

let fact = ref (λn. if n <= 1 then 1 else n * !fact(n-1)) Yes, this captures the

semantics!But how to type check ???

Option 4: λ-Calculus + Fix + Refs (λref)

Translate to statically typed calculus?

var fact = function(n) { if (n <= 1) { return 1; } else { return n * fact(n-1); }};

Page 9: A Fix for Dynamic Scope

9

let fact = ref (λn. if n <= 1 then 1 else n * !fact(n-1))

Page 10: A Fix for Dynamic Scope

10

let fact = ref (λn. 0) infact := λn. if n <= 1 then 1 else n * !fact(n-1);

Backpatching Pattern in λref

fact :: Ref (Int Int)

Assignment relies on and guarantees

the reference invariant

Page 11: A Fix for Dynamic Scope

11

let fact = ref (λn. 0) infact := λn. if n <= 1 then 1 else n * !fact(n-1);

Backpatching Pattern in λref

But we want to avoid initializers to:• Facilitate JavaScript translation• Have some fun!

Simple types suffice if reference isinitialized with dummy function…

Page 12: A Fix for Dynamic Scope

12

Proposal: Open Types for λref

let fact = ref (λn. if n <= 1 then 1 else n * !fact(n-1))

fact :: (fact :: Ref (Int Int)) Ref (Int Int)

Assuming fact points to an integer function,

fact points to an integer function

Page 13: A Fix for Dynamic Scope

13

Proposal: Open Types for λref

let fact = ref (λn. if n <= 1 then 1 else n * !fact(n-1))in !fact(5)

fact :: (fact :: Ref (Int Int)) Ref (Int Int)

Assuming fact points to an integer function,

fact points to an integer function

Type system must checkassumptions at every

dereference

Page 14: A Fix for Dynamic Scope

14

Proposal: Open Types for λref

let fact = ref (λn. if n <= 1 then 1 else n * !fact(n-1))

Motivated by λref programs that result fromdesugaring JavaScript programs

Page 15: A Fix for Dynamic Scope

15

Proposal: Open Types for λref

Motivated by λref programs that result from desugaring JavaScript programs

let fact = λn. if n <= 1 then 1 else n * fact(n-1)

Proposal also applies to, and is easier to show for,

the dynamically-scoped λ-calculus (λdyn)

Bound at the time of call…No need for fix or references

Page 16: A Fix for Dynamic Scope

16

Lexical vs. Dynamic Scope

λEnvironment at definition is frozen in closure…And is used to evaluate function body

Explicit evaluation rule for recursion

Page 17: A Fix for Dynamic Scope

17

λdyn

Lexical vs. Dynamic Scope

λ

Bare lambdas, so allfree variables

resolved in calling environment

Page 18: A Fix for Dynamic Scope

18

λdyn

Lexical vs. Dynamic Scope

λ

No need forfix construct

Page 19: A Fix for Dynamic Scope

19

Open Types for λdyn Types (Base or Arrow)Open TypesType EnvironmentsOpen Type Environments

Page 20: A Fix for Dynamic Scope

20

Open Types for λdyn Open Typing

• Open function type describes environment for function body

Page 21: A Fix for Dynamic Scope

21

Open Types for λdyn Open Typing

• Open function type describes environment for function body

• Type environment at function definition is irrelevant

Page 22: A Fix for Dynamic Scope

22

Open Types for λdyn Open Typing

STLC + Fix

In some sense, extreme

generalization of [T-Fix]

Page 23: A Fix for Dynamic Scope

23

Open Types for λdyn Open Typing

STLC + Fix

Page 24: A Fix for Dynamic Scope

24

Open Types for λdyn Open TypingFor every

• Rely-set contains• Guarantee-set contains (most recent, if multiple)

Page 25: A Fix for Dynamic Scope

25

Open Types for λdyn Open TypingOpen TypingFor every

• Rely-set contains• Guarantee-set contains (most recent, if multiple)

Discharge all

assumptions

Page 26: A Fix for Dynamic Scope

26

Open Types for λdyn Open Typing

Page 27: A Fix for Dynamic Scope

27

Examples

let fact = λn. if n <= 1 then 1 else n * fact(n-1)

in fact 5 fact :: (fact :: Int Int) Int Int

Page 28: A Fix for Dynamic Scope

28

Examples

let fact = λn. if n <= 1 then 1 else n * fact(n-1)

in fact 5

Guarantee Rely

fact :: (fact :: Int Int) Int Int

Page 29: A Fix for Dynamic Scope

29

Error: var [tock] not found

Exampleslet tick n = if n > 0 then “tick ” ++ tock n else “” in

tick 2;

Page 30: A Fix for Dynamic Scope

30

Exampleslet tick n = if n > 0 then “tick ” ++ tock n else “” in

tick 2; tick :: (tock :: Int Str) Int Str

Page 31: A Fix for Dynamic Scope

31

Exampleslet tick n = if n > 0 then “tick ” ++ tock n else “” in

tick 2;

Guarantee Rely

tick :: (tock :: Int Str) Int Str

Page 32: A Fix for Dynamic Scope

32

“tick tock tick tock ”

Exampleslet tick n = if n > 0 then “tick ” ++ tock n else “” in

let tock n = “tock ” ++ tick (n-1) in

tick 2;

Page 33: A Fix for Dynamic Scope

33

Exampleslet tick n = if n > 0 then “tick ” ++ tock n else “” in

let tock n = “tock ” ++ tick (n-1) in

tick 2;

tick :: (tock :: Int Str) Int Str

tock :: (tick :: Int Str) Int Str

Page 34: A Fix for Dynamic Scope

34

Exampleslet tick n = if n > 0 then “tick ” ++ tock n else “” in

let tock n = “tock ” ++ tick (n-1) in

tick 2;

tick :: (tock :: Int Str) Int Str

tock :: (tick :: Int Str) Int Str

Guarantee Rely✓

Page 35: A Fix for Dynamic Scope

35

Error: “bad” not a function

Exampleslet tick n = if n > 0 then “tick ” ++ tock n else “” in

let tock n = “tock ” ++ tick (n-1) in

let tock = “bad” in

tick 2;

Page 36: A Fix for Dynamic Scope

36

Exampleslet tick n = if n > 0 then “tick ” ++ tock n else “” in

let tock n = “tock ” ++ tick (n-1) in

let tock = “bad” in

tick 2;tock :: Str

tick :: (tock :: Int Str) Int Str

tock :: (tick :: Int Str) Int Str

Page 37: A Fix for Dynamic Scope

37

Exampleslet tick n = if n > 0 then “tick ” ++ tock n else “” in

let tock n = “tock ” ++ tick (n-1) in

let tock = “bad” in

tick 2;Guarantee Rely

tock :: Str

tick :: (tock :: Int Str) Int Str

tock :: (tick :: Int Str) Int Str

Page 38: A Fix for Dynamic Scope

38

“tick tick ”

Exampleslet tick n = if n > 0 then “tick ” ++ tock n else “” in

let tock n = “tock ” ++ tick (n-1) in

let tock = tick (n-1) in

tick 2;

Page 39: A Fix for Dynamic Scope

39

Exampleslet tick n = if n > 0 then “tick ” ++ tock n else “” in

let tock n = “tock ” ++ tick (n-1) in

let tock = tick (n-1) in

tick 2;

tick :: (tock :: Int Str) Int Str

tock :: (tick :: Int Str) Int Str

tock :: (tick :: Int Str) Int Str

Page 40: A Fix for Dynamic Scope

40

Exampleslet tick n = if n > 0 then “tick ” ++ tock n else “” in

let tock n = “tock ” ++ tick (n-1) in

let tock = tick (n-1) in

tick 2;Guarantee Rely

tick :: (tock :: Int Str) Int Str

tock :: (tick :: Int Str) Int Str

✓tock :: (tick :: Int Str) Int Str

Page 41: A Fix for Dynamic Scope

41

RecapOpen Types capture

“late packaging” of recursive definitions in

dynamically-scoped languages(Metatheory has not yet been worked)

Several potential applications inlexically-scoped languages…

Page 42: A Fix for Dynamic Scope

42

Open Types for λref

For open types in this setting,type system must support

strong updates to mutable variablese.g. Thiemann et al. (ECOOP 2010), Chugh et al. (OOPSLA 2012)

References in λref are similar to dynamically-scoped bindings in λdyn

Page 43: A Fix for Dynamic Scope

43

Open Types for λref let tick = ref null in

let tock = ref null in

tick := λn. if n > 0 then “tick ” ++ !tock(n) else “”;

tock := λn. “tock ” ++ !tick(n-1);

!tick(2);

tick :: (tock :: Ref (Int Str)) Ref (Int Str)tock :: (tick :: Ref (Int Str)) Ref (Int Str)

tick :: Ref Nulltick :: Ref Nulltock :: Ref Null

tick :: (tock :: Ref (Int Str)) Ref (Int Str)tock :: Ref Null

Guarantee Rely✓tick :: (tock :: Ref (Int Str)) Ref (Int Str)tock :: (tick :: Ref (Int Str)) Ref (Int Str)

Page 44: A Fix for Dynamic Scope

44

Open Types for Methodslet tick n = if n > 0 then “tick ” ++ this.tock(n) else “” inlet tock n = “tock ” ++ this.tick(n-1) inlet obj = {tick=tick; tock=tock} inobj.tick(2);

tick :: (this :: {tock: Int Str}) Int Str tock :: (this :: {tick: Int Str}) Int Str

Page 45: A Fix for Dynamic Scope

45

Related Work• Dynamic scope in lexical settings for:– Software updates– Dynamic code loading– Global flags

• Implicit Parameters of Lewis et al. (POPL 2000)– Open types mechanism resembles their approach– We aim to support recursion and references

• Other related work– Bierman et al. (ICFP 2003)– Dami (TCS 1998), Harper (Practical Foundations for PL)– …

Page 46: A Fix for Dynamic Scope

46

Thanks!

Thoughts? Questions?

Open Types for Checking Recursion in:1. Dynamically-scoped λ-calculus2. Lexically-scoped λ-calculus with

references

Page 47: A Fix for Dynamic Scope

47

EXTRA SLIDES

Page 48: A Fix for Dynamic Scope

48

Higher-Order Functions

• Disallows function arguments with free variables• This restriction precludes “downwards funarg problem”• To be less restrictive:

Page 49: A Fix for Dynamic Scope

49

-17

Partial Environment Consistency

let negateInt () = 0 - x inlet negateBool () = not x inlet x = 17 in negateInt ();

negateInt :: (x :: Int) Unit Int negateBool :: (x :: Bool) Unit Bool x :: Int

Safe at run-timeeven though not all

assumptions satisfied

Page 50: A Fix for Dynamic Scope

50

Partial Environment Consistency

• To be less restrictive:

Only andits transitivedependencies in