Lecture 4a: Interfaces and Protocols
Protocols
Beyond the signatures of a component’s, developers often also need to know about the calling protocol for the specified function. A protocol is a supplementary document that may specify the order of calls to methods and functions, properties of values across calls, global properties of calls, and so on.
In contrast to signatures, such properties tend to come in the form of comments. Checking them at compile time is always difficult, often impossible. Enforcing them with run-time checks calls for cumbersome coding and/or has a serious performance impact. None of this renders the articulation of protocols superfluous.
Example: Modifying Mutable Data Structures at a “Bad Time”
A simple but illustrative example of a protocol constraint is that iterators made from Java’s HashMaps are not modified during an iteration. Point your browser to the Java documentation for HashMaps and search for "modif". The English description of this global protocol constraint is enlightening.
Similarly, the Java documentation says “great care must be exercised if mutable objects are used as map keys.” But Java does not issue a warning when hash keys are modified and, indeed, a program may terminate after delivering ill-defined results. Again, enforcing this constraint completely would be difficult and expensive.
Example: Temporal Orderings or How Components Communicate
A file descriptor is a data representation of a device, say, a file, of your OS. It comes with two obvious pieces of functionality:
open, which connects the device (information) to an internal data representation for the purpose of reading from the device, writing to it, or both.
close, which disconnects the device from the program.
Additionally, it may come with operations for reading, writing, or positioning it to a particular point:
read, which retrieves some information from the file as data;
write, which turns data into file information; and
place, which may tell the OS where in the file the next operation takes place.
English, like the one just below the enumeration of operations;
finite state machine diagrams or regular expressions over method names;
diagrams, specifically UML interaction diagrams.
vertical lifelines, indicating the birth, life, and death of objects or services;
horizontal call-and-return lines, indicating creation and communication among objects and services.
OS CLIENT |
| | |
| <----------------------- | open(file,read-only) |
| | |
| new | |
|----> FileHandle | |
| | | |
| |<------------------| readJson() |
| | JSON | |
| |==================>| return |
| | | |
| . . |
| . . (repeat as often as needed) |
| . . |
| . . |
| |<------------------| readJson() |
| | JSON | |
| |==================>| return |
| | | |
| | | |
| | | |
| |<------------------| close() |
| | | |
| ___ | |
| | |
The diagram shows the “service side” in more detail than is common (and it is conceptual, too). From the perspective of CLIENT, the idea that the FileHandle exists independently of the OS is uninteresting. A specification may therefore hide this second lifeline.
Note If your protocol is about network connectivity, indicated which calls cross the networks with differently shaped message lines.