2000-05-09 Improved software quality through semantic descriptions (Skutt) Karlstad University Dept. of Computer Science Semla Design Method for use in Skywalker A Design Method with a Focus on Semantic Descriptions Karlstad University Ericsson Infotech AB NUTEK
29
Embed
Improved software quality through semantic descriptions (Skutt) Karlstad University Dept. of Computer Science 2000-05-09 Semla Design Method for use in.
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
2000-05-09 Improved software quality through semantic descriptions (Skutt)
Karlstad UniversityDept. of Computer Science
Semla Design Methodfor use in Skywalker
A Design Method with a Focus on Semantic Descriptions
Karlstad University
Ericsson Infotech AB
NUTEK
Semla 2 page 2Karlstad UniversityDept. of Computer Science
Overview
• Data abstractions
• Weak and strong contracts
• Invariants
Semla 2 page 3Karlstad UniversityDept. of Computer Science
An example: A web connection
• We want to model a possible connection across a network
– The other side may or may not be connected
– If connected, the other side has a defined user name which is copied across to our program
String* otherUser
WebConnection
the World Wide Web
The otherside
userName
Semla 2 page 4Karlstad UniversityDept. of Computer Science
Data abstractions
• This is one possible model of a Web connection
• I want to expose the property otherUser
• There is a difference between
– an empty user name, means "user name not known"
– no user name, means "there is no other party"
• Suggest a class interface
String* otherUser
WebConnection
Semla 2 page 5Karlstad UniversityDept. of Computer Science
First attempt
• Class interface
– String* getOtherUser();
• What is the mental process?
– Return whatever is stored in the object
– The user of the object needs to be aware of the storage conventions
String* otherUser
WebConnection
String* getOtherUser();
Semla 2 page 6Karlstad UniversityDept. of Computer Science
Contract for the first attempt
• Precondition:
– true
• Postcondition:
– result = the value of the otherUser variable
• What is gained in abstraction?
– Nothing, possibly R/O
– You might as well access the data directly
String* otherUser
WebConnection
String* getOtherUser();
• Calling style
theOther = connection->getOtherUser();
if (theOther != NULL)
doSomethingWith(theOther);
else
handleTheNoUserCase();
Semla 2 page 7Karlstad UniversityDept. of Computer Science
Second attempt
• Class interface
– bool hasOtherUser();
– String* getOtherUser();
• What is the mental process?
– Define the other user as a concept
• Either there is one or there is not
– The user of this object does not need to be aware of the storage conventions
• He works with the concept of ”another user" rather than with a stored value
(attributesnot
disclosed)
WebConnection
bool hasOtherUser();
String* getOtherUser();
Semla 2 page 8Karlstad UniversityDept. of Computer Science
Contract for the second attempt
• Precondition for hasOtherUser:
– true
• Postcondition for hasOtherUser:
– result = true if there is another user defined, else false
• What is the gain in abstraction?
– The fact that there may or may not be an "other user" becomes a property of the class, not a value of a variable
– No knowledge of the variable is needed to get the answer
– The answer may in fact be evaluated
WebConnection
bool hasOtherUser();
String* getOtherUser();
Semla 2 page 9Karlstad UniversityDept. of Computer Science
Consequences of the second attempt
• Possible calling style
if (connection->hasOtherUser())
{
theOther =
connection->getOtherUser();
doSomethingWith(theOther);
}
else
handleTheNoUserCase();
WebConnection
bool hasOtherUser();
String* getOtherUser();
Semla 2 page 10Karlstad UniversityDept. of Computer Science
What is the difference?
• Your module may be exposed to clients that are– yourself– trusted friends– colleagues within the same project– colleagues from other projects– external customers– API programmers– end users, through a user interface
• Who do you trust?– To whom do you expose a strong or a weak contract?
• A correct call is always your client’s responsibility– Even weak contracts fall back on the client– Error messages or exceptions must be caught by the client or user.
Semla 2 page 11Karlstad UniversityDept. of Computer Science
The implication of a contract
Precondition• A precondition is a Boolean
expression that must be true when an operation is called.
• A precondition is not a guard condition; it is a condition that must be true, not a way to optionally execute an operation.
• The condition is supposed to be true, and anything else is a programming error.
• It can be useful to test the precondition at the beginning of the operation for reliability, but this is in the nature of debugging a program.
Postcondition• A postcondition is a Boolean
expression that must be true after the execution of an operation completes.
• It is an assertion, not an executable statement.
• The condition is supposed to be true, and anything else is a programming error.
• It can be useful to test the postcondition after the operation, but this is in the nature of debugging a program.
Semla 2 page 12Karlstad UniversityDept. of Computer Science
The implication of a contract (cont’d)
Precondition• It is the responsibility of the caller
to satisfy the condition. It is not a condition that the receiver should have to check.
• If the condition is not satisfied, no statement can be made about the integrity of the operation of the system. It is liable to utter failure.
Postcondition• A postcondition imposes a
constraint on the implementor of an operation.
Source: Rumbaugh, J., Jacobson, I., Booch, G., The UML Reference Manual, Addison Wesley
1999. Parts of the descriptions have been rearranged to highlight similarities and differences.
Semla 2 page 13Karlstad UniversityDept. of Computer Science
When to use strong contracts?
• Strong contracts is the default mode
• Use strong contracts when
• the client is yourself, whom you trust to write good code
• the the client is a programmer.
– That is, whenever the client is a programmer, she/he can be trusted.
Semla 2 page 14Karlstad UniversityDept. of Computer Science
When to use weak contracts?
• Weak contracts are the exception
• Use weak contracts for
– end user communication (end users)
• cases where the end user may interfere
• user interfaces
– unforeseeable internal problems
• hardware problems
• communications problems
– very costly preconditions
• matrix inversion
• checking the precondition = doing the job
– concurrent processing
• another thread may break the precondition after the check
Semla 2 page 15Karlstad UniversityDept. of Computer Science
Example Array
• A class Array is an abstraction of a C int array
– an Array instance has a fixed lower index: 0
– an Array instance has a fixed number of elements defined at creation time
• Constructor:
– Array()
• Precondition: true
• Postcondition: number of elements = 0
– Array(int n)
• Precondition: n >= 0
• Postcondition: number of elements = n, all elements = 0
Semla 2 page 16Karlstad UniversityDept. of Computer Science
Example Array
• Properties for Array a
– int size()
• Precondition: true(*)
• Postcondition: the number of elements in the array is returned
• Data access and assignment for Array a
– a[i]
• Precondition: i >= 0 and i < a.size()
• Postcondition: a reference to the element at index ’i’ has been returned
• Usage of data access and assignment of Array a
– Data access
• n = a[i]
– Data assignment
• a[i] = n(*) The precondition true will not be written out. No precondition = true
Semla 2 page 17Karlstad UniversityDept. of Computer Science
Implementation details for Array
• Assume the data storage is through a pointer
– int *_data;
• Constructor Array(int n) {
// assign storage for i elements of int
_data = new int[n];
// initialize the elements to zero
for (int i = 0; i < n; i++)
_data[i] = 0;}
• No promises are given for illegal values of n
– Let the program crash if it wants. It is the client’s problem.
– Make the program crash if you want.
Constructor Array(int n) {
ASSERT (n >= 0) // validate the precondition
// the rest of the constructor
Semla 2 page 18Karlstad UniversityDept. of Computer Science
More implementation details for Array
• Data access
int &operator[](int i)
{
return _data[i];
}
• No promises are given for illegal values of i
– Let the program crash if it wants. It is the client’s problem
– Make the program crash if you want
int &operator[](int i)
{
ASSERT ( (i >= 0) && (i < size()) )
return _data[i];
}
– Any function called in the ASSERT must be side effect free
2000-05-09 Improved software quality through semantic descriptions (Skutt)
Karlstad UniversityDept. of Computer Science
Invariants
Semla 2 page 20Karlstad UniversityDept. of Computer Science
An invariant is ”always” true
• Established at creation
• Maintained by all functions
• Every function implementation can always assume that the invariant is true
• Every function implementation should always restore the invariant
• {I} means that the invariant is valid here
Establish
invariant
<<create>>
operation()Maintain
invariant
operation()Maintain
invariant
{I}
{I}
{I}
Semla 2 page 21Karlstad UniversityDept. of Computer Science
Invariant example
• Document invariants as comments
class WebConnection
{
String *otherUserName; // NULL if no user, else his name
}
• Complicated invariants are documented separately
class WebConnection
{
String *otherUserName;
// Invariant:
// otherUserName == NULL if no "other user" is defined
// *otherUserName == "" means "user exists but not known"
}
Semla 2 page 22Karlstad UniversityDept. of Computer Science
Invariants often document implementation issues
• The exact interpretation of and conventions for otherUserName is a private concern
– special values should not be known to the environment
– the “no user” case should be conveyed to the client through an abstraction
• boolean hasUser()
Semla 2 page 23Karlstad UniversityDept. of Computer Science
Are the invariants visible from the outside?
• The external aspects should be limited to those that are meaningful to the concept described and not tied to the implementation
• But sometimes there are invariant conditions that are given by the concept defined and independent of the implementation
• The size of an array is always >= 0
– So the size in the constructor must be >= 0 to establish the invariant
– Does not depend on the implementation
• The size of a list is always >= 0
– So the size must be >= 1 before a removal not to break the invariant
• Since a removal reduces the size by one
• which would make a negative size if not >= 1 before
• The implementation may add more invariants not visible outside
– size == 0 <=> _first == NULL
Semla 2 page 24Karlstad UniversityDept. of Computer Science
External and internal invariants
• External invariant
– Type invariant
– Abstraction invariant
– Relates to the abstraction itself, regardless of implementation
– Visible from outside
– Documented with the external documentation (API)
• Internal invariant
– Implementation invariant
– Tied to the specific implementation
– Not visible from outside
– Documented in the code only
LinkedList
add(element)find(element)...
LinkedNode
0..1
0..1
_first
client
External invariant:size() > 0
Internal invariant:_first == NULL <=> the list is empty_first != NULL => _first points to the first element in the list
Semla 2 page 25Karlstad UniversityDept. of Computer Science
An implementation invariant: linked list implementation
• A linked list head
• Invariant
– _first == NULL or _first points to the first element in the list
– _first == NULL <=> the list is empty
• Implementation
– constructor: establish invariant
LinkedList() {_first = NULL;} // an empty list
LinkedList
add(element)find(element)...
LinkedNode
0..1
0..1
– add: assume invariant at entry, restore invariant before exit
add(element) {
LinkedNode newNode = new LinkedNode(element);
if (_first == NULL) _first = newNode;
else appendAtEnd(newNode);
}
_first
client
Semla 2 page 26Karlstad UniversityDept. of Computer Science
Another implementation invariant: array implementation
• Data declaration
– int *_data;
– int _size;
• Invariant:
– _data != NULL
– more?
• Constructor Array(int n)
– _data = new int[n];
Array
int _size
Array(int)operator[](int)...
client
1
• Possible alternative invariant
– if _size > 0 then _data != NULL else _data == NULL
• Consequences for the constructor Array(int n)
– if (n == 0) _data = NULL; else _data = new int[n];
• Consequences for the indexing operator operator[](int i)
– none, the precondition assures a correct call
_data
int
Semla 2 page 27Karlstad UniversityDept. of Computer Science
Relations between invariants and pre- and postcontidions
• As a main rule, the invariant is always part of all preconditions and all postconditions
– follows from the definitions
• Part of the invariant is normally implementation oriented and the pre- and postconditions client oriented
– There is one set of pre- and postcondition of interest to the client
– There is another set of pre- and postcondition of interest for the implementation
– the precondition for the implementation =the precondition exported to the clients +the (external) invariant for the abstraction +the (internal) invariant for the implementation
– Similarly for the postcondition
Semla 2 page 28Karlstad UniversityDept. of Computer Science
Implement a queue using an array
• Data declaration
– int *_data;
– int _size;
• Invariant
– _data != NULL
– _size = number of used elements
– the first element is at _data[0]
Stack
int _size
Array(int)operator[](int)...
int1
• Consequence
– Positions 0 through size()-1 hold data
• Removal: remove()
– Precondition: size() > 0
– Implementation
{for (int i = 1; i < _size; i++) _data[i-1] = _data[i]; // maintains implementation invariant
_size = _size - 1;}
_data
client
Semla 2 page 29Karlstad UniversityDept. of Computer Science
Are invariants useful?
• An invariant should be stated explicitly
• Useful for the design
– Forces you to think over what you really want, since you should write it down
• Useful to maintain consistency over time
– Documents your decisions
– Helps you not change your mind halfway through
• Useful to support the implementation
– Tells you what you can rely on and what you need to accomplish in addition to the public preconditions and postconditions
• Useful for error detection
– Tests may be activated on the invariants to detect when :-) they are broken