[Development] Disavowing the Lakos Rule for Q_ASSERT

Ville Voutilainen ville.voutilainen at gmail.com
Tue Aug 27 02:18:22 CEST 2024


On Tue, 27 Aug 2024 at 02:24, Thiago Macieira <thiago.macieira at intel.com> wrote:
>
> On Monday 26 August 2024 13:12:55 GMT-7 Thiago Macieira wrote:
> > "Q_ASSERT don't affect noexceptness"
> >
> > Or
> >
> > "noexcept(false) if you call other, noexcept(false) functions from your
> > code", which includes all the pthread cancellation points in glibc. Since
> > qt_assert is noexcept, Q_ASSERT is not included. This is very easy to
> > implement with a static checker.
> >
> > We could be more complex, with "Q_ASSERT that check preconditions imply
> > noexcept(false) but Q_ASSERT that verify the state of the internal invariant
> > against corruption don't". This would not be easy to implement with a
> > static checker.
>
> I propose we follow the Standard Library implementors' example of
> std::vector::operator[]
>
> libstdc++ does have an assertion there:
>       const_reference
>       operator[](size_type __n) const _GLIBCXX_NOEXCEPT
>       {
>             __glibcxx_requires_subscript(__n);
>             return *(this->_M_impl._M_start + __n);
>       }
>
> So does libc++:
> vector<_Tp, _Allocator>::operator[](size_type __n) _NOEXCEPT {
>   _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < size(), "vector[] index out of
> bounds");
>   return this->__begin_[__n];
> }
>
> Let's call this Pragmatic Lakos Rule.

I wouldn't call it that, because it's a) not pragmatic, it completely
prevents using throwing violation handlers with those operators if
those
assertions are turned into contract assertions b) isn't something that
Lakos would agree to put his name on.

These terminating assertions are indeed there in stdlib
implementations due to a very persistent and stubborn misconception
that termination is the only
approach one can take. But that is a misconception, and that choice
prevents perfectly reasonable use cases. So eventually such libraries
need to
be fixed so that they ship configurations and builds where such
functions can be compiled as non-noexcept with contract checks turned
on, so that
throwing violation handlers can be used. With those (useless)
noexcepts there, we have the library that's supposed to be the most
generic and the
most foundational, and it fails to be that, it bakes in a very
particular failure mode for logic errors.


More information about the Development mailing list