1 / 44

Nested Refinements: A Logic for Duck Typing

Nested Refinements: A Logic for Duck Typing. Ravi Chugh , Pat Rondon, Ranjit Jhala (UCSD). What are “Dynamic Languages”?. d._onto = function ( arr,obj,fn ) { if ( !fn ) { arr.push ( obj ) ; } else if ( fn ) { var func = ( typeof fn == “ string ” ) ? obj [ fn ] : fn;

dustin
Download Presentation

Nested Refinements: A Logic for Duck Typing

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Nested Refinements: A Logic for Duck Typing Ravi Chugh, Pat Rondon, Ranjit Jhala (UCSD)

  2. What are “Dynamic Languages”? d._onto=function(arr,obj,fn) { if (!fn){ arr.push(obj); }elseif(fn){ var func =(typeof fn ==“string”) ? obj[fn] : fn; arr.push(function(){ func.call(obj); }); } } tag-tests affect control flow dictionary objects indexed by arbitrary string keys first-class functions can appear inside objects mutation inheritance affects object lookup

  3. What are “Dynamic Languages”? • Lack of static types • … makes rapid prototyping / multi-language applications easy • … makes reliability / performance / maintenance hard • Goal: Design a type system for these features These alone are hard! tag-tests affect control flow dictionary objects indexed by arbitrary string keys first-class functions can appear inside objects mutation inheritance affects object lookup

  4. iftagoff=“Str”thend.n + d[f](0) elsed.n + f(0) These alone are hard! tag-tests affect control flow dictionary objects indexed by arbitrary string keys first-class functions can appear inside objects

  5. Approach: Refinement Types tag-tests Type environment tracks control flow predicates x :: {|tag()=“Int”tag()=“Bool”} x :: {|tag()=“Bool”} x :: {|tag()=“Int”} iftagofx=“Int”then 0 - xelse notx

  6. Approach: Refinement Types tag-tests d.n + d[m] dictionaries {|tag()=“Dict” tag(sel(,“n”))=“Int” tag(sel(,m))=“Int”} d :: McCarthy axioms

  7. Approach: Refinement Types tag-tests 1 +f(0) dictionaries first-class functions x.x :: f :: x:{|tag()=“Int”}{|tag()=“Int”} x:{|tag()=“Int”}{|n=x} Clear separation of base and arrow types T ::= {|p} | x:T1T2

  8. Approach: Refinement Types tag-tests 1 +f(0) dictionaries first-class functions

  9. Approach: Refinement Types tag-tests 1 + d[f](0) dictionaries d :: {|tag()=“Dict”  sel(,f) ??? } first-class functions Key Challenges How to describe arrow inside formula? How to keep type checking decidable?

  10. Approach: Refinement Types • Reuse refinement type architecture • Find a decidable refinement logic for • Tag-tests • Dictionaries • Lambdas • Define nested refinement type architecture ✓ ✓ ✗ ✓*

  11. Nested Refinements 1 + d[f](0) • {|tag()=“Dict” • sel(,f):: • } d :: {|tag()=“Int”}  {|tag()=“Int”} uninterpreted predicate“x::U” says“x has-type U” uninterpreted constantin the logic… … but syntactic arrowin the type system!

  12. Nested Refinements • Refinement formulas over a decidable logic • uninterpreted functions, McCarthy arrays, linear arithmetic • Only base values refined by formulas All values T ::= {|p}U ::= x:T1T2p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | …| x :: U T ::= {|p} | x:T1T2p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | … traditional refinements

  13. Nested Refinements • Refinement formulas over a decidable logic • uninterpreted functions, McCarthy arrays, linear arithmetic • Only base values refined by formulas • “has-type” allows “type terms” in formulas All values T ::= {|p}U ::= x:T1T2p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | … | x::U T ::= {|p} | x:T1T2p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | … traditional refinements

  14. Nested Refinements • Refinement formulas over a decidable logic • uninterpreted functions, McCarthy arrays, linear arithmetic • Only base values refined by formulas • “has-type” allows “type terms” in formulas All values T ::= {|p}U ::= x:T1T2p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | … | x::U

  15. let foofd = iftagoff=“Str”thend.n + d[f](0) elsed.n + f(0) f:{|Str()::IntInt} d:{|Dict() Int(.n) Str(f)[f]::IntInt} Int foo :: T ::= {|p}U ::= x:T1T2p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | … | x::U

  16. let foofd = iftagoff=“Str”thend.n + d[f](0) elsed.n + f(0) f:{|Str()::IntInt} d:{|Dict() Int(.n) Str(f)[f]::IntInt} Int foo :: T ::= {|p}U ::= x:T1T2p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | … | x::U

  17. let foofd = iftagoff=“Str”thend.n + d[f](0) elsed.n + f(0)  {|tag()=“Int”} {|tag()=“Int”} f:{|Str()::IntInt} d:{|Dict() Int(.n) Str(f)[f]::IntInt} Int foo :: tag()=“Str” T ::= {|p}U ::= x:T1T2p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | … | x::U

  18. let foofd = iftagoff=“Str”thend.n + d[f](0) elsed.n + f(0) f:{|Str()::IntInt} d:{|Dict() Int(.n) Str(f)[f]::IntInt} Int foo :: T ::= {|p}U ::= x:T1T2p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | … | x::U

  19. let foofd = iftagoff=“Str”thend.n + d[f](0) elsed.n + f(0) sel(n,“n”) sel(n,f) f:{|Str()::IntInt} d:{|Dict() Int(.n) Str(f)[f]::IntInt} Int foo :: T ::= {|p}U ::= x:T1T2p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | … | x::U

  20. let foofd = iftagoff=“Str”thend.n + d[f](0) elsed.n + f(0) f:{|Str()::IntInt} d:{|Dict() Int(.n) Str(f)[f]::IntInt} Int foo :: T ::= {|p}U ::= x:T1T2p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | … | x::U

  21. let foofd = iftagoff=“Str”thend.n + d[f](0) elsed.n + f(0) foo :: f: {|tag()=“Str”::} IntInt  d: {|tag()=“Dict” tag(sel(,“n”))=“Int” tag(f)=“Str” sel(,f):: } {|:: {|:: IntInt T ::= {|p}U ::= x:T1T2p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | … | x::U Int  } }

  22. Nested Refinements • Type Language • Subtyping • Extensions • Recap

  23. Subtyping T ::= {|p} | x:T1T2 Subtyping Top Int {|true} {|tag()=“Int”} traditional refinements tag()=“Int”true Implication Int <: Top SMT Solver

  24. Subtyping T ::= {|p} | x:T1T2 Subtyping Top Int {|true} {|tag()=“Int”} traditional refinements tag()=“Int” true tag()=“Int” tag()=“Int” Implication SMT Solver Int <: Top Int <: Int Top  Int <: Int  Int

  25. Subtyping T ::= {|p} | x:T1T2 Subtyping Arrow Rule Top Int {|true} {|tag()=“Int”} traditional refinements tag()=“Int” true tag()=“Int” tag()=“Int” Implication SMT Solver Int <: Top Int <: Int Top  Int <: Int  Int

  26. Subtyping T ::= {|p} | x:T1T2 Subtyping Arrow Rule traditional refinements • Decidable if: • Only values in formulas • Underlying theories decidable Implication SMT Solver • With nested refinements: • No new theories • But implication is imprecise!

  27. Subtyping with Nesting Subtyping Implication ✗ ::TopInt::IntInt SMT Solver Invalid, as these are distinct uninterpreted constants

  28. Subtyping with Nesting When goal is base predicate:pq When goal is “has-type” predicate:px::U Subtyping Subtyping Arrow Rule Implication Implication U’<:U px::U’ pq SMT Solver SMT Solver

  29. Subtyping with Nesting UninterpretedReasoning Normalize formulas to subdivide obligations appropriately SyntacticReasoning + p ::TopInt TopInt<:IntInt p::Int  Int

  30. Nested Refinements • Type Language • Subtyping • Extensions • Recap

  31. Extensions • Simple to add additional type constructors • Extend the grammar of type terms • Add additional syntactic subtyping rules U ::= x:T1T2 | A | List[T] | Null SyntacticRules Arrow Rule Covariant List Rule Null List Rule

  32. Map ∀A,B. {|::AB}{|::List[A]}{|::List[B]} let mapfxs = ifxs=nullthen null else f xs[“hd”] :: map f xs[“tl”] encode recursive data as dictionaries

  33. Filter let filterfxs = ifxs=nullthen null else if f xs[“hd”]then xs[“hd”] :: filter f xs[“tl”] else filter f xs[“tl”] • ∀A,B.{|::x:A{|n=Truex::B}} • {|::List[A]} • {|::List[B]} usual definition, but an interesting type

  34. Dispatch let dispatch d f=d[f] d • ∀A,B.d:{|Dict() ::A} • {|Str() d[]::AB} • {|::B} a form of “bounded quantification” since d::A but additional constraints on A

  35. Recap • Refinement types are a compelling approach • Dynamic dictionaries require dependency • Tag-tests require path sensitivity • But, not enough for lambdas in dictionaries • Nested refinement types are a clean solution • Natural way to describe dynamic idioms • Novel subtyping remains decidable and automatic • Interesting soundness proof

  36. Future Work • Extend to imperative JavaScript setting • Employ strong update techniques • Track prototype chain for inheritance • Better inference • Untyped programmers allergic to annotations • Perhaps utilize run-time information • Applications • JavaScript benchmarks (e.g. SunSpider) • JavaScript frameworks (e.g. Dojo)

  37. Thanks! D :: http://cseweb.ucsd.edu/~rchugh/research/nested/

  38. Extra Slides

  39. Constants

  40. Macros {|::} x:T1T2 x:T1T2 • Types • Formulas • Logical Values EqMod(d,d’,k)  Int has(d,k)  Str(x)  x.k  x[k]  {|tag()=“Int”} tag(x) = “Str” ∀k’. k’!=k sel(d,k)!=sel(d’,k) sel(d,k)!=bot sel(n,“k”) sel(n,k)

  41. Functional Onto let onto callbacks f obj= if f = null then new List(obj,callbacks) else let cb =if tagof f =“Str” then obj[f]else f in new List(fun()-> cb obj, callbacks) ∀A. callbacks:List[TopTop] f:{|Str()::ATop} obj:{|::A (f=null::AInt) (Str(f)[f]::AInt)} List[TopTop] onto ::

  42. Functional Onto (2) let onto (callbacks,f,obj)= if f = null then new List(obj,callbacks) else let cb =if tagof f =“Str” then obj[f]else f in new List(fun()-> cb obj, callbacks) callbacks:List[TopTop] *f:{g|Str(g)g::{x|x=obj}Top} *obj:{o|(f=nullo::{x|x=o}Int) (Str(f)o[f]::{x|x=o}Int)} List[TopTop] onto ::

  43. Normalization • TODO

  44. Related Work • TODO

More Related