Go to the first, previous, next, last section, table of contents.


6.9.3 Redundant Ensures Clauses or Claims

Another kind of redundancy in a function specification is a redundant ensures clause or claim [Tan94]. These have the same syntax as normal ensures-clauses, but use the keyword redundantly. (See section 6 Function Specifications for the syntax.)

A redundant ensures-clause is the dual of an example; instead of stating some property that implies the specification, it states some property that follows from a function specification.

In Larch/C++, a sequence of redundant ensures-clauses can be placed at the end of a spec-case, following the required non-redundant ensures-clause. Each redundant post-cond in such a redundant ensures-clause should be implied by the rest of the spec-case.

Redundant ensures-clauses do not affect the meaning of a function specification. They are, however, useful in highlighting properties of a function specification, or in helping debug the specification.

Each redundant ensures-clause applies to the spec-case of which it is a part. By nesting multiple spec-cases in a pair of curly brackets ({ }), however, one can use redundant ensures-clauses to talk about the entire function specification.

A redundant ensures-clause that uses the keyword liberally asserts a property of executions of the function that terminate normally, but does not require normal termination. A redundant ensures-clause that does not use the keyword liberally asserts the existence of a post-state with the desired properties. Hence ensures redundantly true; asserts that every execution of the function in which the precondition is satisfied always terminates.

As a simple example, consider the following function specification. The claimed postcondition (hereafter, simply "the claim") does not change the meaning of the specification from that given earlier (see section 6 Function Specifications) but it does highlight a property of the specification that is deducible using logic and facts about the integers.

// @(#)$Id: isqrt3.lh,v 1.11 1998/09/23 16:00:31 ruby Exp $
extern int isqrt(int x) throw();
//@ behavior {
//@   requires x >= 0;
//@   ensures (result-1)*(result-1) < x
//@          /\ x < (result+1)*(result+1);
//@   ensures redundantly ((((result - 1) * (result - 1)) < x)
//@            /\ (x <= (result * result)))
//@        \/ (((result * result) <= x)
//@            /\ (x < ((result + 1) * (result + 1))));
//@   example x = 28 /\ result = 5;
//@   example x = 28 /\ result = 6;
//@ }

The semantics of a redundant ensures-clause is that, if the precondition and postcondition are true, and the frame axioms given by the modifies-clause and trashes-clause are satisfied, then the claim (the redundant post-condition) should follow (see Section 5.2 of [Tan94]). That is, what has to be proved to verify a claim is the following [Tan94], where PreCondition is the (desugared) precondition of the function specification (which combines all the spec-cases), MP is the predicate that codes the modifies-clause (see section 6.2.3 The Modifies Clause), TP is the predicate that codes the trashes-clause (see section 6.3.2 The Trashes Clause), PostCondition is the (desugared) postcondition of the function specification, and Claim is the predicate from the redundant ensures-clause.

(PreCondition /\ MP /\ TP /\ PostCondition) => Claim

In cases where there are applicable invariants (see section 7.3 Class Invariants) or history constraints (see section 7.4 History Constraints) these can also be instantiated for the relevant objects and used to help prove the above formula. Thus, for example, in a class member function specification, where there are no class instances other than self involved, it will suffice to prove the following, where Invariant(pre) is the invariant with the to the pre-state (pre) substituted for the state any used to express the invariant, Invariant(post) is the invariant applied to the post-state, HistoryConstraint is the history constraint, and the other symbols are as above. (The history constraint is true if omitted.)

(PreCondition /\ Invariant(pre) /\ MP /\ TP
 /\ PostCondition /\ Invariant(post) /\ HistoryConstraint)
   => Claim

Such a proof should be carried out for each redundant ensures-clause in the ensures-clause-seq.

See [Tan94] for more examples. (Larch/C++ currently only supports what Tan calls "procedure claims".)


Go to the first, previous, next, last section, table of contents.