
On Aug 31, 2012 5:42 AM, "Andrzej Krzemienski" <akrzemi1@gmail.com> wrote:
2012/8/30 Lorenzo Caminiti <lorcaminiti@gmail.com>
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.
Based on your and Vicente's input, I'll remove static_assert from contracts (pre, post, inv, etc). Is any predicate programmable with static_assert also programmable with Boost.ConceptCheck? I guess so if the Boost.ConceptCheck concept can do the static assertion using Boost.MPL or Boost.StaticAssert. If that it true then no need for me to provide static_assert at all, just use Boost.ConceptCheck. Otherwise, I'll allow static_assert together with Boost.ConceptCheck concepts in the requires clausle. How does that sound?
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
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
--Lorenzo