Introduction ============ 1) Has anyone heard of the Turing Award? 1.1) Who got it in 2008? 1.2) What did this person do? 2) What is a type? What is the int, bool and double types? 3) What else we have in a program, beside ints, bools and other primitive types? 3.1) And how to describe these types? * An ADT is a type that is specified not but the set of values it may assume, but instead, it is defined by the operations that apply on it. 4) How a description of a type like this should be? - Precise and unambiguous - Complete - Not overspecific (abstract) 5) Why should we not be overspecific? - Data may change. Example: the text editor that is made in Brazil, and is exported to Israel. - Needs may change. Example: the list that is made for the Portuguese dictionary and is now used to control pending orders. 6) Which operations should be part of an abstract data type? The philosophy of selfishness: - If something is not useful to me, then I don't need it. - Just give to the user what the user wants. 7) Why is it so important, to give to the user only what the user wants? - The key is to hide information, to be free to change it. - Examples: - Millenium bug - Zip code - TRW * ADTs are a remarkable theory whose only purpose is to describe stacks. [Edsger Djikstra] 6) Let's try to describe a stack? 6.1) What operations do we normally find in a stack? - put, remove, item, empty, new. 6.2) And how we describe each of these operations? * The description of an ADT will be divided into four parts: - TYPES, FUNCTIONS, AXIOMS and PRECONDITIONS TYPES - Stack[G] 7) What is this 'G'? - Stack[G] is not exactly a type, but a type constructor. The type would be Stack[int], for instance. FUNCTIONS 7) How to specify the signature of the operation put? put: STACK[G] * G -> STACK[G] 7.1) What about the other operations? remove: STACK[G] !-> STACK[G] 7.2) Does remove work for any STACK? item: STACK[G] !-> G empty: STACK[G] -> BOOLEAN new: STACK[G] These functions are grouped into three categories: - creators: create a new instance of the type - query: ask a property of an instance of the type, without modifying it. - command: modifies and instance of the type. AXIOMS: 8) What distinguishes these functions from the functions used in a queue? What about any other container? A1: empty(new) A2: not empty(put(s, x)) 8.1) Any other property? A3: item(put(s, x)) = x A4: remove(put(s, x)) = s 9) How can we use the axioms to simplify the expression below? item ( remove ( put ( put ( new, a) ), b ) ) PRECONDITIONS 10) When a function needs some pre-conditions? 10.1) Which functions need pre-conditions? 10.2) What are the requirements for remove and item to work well? - remove(s: STACK[G]) require not empty(s) - item (s: STACK[G]) require not empty(s) 11) What is a class? - A class is an abstract data type equipped with a possibly partial implementation. 11.1) Is any implementation of the STACK above, a true stack? 12) How to describe a class? E1) An ADT specification. E2) A choice of representation. 12.1) And what else? E3) A mapping from E2 to E1. 13) What should be exposed to the user of our class? - The iceberg view: - public part: E1 - secret part: E2 and E3 14) What is object oriented software construction? - This is the art of building programs as structured collections of (possibly) partial implementations of abstract data types. 15) In software engineering books, in general we see the phases of software development divided into, say: specification, design, implementation, testing and deployment. What is the difference between specification and design? - Level of detail: specification -> real world design -> ADT implementation -> classes 16) What is design by contract? 17) What is a contract? - requirements upon the caller made by the provider - promises made by the provider to the caller 18) Some changes may break the caller or the provider. Which changes are safe? - require no more, promise no less 19) Let's assume that we have a TAD MEM_ALLOC, which provides one function: allocate: MEM_ALLOC * Integer -> BUFFER A caller may call allocate passing the capacity of the buffer, and the TAD will return a buffer with at least that capacity. Which changes can happen in such environment? - The caller may ask for less. - The provider may provide more. 20) Some languagens provide mechanisms to enforce a contract. Examples? class ACCOUNT feature balance: INTEGER -- Current balance deposit (sum: INTEGER) -- Add `sum' to account. require non_negative: sum >= 0 do balance := balance + sum ensure --one_more_deposit: deposit_count = old deposit_count + 1 updated: balance = old balance + sum end 21) How Java defines a contract? 21.1) Which requirements can be posed on method arguments? * conditions on argument values * conditions on order of execution of methods * conditions on execution in a multi-threaded environment 22) How to enforce these requirements? - Types - Exceptions - Assertions 23) How can we design a VECTOR abstract data type? 23.1) What are the operations that make sense in a vector? TYPE VECTOR FUNCTIONS: x: VECTOR -> REAL y: VECTOR -> REAL add: VECTOR * VECTOR -> VECTOR sub: VECTOR * VECTOR -> VECTOR equals: VECTOR * VECTOR -> BOOLEAN isOrigin: VECTOR -> BOOLEAN new: REAL * REAL -> VECTOR origin: VECTOR AXIOMS: x ( origin ) = 0.0 y ( origin ) = 0.0 isOrigin ( sub (v, v) ) equals (add (v, origin), v) equals (sub ( add (u, v), v), u) equals (add ( sub (u, v), v), u) 24) How can we design an ARRAY abstract data type? 24.1) What are the operations that make sense in an array? TYPE ARRAY[G] FUNCTIONS: get: ARRAY[G] * INTEGER -> G put: ARRAY[G] * INTEGER * G -> ARRAY[G] length: ARRAY[G] -> INTEGER new: INTEGER -> ARRAY[G] AXIOMS: get(a, put(a, x, n), n) = x PRECONDITIONS get(a, n) require n < length(a) put(a, x, n) require n < length(a) get(a, n) require n >= 0 put(a, x, n) require n >= 0 25) How can we design a memory allocator? 25.1) Which operations make sense in a memory allocator? TYPE MEM_ALLOC FUNCTIONS: alloc: MEM_ALLOC * INTEGER -> MEM_ALLOC * ADDRESS free: MEM_ALLOC * ADDRESS -> MEM_ALLOC capacity: MEM_ALLOC -> INTEGER new: MEM_ALLOC AXIOMS: free(alloc(m, n)) = m PRECONDITIONS alloc(m, n) require n < capacity(m) alloc(m, n) require n >= 0