Algebraic specifications

Dr. Constantinos Constantinides, P.Eng.

Department of and Software Engineering Concordia University Montreal, Canada

7 January, 2020

1/101 Types

◮ A type is a collection of values. ◮ Examples of types include the integer or the Boolean type. ◮ We can distinguish between simple types and composite (or aggregate) types based on whether or not the values of a type can contain subparts. ◮ As an example, we can say that the integer type is simple, whereas a student record is a composite . ◮ A data item is an instance (also: a member) of a type.

2/101 Abstract data types

◮ An (ADT) is a mathematical model: A definition for a type solely in terms of the of values and a set of operations on that type. ◮ The behavior of each operation is determined by its inputs and outputs. ◮ This implies that an ADT is implementation-independent.

3/101 Data types (or concrete data types)

◮ A (concrete) data type is the concrete description of how an ADT is actually implemented. ◮ For example in int x = 7;, we instruct the compiler about the type of variable x (and implicitly about the legal operations as well as about its range of values).

4/101 ADTs and data structures

◮ Do not confuse ADTs with data structures. The former are abstract definitions solely in terms of interfaces, whereas the latter are particular ways of storing and organizing data. ◮ Data structures can be deployed in order to define ADT’s.

5/101 Formal specifications and algebraic specifications

◮ A formal specification is a mathematical description of software system. ◮ It describes what the system should do, but not necessarily how it should do it. ◮ An algebraic specification is a technique that supports the specification of a system through its representation as a collection of sets together with a description of operations on the sets.

6/101 Formal specifications and algebraic specifications /cont.

◮ This aligns with the notion of an abstract data type. ◮ Each specification has a name (with an optional generic parameter list) and a body. ◮ Generic parameters allow abstract types which are collections of other types (such as lists and stacks) to be specified without committing to a particular type of the elements in the collection.

7/101 Abstraction: Interfaces and information hiding

◮ Clients of a system need to know what services a system provides (i.e. what operations are provided by the of the system). ◮ Implementors may provide an initial implementation which they can subsequently modify in order to improve performance or other non-functional requirement.

8/101 Specification

◮ A specification consists of five parts:

1. A declaration of the sort (type) of the entity to be specified and possibly an import of other specifications to be reused in the current specification.

2. Informal description of its operations.

3. Signatures of operations (syntax).

4. Variables (to be used in axioms).

5. Axioms: Statements (rules) that must always hold (semantics: meaning of operations).

9/101 Operations on ADTs

◮ Operations can be classified into the following:

◮ Primitive constructors take no arguments and create objects of the underlying abstract data type.

◮ Non-primitive constructors take arguments and create objects.

◮ Mutators access an object in order to write.

◮ Observers access an object in order to read.

10/101 Example: The Boolean ADT Declaration of the sort and signatures of operations

Spec: Boolean; Sort: Boolean; Operations: true → Boolean; false → Boolean; not : Boolean → Boolean; and : Boolean × Boolean → Boolean; or : Boolean × Boolean → Boolean; impl : Boolean × Boolean → Boolean; bicond : Boolean × Boolean → Boolean; ◮ Signatures tell us how to form complex terms from primitive operations.

11/101 Axioms on ADTs

◮ Axioms specify the semantics (meaning) of the ADT, and they characterize its behavior. ◮ They are specified using the operations defined in the signature part. ◮ As a rule of thumb, we write an axiom for each inspection operation over each constructor or mutator operation.

12/101 Axioms on ADTs /cont.

◮ The specification may also include exceptions that define conditions under which the axioms do not hold. ◮ This can be done either by using undefined as the output of certain axioms (indicating that the evaluation of the operation results in an error), or by using an exceptions clause in the specification.

13/101 Example: The Boolean ADT: Variables and axioms

Variables: x, y: Boolean; Axioms: [A1] not(true)= false; [A2] not(false) = true; [A3] false and x = false; [A4] true and x = x; [A5] true or x = true; [A6] false or x = x; [A7] x or y = y or x; [A8] x and y = y and x; [A9] not (x and y) = (not x) or (not y); [A10] not (x or y) = (not x) and (not y); [A11] x impl y = not(x) or y; [A12] x bicond y = (x impl y) and (y impl x);

14/101 Example: The Boolean ADT Discussion on Axioms

◮ Axioms A7 and A8 capture the commutativity of conjunction and disjunction respectively: ◮ xory=yorx: (x ∨ y) ⊢ (y ∨ x) , and ◮ xandy=yandx: (x ∧ y) ⊢ (y ∧ x)

15/101 Example: The Boolean ADT Discussion on Axioms /cont.

◮ Axioms A9 and A10 capture De Morgan’s Laws: ◮ not (x and y) = (not x) or (not y) : ¬(x ∧ y) ⊢ (¬x ∨¬y), and ◮ not (x or y) = (not x) and (not y) : ¬(x ∨ y) ⊢ (¬x ∧¬y)

16/101 Example: The set of natural numbers Declaration of the sort

Spec: Natural; Sort: Nat; Imports: Boolean;

17/101 Example: The set of natural numbers Informal description of operations

Description: Operations on natural numbers include succ which returns the successor number, and add which adds two natural numbers.

18/101 Example: The set of natural numbers Signatures of operations

Operations: zero → Nat; iszero : Nat → Boolean; succ : Nat → Nat; add : Nat × Nat → Nat;

19/101 Signatures of operations

◮ For variables x, y : Nat, the following terms are legal: ◮ iszero(succ(x))

◮ add(succ(x), y)

◮ The following term is not legal ◮ succ(iszero(x))

20/101 Example: The set of natural numbers Variables and axioms

Variables: x, y : Nat; Axioms: [A1] iszero(succ(x)) = false; [A2] add(zero, x) = x; [A3] add(succ(x), y) = add(x, succ(y));

21/101 Example: The Set ADT

◮ Consider the ADT Set. ◮ Since a set can hold a collection of elements of any type, we will include a generic parameter Element in the specification.

22/101 Example: The Set ADT Declaration of the sort

Spec: Set (Element); Sort: Set; Imports: Boolean, N0;

23/101 Example: The Set ADT Description of operations

◮ newset creates an empty set. ◮ add (Set, Element) adds Element into Set. ◮ remove (Set, Element) removes Element from Set. ◮ size(Set) returns the number of elements in Set. ◮ isempty(Set) returns true if Set contains no elements and it returns false otherwise. ◮ ismember(Set, Element) returns true if Element is a member of Set and it returns false otherwise.

24/101 Example: The Set ADT Signatures of operations

Operations:

newset → Set; add : Set × Element → Set; remove : Set × Element → Set; size : Set → N0; isempty : Set → Boolean; ismember : Set × Element → Boolean;

25/101 Example: The Set ADT Variables and axioms

Variables: s: Set; x, y: Element;

Axioms: [A1] isempty(newset) = true; [A2] ismember(newset, x) = false; [A3] ismember(add(s, x), x) = true;

26/101 Example: The Set ADT Axioms /cont.

The axiom [A1] isempty(newset) = true;

can be also captured by size(newset) = 0;

27/101 Example: The Set ADT Axioms /cont.

◮ The axiom [A4] add(add(s, x), y) = add(add(s, y), x) ensures that the order is not important in sets.

28/101 Example: The Set ADT Axioms /cont.

◮ The axiom [A5] size(add(add(newset, x), x)) = 1 ensures that no repetitions are allowed.

◮ An alternative axiom would be add(add(newset, x), x) = add(newset, x)

29/101 Example: The Set ADT Axioms /cont.

[A6] size(add(s, x)) = if (not(ismember(s, x))) then size(s) + 1 else size(s);

30/101 This slide is left empty.

31/101 Example: The Set ADT Axioms are universally quantified

◮ Note that we interpret each axiom as being universally quantified by all variables appearing in it. ◮ For example, the axiom [A3] ismember(add(s, x), x) = true; is an abbreviation of ∀(s : Set, x : Element) | ismember(add(s, x), x)= true;

32/101 Example: String Declaration of the sort

Spec: String; Sort: String; Imports: Char, N0, Boolean;

33/101 Example: String Description of operations

Description: Operation new creates an empty string, append concatenates two strings, add places a at the end of a string, length returns the size of the string, isempty returns true if the string is empty and it returns false otherwise, and equal compares two strings for equality.

34/101 Example: String Signatures of operations

Operations: new → String; append : String × String → String; add : String × Char → String; length : String → N0; isempty : String → Boolean; equal : String × String → Boolean;

35/101 Example: String Variables and axioms

Variables: x, y, z: String; : Char; Axioms: [A1] isempty(new) = true; [A2] length(new) = 0; [A3] isempty(add(x, c)) = false; [A4] length(add(x, c)) = length(x) + 1; [A5] append(x, new) = x; [A6] append(x, add(y, c)) = add(append(x, y), c); [A7] equal(new, new) = true; [A8] equal(new, add(new, c)) = false;

36/101 Example: Array Declaration of the sort

Spec: Array (Element); Sort: Array; Imports: N;

37/101 Example: Array Description of operations

Description: ◮ Arrays are collections of elements of generic type Element. They have a lower and an upper bound returned by operations first and last. ◮ Individual elements are accessed by their numeric indices. ◮ Operation create takes a lower and an upper bound parameter and constructs an array, initializing its values to undefined. ◮ Operation assign places an element in the given index. ◮ Operation eval returns the element at a given index.

38/101 Example: Array Signatures of operations

Operations: create : N × N → Array; assign : Array × N × Element → Array; first : Array → N; last : Array → N; eval : Array × N → Element;

39/101 Example: Array Variables and axioms

Variables: x, y, z : N; el : Element; arr : Array; Axioms: [A1] first(create(x, y)) = x; [A2] last(create(x, y)) = y; [A3] eval(create (x, y), z) = undefined; [A4] eval(assign(arr, x, el), y) = if (y < first(arr) or y > last(arr)) then undefined else if (y = x) then el else eval(arr, y);

40/101 Example: The Bag ADT

◮ Consider the ADT Bag. ◮ Since a set can hold a collection of elements of any type, we will include a generic parameter Element in the specification.

41/101 Example: The Bag ADT Declaration of the sort

Spec: Bag (Element); Sort: Bag; Imports: Boolean, N0;

42/101 Example: The Bag ADT Description of operations

◮ newbag creates and returns an empty bag. ◮ add (Bag, Element) adds Element into Bag and returns an updated bag. ◮ remove (Bag, Element) removes Element from Bag and returns an updated bag. ◮ size(Bag) returns the numbers of elements currently held in the collection. ◮ isempty(Bag) returns true if Bag contains no elements and it returns false otherwise. ◮ ismember(Bag, Element) returns true if Element is a member of Bag and it returns false otherwise.

43/101 Example: The Bag ADT Description and operations /cont.

Operations: newbag → Bag; add : Bag × Element → Bag; remove : Bag × Element → Bag; size : Bag → N0; isempty : Bag → Boolean; ismember : Bag × Element → Boolean;

44/101 Example: The Bag ADT Variables and axioms

Variables: b : Bag; x, y : Element;

Axioms: [A1] size(newbag) = 0; [A2] isempty(newbag) = true; [A3] ismember(newbag, x) = false; [A4] ismember(add(b, x), x) = true; [A5] add(add(b, x), y) = add(add(b, y), x);

45/101 Example: The Bag ADT Variables and axioms /cont.

Variables: b : Bag; x, y : Element;

Axioms: [A6] size(add(add(newbag, x), x)) = 2; [A7] size(add(b, x)) = size(b) + 1; [A8] ismember(remove (add (newbag, x), x), x) = false;

46/101 Example: The List ADT

◮ Consider the specification of a list. ◮ Since a list can hold a collection of elements of any type, we will include a generic parameter Element in the specification.

47/101 Example: The List ADT Declaration of the sort

Spec: List (Element); Sort: List; Imports: Boolean, N0;

48/101 Example: The List ADT Description of operations

◮ newlist returns an empty list. ◮ (Element, List) creates a list with Element as the head and List as the tail. ◮ head(List) returns the head of List. ◮ tail(List) returns the tail of List. ◮ length(List) returns the length of List. ◮ concatenate (List1, List2) joins two lists (in the order specified) and returns a new list.

49/101 Example: The List ADT Signature of operations

Operations: newlist → List; concatenate: List × List → List; cons: Element × List → List; tail: List → List; head: List → Element; length: List → N0;

50/101 Example: The List ADT Variables and axioms

Variables: lst, lst2: List; el: Element; Axioms: [A1] length (newlist) = 0; [A2] head (newlist) = undefined; [A3] length(lst) = 0 → (head (lst)) = undefined; [A4] head (cons (el, lst)) = el; [A5] tail (cons (el, lst)) = lst; [A6] length (cons (el, lst)) = length (lst) + 1;

51/101 Example: The List ADT Variables and axioms /cont.

Variables: lst, lst2: List; el: Element; Axioms: [A7] head (concatenate (lst, lst2)) = head (lst); [A8] tail (concatenate (lst, lst2)) = concatenate (tail(lst), lst2); [A9] length (concatenate (lst, lst2)) = length (lst) + length (lst2);

52/101 Example: The List ADT Handling exceptions

◮ Note that for [A3] we could alternatively have specified the following: Axioms: lst = (newlist) → failure (head (lst)); length(lst) = 0 → failure (head (lst));

53/101 Example: The Stack ADT

◮ Consider the specification of an unbouded stack. ◮ The stack ADT defines a container of objects that are inserted or removed according to a last-in-first-out (LIFO) protocol. ◮ There are two major stack operations: push inserts an element onto the stack, and pop removes the last inserted element and returns an updated stack. ◮ Note that both major operations access the stack from the same end.

54/101 Example: The Stack ADT /cont.

◮ Furthermore, there are some auxiliary operations: top returns the last inserted element without removing it from the collection, size returns the number of elements stored, isempty returns a Boolean value indicating whether no elements are stored in the collection. ◮ Since a stack can hold a collection of elements of any type, we will include a generic parameter Element in the specification.

55/101 Example: The Stack ADT Declaration of the sort

Spec: Stack (Element); Sort: Stack; Imports: Boolean, N0;

56/101 Example: The Stack ADT Description of operations

◮ newstack returns an empty stack. ◮ push (Stack, Element) adds Element as the top element of the stack. ◮ pop (Stack) returns a stack with the topmost element removed. ◮ top (Stack) returns (but does not remove) the top element of the stack. ◮ size (Stack) returns the current number of items in the stack. ◮ isempty(Stack) returns true if the collection is empty, and it returns false otherwise.

57/101 Example: The Stack ADT Signature of operations

Operations: newstack → Stack; push: Stack × Element → Stack; pop: Stack → Stack; top: Stack → Element; size: Stack → N0; isempty: Stack → Boolean;

58/101 Example: The Stack ADT Variables and axioms

Variables: s: Stack; el: Element; Axioms: [A1] size (newstack) = 0; [A2] isempty (newstack) = true; [A3] pop (newstack) = undefined; [A4] top (newstack) = undefined; [A5] pop (push (s, el)) = s; [A6] top (push (s, el)) = el; [A7] isempty (pop (push (newstack, el))) = true; preconditions pre : pop( s : stack ) = not isempty(s); pre : top( s : stack ) = not isempty(s); end

59/101 Example: The Stack ADT Preconditions to axioms

◮ Note that in addition to the axioms characterizing the behavior of the ADT Stack, we have included two preconditions for pop and top as follows:

preconditions pre : pop( s : stack ) = not isempty(s); pre : top( s : stack ) = not isempty(s); end

60/101 The Stack ADT: Axioms /cont.

◮ The axiom isempty (pop (push ((newstack), el))) = true; implies that operations push and pop are mutually inverse.

61/101 Example: The Queue ADT

◮ Consider the specification of an unbounded queue. ◮ The queue ADT defines a collection that stores arbitrary objects. ◮ Insertions and deletions follow a first-in first-out (FIFO) protocol. ◮ There are two major queue operations: enqueue inserts an element at the rear of the queue and returns a queue, and dequeue removes the element at the front of the queue and returns a queue.

62/101 Example: The Queue ADT /cont.

◮ Additionally, there are some auxiliary operations: front returns the front element without removing it from the collection, size returns the number of elements stored, and isempty returns a Boolean value indicating whether no elements are stored. ◮ Note that the two major operations access the queue from two different ends: the front and the rear. ◮ Since a queue can hold a collection of elements of any type, we will include a generic parameter Element in the specification.

63/101 Example: The Queue ADT Declaration of the sort

Spec: Queue (Element); Sort: Queue; Imports: Boolean, N0;

64/101 Example: The Queue ADT Description of operations

◮ newqueue returns an empty queue. ◮ enqueue (Element) inserts Element to the rear of the queue. ◮ dequeue returns a queue with the element from the front of the queue removed. ◮ front returns (but does not remove) the front element. ◮ size returns the number of elements in the collection. ◮ isempty returns true if there are no elements in the collection and it returns false otherwise.

65/101 Example: The Queue ADT Description and operations /cont.

Operations: newqueue: → Queue; enqueue: Queue × Element → Queue; dequeue: Queue → Queue; front: Queue → Element; size: Queue → N0; isempty: Queue → Boolean;

66/101 Example: The Queue ADT Variables and axioms

Variables: q : Queue; x, y : Element; Axioms: [A1] size (newqueue) = 0; [A2] isempty(newqueue) = true; [A3] dequeue(newqueue) = undefined;

67/101 Example: The Queue ADT Variables and axioms /cont.

◮ The axiom [A4] isempty (dequeue (enqueue ((newqueue), x))) = true; implies that operations enqueue and dequeue are mutually inverse.

[A5] (isempty(q) = true) → (dequeue (q) = undefined); [A6] front(newqueue) = undefined;

68/101 Example: The Queue ADT Variables and axioms

Variables: q : Queue; x, y : Element; Axioms: [A7] front(enqueue(q, x)) = if isempty(q) then x else front(q);

69/101 Example: The Queue ADT Variables and axioms

◮ The axiom [A8] front (enqueue ((enqueue ((newqueue), x)), y)) = x; implies that the ADT implements a FIFO protocol.

70/101 Example: A Cartesian Point

◮ Consider a point that represents a pair of cartesian coordinates.

71/101 Example: A Cartesian Point Declaration of the sort

Spec: Point; Sort: Point; Imports: R, Boolean;

72/101 Example: A Cartesian Point Description of operations

◮ newpoint that takes a pair of coordinates and returns a new point. ◮ getX(point) and getY(Point) return the x or y coordinate respectively. ◮ move(Point, Point) places the point to a new set of coordinates. ◮ equal(Point, Point) returns true if the two points lie on the same set of coordinates, and it returns false otherwise.

73/101 Example: A Cartesian Point Description and operations /cont.

Operations: newpoint: R × R → Point; getX: Point → R; getY: Point → R; move: Point × Point → Point; equal: Point × Point → Boolean;

74/101 Example: A Cartesian Point Variables and axioms

Variables: w, x, y, z: R; Axioms: [A1] getX (newpoint(x, y)) = x; [A2] getY (newpoint(x, y)) = y; [A3] getX (move (newpoint(u, v), newpoint(w, z))) = w; [A4] getY (move (newpoint(u, v), newpoint(w, z))) = z; [A5] equal (newpoint (x, y), newpoint (w, z)) = if (x = w) and (y = z) then true else false;

75/101 Example: The Map ADT Declaration of the sort

Spec: Map (Key, Element); Sort: Map; Imports: N0, Boolean; Description: A map (Dictionary) ADT.

76/101 Example: The Map ADT Description of operations

◮ create : Creates and returns an empty map. ◮ put (Key, Element) : puts the (Key, Element) pair into the map. If Key already exists in the map, then Element replaces the existing element. Returns an updated map. ◮ get (Key) : Returns the element of the pair associated with Key, or it returns null if Key was not found. ◮ remove (Key) : Removes the pair associated with Key in the map. Returns null if Key was not found; otherwise, it returns the Element associated with Key.

77/101 Example: The Map ADT Description of operations /cont.

◮ containsElement (Element) : Determines whether the map contains a pair that includes the Element. Returns true if Element is found, and it returns false otherwise. ◮ containsKey (Key) : Determines whether the map contains a pair that includes the Key. Returns true if Key is found, and it returns false otherwise. ◮ isempty : Determines whether the collection is empty. Returns true if the collection is empty and it returns false otherwise. ◮ clear : Erases all entries from the collection. ◮ size : Returns the number of pairs currently stored the collection.

78/101 Example: The Map ADT Signatures of operations

Operations: create → Map; put: Map × Key × Element → Map; get: Map × Key → Element; remove: Map × Key → Element; containsElement: Map × Element → Boolean; containsKey: Map × Key → Boolean; isempty: Map → Boolean; clear: Map → Map; size: Map → N0;

79/101 Example: The Map ADT Variables and axioms

Variables: m: Map; k, k2: Key; el: Element; Axioms: [A1] size (create) = 0; [A2] isempty (create) = true; [A3] size(clear(m)) = 0; [A4] isempty(clear(m)) = true;

80/101 Example: The Map ADT Variables and axioms /cont.

Variables: m: Map; k, k2: Key; el: Element; Axioms: [A5] put(m, k, el) → containsElement(m, el) ∧ containsKey(m, k); [A6] isempty (put (m, k, el)) = false; [A7] size (put (m, k, el)) = if not (containsKey(m, k)) then size(m) + 1 else size(m); [A8] remove (put (m, k, el), k) = el;

81/101 Reusing specifications

◮ The importance of reuse lies on the fact that it allows the deployment of proven solutions in different contexts, thus speeding up the development process, cutting down costs, increasing productivity and improving the quality of software. ◮ We have two mechanisms that support reuse: 1 Importing and using simple specifications in complex ones. This is analogous to delegation in OOP. 2 Specification enrichment. This is analogous to inheritance in object-oriented programming (OOP).

82/101 Reusing specifications through specification enrichment

◮ As ADT’s define types, enrichment of ADT’s is analogous to inheritance in object-oriented programming which is a mechanism that can create a related set of types: ◮ Type T2 is a subtype of Type T1 (and consequently T1 is a supertype of T2) if every legitimate instance of T2 is also a legitimate instance of T1, implying that an instance of the subtype T2 can appear wherever an instance of the supertype is expected.

83/101 Reusing specifications through specification enrichment /cont.

◮ We can reuse existing specifications to define new ADT’s by incrementally adding more operations and axioms. ◮ The extended version inherits the sorts, operations and axioms defined in the original presentation. ◮ Additionally, new operations may override operations with the same name in the base sort.

84/101 Example: Ternary

◮ The specification below extends Natural to define a new sort Ternary:

Spec: NaturalModulo3 extend Natural by Sort: Ternary; Axioms: succ(succ(succ(zero))) = zero;

85/101 Example: Subclassifying List to define a (bounded) Stack: Declaration and operations

Spec: Stack (Element); Sort: Stack; extend List (Element) by Description: Omitted here. Operations: newstack → Stack; push: Stack × Element → Stack; pop: Stack → Stack; top: Stack → Element; isfull: Stack → Boolean;

86/101 Example: Subclassifying List to define a (bounded) Stack: Variables and Axioms

Variables: s: Stack; el: Element; Capacity: N1; Axioms: [A1] pop (newstack) = undefined; [A2] top (newstack) = undefined; [A3] top (push (s, el)) = el; [A4] push(s, el) = cons (el, s); preconditions pre : push( s : stack, el: Element ) = (length(s) < Capacity); end

87/101 Example: Subclassifying List to define a (bounded) Stack: Variables and Axioms

Variables: s: Stack; el: Element; Capacity: N1; [A5] pop(s) = tail(s); preconditions pre : pop( s : stack ) = (length(s) > 0); end

88/101 Example: Subclassifying List to define a Queue

Spec: Queue (Element); Sort: Queue; extend List (Element) by Description: (Omitted.) Variables: q: Queue; el: Element; Axioms: [A1] enqueue (q, el) = concatenate (q, cons(el, nil)); [A2] dequeue (q) = tail(q);

89/101 Example: Subclassifying Stack to define BStack

◮ Consider the specification of a bounded stack, BStack, which is an extension (and a subtype) of the Stack ADT defined previously. ◮ In the extended specification, a new element can be pushed onto the stack only if the size of the stack has not yet reached its maximum capacity.

90/101 Example: Bounded Stack Declaration of the sort and description and signatures of operations

Spec: Bounded Stack (Element); Sort: BStack; extend Stack (Element) by Description: A new definition of newstack will return a BStack of non-zero capacity. A new operation isfull returns true if the collection has reached its maximum capacity, and it returns false otherwise. Operations: newstack → BStack; isfull: BStack → Boolean;

91/101 Example: Bounded Stack Variables and axioms

Variables: s: BStack; Capacity: N1; Axioms: [A1] isfull(s) = if (size(s) = Capacity) then true else false;

92/101 Example: Bounded Stack Variables and axioms

Variables: s: BStack; Capacity: N1; Axioms: [A2] size (push (s, el)) = if (not(isfull(s))) then size(s) + 1 else Capacity; preconditions pre : push( s : BStack ) = not isfull(s); end

93/101 Example: Subclassifying Map to define BMap Declaration of the sort and operations

Spec: Bounded Map (Key, Element); Sort: BMap; Imports: None. extend Map (Key, Element) by Description: A new definition of create returns an empty bounded map of non-zero capacity, and isfull returns true if the number of elements in the collection have reached the maximum capacity of the collection; it returns false otherwise. Operations: create → BMap; isfull: BMap → Boolean;

94/101 Example: BMap Variables and Axioms

Variables: m: BMap; k: Key; el: Element; Capacity: N1; Axioms: [A1] isfull(create) = false; [A2] isfull(m) = if (size(m) = Capacity) then true else false;

95/101 Example: BMap Variables and Axioms

[A3] size (put (m, k, el)) = if (isfull(m) ∨ containsKey(m, k)) then size(m) else size(m) + 1; preconditions pre : put( m : Map, k: Key, e: Element ) = not isfull(m); end

96/101 Recommendations for specification enrichment

◮ We may consider the following design recommendations for enrichment: ◮ First and foremost, use specification enrichment to model an is-a relationship. For example, a linked list is a list, but neither a stack nor a queue are vectors. ◮ Place common features in the specification of the supetype.

97/101 Types of specification enrichment

◮ Drawing analogies from OOP and based on the objective for its deployment, we can identify the following types of specification enrichment: ◮ Specialization: This is the most common use of enrichment. The extended ADT is a specialized version of the parent ADT, and thus satisfies the interface of the parent ADT in all relevant aspects, adding any particular behavior through overriding. Extended specifications are subtypes. The bounded stack example described above is one such case. ◮ Specification: This type of inheritance is deployed to enforce an interface on a type. The subtype implements the abstract specification of the parent ADT. Subclasses are subtypes.

98/101 Types of specification enrichment /cont.

◮ Construction: There is no logical relationship between the two ADTs. An extended specification inherits functionality to be reused for practical reasons. Extended specifications are not necessarily subtypes. ◮ Extension: An extended specification merely adds new behavior and does not modify or alter any of the inherited features. Extended specifications are subtypes.

99/101 Types of specification enrichment /cont.

◮ Limitation: The behavior in the extended ADT is smaller or more restrictive than the behavior of the parent ADT. Extended ADTs are not subtypes. ◮ Combination: An extended specification is formed by combining features from more than one parent specifications.

100/101 Disadvantages of algebraic specifications

◮ Algebraic specifications are not adequate when we have to define procedures that have side effects. ◮ A procedure is said to produce a side effect if it modifies some state in addition to its return value. ◮ For example, a procedure might modify some global variable, modify one of its arguments, write data to a display or file, or read some data from other side-effecting operations.

101/101