Wrap function declarations such that they provide pre- and post-conditions. More...
Go to the source code of this file.
Macros | |
#define | ellipsis_invariant(COND, MESSAGE) |
#define | ellipsis_postcondition(COND, MESSAGE) |
#define | ellipsis_precondition(COND, MESSAGE) |
#define | EXBINDING(NAME) |
#define | INBINDING(NAME) |
Wrap function declarations such that they provide pre- and post-conditions.
This is a mechanism that is unfortunately not too easy to use, but does its job. Suppose you want to have a function interface
that returns the pointer to the object with the minimum value. With C++'s contracts I would like to add pre- and postconditions to that
That is, I want an assertion such that both pointers are non-null on entry and that the return value also is not null and equal to one of both pointer values. With some extensions that we have in eĿlipsis, we can formulate an inline interface of such a function as follows.
The private function minP_Inner
would then implement the feature itself, basically what usually would just be the definition of the function minP
.
Cooking up such interfaces manually has two disadvantages:
minP_Inner
, so optimization opportunities arising from this information can not be used within the implementation of minP_Inner
.minP_Inner
, so ideally it would be asserted there, or even omitted if it can be deduced statically.By using this header here, you may write the above inline function a bit differently such that these disadvantages are avoided:
The first minor feature that you can see here is that the use of EXBINDING and INBINDING spares you from inventing your own naming scheme for the externally visible identifier and the internally visible one.
The real strength of this approach comes from the pseudo-macros ellipsis_precondition and ellipsis_postcondition which result in different checks within the external interface and the internal implementation.
Ideally, this will lead to an inline function with the following properties:
The implementation of all of this is a bit tedious still, but working. If your function is to live in mininmal.h
(for the declaration) and minimal.c
(for the definition) you would have to create two auxiliary files, minimal-interface.h
and minimal-implementation.c
. In the first you'd place the inline function as given above (with EXBINDING etc) and in the second you'd place the function definition; you'd just also have to put EXBINDING around the function name:
In your minimal.h
header file you place a special include
and in your minimal.c
header file you place a special include
Here the first would include the file minimal-interface.h
several times to create different kind of inline wrappers. The second would include minimal-implementation.c
and also minimal-interface.h
to propagate the pre- and postconditions to the defined functions.
-interface.h
and -implementation.c
) is crucial.minP
) is binary compatible with any other implementation that does not use pre- or postconditions.Evidently this only works if you use eĿlipsis as a preprocessor, either in one go (e.g using the compiler wrapper ellipsis-gnuc.sh) or by producing an intermediate preprocessed source.
#define ellipsis_invariant | ( | COND, | |
MESSAGE | |||
) |
A condition COND
that is a pre- and a postcondition.
The second, optional, parameter is a string literal that should provide information for the case that the condition COND
does not hold.
#define ellipsis_postcondition | ( | COND, | |
MESSAGE | |||
) |
A postcondition that is checked (compile time if possible otherwise runtime) in the context of the called function after the body of the function has been run, before a return to the caller.
The second, optional, parameter is a string literal that should provide information for the case that the condition COND
does not hold.
After the call, it will be assumed, that the condition holds.
#define ellipsis_precondition | ( | COND, | |
MESSAGE | |||
) |
A precondition COND
that is checked (compile time if possible otherwise runtime) in the context of the caller before entering the body of the function.
The second, optional, parameter is a string literal that should provide information for the case that the condition COND
does not hold.
In the body of the function, it will be assumed, that the condition holds.
#define EXBINDING | ( | NAME | ) |
The external name of a contracted function.
#define INBINDING | ( | NAME | ) |
The internal name of a contracted function.