More Related Content Similar to Developing Software that Matters (condensed) (20) More from Gneuromante canalada.org (9) Developing Software that Matters (condensed)1. OOP: Why?
Franco Gasperoni
gasperoni@adacore.com
http://www.adacore.com/
http://libre.adacore.com/
www.adacore.com 2. Slides Home page
• http://libre.adacore.com/Software_Matters
All the course slides are there (PDF and PowerPoint)
Slide 2 3. Copyright Notice
• © AdaCore under the GNU Free Documentation License
• Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU Free Documentation
License, Version 1.1 or any later version published by the Free
Software Foundation; provided its original author is mentioned and
the link to http://libre.adacore.com/ is kept. A copy of the license
is included in available at:
• http://www.fsf.org/licenses/fdl.html
Slide 3 4. Objectives
Why OOP
Comparing ways to
structure software
– Functionality-oriented
Functionality-
– Object-oriented
Object-
– Structural problems with
both approaches
Slide 4 6. Why OOP?
• What are OOP’s benefits?
• What problem does OOP solve?
Slide 6 7. Side Note on
Software Construction
Processes
www.adacore.com 9. Software Processes
• A Software Process is
– A set of activities (e.g. requirements, analysis, design, coding,
testing) combined and sequenced in a particular fashion to
produce software
• Recent trend: Agile Software Development
– Customer needs evolve with time
– Satisfying customers at delivery time (rather than at project
initiation) is more important than conforming to initial customer
requirements
Slide 9 10. Example of Software Processes
Waterfall Iterative eXtreme Programming (XP)
Requirements
Requirements
Analysis
Testing
Coding
Design
Requirements Analysis
Design
Requirements
Analysis
Testing
Coding
Design
Coding
Analysis Testing
Requirements
Analysis
Testing
Coding
Requirements
Design
Time
Analysis
Design
Requirements
Design
Analysis
Testing
Coding
Design
Coding
Testing
Requirements
Coding
Analysis
Testing
Coding
Requirements
Design
Analysis
Design
Requirements
Analysis
Testing
Coding
Design
Testing Coding
Testing
Scope (customer needs)
Slide 10 11. • This course is independent of
• Particular software construction methodology
Slide 11 13. Need to Structure and Organize
Organization / Structure is fundamental to:
• Engineering activities
– Buildings, software, planes, ...
• Many human endeavours
– Music, books, business corporations, ...
• Nature is structured
– Human body, plants, the universe, ...
Slide 13 14. Why do we Need to Structure & Organize Software?
• Divide the work among groups of people
• Helping people to understand the software
• Make software fixes possible
• Make software evolution possible
•…
Slide 14 15. Properties of an Ideal Software Architecture
• Loose coupling between components of the software
– Division of labor
– Components re-use
• No functionality/code duplication
• Code changes minimized when software evolves
• Code re-testing minimized when software evolves
Slide 15 16. Structuring Elements of Software
When creating a new system you identify its:
• Data types
– Kind of data that will be manipulated
• Operations
– Manipulations on the data
Slide 16 17. OOP vs SP
Two dimensions around which to organize software:
• Around its operations
– Structured Programming (SP)
• Around its Data Types
– Object-Oriented Programming (OOP)
Slide 17 18. Example
operations
related
types
op1() op2() op3() op4() op5()
X X X
A
X X X
B
X X X
C
Slide 18 19. SP: A centralized view of Software
operations
related
types
op1() op2() op3() op4() op5()
X X X
A
X X X
B
X X X
C
Slide 19 20. OOP: A distributed view of Software
operations
related
types
op1() op2() op3() op4() op5()
X X X
A
X X X
B
X X X
C
Slide 20 21. SP vs OOP: Where Differences Are Significant
The key discriminator between SP and OOP is change
• Change in operations
– What happens when new operations need to be added to an SP or an
OOP program?
• Change in data types
– What happens when new data types need to be added to an SP or an
OOP program?
Slide 21 22. New Operation
operations
related
types
op1() op2() op3() op4() op5() new()
X X X
A
X X X X
B
X X X X
C
Slide 22 23. New Operation: SP – a Good Choice
operations
related
types
op1() op2() op3() op4() op5() new()
X X X
A
X X X X
B
X X X X
C
Slide 23 24. New Operation: OOP – A Poor Choice
operations
related
types
op1() op2() op3() op4() op5() new()
X X X
A
X X X X
B
X X X X
C
Slide 24 25. New Data Type
operations
related
types
op1() op2() op3() op4() op5()
X X X
A
X X X
B
X X X
C
X X X
NEW
Slide 25 26. New Data Type: SP - A Poor Choice
operations
related
types
op1() op2() op3() op4() op5()
X X X
A
X X X
B
X X X
C
X X X
NEW
Slide 26 27. New Data Type: OOP - A Good Choice
operations
related
types
op1() op2() op3() op4() op5()
X X X
A
X X X
B
X X X
C
X X X
NEW
Slide 27 28. New functionalities can be
factored in few tagged types
Summary
Data type
changes
??
Use
Object
Use
Oriented
Object
Oriented
use Functionality‐Oriented
Functionality changes Slide 28 30. Programming Language Design Goals
•C
– A portable, higher-level assembly language
– No safety or security concerns
• C++
– An object-oriented language upwardly compatible with C
– No safety or security concerns
• Java
– Fix C++ insecurity problems (i.e. cannot create a virus in Java)
– No safety concerns
Slide 30 31. Ada
Industrial-strength version of Pascal designed to build:
• Safe software
• Secure software
• Software that needs to evolve
• Mixed-language software
• Language designed by an international team
– 1983: First version of the language
– 1995: Major revision (adds OOP, …)
– 2005: Latest revision
Slide 31 32. Some Industrial Applications in Ada
• Business-critical
– Canal+ Technologies: Pay-per-view, access control
– BNP: Trading Language
– Philips: Semiconductor assembly equipment
– Helsinki radiotelescope
• Mission-critical
– Astree: European-wide railroad signaling
– Weirton Steel - process controller
– Mondex electronic money
– Scanning Electron microscope
• Safety-critical
– Airbus A340
– Boeing 777
Slide 32 33. Ziegler’s Study: Comparing C & Ada
• 1995 VADS study
– 60 engineers, from 1984 ..1994 with MS degrees in computer science
– All knew C at hire. All programmed in both C and Ada.
• VADS
– About 4.5 million lines of code, 22000 files, cost >$28m over 10 years
2500000
2000000
1500000
ll in s
AL e
1000000
500000
0
C Code Ada Code Make Scripts Miscellany
Slide 33 34. Costs Per Feature During Implementation
cost/feature:
$350
$300
$250
$200
$150
$100
$50
$0
C C, including Makefiles ADA
Slide 34 36. Summary
• Developing software in Ada is 60% cheaper than in C
• Code developed in Ada has 9 times less bugs than in C
• Was Ada consistently better? *YES*
– Over different subsets of VADS
– For experienced AND inexperienced programmers
– For both C experts AND Ada experts
– For the highest AND lowest rated programmers
• Was Ada harder to learn? *No*
• Was Ada code more reliable? *YES*
http://www.adaic.com/whyada/ada-vs-c/cada_art.html
Slide 36 37. From an Education Perspective
• Ada is a good language to teach good software practice
– Reliability, safety, security
• Ada allows to design SP and OOP software
• Free Software high-quality Ada environment available
– http://libre.adacore.com
– GNAT GPL Edition (Ada 2005)
– Linux, Mac OS, Windows
Slide 37 38. • Programming in the Large
– specification & implementation
– privacy
38
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 39. Separate Compilation
T
C
H O
object
Compiler
D
E E
P L
i
C
R executable
O n
object
Compiler
D
k
O E
e
B r
L
E C
O
object
Compiler
M D
libraries
E
39
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 40. Problem with this approach
C
C C
O
O O
D
D D
E
E
C E
O
C
D
O
E
D
E
• No structure
• To write your own code
– YOU MUST understand
everybody else’s code
40
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 41. Idea: Specify the Services
SPECIFY
the Services provided
by each module
41
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 42. • SPEC = list of services provided
• BODY = implementation of the services (hidden)
Service_1
Service_2
Service_3
Service_1
implementation
Service_2
implementation
Service_3
implementation
Software module 42
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 43. SPECIFICATION
?
43
BODY
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 44. Example
• Create a Queue module that can
– Add an Integer to the Queue
– See the First integer in the Queue
– Get the first integer in the Queue
– Test whether the Queue is Empty
44
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 45. queue.ads
queue.ads
package Queue is
package Queue is
procedure Add (Element ::Integer);
procedure Add (Element Integer);
function First return Integer;
function First return Integer;
function Get return Integer;
function Get return Integer;
function Empty return Boolean;
function Empty return Boolean;
end Queue;
end Queue;
45
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 46. To write Client only need to look at
queue.ads
queue.ads
package Queue is
package Queue is
procedure Add (Element : :Integer);
procedure Add (Element Integer);
function First return Integer;
function First return Integer;
function Get return Integer;
function Get return Integer;
function Empty return Boolean;
function Empty return Boolean;
end Queue;
end Queue;
? package Queue
46
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 47. Using package Queue
client.adb
with Queue;
procedure Client is
Queue_Error : exception;
X : Integer;
begin
Queue.Add (3);
Queue.Add (4);
if not Queue.Empty then
X := Queue.Get;
else
raise Queue_Error;
end if;
end Client;
47
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 48. Specifications Reduce Complexity
SPEC
SPEC
SPEC
SPEC SPEC
SPEC
SPEC
SPEC
• To write your own code
– only need to understand
specs for the services
you need
48
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 49. Aside: use clause
with Queue; use Queue;
procedure Client is
Queue_Error : exception;
X : Integer;
begin
Queue. Add (3);
Queue. Add (4);
if not Queue. Empty then
X := Queue. Get;
else
raise Queue_Error;
end if;
end Client;
49
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 50. A Spec can have several
implementations
queue.ads
queue.ads
package Queue is
package Queue is (Element : Integer);
procedure Add
procedure Add (Element : Integer);
function First return Integer;
function First return Integer;
function Get return Integer;
function Get return Integer;
function Empty return Boolean;
function Empty return Boolean;
end Queue;
end Queue;
• Can change implementation
second
second
first implement.
first implement.
• WITHOUT having to change
implement.
implement.
ANY of the client’s code
50
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 51. One Possible Implementation:
Circular Buffer
Q
0 1
Max_Size - 1
Q_First
Q_Last
51
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 53. In Ada
• Spec always checked against implementation
• Must with the specs that you are going to
use (not in C)
• Packages provide multiple name spaces
53
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 54. Spec is checked against its body
package Queue is
package Queue is
procedure Add (Element ::Integer);
procedure Add (Element Integer);
...
...
end Queue;
end Queue; Compilation Error if no
procedure Add (Element : Integer) is
…
package body Queue is begin
package body Queue is …
...
... end Add;
...
...
end Queue;
end Queue;
54
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 55. Must with Specs used
with Queue;
procedure Client is Compilation
... error
begin
Queue.Add (3);
...
end Client;
55
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 56. Multiple Name Spaces
package Set is
package Queue is package Set is
package Queue is
procedure Add (E ::Integer);
procedure Add (E Integer);
procedure Add (E ::Integer);
procedure Add (E Integer);
...
... ...
...
end Set;
end Queue; end Set;
end Queue;
with Queue;
with Set;
procedure Client is
begin
Queue.Add (3);
Set.Add (99);
end Client; 56
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 57. Use Clause and Ambiguities
package Set is
package Queue is package Set is
package Queue is
procedure Add (E ::Integer);
procedure Add (E Integer);
procedure Add (E ::Integer);
procedure Add (E Integer);
...
... ...
...
end Set;
end Queue; end Set;
end Queue;
with Queue; use Queue;
with Set; use Set;
Compilation
procedure Client is error
begin ambiguity
Add (123);
end Client;
57
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 58. And … Ada has overloading
package Queue is
package Queue is
procedure Add (E ::Integer);
procedure Add (E Integer);
procedure Add (E ::Float);
procedure Add (E Float);
...
...
end Queue;
end Queue;
with Queue; use Queue;
procedure Client is
begin
Add (123);
Add (3.141);
end Client; 58
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 59. • Programming in the Large
– specification & implementation
– privacy
59
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 60. Having Several Queues
package Queues is
package Queues is
type Queue is …;
type Queue is …;
procedure Add (Q ::Queue; Element ::Integer);
procedure Add (Q Queue; Element Integer);
function First (Q ::Queue) return Integer;
function First (Q Queue) return Integer;
function Get (Q ::Queue) return Integer;
function Get (Q Queue) return Integer;
function Empty (Q ::Queue) return Boolean;
function Empty (Q Queue) return Boolean;
end Queues;
end Queues;
60
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 61. Using Several Queues
with Queues; use Queues;
procedure Client is
Q1 : Queue;
Q2 : Queue;
begin
Add (Q1, 123);
Add (Q2, 3);
Add (Q2, Get (Q1));
end Client;
61
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 62. One possible implementation ...
type Element is record
type Element is record
Val : Integer;
Val : Integer;
Next : access Element;
Next : access Element;
end record;
end record;
type Queue is record
type Queue is record
First : access Element;
First : access Element;
Last : access Element;
Last : access Element;
end record;
end record;
package Queues is
type Queue is …;
procedure Add (Q : Queue; Element : Integer);
function First (Q : Queue) return Integer;
function Get (Q : Queue) return Integer;
function Empty (Q : Queue) return Boolean;
end Queues;
62
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 63. Client code allowed to depend
on the implementation !
with Queues; use Queues;
procedure Client is
Q1 : Queue;
Q2 : Queue;
begin
Add (Q1, 123);
Add (Q2, 3);
OK
Q2.Last := null;
end Client;
63
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 64. Another implementation ...
type Table (Natural range <>) of Integer;
type Table (Natural range <>) of Integer;
type Queue (Max: Natural) is record
type Queue (Max: Natural) is record
Q : Table (0 .. Max);
Q : Table (0 .. Max);
First : Natural;
First : Natural;
Last : Natural;
Last : Natural;
Size : Natural;
Size : Natural;
package Queues is end record;
end record;
type Queue is …;
procedure Add (Q : Queue; Element : Integer);
function First (Q : Queue) return Integer;
function Get (Q : Queue) return Integer;
function Empty (Q : Queue) return Boolean;
end Queues;
64
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 65. … breaks client code !
with Queues; use Queues;
procedure Client is
Q1 : Queue;
Q2 : Queue;
begin
Add (Q1, 123);
Add (Q2, 3);
Compilation
error
Q2.Last := null;
end Client;
65
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 66. Even without changing
the implementation
there is a PROBLEM
with Queues; use Queues;
procedure Client is
Q1 : Queue;
Q2 : Queue;
begin
Add (Q1, 123); Q2: 3
3
Q2 is in an
Add (Q2, 3);
inconsistent First
state Last
Q2.Last := null;
null 66
end Client;
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 67. You need PRIVACY
• Exposing your data structures is risky
– Client code may manipulate the structures
directly without using your own services
– Client code is hard to change
– Creates strong coupling
67
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 68. • If there is a bug concerning a Queue, you
may have to look at 1000s of packages to
find the bug
• If you change the implementation you
may have to update 1000s of packages
68
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 69. Private types
package Queues is
package Queues is
type Queue is private;
type Queue is private;
procedure Add (Q ::Queue; Element ::Integer);
procedure Add (Q Queue; Element Integer);
function First (Q ::Queue) return Integer;
function First (Q Queue) return Integer;
function Get (Q ::Queue) return Integer;
function Get (Q Queue) return Integer;
function Empty (Q ::Queue) return Boolean;
function Empty (Q Queue) return Boolean;
private
private
type Queue is …;
type Queue is …;
end Queues;
end Queues;
69
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 70. In any implementation ...
package Queues is
type Queue is private;
procedure Add (Q : Queue; Element : Integer);
function First (Q : Queue) return Integer;
function Get (Q : Queue) return Integer;
function Empty (Q : Queue) return Boolean;
private
type Element is record
Val : Integer;
Next : access Element;
end record;
type Queue is record
First : access Element;
Last : access Element;
end record;
end Queues;
70
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 71. … private types are PRIVATE
with Queues; use Queues;
procedure Client is
Q1 : Queue;
Q2 : Queue;
begin
Add (Q1, 123);
Add (Q2, 3);
Compilation
error
Q2.Last := null;
end Client;
71
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 72. Advantages of private types
• Enforces the contract of a specification
• No client code can corrupt your data structures
• Can change implementation without changing
client code
72
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 73. Why is the private part in the spec ?
package Queues is
type Queue is private;
procedure Add (Q : Queue; Element : Integer);
function First (Q : Queue) return Integer;
function Get (Q : Queue) return Integer;
function Empty (Q : Queue) return Boolean;
private
type Element is record
Val : Integer;
Next : access Element;
end record;
type Queue is record
First : access Element;
Last : access Element;
end record;
end Queues;
73
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 74. … because we still need to
compile the clients code
with Queues; use Queues;
procedure Client is
Q1 : Queue;
begin
Add (Q1, 123);
end Client;
74
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 75. … but you can make a private type
quite private
package Queues is
type Queue is private;
procedure Add (Q : Queue; Element : Integer);
function First (Q : Queue) return Integer;
function Get (Q : Queue) return Integer;
function Empty (Q : Queue) return Boolean;
private
type Queue_Info;
type Queue is access Queue_Info;
end Queues;
75
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 76. package body Queues is
type Element is record
Val : Integer;
Next : access Element;
end record;
type Queue_Info is record
First : access Element;
Last : access Element;
end record;
...
end Queues;
76
http://libre.adacore.com © AdaCore under the GNU Free Documentation License 78. When creating a new system
you must identify its ...
• Data types
(what kind of data will be manipulated)
• Functionalities
(what kind of manipulations are allowed)
78
© AdaCore 79. Software System Organization
• Around its functionalities
(structured programming)
• around its data types
(object-oriented programming)
79
© AdaCore 80. Design an alert system
for an industrial plant
• log all the incoming alerts
• handle an alert (inform right people, etc.)
80
© AdaCore 81. alerts.ads
alerts.ads
with Calendar;
with Calendar;
package Alerts is
package Alerts is
type Alert is private;
type Alert is private;
procedure Handle (A ::in out Alert);
procedure Handle (A in out Alert);
procedure Log (A ::Alert);
(A Alert);
procedure Log
private
private
type Alert is record
type Alert is record
Time_Of_Arrival ::Calendar.Time;
Time_Of_Arrival Calendar.Time;
Cause ::String (1 .. 200);
String (1 .. 200);
Cause
end record;
end record;
end Alerts;
end Alerts;
81
© AdaCore 82. Having several kind of alerts
• Low
• Medium
– dispatch a technician
• High
– dispatch an engineer
– if problem not fixed within a delay ring an alarm
82
© AdaCore 83. with Calendar; use Calendar;
with Persons; use Persons;
package Alerts is
type Priority is (Low, Medium, High);
type Alert (P : Priority) is private;
procedure Handle (A : in out Alert);
procedure Log (A : Alert);
procedure Set_Alarm (A : in out Alert; Wait : Duration);
private
type Alert (P : Priority) is record ... end record;
end Alerts;
83
© AdaCore 84. private
type Alert (P : Priority) is record
Time_Of_Arrival : Time;
Cause : String (1 .. 100);
case P is
when Low =>
null;
when Medium =>
Technician : Person;
when High =>
Engineer : Person;
Ring_Alarm_At : Time;
end case;
end record; 84
end Alerts; © AdaCore 86. Variant Programming
procedure Handle (A : in out Alert) is
begin
A.Time_Of_Arrival := Calendar.Clock;
A.Cause := Get_Cause (A);
Log (A);
case A.P is
when Low =>
null;
when Medium =>
A.Technician := Assign_Technician;
when High =>
A.Engineer := Assign_Engineer;
Set_Alarm (A, Wait => 1800);
end case;
86
end Handle;
© AdaCore 87. Typical Routine for Alert Objects
(version 1)
procedure Some_Routine (A : in out Alert) is
begin
...
case A.P is
when Low =>
...
when Medium =>
...
when High =>
...
end case;
end Some_Routine;
87
© AdaCore 88. Typical Routine for Alert Objects
(version 2)
procedure Some_Routine (A : in out Alert) is
begin
...
if A.P = Low then
...
elsif A.P = Medium then
...
elsif A.P = High then
...
else
raise Internal_Error; -- defensive programming
end if;
end Some_Routine; 88
© AdaCore 89. Variant Programming is checked
procedure Set_Alarm (A : in out Alert; Wait : Duration) is
begin
A.Ring_Alarm_At := A.Time_Of_Arrival + Wait;
end Handle;
Constraint_Error
raised if
A.Priority /= High
89
© AdaCore 90. Handling an Alert
• You have a Get_Alert routine
• Connected to the sensors in the factory
• Collects the alerts
with Alerts; use Alerts;
with Alerts; use Alerts;
function Get_Alert return Alert; Returns an
function Get_Alert return Alert;
unconstrained Alert
the discriminant value
is not known
at compile time
90
© AdaCore 91. with Alerts; use Alerts;
with Alerts; use Alerts;
with Get_Alert;
with Get_Alert;
procedure Process_Alerts is
procedure Process_Alerts is
begin
begin
Probably a
loop -- infinite loop
loop -- infinite loop
blocking call
declare
declare
A ::Alert := Get_Alert;
A Alert := Get_Alert;
begin
begin
Handle (A); -- could have written Handle (Get_Alert);
Handle (A); -- could have written Handle (Get_Alert);
end;
end;
end loop;
end loop;
end Process_Alerts;
end Process_Alerts;
• The case inside Handle selects the right to
execute depending on the discriminant
• Handling code centralized in Handle 91
© AdaCore 93. To add functionality ...
function Last (Q : Queue) return Integer;
package Queues is
type Queue is private;
procedure Add (Q : Queue; Element : Integer);
function First (Q : Queue) return Integer;
function Get (Q : Queue) return Integer;
function Empty (Q : Queue) return Boolean;
function Last (Q : Queue) return Integer;
private
type Queue is …;
end Queues;
93
© AdaCore 94. But ...
• Every time you change a spec you must
recompile all its clients
• Every time you change a module you must
RETEST the whole module
94
© AdaCore 95. Solution: use child units
queues.ads
package Queues is
type Queue is private;
procedure Add (Q : Queue; Element : Integer);
function First (Q : Queue) return Integer;
function Get (Q : Queue) return Integer;
function Empty (Q : Queue) return Boolean;
private
type Queue is …;
Child end Queues;
subprogram
queues-last.ads
function Queues . Last (Q : Queue) return Integer;
95
© AdaCore 96. Child Units Rules
• The body or private part of a child unit can
see the private part of all of its parents
• The spec of a child unit does NOT
96
© AdaCore 97. Using a child unit
with Queues; use Queues;
with Queues.Last;
procedure Client is
Q : Queue;
X : Integer;
begin
Add (Q, 123);
Add (Q, 3);
X := Queues.Last (Q);
end Client;
97
© AdaCore 98. queues.ads
package Queues is
type Queue is private;
procedure Add (Q : Queue; Element : Integer);
function First (Q : Queue) return Integer;
function Get (Q : Queue) return Integer;
function Empty (Q : Queue) return Boolean;
private
type Queue is …;
end Queues;
Child
package
queues-new_functionality.ads
package Queues . New_Functionality is
function Last (Q : Queue) return Integer;
end Queues . New_Functionality
98
© AdaCore 99. with Queues; use Queues;
with Queues.New_Functionality;
procedure Client is
Q : Queue;
X : Integer;
begin
Add (Q, 123);
Add (Q, 3);
X := Queues.New_Functionality.Last (Q);
end Client;
99
© AdaCore 101. Adding NEW Functionality...
• Do not modify what is working already
– No need to retest what you already did
since you do not need to touch it
• Just add the functionality in a separate
child unit (subprogram or package)
101
© AdaCore 102. Adding new functionality
It’s simple: Use child subprograms/packages
simple
procedure Alerts.New_Functionality (A : in out Alert) is
begin
...
case A.P is
when Low =>
...
when Medium =>
...
when High =>
...
end case;
end Alerts.New_Functionality; 102
© AdaCore 103. Adding a NEW Data Variant...
• You have to modify the spec containing
your data type
• have to modify all the routines that
manipulate the data type to process new
variant
– Error Prone & labor intensive
– need to retest everything for regressions
103
© AdaCore 104. Adding a data type
Much more work: need to modify the spec...
work
package Alerts is
...
private
type Alert (P : Priority) is record
...
case P is
when Low => . . .
when Medium => . . .
when High => . . .
when Emergency => . . .
end case;
end record;
end Alerts; 104
© AdaCore 105. … as well as ALL the routines using Alert
procedure Some_Routine (A : in out Alert) is
begin
...
case A.P is
when Low =>
...
when Medium =>
...
when High =>
...
when Emergency =>
...
end case;
end Some_Routine; 105
© AdaCore 106. ... ALL the routines !
procedure Some_Routine (A : in out Alert) is
begin
...
if A.P = Low then
...
elsif A.P = Medium then
...
elsif A.P = High then
...
elsif A.P = Emergency then
...
else
raise Internal_Error; -- defensive programming
end if;
end Some_Routine;
106
© AdaCore 107. Important Remark
• For either type of change client routines such as
Process_Alerts do not need modifications
with Alerts; use Alerts;
with Alerts; use Alerts;
with Get_Alert;
with Get_Alert;
procedure Process_Alerts is
procedure Process_Alerts is
begin
begin
loop -- infinite loop
loop -- infinite loop
Handle (Get_Alert);
Handle (Get_Alert);
end loop;
end loop;
end Process_Alerts;
end Process_Alerts; 107
© AdaCore 109. • Data types are well known before starting the
design
• Adding new data variants will happen infrequently
• Will add lots of new functionalities on existing data
types over the life time of the system
109
© AdaCore 110. Data
type
changes
use Functionality-Oriented
110
Functionality changes
© AdaCore 111. • Object-Oriented Organization
inheritance
–
– polymorphism
– abstract types & subprograms
– modifying an OO system
– when to use OO organization
111
© AdaCore 112. When creating a new system
you must identify its ...
• Data types
(what kind of data will be manipulated)
• Functionalities
(what kind of manipulations are allowed)
112
© AdaCore 113. Software System Organization
• Around its functionalities
– (functionality-oriented / structured programming)
• around its data types
– (object-oriented programming)
113
© AdaCore 114. • Object-Oriented Organization
inheritance (simple)
–
– polymorphism
– abstract types & subprograms
– modifying an OO system
– when to use OO organization
114
© AdaCore 115. Often types have
some but not all
properties in common...
• Create completely different types
• Use variant programming to factor commonalties
• Use inheritance
115
© AdaCore 116. Alert
Alert
Time_Of_Arrival
Time_Of_Arrival
Cause
Cause
Handle ()
Handle ()
Log ()
Log ()
Medium_Alert High_Alert
Medium_Alert High_Alert
Low_Alert
Low_Alert
Time_Of_Arrival Time_Of_Arrival
Time_Of_Arrival Time_Of_Arrival
Time_Of_Arrival
Time_Of_Arrival
Cause
Cause
Cause Cause
Cause
Cause
Handle ()
Handle ()
Log () Handle ()
Log () Handle ()
Handle ()
Handle ()
Log ()
Log () Log ()
Log ()
inherited 116
© AdaCore 117. Alert
Alert
Time_Of_Arrival
Time_Of_Arrival
Cause
Cause
Handle ()
Handle ()
Log ()
Log ()
Medium_Alert High_Alert
Medium_Alert High_Alert
Low_Alert
Low_Alert
Time_Of_Arrival Time_Of_Arrival
Time_Of_Arrival Time_Of_Arrival
Time_Of_Arrival
Time_Of_Arrival
Cause
Cause
Cause Cause
Cause
Cause
Handle ()
Handle ()
Log ()
Log () Handle ()
Handle ()
Handle ()
Handle ()
Log ()
Log ()
Log ()
Log () 117
redefined © AdaCore 118. Alert
Alert
Time_Of_Arrival
Time_Of_Arrival
Cause
Cause
Handle ()
Handle ()
Log ()
Log ()
Medium_Alert High_Alert
Medium_Alert High_Alert
Low_Alert
Low_Alert
Time_Of_Arrival Time_Of_Arrival
Time_Of_Arrival Time_Of_Arrival
Time_Of_Arrival
Time_Of_Arrival
Cause
Cause
Cause Cause
Cause
Cause
Engineer
Technician Engineer
Technician
Handle () Ring_Alarm_At
Handle () Ring_Alarm_At
Log () Handle ()
Log () Handle ()
Handle ()
Handle ()
Log ()
Log () Log ()
Log ()
Set_Alarm
Set_Alarm 118
added © AdaCore 119. • Alert
• Low_Alert
• Medium_Alert
• High_Alert
Are 4 Different Types
119
© AdaCore 120. with …;
Alert is a tagged type
package Alerts is
type Alert is tagged record
Time_Of_Arrival : Calendar.Time;
Cause : String (1 .. 200);
end record;
procedure Handle (A : in out Alert);
procedure Log (A : Alert);
Primitive
... operations
end Alerts; (methods)
120
© AdaCore 121. package Alerts is
type Alert is tagged record
Time_Of_Arrival : Calendar.Time;
Cause : String (1 .. 200);
inherited
end record;
procedure Handle (A : in out Alert);
procedure Log (A : Alert);
type Low_Alert is new Alert with null record;
...
end Alerts; Derived type
inherits everything
by default
121
© AdaCore 122. package Alerts is
type Alert is tagged record
Time_Of_Arrival : Calendar.Time;
Cause : String (1 .. 200);
inherited
end record;
procedure Handle (A : in out Alert);
procedure Log (A : Alert);
type Medium_Alert is new Alert with record
Technician : Person;
added
end record;
procedure Handle (A : in out Medium_Alert); redefined
...
122
end Alerts;
© AdaCore 123. package Alerts is
type Alert is tagged record
Time_Of_Arrival : Calendar.Time;
Cause : String (1 .. 200);
end record; inherited
procedure Handle (A : in out Alert);
procedure Log (A : Alert);
type High_Alert is new Alert with record
Engineer : Person; added
Ring_Alarm_At : Calendar.Time;
end record;
procedure Set_Alarm (A : in out High_Alert; Wait : Duration);
procedure Handle (A : in out High_Alert);
redefined
end Alerts;
123
© AdaCore 124. Record Fields
• Are always inherited
• Can never be redefined or deleted
• You can add new attributes
124
© AdaCore 125. Inherited Fields
with Alerts; use Alerts;
procedure Client is
A : Alert;
A_L : Low_Alert;
A_M : Medium_Alert;
A_H : High_Alert;
begin
A . Time_Of_Arrival := …;
OK
A_L . Time_Of_Arrival := …;
A_M . Time_Of_Arrival := …;
A_H . Time_Of_Arrival := …;
end Client; 125
© AdaCore 126. Inherited Fields
with Alerts; use Alerts;
procedure Client is
A : Alert;
A_L : Low_Alert;
A_M : Medium_Alert;
Compilation
A_H : High_Alert;
Error
Engineer
begin
defined only
A . Engineer := …;
for
A_L . Engineer := …;
High_Alert
A_M . Engineer := …;
A_H . Engineer := …;
end Client; 126
© AdaCore 127. Operations (methods)
• Inherited operation has exactly the same
code as the original
• Redefined (or overridden) operations have
new code (can never delete an operation)
• Added operations are new operations
127
© AdaCore 128. Inherited &
with Alerts; use Alerts;
with Alerts; use Alerts;
procedure Client is
procedure Client is
Redefined
A ::Alert;
Alert;
A
Operations
A_L ::Low_Alert;
A_L Low_Alert;
A_M ::Medium_Alert;
A_M Medium_Alert;
A_H ::High_Alert;
A_H High_Alert;
begin
begin type Alert is tagged record ... end record;
type Alert is tagged record ... end record;
Handle (A); procedure Handle (A ::in out Alert);
procedure Handle (A in out Alert);
Handle (A);
type Low_Alert is new Alert with ... end record;
type Low_Alert is new Alert with ... end record;
Handle (A_L);
Handle (A_L);
type Medium_Alert is new Alert with ... end record;
type Medium_Alert is new Alert with ... end record;
Handle (A_M); procedure Handle (A ::in out Medium_Alert);
procedure Handle (A in out Medium_Alert);
Handle (A_M);
type High_Alert is new Alert with ... end record;
type High_Alert is new Alert with ... end record;
A_H.Handle; Ada 2005
A_H.Handle; ‐‐‐‐Ada 2005
procedure Handle (A ::in out High_Alert);
procedure Handle (A in out High_Alert); 128
end Client;
end Client; © AdaCore 129. Added Operations
with Alerts; use Alerts;
procedure Client is
A : Alert;
A_L : Low_Alert;
A_M : Medium_Alert;
Compilation
A_H : High_Alert;
Error
begin Set_Alarm
Set_Alarm (A, 1800); defined only
Set_Alarm (A_L, 1800); for
Set_Alarm (A_M, 1800); High_Alert
A_H.Set_Alarm (1800);
end Client; 129
© AdaCore 130. Variant Programming
procedure Handle (A : in out Alert) is
begin
A.Time_Of_Arrival := Calendar.Clock;
A.Cause := Get_Cause (A);
Log (A);
case A.P is
when Low =>
null;
when Medium =>
A.Technician := Assign_Technician;
when High =>
A.Engineer := Assign_Engineer;
Set_Alarm (A, Wait => 1800);
end case;
130
end Handle;
© AdaCore 131. Programming with Inheritance
procedure Handle (…) is
procedure Handle (…) is
begin
begin
procedure Handle (A : in out Alert) is A.Time_Of_Arrival := …;
A.Time_Of_Arrival := …;
A.Cause := …;
A.Cause := …;
begin Log (A);
Log (A);
A.Time_Of_Arrival := Calendar.Clock; case A.P is
case A.P is
A.Cause := Get_Cause (A); when Low => =>
when Low
null;
null;
Log (A); when Medium =>
when Medium =>
A.Technician := …;
end Handle; A.Technician := …;
when High =>
when High =>
A.Engineer := …;
A.Engineer := …;
Set_Alarm (A, ...);
Set_Alarm (A, ...);
procedure Handle (A : in out Medium_Alert) is end case;
end case;
end Handle;
begin end Handle;
Handle (Alert (A)); -- First handle as plain Alert
A.Technician := Assign_Technician;
end Handle;
131
© AdaCore 132. procedure Handle (…) is
procedure Handle (…) is
begin
begin
procedure Handle (A : in out Alert) is A.Time_Of_Arrival := …;
A.Time_Of_Arrival := …;
A.Cause := …;
A.Cause := …;
begin Log (A);
Log (A);
A.Time_Of_Arrival := Calendar.Clock; case A.P is
case A.P is
A.Cause := Get_Cause (A); when Low => =>
when Low
null;
null;
Log (A); when Medium =>
when Medium =>
A.Technician := …;
end Handle; A.Technician := …;
when High =>
when High =>
A.Engineer := …;
A.Engineer := …;
Set_Alarm (A, ...);
Set_Alarm (A, ...);
procedure Handle (A : in out High_Alert) is end case;
end case;
end Handle;
begin end Handle;
Handle (Alert (A)); -- First handle as plain Alert
A.Engineer := Assign_Engineer;
Set_Alarm (A, Wait => 1800);
132
end Handle; © AdaCore 133. Centralized vs Distributed Code
• The code which is centralized in the same
routine in the functionality-oriented version
• is now distributed across 3 different routines
in the object-oriented version
133
© AdaCore 134. • Object-Oriented Organization
– inheritance (simple)
• encapsulation & inheritance
– polymorphism
– abstract types & subprograms
– modifying an OO system
– when to use OO organization
134
© AdaCore 135. with …;
package Alerts is
type Alert is tagged private;
procedure Handle (A : in out Alert);
procedure Log (A : Alert);
private
type Alert is tagged record
Time_Of_Arrival : Calendar.Time;
Cause : String (1 .. 200);
end record;
end Alerts;
135
© AdaCore 136. Child Package
with Alerts; use Alerts;
with Alerts; use Alerts;
with …;
with …;
package Alerts.Medium is
package Alerts.Medium is
type Medium_Alert is new Alert with private;
type Medium_Alert is new Alert with private;
procedure Handle (A :: in out Medium_Alert);
procedure Handle (A in out Medium_Alert);
private
private
type Medium_Alert is new Alert with record
type Medium_Alert is new Alert with record
Technician ::Person;
Technician Person;
end record;
end record;
end Alerts.Medium;
end Alerts.Medium;
136
© AdaCore 137. Important Remark
• Adding a new type derived from Alert
– No need to modify what is working already
– No need to retest what you did already
• Just add the data type in a separate
package (regular or child package)
137
© AdaCore 138. • Object-Oriented Organization
– inheritance (simple)
polymorphism
–
– abstract types & subprograms
– modifying an OO system
– when to use OO organization
138
© AdaCore 139. Handling an Alert
• You have a Get_Alert routine
• Connected to the sensors in the factory
• Collects the alerts
with Alerts; use Alerts;
with Alerts; use Alerts;
function Get_Alert return ???;
function Get_Alert return ???;
139
© AdaCore 140. Objective
• Be able to mimic the code used in the variant
programming case
with Alerts; use Alerts;
with Alerts; use Alerts;
with Get_Alert;
with Get_Alert;
procedure Process_Alerts is
procedure Process_Alerts is
begin
begin
loop -- infinite loop
loop -- infinite loop
Handle (Get_Alert);
Handle (Get_Alert);
end loop;
end loop;
end Process_Alerts;
end Process_Alerts;
140
© AdaCore 141. Medium_Alert High_Alert
Low_Alert
Handle()
Handle() Handle()
Log()
Log() Log()
Private Private Set_Alarm()
stuff stuff
Private
stuff
The exact same interface because
they all derive from type Alert
141
© AdaCore 142. Inheritance & Interfaces
• All type T derived from Alert must implement
or inherit:
– procedure Handle (A : in out T);
– procedure Log (A : T);
• Cannot remove inherited operations, you can
only redefine their implementation
142
© AdaCore 143. Idea: select the operation
dynamically
Obj ::some unknown type derived from Alert;
Obj some unknown type derived from Alert;
Handle (Obj);
Handle (Obj);
Handle() Handle()
? ?
143
© AdaCore 145. Inheritance Theorem
For all type D
For all type D
derived from
derived from
T
T
⊆
set of operations
set of operations set of operations
set of operations
implemented
implemented implemented
implemented
for objects of type
for objects of type for objects of type
for objects of type
D
T D
T
145
© AdaCore 146. • Object-Oriented Organization
– inheritance (simple)
– polymorphism
• dynamic dispatching
• Using access parameters
• redispatching
– abstract types & subprograms
– modifying an OO system
– when to use OO organization
146
© AdaCore 147. Handling an Alert
• You have a Get_Alert routine
• Connected to the sensors in the factory
• Collects the alerts
with Alerts; use Alerts;
with Alerts; use Alerts;
function Get_Alert return Alert’Class;
function Get_Alert return Alert’Class;
147
© AdaCore 148. Dynamic Dispatching
with Alerts; use Alerts;
with Alerts; use Alerts;
with Get_Alert;
with Get_Alert;
procedure Process_Alerts is
procedure Process_Alerts is
begin
begin
loop -- infinite loop
loop -- infinite loop
declare
declare
A ::Alert’Class := Get_Alert;
A Alert’Class := Get_Alert;
begin
begin
Handle (A); -- could have written Handle (Get_Alert);
Handle (A); -- could have written Handle (Get_Alert);
end;
end;
end loop;
end loop;
end Process_Alerts;
end Process_Alerts;
Dispatching Call 148
© AdaCore 149. Where is the magic ?
A ::Alert’Class := Get_Alert;
A Alert’Class := Get_Alert;
Handle (A);
Handle (A);
Dynamic
Binding
? ?
Handle() Handle()
Low_Alert
High_Alert
149
© AdaCore 150. Tables of pointers to primitive operations
1 1
Handle Handle Handle
1
2 2 2 Log
3 Set_Alarm
’Tag is a pointer
’Tag ’Tag ’Tag
Time_Of_Arrival Time_Of_Arrival Time_Of_Arrival
Cause Cause Cause
Engineer Technician
Ring_Alarm_At
High_Alert Medium_Alert Low_Alert
150
© AdaCore 151. How do you know if call
Op (V, …)
is dispatching ?
- Type of V is T’Class for some tagged type T
- Op is a primitive operation of T
type T is … end record;
procedure Op (P : T; …) (or function)
procedure Op (P : in out T; …)
procedure Op (P : access T; …) (or function)
151
© AdaCore 152. Static vs Dynamic Binding
STATIC BINDING = call known at compile time
DYNAMIC BINDING = call known only at run time
152
© AdaCore 153. AL ::Low_Alert;
AL Low_Alert;
Handle (AL);
Handle (AL);
Static
A ::Alert’Class := Get_Alert;
A Alert’Class := Get_Alert;
Binding
Handle (A);
Handle (A);
Dynamic
Binding
A ::High_Alert’Class := …;
A High_Alert’Class := …;
Handle (A);
Handle (A);
Dynamic
Binding 153
© AdaCore 154. • Object-Oriented Organization
– inheritance (simple)
– polymorphism
• dynamic dispatching
• redispatching
– abstract types & subprograms
– modifying an OO system
– when to use OO organization
154
© AdaCore 155. procedure Handle (A : in out Alert) is
begin
A.Time_Of_Arrival := Calendar.Clock;
A.Cause := Get_Cause (A);
Log (A);
Static always calls: procedure Log (A : Alert);
end Handle;
Binding
procedure Handle (A : in out Medium_Alert) is
begin
Handle (Alert (A)); -- First handle as plain Alert
A.Technician := Assign_Technician;
end Handle;
155
© AdaCore 156. What if …
… we override Log
package Alerts is
type Alert is tagged private;
procedure Handle (A : in out Alert);
procedure Log (A : Alert);
type Medium_Alert is new Alert with private;
procedure Handle (A : in out Medium_Alert);
procedure Log (A : Medium_Alert);
private
….
end Alerts;
156
© AdaCore 157. procedure Handle (A : in out Alert) is
begin
A.Time_Of_Arrival := Calendar.Clock;
A.Cause := Get_Cause (A);
Log (Alert’Class (A));
Dynamic Binding
end Handle;
Redispatching
procedure Handle (A : in out Medium_Alert) is
begin
Handle (Alert (A)); -- First handle as plain Alert
A.Technician := Assign_Technician;
end Handle;
157
© AdaCore 158. Dispatching Philosophy
• Ada:
– All primitive operations are potentially dispatching
– Decide when to have a dispatching call
• C++:
– Decide which methods are dispatching (virtual methods)
– All calls to these functions are dispatching by default
• Java:
– All primitive operations are dispatching
– all calls are dispatching 158
© AdaCore 159. • Object-Oriented Organization
– inheritance (simple)
– polymorphism
abstract types & subprograms
–
– modifying an OO system
– when to use OO organization
159
© AdaCore 160. In the Alert example ...
• One could create objects of type Alert rather than
– Low_Alert, Medium_Alert, High_Alert
• Undesirable if plain Alert has no significance but
is used only to transmit:
– Fields: Time_Of_Arrival & Cause
– Methods: Handle & Log
160
© AdaCore 161. Make Alert an abstract type
package Alerts is
type Alert is abstract tagged private;
procedure Handle (A : in out Alert);
procedure Log (A : Alert);
private
type Alert is tagged record
Time_Of_Arrival : Calendar.Time;
Cause : String (1 .. 200);
end record;
end Alerts;
161
© AdaCore 162. Cannot create objects of an
abstract type
type Alert is abstract tagged private;
A : Alert; Compilation error
Alert is an
abstract type
162
© AdaCore 163. Can have abstract operations
package Alerts is
type Alert is abstract tagged private;
procedure Handle (A : in out Alert);
procedure Log (A : Alert) is abstract;
private
type Alert is tagged record
Time_Of_Arrival : Calendar.Time;
Cause : String (1 .. 200);
end record;
end Alerts;
163
© AdaCore 164. • Object-Oriented Organization
– inheritance (simple)
– polymorphism
– abstract types & subprograms
modifying an OO system
–
– when to use OO organization
164
© AdaCore 165. Adding a NEW Type...
• Do not modify what is working already
– No need to retest what you already did
since you do not need to touch it
• Just add the data type in a separate
package (regular or child package)
165
© AdaCore 166. package Alerts is
package Alerts is
type Alert is abstract tagged private;
type Alert is abstract tagged private;
procedure Handle (A :: in out Alert);
procedure Handle (A in out Alert);
procedure Log (A ::Alert);
(A Alert);
procedure Log
private
private
......
end Alerts;
end Alerts;
with Alerts; use Alerts;
with Alerts; use Alerts;
package Alerts.Medium is
package Alerts.Medium is
type Medium_Alert is new Alert with private;
type Medium_Alert is new Alert with private;
procedure Handle (A :: in out Alert);
procedure Handle (A in out Alert);
procedure Log (A ::Alert);
(A Alert);
procedure Log
private
private
......
end Alerts.Medium;
end Alerts.Medium; 166
© AdaCore 167. Adding NEW Functionality...
• Have to modify the spec containing tagged
type T to which we add the functionality
• Have to modify all the packages containing
types derived from T to implement the new
functionality
– Error Prone & labor intensive
– need to retest everything for regressions
167
© AdaCore 168. Example
• Suppose you want to add a new functionality
• that behaves DIFFERENTLY for all alert types
168
© AdaCore 169. package Alerts is
package Alerts is
type Alert is abstract tagged private;
type Alert is abstract tagged private;
procedure New_Functionality (A ::Alert);
procedure New_Functionality (A Alert);
......
with Alerts; use Alerts;
with Alerts; use Alerts;
package Alerts.Medium is
package Alerts.Medium is
type Medium_Alert is new Alert with private;
type Medium_Alert is new Alert with private;
procedure New_Functionality (A ::Medium_Alert);
procedure New_Functionality (A Medium_Alert);
......
with Alerts; use Alerts;
with Alerts; use Alerts;
package Alerts.High is
package Alerts.High is
type High_Alert is new Alert with private;
type High_Alert is new Alert with private;
procedure New_Functionality (A ::High_Alert);
procedure New_Functionality (A High_Alert);
...... 169
© AdaCore 170. • Object-Oriented Organization
– inheritance (simple)
– polymorphism
– abstract types & subprograms
– modifying an OO system
when to use OO organization
–
170
© AdaCore 171. • System Functionalities are well understood before
starting the design
• Adding new functionality will happen infrequently
• Will add lots of new data types with the same
functionality over the life time of the system
171
© AdaCore 172. New functionalities can be
factored in few tagged types
Data
type
changes
??
Use
Object
Use
Oriented
Object
Oriented
use Functionality-Oriented
172
Functionality changes
© AdaCore