Lecture 02 Programming Abstractions
Joseph Haugh
University of New Mexico
Free Recall
- Open a blank text file or grab a piece of paper
- Think about and write down everything you can remember from last lecture and beyond
Searching for the Right Abstraction
- The language we speak relates to the way we think.
- The way we view programming affects the kinds of systems we construct.
- Thus, the level of abstraction impacts:
- Programming productivity
- Reasoning about programs
- Program analysis
- Formal verification
Control Abstractions
- Flow of control defines the order in which instructions are executed.
- Sequential flow of control is built into most machines (program counter)
- Conditional jumps allow the interpreter to skip and/or repeat code segments
- if and goto statements provide a more uniform treatment by separating the condition from the flow of control transfer.
- Further reductions in complexity are achieved by the shift to structured programming
- Exceptions provide a structured mechanism for handling error conditions
Procedural Abstractions
- Procedural abstractions laid the foundation for modular design.
- Macro substitution offered a mechanism for naming sections of code and inserting them as needed
- Subroutines (non-recursive), introduced as a memory saving device, structured the flow of control
- Blocks provide an in-line structuring construct central to all modern programming languages
- Procedures (recursive) encapsulate processing, thus eliminating the need to look at the way they are coded (if a specification exists!)
- Functions (pure) are procedures without side effects
Data Abstraction
- Data is central to the representation of state.
- Built-in data types provide essential but primitive forms of data representation and operations on them
- Programmer-defined types facilitate tailoring data selection to the specifics of the application
- Statically typed languages improve dependability by doing strict compile-time checking
Data Abstraction Cont.
- Abstract data type (ADT) is a formal characterization of a set of data structures sharing a common set of operations
- Generic types (e.g., generics in Java) allow for parameterized definitions
Concurrency
- Concurrency impacts the choice of components and connectors.
- Coroutines introduced the notion of passing the flow of control among subroutines
- Concurrent process (e.g. thread in Java) provides for logically parallel execution
- Inter-process communication assumes a variety of forms:
- Shared variables
- Message passing
- Remote procedure call
- Synchronization (mutual exclusion, barriers, etc.)
Functions Revisited
- As in mathematics, a function defines a transformation from its inputs to the outputs.
- It has no side effects (no memory and no changes in the program state)
- It is deterministic (same inputs generate the same outputs every time)
Function Example: factorial
- factorial(n) where n is a natural number returns
- 1 if n = 0
- n ⋅ (n − 1) ⋅ ⋅ ⋅ 1 if n > 0
- Functions are often defined recursively
- factorial(n) returns
- 1 if n = 0
- n * factorial (n − 1) if n > 0
- What happens if n is an integer?
- factorial(n) returns
- error if n < 0
- 1 if n = 0
- n * factorial (n − 1) if n > 0
Factorial in Java
public static int factorial(int n) throws ArithmeticException {
if (n < 0) throw new ArithmeticException();
else if (n == 0 || n == 1) return 1;
return n * factorial (n - 1);
}
public static int factorial (int n) {
if (n < 0) {
System.err.println("Error: Factorial is undefined" +
" for negative integers.");
return 0;
}
else if (n == 0 || n == 1) return 1;
return n * factorial (n - 1);
}
Axiomatic Specification
- A mathematical relation between the input and output values.
- Assertions represent a convenient abstract mechanism for function specification
- An assertion is a logical fact that is true about the state of the program at some point in its execution
- Some programming languages provide assertions as built-in constructs
- A pre-assertion defines the relevant properties of the input values
- A post-assertion defines the relevant properties of the output value
Axiomatic Spec: Sort
Sort(X) returns Y
- pre:
- X is an array of integers indexed from 0 to N
- post:
- Y is an array of integers indexed from 0 to N
- Y is sorted in ascending order
- any integer k occurs the same number of times in both X and Y
Operational Specification (Pseudocode)
- An operational specification is an abstract program that:
- Establishes the desired relation between inputs and outputs
- Places no restrictions on how the function is ultimately coded
- Any code that accomplishes the same transformation is acceptable
- Some coding solutions may be more efficient than others
Pseudocode: Sort
Sort(X) returns Y
- given:
- X is an array of integers indexed from 0 to N
- Y is an array of integers indexed from 0 to N
- copy X into Y
- while (there exists i and j such that i < j and Y [i] > Y [j])
Sort in Java: bubblesort
public static int[] bubbleSort(int[] ary) {
// assert ary.length > 0;
int length = ary.length-1;
boolean swap = true;
while(swap) {
swap = false;
for(int i = 0; i < length; i++) {
if(ary[i + 1] < ary[i]) {
int tmp = ary[i];
ary[i] = ary[j];
ary[j] = tmp;
swap = true;
}
}
}
return ary;
}
Sort in Java: quicksort
public static void quickSort(int[] ary, int low, int high) {
if(ary == null || ary.length == 0) return;
if(low >= high) return;
int mid = low + (high - low) / 2;
int pivot = ary[mid];
int i = low, j = high;
while(i <= j) {
while(ary[i] < pivot) i++;
while(ary[j] > pivot) j--;
if(i <= j) {
int tmp = ary[i];
ary[i] = ary[j];
ary[j] = tmp;
i++;
j--;
}
}
if(low < j) quickSort(ary, low, j);
if(high > i) quickSort(ary, i, high);
}
Procedures Revisited
- Procedures, in contrast to functions, may have side effects due to:
- Local variables
- Access to resources
- Access to devices
- The result of invoking a procedure may lead to:
- Returning data whose values depend on the internal state of the procedure
- Changes in the internal state of the procedure
- The specification methods are similar except for:
- The treatment of the internal state!
Abstract State Specification
- The internal state (e.g., data structures) of a procedure may be highly complex
- Proper abstraction of the internal state simplifies greatly the specification
- Users of the procedure need not be exposed to the internal data representation
- Internal representation may change over time
- Specification is not affected
- Code may be drastically affected
Documentation Implications (1/2)
- Pre and Post assertions are the best way to document procedures and methods.
- Assertions are very helpful when placed at critical junctions in the code.
- Pseudocode:
- is not as helpful as assertions in documenting code
- is very good at capturing processing logic, e.g., explicit task scheduling
- must be highly abstract with a typical ratio of 1:10 (text vs. code)
Documentation Implications (2/2)
- Focusing on an abstract state:
- is challenging
- simplifies documentation
- protects the documentation against implementation changes
- is primarily associated with object and class documentation