
Visitor: Just Do It Didier Verna Introduction C++ Revisiting the Visitor: the “Just Do It” Pattern LISP Step 1: plain LISP Step 2: brute force Step 3: first class Step 4: mapping Didier Verna Step 5: generic map State Step 6: objects [email protected] Step 7: closures http://www.lrde.epita.fr/˜didier step 8: visit schemes Conclusion ACCU 2009 – Friday, April 24th 1/25 Introduction Visitor: Just Do It Necessary literature Didier Verna The GOF Book: Design Patterns, Elements of Introduction Reusable Object-Oriented Software. Gamma, Helm, C++ LISP Johnson, Vlissides. Step 1: plain LISP Step 2: brute force The POSA Book: Pattern-Oriented Software Step 3: first class Step 4: mapping Architecture. Buschmann, Meunier, Rohnert, Step 5: generic map Sommerlad, Stal. State Step 6: objects Step 7: closures step 8: visit schemes What is a software design pattern ? Conclusion I Context (POSA) I Problem I Solution I Consequences (GOF) 2/25 A constatation Visitor: Just Do It Peter Norvig (Object World, 1996) Didier Verna About the GOF book: Introduction C++ 16 of 23 patterns are either invisible or simpler LISP [...] in Dylan or Lisp Step 1: plain LISP Step 2: brute force Step 3: first class Step 4: mapping Step 5: generic map Peter Norvig is right, so State I is the GOF book (70%) wrong ? Step 6: objects Step 7: closures I are patterns (70%) useless ? step 8: visit schemes Conclusion 3/25 Some clues from the GOF book itself Visitor: Just Do It Didier Verna Although design patterns describe object-oriented designs, they are based on Introduction practical solutions that have been implemented in C++ mainstream object-oriented programming LISP Step 1: plain LISP languages [. ] Step 2: brute force Step 3: first class Step 4: mapping Step 5: generic map State Similarly, some of our patterns are supported Step 6: objects Step 7: closures directly by the less common object-oriented step 8: visit schemes languages. Conclusion I That’s what people usually miss 4/25 Patterns descriptions / organizations Visitor: Just Do It GOF: Creational, Structural, Behavioral Didier Verna I usage-oriented Introduction POSA: Architectural, Design, Idioms C++ I abstraction-oriented LISP Step 1: plain LISP Step 2: brute force Idioms according to POSA Step 3: first class Step 4: mapping An idiom is a low-level pattern specific to a Step 5: generic map State programming language. An idiom describes how to Step 6: objects Step 7: closures implement particular aspects of components or the step 8: visit schemes relationships between them using the features of Conclusion the given language. [. ] They address aspects of both design and implementation. I GOF’s design patterns are closer to POSA’s idioms 5/25 The risk: blind pattern application Visitor: Just Do It POSA’s advice: Didier Verna [. ] sometimes, an idiom that is useful for one Introduction programming language does not make sense into C++ another. LISP Step 1: plain LISP Step 2: brute force Step 3: first class Step 4: mapping GOF’s Visitor example: Step 5: generic map State Use the Visitor pattern when [. ] many distinct Step 6: objects Step 7: closures and unrelated operations need to be performed on step 8: visit schemes objects in an object structure, and you want to Conclusion avoid “polluting” their classes with these operations. I But who said operations belong to classes ? 6/25 Table of contents Visitor: Just Do It Didier Verna 1 Visiting in C++ Introduction 2 Visiting in LISP C++ ISP LISP Step 1: plain L Step 1: plain LISP Step 2: brute force visiting Step 2: brute force Step 3: first class Step 3: first class generic functions Step 4: mapping Step 5: generic map Step 4: mapping State Step 6: objects Step 5: generic mapping Step 7: closures step 8: visit schemes Conclusion 3 Visiting with state Step 6: objects Step 7: lexical closures Step 8: dynamic visitation schemes 7/25 Visiting in C++ Visitor: Just Do It Problems: Didier Verna Original hierarchy R/O Introduction C++ Abstract the visiting process away LISP Step 1: plain LISP Step 2: brute force Solution: Step 3: first class Step 4: mapping 1 Equip original hierarchy for visits Step 5: generic map State I A Visitable abstract class Step 6: objects I An accept method in each visitable component Step 7: closures step 8: visit schemes 2 Write independent visitors Conclusion I A Visitor abstract class I A visit method for each visitable component 9/25 Step 1: plain LISP Visitor: Just Do It Classes Didier Verna ( defclass class (superclass1 superclass2 ...) Introduction ((slot :initform <form> :initarg :slot :accessor slot) ...) C++ options ...) LISP ( make−instance ’class :slot <value> ...) Step 1: plain LISP Step 2: brute force Step 3: first class Step 4: mapping Step 5: generic map Generic functions, methods State ( defgeneric func (arg1 arg2 ...) Step 6: objects (:method ((arg1 class1) arg2 ...) Step 7: closures step 8: visit schemes body ) options ...) Conclusion ( defmethod func ((arg1 class1) arg2 ...) body ) I Methods are outside the classes (ordinary function calls) I Multiple dispatch (multi-methods) 11/25 Summary of step 1 Visitor: Just Do It 1 Original hierarchy untouched Didier Verna I Generic function model (outside the classes) Introduction 2 Abstract the visiting process away C++ I Still needs to be done LISP Step 1: plain LISP Step 2: brute force Step 3: first class Step 4: mapping Step 5: generic map State Step 6: objects Step 7: closures step 8: visit schemes Conclusion 12/25 Step 2: brute force visiting Visitor: Just Do It Abstract the visiting process away Didier Verna I OK: the accept generic function Introduction C++ But what’s wrong with this picture ? LISP Step 1: plain LISP obj visitor Step 2: brute force Step 3: first class Step 4: mapping Step 5: generic map State Step 6: objects accept visit Step 7: closures step 8: visit schemes obj visitor Conclusion obj visitor obj visitor ... ... I One indirection too many 13/25 Step 3: first class (generic) functions Visitor: Just Do It Notion of first class / order Didier Verna (Christopher Strachey, 1916–1975) Introduction storage (in variables) C++ aggregation (in structures) LISP Step 1: plain LISP Step 2: brute force argument (to functions) Step 3: first class Step 4: mapping return value (from functions) Step 5: generic map State anonymous manipulation Step 6: objects Step 7: closures dynamic creation step 8: visit schemes Conclusion ... I Generic functions are first class objects in LISP 14/25 The better picture Visitor: Just Do It Didier Verna obj Introduction C++ LISP Step 1: plain LISP accept visitor Step 2: brute force Step 3: first class obj Step 4: mapping obj Step 5: generic map obj State ... Step 6: objects Step 7: closures step 8: visit schemes Conclusion Retrieving function objects in LISP (function func) ;; => #<FUNCTION FUNC> # ’ func ;; => #<FUNCTION FUNC> 15/25 Step 4: mapping Visitor: Just Do It Prominent concept in functional programming Didier Verna I Along with folding (reduction), filtering etc. Introduction Thanks to first class functions C++ I Argument passing LISP Step 1: plain LISP Step 2: brute force Typical mapping example Step 3: first class Step 4: mapping "foo" "bar" "baz" Step 5: generic map ( mapcar # ’ string−upcase ’ ( )) ;; =>("FOO""BAR""BAZ") State Step 6: objects Step 7: closures step 8: visit schemes I “visiting” is a form of structural mapping Conclusion 16/25 Step 5: generic mapping Visitor: Just Do It Having to specialize mapobject is boring Didier Verna I Mapping over lists, vectors, arrays, even class slots Introduction should be written only once C++ LISP The CLOS Meta-Object Protocol (MOP) Step 1: plain LISP Step 2: brute force CLOS itself is object-oriented Step 3: first class Step 4: mapping I The CLOS MOP: a de facto implementation standard Step 5: generic map I The CLOS components (classes etc.) are State Step 6: objects (meta-)objects of some (meta-)classes Step 7: closures step 8: visit schemes We have reflexive (introspective) access to class slots Conclusion I 17/25 Step 6: objects Visitor: Just Do It How about a component counter visitor ? Didier Verna C++: left as an exercise. Introduction C++ LISP: how does that fit with first class functions ? LISP I Global state (yuck !) Step 1: plain LISP I Behavior + state = objects ! Step 2: brute force Step 3: first class Step 4: mapping So we’re back to visitor objects ? Step 5: generic map State There has got to be a better way. Step 6: objects I Step 7: closures step 8: visit schemes Conclusion 19/25 Step 7: lexical closures Visitor: Just Do It Behavior + State without the OO machinery Didier Verna Introduction Typical functional example (with anonymous function) C++ ( defun make−adder ( n ) LISP (lambda (x) (+ n x))) Step 1: plain LISP Step 2: brute force ( funcall ( make−adder 3) 5) ;; =>8 Step 3: first class Step 4: mapping Step 5: generic map State Closures with mutation (impure functional programming) Step 6: objects Step 7: closures ( l e t (( count 0 ) ) step 8: visit schemes ( defun increment () ( incf count ))) Conclusion (increment) ;; =>1 (increment) ;; =>2 ;;... 20/25 Step 8: dynamic visitation schemes Visitor: Just Do It How about a component nesting counter visitor ? Didier Verna C++: left as an exercise. Introduction C++ LISP: modification of the visit process required LISP 1 increment nesting level before visiting an object Step 1: plain LISP 2 actual visit Step 2: brute force Step 3: first class 3 decrement nesting level afterwards Step 4: mapping Step 5: generic map Do we need a dedicated mapobject for that ? State Step 6: objects Step 7: closures No ! We have the MOP’s generic function protocol
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages22 Page
-
File Size-