introduction to programmingse.inf.ethz.ch/old/teaching/2007-f/eprog-0001/slides/22... · 2007. 12....
TRANSCRIPT
-
Einführung in die ProgrammierungIntroduction to Programming
Prof. Dr. Bertrand Meyer
Chair of Software Engineering
Lecture 22: Undo/Redo
-
2Introduction to Programming, lecture 22: Undo / Redo
Further reference
Chapter 21 of my Object-Oriented Software Construction, Prentice Hall, 1997
Erich Gamma et al., Design Patterns, Addison –Wesley, 1995: “Command pattern”
-
3Introduction to Programming, lecture 22: Undo / Redo
The problem
Enabling users of an interactive system to cancel the effect of the last command
Often implemented as “Control-Z”
Should support multi-level undo-redo (“Control-Y”), with no limitation other than a possible maximum set by the user
-
4Introduction to Programming, lecture 22: Undo / Redo
Why are we doing this?
Useful in every interactive application Don‟t even think of writing an interactive system
without an undo-redo mechanism
Useful design pattern (“Command”)
Illustration of general algorithmic and data structure techniques
Review of O-O techniques: inheritance, deferred classes, polymorphic data structures, dynamic binding…
Beautiful and elegant
-
5Introduction to Programming, lecture 22: Undo / Redo
Our working example: a text editor
Notion of “current line”.Assume commands such as:
Remove current line Replace current line by specified text Insert line before current position Swap current line with next if any “Global search and replace” (hereafter GSR): replace
every occurrence of a specified string by another ...
This is a line-oriented view for simplicity, but the discussion applies to more sophisticated views
-
6Introduction to Programming, lecture 22: Undo / Redo
Underlying class (from application*)
class EDIT_CONTROLLER feature
text: TWO_WAY_LIST [STRING]
remove-- Delete line at current position.
requirenot off
dotext.remove
end
put_right (line: STRING)-- Insert line after current position.
requirenot after
dotext.put_right (line)
end...
end *or “model” (cf. MVC)
-
7Introduction to Programming, lecture 22: Undo / Redo
A straightforward solution
Before performing any operation, save entire state
In the example: text being edited,current position in text
If user issues “Undo” request, restore entire state as last saved
But: huge waste of resources, space in particular
Intuition: only save the “diff” between states.
-
8Introduction to Programming, lecture 22: Undo / Redo
Key step in devising a software architecture
Here:
The notion of “command”
Finding the right abstractions
(the interesting object types)
-
9Introduction to Programming, lecture 22: Undo / Redo
Keeping the history of the session
The history list:
history : TWO_WAY_LIST [COMMAND]
Removal SwapInsertion Insertion Insertion
Oldest Most recent
-
10Introduction to Programming, lecture 22: Undo / Redo
What’s a “command” object?
A command object includes information about one execution of a command by the user, sufficient to:
Execute the command
Cancel the command if requested later
For example, in a Removal command object, we need:
• The position of the line being removed
• The content of that line!
-
11Introduction to Programming, lecture 22: Undo / Redo
General notion of command
deferred class COMMAND feature
execute-- Carry out one execution of this command.
undo-- Cancel an earlier execution of this command.
end
deferred
: doneend
deferredend
done: BOOLEAN -- Has this command been executed?
ensurealready: done
requirealready: done
-
12Introduction to Programming, lecture 22: Undo / Redo
Command class hierarchy
execute*
undo*
…
execute+
undo+
line: STRINGindex: INTEGER
...
execute+
undo+
index
...
+
* deferred
effective
*COMMAND
+REMOVAL
+INSERTION
-
13Introduction to Programming, lecture 22: Undo / Redo
Underlying class (from business model)
class EDIT_CONTROLLER feature
text : TWO_WAY_LIST [STRING]
remove-- Remove line at current position.
requirenot off
dotext.remove
end
put_right (line : STRING)-- Insert line after current position.
requirenot after
dotext.put_right (line)
end
... also item, index, go_ith, put_left ...end
-
14Introduction to Programming, lecture 22: Undo / Redo
A command class (sketch, no contracts)
class REMOVAL inherit COMMAND feature
controller : EDIT_CONTROLLER-- Access to business model
line : STRING-- Line being removed
index : INTEGER-- Position of line being removed
execute-- Remove current line and remember it.
do line := controller.item ; index := controller.indexcontroller.remove ; done := True
end
undo-- Re-insert previously removed line.
do controller.go_i_th (index)controller.put_left (line)
endend
-
15Introduction to Programming, lecture 22: Undo / Redo
A polymorphic data structure:
history : TWO_WAY_LIST [COMMAND]
Removal SwapInsertion Insertion Insertion
Oldest Most recent
The history list
-
16Introduction to Programming, lecture 22: Undo / Redo
Reminder: the list of figures
classLIST [G]
feature...last: G do ...extend (x: G) do ...
end
fl : LIST [FIGURE]r : RECTANGLEs : SQUAREt : TRIANGLEp : POLYGON...
fl.extend (p); fl.extend (t); fl.extend (s); fl.extend (r)fl.last.display
(SQUARE)
(RECTANGLE)
(TRIANGLE)
(POLYGON)
fl
-
17Introduction to Programming, lecture 22: Undo / Redo
Reminder: a composite figure as a list
Cursor
item
forth
-
18Introduction to Programming, lecture 22: Undo / Redo
A polymorphic data structure:
history : TWO_WAY_LIST [COMMAND]
Removal SwapInsertion Insertion Insertion
Oldest Most recent
The history list
-
19Introduction to Programming, lecture 22: Undo / Redo
Executing a user command
decode_user_request
if “Request is normal command” then“Create command object c corresponding to user request”
history.extend (c)c.execute
elseif “Request is UNDO” then
if not history.before then -- Ignore excessive requestshistory.item.undohistory.back
endelseif “Request is REDO” then
if not history.is_last then -- Ignore excessive requestshistory.forthhistory. item.execute
endend
item
Pseudocode, see implementation next
Removal SwapInsertion Insertion
-
20Introduction to Programming, lecture 22: Undo / Redo
Conditional creation (1)
…
…
a1 : A
if condition_1 then-- “Create a1 as an instance of B”
elseif condition_2 then-- “Create a1 as an instance of C”
... etc.
a1 : A; b1 : B ; c1 : C ; d1 : D ; ...if condition_1 then
create b1.make (...)a1 := b1
elseif condition_2 then
create c1.make (...)a1 := c1
... etc.
A
B C
D
-
21Introduction to Programming, lecture 22: Undo / Redo
Conditional creation (2)
…
…
a1 : A
if condition_1 then-- “Create a1 as an instance of B”
elseif condition_2 then-- “Create a1 as an instance of C”
... etc.
a1 : Aif condition_1 then
create {B } a1.make (...)elseif condition_2 then
create {C } a1.make (...)... etc.
A
B C
D
-
22Introduction to Programming, lecture 22: Undo / Redo
Executing a user command
decode_user_request
if “Request is normal command” then“Create command object c corresponding to user request”
history.extend (c)c.execute
elseif “Request is UNDO” then
if not history.before then -- Ignore excessive requestshistory.item.undohistory.back
endelseif “Request is REDO” then
if not history.is_last then -- Ignore excessive requestshistory.forthhistory. item.execute
endend
item
Removal SwapInsertion Insertion
-
23Introduction to Programming, lecture 22: Undo / Redo
Creating command objects: first approach
c : COMMAND
...
decode_user_request
if “Request is remove” then
create {REMOVAL } c
elseif “Request is insert” then
create {INSERTION } celse
etc.
-
24Introduction to Programming, lecture 22: Undo / Redo
Command class hierarchy
execute*
undo*
…
execute+
undo+
line: STRINGindex: INTEGER
...
execute+
undo+
index
...
+
* deferred
effective
*COMMAND
+REMOVAL
+INSERTION
-
25Introduction to Programming, lecture 22: Undo / Redo
Creating command objects : better approach
Give each command type a number
Initially, fill an array commands with
one instance of every command type.
To get a new command object:
“Determine command_type”
c := (commands [command_type]).twinRemoval
Insertion
Swap
...
1
2
n
command_type
Duplicate a “prototype”
commands
-
26Introduction to Programming, lecture 22: Undo / Redo
The undo-redo (or “command”) pattern
Has been extensively used (e.g. in EiffelStudio and other Eiffel tools)
Fairly easy to implement
Details must be handled carefully (e.g. some commands may not be undoable)
Elegant use of O-O techniques
Disadvantage: explosion of small classes
-
27Introduction to Programming, lecture 22: Undo / Redo
Using agents
For each user command, have two routines:
The routine to do it
The routine to undo it!
-
28Introduction to Programming, lecture 22: Undo / Redo
The history list in the undo-redo pattern
history : TWO_WAY_LIST [COMMAND]
Removal SwapInsertion Insertion Insertion
Oldest Most recent
-
29Introduction to Programming, lecture 22: Undo / Redo
The history list using agents
The history list simply becomes a list of agents pairs:
history : TWO_WAY_LIST [TUPLE
[doer : PROCEDURE [ANY, TUPLE],
undoer : PROCEDURE [ANY, TUPLE]]
Basic scheme remains the same, but no need for command
objects any more; the history list simply contains agents.
Insertion Insertion Removal SwapInsertion
De-insertion
De-insertion
Re-insertion
SwapDe-insertion
Named tuple
-
30Introduction to Programming, lecture 22: Undo / Redo
Executing a user command (before)
decode_user_request
if “Request is normal command” then“Create command object c corresponding to user request”
history.extend (c)c.execute
elseif “Request is UNDO” then
if not history.before then -- Ignore excessive requestshistory.item.undohistory.back
endelseif “Request is REDO” then
if not history.is_last then -- Ignore excessive requestshistory.forthhistory. item.execute
endend
item
Removal SwapInsertion Insertion
-
31Introduction to Programming, lecture 22: Undo / Redo
Executing a user command (now)
“Decode user_request giving two agents do_it and undo_it ”if “Request is normal command” then
history.extend ([do_it, undo_it ])do_it.call ([])
elseif “Request is UNDO” then
if not history.before thenhistory.item.undoer .call ([])history.back
endelseif “Request is REDO” then
if not history.is_last thenhistory.forthhistory.item.doer .call ([])
endend
Insertion Insertion Removal Swap
De-insertion
De-insertion
Re-insertion
Swap
-
32Introduction to Programming, lecture 22: Undo / Redo
What we have seen
People make mistakes!Even when they don‟t mess up, they want to experiment: undo-redo supports “trial and error” experimental style
Undo-redo pattern: Very useful in practice Widely used Fairly easy to implement Excellent illustration of elegant O-O techniques Even better with agents!
-
33Introduction to Programming, lecture 22: Undo / Redo
Further reference
Chapter 21 of “Object-Oriented Software Construction”, Prentice Hall, 1997
-
34Introduction to Programming, lecture 22: Undo / Redo
End of lecture 22
-
35Introduction to Programming, lecture 22: Undo / Redo
(Supplementary) lecture 18:Elements of compiling and
parsing
-
36Introduction to Programming, lecture 22: Undo / Redo
Compiler steps
Lexical analysis
Parsing (syntax analysis)
Semantic processing
Code generation
Optimization
-
37Introduction to Programming, lecture 22: Undo / Redo
Compiler steps
Lexical analysis
Identify tokens
Parsing (syntax analysis)
Identify syntactic structure
Semantic processing
Identify semantic information, e.g. types
Code generation
Produce code
Optimization
Improve efficiency of generated code
-
38Introduction to Programming, lecture 22: Undo / Redo
Code generation
Often performed in two or more steps
Examples:
.NET: compilers produce (CIL) Common Intermediate Language code, then “jitted” to native code
EiffelStudio “classic”: compiler produces C, then compiled to native code
EiffelStudio on .NET: uses CIL like other .NET compilers
-
39Introduction to Programming, lecture 22: Undo / Redo
A simple approach
Scripting language with single-line commands of the formaction arg1 arg2 …
For exampletravel Haldenegg Limmatplatz Tram 4
This can be processed very simply: Fill in a table of commands (travel etc.), e.g. hash table Read each line through read_line Find successive words Look up command name (first word) in command table Depending on the command, process the arguments
Drawbacks: tied to exact format (no flexibility); syntax and semantics closely intertwined; error processing not easy.
-
40Introduction to Programming, lecture 22: Undo / Redo
Strategies: compiler and interpreter
As mathematical functions:
interpreter: Program x Input Output
compiler: Program [Input Output]Consistency:
p: Program, i: Input |
interpreter (p, i) = [compiler (p)] (i)
-
41Introduction to Programming, lecture 22: Undo / Redo
EiffelStudio
Serialization
EiffelStore
EiffelStudio
Ansi C
Executable
system
IL
EiffelBase
WEL
EiffelVision
EiffelNet
EiffelWeb
EiffelMath
EiffelCOM
Persistent
objects
Eiffel
Runtime
Databases
(Rel, OO)
C compilation
JitterEiffel compilation
User classes
General library
Win32 GUI
Networking
Web scripting
Advanced numerics
External
C/C++/Java
.NET
Assemblies
EiffelBuild
GUI builder
Multiplatform GUI library
Browsing, fast compiling (Melting Ice™), debugging, diagrams, metrics...
-
42Introduction to Programming, lecture 22: Undo / Redo
EiffelStudio: Melting Ice Technology
Fast recompilation: time depends on size of change, not size of program
Full type checking
“Freeze” once in a while
Optimized compilation: finalize.
-
43Introduction to Programming, lecture 22: Undo / Redo
Melting Ice Technology
MELTED
FROZEN
YOUR SYSTEM
EIFFELSTUDIOExecution,browsing,
debugging,documentation ...
MELTING
FREEZINGMachine code(from C code)
-
44Introduction to Programming, lecture 22: Undo / Redo
Compilation modes
“Workbench” mode:
Melt
Freeze (requested, or automatic in case of new externals)
Finalized mode
-
45Introduction to Programming, lecture 22: Undo / Redo
Parsing: concrete syntax tree
if a = b then x := y else x.f (y ) end
-
46Introduction to Programming, lecture 22: Undo / Redo
Parsing: abstract syntax tree (AST)
if a = b then x := y else x.f (y ) end
-
47Introduction to Programming, lecture 22: Undo / Redo
The two key structures of a modern compiler
Abstract syntax tree (AST)
Records abstract structure of program texts
“Decorated” by successive passes of the compiler
Symbol table
Records information about program elements (classes, features, …)
Often implemented as a hash table
These structures are connected: nodes of the AST may refer to entries in the symbol table
-
48Introduction to Programming, lecture 22: Undo / Redo
Compiler passes
In the old days: Program text was read from sequential input (e.g.
punched cards, tape) Storage was expensive, so the text would have to be
read several times, each called a pass of the compiler A performance goal was to minimize the number of
passesToday the notion is more diffuse:
First “pass” (parsing) produces an AST and symbol table
Successive steps (still called passes) build up (“decorate”) these structures and generated the code
In EiffelStudio: degrees (6 then down)
-
49Introduction to Programming, lecture 22: Undo / Redo
EiffelStudio degrees
6: Explore universe5: Parsing4: Inheritance analysis3: Type checking2: Overall analysis1: Bytecode generation-1, -2, -3 (freezing & finalize): C code generation & optimization
A [i, j]
B [(i-1)*R + j-1]
-
50Introduction to Programming, lecture 22: Undo / Redo
Lexical analysis
The elementary step of compilation
Purpose: identify the successive tokens of the input
Examples of token types (constructs):
IdentifierA_name
Integer constant3654
String constant″ABCD″
Symbol:=
-
51Introduction to Programming, lecture 22: Undo / Redo
Grammars for lexical analysis
“Regular” (Chomsky type 3) grammars
Like ordinary BNF or BNF-E but with strict restrictions:
Repetition: just of the form A* or A+ where A is a lexical construct
No recursion: not possible to have both A‟s definition use B and conversely
-
52Introduction to Programming, lecture 22: Undo / Redo
Example
+
Abbreviate asLetter == 'a' .. 'z' 'A' .. 'Z‘Decimal_digit == '0' .. ‘9
-
53Introduction to Programming, lecture 22: Undo / Redo
Finite automata
+
-
54Introduction to Programming, lecture 22: Undo / Redo
Building a lexical analyzer: EiffelLex
Use a Lexical Grammar File, e.g.
Decimal „0‟ .. „9‟
Natural + („0‟.. „9‟)
Integer [„+‟ | „-‟] „1‟.. „9‟ * („0‟ .. „9‟)
-
55Introduction to Programming, lecture 22: Undo / Redo
The syntax level
Instruction == Assignment | Conditional
Assignment == Identifier := Identifier
Conditional == if Identifier then Compound end
Compound == {Instruction ; }*
Terminal (from the lexical level)
Non-terminal
-
56Introduction to Programming, lecture 22: Undo / Redo
Top-down recursive descent
Instruction == Assignment | Conditional
Assignment == Identifier := Identifier
Conditional == if Identifier then Compound end
Compound == {Instruction ; }*
Turn the grammar into a set of mutually recursive
procedures!
-
57Introduction to Programming, lecture 22: Undo / Redo
Top-down recursive descent
Instruction == Assignment | Conditional | Compound
Assignment == Identifier := Identifier
Conditional == if Identifier then Compound end
Compound == {Instruction ; }*
Turn the grammar into a set of mutually recursive
procedures!
But: Left recursion
-
58Introduction to Programming, lecture 22: Undo / Redo
An object-oriented view
EiffelParse: turn each construct into a class!
Advantages:
Very easy to write(especially with translator: YOOC!)
Recursive descent algorithm, simple and clear
Easy to add semantics
Easy to add several semanticse.g. compiler, interpreter, pretty-printer,static analyzer...Just use inheritance
Disadvantage: less fast than bottom-up techniques (e.g. Yacc, Gobo parse)
-
59Introduction to Programming, lecture 22: Undo / Redo
EiffelParse top classes
CONSTRUCT
The following ones are its descendants
AGGREGATE
Example: CONDITIONAL
CHOICE
Example: INSTRUCTION
REPETITION
Example: COMPOUND