CS 342 Overall plan for lectures on CLU * Introduction * semantic-model * syntax * data-abstraction * type-checking * design-with-abstractions * exception-handling * iteration * polymorphism Today's lecture: * Introduction ** History and Goals *** History *** Goals ** Abstraction in general *** Abstraction Techniques *** Kinds of abstractions * Semantic model: objects, environment, assignment, calls ** Objects *** Mutable objects *** Immutable objects ** Environment *** variables *** constants (equates) ** Assignment ** Calling mechanism ---------- % example showing mutation and aliasing addh_something = proc(a: array[int]) % MODIFIES: a % EFFECT: extend a by adding 5 to its high end array[int]$addh(a,5) end addh_something start_up = proc() % EFFECT: prints "3\n4\n5\n" on primary output x,y: array[int] x := array[int]$[1,2,3] y := x % makes x and y aliases stream$putl(po, int$unparse(array[int]$size(y))) array[int]$addh(x,4) % mutates object denoted by x po: stream := stream$primary_output() stream$putl(po, int$unparse(array[int]$size(y))) addh_something(y) stream$putl(po, int$unparse(array[int]$size(x))) end start_up ---------- * Syntax ** lexical ** declarations *** equates *** variable declarations ** statements *** assignment *** compound ** Syntactic sugars *** Arithmetic operations ------------ suppose a,b: int a + b => int$add(a,b) a < b => int$lt(a,b) a = b => int$equal(a,b) -a => int$minus(a) suppose a,b: real a + b => real$add(a,b) a < b => real$lt(a,b) a = b => real$equal(a,b) -a => real$minus(a) ------------ *** Boolean operations ------------ suppose a,b: bool a & b => bool$and(a,b) a | b => bool$or(a,b) a = b => bool$equal(a,b) ~a => bool$not(a) ------------ *** General comparisons (for most types) ------------ suppose a,b: T a = b => T$equal(a,b) a ~= b => bool$not(T$equal(a,b)) a >= b => T$ge(a,b) a > b => T$gt(a,b) a <= b => T$le(a,b) a < b => T$lt(a,b) ------------ * Data Abstraction ** Examples (built-in types of CLU) *** int ------------ add = proc(a,b: int) returns(int) signals(overflow) % EFFECT: if a+b is in represented set of integers, return a+b; % otherwise signal overflow. from_to_by = iter(from, to: int) yields(int) % EFFECT: yield from, from+1, ..., to parse = proc(s: string) returns(int) signals(bad_format,overflow) % EFFECT: if s has the form of a base 10 integer literal, % if the integer coded by s is in the represeted set, % then return the integer coded by s, otherwise signal overflow; % else if s has the wrong form, signal bad_format. lt = proc(a,b: int) returns(bool) % EFFECT: return a < b equal = proc(a,b: int) returns(bool) % EFFECT: return true iff a is the same as b copy = proc(a: int) returns(int) % EFFECT: return a -------------------- *** array -------------- create = proc(lb: int) returns(array[t]) % EFFECT: returns a new, empty array with low bound lb (The phrase "a new array" means an array that is different from all others.) fill = proc(lb, cnt: int, elem: t) returns(array[t]) signals(negative_size) % EFFECT: if cnt < 0, signal negative_size; otherwise return a new % array with low bound lb and a tuple of size cnt, % where each element of the tuple is elem. addh = proc(a: array[t], elem: t) % MODIFIES: a % EFFECT: extend a by 1 on the high end and makes elem the new element fetch = proc(a: array[t], i: int) returns(t) signals(bounds) % EFFECT: if i is out of bounds (i.e., less than the low bound of a % or greater than the size of a's tuple plus the low bound % minus one), then signal bounds; otherwise return % the ith element of a. store = proc(a: array[t], i: int, elem: t) signals(bounds) % EFFECT: if i is out of bounds, signal bounds; otherwise make elem % the ith element of a. elements = iter(a: array[t]) yields(t) % EFFECT: yields the elements of a's tuple, in order from low to high equal = proc(a,b: array[t]) returns(bool) % EFFECT: return true iff a and b are the same object -------------- ** Clusters (modules that implement data abstractions) *** operation export and hiding *** representation (rep) *** security of data abstraction (langauge enforcement of data abtraction) ------------ % create of interval create = proc(l,u: int) returns(interval) signals(empty) % EFFECT: if l <= u, then return [l,u], otherwise signal empty if (l <= u) then return(up(rep${lower:l, upper:u})) else signal empty end end create ------------ **** up **** down **** cvt **** rep type not equal to abstract type * Type checking ** structural (for equates) ** By name for abstract types ** No Coercions ** Across module boundaries (library) *** module interfaces **** modules: procedures, clusters, (and iterators) **** interface (signature) **** DU (description unit) **** compilation environment *** practical steps in using the CLU compiler and library **** spec files **** compilation environment files **** creating a library **** compiling a file * Design with Data Abstractions * Exception Handling ** What is an exception? ** Is a language-defined exception handling mechanism necessary? *** require that caller insure that they don't happen *** status codes *** label parameters (gotos) *** pass procedure to be called in case of exception ** Trade-offs in langauge-defined exception mechanism *** benefits: *** problems: ** Trade-offs in use of exceptions (exceptions vs. precondition) ** Exceptions in CLU *** Where can exceptions be handled? **** single level model (CLU) **** multiple level model (Ada) *** Declarations ----------- pop = proc(s: stack) signals(empty) ----------- *** Interaction with type checking *** Raising an exception (signal statement) ----------------------- if rep$empty(s) then signal empty end ---------------------- **** Effect of raising an exception ***** termination model (CLU) ***** resumption model (Mesa, Ceder, ...) *** Exceptions handlers ----------- stack$pop(foo(mystack)) except when empty: % handler code stream$putl(stderr, "popped empty stack") when foo_ex(i: int) stream$putl(stderr, "foo exception: " || int$unparse(i)) when bar, baz (*): % ignore exception results, if any, of these % bar and baz may have different number and types of exception results others: % all other exceptions handled here but results are lost end % flow continues here ----------- **** scope of exception handlers **** Finding exception handlers **** Begin - end blocks ------------- begin check_format(s) check_for_illegal_opcodes(s) end except when syntax_error: % ... end ------------- **** Unhandled exceptions **** propogation of exceptions --------------- p[i] := instruction$parse(in_str) resignal syntax_error --------------- ** Exit statement for local flow of control ------------ lt = proc(s1, s2: setoft) returns(bool) % EFFECT: Is s1 a proper subset of s2? begin % suppose we can't find out the sizes of s1 or s2 for e: t in setoft$elements(s2) do if ~setoft$is_member(s1, e) then exit okay end %********here end % every element in s2 is in s1 return(false) end except when okay : end % there is some element, e', in s2 such that ~setoft$is_member(s1, e') for e: t in setoft$elements(s1) do if ~setoft$is_member(s2, e) then return(false) end end % for all elements, e, in s1, setoft$is_member(s2, e) and % there is some element, e', in s2 such that ~setoft$is_member(s1, e') return(true) end lt ------------ ** Implementation (may be omitted) *** Goals: no slowdown for normal case *** Actions: *** branch table method *** handler table method ** Summary * Iteration over abstract data types ** Problem *** example: intset *** ways to iterate over intsets ** streams (generators) ** CLU iterators ------------------ intset = cluster is elements, ... rep = array[int] % REP INVARIANT: For r: rep, r contains no duplicates % % ABSTRACTION FUNCTION: r: rep represents the set containing % just the elements of r. elements = iter(s: cvt) yields(i:int) % EFFECT: yield each element of s, once only for i: int in array[int]$indexes(s) do yield(s[i]) end end elements end intset ------------------ ------------------ elements = iter(s: cvt) yields(i:int) for i: int in array[int]$elements(s) do yield(i) end end elements ------------------ --------------- blank_positions = iter() yields(int) % EFFECT: Yield 3, 7, 11 yield(3) yield(7) yield(11) end blank_positions fields = iter(s: string) yields(string) % REQUIRES: s has at least 14 characters % EFFECT: Yield each of the address fields of a pseudo-code instr. yield(string$substr(s,4,3)) yield(string$substr(s,8,3)) yield(string$substr(s,12,3)) end fields -------------- ** Implementation of CLU iterators (may be omitted) * Type polymophism ** makes more general abstractions *** declaration ------------ sort = proc[t: type] (a: array[t], cmp: cmptype) cmptype = proctype(t,t) returns(bool) % ... end sort sort_increasing = proc[t: type] (a: array[t]) where t has lt: proctype(t,t) returns(bool) % ... end sort_increasing ------------ **** Trade-offs between requiring operations or passing as arguments ** instantiation ** Type checking *** type checking instantiations **** static checks **** examples *** type checking for implemenations ** Implemenation of parameterized procedures