Title: Explicit State
1Explicit State
- Seif Haridi
- Peter Van Roy
2Explicit State I
The box O
- The box O can remember information between
independent invocations, it has a memory - The basic elements of explicit state
- Index datatypes
- Basic techniques and ideas of using state in
program design
An Interface that hides the state
- State as a group of memory cells
Group of functions and procedures that
operate on the state
3Explicit State II
The box O
- What is the difference between implicit state and
explicit state - What is the difference between state in general
and encapsulated state - Component based programming and object-oriented
programming - Data abstractions using encapsulated state
An Interface that hides the state
- State as a group of memory cells
Group of functions and procedures that
operate on the state
4What is state?
- State is a sequence of values in time that
contains the intermediate results of a desired
computation - Declarative programs can also have state
according to this definition - Consider the following program
fun Sum Xs A case Xs of XXr then Sum
Xr AX nil then A end end Show
Sum 1 2 3 4 0
5What is implicit state?
- The two arguments Xs and A
- represent an implicit state
- Xs A
- 1 2 3 4 0
- 2 3 4 1
- 3 4 3
- 4 6
- nil 10
fun Sum Xs A case Xs of XXr then Sum
Xr AX nil then A end end Show
Sum 1 2 3 4 0
6What is explicit state Example?
An unbound variable
X
C
A cell C is created with initial value 5 X is
bound to C
5
X
C
The cell C, which X is bound to, is assigned
the value 6
6
X
7What is explicit state Example?
An unbound variable
X
- The cell is a value container with a unique
identity - X is really bound to the identity of the cell
- When the cell is assigned, X does not
- change
C
A cell C is created with initialvalue 5 X is
bound to C
5
X
C
The cell C, which X is bound to, is assigned
the value 6
6
X
8What is explicit state?
- X NewCell I
- Creates a cell with initial value I
- Binds X to the identity of the cell
- Example X NewCell 0
- XJ
- Assumes X is bound to a cell C (otherwise
exception) - Changes the content of C to become J
- Y _at_X
- Assumes X is bound to a cell C (otherwise
exception) - Binds Y to the value contained in C
9Examples
- X NewCell 0
- X5
- Y X
- Y10
- _at_X 10 returns true
- X Y returns true
0
X
5
X
Y
10
X
Y
10Examples
- X NewCell 10Y NewCell 10
- X Y returns false
- Because X and Y refer to different cells, with
different identities - _at_X _at_Y returns true
10
X
10
Y
11Examples
0
X
- X NewCell 0
- X5
- Y X
- Y10
- _at_X 10returns true
5
X
Y
10
X
Y
12The model extended with cells
Semantic stack (Thread 1)
Semantic stack (Thread n)
.....
w f(x) z person(ay) y ?1 u ?2 x
?1 w ?2 x .... ....
single assignment store
mutable store
13The stateful model
?s? skip
empty statement ?s1? ?s2?
statement sequence
...
thread ?s1? end thread
creation NewCell ?x? ?c? cell
creation Exchange ?c? ?x? ?y? cell
exchange
Exchange bind ?x? to the old content of ?c? and
set the content of the cell ?c? to ?y?
14The stateful model
NewCell ?x? ?c? cell creation Exchan
ge ?c? ?x? ?y? cell exchange
Exchange bind ?x? to the old content of ?c? and
set the content of the cell ?c? to ?y?
proc Assign C X Exchange C _ X end fun
Access C X inExchange C X XX end The _at_ and
syntaxes are syntactic sugar for Assign and
Access
15Do we need explicit state?
- Up to now the computation model we introduced in
the previous lectures did not have any notion of
explicit state - And important question is do we need explicit
state? - There is a number of reasons for introducing
state. We discuss them some of them here
16Programs that changetheir behavior over time
- Declarative program all information is in the
arguments - Stateful program new information can be put
inside a running program
Program
Program
17Modular programs
- A system (program) is modular if changes
(updates) in the program are confined to the
components where the functionality are changed - Here is an example where introduction of explicit
state in a well confined way leads to program
modularity compared to programs that are written
using only the declarative model (where evey
component is a function)
18Encapsulated state I
fun MF fun F ... ?Definition of
F? endfun G ... ?Definition of
G? end in export(fF gG) end M MF
- Assume we have three persons, P, U1, and U2
- P is a programmer who developed a component M
that provides two functions F and G - U1 and U2 are system builders that use the
component M
19Encapsulated state I
- Assume we have three persons, P, U1, and U2
- P is a programmer who developed a component M
that provides two functions F and G - U1 and U2 are system builders that use the
component M
functor MF export fF gG define fun F ...
?Definition of F? end fun G ...
?Definition of G? end end
20Encapsulated state II
- User U2 has a demanding application
- He wants to extend the module M to enable him to
monitor how many times the function F is invoked
in his application - He goes to P, and asks him to do so without
changing the interface to M
fun M fun F ... ?Definition of
F? endfun G ... ?Definition of
G? end in export(fF gG) end
21Encapsulated state III
- This cannot be done in the declarative model
because F cannot remember its previous
invocations - The only way is to change the interface to F by
adding two extra arguments FIn and FOut - fun F ... FIn ?FOut FOut FIn1 ... end
- The rest of the program always remembers the
previous number of invocations (FIn), and FOut
returns the new number of invocations - But this changes the interface!
22Encapsulated state III
fun MF X NewCell 0 fun F ...
X_at_X1 ?Definition of F? endfun G ...
?Definition of G? end fun Count _at_X end in
export(fF gG cCount) end M MF
- A cell is created when MF is called
- Due to lexical scoping the cell is only visible
to the created version of F and Count - The M.f did not change
- New function M.c is available
- X is hidden only visible inside M (encapsulated
state)
23Relationship between the declarative model and
the stateful model
- Declarative programming guarantees by
construction that each procedure computes a
function - This means each component (and subcomponent) is a
function - It is possible to use encapsulated state (cells)
so that a component is declarative from outside,
and stateful from the inside - Considered as a black-box the program procedure
is still a function
24Programs with accumulators
- local
- fun Sum1 Xs A
- case Xs
- of XXr then Sum1 Xr AX
- nil then A
- end end
- in fun Sum Xs Sum1 Xs 0 end
25Programs with accumulators
fun Sum Xs fun Sum1 Xs case Xs
of XXr then AX_at_A Sum1 Xr
nil then Access A end end A
NewCell 0 in Sum1 Xs end
- fun Sum Xs
- fun Sum1 Xs A
- case Xs
- of XXr then Sum1 Xr AX
- nil then A
- end end
- in Sum1 Xs 0 end
26Programs with accumulators
fun Sum Xs fun Sum1 Xs case Xs
of XXr then AX_at_A Sum1 Xr
nil then _at_A end end A NewCell
0 in Sum1 Xs end
fun Sum Xs A NewCell 0 in ForAll Xs
proc X AX_at_A end_at_A end
27Programs with accumulators
fun Sum Xs A NewCell 0 in ForAll Xs
proc X AX_at_A end_at_A end
fun Sum Xs A NewCell 0 in for X in Xs
do AX_at_A end_at_A end The state is
encapsulated inside each procedure invocation
28Data abstraction (revisited)
- With encapsulated state, we can complete the
discussion started in Chapter 4 - For a given functionality, there are many ways to
package the data abstraction. We distinguish
three axes. - Open vs. secure is the internal representation
visible to the program or hidden? - Declarative vs. stateful does the data
abstraction have encapsulated state or not? - Bundled vs. unbundled is the data kept together
from the operations or is it separable? - Let us see what our stack abstraction looks like
with some of these possibilities
29StackOpen, declarative, and unbundled
- Here is the basic stack, as we saw it
beforefun NewStack nil endfun Push S E
ES endfun Pop S E case S of XS1 then EX S1
end endfun IsEmpty S Snil end - This is completely unprotected. Where is it
useful? Primarily, in small programs in which
expressiveness is more important than security.
30StackSecure, declarative, and unbundled
- We can make the declarative stack secure by using
a wrapperlocal Wrap Unwrapin NewWrapper
Wrap Unwrap fun NewStack Wrap nil end fun
Push S E Wrap EUnwrap S end fun Pop S E
case Unwrap S of XS1 then EX Wrap S1 end
end fun IsEmpty S Unwrap S nil endend - Where is this useful? In large programs where we
want to protect the implementation of a
declarative component.
31StackSecure, stateful, and bundled
- This is the simplest way to make a secure
stateful stackproc NewStack Push Pop
IsEmpty CNewCell nilin proc Push X
CX_at_C end fun Pop case _at_C of XS then CS
X end end fun IsEmpty C _at_Cnil endend - Compare the declarative with the stateful
versions the declarative version needs two
arguments per operation, the stateful version
uses higher-order programming (instantiation) - With some syntactic support, this gives
object-oriented programming
32StackSecure, stateful, and unbundled
- Let us combine the wrapper with statelocal Wrap
Unwrapin NewWrapper Wrap Unwrap fun
NewStack Wrap NewCell nil end proc Push W
X CUnwrap W in CX_at_C end fun Pop W
CUnwrap W in case _at_C of XS then CS X
end end fun IsEmpty S _at_ Unwrap Wnil end
end - This version is stateful but lets us store the
stack separate from the operations. The same
operations work on all stacks.
33Some ways to package a stack
- Open, declarative, and unbundled the usual
declarative style, e.g., as in Prolog and Scheme - Secure, declarative, and unbundled use wrappers
to make the declarative style secure - Secure, stateful, and bundled the usual
object-oriented style, e.g., as in Smalltalk and
Java - Secure, stateful, and unbundled an interesting
variation on the usual object-oriented style - Other possibilities there are four more
possibilities! Try to write all of them.
34Indexed Collections
- Indexed collections groups a set of (partial)
values - The individual elements are accessible through an
index - The declarative model provides
- tuples, e.g. date(17 december 2001)
- records, e.g. date(day17 monthdecemeber
year2001) - We can now add state to the fields
- arrays
- dictionaries
35Arrays
- An array is a mapping from integers to (partial)
values - The domain is a set of consecutive integers, with
a lower bound and an upper bound - The range can be mutated (change)
- A good approximation is to thing of arrays as a
tuple of cells
36Operations on arrays
- A Array.new LB UB ?Value
- Creates an array A with lower bound LB and upper
bound UB - All elements are initialized to Value
- There are other operations
- To access and update the elements of the array
- Get the lower and upper bounds
- Convert an array to tuple and vice versa
- Check its type
37Example 1
fun MakeArray L H F A Array.new L H
unit in for I in L..H do A.I F I
end A end
- A MakeArray L H F
- Creates an array A where for each index I is
mapped to F I
38Array2Record
- R Array2Record L A
- Define a function that takes a label L and an
array A, it returns a record R whose label is L
and whose features are from the lower bound of A
to the upper bound of A - We need to know how to make a record
- R Record.make L Fs
- creates a record R with label L and a list of
features (selector names), returns a record with
distict fresh variables as values - L Array.low A and H Array.high A
- Return lower bound and higher bound of array A
39Array2Record
- fun Array2Record LA A
- L Array.low A
- H Array.high A
- R Record.make LA From L H
- in
- for I in L..H do
- R.I A.I
- end
- R
- end
40Tuple to Array
- fun Tuple2Array T
- H Width T
- in
- MakeArray
- 1 H
- fun I T.I end
- end
41Dictionaries (Hash tables)
- A dictionary is a mapping from simple values or
literals (integers, atoms, amd names) to
(partial) values - Both the domain and the range can be mutated
(changed) - The pair consisting of the literal and the value
is called an item - Items can be added, changed and removed in
amortized constant time - That is to say n operations takes on average O(n)
42Operations on dictionaries
- D Dictionary.new
- Creates an empty dictionary
- There are other operations
- To access and update (and add) the elements of a
dictionary using the . and notations - Remove an item, test the memership of a key
- Convert a dictionary to a record and vice versa
- Check its type
43Indexed Collections
stateless collection
Tuple
Add state
Add atoms as indices
stateful collection
Array
Record
Add atoms as indices
Add state
Dictionary
44Other collections
stateless collection
lists
potentially infinite lists
ports
streams
stateful collection
generalizes streams to stateful mailboxes
stacks
queues
stateless
45Encapsulated statefulabstract datatypes
- These are stateful entities that can be access
only by the external interface - The implementation is not visible outside
- The are two method to build stateful abstract
data types - The functor based approach (record interface)
- The procedure dispatch approach
46The functor-based approach
- fun NewCounter I
- S Record.toDictionary state(vI)
- proc Inc S.v S.v 1 end
- proc Dec S.v S.v 1 end
- fun Get S.v end
- proc Put I S.v I end
- proc Display Show S.v end
- in o(incInc decDec getGet putPut
showDisplay) - end
47The functor-based approach
- fun NewCounter I
- S Record.toDictionary state(vI)
- proc Inc S.v S.v 1 end
- proc Dec S.v S.v 1 end
- fun Get S.v end
- proc Put I S.v I end
- proc Display Show S.v end
- in o(incInc decDec getGet putPut
showDisplay) - end
The state is collected in dictionary S The state
is completely encapsulated i.e. not visible out
side
48The functor-based approach
- fun NewCounter I
- S Record.toDictionary state(vI)
- proc Inc S.v S.v 1 end
- proc Dec S.v S.v 1 end
- fun Get S.v end
- proc Put I S.v I end
- proc Display Show S.v end
- in o(incInc decDec getGet putPut
showDisplay) - end
The interface is created for each instance
Counter
49The functor-based approach
- fun NewCounter I
- S Record.toDictionary state(vI)
- proc Inc S.v S.v 1 end
- proc Dec S.v S.v 1 end
- fun Get S.v end
- proc Put I S.v I end
- proc Display Show S.v end
- in o(incInc decDec getGet putPut
showDisplay) - end
function that access the state by lexical scope
50Call pattern
- declare C1 C2
- C1 NewCounter 0
- C2 NewCounter 100
- C1.inc
- C1.show
- C2.dec
- C2.show
51Defined as a functor
- functor Counter
- export incInc decDec getGet putPut
showDisplay initInit - define
- S
- proc Init init(I) S Record.toDictionary
state(vI) end - proc Inc S.v S.v 1 end
- proc Dec S.v S.v 1 end
- fun Get S.v end
- proc Put I S.v I end
- proc Display Show S.v end
- end
52Functors
- Functors have been used as a specification of
modules - Also functors have been used as a specification
of abstract datatypes - How to create a stateful entity from a functor?
53Explicit creation of objects from functors
- Given a variable F that is bound to a functor
- O Module.apply Fcreates stateful ADT
object O that is an instance of F - Given the functor F is stored on a file f.ozf
- O Module.link f.ozfcreates stateful
ADT object O that is an instance of F
54Defined as a functor
- functor Counter
- export incInc decDec getGet putPut
showDisplay initInit - define
- S
- proc Init init(I) S Record.toDictionary
state(vI) end - proc Inc S.v S.v 1 end
- proc Dec S.v S.v 1 end
- fun Get S.v end
- proc Put I S.v I end
- proc Display Show S.v end
- end
55Pattern of use
- fun New Functor Init
- M Module.apply Functor
- M.init Init
- M
- end
- declare C1 C2
- C1 New Counter init(0)
- C1.inc C1.show
- C2.inc C2.show
56Example memoization
- Stateful programming can be used to speed up
declarative (functional) components by
remembering previous results - Consider Pascals triangle
- One way to make it faster between separate
invocations is to remember previously computed
rows - Here follow our principle and change only the
internals of a component
57Functions over lists
1
- Compute the function Pascal N
- Takes an integer N, and returns the Nth row of a
Pascal triangle as a list - For row 1, the result is 1
- For row N, shift to left row N-1 and shift to the
right row N-1 - Align and add the shifted rows element-wise to
get row N
1
1
1
2
1
(0)
1
3
3
1
(0)
1
4
6
4
1
0 1 3 3 1 1 3 3 1 0
Shift right
Shift left
58Faster Pascal
fun FastPascal N if N1 then 1 else
local L in LFastPascal N-1
AddList ShiftLeft L ShiftRight L end
end end
- Introduce a local variable L
- Compute FastPascal N-1 only once
- Try with 30 rows.
- FastPascal is called N times, each time a list on
the average of size N/2 is processed - The time complexity is proportional to N2
(polynomial) - Low order polynomial programs are practical.
59Memoizing FastPascal
- FastPascal N New Version
- Make a store S available to FastPascal
- Let K be the number of the rows stored in S (i.e.
max row is the Kth row) - if N is less or equal K retrieve the Nth row from
S - Otherwise, compute the rows numbered K1 to N,
and store them in S - Return the Nth row from S
- Viewed from outside (as a black box), this
version behaves like the earlier one but faster
declare S Module.apply StoreFun S.put 2
1 1 Browse Get S 2 Browse Size
S (see the program)
60The store functor
- functor
- export putPut getGet sizeSize
- define
- S NewDictionary
- C NewCell 0
- proc Put K X
- if Not Dictionary.member S K then
- C_at_C1
- end
- S.K X
- end
- fun Get K S.K end
- fun Size _at_C end
- end
61The Pascal functor
- functor PascalFun
- import S at 'Store.ozf System
- export
- pascalFastPascal
- define
- fun FastPascal N ?Definition of Pascal? end
- ?Definition of help procedures for Pascal?
- S.put 1 1
- end
62Memo Pascal (1)
- fun FastPascal N
- MaxRow in
- MaxRow S.size
- if N lt MaxRow then
- S.get N
- else L in
- ?Compute the next N-MaxRow rows stating from
row the value of MaxRow, call this list of
rows L? - PutList S MaxRow1 L
- S.get N
- end
- end
63Memo Pascal (2)
- fun FastPascal N
- MaxRow in
- MaxRow S.size
- if N lt MaxRow then
- S.get N
- else L in
- L PascalListNext N-MaxRow S.get
MaxRow - PutList S MaxRow1 L
- S.get N
- end
- end
64The procedure dispatch approach
- Another method to realize stateful data
abstractions is the procedure dispatch approach - The instance of the data abstraction is a one
argument procedure - The procedure receives messages (when called)
- and dispatches to the right function according to
the label of the message - State is encapsulated
- The interface is defined as messages (implemented
as records)
65The procedure-based approach
- fun NewCounter I
- S Record.toDictionary state(vI)
- proc Inc inc S.v S.v 1 end
- proc Dec dec S.v S.v 1 end
- procGet get(I) I S.v end
- proc Put put(I) S.v I end
- proc Display show Show S.v end
- D o(incInc decDec getGet putPut
showDisplay) - in proc M D.Label M M end
- end
66Call pattern
- declare C1 C2
- C1 NewCounter 0
- C2 NewCounter 100
- C1 put(10) C1 inc
- declare X C1 get(X)
- C1 show
- C2 dec
- C2 show
67Declarative vs. Stateful
- We are going to study two different
implementations of an algorithm, one using a
stateful data type representation and the other
using a stateless representation - The stateful representation will lead to a
stateful (imperative) algorithm - The stateless representation will lead to a
declarative (functional) algorithm - We start from the abstract description of the
algorithm - Which approach is better? We will see!
68Transitive closure
- A directed graph consists of a set of vertices
(nodes) V and a set of edges (represented as set
of pairs of vertices) E - (vi,vj) ? E iff there is an edge from vi to vj
2
3
1
1,2,3,4,5,6 (1,2), (2,3), (3,4), (4,5),
(5,6),(6,2) (1,2)
The vertices
The edges
4
6
5
69Transitive closure
- Calculate a new graph TG, from the original graph
G such that TG is the transitive closure of G - That is to say there is an edge between a pair of
nodes (i,j) in TG iff there is a path from i to j
in the graph G
70Transitive closure
The set of immediate predecessors on node I,
Pred(I) The set of immediate successors on node
I, Suc(I)
2
3
Pred(2) 1 6 5 Suc(2) 3
1
4
6
5
71The algorithm works by transforming the graph
incrementally
72The algorithm works by transforming the graph
incrementally
2
2
3
3
1
1
4
4
6
6
5
5
73The abstract algorithm
- For each node x in the graph G
- For each node y in Pred(x)
- For each node z in Suc(x) add the edge (y,z) to G
74The representation
- The representation determines very much the model
of implementation - List (tree) based representation is suitable for
a declarative formulation - Array (dictionary) based representation is
suitable for a stateful formulation
75Representation
- The adjacency list representation
- The graph is a list of elements of the form INs
- I is the node identifier, Ns is the list of
successor nodes - The matrix representation
- The graph is a two dimensional array GM where
GM.I.J is true iff there is an edge from node I
to node J
76Transitive closure
- The matrix representation
- M is the matrix
M.I.K true
M.K.J true M.L.K false
I
J
K
L
77From abstract to concreteMatrix representation
- For each node K in the graph G
- For each node I in Pred(K)
- For each node J in Suc(K) add the edge (I,J) to G
proc StateTrans GM LArray.low GM
HArray.high GM in for K in L..H do ?For
each in I in Pred(K) For each J in Suc(K)
add GM.I.J true ? end end
78From abstract to concreteMatrix representation
- For each node K in the graph G
- For each node I in Pred(K)
- For each node J in Suc(K) add the edge (I,J) to G
proc StateTrans GM LArray.low GM
HArray.high GM in for K in L..H do for
I in L..H do if GM.I.K then For
each J in Suc(K) add
GM.I.J true ? end end end
79From abstract to concreteMatrix representation
proc StateTrans GM L H ... in for K
in L..H do for I in L..H do if GM.I.K
then for J in L..H do if
GM.K.J then GM.I.J true
end end end if end for
end for end
proc StateTrans GM LArray.low GM
HArray.high GM in for K in L..H do for
I in L..H do if GM.I.K then For
each J in Suc(K) add
GM.I.J true ? end end end
80From abstract to concreteMatrix representation
proc StateTrans GM L H ... in for K
in L..H do for I in L..H do if GM.I.K
then for J in L..H do if
GM.K.J then GM.I.J true
end end end if end for
end for end
proc StateTrans GM LArray.low GM
HArray.high GM in for K in L..H do for
I in L..H do if GM.I.K then For
each J in Suc(K) add
GM.I.J true ? end end end
81From abstract to concreteMatrix representation
proc StateTrans GM L H ... in for K
in L..H do for I in L..H do if GM.I.K
then for J in L..H do if
GM.K.J then GM.I.J true
end end end if end for
end for end
proc StateTrans GM L H ... in for K
in L..H do for I in L..H do if GM.I.K
then for J in L..H do
GM.I.J GM.I.J orelse GM.K.J end end
if end for end for end
82Transitive closureadjacency lists
1 2 2 1 3 3 4 4 5 5
2 6 2
The immediate successor list is sorted, e.g. 2
1 3
2
3
1
4
6
5
83From abstract to concreteAdjacency list
representation
- For each node X in the graph G
- For each node Y in Pred(X)
- For each node Z in Suc(X) add the edge (Y,Z) to
G
fun DeclTrans G Xs Nodes G in FoldL Xs
fun InG X SX Suc X ?For
each node Y in Pred(X) For each Z in SX add
edge (Y,Z) ? end G end
G0, F G0 X0 , F F G0 X0 X1, ...
This is FoldL Xs F G0
84From abstract to concreteAdjacency list
representation
fun IncPath X SX InG Map InG fun
YSY YIf ?Y in Pred(X) ? then Union SY
SX else SY end end end
fun DeclTrans G Xs Nodes G in FoldL Xs
fun InG X SX Suc X ?For
each node Y in Pred(X) For each Z in SX add
edge (Y,Z) in GC ? end
G end
?For each node Y in PX For each Z in SX add
edge (Y,Z) in GC ?
85From abstract to concreteAdjacency list
representation
fun IncPath X SX InG Map InG fun
YSY YIf Member X SY then Union SY
SX else SY end end end
fun DeclTrans G Xs Nodes G in FoldL Xs
fun InG X SX Suc X ?For
each node Y in Pred(X) For each Z in SX add
edge (Y,Z) in GC ? end
G end
Y in Pred(X) if and only if X in Pred(Y)
86Conclusion
- The stateful algorithm was straightforward in
this case - The declarative algorithm was a bit harder
- Both algorithms are of O(n3)
- In the declarative algorithm we assume Successor
list is sorted - Union is just implemented by mergeing sorted
lists O(n) - We exploited the fact that Y in Pred(X) if and
only if X in Pred(Y) - The declarative one is better if the graph is
sparse (many elements in the martix are false)
87System building
- Abstraction is the best tool to build complex
system - Complex systems are built by layers of
abstractions - Each layer have to parts
- Specification, and
- Implementation
- Any layer uses the specification of the lower
layer to implement its functionality
88Properties needed to support the principle of
abstraction
- Encapsulation
- Hide internals from the interface
- Compositionality
- Combine parts to make new parts
- Instantiation/invocation
- Create new instances of parts
89Component base programming
- Supports
- Encapsulation
- Compositionality
- Instantiation
90Object-oriented programming
- Supports
- Encapsulation
- Compositionality
- Instantiation
- Plus
- Inheritance
91Component-based programming
- Good software is good in the large and in the
small, in its high level architecture and in its
low-level details. In Object-oriented software
construction by Bertrand Meyer - What is the best way to build big applications?
- A large application is (almost) always built by a
team - How should the team members communicate?
- This depends on the applications structure
(architecture) - One way is to structure the application as a
hierarchical graph
92Component-based programming
Interface
External world
Component instance
93Component based design
- Team members are assigned individual components
- Team members communicate at the interface
- A component, can be implemented as a record that
has a name, and a list of other component
instances it needs, and a higher-order procedure
that returns a component instance with the
component instances it needs - A component instance has an interface and an
internal entities that serves the interface
94Model independence priciple
- As the system evolves, a component implementation
might change or even the model changes - declarative (functional)
- stateful sequential
- concurrent, or
- relational
- The interface of a component should be
independent of the computation model used to
implement the component - The interface should depend only on the
externally visible functionality of the component
95Examplememoization
- Consider Pascals triangle
- One way to make it faster between separate
invocations is to remember previously computed
rows - Here we follow our principle and change only the
internals of a component
96What happens at the interface?
- The power of the component based infrastructure
depends on large extent on the expressiveness of
the interface - How does components communicate with each others?
- We have three possible case
- The components are written in the same language
- The components are written in different languages
- The components are written in different
computation model
97Components in the same language
- This is easy
- In Mozart/Oz component instances are modules
(records whose fields contain the various
services provided by the component-instance part - In Java, interfaces are provided by objects
(method invocations of objects) - In Erlang, component instances are mainly
concurrent processes (threads), communication is
provided by sending asynchronous messages
98Components in different languages
- An intermediate common language is defined to
allow components to communicate given that the
language provide the same computation model - A common example is CORBA IDL (Interface
Definition Language) which maps a language entity
to a common format at the client component, and
does the inverse mapping at the service-provider
component - The components are normally reside on different
operating system processes (or even on different
machines) - This approach works if the components are
relatively large and the interaction is
relatively infrequent
99Illustration (one way)
A component C1 calling the function (method)
f(x) in the Component C2
Translate f(x) from language L1 (structured
data) to IDL (sequence of bytes)
Translate f(x) from language IDL (sequence of
bytes) to language L2 (structured data)
A component C2 invoking the function (method)
f(x)