160 likes | 762 Views
Abstract data types What does ‘ abstract ’ mean? From Latin: to ‘ pull out ’— the essentials To defer or hide the details Abstraction emphasizes essentials and defers the details, making engineering artifacts easier to use
E N D
Abstract data types • What does ‘abstract’ mean? • From Latin: to ‘pull out’—the essentials • To defer or hide the details • Abstraction emphasizes essentials and defers the details, making engineering artifacts easier to use • 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 • 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) • See multimedia: ADT for digits (properties)
ADT = properties + operations • 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 • Thus, an ADT couples its data and operations • OOP emphasizes data abstraction
Formal, language-independent ADTs • An ADT is a formal description, not code; independent of any programming language • Why is code independence a good idea? • Promotes design by contract: • Specify responsibilities of suppliers and clients explicitly, so they can be enforced, if necessary
Generic Queue ADT • 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 B set of Boolean (elements T and F) N set of natural numbers, including 0 • The NAME specifies the name of a type • Generic parameter, <I>, to specify elements of collection types • SETS specifies all the types of parameters in SIGNATURES section
SIGNATURES section (see umprobso—“you are adding”) SIGNATURES Queue() -> Q front(Q) -/-> I isEmpty(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: • isEmpty(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 isEmpty(Q) -> B enqueue(Q, I) -> Q length(Q) -> N dequeue(Q) -/-> Q • -> denotes a full function over the set Q, always producing the specified type of output • ‑/‑> 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 enQueue undefined? • Answering these questions about partial functions is semantics • Specifically, the preconditions • 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) -> isEmpty (q) = false dequeue(q) -> isEmpty (q) = false • VARIABLES -- declares instances of SETS, needed in PRE- and POST-CONDITIONS • How are the variables used in PRECONDITIONS? • What is the scope of these variables?
Preconditions • Specify constraints on any partial functions, indicating when they fail • front(q) -> isEmpty (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., isEmpty(q) -> true.
Postconditions • Define effects of functions, i.e., what they accomplish POSTCONDITIONS Queue() = (qList = List()) isEmpty(q) = null(qList) length(q) = length(qList) front(q) = head(qList) enqueue(q,i) = (qList = append(qList, i)) dequeue(q,i) = (qList = tail(qList, i)) • First postcondition defines constructor in terms of List • Reusing List implies a constructive semantics, building from other ADTs, already defined • Why is constructive semantics a good fit for OOP? • What does second postcondition tell you?
Axiomatic semantics • 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) • null(List()) = true //How self-evident? • null(prepend(list1,i)) = null(append(list1,i)) = false //Explain? • length(List()) = 0 • length(append(list1, i)) = length(list1)+1 • tail(append(list1,i)) = if null(list1) then [] else append(tail(list1),i))
Constructive semantics(See umprobso, “Queue of football”) • Explain rest of Queue’s postconditions: front(q) = head(qList) enqueue(q,i) = (qList = append(qList, i)) dequeue(q,i) = (qList = tail(qList, i)) • Why would this be harder with axioms? • (See umprobso, “axiomatic”)
Inheritance and ADTs • See Employee example • How does inheritance affect name section? • NAME Employee SUPERTYPES Person • 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 • Could add notation {abstract} to specify abstract functions
Fruit ADT assignment • 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