Revisiting the Visitor: the ``Just Do It'' Pattern

Revisiting the Visitor: the ``Just Do It'' Pattern

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

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    22 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us