Data Abstraction and Encapsulation • Key research: – Dennis & Van Horn CACM, March '66 • first notion of abstract types and capabilities – Parnas: "On the Criteria to be Used in Decomposing Systems into Modules." CACM, Dec '72 – Liskov: CLU – Wulf/Shaw: Alphard – Lampson: Euclid – Good: GYPSY – Xerox: Mesa – Hoare/Brinch Hansen: monitors – Wirth: Modula & Modula-2 – Honeywell-Bull: Ada Parnas's Principles • One must provide the intended user with all the information needed to use the module and nothing more. • One must provide the implementer with all the information needed to complete the module and nothing more. Data Abstraction • Emphasis on behavior (operations capture behavior) • Implementation is not important to user of abstraction • In order to support data abstraction, language must provide: – linguistic construct • permits abstraction to be implemented as a unit • supports representation specification – ways to limit access to object • access should only be to defined operations • no access to representation --> clusters, modules, forms, packages, classes... Simple - Data Only package earth is type continent is (Africa, Antarctica, Asia, Australia, Europe, NorthAmerica, SouthAmerica); radius: constant float:= 6.4e6; area: constant array (continent) of float:= (30.3e9, 13.0e9, 43.3e9, 7.7e9, 10.4e9, 24.9e9, 17.8e9); population : array (continent) of integer; end earth; Logical clustering Information Hiding package trig is function sin(x: float) return Float; function cos(x: float) return Float; end trig; package body trig is pi: constant Float:= 3.14159; function norm(x: float) return float is ...; - return x modulo 2*pi function sin(x: float) return float is ...; --return the sine of norm(x) function cosine (x: float) return float is ...; --return the cosine of norm(x) end trig Exporting functions only Implementation is hidden Simple Objects - Creates one directory package directory_object is - exports two procs that procedure insert(newname : in Name; newnumber : in Number); can operate on directory procedure lookup(oldname : in Name; - directory itself hidden oldnumber : out Number; from access found : out Boolean); end directory_object; package body directory_object is type Dirnode; type Dirptr is access Dirnode; type Dirnode is record entryname : Name; entrynumber : Number; left, right : Dirptr; end record; root: dirptr; Implements a directory (cont) Simple Objects procedure insert(newname : in Name; newnumber : in Number) is ... -- add new newname, newnumber to the directory procedure lookup(oldname : in Name; oldnumber : out Number; found : out Boolean); ... -- find oldname entry in directory begin ...; -- initialize the directory end directory_object; -----------------directory-object.insert (me, 41039); ... directory_object.lookup (me, mynumber, ok); Operations user can perform on directory Object Classes generic package directory_class is procedure insert(newname: in Name; newnumber: in Number); procedure lookup(oldname: in Name; oldnumber: out Number; found: out Boolean); end directory_class; package body directory_class is type Dirnode; type Dirptr is access Dirnode; type Dirnode is record entryname : Name; entrynumber : Number; left, right : Dirptr; end record; root: dirptr; Describes an instance of a directory (cont) Object Classes procedure insert(newname: in Name; newnumber: in Number) is ... -- add new newname, newnumber to the directory procedure lookup(oldname: in Name; oldnumber: out Number; found: out Boolean); ... -- find oldname entry in directory begin ... -- initialize the directory end directory_class; -----------------package homedir is new directory_class package workdir is new directory_class workdir.insert (me, 41039); homedir.insert (me, 30570); workdir.lookup (me, mynumber, ok); Derived objects No notion of inheritance Abstract Types - Motivation datatype rational = rat of (int * int); val zero = rat (0, 1); and one = rat (1, 1); fun op ++ (rat(m1, n1): rational, rat(m2, n2): rational) = rat (m1*n2 + m2*n1, n1*n2) ----------------------rat(3,2) --creates rational number 3/2 rat(6,4) --creates rational number 6/4 Abs Types - (cont) Motivation if one ++ rat(1,2) = rat (6,4) then ... else ... Won’t test = although it should rat(0,0) -- no corresponding rat(1,0) -- rational numbers! -----------------------Have: Rational = {rat(m,n) | m,n integer} Desire: Rational = {rat(m,n) | m,n integer; n>0; m,n have no common factor} -- a type based on a (representation) type that does not exist -- in common languages. abstract type: based on a set of operations: constants, functions and procedures -- values defined only indirectly. Abstract Types - Example abstype rational = rat of (int * int); with val zero = rat (0, 1); and one = rat (1, 1); fun op // (m: int, n: int) = if n <> 0 then rat(m,n) else ... -- invalid rational number and op ++ (rat(m1, n1): rational, rat(m2, n2): rational) = rat (m1*n2 + m2*n1, n1*n2) Abs Types (cont) Example and op == (rat(m1, n1): rational, rat(m2, n2): rational) = (m1*n2 = m2*n1) and float (rat(m,n): rational) = m/n end ----------------------val h = 1//2 --creates rational number 1/2 val i = 6//4 --creates rational number 6/4 if one ++ h = = i then ... else ... -- now this works Another Abstract Type package directory_type is type Directory is limited private; procedure insert(dir: in out Directory; newname: in Name; newnumber : in Number); procedure lookup(dir: in Directory; oldname: in Name; oldnumber: out Number; found: out Boolean); private type Dirnode; type Directory is access Dirnode; type Dirnode is record ... end record; end directory_type; Implementation details in a specification! Another Abstract Type (cont) package body directory_type is procedure insert(dir: in out Directory; newname: in Name; newnumber : in Number) is ... -- add new newname, newnumber to dir procedure lookup(dir: in Directory; oldname: in Name; oldnumber: out Number; found: out Boolean); ... -- find oldname entry in dir end directory_type; Using directory_type use directory_type; -- allows dropping dot notation homedir: Directory; workdir: Directory; ... insert (workdir, me, 41039); insert (homedir, me, 97548); ... lookup (workdir, me, mynumber, ok); Objects and Abstract Types • Abstract types are similar to built-in types and have firstclass status: values of the type are first-class. Objects, in general, are not. In object example, homedir and workdir couldn't be passed as arguments, for e.g. • Abstract type notation is more natural: values and variables of the type are arguments rather than dot-notated prefixes. • Abstract types work in all programming paradigms. Objects, being updatable entities, fit the imperative programming style. Generics generic capacity: in positive; type Item is private; package queue_class is procedure append(newitem : in Item); procedure remove(olditem : out Item); end queue_class; More Generics package body queue_class is items : array (1..capacity) of Item; size, front, rear : Integer range 0..capacity; procedure append(newitem : in Item) is begin ... items(rear):= newitem; ...; end; procedure remove(olditem : out Item) is begin ... olditem:= items(front); ...; end end; begin front:= 1; rear:= 0; end queue_class; Using queue_class package line_buffer is new queue_class(120, Character); type Transaction is record ... end record; package audit_trail is new queue_class(100, Transaction); T: Transaction; ... line_buffer.append('*'); ... audit_trail.remove(T); Generics with Dependent Types generic type Item is private; type Sequence is array (Integer range <>) of Item; with function precedes (x,y: Item) return Boolean; package sorting is procedure sort(seq : in out Sequence); procedure merge(seq1, seq2 : in out Sequence; seq : out Sequence); end sorting; Sorting (body) package body sorting is procedure sort(seq : in out Sequence) is begin ...; if precedes(seq(i), seq(j)) then ...; ...; end; procedure merge(seq1, seq2 : in out Sequence; seq : out Sequence) is begin ...; end; end sorting; Using Generic type Float_sequence is array(Integer range <>) of Float; package ascending is new sorting(Float, Float_sequence, "<="); package descending is new sorting(Float, Float_sequence, ">="); ... type Trans_sequence is array(Integer range <>) of Transaction; function earlier(t1, t2 : Transaction) return Boolean is ...; --return true if t1 precedes t2 end earlier; package transaction_sorting is new sorting(Transaction, Trans_sequence, earlier); Arguments in Ada Procedure/Function abstraction Generic abstraction argument type First class value yes yes Reference to a variable yes yes Procedure/function abstraction no yes type no yes • Oddity that Ada does not allow procedure/function arguments to procedures and functions. • Not unusual to not allow type parameters to procedures/functions.