Revisiting the Visitor: the Just Do It Pattern C++ L ISP Step 1: - - PowerPoint PPT Presentation

revisiting the visitor the just do it pattern
SMART_READER_LITE
LIVE PREVIEW

Revisiting the Visitor: the Just Do It Pattern C++ L ISP Step 1: - - PowerPoint PPT Presentation

Visitor: Just Do It Didier Verna Introduction Revisiting the Visitor: the Just Do It Pattern C++ L ISP Step 1: plain L ISP Step 2: brute force Step 3: first class Didier Verna Step 4: mapping Step 5: generic map State


slide-1
SLIDE 1

Visitor: Just Do It Didier Verna Introduction C++ 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

Revisiting the Visitor: the “Just Do It” Pattern

Didier Verna

didier@lrde.epita.fr http://www.lrde.epita.fr/˜didier

ACCU 2009 – Friday, April 24th

1/25

slide-2
SLIDE 2

Visitor: Just Do It Didier Verna Introduction C++ 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

Introduction

Necessary literature The GOF Book: Design Patterns, Elements of Reusable Object-Oriented Software. Gamma, Helm, Johnson, Vlissides. The POSA Book: Pattern-Oriented Software

  • Architecture. Buschmann, Meunier, Rohnert,

Sommerlad, Stal. What is a software design pattern ?

◮ Context (POSA) ◮ Problem ◮ Solution ◮ Consequences (GOF) 2/25

slide-3
SLIDE 3

Visitor: Just Do It Didier Verna Introduction C++ 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

A constatation

Peter Norvig (Object World, 1996) About the GOF book: 16 of 23 patterns are either invisible or simpler [...] in Dylan or Lisp Peter Norvig is right, so

◮ is the GOF book (70%) wrong ? ◮ are patterns (70%) useless ? 3/25

slide-4
SLIDE 4

Visitor: Just Do It Didier Verna Introduction C++ 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

Some clues from the GOF book itself

Although design patterns describe

  • bject-oriented designs, they are based on

practical solutions that have been implemented in mainstream object-oriented programming languages [. . . ] Similarly, some of our patterns are supported directly by the less common object-oriented languages. ◮ That’s what people usually miss

4/25

slide-5
SLIDE 5

Visitor: Just Do It Didier Verna Introduction C++ 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

Patterns descriptions / organizations

GOF: Creational, Structural, Behavioral

◮ usage-oriented

POSA: Architectural, Design, Idioms

◮ abstraction-oriented

Idioms according to POSA An idiom is a low-level pattern specific to a programming language. An idiom describes how to implement particular aspects of components or the relationships between them using the features of the given language. [. . . ] They address aspects of both design and implementation. ◮ GOF’s design patterns are closer to POSA’s idioms

5/25

slide-6
SLIDE 6

Visitor: Just Do It Didier Verna Introduction C++ 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

The risk: blind pattern application

POSA’s advice: [. . . ] sometimes, an idiom that is useful for one programming language does not make sense into another. GOF’s Visitor example: Use the Visitor pattern when [. . . ] many distinct and unrelated operations need to be performed on

  • bjects in an object structure, and you want to

avoid “polluting” their classes with these

  • perations.

◮ But who said operations belong to classes ?

6/25

slide-7
SLIDE 7

Visitor: Just Do It Didier Verna Introduction C++ 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

Table of contents

1

Visiting in C++

2

Visiting in LISP Step 1: plain LISP Step 2: brute force visiting Step 3: first class generic functions Step 4: mapping Step 5: generic mapping

3

Visiting with state Step 6: objects Step 7: lexical closures Step 8: dynamic visitation schemes

7/25

slide-8
SLIDE 8

Visitor: Just Do It Didier Verna Introduction C++ 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

Visiting in C++

Problems: Original hierarchy R/O Abstract the visiting process away Solution:

1 Equip original hierarchy for visits

◮ A Visitable abstract class ◮ An accept method in each visitable component

2 Write independent visitors

◮ A Visitor abstract class ◮ A visit method for each visitable component 9/25

slide-9
SLIDE 9

Visitor: Just Do It Didier Verna Introduction C++ 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

Step 1: plain LISP

Classes

( defclass class ( superclass1 superclass2 . . . ) ( ( s l o t : i n i t f o r m <form> : i n i t a r g : s l o t : accessor s l o t ) . . . )

  • ptions . . . )

( make−instance ’ class : s l o t <value > . . . )

Generic functions, methods

( defgeneric func ( arg1 arg2 . . . ) ( : method ( ( arg1 class1 ) arg2 . . . ) body )

  • ptions . . . )

( defmethod func ( ( arg1 class1 ) arg2 . . . ) body )

◮ Methods are outside the classes (ordinary function calls) ◮ Multiple dispatch (multi-methods)

11/25

slide-10
SLIDE 10

Visitor: Just Do It Didier Verna Introduction C++ 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

Summary of step 1

1 Original hierarchy untouched

◮ Generic function model (outside the classes)

2 Abstract the visiting process away

◮ Still needs to be done 12/25

slide-11
SLIDE 11

Visitor: Just Do It Didier Verna Introduction C++ 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

Step 2: brute force visiting

Abstract the visiting process away

◮ OK: the accept generic function

But what’s wrong with this picture ?

  • bj visitor
  • bj visitor
  • bj visitor

... ...

visit accept

  • bj

visitor

◮ One indirection too many

13/25

slide-12
SLIDE 12

Visitor: Just Do It Didier Verna Introduction C++ 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

Step 3: first class (generic) functions

Notion of first class / order

(Christopher Strachey, 1916–1975)

storage (in variables) aggregation (in structures) argument (to functions) return value (from functions) anonymous manipulation dynamic creation . . . ◮ Generic functions are first class objects in LISP

14/25

slide-13
SLIDE 13

Visitor: Just Do It Didier Verna Introduction C++ 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

The better picture

  • bj

...

  • bj
  • bj

visitor accept

  • bj

Retrieving function objects in LISP

( function func ) ; ; => #<FUNCTION FUNC> # ’ func ; ; => #<FUNCTION FUNC> 15/25

slide-14
SLIDE 14

Visitor: Just Do It Didier Verna Introduction C++ 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

Step 4: mapping

Prominent concept in functional programming

◮ Along with folding (reduction), filtering etc.

Thanks to first class functions

◮ Argument passing

Typical mapping example

(mapcar # ’ string−upcase ’ ( "foo" "bar" "baz" ) ) ; ; => ( "FOO" "BAR" "BAZ" )

◮ “visiting” is a form of structural mapping

16/25

slide-15
SLIDE 15

Visitor: Just Do It Didier Verna Introduction C++ 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

Step 5: generic mapping

Having to specialize mapobject is boring

◮ Mapping over lists, vectors, arrays, even class slots

should be written only once

The CLOS Meta-Object Protocol (MOP) CLOS itself is object-oriented

◮ The CLOS MOP: a de facto implementation standard ◮ The CLOS components (classes etc.) are

(meta-)objects of some (meta-)classes

◮ We have reflexive (introspective) access to class slots

17/25

slide-16
SLIDE 16

Visitor: Just Do It Didier Verna Introduction C++ 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

Step 6: objects

How about a component counter visitor ? C++: left as an exercise. . . LISP: how does that fit with first class functions ?

◮ Global state (yuck !) ◮ Behavior + state = objects !

So we’re back to visitor objects ? ◮ There has got to be a better way. . .

19/25

slide-17
SLIDE 17

Visitor: Just Do It Didier Verna Introduction C++ 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

Step 7: lexical closures

Behavior + State without the OO machinery Typical functional example (with anonymous function)

( defun make−adder ( n ) ( lambda ( x ) (+ n x ) ) ) ( funcall ( make−adder 3) 5) ; ; => 8

Closures with mutation (impure functional programming)

( l e t ( ( count 0)) ( defun increment ( ) ( incf count ) ) ) ( increment ) ; ; => 1 ( increment ) ; ; => 2 ; ; . . . 20/25

slide-18
SLIDE 18

Visitor: Just Do It Didier Verna Introduction C++ 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

Step 8: dynamic visitation schemes

How about a component nesting counter visitor ? C++: left as an exercise. . . LISP: modification of the visit process required

1 increment nesting level before visiting an object 2 actual visit 3 decrement nesting level afterwards

Do we need a dedicated mapobject for that ? ◮ No ! We have the MOP’s generic function protocol

21/25

slide-19
SLIDE 19

Visitor: Just Do It Didier Verna Introduction C++ 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

The generic function protocol

Generic function invocation

Return value call−next−method

Before Method Primary Method After Method Around Method

Methods are CLOS meta-objects Methods can be added/removed dynamically

22/25

slide-20
SLIDE 20

Visitor: Just Do It Didier Verna Introduction C++ 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

Summary

Decoupling from original hierarchy: n/a

◮ Generic function model (outside the classes)

Visiting infrastructure:

◮ First class generic functions (as argument) ◮ CLOS MOP (introspection)

◮ Generic machinery in 10 lines of code Visiting with state:

◮ Lexical closures ◮ First class functions (anonymous) ◮ Generic function protocol (before/after)-methods

◮ 5–10 more lines of code (original code untouched)

23/25

slide-21
SLIDE 21

Visitor: Just Do It Didier Verna Introduction C++ 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

Conclusion

The “iceberg” metaphor

Programming Language Programmer’s Application DESIGN PATTERN What you need to write What’s already here

Lisp

Notice the difference ? 24/25

slide-22
SLIDE 22

Visitor: Just Do It Didier Verna Introduction C++ 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

Next LISP Events

ELS’09: 2nd European LISP Symposium May 27-29 2009, Milan, Italy http://www.european-lisp-symposium.org ELW’09: 6th European LISP Workshop July 6 2009, Genova, Italy co-located with ECOOP . http://elw.bknr.net/2009

25/25