Boost logo

Boost :

Subject: Re: [boost] [contract] Contracts for constexpr functions
From: Paul A. Bristow (pbristow_at_[hidden])
Date: 2016-08-16 13:15:17


> -----Original Message-----
> From: Boost [mailto:boost-bounces_at_[hidden]] On Behalf Of Lorenzo Caminiti
> Sent: 14 August 2016 02:56
> To: boost_at_[hidden]
> Subject: [boost] [contract] Contracts for constexpr functions
>
> Hello all,
>
> A couple of the proposals I read on adding Contract Programming to the
> C++ standard raise the question if contracts should be supported for
> constexpr functions or not. I tough about this question a bit... but I
> am still not sure of the answer. I wanted to discuss this topic with
> this mailing list, especially with respect to what Boost.Contract can
> currently do.
>
> My general impression is that preconditions, postconditions, and class
> invariants should useful for constexpr functions but noting that:
>
> * Probably old values will not be useful in constexpr functions
> because constexpr prevents its functions from having side-effects (so
> it seems there will no variable visible outside of the function that
> the function body can change, and those variables are usually the
> candidates for making old copies).
> * Subcontracting will never apply to constexpr functions because they
> cannot be virtual.
>
> For example:
>
> struct conststr { // No virtual function so no subcontracting.
> [[invariant: empty() == (size() == 0)]] // Useful class invariants.
> [[invariant: data() != nullptr]]
>
> template<unsigned N>
> constexpr conststr(char const (&s)[N])
> [[requires: s != nullptr]] // Useful preconditions.
> : data_(s), size_(N - 1)
> {}
>
> constexpr char back() const
> [[ensures(result): result == data()[size() - 1]]] //
> Useful postconditions.
> // Old values never useful because constexpr has no side-effects?
> {
> return data_[size_ - 1];
> }
>
> constexpr unsigned size() const { return size_; }
> constexpr bool empty() const { return size_ == 0; }
> constexpr char const* data() const { return data_; }
>
> private:
> char const* data_;
> unsigned size_;
> };
>
> That said, if I understand it correctly, the following are not allowed
> from within constexpr functions:
>
> 1. (Literal) type local variables with non-trivial constexpr
> destructors (see N3597 and subsequent proposals).
> 2. Try-catch statements (see N3597 and subsequent proposals).
> 3. Lambda functions (see N4487).
>
> Reading a few proposals, it seems that supporting the above from
> constexpr functions would be technically possible, but difficult to
> implement (see N3597 and its subsequent proposals, N4487, etc.). I'm
> not really familiar with these constexpr restrictions and
> plans/discussions to relax them in future revisions of the standard...

This is already happening in GCC6.1.1 and Microsoft are not too far behind.

For example, try'n'catch works fine - provided nothing throws while evaluating a constexpr,
when it fails to compile, as it should.

> Boost.Contract implementation uses all the above 1-2-3 respectively to:
>
> a. Check class invariants and postconditions at function exit (using RAII).
> b. Catch assertion failures as well as any other exception that might
> occur while evaluating an asserted conditions and then call the
> appropriate contract failure handler.
> c. Conveniently program functors that check pre- and postconditions
> within the contracted function.
>
> Therefore Boost.Contract implementation does not currently support
> contracts for constexpr functions.

FWIW, I think that is reasonable and wise.

The situation is changing too rapidly, and may be overtaken by Contracts within the language.

Paul

---
Paul A. Bristow
Prizet Farmhouse
Kendal UK LA8 8AB
+44 (0) 1539 561830

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