1 modularity shani bard based on a lecture by john mitchell reading: chapter 9
Post on 19-Dec-2015
213 views
TRANSCRIPT
2
Why Modularity?
effective design - each module can be designed and tested independently
easy to understand – subprograms are smaller and easier to understand then the original big program
3
Modularity goal
divide and conquer
• allow one module to be written with little knowledge of the code in another module
• allow a module to be redesigned and reimplemented without modifying other parts of the system
Modern programming languages and software development environments support modularity in different ways
4
In this chapter
ways that programs can be divided into meaningful parts
the way that programming languages can be designed to support these divisions
• In Chapters 10–13 we explore object-oriented languages in detail, in this chapter we are concerned with modularity mechanisms that do not involve objects
5
Topics
structured programming support for abstraction Modules
• to describe module systems and generic programming we will use:
– standard ML module system– C++ Standard Template Library (STL)
6
Stepwise Refinement
Wirth, 1971 • “… program ... gradually developed in a sequence
of refinement steps”• In each step, instructions … are decomposed into
more detailed instructions.
Historical reading on web (CS242 Reading page)• N. Wirth, Program development by stepwise
refinement, Communications of the ACM, 1971• D. Parnas, On the criteria to be used in
decomposing systems into modules, Comm ACM, 1972
• Both ACM Classics of the Month
7
Dijkstra’s Example (1969)
beginprint first 1000 primes
end beginvariable table pfill table p with first 1000 primesprint table p
endbegin
int array p[1:1000]make for k from 1 to 1000
p[k] equal to k-th primeprint p[k] for k from 1 to 1000
end
9
Data Refinement
Wirth, 1971 again:• As tasks are refined, so the data may have to
be refined, decomposed, or structured, and it is natural to refine program and data specifications in parallel
10
Example
For level 2, represent account balance by integer variable
For level 3, need to maintain list of past transactions
Bank Transactions
Deposit Withdraw Print Statement
Print transaction history
11
Modularity: Basic Concepts
Component• Meaningful program unit
– Function, data structure, module, …
Interface• Types and operations defined within a component
that are visible outside the component
Specification• Intended behavior of component, expressed as
property observable through interface
Implementation• Data structures and functions inside component
12
Example: Function Component
Component• Function to compute square root
Interface• float sqroot (float x)
Specification• If x>1, then sqrt(x)*sqrt(x) x.
Implementationfloat sqroot (float x){ float y = x/2; float step=x/4; int i; for (i=0; i<20; i++){if ((y*y)<x) y=y+step; else y=y-step; step = step/2;} return y;}
13
Example: Data Type - Heap sort using library data structure
Component• Priority queue: data structure that returns
elements in order of decreasing priority
Interface Priority queue: structure with three operations• Type pq• Operations empty : pq insert : elt * pq pq deletemax : pq elt * pq
14
Example: Data Type
Specification• Each priority queue has a multiset of elements.
There must be an ordering < on the elements that may be placed in a priority queue. (For integer priority queues, we may use the ordinary < ordering on integers)
• An empty priority queue has no elements• Insert add to set of stored elements• Deletemax returns max elt and pq of
remaining elts These specifications do not impose any
restrictions on the implementation
15
Implementation - top-down design
Algorithm using priority queue (heap sort) First step: the problem - sorting an array
function sortbegin
sort an array of integers
end
Second step: refine the statement sort an array of integers into subtasks function sort (n : int, A : array [1..n] of int) begin
place each element of array A in a priority queueremove elements in decreasing order and place in array A
end
16
Implementation - top-down design
Final step: final refinement
function sort (n : int, A : array [1..n] of int)begin
priority queue s;s := empty;for i := 1 to n do s := insert(A[i], s);for i := n downto 1 do (A[i],s) := deletemax(s);
end
This gives us an O(n log n) sorting algorithm
17
support for abstraction
abstraction mechanism • emphasizes the general properties of some code
and hides details• generally separats a program into parts that
contain details and parts where these details are hidden
– client: the part of a program that uses program component– implementation: the part of a program that defines a
program component
• The interaction between the client and implementation of an abstraction is usually restricted to a specific interface
18
support for abstraction
Procedural Abstraction• Client: a program making a function call• Implementation: the encapsulated function
body
Advantages:• well-defined interface• local variables has no effect on other parts of
the program• enclosing code inside a function makes the
code generic and reusable
19
Data Abstraction
hiding information about the way that data are represented
Goals:• Identifying the interface of the data structure• information hiding by separating
implementation decisions from parts of the program that use the data structure
• Allowing the data structure to be used in many different ways by many different programs
20
Abstract Data Types
Prominent language development of 1970’s
Main ideas:• Separate interface from implementation
– Example: • Sets have empty, insert, union, is_member?, …• Sets implemented as … linked list …
• Use type checking to enforce separation– Client program only has access to operations in
interface– Implementation encapsulated inside ADT construct
21
ML - abstract data type
An ML declaration of an abstract data type of complex numbers may be written as follows:abstype cmplx = C of real * real with
fun cmplx(x,y: real) = C(x,y)fun x coord(C(x,y)) = xfun y coord(C(x,y)) = yfun add(C(x1, y1), C(x2, y2)) = C(x1+x2,
y1+y2)end
ML returns: type cmplx val cmplx = fn : real * real → cmplx val x coord = fn : cmplx → real val y coord = fn : cmplx → real val add = fn : cmplx * cmplx → cmplx
22
Representation Independence
a type has a property called representation independent when it has built-in operations
In a type-safe programming language with abstract data types we can:• declare variables of an abstract type• define operations on any abstract type• use type-checking rules to guarantee that only
these specified operations can be applied to values of the abstract type
23
Partition Operations
it is possible to partition the operations on the type into three groups:
• Constructors: operations that build elements of the type• Operators: operations that map elements of the type
that are definable only with constructors to other elements of the type that are definable with only constructors
• Observers: operations that return a result of some other type
24
Partition Operations - Example
empty : setinsert : int * set → setunion : set * set → setisMember: int * set → bool
the operations can be partitioned as follows:• Constructors: empty and insert• Operator: union• Observer: isMember
we may prove properties of all elements of an abstract type by induction on the number of uses of constructors necessary to produce a given element
25
Modules
General construct for information hiding Two parts
• Interface: A set of names and their types
• Implementation: Declaration for every entry in the interface
Additional declarations that are hidden
Examples:• Modula modules, Ada packages, ML
structures, ...
26
Modules and Data Abstraction
module Setinterface
type set val empty : set
fun insert : elt * set -> set fun union : set * set -> set fun isMember : elt * set ->
boolimplementation
type set = elt list val empty = nil fun insert(x, elts) = ... fun union(…) = ...
...end Set
Can define ADT• Private type• Public operations
More general• Several related
types and operations
Some languages• Separate interface
and implementation
• One interface can have multiple implementations
27
Modula
developed by Pascal designer Niklaus Wirth in
the late 1970s main innovation of Modula over Pascal is a module system Interface is called definition module Implementation is called implementation
module
28
Modula – transparent Module
definition module Fractions;type fraction = ARRAY [1 .. 2] OF INTEGER;procedure add (x, y : fraction) : fraction;procedure mul (x, y : fraction) : fraction;
end Fractions.implementation module Fractions;
procedure Add (x, y : Fraction) : Fraction;VAR temp : Fraction;BEGIN
temp [1] := x [1] * y [2] + x [2] * y [1];temp [2] := x [2] * y [2]; RETURN temp;
END Add;procedure Mul (x, y : Fraction) : Fraction;...END Mul;
end Fractions. In this example, a complete type declaration is included in
the interface. As a result, the client code can see that a fraction is an array of integers – not a good use of the Module abilities
29
Modula – opaque Module
definition module Stack moduletype stack (* an abstract type *)procedure create stack ( ) : stackprocedure push( x:integer, var s:stack ) :
stack...
end Stack moduleimplementation module Stack module
type stack =array [1..100] of integer...
end Stack module
30
ADA
designed in the late 1970s and early 1980s as the result of an initiative by the U.S. Department of Defense (DoD)
The DoD wanted to standardize its software around a common language that would provide program structuring capabilities and specific features related to real time programming
By some measures, Ada has been a successful language:• Many Ada programs have been written and used• Some Ada design issues led to research studies and improvements in
the state of the art of programming language design
adoption of the language outside of suppliers of the U.S. government has been limited• Lack of easily available implementations• companies who produced Ada compilers expected to sell them for high
prices to military contractors
31
ADA packages
Interface is called package specification Implementation is called package bodypackage FractionPkg is
type fraction is array ... of integer;procedure Add ...
end FractionPkg;package body FractionPkg is
procedure Add ...end FractionPkg;
32
ML Modules
designed in the mid-1980s as part of a redesign
and standardization effort for the ML programming language three main parts
• structures• signatures• functors
33
ML structure
a module, which is a collection of type, value, and structure declarations
structure S =struct
type t = intval x : t = 3
end
s.x = 3
s.t = int
34
ML signature
module interface signatures behave as a formof “type” for a structure a module may have more than one signature a signature may have more than one associated module If a structure satisfies the description given
in a signature, the structure “matches” the signature
35
ML signature
signature SIG =sig
type tval x : t
end
Because the structure S previously introduced satisfies these conditions, it is said to match the signature SIG
The structure S also matches the following signature SIG’: signature SIG’ =
sigtype tval x : int
end
SIG AND SIG’ are different, because there are structures that
satisfy only one of them and not the other
36
ML Functor
Functors are functions from structures to structures. Functors are used to define generic modules.
Because ML does not support higher-order functors (functors taking functors as arguments or yielding functors as results), there is no need for functor signatures.
functor F ( S : SIG ) : SIG =struct
type t = S.t * S.tvalx : t= (S.x,S.x)
end
37
Generic Abstractions
Parameterize modules by types, other modules
Create general implementations • Can be instantiated in many ways
Language examples:• Ada generic packages, C++ templates, ML
functors, …• ML geometry modules in book• C++ Standard Template Library (STL) provides
extensive examples
38
C++ Templates
Type parameterization mechanism• template<class T> … indicates type parameter T• C++ has class templates and function templates
Instantiation at link time• Separate copy of template generated for each
type• Why code duplication?
– Size of local variables in activation record– Link to operations on parameter type
39
Example (discussed in earlier lecture)
Monomorphic swap functionvoid swap(int& x, int& y){ int tmp = x; x = y; y = tmp;}
Polymorphic function templatetemplate<class T>void swap(T& x, T& y){ T tmp = x; x = y; y = tmp;}
Call like ordinary functionfloat a, b; … ; swap(a,b); …
40
Standard Template Library for C++
Many generic abstractions• Polymorphic abstract types and operations
Useful for many purposes• Excellent example of generic programming
Efficient running time (but not always space) Written in C++
• Uses template mechanism and overloading• Does not rely on objects – No virtual functions
Architect: Alex Stepanov
41
Main entities in STL
Container: Collection of typed objects• Examples: array, list, associative dictionary, ...
Iterator: Generalization of pointer or address Algorithm Adapter: Convert from one form to another
• Example: produce iterator from updatable container
Function object: Form of closure (“by hand”) Allocator: encapsulation of a memory pool
• Example: GC memory, ref count memory, ...
42
Example of STL approach
#include <string>#include <list>int main (void) {
list<string> citieslist;}
operations for putting elements on the front orback of a list:
citieslist.push back(“Haifa”);citieslist.push back(“Be’er Sheva”);citieslist.push front(“London”);citieslist.push front(“Liverpool”);
43
Example of STL approach
We now have a list with four strings in our list. We can print the words in our list by using an iterator.
declaration of an iterator for lists of strings:
list<string>::iterator citieslistIterator;
an STL iterator is like a pointer – an iterator points to an element of a container, and dereferencing a nonnull iterator produces an object from the container
for (citieslistIterator =citieslist.begin(); citieslistIterator!= citieslist.end(); ++citieslistIterator) {
// dereference the iterator to get the list elementcout << * citieslistIterator << endl;
}
44
Example of STL approach
Function to merge two sorted lists• merge : range(s) range(t) comparison(u) range(u) This is conceptually right, but not STL syntax.
Basic concepts used• range(s) - ordered “list” of elements of type s,
given by pointers to first and last elements• comparison(u) - boolean-valued function on
type u• subtyping - s and t must be subtypes of u
45
How merge appears in STL
Ranges represented by iterators• iterator is generalization of pointer• supports ++ (move to next element)
Comparison operator is object of class Compare
Polymorphism expressed using templatetemplate < class InputIterator1, class InputIterator2,
class OutputIterator, class Compare >
OutputIterator merge(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, InputIterator1 last2,
OutputIterator result, Compare comp)
46
Comparing STL with other libraries
C:
qsort( (void*)v, N, sizeof(v[0]), compare_int );
C++, using raw C arrays:
int v[N];
sort( v, v+N );
C++, using a vector class:
vector v(N);
sort( v.begin(), v.end() );
47
Efficiency of STL
Running time for sortN = 50000 N = 500000
C 1.4215 18.166C++ (raw arrays) 0.2895 3.844C++ (vector class) 0.2735 3.802
Main point• Generic abstractions can be convenient and efficient
!• But watch out for code size if using C++ templates…
48
Chapter Summary
In this chapter, we studied some of the ways that programs can be divided into meaningful parts and the way that programming languages support these divisions
main topics:• structured programming• support for abstraction• Modules
Two examples were used to investigate module systems and generic programming• standard ML module system• C++ Standard Template Library (STL)
Two important concepts in modular program development are interfaces and specifications