1 / 26

Good Advice for Type-directed Programming

Good Advice for Type-directed Programming. Aspect-oriented Programming and Extensible Generic Functions. Geoffrey Washburn [ geoffw@cis.upenn.edu ] Joint work with Stephanie Weirich [ sweirich@cis.upenn.edu ]. Introduction. Type-directed programming is a form of generic programming.

kylie-bauer
Download Presentation

Good Advice for Type-directed Programming

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. Good Advice for Type-directed Programming Aspect-oriented Programming and Extensible Generic Functions Geoffrey Washburn [geoffw@cis.upenn.edu] Joint work with Stephanie Weirich [sweirich@cis.upenn.edu]

  2. Introduction • Type-directed programming is a form of generic programming. • operation determined by the “shape” of data • many applications (serialization, iteration, etc…) • improves reusability • Key idea: AOP is compelling mechanism for specializing type-directed functions.

  3. Outline • Aspect-oriented programming in AspectML. • Type-directed programming in AspectML. • Specializing type-directed operations via advice. • Comparison of generic extension via aspects with “Scrap Your Boilerplate With Class”.

  4. AOP in AspectML • Aspects cut across the boundaries of other sorts of abstractions. • Aspects are coherent collections of advice. • Advice specifies when and where to perform a computation.

  5. Example advice val f : Int → Bool val g : Int → Int (* trace the argument to f & g *) advice before (|f,g|) (in:Int,stk,info): Int = print ((getFunName info) ^ “ ” ^ (intToString in)); in advice also gets the current call stack and function metadata. the argument that was passed to fand g “when” the advice applies: before f and g are called advice is a declaration form. “where” the advice applies: functions f and g

  6. Advice times in advice before (|f|) (in:a, stk, info) : a = … around proceed before f:a→b after advice around (|f|) (in:a, stk, info) : b = … proceed … out advice after (|f|) (out:b, stk, info) : b = …

  7. Advice in AspectML • “where” is specified by a pointcut. • sets of in-scope function identifiers, (|f1,…,fn|) • the any pointcut • “when” is specified by a time: before, after, or around. • Syntax of advice: advicetimeexpression(x,y,z)=expression

  8. AspectML is dynamic • advice installed during program execution • fun init_module () = let advice before … advice after … in … end • advice has global scope • installation order determines execution order • pointcuts are first-class values • let val x = (| f , g |) advice before x …

  9. Polymorphic advice • Return type could either be Bool or Int. val f : Int → Bool val g : Int → Int (* trace the return value of f & g *) advice after (|f,g|) (out:???,stk,info):??? = print ((getFunName info) ^ “ ” ^ (???)); in

  10. Polymorphic pointcuts • Solution: polymorphic pointcuts and advice • In general pointcuts have a type pc (<a1 … an>σ1→σ2). • σ1 corresponds to argument type of before and around advice. • σ2 corresponds to argument type of after advice. • Type of (|f,g|) is pc (<a> Int→a). • <a> Int→a is least common instance of Int→Bool and Int→Int.

  11. Type analysis (* trace the return value of f & g *) advice after (|f,g|)<a>(out:a,stk,info):a = print ((getFunName info) ^ “ ” ^ (???)); in (* trace the return value of f & g *) advice after (|f,g|)<a>(out:a,stk,info):a = print ((getFunName info) ^ “ ” ^ (typecase a of | Bool ⇒ boolToString out | Int ⇒ intToString out)); in a = Bool a = Int

  12. Generic programming (* trace the return value of f & g *) advice after (|f,g|)<a>(out:a,stk,info):a = print ((getFunName info) ^ “ ” ^ (typecase a of | Bool ⇒ boolToString out | Int ⇒ intToString out)); in (* type-directed serialization *) fun toString <a>(x : a) : String = typecase a of | Bool ⇒ boolToString x | Int ⇒ intToString x | ???

  13. Data type generic programming • Need generic way to handle arbitrary data constructors. • Adapt spines, as developed by Hinze, Löh, and Oliveira.datatype Spine = | SCons : <a> a → Spine a | SApp : <a b> Spine (a → b) → a → Spine b • Spines are a generic representation of data type structure

  14. Creating spines • AspectML primitive toSpine : <a> a → Option (Spine a). • Spines are recursive in argument, not data type.datatype Foo = Bar : Int → Bool → Char → Foo toSpine (Bar 3 True ‘a’) ⇒ Some (SApp (SApp (SApp (SCons Bar) 3) True) ‘a’) SCons SApp SApp SApp Bar True ‘a’ 3

  15. List spine • Only produces Spine if applied to a data constructor. • toSpine 1 ⇒ None toSpine [1,2] ⇒Some (SApp (SApp (SCons ::) 1) [2]) SCons SApp SApp :: [2] 1

  16. Total type-directed function (* type-directed serialization *) fun toString <a>(x: a) : String = typecase a of | Bool ⇒ boolToString x | Int ⇒ intToString x | (b → c) ⇒ “<fn>” | _ ⇒ (case (toSpine x) | Some x’ ⇒ spineToString x’ | None ⇒ raise Error) and spineToString<a>(x: Spine a) : String = case x of | SCons c ⇒ consToString c | SApp spn arg ⇒ “(“ ^ (spineToString spn) ^ “ ” ^ (toString arg) ^ “)”

  17. Overriding defaults • toString works for all values now. • But toString [1,2] produces “(((::) 1) ((:: 2) Nil)))”. • Would like to override the default printing behavior for lists. • Unrealistic to edit toString every time we want to refine the behavior. • Need some kind of specialization mechanism.

  18. Overriding with advice (* extend toString for lists *) advice around (|toString|)<a>(in:a,stk,info)= typecase a of | [b] ⇒ “[” ^ (concat “,” (map toString in)) ^ “]”) | _ ⇒ proceed in) (* extend toString for lists *) case-advice around (|toString|) (in:[a],stk,info) = “[” ^ (concat “,” (map toString in)) ^ “]”)

  19. Benefits of using advice • Pay as you go: original function does not need to be designed for specialization in advance. • Specialized may occur in separate modules from definition. • Separation of function author from data type author. • Specialization without access to the source code. • Specialization at run-time, by dynamically loaded code.

  20. Related approaches to extensibility • How do aspects compare for generic extension with type-classes, ala “Scrap Your Boilerplate with Class”? • Type-classes traditionally a very static mechanism, while aspects in AspectML are very dynamic. • Trade-off: more aggressive optimization may be possible with type-classes versus dynamic extension.

  21. Scrapping your boilerplate with class • Each type-directed operation defined as type-class.class Show a where show :: a → String • Default type-directed operation is implemented by SYB library using explicit dictionary.instance Data ShowD t ⇒ Show t where show v = showConstr (toConstr v) ++ (concat “ “ (gmapQ showPrxy (showD dict) v)) • Specialized behavior by specifying an instance for a type. instance Show a ⇒ Show [a] where show xs = “[” ++ (concat “,” (map show xs)) ++ “]”

  22. Problems with existentials data Exists = Ex :: forall a. a → Exists • Can’t directly write a specialized caseinstance Show Exists where show (Ex (x :: a)) = “pack “ ++ (show x) • Ill typed because don’t know if a has instance for Show. • Could rewrite data type asdata Exists = Ex :: forall a. Show a ⇒ a → Exists • Requires unsupported compiler extension. • Unrealistic to modify Exists for every type-directed operation.

  23. More comparison • Type-classes an entirely compile-time mechanism, not possible to construct new instances at runtime. • AspectML can install aspects at any time. • Useful when working with mobile or dynamically loaded code that may export new data types.

  24. More comparison • Type-class constraints in SYB can become complicated for the user, over-constrained, non-terminating, or unsolvable in practice. • Type-classes have the advantage of enforcing and describing the domain of type-directed functions.

  25. Summary • Advice can be used to specify when and where a computation should occur. • Aspects are symbiotic with type analysis. • Writing extensible type-directed operations with advice avoids limitations of type-class based SYB.

  26. The future • Using information-flow to reason about the use of type analysis and aspects. • Extending AspectML implementation. • Writing large scale software with these techniques. • Ask me if you would like a demo or snapshot of AspectML.

More Related