1 / 36

Parameterized Modules for Classes and Extensible Functions

/ke • noo/. Parameterized Modules for Classes and Extensible Functions. Keunwoo Lee Craig Chambers University of Washington FOOL/WOOD workshop, Jan. 2006. computational nihilist (grad student). (advisor). Consider a module…. module Lang = { abstract class Expr of {}

roden
Download Presentation

Parameterized Modules for Classes and Extensible Functions

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. /ke • noo/ Parameterized Modules for Classes and Extensible Functions Keunwoo Lee Craig Chambers University of Washington FOOL/WOOD workshop, Jan. 2006 computational nihilist (grad student) (advisor)

  2. Consider a module… module Lang = { abstractclass Expr of {} abstract fun eval:Expr ! Int }

  3. Desideratum 1:Data type extensibility module Lang = { abstractclass Expr of {} abstract fun eval:Expr ! Int } module C = { class Const extends Lang.Expr of {value:Int} extendfun Lang.eval(Const {value=v}) = v }

  4. Desideratum 2:Function extensibility module Lang = { abstractclass Expr of {} abstract fun eval:Expr ! Int } module P = { fun print:Lang.Expr ! String extendfun print(Lang.Expr) = "" } module C = { class Const extends Lang.Expr of {value:Int} extendfun Lang.eval(Const {value=v}) = v }

  5. Desideratum 3:Reusable extensions module Lang = { abstractclass Expr of {} abstractfun eval:Expr ! Int } moduleLang = { abstractclass Expr of {} abstractfun eval:Expr ! Int } module MakePlus = (L:LangSig) !{ } signature LangSig = sig { abstractclass Expr of {} abstract fun eval:Expr ! Int } module Plus = MakePlus(Lang) module Plus = MakePlus(Lang)(* { class Plus extendsLang.Expr of {left:Lang.Expr, right:Lang.Expr} extendfunLang.eval(Plus …) … } *) class Plus extendsL.Expr of {left:L.Expr, right:L.Expr} extendfunL.eval(Plus {left, right}) = …

  6. Desideratum 4:Modular typechecking module Lang = { abstractclass Expr of {} abstractfun eval:Expr ! Int } : sig { abstractclass Expr of {} abstractfun eval:Expr ! Int } signature LangSig = sig { abstractclass Expr of {} abstractfun eval:Expr ! Int } · module Plus = MakePlus(Lang) module MakePlus = (L:LangSig) !{ class Plus extends L.Expr of {left:L.Expr, right:L.Expr} extendfun L.eval(Plus {left, right}) = … }

  7. Desiderata summary • Data type extensibility • Function extensibility • Reusable extensions • Modular typechecking

  8. Related work • ML module system [MacQueen 84, …, Dreyer+03] • No nontrivial extensible datatypes or functions • OO module systems: Jiazzi [McDirmid+01], JavaMod [Ancona/Zucca01], etc. • Single-dispatch; function extensibility via design pattern • OO parameterized classes: • Multiple inheritance, mixins [Bracha/Cook90], traits [Schärli+03,etc.] • Virtual types [Madsen/Møller-Pedersen89]: gbeta [Ernst01], Scala [Odersky+04], etc. • Single-dispatch; function extensibility via design pattern

  9. Previous work: EML[Millstein et al., ICFP'02] • Extensible datatypes/functions, modular typechecking • A simple, restrictive parameterized module system • Present work: F(EML) • extension of EML with much more useful functors

  10. Outline • Desiderata • Signatures: key issues • Solutions • Conclusions

  11. MakePlus, revisited module Lang = { abstractclass Expr of {} abstractfun eval:Expr ! Int } : sig { abstractclass Expr of {} abstractfun eval:Expr ! Int } signature LangSig = sig { abstractclass Expr of {} abstractfun eval:Expr ! Int } · module Plus = MakePlus(Lang) module MakePlus = (L:LangSig) !{ class Plus extends L.Expr of {left:L.Expr, right:L.Expr} extendfun L.eval(Plus {left, right}) = … }

  12. A straw man signature calculus Signatures are compatible iff: • Exact syntactic match on declarations • Width subtyping: freely permit subsumption to "forget" extra declarations Both inflexible and unsound

  13. Signatures: Key issues • Signatures constrain: • Names and modularization choices ) alias declarations module Lang' = { aliasclass Expr = Foo.Exp aliasfun eval = Bar.eval } signature LangSig = sig { abstractclassExpr of {} abstractfuneval:Expr ! Int } sig { abstractclassExpr of {} abstractfuneval:Expr ! Int } ·

  14. Signatures: Key issues • Signatures constrain: • Names and modularization choices • Relationships among declarations/types ) richer relation language signature LangSig = sig { abstractclass Expr of {} abstractfun eval:Expr ! Int } signature LangSig = sig { abstractclass Expr < Objectof {} abstractfun eval:Expr ! Int } sig { abstractclass Expr extends Object of {} abstractfun eval:Expr ! Int } ·

  15. Signatures: Key issues • Signatures constrain: • Names and modularization choices • Relationships among declarations/types • Extra parts that may be ignored ? signature LangSig = sig { abstractclass Expr extends Object of {} abstractfun eval:Expr ! Int } sig { abstractclass Expr extends Object of {} abstractfun eval:Expr ! Int abstract fun f:Expr ! String } · ) width subtyping via sealing

  16. Signatures: Key issues • Signatures constrain: • Names and modularization choices • Relationships among declarations/types • Extra parts that may be ignored ) alias declarations ) richer relation language ) width subtyping via sealing

  17. Outline • Desiderata • Signatures: key issues • Solutions • Enriched relations • Sealing for subsumption • Conclusions

  18. Class relations module Lang = { abstractclass Expr of {} abstractfun eval:Expr ! Int } signature LangSig = sig { abstractclass Expr of {} abstractfun eval:Expr ! Int } module MakePlus = (L:LangSig) !{ class Plus extends L.Expr of {left:L.Expr, right:L.Expr} extendfun L.eval(Plus {left, right}) = … }

  19. Class relations module Lang = { abstractclass Expr of {} abstractfun eval:Expr ! Int } module B uses Lang = { abstract class BinOp extends Lang.Expr of … } signature BOSig = sig { abstractclass BinOp extends Lang.Expr of … } module Comm uses B, Lang = { abstract class BinOp extends B.BinOp of … } module MakePlus = (O:BOSig) !{ class Plus extendsO.BinOp of … extendfun Lang.eval(Plus …) = … }

  20. Enriched class relations C · C' subtyping C < C' strict subtyping C <k C' k-level subtyping C <1 C' ´ C extends C' C <0 C' ´ C = C' C  C' non-aliasing C disjoint C' non-intersection fresh C freshly declared class

  21. Why these relations? • Languages with symmetric-best-match dispatch care about inequalities and non-intersection (which is unusual) • How does one prove methods unambiguous? fun f:C ! Unit extend fun f(C) = () extend fun f(D) = () • C Å D is non-empty, computable, and covered by a case of f (requires ·) • D < C • C disjoint D

  22. A <k <k  C D disjoint C D Deriving disjointness

  23. : : sig { class Neg of {…} where Neg <1 Lang.Expr} sig { class Const … where Const <1 Lang.Expr } fresh Const fresh Neg Deriving distinctness • How to modularly deduce non-aliasing? module C = { class Const extends Lang.Expr … } module N = { class Neg extends Lang.Expr … } module X = (A:sig { class Neg whereNeg disjoint C.Const, … }) = … module NBad = { aliasclass Neg = C.Const … }

  24. Enriched class relations C · C' subtyping C < C' strict subtyping C <k C' k-level subtyping C <1 C' ´ C extends C' C <0 C' ´ C = C' C  C' non-aliasing C disjoint C' non-intersection fresh C freshly declared class

  25. Outline • Desiderata • Signatures: key issues • Solutions • Enriched relations • Sealing for subsumption • Conclusions

  26. (Object, Object) (Bad.E, Object) (Object, Int) (Bad.E, Int) Hiding methods:naïve width subtyping fails module M = { fun f:(Object, Object) ! Unit extendfun f(Object, Object) = () extendfun f(Object, Int) = () } module M = { fun f:(Object, Object) ! Unit extendfun f(Object, Object) = () extendfun f(Object, Int) = () } : ? sig { fun f:(Object, Object) ! Unit extendfun f(Object, Object) extendfun f(Object, Int) } signature S = sig { fun f:(Object, Object) ! Unit } · module BreakMS = (A:S) ! { class E extends Object extendfun A.f(E, Object) = () } module Bad = BreakMS(M) module Bad = BreakMS(M) (* { class E extends Object extendfun M.f(E, Object) = () } *)

  27. What's going on? • A signature's visibleparts give clients both capabilities to extend, and obligations they incur by so extending • Must never hide an obligation while granting the associated capability…

  28. (Object, Object) (Bad.E, Object) (Object, Int) (Bad.E, Int) What's going on? module M = { fun f:(Object, Object) ! Unit extendfun f(Object, Object) = () extendfun f(Object, Int) = () } module M = { fun f:(#Object, Object) ! Unit extendfun f(Object _, Object _) = () extendfun f(Object _, Int _) = () } : ? sig { fun f:(Object, Object) ! Unit extendfun f(Object, Object) extendfun f(Object, Int) } signature S = sig { fun f:(Object, Object) ! Unit } · Cannot allow both hiding here… module BreakMS = (A:S) ! { class E extends Object extendfun A.f(E, Object) = () } …and extension here module Bad = BreakMS(M) (* { class E extends Object extendfun M.f(E, Object) = () } *) module Bad = BreakMS(M)

  29. supertypes of open below type: cases may be hidden here strict subtypes of open below type: clients may add cases here open below sig { fun f:(Object, Object) ! Unit open below (Object, Object) extendfun f(Object, Object) extendfun f(Object, Int) } sig { fun f:(Object, Object) ! Unit open below (Object, Object) extendfun f(Object, Int) } · (Object, Object) (Bad.E, Object) (Object, Int) (Bad.E, Int)

  30. open below sig { fun f:(Object, Object) ! Unit open below (Object, Object) extendfun f(Object, Object) extendfun f(Object, Int) } sig { fun f:(Object, Object) ! Unit open below (Object, Object) } · supertypes of open below type: cases may be hidden here (Object, Object) (Bad.E, Object) (Object, Int) strict subtypes of open below type: clients may add cases here (Bad.E, Int)

  31. types disjoint from open below type: cases may be hidden here (Object, String) open below sig { fun f:(Object, Object) ! Unit open below (Object, Int) extendfun f(Object, Object) extendfun f(Object, Int) } sig { fun f:(Object, Object) ! Unit open below (Object, Int) extendfun f(Object, Object) extendfun f(Object, Int) extend fun f(Object, String) } sig { fun f:(Object, Object) ! Unit open below (Object, Int) } · supertypes of open below type: cases may be hidden here (Object, Object) (Bad.E, Object) (Object, Int) strict subtypes of open below type: clients may add cases here (Bad.E, Int)

  32. open below sig { fun f:(Object, Object) ! Unit open below (Object, Int) extendfun f(Object, Object) extendfun f(Object, Int) } sig { fun f:(Object, Object) ! Unit open below (Object, Object) } sig { fun f:(Object, Object) ! Unit open below (Object, Int)} · any client that extends below (Object, Int) also extends below (Object, Object) (Object, Object) (Bad.E, Object) (Object, Int) (Bad.E, Int)

  33. Hiding functions • Unsafe to hide an abstract function, and permit concrete extension of class on which that function is abstract • Class sigs can be closed: closed class C … denotes class that cannot be extended via this signature • Abstract functions can only be hidden when "owning" class is closed (& non-instantiable)

  34. Outline • Desiderata • Signatures: key issues • Solutions • Conclusions

  35. Status • Implementation • Prototype interpreter: handles our examples • Formalization • Small-step operational semantics • Partial soundness proof (via translation to EML) • Summary in paper; details/full proof in technical report (forthcoming) and dissertation (forthcoming, somewhat later)

  36. Conclusions • F(EML) combines extensibility, code reuse, and modular typechecking; key features: • Aliases for renaming/remodularization • Rich language of declaration/type relations • Signature subsumption via selective sealing • Future work: • Hierarchical checking of modularity obligations for nested modules (relaxed checking) • Multiple dispatch + virtual types + (mutual) recursion

More Related