|
Boost : |
Subject: Re: [boost] [contract] static_assert in contracts or not?
From: Lorenzo Caminiti (lorcaminiti_at_[hidden])
Date: 2012-09-01 02:41:43
On Aug 31, 2012 5:42 AM, "Andrzej Krzemienski" <akrzemi1_at_[hidden]> wrote:
>
> 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.
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
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk