Abstract data types What does abstract mean n
Abstract data types What does ‘abstract’ mean? n From Latin: to ‘pull out’—the essentials n – To defer or hide the details – Abstraction emphasizes essentials and defers the details, making engineering artifacts easier to use n I don’t need a mechanic’s understanding of what’s under a car’s hood in order to drive it – What’s the car’s interface? – What’s the implementation?
Floating point numbers n You don't need to know how much about floating point arithmetic works to use float – Indeed, the details can vary depending on processor, even virtual coprocessor – But the compiler hides all the details from you-some numeric ADTs are built-in – All you need to know is the syntax and meaning of operators, +, -, *, /, etc. Hiding the details of implementation is called encapsulation (data hiding) n See multimedia: ADT for digits (properties) n
ADT = properties + operations n An ADT describes a set of objects sharing the same properties and behaviors – The properties of an ADT are its data (representing the internal state of each object • double d; -- bits representing exponent & mantissa are its data or state – The behaviors of an ADT are its operations or functions (operations on each instance) • sqrt(d) / 2; //operators & functions are its behaviors n Thus, an ADT couples its data and operations – OOP emphasizes data abstraction
Formal, language-independent ADTs n An ADT is a formal description, not code; independent of any programming language – Why is code independence a good idea? n Promotes design by contract: – Specify responsibilities of suppliers and clients explicitly, so they can be enforced, if necessary
Generic Queue ADT n An ADT specification has six parts – The first three dealing with syntax… NAME, SETS and SIGNATURES NAME Queue<I> SETS I set of all items (generic type) Q set of all Queues Bset of Boolean (elements T and F) N set of natural numbers, including 0 n The NAME specifies the name of a type – Generic parameter, <I>, to specify elements of collection types n SETS specifies all the types of parameters in SIGNATURES section
SIGNATURES section (see umprobso—“you are adding”) SIGNATURES n n n Queue() -> Q front(Q) -/-> I is. Empty(Q) -> B enqueue(Q, I) -> Q length(Q) -> N dequeue(Q) -/-> Q SIGNATURES specifies the operations or services provided by ADT Notation of mathematical functions, with one or more inputs and producing one result: – is. Empty(Q) -> B: Given a Queue (domain), produces a Boolean (range) Functions have no side effects at all: – front(Q): given a Q, returns an item (no change) – enqueue(Q, I): returns a NEW Queue – dequeue(Q): returns another Queue Functional approach may seem inefficient, but facilitates semantics – Implementation should preserve the abstract behavior of ADT Syntax is relatively easy to specify; semantics is a bit harder….
Full vs. partial functions SIGNATURES Queue() -> Q front(Q) -/-> I is. Empty(Q) -> B enqueue(Q, I) -> Q length(Q) -> N dequeue(Q) -/-> Q n -> denotes a full function over the set Q, always producing the specified type of output n ‑/‑> denotes a partial function over the set Q, which may not always produce the output – Instead its result may be undefined When is front undefined? When is en. Queue undefined? n Answering these questions about partial functions is semantics n Specifically, the preconditions n – A partial function is undefined if any of its preconditions do not hold
Semantics of ADTs Three sections for semantics of ADTs: variables, preconditions, and postconditions VARIABLES i: I; q, r: Q; n: N; b: B PRECONDITIONS front(q) -> is. Empty (q) = false dequeue(q) -> is. Empty (q) = false n VARIABLES -- declares instances of SETS, needed in PRE- and POST-CONDITIONS n How are the variables used in PRECONDITIONS? n What is the scope of these variables? n
Preconditions n n n n Specify constraints on any partial functions, indicating when they fail front(q) -> is. Empty (q) = false //What does this constraint tell you? – PRECONDITIONs very explicit about the when a partial function fails Formalizes design by contract: analogous to written business contracts – Inspire confidence between clients and suppliers of products E. g. , a contract for building a house, or a contract to write a book – A contract specifies the product that the supplier will produce – A contract also specifies the price the client will pay and other terms – Such as constraints on a contract—installments, liability, etc. ADT specifies a contract between the supplier and client of an ADT – Supplier warrants that ADT will produce the specified behavior – so long as client provides the expected inputs – so long as client doesn’t violate the pre-conditions, behaviors will work – if the client violates the contract (any pre-condition), the behavior fails – Yet even the failure is predictable and can be handled predictably Thus PRECONDITIONS also set up exception handling Note: no need to include trivial preconditions, e. g. , is. Empty(q) -> true.
Postconditions n Define effects of functions, i. e. , what they accomplish POSTCONDITIONS Queue() = (q. List = List()) is. Empty(q) = null(q. List) length(q) = length(q. List) front(q) = head(q. List) enqueue(q, i) = (q. List = append(q. List, i)) dequeue(q, i) = (q. List = tail(q. List, i)) n First postcondition defines constructor in terms of List – Reusing List implies a constructive semantics, building from other ADTs, already defined n n Why is constructive semantics a good fit for OOP? What does second postcondition tell you?
Axiomatic semantics n Defines relations between operations strictly in terms of universal axioms (self-evident truths) – Axioms define an ADT independently of other ADTs – Constructive approach builds new ADTs based on knowledge of existing ones – The buck has to stop somewhere: e. g. , the List ADT uses an axiomatic semantics – Book has an optional section on universal axioms
List postconditions (axioms) n n null(List()) = true //How self-evident? null(prepend(list 1, i)) = null(append(list 1, i)) = false //Explain? length(List()) = 0 length(append(list 1, i)) = length(list 1)+1 tail(append(list 1, i)) = if null(list 1) then [] else append(tail(list 1), i))
Constructive semantics (See umprobso, “Queue of football”) Explain rest of Queue’s postconditions: front(q) = head(q. List) enqueue(q, i) = (q. List = append(q. List, i)) dequeue(q, i) = (q. List = tail(q. List, i)) n Why would this be harder with axioms? n – (See umprobso, “axiomatic”)
Inheritance and ADTs n n See Employee example How does inheritance affect name section? – NAME Employee SUPERTYPES Person n How does inheritance affect other sections? – Employee inherits functions for name, address, etc, from Person – Inherits both syntax (SIGNATURES) and semantics – No need to redefine functions in Employee unless they do something different • So Employee just supplies new constructor, GROSS_PAY, TAX_DUE – Semantics can benefit further from reuse implied by inheritance – Constructor for Employee invokes constructor for Person n Could add notation {abstract} to specify abstract functions
Fruit ADT assignment n Your assignment (on Blackboard): – Improve your UML analysis • Per my comments • You may want to improve my analysis! – Develop an ADT design • Think of it as a contract that you could hand over to a programmer (that would be you!) – Extra credit: design a user interface ADT(s) • loosely coupled to problem domain ADT
- Slides: 15