Title: Data Abstraction, State, and Objects Abstract Data Types (VRH 3.7) State / Data Abstraction(VRH 6.1, 6.3, 6.4.1, 6.4.2) Object System Implementation (VRH 7.6)
1Data Abstraction, State, and ObjectsAbstract
Data Types (VRH 3.7)State / Data Abstraction(VRH
6.1, 6.3, 6.4.1, 6.4.2)Object System
Implementation (VRH 7.6)
- Carlos Varela
- RPI
- Adapted with permission from
- Seif Haridi
- KTH
- Peter Van Roy
- UCL
2Abstract data types
- A datatype is a set of values and an associated
set of operations - A datatype is abstract if only it is completely
described by its set of operations regradless of
its implementation - This means that it is possible to change the
implementation of the datatype without changing
its use - The datatype is thus described by a set of
procedures - These operations are the only thing that a user
of the abstraction can assume
3Example A Stack
- Assume we want to define a new datatype ?stack T?
whose elements are of any type T - fun NewStack ?Stack T?
- fun Push ?Stack T? ?T? ?Stack T?
- fun Pop ?Stack T? ?T? ?Stack T?
- fun IsEmpty ?Stack T? ?Bool?
- These operations normally satisfy certain
conditions - IsEmpty NewStack true
- for any E and S0, S1Push S0 E and S0 Pop S1
E hold - Pop NewStack E raises error
4Stack (implementation)
- fun NewStack nil end
- fun Push S E ES end
- fun Pop S E case S of XS1 then E X S1 end
end - fun IsEmpty S Snil end
5Stack (another implementation)
- fun NewStack nil end
- fun Push S E ES end
- fun Pop S E case S of XS1 then E X S1 end
end - fun IsEmpty S Snil end
- fun NewStack emptyStack end
- fun Push S E stack(E S) end
- fun Pop S E case S of stack(X S1) then E X S1
end end - fun IsEmpty S SemptyStack end
6Dictionaries
- The datatype dictionary is a finite mapping from
a set T to ?value?, where T is either ?atom? or
?integer? - fun NewDictionary
- returns an empty mapping
- fun Put D Key Value
- returns a dictionary identical to D except Key is
mapped to Value - fun CondGet D Key Default
- returns the value corresponding to Key in D,
otherwise returns Default - fun Domain D
- returns a list of the keys in D
7Implementation
- fun Put Ds Key Value
- case Ds
- of nil then KeyValue
- (KV)Dr andthen KeyK then
- (KeyValue) Dr
- (KV)Dr andthen KgtKey then
- (KeyValue)(KV)Dr
- (KV)Dr andthen KltKey then
- (KV)Put Dr Key Value
- end
- end
8Implementation
- fun CondGet Ds Key Default
- case Ds
- of nil then Default
- (KV)Dr andthen KeyK then
- V
- (KV)Dr andthen KgtKey then
- Default
- (KV)Dr andthen KltKey then
- CondGet Dr Key Default
- end
- end
- fun Domain Ds
- Map Ds fun K_ K end
- end
9Further implementations
- Because of abstraction, we can replace the
dictionary ADT implementation using a list, whose
complexity is linear (i.e., O(n)), for a binary
tree implementation with logarithmic operations
(i.e., O(log(n)). - Data abstraction makes clients of the ADT unaware
(other than through perceived efficiency) of the
internal implementation of the data type. - It is important that clients do not use anything
about the internal representation of the data
type (e.g., using Length Dictionary to get the
size of the dictionary). Using only the
interface (defined ADT operations) ensures that
different implementations can be used in the
future.
10Secure abstract data typesStack is not secure
- fun NewStack nil end
- fun Push S E ES end
- fun Pop S E
- case S of XS1 then EX S1 end
- end
- fun IsEmpty S Snil end
11Secure abstract data types II
- The representation of the stack is visible
- a b c d
- Anyone can use an incorrect representation, i.e.,
by passing other language entities to the stack
operation, causing it to malfunction (like abX
or YabY) - Anyone can write new operations on stacks, thus
breaking the abstraction-representation barrier - How can we guarantee that the representation is
invisible?
12Secure abstract data types III
- The model can be extended. Here are two ways
- By adding a new basic type, an unforgeable
constant called a name - By adding encapsulated state.
- A name is like an atom except that it cannot be
typed in on a keyboard or printed! - The only way to have a name is if one is given it
explicitly - There are just two operations on names
- NNewName returns a fresh name
- N1N2 returns true or false
13Secure abstract datatypes IV
- We want to wrap and unwrap values
- Let us use names to define a wrapper unwrapper
- proc NewWrapper ?Wrap ?Unwrap
- KeyNewName
- in
- fun Wrap X
- fun K if KKey then X end end
- end
- fun Unwrap C
- C Key
- end
- end
14Secure abstract data typesA secure stack
- With the wrapper unwrapper we can build a
secure stack - local Wrap Unwrap in
- 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 Snil end
- end
15Capabilities and security
- We say a computation is secure if it has
well-defined and controllable properties,
independent of the existence of other (possibly
malicious) entities (either computations or
humans) in the system - What properties must a language have to be
secure? - One way to make a language secure is to base it
on capabilities - A capability is an unforgeable language entity
( ticket ) that gives its owner the right to
perform a particular action and only that action - In our model, all values are capabilities
(records, numbers, procedures, names) since they
give the right to perform operations on the
values - Having a procedure gives the right to call that
procedure. Procedures are very general
capabilities, since what they do depends on their
argument - Using names as procedure arguments allows very
precise control of rights for example, it allows
us to build secure abstract data types - Capabilities originated in operating systems
research - A capability can give a process the right to
create a file in some directory
16Secure abstract datatypes V
- We add two new concepts to the computation model
- NewChunk Record
- returns a value similar to record but its arity
cannot be inspected - recall Arity foo(a1 b2) is a b
- NewName
- a function that returns a new symbolic
(unforgeable, i.e. cannot be guessed) name - foo(a1 b2 NewName3) makes impossible to
access the third component, if you do not know
the arity - NewChunk foo(a1 b2 NewName3)
- Returns what ?
17Secure abstract datatypes VI
- proc NewWrapper ?Wrap ?Unwrap
- KeyNewName
- in
- fun Wrap X
- NewChunk foo(KeyX)
- end
- fun Unwrap C
- C.Key
- end
- end
18Secure abstract data typesAnother secure stack
- With the new wrapper unwrapper we can build
another secure stack (since we only use the
interface to wrap and unwrap, the code is
identical to the one using higher-order
programming) - local Wrap Unwrap in
- 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 Snil end
- end
19What 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 Browse
Sum 1 2 3 4 0
20What 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 Browse
Sum 1 2 3 4 0
21What 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
22What 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
23What 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
- Assign X J
- Assumes X is bound to a cell C (otherwise
exception) - Changes the content of C to become J
- Y Access X
- Assumes X is bound to a cell C (otherwise
exception) - Binds Y to the value contained in C
24Examples
- X NewCell 0
- Assign X 5
- Y X
- Assign Y 10
- Access X 10 returns true
- X Y returns true
0
X
5
X
Y
10
X
Y
25Examples
- X NewCell 10Y NewCell 10
- X Y returns false
- Because X and Y refer to different cells, with
different identities - Access X Access Yreturns true
10
X
10
Y
26The model extended with cells
Semantic stack
w f(x) z person(ay) y ?1 u ?2 x
?1 w ?2 x .... ....
single assignment store
mutable store
27The stateful model
?s? skip
empty statement ?s1? ?s2?
statement sequence
...
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?
28The 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
C X is syntactic sugar for Assign C X _at_C is
syntactic sugar for Access C XCY is
syntactic sugar for Exchange C X Y
29Abstract data types (revisited)
- For a given functionality, there are many ways to
package the ADT. We distinguish three axes. - Open vs. secure ADT is the internal
representation visible to the program or hidden? - Declarative vs. stateful ADT does the ADT have
encapsulated state or not? - Bundled vs. unbundled ADT is the data kept
together from the operations or is it separable? - Let us see what our stack ADT looks like with
some of these possibilities
30StackOpen, 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.
31StackSecure, 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.
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 Assign C XAccess C
end fun Pop W CUnwrap W in case Access
C of XS then Assign C S X end end fun
IsEmpty S Access 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.
33StackSecure, stateful, and bundled
- This is the simplest way to make a secure
stateful stackproc NewStack ?Push ?Pop
?IsEmpty CNewCell nilin proc Push X
Assign C XAccess C end fun Pop case
Access C of XS then Assign C S X end
end fun IsEmpty Access C nil 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 is object-based
programming
34Four ways to package a stack
- Open, declarative, and unbundled the usual
declarative style, e.g., in Prolog and Scheme - Secure, declarative, and unbundled use wrappers
to make the declarative style secure - Secure, stateful, and unbundled an interesting
variation on the usual object-oriented style - Secure, stateful, and bundled the usual
object-oriented style, e.g., in Smalltalk and
Java - Other possibilities there are four more
possibilities! Exercise Try to write all of
them.
35Encapsulated stateful abstract datatypes ADT
- These are stateful entities that can be accessed
only by the external interface - The implementation is not visible outside
- We show two methods to build stateful abstract
data types - The functor based approach (record interface)
- The procedure dispatch approach
36The functor-based approach
- fun NewCounter I
- S NewCell I
- proc Inc S _at_S 1 end
- proc Dec S _at_S - 1 end
- fun Get _at_S end
- proc Put I S I end
- proc Display Browse _at_S end
- in o(incInc decDec getGet putPut
displayDisplay) - end
37The functor-based approach
- fun NewCounter I
- S NewCell I
- proc Inc S _at_S 1 end
- proc Dec S _at_S - 1end
- fun Get _at_S end
- proc Put I S I end
- proc Display Browse _at_S end
- in o(incInc decDec getGet putPut
browseDisplay) - end
The state is collected in cell S The state is
completely encapsulated i.e. not visible outside
38The functor-based approach
- fun NewCounter I
- S NewCell I
- proc Inc S _at_S 1 end
- proc Dec S _at_S - 1end
- fun Get _at_S end
- proc Put I S I end
- proc Display Browse _at_S end
- in o(incInc decDec getGet putPut
displayDisplay) - end
The interface is created for each instance
Counter
39The functor-based approach
- fun NewCounter I
- S NewCell I
- proc Inc S _at_S 1 end
- proc Dec S _at_S - 1end
- fun Get _at_S end
- proc Put I S I end
- proc Display Browse S.v end
- in o(incInc decDec getGet putPut
displayDisplay) - end
functions that access the state by lexical scope
40Call pattern
- declare C1 C2
- C1 NewCounter 0
- C2 NewCounter 100
- C1.inc
- C1.display
- C2.dec
- C2.display
41Defined as a functor
- functor Counter
- export incInc decDec getGet putPut
displayDisplay initInit - define
- S
- proc Init init(I) S NewCell I end
- proc Inc S _at_S 1 end
- proc Dec S _at_S - 1 end
- fun Get _at_S end
- proc Put I S I end
- proc Display Browse _at_S end
- end
42Functors
- 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?
43Explicit 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
44Defined as a functor
- functor Counter
- export incInc decDec getGet putPut
displayDisplay initInit - define
- S
- proc Init init(I) S NewCell I end
- proc Inc S _at_S 1 end
- proc Dec S _at_S - 1 end
- fun Get _at_S end
- proc Put I S I end
- proc Display Browse _at_S end
- end
45Pattern of use
- fun New Functor Init
- M in
- M Module.apply Functor
- M.init Init
- M
- End
- declare C1 C2
- C1 New Counter init(0)
- C2 New Counter init(100)
- C1.inc C1.put 50 C1.display
- C2.dec C2.display
Generic function to create objects from functors
Object interface is a record with procedure
values inside fields
46The procedure-based approach
- fun Counter
- S
- proc Inc inc(Value) S _at_S Value end
- proc Display display Browse _at_S end
- proc Init init(I) S NewCell I end
- D o(incInc displayDisplay initInit)
- in proc M D.Label M M end
- end
47The procedure-based approach
- fun Counter
- S
- ...
- D o(incInc displayDisplay initInit)
- in proc M D.Label M M end
- end
- fun New Class InitialMethod
- O Class
- in O InitialMethod O end
48Example
- The following shows how an object is created from
a class using the procedure New/3, whose first
argument is the class, the second is the initial
method, and the result is the object. - New/3 is a generic procedure for creating
objects from classes. - declare C New Counter init(0)C displayC
inc(1)C display
Object interface is as a procedure of one
argument, which expects a record
49Exercises
- Write the higher-order function Map used by the
Domain function in the Dictionary ADT. - Solve problem 17 in Section 3.10 (pg. 232). You
do not need to implement it using gump, simply
specify how you would add currying to Oz (syntax
and semantics). - Do exercise 2 in Section 6.10 (pg. 482).
- Read Sections 7.1-4, and 7.7