Boost logo

Boost :

Subject: Re: [boost] [contract] static_assert in contracts or not?
From: Andrzej Krzemienski (akrzemi1_at_[hidden])
Date: 2012-08-31 08:41:33


2012/8/30 Lorenzo Caminiti <lorcaminiti_at_[hidden]>

>
> 1) Would you expect to be able to use static_assert within contract
> assertions (preconditions, postconditions, and class invariants)? Note
> that only boolean conditions are allowed by N1962 within contracts,
> general code is not allowed, therefore this is not a trivial question.
>
> For example, would you expect to be able to do the following option A:
>
> template< typename To, typename From >
> To* memcopy ( To* to, From* from )
> precondition{
> static_assert(sizeof(To) >= sizeof(From), "destination too
> small");
> static_assert(boost::is_convertible<From, To>::value,
> "incompatible types");
> to; // pointer not null
> from; // pointer not null
> }
> {
> // ...
> }
>
> In this case, would it ever make sense to use static_assert in
> postcondition and/or class invariants even if that were allowed?
>

This is an interesting example. Here I can see the value of static asserts
as contracts. But as you observe, it looks that they only make sense as
precondtions: function "expects" and caller "ensures". It is difficult to
imagine that a function could "ensure" anything itself at compile-time
(that you couldn't check yourself). Invariants, as contract, are somewhat
closer to pstconditions.

But for those "static preconditions" there exist better tools. For instance
"static if" proposed for C++17:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3329.pdf
In section 2.4 it describes sort of "small concepts". Using this proposal,
your example could be rewritten to:

  template< typename To, typename From >
    To* memcopy ( To* to, From* from )
      if (sizeof(To) >= sizeof(From) && is_convertible<From, To>::value)
      precondition{
        to != nullptr;
        from != nullptr
      }

> {
> // ...
> }

This works somewhat different though. It makes the function not even
defined for incompatible types (error message would be "no matching
function found"). The assertion variant does recognize that you intended to
call our function and tells you exactly why it was a bad idea.

You can implement this behavior in C++03 with boost::enable_if, I guess.

>
> Or would you just use static_assert in the body, option B:
>
> template< typename To, typename From >
> To* memcopy ( To* to, From* from )
> precondition{
> to; // pointer not null
> from; // pointer not null
> }
> {
> static_assert(sizeof(To) >= sizeof(From), "destination too small");
> static_assert(boost::is_convertible<From, To>::value,
> "incompatible types");
> // ...
> }
>
> I don't like this because the assertions are about the specifications
> (they assert a requirement of the interface) so they should go in the
> declaration and not in the implementation.
>

I agree that this is worse.

> Or maybe the assertions should be represented as concept requirements
> on To and From, option C:
>
> template< typename To, typename From >
> requires SizeofGreaterEqual<To, From>, Convertible<From, To>
> To* memcopy ( To* to, From* from )
> precondition{
> to; // pointer not null
> from; // pointer not null
> }
> {
> // ...
> }
>
> (Only we don't have concepts...)
>

But we have enable_if which is sufficient. It has an ugly syntax, but I
guess your framework could make it simpler. But then, even with full
concepts in C++ assertions have an advantage: they give you a cleaner error
message.

> 2) Let's assume, we answered option A to question 1):
>
> template< typename To, typename From >
> To* memcopy ( To* to, From* from )
> precondition{
> static_assert(sizeof(To) >= sizeof(From), "destination too
> small");
> static_assert(boost::is_convertible<From, To>::value,
> "incompatible types");
> to; // pointer not null
> from; // pointer not null
> }
> {
> // ...
> }
>
> Would you expect these static_asserts to be disabled when precondition
> compilation and checking is turned off at compilation time? I'd think
> so.
>

Are you asking (a) what I would want to have, or (b) what I would expect if
I have seen this syntax?
If (a): As I understand it, people consider disabling assertions, in order
to avoid run-time overhead. Since static assertions add no overhead I would
never want to disable them.

If (b): the way assertions are grouped in the example, it might suggest
that disabling precondition would disable both kinds of assertions.

Regards,
&rzej


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk