26
Good Advice for Type-directed Programming Aspect-oriented Programming and Extensible Generic Functions Geoffrey Washburn [[email protected]] Joint work with Stephanie Weirich [[email protected]]

Good Advice for Type-directed Programming

Embed Size (px)

DESCRIPTION

Good Advice for Type-directed Programming. Aspect-oriented Programming and Extensible Generic Functions. Geoffrey Washburn [ [email protected] ] Joint work with Stephanie Weirich [ [email protected] ]. Introduction. Type-directed programming is a form of generic programming. - PowerPoint PPT Presentation

Citation preview

Page 1: Good Advice for  Type-directed Programming

Good Advice for Type-directed Programming

Aspect-oriented Programming and Extensible Generic Functions

Geoffrey Washburn [[email protected]]Joint work with Stephanie Weirich [[email protected]]

Page 2: Good Advice for  Type-directed Programming

Good Advice for Type-directed Programming 2006/09/16

2

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.

Introduction

Page 3: Good Advice for  Type-directed Programming

Good Advice for Type-directed Programming 2006/09/16

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”.

Page 4: Good Advice for  Type-directed Programming

Good Advice for Type-directed Programming 2006/09/16

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.

Page 5: Good Advice for  Type-directed Programming

Good Advice for Type-directed Programming 2006/09/16

5

val f : Int → Boolval 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 is a declaration

form. “where” the advice applies: functions f

and g

“when” the advice applies: before f and g are called

the argument that was passed to f

and g

advice also gets the current call stack

and function metadata.

Example advice

Page 6: Good Advice for  Type-directed Programming

Good Advice for Type-directed Programming 2006/09/16

6

around

f:a→b

before

after

in

out

advice after (|f|) (out:b, stk, info) : b = …

proceed

advice around (|f|) (in:a, stk, info) : b = … proceed …

advice before (|f|) (in:a, stk, info) : a = …

Advice times

Page 7: Good Advice for  Type-directed Programming

Good Advice for Type-directed Programming 2006/09/16

7

“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:advice time expression (x,y,z)= expression

Advice in AspectML

Page 8: Good Advice for  Type-directed Programming

Good Advice for Type-directed Programming 2006/09/16

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 …

Page 9: Good Advice for  Type-directed Programming

Good Advice for Type-directed Programming 2006/09/16

9

val f : Int → Boolval g : Int → Int

(* trace the return value of f & g *)advice after (|f,g|) (out:???,stk,info):??? = print ((getFunName info) ^ “ ” ^ (???)); in

Polymorphic advice

Return type could either be Bool or Int.

Page 10: Good Advice for  Type-directed Programming

Good Advice for Type-directed Programming 2006/09/16

10

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.

Polymorphic pointcuts

Page 11: Good Advice for  Type-directed Programming

Good Advice for Type-directed Programming 2006/09/16

11

(* 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

Type analysis

Page 12: Good Advice for  Type-directed Programming

Good Advice for Type-directed Programming 2006/09/16

12

(* 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 | ???

Generic programming

Page 13: Good Advice for  Type-directed Programming

Good Advice for Type-directed Programming 2006/09/16

13

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

Data type generic programming

Page 14: Good Advice for  Type-directed Programming

Good Advice for Type-directed Programming 2006/09/16

14

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’)

Creating spines

SAppSAppSCons

‘a’Bar True

SApp

3

Page 15: Good Advice for  Type-directed Programming

Good Advice for Type-directed Programming 2006/09/16

15

Only produces Spine if applied to a data constructor. toSpine 1 ⇒ None

List spine

toSpine [1,2] ⇒ Some (SApp (SApp (SCons ::) 1) [2])

SAppSCons

:: [2]

SApp

1

Page 16: Good Advice for  Type-directed Programming

Good Advice for Type-directed Programming 2006/09/16

16

(* 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) ^ “)”

Total type-directed function

Page 17: Good Advice for  Type-directed Programming

Good Advice for Type-directed Programming 2006/09/16

17

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.

Overriding defaults

Page 18: Good Advice for  Type-directed Programming

Good Advice for Type-directed Programming 2006/09/16

18

(* 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)) ^ “]”)

Overriding with advice

Page 19: Good Advice for  Type-directed Programming

Good Advice for Type-directed Programming 2006/09/16

19

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.

Benefits of using advice

Page 20: Good Advice for  Type-directed Programming

Good Advice for Type-directed Programming 2006/09/16

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.

Page 21: Good Advice for  Type-directed Programming

Good Advice for Type-directed Programming 2006/09/16

21

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)) ++ “]”

Scrapping your boilerplate with

class

Page 22: Good Advice for  Type-directed Programming

Good Advice for Type-directed Programming 2006/09/16

22

Problems with existentials

Can’t directly write a specialized case

instance 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 as

data Exists = Ex :: forall a. Show a ⇒ a → Exists

Requires unsupported compiler extension. Unrealistic to modify Exists for every type-directed

operation.

data Exists = Ex :: forall a. a → Exists

Page 23: Good Advice for  Type-directed Programming

Good Advice for Type-directed Programming 2006/09/16

23

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.

More comparison

Page 24: Good Advice for  Type-directed Programming

Good Advice for Type-directed Programming 2006/09/16

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.

Page 25: Good Advice for  Type-directed Programming

Good Advice for Type-directed Programming 2006/09/16

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.

Page 26: Good Advice for  Type-directed Programming

Good Advice for Type-directed Programming 2006/09/16

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.