Re-define assert() to help the optimizer

395 views
Skip to first unread message

Frédéric TERRAZZONI

unread,
Nov 27, 2012, 3:26:43 PM11/27/12
to std-pr...@isocpp.org

The assert() macro is a very useful tool to document invariants that are supposed to be true at a certain point in the code. Moreover, they also help the programmer to find bugs since it is expanded to an error-checking code in debug mode. However, in release mode (NDEBUG), this macro is expanded to ((void)0). For me, that specific definition of assert leads to a loss a useful information that could be used by the optimizer.


For instance, if the optimizer was assert-aware, it would be almost possible to emulate the restrict keyword of C99 :

void fn_c99(double * restrict a, double * restrict b) { ... }   

void fn_cpp(double * a, double * b) { assert(a!=b); ... } // (note: for equivalence, a & b must not be arrays)


This is only one example, but we can easily imagine more situations where it could be useful to explicit various constraints (inequalities, !=nullptr, ...) that would help the optimizer (to remove useless branches for instance).

 

By expliciting all the contraints that we have on the variables:

1- We're giving new hints to the optimizer that it cannot prove itself (in release mode)

2- We can check the conformance of our code to these assertions (in debug mode)

 

The current definition of assert() doesn't allow this kind of optimization since the compiler doesn't even see the assertions (they are removed by the pre-compiler if NDEBUG is defined). Two little modifications of the standard would be enough to enable it: let the expansion of assert() be implementation-defined in release mode + allow assert-based optimizations.


What do you think about this proposal?

Martinho Fernandes

unread,
Nov 27, 2012, 3:31:58 PM11/27/12
to std-pr...@isocpp.org
The compiler can still see the assertions. The standard does not require the preprocessor to be separate from the compiler, nor does it forbid the preprocessor from passing extra information to the compiler. Thus this optimization is already enabled. If it does not exist in the wild that is not because of the C++ standard.

Martinho

Frédéric TERRAZZONI

unread,
Nov 27, 2012, 3:49:19 PM11/27/12
to std-pr...@isocpp.org
The assert() in release mode is defined to be a no-op. As far as I know, the compiler is only allowed to make optimizations if the output preserves the semantic. 

#define NDEBUG
#include <cassert>

int fn(int a) {
assert(a==2);
return a*2;
}

In this code, assert() is required by the standard to expand to nop. Here the assert() 's semantic is "do nothing", because NDEBUG is defined. So I could perfectly call fn(3) and expect it to return 6. Consequently, fn is equivalent to its non-optimized version :

int fn(int a) {
return a*2;
}

My proposal is to slightly change the semantic of assert() in order to allow this kind of optimization.

Martinho Fernandes

unread,
Nov 27, 2012, 3:55:35 PM11/27/12
to std-pr...@isocpp.org
On Tue, Nov 27, 2012 at 9:49 PM, Frédéric TERRAZZONI <akr...@gmail.com> wrote:
The assert() in release mode is defined to be a no-op. As far as I know, the compiler is only allowed to make optimizations if the output preserves the semantic. 

#define NDEBUG
#include <cassert>

int fn(int a) {
assert(a==2);
return a*2;
}

In this code, assert() is required by the standard to expand to nop. Here the assert() 's semantic is "do nothing", because NDEBUG is defined. So I could perfectly call fn(3) and expect it to return 6. Consequently, fn is equivalent to its non-optimized version :

int fn(int a) {
return a*2;
}

My proposal is to slightly change the semantic of assert() in order to allow this kind of optimization.


It's a breaking change, then?

Martinho


Frédéric TERRAZZONI

unread,
Nov 27, 2012, 4:01:00 PM11/27/12
to std-pr...@isocpp.org
If some assert() doesn't always hold true in a program, then I consider the code to be already broken. In that sense, it's not a breaking change.

Andrzej Krzemieński

unread,
Nov 28, 2012, 7:15:39 AM11/28/12
to std-pr...@isocpp.org

I find such proposal very useful. It would enable some assert-based optimizations. This suggestion was raised years ago by Niklas Matthies (see here). It requires that there is some intrinsic function that represents an undefined behavior that the compiler is aware of:

constexpr bool undefined_behavior() noexcept;

When compiler sees it, it is guaranteed that the function will trigger an undefined behavior and compiler is allowed to perform arbitrary optimizations (this is a consequence of mixing UB and as-if rules).

Now an assert can be defined as:

#ifdef NDEBUG
#  define ASSERT( PRED ) static_cast<void>( (PRED) || undefined_behavior() ) #endif

This is an information to the compiler: either the condition is true, or you can do whatever you want. I tried to provide a more thorough explanation of the mechanism here.



Nicol Bolas

unread,
Nov 28, 2012, 10:15:01 AM11/28/12
to std-pr...@isocpp.org


On Wednesday, November 28, 2012 4:15:39 AM UTC-8, Andrzej Krzemieński wrote:


W dniu wtorek, 27 listopada 2012 21:26:43 UTC+1 użytkownik Frédéric TERRAZZONI napisał:

The assert() macro is a very useful tool to document invariants that are supposed to be true at a certain point in the code. Moreover, they also help the programmer to find bugs since it is expanded to an error-checking code in debug mode. However, in release mode (NDEBUG), this macro is expanded to ((void)0). For me, that specific definition of assert leads to a loss a useful information that could be used by the optimizer.


For instance, if the optimizer was assert-aware, it would be almost possible to emulate the restrict keyword of C99 :

void fn_c99(double * restrict a, double * restrict b) { ... }   

void fn_cpp(double * a, double * b) { assert(a!=b); ... } // (note: for equivalence, a & b must not be arrays)


This is only one example, but we can easily imagine more situations where it could be useful to explicit various constraints (inequalities, !=nullptr, ...) that would help the optimizer (to remove useless branches for instance).

 

By expliciting all the contraints that we have on the variables:

1- We're giving new hints to the optimizer that it cannot prove itself (in release mode)

2- We can check the conformance of our code to these assertions (in debug mode)

 

The current definition of assert() doesn't allow this kind of optimization since the compiler doesn't even see the assertions (they are removed by the pre-compiler if NDEBUG is defined). Two little modifications of the standard would be enough to enable it: let the expansion of assert() be implementation-defined in release mode + allow assert-based optimizations.


What do you think about this proposal?


I find such proposal very useful. It would enable some assert-based optimizations. This suggestion was raised years ago by Niklas Matthies (see here). It requires that there is some intrinsic function that represents an undefined behavior that the compiler is aware of:

constexpr bool undefined_behavior() noexcept;

When compiler sees it, it is guaranteed that the function will trigger an undefined behavior

How exactly do you "guarantee" undefined behavior? It's undefined; by definition, anything can happen.
 

Tony V E

unread,
Nov 28, 2012, 10:27:23 AM11/28/12
to std-pr...@isocpp.org
constexpr bool undefined_behavior() noexcept;

When compiler sees it, it is guaranteed that the function will trigger an undefined behavior

How exactly do you "guarantee" undefined behavior? It's undefined; by definition, anything can happen.


Exactly - how can you _not_ guarantee it?   Whatever happens next, satisfies "undefined".  :-)
Basically, in the standard say something like  "the behaviour of std::undefined_behaviour() is undefined".
And thus after that function is called, the compiler is free to do whatever it likes with the code.

The real question is whether we want _that_ much leeway.  It really probably doesn't change anything - most asserts() are checking against conditions that would lead to undefined behaviour anyhow.

Tony

Martinho Fernandes

unread,
Nov 28, 2012, 10:31:04 AM11/28/12
to std-pr...@isocpp.org
On Wed, Nov 28, 2012 at 4:27 PM, Tony V E <tvan...@gmail.com> wrote:
constexpr bool undefined_behavior() noexcept;

When compiler sees it, it is guaranteed that the function will trigger an undefined behavior

How exactly do you "guarantee" undefined behavior? It's undefined; by definition, anything can happen.


Exactly - how can you _not_ guarantee it?   Whatever happens next, satisfies "undefined".  :-)
Basically, in the standard say something like  "the behaviour of std::undefined_behaviour() is undefined".
And thus after that function is called, the compiler is free to do whatever it likes with the code.


What do we need the function for then? Just do like we have been doing all this time: say that if the condition does not hold, the behaviour is undefined.

Martinho

 

Andrzej Krzemieński

unread,
Nov 28, 2012, 10:58:21 AM11/28/12
to std-pr...@isocpp.org

Perhaps I used wrong words. I will rename the function from undefined_behavior to impossible_to_get_here. This function is not a normal function it is a compiler "intrinsic", recognized by the compiler. The provision that the compiler obtains when compiling the execution of this function is that if this function is (or would be) executed, the compiler can depart from the constraint that it normally works under: guaranteeing certain observable behavior of the program.

This is the value that this special function offers: it allows the compiler to do something that it typically is not allowed to do: arbitrarily change the observable behavior of the program. But it is not allowing mess though, because we are only allowing this provision if assertion would fail.

Normal UB is not controlled by the compiler. You (the programmer) tell the program to do something wrong, and the compiler just correctly transforms that to a binary code. In this proposal the "pseudo UB" would work differently. The compiler (only when you allow it to) can modify the program behavior in a way that you cannot control, but to the benefit of your program. For instance, the following code:

int passengers = getPassengers();
switch( passengers % 2 ) {
case 1:
 
return handleOdd( passengers );
case 2:
 
return handleEven( passengers );
default:
 
impossible_to_get_here();
 
// equivalent to assert(false);
}

Would allow the compiler to rearrange the code to:

switch( passengers % 2 ) {
case 1:
 
return handleOdd( passengers );
default:
 
return handleEven( passengers ); }

Even though as-if rule would not allow that.
 

Lawrence Crowl

unread,
Nov 28, 2012, 5:49:42 PM11/28/12
to std-pr...@isocpp.org
I think rather than tinker with a macro with problematic
characteristics, we should have targeted language features.

See N1962 Proposal to add Contract Programming to C++ (revision 4)
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2006/n1962.html
and N1867 Synergies between Contract Programming, Concepts and
Static Assertions
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1867.html

--
Lawrence Crowl

Frédéric TERRAZZONI

unread,
Nov 29, 2012, 10:40:54 AM11/29/12
to std-pr...@isocpp.org
@Andrzej Krzemienski:

Like Martinho, I don't understand why such a primitive should be exposed (undefined_behavior() or impossible_to_get_here()).

It is much more simple to say right in the standard :
- If NDEBUG is undefined, then assert(false) abort the program.
- If NDEBUG is defined, then assert(false) is UB (instead of doing nothing, in the current version)

The actual definition of the assert() macro should be left as an implementation detail. Compared to the current version of assert(), I do not see any drawback : it won't break code that is not already-broken, and it gives an easy way to help the compiler producing better output.

@Lawrence Crowl:

The contract programming proposal is indeed better to deal with class invariants & pre/post-conditions. But it may not be always the best solution, especially if we are inside a function/method and we're asserting things about intermediary results.

For instance, if at some point we want to benefit from automatic vectorization then we would be able to write :

float *a,*b,*c;
size_t n;

// a,b,c are arrays of size n

assert(c + n <= a || a + n <= c); //a doesn't alias c
assert(c + n <= b || b + n <= c); //b doesn't alias c

// vectorizable loop
for(size_t i = 0 ; i < n ; i++)
c[i] = a[i]*b[i];
Notice that these two assertions doesn't prevent a and b to overlap (it is not possible to emulate this with the "restrict" keyword, because it's not expressive enough)

Jean-Marc Bourguet

unread,
Nov 29, 2012, 10:59:04 AM11/29/12
to std-pr...@isocpp.org
1/ Is this a standardization of a feature already provided by compilers?

Until more indication that it would really be useful, I tend to think that if it was really useful for performance, compilers would have provided the feature in an implementation specific way and I don't remember having seen any. Well, gcc has __builtin_unreachable() but it seems designed for something else. I'd have expected a __builtin_assume if the feature was available.

2/ I'd provide this in a way not tied to an existing feature. It may be tempting, but I know projects which are using assert so that it fails when compiled without NDEBUG and providing an alternate execution path when compiled with NDEBUG.

Yours,

--
Jean-Marc

Andrzej Krzemieński

unread,
Nov 29, 2012, 11:02:31 AM11/29/12
to std-pr...@isocpp.org


W dniu czwartek, 29 listopada 2012 16:40:54 UTC+1 użytkownik Frédéric TERRAZZONI napisał:
@Andrzej Krzemienski:

Like Martinho, I don't understand why such a primitive should be exposed (undefined_behavior() or impossible_to_get_here()).

It is much more simple to say right in the standard :
- If NDEBUG is undefined, then assert(false) abort the program.
- If NDEBUG is defined, then assert(false) is UB (instead of doing nothing, in the current version)

The actual definition of the assert() macro should be left as an implementation detail. Compared to the current version of assert(), I do not see any drawback : it won't break code that is not already-broken, and it gives an easy way to help the compiler producing better output.

Indeed, the way you present it above, it is much simpler and gives the same power to the compiler.
 
@Lawrence Crowl:

The contract programming proposal is indeed better to deal with class invariants & pre/post-conditions. But it may not be always the best solution, especially if we are inside a function/method and we're asserting things about intermediary results.

One other argument for "enhancing" an assert as you propose is that it requires very small change to the standard; counter to contract-programming proposal (which is good otherwise).

Tony V E

unread,
Nov 29, 2012, 11:49:35 AM11/29/12
to std-pr...@isocpp.org
On Thu, Nov 29, 2012 at 10:59 AM, Jean-Marc Bourguet
<jm.bo...@gmail.com> wrote:
>
> 2/ I'd provide this in a way not tied to an existing feature. It may be
> tempting, but I know projects which are using assert so that it fails when
> compiled without NDEBUG and providing an alternate execution path when
> compiled with NDEBUG.
>

Yes, I've seen plenty of code that looks like:

assert(p != NULL);
if (p == NULL)
return false; // or etc

You can argue whether that makes sense or not (I think there are valid
arguments on both sides), but either way, it is common enough that we
can't change assert's NDEBUG behaviour.


So a std::assume(expr) might be nicer.

Tony

Frédéric TERRAZZONI

unread,
Nov 29, 2012, 12:35:03 PM11/29/12
to std-pr...@isocpp.org
I dislike this code, and I've (hopefully) never seen this. It looks like a quick "bugfix". If I write a function taking a pointer argument, I want its "contract" to be the same no matter I've defined NDEBUG or not: 

- If it doesn't accept a nullptr, then I assert(p!=nullptr); and I document it
- If it can handle nullptr, then I use a conditionnal statement and I document it

Consequently, when this software is running in real word (with NDEBUG naturally), some new vicious code paths are made available. Certainly, some of them have not been properly tested since they're only reachable with NDEBUG. Good luck to debug them afterwards (and no, you cannot disable NDEBUG because the program is likely to abort before the actual bug).

It's worth noting that this kind of code could be warned as "potentially dangerous" by the compilers if the assert was improved :
assert(condition);
if(!condition) { ... }    // warning 

Anyway, I can understand your opinion, and I also understand that some people may want to use it (it is valid C++ code according to the standard after all).

However, I still see some problems with "std::assume": (expr) is not supposed to be evaluated if NDEBUG is defined, so it cannot be a function/class. If it is a keyword, it's likely to break existing code. The only possibility is to implement it as a macro (in a separate header). Since, you cannot put a macro in a namespace, your "std::assume" becomes "assume".

Martinho Fernandes

unread,
Nov 29, 2012, 12:47:55 PM11/29/12
to std-pr...@isocpp.org
On Thu, Nov 29, 2012 at 6:35 PM, Frédéric TERRAZZONI <akr...@gmail.com> wrote:

It's worth noting that this kind of code could be warned as "potentially dangerous" by the compilers if the assert was improved :
assert(condition);
if(!condition) { ... }    // warning 


As most warnings, this code can still be warning by compilers and static analysers, regardless of what the standard says about assert being "improved" or not. The standard has no say in what warnings can be emitted. If you want this kind of warning, request them of the compiler writers, not of the SC.

Martinho

Frédéric TERRAZZONI

unread,
Nov 29, 2012, 12:56:33 PM11/29/12
to std-pr...@isocpp.org
Yes of course, I was not asking for specific warnings to be standardized. I was trying to say that if assert() was improved, then it would be easy to fix all these incompatible programs if the compilers were able to generate good warnings. 

Tony V E

unread,
Nov 29, 2012, 1:15:23 PM11/29/12
to std-pr...@isocpp.org
On Thu, Nov 29, 2012 at 12:35 PM, Frédéric TERRAZZONI <akr...@gmail.com> wrote:
>
> However, I still see some problems with "std::assume": (expr) is not
> supposed to be evaluated if NDEBUG is defined, so it cannot be a
> function/class. If it is a keyword, it's likely to break existing code. The
> only possibility is to implement it as a macro (in a separate header).
> Since, you cannot put a macro in a namespace, your "std::assume" becomes
> "assume".
>

Well, unless we start allowing namespaced keywords. :-)

Andrzej Krzemieński

unread,
Nov 29, 2012, 2:18:26 PM11/29/12
to std-pr...@isocpp.org


W dniu czwartek, 29 listopada 2012 18:35:03 UTC+1 użytkownik Frédéric TERRAZZONI napisał:
I dislike this code, and I've (hopefully) never seen this. It looks like a quick "bugfix". If I write a function taking a pointer argument, I want its "contract" to be the same no matter I've defined NDEBUG or not: 

- If it doesn't accept a nullptr, then I assert(p!=nullptr); and I document it
- If it can handle nullptr, then I use a conditionnal statement and I document it

Consequently, when this software is running in real word (with NDEBUG naturally), some new vicious code paths are made available. Certainly, some of them have not been properly tested since they're only reachable with NDEBUG. Good luck to debug them afterwards (and no, you cannot disable NDEBUG because the program is likely to abort before the actual bug).

It's worth noting that this kind of code could be warned as "potentially dangerous" by the compilers if the assert was improved :
assert(condition);
if(!condition) { ... }    // warning 

Anyway, I can understand your opinion, and I also understand that some people may want to use it (it is valid C++ code according to the standard after all).

How about introducing a third "mode" of macro assert()? E.g., If NDEBUG is defined (to nearly any value) leave the behavior as it is today, but if it is defined to some special value, say 10, then apply the "UB" behavior. Or, Introduce another macro similar to NDEBUG, say XNDEBUG: if defined assertion failure is an UB?

Regards,
&rzej

Frédéric TERRAZZONI

unread,
Nov 29, 2012, 2:36:01 PM11/29/12
to std-pr...@isocpp.org
I like the idea of having a 3-modes assert (more than the introduction of another "word" having a similar semantic which could lead to confusion). However some problems need to be addressed :

1- Using a special value of NDEBUG is not very elegant :

    * NDEBUG undefined : check the assertion at runtime
    * NDEBUG defined (any value) : do nothing
    * NDEBUG defined (one particular value) : UB if condition is false

The 3 possibles value are not "symmetric". Moreover, which the particular value could we use ? If we choose a simple one (1,0,-1...), it's likely to be already used by some people and it could break their codes.

2- Using a new macro (XNDEBUG) is also problematic because we would have 4 states :

    * NDEBUG undefined + XNDEBUG undefined : check assertion at runtime
    * NDEBUG undefined + XNDEBUG defined : UB if condition is false ?
    * NDEBUG defined+ XNDEBUG undefined : do nothing
    * NDEBUG defined+ XNDEBUG defined : UB if condition is false ?






Andrzej Krzemieński

unread,
Nov 29, 2012, 2:43:54 PM11/29/12
to std-pr...@isocpp.org

One possible answer to question 2:
 
    • NDEBUG undefined + XNDEBUG undefined : check assertion at runtime
    • NDEBUG undefined + XNDEBUG defined : UB if condition is false
    • NDEBUG defined+ XNDEBUG undefined : do nothing
    • NDEBUG defined+ XNDEBUG defined -- this is a compile-time error

    This would avoid the situation where two people inadvertently define either macro with different intentions in mind.


    Frédéric TERRAZZONI

    unread,
    Nov 29, 2012, 3:06:12 PM11/29/12
    to std-pr...@isocpp.org
    IMO it seems reasonable.

    To summarize :
    - It doesn't break existing code relying on the current assert() behavior
    - It doesn't introduce a new macro, nor a new keyword  (nor a namespaced keyword :)
    - The UB-assert cannot be enabled inadvertently in legacy code (NDEBUG + XNDEBUG = compile time error)
    - This proposal asks for very few modifications in the standard


    Lawrence Crowl

    unread,
    Nov 29, 2012, 3:30:02 PM11/29/12
    to std-pr...@isocpp.org
    On 11/29/12, Frédéric TERRAZZONI <akr...@gmail.com> wrote:
    > @Lawrence Crowl:
    >
    > The contract programming proposal is indeed better to deal with class
    > invariants & pre/post-conditions. But it may not be always the best
    > solution, especially if we are inside a function/method and we're
    > asserting things about intermediary results.
    >
    > For instance, if at some point we want to benefit from automatic
    > vectorization then we would be able to write :
    >
    > float *a,*b,*c;
    > size_t n;
    >
    > // a,b,c are arrays of size n
    >
    > assert(c + n <= a || a + n <= c); //a doesn't alias c
    > assert(c + n <= b || b + n <= c); //b doesn't alias c
    >
    > // vectorizable loop
    > for(size_t i = 0 ; i < n ; i++)
    > c[i] = a[i]*b[i];
    >
    > Notice that these two assertions doesn't prevent a and b to overlap
    > (it is not possible to emulate this with the "restrict" keyword,
    > because it's not expressive enough)

    If a, b, c and n are parameters, then a precondition works. If they
    are global variables visible to the caller, then a precondition
    works. Otherwise, a function invariant works.

    --
    Lawrence Crowl

    Lawrence Crowl

    unread,
    Nov 29, 2012, 3:38:21 PM11/29/12
    to std-pr...@isocpp.org
    On 11/29/12, Jean-Marc Bourguet <jm.bo...@gmail.com> wrote:
    > 1/ Is this a standardization of a feature already provided by
    > compilers?
    >
    > Until more indication that it would really be useful, I
    > tend to think that if it was really useful for performance,
    > compilers would have provided the feature in an implementation
    > specific way and I don't remember having seen any. Well, gcc
    > has __builtin_unreachable() but it seems designed for something
    > else. I'd have expected a __builtin_assume if the feature was
    > available.

    The Sun compiler had something like performance assertions.
    Great for benchmarks, but because it was Sun-specific and not
    standard, many shops were not willing to use it.

    GCC has __builtin_expect, which isn't quite the same thing. Again,
    people tend to avoid it except in very small areas of code.

    Before people are going to seriously use these mechanisms, they
    need to be standard. The assert macro is inadequate in a lot of
    ways, but everyone uses it precisely because it is standard.

    Any mechanism in this space would be best if it could simultaneously
    serve most of the needs of folks interested in correctness and
    folks interested in performance.

    > 2/ I'd provide this in a way not tied to an existing feature. It
    > may be tempting, but I know projects which are using assert
    > so that it fails when compiled without NDEBUG and providing an
    > alternate execution path when compiled with NDEBUG.

    --
    Lawrence Crowl

    Marc

    unread,
    Nov 29, 2012, 3:57:58 PM11/29/12
    to std-pr...@isocpp.org
    Hello,

    having a way to provide some extra information to the compiler looks like a good idea. However, I disagree with re-using assert for that. There are many places with: assert(expensive_check_that_structure_is_valid()); where you clearly don't want to run the check in release mode, and the compiler wouldn't be able to remove the check if the preprocessor didn't do it (some compiler magic might be possible so it doesn't actually execute the code, but then it wouldn't be implementable in terms of the existing __builtin_unreachable()).

    Andrzej Krzemieński

    unread,
    Nov 29, 2012, 4:08:28 PM11/29/12
    to std-pr...@isocpp.org


    W dniu czwartek, 29 listopada 2012 21:57:58 UTC+1 użytkownik Marc napisał:
    Hello,

    having a way to provide some extra information to the compiler looks like a good idea. However, I disagree with re-using assert for that. There are many places with: assert(expensive_check_that_structure_is_valid()); where you clearly don't want to run the check in release mode, and the compiler wouldn't be able to remove the check if the preprocessor didn't do it (some compiler magic might be possible so it doesn't actually execute the code, but then it wouldn't be implementable in terms of the existing __builtin_unreachable()).

    In this "third" mode we are discussing, the predicate would not be evaluated. The compiler is not forced to optimize the code, so it is not forced to compile the code to execute the predicate. The compiler would only optimize if it knew the condition would not be checked: this is possible in two cases: (1) when someone types assert(false) or when someone checks a condition that has already been checked:

    if (x == 0) {
     
    //...
    }
    else {
     
    assert(x != 0);
    }



    One other example already shown in this thread:

    int passengers = getPassengers();
    switch( passengers % 2 ) {
    case 1:
     
    return handleOdd( passengers );
    case 2:
     
    return handleEven( passengers );
    default:

     
    assert(false);
    }

    Frédéric TERRAZZONI

    unread,
    Nov 29, 2012, 4:14:05 PM11/29/12
    to std-pr...@isocpp.org
    @Lawrence Crowl: I read your link (http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2006/n1962.html#block-invariants) far too quickly. It seems that "block invariants" is closely related to what we're talking about in that topic. I noticed you were involved in it, so do you know what the SC think about introducing contract programming (since 2006) ? (slightly off-topic question, but not totally)

    Lawrence Crowl

    unread,
    Nov 29, 2012, 10:20:27 PM11/29/12
    to std-pr...@isocpp.org
    On 11/29/12, Frédéric TERRAZZONI <akr...@gmail.com> wrote:
    The C++ committee decided not to pursue the feature for C++11.
    Right now, there is no one working on it, and I do not have the time
    to do so.

    --
    Lawrence Crowl

    Olaf van der Spek

    unread,
    Nov 30, 2012, 4:04:30 AM11/30/12
    to std-pr...@isocpp.org
    Op donderdag 29 november 2012 21:38:21 UTC+1 schreef Lawrence Crowl het volgende:

    Before people are going to seriously use these mechanisms, they 
    need to be standard.  The assert macro is inadequate in a lot of
    ways, but everyone uses it precisely because it is standard.

    In what ways is it inadequate (just curious)?

    Olaf van der Spek

    unread,
    Nov 30, 2012, 4:09:51 AM11/30/12
    to std-pr...@isocpp.org
    Op donderdag 29 november 2012 22:08:28 UTC+1 schreef Andrzej Krzemieński het volgende:

    One other example already shown in this thread:

    int passengers = getPassengers();
    switch( passengers % 2 ) {
    case 1:
     
    return handleOdd( passengers );
    case 2:
     
    return handleEven( passengers );
    default:
     
    assert(false);
    }

    Would allow the compiler to rearrange the code to:

    switch( passengers % 2 ) {
    case 1:
     
    return handleOdd( passengers );
    default:
     
    return handleEven( passengers );
    }
     
    For even you'd want case 0, not case 2. For odd you'd generally want != 0, not == 1.

    IMO redefining assert (breaking backwards compatibility) just isn't an option.

    Andrzej Krzemieński

    unread,
    Nov 30, 2012, 4:17:13 AM11/30/12
    to std-pr...@isocpp.org


    W dniu piątek, 30 listopada 2012 10:09:51 UTC+1 użytkownik Olaf van der Spek napisał:
    Op donderdag 29 november 2012 22:08:28 UTC+1 schreef Andrzej Krzemieński het volgende:
    One other example already shown in this thread:

    int passengers = getPassengers();
    switch( passengers % 2 ) {
    case 1:
     
    return handleOdd( passengers );
    case 2:
     
    return handleEven( passengers );
    default:
     
    assert(false);
    }

    Would allow the compiler to rearrange the code to:

    switch( passengers % 2 ) {
    case 1:
     
    return handleOdd( passengers );
    default:
     
    return handleEven( passengers );
    }
     
    For even you'd want case 0, not case 2. For odd you'd generally want != 0, not == 1.

    The example is supposed to show how an "improved" assert can allow certain code rearrangements -- not to handle even or odd numbers.

    IMO redefining assert (breaking backwards compatibility) just isn't an option.

    In this discussion it was shown that this behavior can be implemented without breaking backwards compatibility: by introducing a third "mode" of assertions (similar to NDEBUG).

    Olaf van der Spek

    unread,
    Nov 30, 2012, 4:24:40 AM11/30/12
    to std-pr...@isocpp.org
    On Fri, Nov 30, 2012 at 10:17 AM, Andrzej Krzemieński
    <akrz...@gmail.com> wrote:
    >> For even you'd want case 0, not case 2. For odd you'd generally want != 0,
    >> not == 1.
    >
    >
    > The example is supposed to show how an "improved" assert can allow certain
    > code rearrangements -- not to handle even or odd numbers.

    I know, but having bugs in examples doesn't seem right.

    >> IMO redefining assert (breaking backwards compatibility) just isn't an
    >> option.
    >
    >
    > In this discussion it was shown that this behavior can be implemented
    > without breaking backwards compatibility: by introducing a third "mode" of
    > assertions (similar to NDEBUG).

    What if a library header depending on the old assert() behaviour is
    included in a program that has the new behaviour enabled?
    Or code being copied between the two environments? The behaviour would
    'silently' change.

    What if I want to use both behaviours in the same program?

    --
    Olaf

    Andrzej Krzemieński

    unread,
    Nov 30, 2012, 5:17:23 AM11/30/12
    to std-pr...@isocpp.org
    > In this discussion it was shown that this behavior can be implemented
    > without breaking backwards compatibility: by introducing a third "mode" of
    > assertions (similar to NDEBUG).

    What if a library header depending on the old assert() behaviour is
    included in a program that has the new behaviour enabled?

    I am not sure i understand the situation you are describing. (a short example would help.) Normally you put an assert in a CPP file and it is compiled separately and assertions work the way you configured them in your implementation file. If a "new program" (i.e. a new translation unit) defines macro XNDEBUG its asserts are optimized, but it does not affect the behavior of asserts in other translation units. This is similar to the current situation where you can define macro NDEBUG only in some translation units and the behavior is well defined.
     
    Or code being copied between the two environments? The behaviour would
    'silently' change.

    I am sorry. I do not know what you mean here. I guess you say that the "behaviour would 'slightly' change" if somewhere I decide to define macro XNDEBU. But I do not see how it has anything to do with breaking backwards compatibility. "Old porgrams" do not define macro XNDEBUG, so the upgrade of the language with "improved" assert cannot affect them.

    What if I want to use both behaviours in the same program?

    You can request different behavior of assert even in the same TU. You can do it even today:

    #define NDEBUG
    #include <cassert>
    assert(false);

    #undef NDEBUG
    #include <cassert>
    assert(false);



    Regards,
    &rzej

    Olaf van der Spek

    unread,
    Nov 30, 2012, 5:37:26 AM11/30/12
    to std-pr...@isocpp.org
    On Fri, Nov 30, 2012 at 11:17 AM, Andrzej Krzemieński
    <akrz...@gmail.com> wrote:
    >> > In this discussion it was shown that this behavior can be implemented
    >> > without breaking backwards compatibility: by introducing a third "mode"
    >> > of
    >> > assertions (similar to NDEBUG).
    >>
    >> What if a library header depending on the old assert() behaviour is
    >> included in a program that has the new behaviour enabled?
    >
    >
    > I am not sure i understand the situation you are describing. (a short
    > example would help.) Normally you put an assert in a CPP file and it is
    > compiled separately and assertions work the way you configured them in your
    > implementation file.

    Some (Boost) libraries are header-only. They're not compiled separately.
    They'd not be able to depend on any particular behaviour.

    > If a "new program" (i.e. a new translation unit)
    > defines macro XNDEBUG its asserts are optimized, but it does not affect the
    > behavior of asserts in other translation units. This is similar to the
    > current situation where you can define macro NDEBUG only in some translation
    > units and the behavior is well defined.

    Is it?
    If a class defines extra debug data members if NDEBUG isn't present
    (think iterator validation for example) you might have ODR violations.

    >>
    >> Or code being copied between the two environments? The behaviour would
    >> 'silently' change.
    >
    >
    > I am sorry. I do not know what you mean here. I guess you say that the
    > "behaviour would 'slightly' change" if somewhere I decide to define macro
    > XNDEBU. But I do not see how it has anything to do with breaking backwards
    > compatibility. "Old porgrams" do not define macro XNDEBUG, so the upgrade of
    > the language with "improved" assert cannot affect them.

    That's true, but the behaviour of identical code fragments would no
    longer be identical.
    For no-NDEBUG and NDEBUG that's also the case, but that distinction is
    well known, you often have debug and release builds.

    >> What if I want to use both behaviours in the same program?
    >
    >
    > You can request different behavior of assert even in the same TU. You can do
    > it even today:
    >
    > #define NDEBUG
    > #include <cassert>
    > assert(false);
    >
    > #undef NDEBUG
    > #include <cassert>
    > assert(false);

    I know, but IMO that's seriously ugly.
    I'd rather have assert(false); assume(false);

    --
    Olaf

    Andrzej Krzemieński

    unread,
    Nov 30, 2012, 7:50:35 AM11/30/12
    to std-pr...@isocpp.org


    W dniu piątek, 30 listopada 2012 11:37:26 UTC+1 użytkownik Olaf van der Spek napisał:
    On Fri, Nov 30, 2012 at 11:17 AM, Andrzej Krzemieński
    <akrz...@gmail.com> wrote:
    >> > In this discussion it was shown that this behavior can be implemented
    >> > without breaking backwards compatibility: by introducing a third "mode"
    >> > of
    >> > assertions (similar to NDEBUG).
    >>
    >> What if a library header depending on the old assert() behaviour is
    >> included in a program that has the new behaviour enabled?
    >
    >
    > I am not sure i understand the situation you are describing. (a short
    > example would help.) Normally you put an assert in a CPP file and it is
    > compiled separately and assertions work the way you configured them in your
    > implementation file.

    Some (Boost) libraries are header-only. They're not compiled separately.
    They'd not be able to depend on any particular behaviour.

    > If a "new program" (i.e. a new translation unit)
    > defines macro XNDEBUG its asserts are optimized, but it does not affect the
    > behavior of asserts in other translation units. This is similar to the
    > current situation where you can define macro NDEBUG only in some translation
    > units and the behavior is well defined.

    Is it?
    If a class defines extra debug data members if NDEBUG isn't present
    (think iterator validation for example) you might have ODR violations.

    While I acknowledge the problem you are describing, I believe the problem is there already (because we have NDEBUG and non-NDEBUG) and template library authors must already address it. The proposal would not make the problem worse because "XNDEBUG" is similar to "NDEBUG": in either case you do not want to add auxiliary members (unlike for non-NDEBUG).


    >>
    >> Or code being copied between the two environments? The behaviour would
    >> 'silently' change.
    >
    >
    > I am sorry. I do not know what you mean here. I guess you say that the
    > "behaviour would 'slightly' change" if somewhere I decide to define macro
    > XNDEBU. But I do not see how it has anything to do with breaking backwards
    > compatibility. "Old porgrams" do not define macro XNDEBUG, so the upgrade of
    > the language with "improved" assert cannot affect them.

    That's true, but the behaviour of identical code fragments would no
    longer be identical.
    For no-NDEBUG and NDEBUG that's also the case, but that distinction is
    well known, you often have debug and release builds.

    I don't know. Perhaps I fail to imagine the situation you are describing here. If you use release mode, you can define XNDEBUG in all yout TUs, and I cannot imagine how it would cause ODR violation (assuming that your asserts do not cause it already in C++03).
     

    >> What if I want to use both behaviours in the same program?
    >
    >
    > You can request different behavior of assert even in the same TU. You can do
    > it even today:
    >
    > #define NDEBUG
    > #include <cassert>
    > assert(false);
    >
    > #undef NDEBUG
    > #include <cassert>
    > assert(false);

    I know, but IMO that's seriously ugly.
    I'd rather have assert(false); assume(false);

    I would see the value of 'assume' only if I had to use both macros in one function:

    if (c1) {
     
    assert(c2);
     
    //...
    }  
    else {
      assume
    (c2);
     
    //...
    }

    But it doesn't look realistic to me.

    Regards,
    &rzej

    Olaf van der Spek

    unread,
    Nov 30, 2012, 1:56:48 PM11/30/12
    to std-pr...@isocpp.org
    On Fri, Nov 30, 2012 at 1:50 PM, Andrzej Krzemieński <akrz...@gmail.com> wrote:
    >> Is it?
    >> If a class defines extra debug data members if NDEBUG isn't present
    >> (think iterator validation for example) you might have ODR violations.
    >
    >
    > While I acknowledge the problem you are describing, I believe the problem is
    > there already (because we have NDEBUG and non-NDEBUG) and template library
    > authors must already address it. The proposal would not make the problem

    AFAIK this is addressed by compiling all files with the same defines
    and settings.

    > worse because "XNDEBUG" is similar to "NDEBUG": in either case you do not
    > want to add auxiliary members (unlike for non-NDEBUG).

    True, but what behavior should the template authors expect? The old or
    the 'new'?

    >> That's true, but the behaviour of identical code fragments would no
    >> longer be identical.
    >> For no-NDEBUG and NDEBUG that's also the case, but that distinction is
    >> well known, you often have debug and release builds.
    >
    >
    > I don't know. Perhaps I fail to imagine the situation you are describing
    > here. If you use release mode, you can define XNDEBUG in all yout TUs, and I
    > cannot imagine how it would cause ODR violation (assuming that your asserts
    > do not cause it already in C++03).

    This one isn't about ODR violations, it's about expectations for
    someone that reads or writes the code.

    >> > You can request different behavior of assert even in the same TU. You
    >> > can do
    >> > it even today:
    >> >
    >> > #define NDEBUG
    >> > #include <cassert>
    >> > assert(false);
    >> >
    >> > #undef NDEBUG
    >> > #include <cassert>
    >> > assert(false);
    >>
    >> I know, but IMO that's seriously ugly.
    >> I'd rather have assert(false); assume(false);
    >
    >
    > I would see the value of 'assume' only if I had to use both macros in one
    > function:
    >
    > if (c1) {
    > assert(c2);
    > //...
    > }
    > else {
    > assume(c2);
    > //...
    > }
    >
    > But it doesn't look realistic to me.

    Why not?
    --
    Olaf

    Andrzej Krzemieński

    unread,
    Nov 30, 2012, 3:30:02 PM11/30/12
    to std-pr...@isocpp.org


    W dniu piątek, 30 listopada 2012 19:56:48 UTC+1 użytkownik Olaf van der Spek napisał:
    On Fri, Nov 30, 2012 at 1:50 PM, Andrzej Krzemieński <akrz...@gmail.com> wrote:
    >> Is it?
    >> If a class defines extra debug data members if NDEBUG isn't present
    >> (think iterator validation for example) you might have ODR violations.
    >
    >
    > While I acknowledge the problem you are describing, I believe the problem is
    > there already (because we have NDEBUG and non-NDEBUG) and template library
    > authors must already address it. The proposal would not make the problem

    AFAIK this is addressed by compiling all files with the same defines
    and settings.

    > worse because "XNDEBUG" is similar to "NDEBUG": in either case you do not
    > want to add auxiliary members (unlike for non-NDEBUG).

    True, but what behavior should the template authors expect? The old or
    the 'new'?

    We are talking about assertions. Frederic proposes change in behavior only in case assertion fails (well, technically, when the predicate in assertion evaluates to false). Template authors should not expect an assertion to fail. We put assertions and are sure that they do not fail. If suspect it might fail, we fix the bug so that we are sure our assertion never fails. With this attitude in mind, template authors do not have to care what behavior they get if assertion fails, because they are confident it will not happen. As Frederic pointed out, when your assertion fails in NDEBUG mode you also get an undefined behavior, although at some "higher level of abstraction".

    >> That's true, but the behaviour of identical code fragments would no
    >> longer be identical.
    >> For no-NDEBUG and NDEBUG that's also the case, but that distinction is
    >> well known, you often have debug and release builds.
    >
    >
    > I don't know. Perhaps I fail to imagine the situation you are describing
    > here. If you use release mode, you can define XNDEBUG in all yout TUs, and I
    > cannot imagine how it would cause ODR violation (assuming that your asserts
    > do not cause it already in C++03).

    This one isn't about ODR violations, it's about expectations for
    someone that reads or writes the code.

    Perhaps it is just me, but my primary expectation of asserts is that they should never fail. I plant lot of them and are confident (or, I believe) that none of the asserts will ever fire. If one fires, especially in production (either in NDEBUG or 'XNDEBUG' mode) what code is executed next (the one I wrote or the one rearranged by the compiler) would be my least concern. Because a failing assert indicates a bug in my code.
     
    >> > You can request different behavior of assert even in the same TU. You
    >> > can do
    >> > it even today:
    >> >
    >> > #define NDEBUG
    >> > #include <cassert>
    >> > assert(false);
    >> >
    >> > #undef NDEBUG
    >> > #include <cassert>
    >> > assert(false);
    >>
    >> I know, but IMO that's seriously ugly.
    >> I'd rather have assert(false); assume(false);
    >
    >
    > I would see the value of 'assume' only if I had to use both macros in one
    > function:
    >
    > if (c1) {
    >   assert(c2);
    >   //...
    > }
    > else {
    >   assume(c2);
    >   //...
    > }
    >
    > But it doesn't look realistic to me.

    Why not?

    I cannot even imagine what that means, that you 'assert' one thing and you 'assume' another. Now if I imagine a guy that is only learning C++ and he is told that he sometimes has to assert something in the code, sometimes he has to assume something, and sometimes he has to both assert and assume. Wouldn't that be too complicated? The way I understand assertions (but perhaps this is only me)is that you express something condition that you expect never to be true at this point. What the compiler does with it is secondary. I.e., in ideal world (where the halting problem is resolved) a compiler would verify that my assertions ever fail. Since it cannot do it, there is no good action to be taken, so we are given option: check and terminate, ignore (for performance reasons), ignore, but check syntax (this option is not available). Further optimizations are just another option in the set.

    In other words, when I plant an assert, in my mind it means "condition C will never happen"; it does not mean "when NDEBUG is not defined then evaluate C and if it fails call abort; otherwise do nothing". Assert is a tool from "declarative" programming rather than "imperative" programming. But again, this is probably only my point of view.

    Regards,
    &rzej

    Lawrence Crowl

    unread,
    Nov 30, 2012, 4:12:22 PM11/30/12
    to std-pr...@isocpp.org
    On 11/30/12, Olaf van der Spek <olafv...@gmail.com> wrote:
    > Op 29 november 2012 schreef Lawrence Crowl het volgende:
    > > Before people are going to seriously use these mechanisms, they
    > > need to be standard. The assert macro is inadequate in a lot of
    > > ways, but everyone uses it precisely because it is standard.
    >
    > In what ways is it inadequate (just curious)?

    Assert has many uses, and having only one name makes it hard to
    enable assert for only some uses.

    One of the uses is precondition checking. Unfortunately, the assert
    is in the body of the function and unavailable to the compiler
    at the call site, which means that the compiler cannot eliminate
    provably true assertions.

    --
    Lawrence Crowl

    Olaf van der Spek

    unread,
    Dec 1, 2012, 7:31:39 AM12/1/12
    to std-pr...@isocpp.org
    On Fri, Nov 30, 2012 at 9:30 PM, Andrzej Krzemieński <akrz...@gmail.com> wrote:
    >> True, but what behavior should the template authors expect? The old or
    >> the 'new'?
    >
    >
    > We are talking about assertions. Frederic proposes change in behavior only
    > in case assertion fails (well, technically, when the predicate in assertion
    > evaluates to false). Template authors should not expect an assertion to
    > fail. We put assertions and are sure that they do not fail. If suspect it

    Who is we? ;)
    True, assertions aren't expected to fail, but they're not guaranteed
    to halt the program either. The code that follows might depend on that
    last property.
    I think examples were posted already.

    > might fail, we fix the bug so that we are sure our assertion never fails.
    > With this attitude in mind, template authors do not have to care what
    > behavior they get if assertion fails, because they are confident it will not
    > happen. As Frederic pointed out, when your assertion fails in NDEBUG mode
    > you also get an undefined behavior, although at some "higher level of
    > abstraction".

    I don't think that's always true.

    >> This one isn't about ODR violations, it's about expectations for
    >> someone that reads or writes the code.
    >
    >
    > Perhaps it is just me, but my primary expectation of asserts is that they
    > should never fail. I plant lot of them and are confident (or, I believe)
    > that none of the asserts will ever fire. If one fires, especially in
    > production (either in NDEBUG or 'XNDEBUG' mode) what code is executed next
    > (the one I wrote or the one rearranged by the compiler) would be my least
    > concern. Because a failing assert indicates a bug in my code.

    Again, I think that's just one use case of asserts.

    >> > But it doesn't look realistic to me.
    >>
    >> Why not?
    >
    >
    > I cannot even imagine what that means, that you 'assert' one thing and you
    > 'assume' another. Now if I imagine a guy that is only learning C++ and he is
    > told that he sometimes has to assert something in the code, sometimes he has
    > to assume something, and sometimes he has to both assert and assume.
    > Wouldn't that be too complicated? The way I understand assertions (but

    If you don't need the current behavior of assert, you don't need to
    use/teach it, do you?

    > perhaps this is only me)is that you express something condition that you
    > expect never to be true at this point. What the compiler does with it is
    > secondary. I.e., in ideal world (where the halting problem is resolved) a
    > compiler would verify that my assertions ever fail. Since it cannot do it,
    > there is no good action to be taken, so we are given option: check and
    > terminate, ignore (for performance reasons), ignore, but check syntax (this
    > option is not available). Further optimizations are just another option in
    > the set.
    >
    > In other words, when I plant an assert, in my mind it means "condition C
    > will never happen"; it does not mean "when NDEBUG is not defined then
    > evaluate C and if it fails call abort; otherwise do nothing". Assert is a
    > tool from "declarative" programming rather than "imperative" programming.
    > But again, this is probably only my point of view.

    That's true for some of my asserts as well, but not for all of them.
    --
    Olaf

    Andrzej Krzemieński

    unread,
    Dec 1, 2012, 8:52:38 AM12/1/12
    to std-pr...@isocpp.org


    W dniu sobota, 1 grudnia 2012 13:31:39 UTC+1 użytkownik Olaf van der Spek napisał:
    On Fri, Nov 30, 2012 at 9:30 PM, Andrzej Krzemieński <akrz...@gmail.com> wrote:
    >> True, but what behavior should the template authors expect? The old or
    >> the 'new'?
    >
    >
    > We are talking about assertions. Frederic proposes change in behavior only
    > in case assertion fails (well, technically, when the predicate in assertion
    > evaluates to false). Template authors should not expect an assertion to
    > fail. We put assertions and are sure that they do not fail. If suspect it

    Who is we? ;)
    True, assertions aren't expected to fail, but they're not guaranteed
    to halt the program either. The code that follows might depend on that
    last property.
    I think examples were posted already.

    "The code that follows might depend on" the property that assertions "are not guaranteed to halt the program"? This is how I understood your sentence. Is this it right? Do you mean the situation like this:
    assert(p != NULL);
    if (p == NULL)
       
    return false; // or etc

    I.e., "either abort or return"? Then I see what you mean. But is this a "valid" use of assertion? Why do you assert if you know what to do in such case?
     

    > might fail, we fix the bug so that we are sure our assertion never fails.
    > With this attitude in mind, template authors do not have to care what
    > behavior they get if assertion fails, because they are confident it will not
    > happen. As Frederic pointed out, when your assertion fails in NDEBUG mode
    > you also get an undefined behavior, although at some "higher level of
    > abstraction".

    I don't think that's always true.

    What are the other cases? "abort or return" as the one above, or anything else?


    >> This one isn't about ODR violations, it's about expectations for
    >> someone that reads or writes the code.
    >
    >
    > Perhaps it is just me, but my primary expectation of asserts is that they
    > should never fail. I plant lot of them and are confident (or, I believe)
    > that none of the asserts will ever fire. If one fires, especially in
    > production (either in NDEBUG or 'XNDEBUG' mode) what code is executed next
    > (the one I wrote or the one rearranged by the compiler) would be my least
    > concern. Because a failing assert indicates a bug in my code.

    Again, I think that's just one use case of asserts.

    What are the others?


    >> > But it doesn't look realistic to me.
    >>
    >> Why not?
    >
    >
    > I cannot even imagine what that means, that you 'assert' one thing and you
    > 'assume' another. Now if I imagine a guy that is only learning C++ and he is
    > told that he sometimes has to assert something in the code, sometimes he has
    > to assume something, and sometimes he has to both assert and assume.
    > Wouldn't that be too complicated? The way I understand assertions (but

    If you don't need the current behavior of assert, you don't need to
    use/teach it, do you?

    I do not understand what you are saying here. I need assertions to express my understanding of the code and I accept the "behavior" (abort or no-op). And I need to use the tool.


    > perhaps this is only me)is that you express something condition that you
    > expect never to be true at this point. What the compiler does with it is
    > secondary. I.e., in ideal world (where the halting problem is resolved) a
    > compiler would verify that my assertions ever fail. Since it cannot do it,
    > there is no good action to be taken, so we are given option: check and
    > terminate, ignore (for performance reasons), ignore, but check syntax (this
    > option is not available). Further optimizations are just another option in
    > the set.
    >
    > In other words, when I plant an assert, in my mind it means "condition C
    > will never happen"; it does not mean "when NDEBUG is not defined then
    > evaluate C and if it fails call abort; otherwise do nothing". Assert is a
    > tool from "declarative" programming rather than "imperative" programming.
    > But again, this is probably only my point of view.

    That's true for some of my asserts as well, but not for all of them.

    In a couple of places you indicated that there are other uses of assertions (then to indicate a bug). What are they?

    Regards,
    &rzej

    Olaf van der Spek

    unread,
    Dec 2, 2012, 10:31:50 AM12/2/12
    to std-pr...@isocpp.org
    On Sat, Dec 1, 2012 at 2:52 PM, Andrzej Krzemieński <akrz...@gmail.com> wrote:
    >> True, assertions aren't expected to fail, but they're not guaranteed
    >> to halt the program either. The code that follows might depend on that
    >> last property.
    >> I think examples were posted already.
    >
    >
    > "The code that follows might depend on" the property that assertions "are
    > not guaranteed to halt the program"? This is how I understood your sentence.
    > Is this it right?

    Kinda. The compiler can't assume the assertion is true, because assert
    isn't guaranteed to abort if it's not.
    If assert was guaranteed to abort (basically like my proposed assure),
    it could make that assumption.

    > Do you mean the situation like this:
    > assert(p != NULL);
    > if (p == NULL)
    > return false; // or etc

    Yep

    > I.e., "either abort or return"? Then I see what you mean. But is this a
    > "valid" use of assertion?

    Don't know, but it is used like that in existing code.

    > Why do you assert if you know what to do in such
    > case?

    Maybe you want the debugger to break there.
    Maybe the code that follows kinda silently ignores the error, but
    you'd still want to know about it in debug builds.

    > What are the other cases? "abort or return" as the one above, or anything
    > else?

    Mostly abort or deal with it like above.

    Olaf

    Andrzej Krzemieński

    unread,
    Dec 3, 2012, 4:06:25 AM12/3/12
    to std-pr...@isocpp.org

    >> True, assertions aren't expected to fail, but they're not guaranteed
    >> to halt the program either. The code that follows might depend on that
    >> last property.
    >> I think examples were posted already.
    >
    >
    > "The code that follows might depend on" the property that assertions "are
    > not guaranteed to halt the program"? This is how I understood your sentence.
    > Is this it right?

    Kinda. The compiler can't assume the assertion is true, because assert
    isn't guaranteed to abort if it's not.
    If assert was guaranteed to abort (basically like my proposed assure),
    it could make that assumption.

    > Do you mean the situation like this:
    > assert(p != NULL);
    > if (p == NULL)
    >     return false; // or etc

    Yep

    > I.e., "either abort or return"? Then I see what you mean. But is this a
    > "valid" use of assertion?

    Don't know, but it is used like that in existing code.

    > Why do you assert if you know what to do in such
    > case?

    Maybe you want the debugger to break there.
    Maybe the code that follows kinda silently ignores the error, but
    you'd still want to know about it in debug builds.

    OK, now I understand the concern. However, I wonder if this "XNDEBUG" behavior would really affect anyone. If you use assertions in this way "abort of handle" in your own code (i.e., not in a library), you will not be hurt, because you control the "mode" of assertions. If you are writing a library that does not require the distribution of source code (i.e., a non-template library), again, you are in control of the assertion mode. Only when you ship a "template library", you might get hit. But would you do this "abort of handle" trick in a template library, where the code is exposed to the clients? It would be like you (the library author) were imposing certain diagnostic measures on the clients, that clients may not wish. Do you know any template library that exposes the behavior "abort of handle"?

    Regards,
    &rzej

    Olaf van der Spek

    unread,
    Dec 3, 2012, 5:22:20 PM12/3/12
    to std-pr...@isocpp.org
    On Mon, Dec 3, 2012 at 10:06 AM, Andrzej Krzemieński <akrz...@gmail.com> wrote:
    >> > Why do you assert if you know what to do in such
    >> > case?
    >>
    >> Maybe you want the debugger to break there.
    >> Maybe the code that follows kinda silently ignores the error, but
    >> you'd still want to know about it in debug builds.
    >
    >
    > OK, now I understand the concern. However, I wonder if this "XNDEBUG"
    > behavior would really affect anyone. If you use assertions in this way
    > "abort of handle" in your own code (i.e., not in a library), you will not be
    > hurt, because you control the "mode" of assertions. If you are writing a
    > library that does not require the distribution of source code (i.e., a
    > non-template library), again, you are in control of the assertion mode. Only
    > when you ship a "template library", you might get hit.

    Header-only code isn't always template code.

    > But would you do this
    > "abort of handle" trick in a template library, where the code is exposed to
    > the clients? It would be like you (the library author) were imposing certain
    > diagnostic measures on the clients, that clients may not wish. Do you know
    > any template library that exposes the behavior "abort of handle"?

    No, but then again I don't really pay attention to that code.

    One example from my own code though:
    http://code.google.com/p/xbt/source/browse/trunk/xbt/misc/xbt/to_array.h

    --
    Olaf

    Andrzej Krzemieński

    unread,
    Dec 6, 2012, 4:08:22 AM12/6/12
    to std-pr...@isocpp.org
     
    > But would you do this
    > "abort of handle" trick in a template library, where the code is exposed to
    > the clients? It would be like you (the library author) were imposing certain
    > diagnostic measures on the clients, that clients may not wish. Do you know
    > any template library that exposes the behavior "abort of handle"?

    No, but then again I don't really pay attention to that code.

    One example from my own code though:
    http://code.google.com/p/xbt/source/browse/trunk/xbt/misc/xbt/to_array.h

    Thanks for the example. It looks like you are using an assert to express a precondition. How do you specify the contract for your function to_array?
    Do you say "Requires that input range is of the same size as the requested array's size; returns all elements from range in array".
    Or do you say "Requires nothing; if input range is of the same size then returns all elements from range in array, otherwise returns an array of zeros"
    ?

    Regards,
    &rzej

    Olaf van der Spek

    unread,
    Dec 6, 2012, 8:10:40 AM12/6/12
    to std-pr...@isocpp.org
    On Thu, Dec 6, 2012 at 10:08 AM, Andrzej Krzemieński <akrz...@gmail.com> wrote:
    >> No, but then again I don't really pay attention to that code.
    >>
    >> One example from my own code though:
    >> http://code.google.com/p/xbt/source/browse/trunk/xbt/misc/xbt/to_array.h
    >
    >
    > Thanks for the example. It looks like you are using an assert to express a
    > precondition. How do you specify the contract for your function to_array?

    I don't.

    > Do you say "Requires that input range is of the same size as the requested
    > array's size; returns all elements from range in array".
    > Or do you say "Requires nothing; if input range is of the same size then
    > returns all elements from range in array, otherwise returns an array of
    > zeros"

    Probably the former, although I'm struggling with this function.


    --
    Olaf
    Reply all
    Reply to author
    Forward
    0 new messages