440 likes | 575 Views
From Patterns to Programming Languages. Matthias Felleisen Northeastern University. Background and Experience . Theory of PL Expressiveness PLT Scheme (IDE, tools, Scheme) 200 Kloc Scheme, 200Kloc C++ (inh) 400 downloads/day for last year 94/95: design patterns use in implementation
E N D
From Patterns to Programming Languages Matthias Felleisen Northeastern University Kestrel
Background and Experience • Theory of PL Expressiveness • PLT Scheme (IDE, tools, Scheme) • 200 Kloc Scheme, 200Kloc C++ (inh) • 400 downloads/day for last year • 94/95: design patterns • use in implementation • implementing patterns in Scheme • “A Little Java, A Few Patterns” • papers on patterns for extensibility • 96/97: Patterns in the IDE (ESOP) Kestrel
Patterns and Expressiveness Kestrel
Patterns (GoF) pattern name problem solution consequences adapter mismatch of interface create adapter class e.g., class adapters may introduce additional behavior Kestrel
Patterns (PL) name problem solution consequences store passing mismatch of interface: have FP, need state pass store as data structure; lookup & modify locations man. introduce additional behavior Kestrel
Patterns (PL: store passing) here we go: val xcount = ref 0; // xf : int -> (TypeG, int) fun xf (xcount) = … let val xcount = !xcount + 1; in (G, xcount); would like, but don’t have val xcount = ref 0; // xf : unit -> TypeG fun xf () = … xcount = !xcount + 1; G; Kestrel
Patterns (PL: store passing) fun f fun f-sps Kestrel
Patterns (PL) name problem solution consequences continuation passin g mismatch of interface: have FP, need exceptions pass control as function introduce additional behavior Kestrel
Patterns (PL: continuation passing) here we go: // xf : (GType -> FA) -> FA fun xf (roc) = … if cond then 10; else roc(G); would like, but don’t have // xf : unit -> TypeG fun xf () = … if cond then exit(10); else G; Kestrel
Patterns (PL: continuation passing) fun f fun f-cps Kestrel
Patterns (PL) name problem solution consequences nested blocks lack blocks in FPL apply anonymous function physically separate variables from values Kestrel
Patterns (PL: nested blocks) here we go: ((lambda (x y) … x … y … ) 10 20) would like, but don’t have (let ([x 10] [y 20]) … x … y … ) Kestrel
Patterns (PL) name problem solution consequences for-loop lack for-loop in FPL use recursive function physically separate loop variable from initial value Kestrel
Patterns (PL: nested blocks) here we go: (for-each (lambda (j) (set! sum (+ sum j))) (build-list 10 (lambda (k) (+ k 10)))) would like, but don’t have (for j = 10 to 20 (set! sum (+ sum j))) Kestrel
Patterns from PL • Landin: patterns are everywhere • some are local --> syntactic sugar • some are global --> essential constructs • Strachey, Wadsworth: • denotational semantics & global patterns • Felleisen (1988): • theory of expressiveness relative to a base language Kestrel
Patterns and Language Constructs Kestrel
Pattern Programming • Programming with patterns is good. • With Patterns, programmers can discuss lots of code with a few words. • Patterns suggest invariants, helping reasoning about code. Kestrel
Pattern Programming • Programming patterns explicitly is bad. • Programmers may “lie” about patterns. • Pattern maintenance may break logical invariants Kestrel
The Adapter Pattern: One More Time /* Adapter Pattern: object adapter GraphicalOutput adapts VendorGraphics to OutputRoutines */ interface OutputRoutines { … } class GraphicalOutput implements OutputRoutines { … } class VendorGraphics { … } two lines of comments explain 100 lines of code Kestrel
The Adapter Pattern: One More Time /* Adapter Pattern: object adapter GraphicalOutput adapts VendorGraphics to OutputRoutines */ classOutputRoutines { … } class GraphicalOutput extends OutputRoutines { … } class VendorGraphics { … } it’s no longer an adaptation -- it’s implementation inheritance Kestrel
Patterns as Comments • When patterns are comments and informal language, nobody knows whether our claims are true. • Somebody else may change the code or the comments. • Then they are out of sync. • Are such patterns useful? Kestrel
Patterns as Language Constructs • local patterns vs global patterns • local patterns via syntactic extensions • global patterns via aspects (?) • if aspects work, we can experiment with a pattern and see whether it is useful • if so, we should add them to the language. Kestrel
Scheme’s Macros: Principles • Macros are transformations on the abstract syntax trees • Macros respect the scoping (and other) information of the input ASTs. • Macros respect the scoping information of their “host” module. Kestrel
Scheme’s Macros: Example (define-syntax let (syntax-rules () [(let ([<x:var> <rhs:exp>] ...) <body:exp>...) ((lambda (<x:var>...) <body:exp>...) <rhs:exp> ...)])) ;; use: (let ([x 10][y 20]) (printf "the variables are: ~s ~s ~n" x y) (+ x y)) Kestrel
Local Patterns as Language Constructs • (define-syntax-patternAdapter • [rewrite • (_ <aN>adapts<aT> • to<dI>as<aV> • (fields<fd>...) • (methods<md> ...))] • [as(class <aN>implements<dI> • (fields (<aT><aV>) <fd>...) • (methods<md>...))]) Kestrel
Pattern Elaboration Kestrel
Patterns and Synthesized Information (Patterns and Proofs) Kestrel
Making Patterns as Constructs Work Programmers need to see information at the level at which they program. Information is: syntax error type error run-time exception reporting Kestrel
Information about Programs Matters (A + B) * C : misuse of variable produces: MultiplicationExpression<class LazyBinaryExpression<class AdditionExpression<class MatrixICCL::Matrix<class MatrixICCL::BoundsChecker<class MatrixICCL::ArrFormat<class MatrixICCL::StatExt<struct MatrixDSL::int_number<int,7>,struct MatrixDSL::int_number<int,7>>,class MatrixICCL::Rect<class MatrixICCL::StatExt<struct MatrixDSL::int_number<int,7>,struct MatrixDSL::int_number<int,7>>>,class MatrixICCL::Dyn2DCContainer<class MATRIX_ASSEMBLE_COMPONENTS<class MATRIX_DSL_ASSIGN_DEFAULTS<class MATRIX_DSL_PARSER<struct MatrixDSL::matrix<int,struct MatrixDSL::structure<struct MatrixDSL::rect<struct MatrixDSL::stat_val<struct MatrixDSL::int_number<int,7>>,struct MatrixDSL::stat_val<struct MatrixDSL::int_number<int,7>>,struct MatrixDSL::unspecified_DSL_feature>,struct MatrixDSL::dense<struct MatrixDSL::unspecified_DSL_feature>,struct MatrixDSL::dyn<struct MatrixDSL::unspecified_DSL_feature>>,struct MatrixDSL::speed<struct MatrixDSL::unspecified_DSL_feature>,struct MatrixDSL::unspecified_DSL_feature,struct MatrixDSL::unspecified_DSL_feature,struct MatrixDSL::unspecified_DSL_feature,struct MatrixDSL::unspecified_DSL_feature>>::DSLConfig>::DSLConfig>>>>>,class MatrixICCL::Matrix<class MatrixICCL::BoundsChecker<class MatrixICCL::ArrFormat<class MatrixICCL::StatExt<struct MatrixDSL::int_number<int,7>,struct MatrixDSL::int_number<int,7>>,class MatrixICCL::Rect<class MatrixICCL::StatExt<struct MatrixDSL::int_number<int,7>,struct MatrixDSL::int_number<int,7>>>,class MatrixICCL::Dyn2DCContainer<class MATRIX_ASSEMBLE_COMPONENTS<class MATRIX_DSL_ASSIGN_DEFAULTS<class MATRIX_DSL_PARSER<struct MatrixDSL::matrix<int,struct MatrixDSL::structure<struct MatrixDSL::rect<struct MatrixDSL::stat_val<struct MatrixDSL::int_number<int,7>>,struct MatrixDSL::stat_val<struct MatrixDSL::int_number<int,7>>,struct MatrixDSL::unspecified_DSL_feature>,struct MatrixDSL::dense<struct MatrixDSL::unspecified_DSL_feature>,struct Ma… Kestrel
Patterns and Errors Kestrel
Pattern Macros: A Full Example • expansion rules • instance from GoF • consistency error • syntax check, scope check • type check Kestrel
The Composite Pattern: New Syntax (COMPOSITE (ABSTRACT <abs:variable> (FIELDS (<f:variable> <f:exp>)...) (METHODS(<m:variable> <m:exp>)) (ABSTRACT:METHODS <am:variable> ...)) (CONCRETE <con1:variable> (FIELDS(<cf:variable> <cf:exp>) ...) (METHODS(<cm:variable> <cm:exp>) ...)) (COMPOSITE:METHODS (<cm:variable> <cm:exp>) ...)) Kestrel
The Composite Pattern: Elaboration (begin ;; --- ABSTRACT CLASS (define <abs:variable> (class* object% () () (private (<f:variable> <f:exp>) ...) (public (<am:variable> (lambda x (error '<am:variable> "not implemented ...))) ;; --- CONCRETE CLASSES (define <con1:variable> (class* etc. ….. ………………………………………………))) Kestrel
Source Correlation • to track source information through expansions • to provide feedback in terms of original source Kestrel
Elaboration Tracking • to keep track of history of macro transformations • to help IDE untangle complex interactions between complex pattern embeddings Kestrel
Conclusion Kestrel
Summary • patterns have a long history, pre-GoF • patterns should be language constructs for the obvious reasons • macros (and an expressive base language) can turn most patterns into language constructs Kestrel
Patterns via Macros • abstract factory, factory, singleton, adapter, bridge, composite, decorator, façade, proxy, chain, command, interpreter, iterator, observer, state, strategy, visitor, template • from local macros using a base language with higher-order functions and assignment Kestrel
Challenges • global patterns • a well-founded theory of patterns • more experience with pattern in languages with explicit type declarations Kestrel
The End • Shriram Krishnamurthi • Daniel Friedman • Cormac Flanagan • and PLT Kestrel