7

I often see experienced programmers write !!x, even though the expected expression is a Boolean (i.e., zero or not zero) and not an integer.

For example, a line from boost:

BOOST_ASSERT(!!p); // where `p` is a pointer

What's the point of !!p when just p will do?

What I understand by a Boolean parameter is an expression converted to a value of integral type, and the value is compared against zero, explicitly or implicitly (with if or its ternary operator equivalent).

Thus, anything that takes a Boolean and expects only 0 or 1 is wrongly implemented, if my understanding of Boolean is correct.

For clarification: it's obvious that ! converts to bool; the question is explicitly asking for why.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
Hrisip
  • 900
  • 4
  • 13
  • 1
    The answer depends on context. Post some surrounding lines of code? What does the surrounding code do? – anatolyg Dec 06 '20 at 17:25
  • 3
    Related: https://stackoverflow.com/questions/14751973/what-is-in-c – ForceBru Dec 06 '20 at 17:26
  • @anatolyg https://www.boost.org/doc/libs/1_68_0/boost/container/stable_vector.hpp search for `!!p` – Hrisip Dec 06 '20 at 17:28
  • Looks redundant to me. – HolyBlackCat Dec 06 '20 at 17:34
  • 2
    That's a loaded question. If "just `p` will do", then there is literally no point - by your own claim. But the situation is more likely that either "just `p` will *not* do". For example, if there are two overloads, one that takes the native type of `p` and one that takes a `bool`. Or that we are protecting ourselves from issues arising from using the same syntax but when the types have changed (such as after some future maintenance, or copying and pasting the code to reuse in another situation.) Paranoia is probably the justification for most actual uses. – Wyck Dec 06 '20 at 17:35
  • I am (by my own admission at least) an experienced developer. I can tell you that when I don't remember whether something has to be a boolean up front, I'd do a conversion. It's pure laziness. When I learn it's superfluous, I try to avoid it. But you can't always remember everything all the time for every library. Some folks would just do it all the time for consistency. ¯\\_(ツ)_/¯ – StoryTeller - Unslander Monica Dec 06 '20 at 17:47
  • @StoryTeller-UnslanderMonica The C standard says *"if expression (which shall have a scalar type) is false (that is, compares equal to 0), the `assert` macro writes information [...]"*. So the expression must have a scalar type, which `!!` ensures here I guess. I am not sure how that relates to `explicit operator bool()` of class types, but if that means assert doesn't do any conversions and expects a scalar type, then you'd be right about the defensive`!!`. – Aykhan Hagverdili Dec 06 '20 at 18:08
  • I see that you've edited the question. Is there something that is not covered in either the answers below or on the duplicate target? – cigien Dec 06 '20 at 19:36
  • @cigien, the answers don't answer anything(yet a couple of comments kind of do). I have no idea what dfrib was trying to say. After going through the "duplicate" and the links in it I saw some interesting speculations. I will summarize all possible answers here some time later. – Hrisip Dec 06 '20 at 20:00
  • @Hrisip If you feel you have a novel answer to the question, then go ahead and post it on the target. I'm confident that any answer that works here, will work on the target as well. – cigien Dec 06 '20 at 20:03
  • @cigien, I don't think I will come up with something. I'll only do the good thing of collecting the real answers. – Hrisip Dec 06 '20 at 20:09
  • @Hrisip Yes, a summary of various other answers that describe how they are related would be a useful answer. – cigien Dec 06 '20 at 20:16
  • 2
    @Hrisip _"I have no idea what dfrib was trying to say."_ - Do note that I wrote two thorough comments to your brief and confusing comment to my answer that you never gave any feedback back to. T.b.h. you don't seem very keen at _helping_ the answerers after they spend their time answering the question that you have now updated twice since the original answers were posted. I will delete my answer and hope you can spend your own time self-answering this one, as it's hard to know what kind of answer you are actually after (or even what you are actually asking about). – dfrib Dec 06 '20 at 20:31
  • 2
    *The question is explicitly asking for 'why'.* Coupled with *...when just `p` will do?* For which the answer can only be that it is superfluous and redundant. The interesting cases are when `p` just won't do, but you've excluded those from consideration. – Eljay Dec 06 '20 at 20:35
  • @Eljay, you're wrong. One of the possible answers: warnings. So would it do or not depends. – Hrisip Dec 06 '20 at 20:52
  • What example code can you provide that produces a warning unless `!!p`? – Eljay Dec 06 '20 at 21:18
  • 2
    @Hrisip that will merely define that case to be excluded from the scope of the question as well. [The scope of the question as posed being restricted to the condition "when just `p` will do", if `p` gives warnings that `!!p` doesn't, it just won't do.] – sehe Dec 06 '20 at 21:23
  • @Eljay, the question is not about my code, and the possible answer is not mine, but from another post. But I can say that if it's possible to get such a warning, then it would be some specific platform and compiler. There even exist warnings that don't make sense, and those who write libraries often choose to adjust the code just to silent the warnings. – Hrisip Dec 06 '20 at 21:24
  • @sehe, by 'will do' I mean from my standpoint. Since I'm not the one who writes such code, it should be obvious. How could I possibly know whether such code is necessary. That's the whole premise of the question. – Hrisip Dec 06 '20 at 21:31

2 Answers2

10

By default, BOOST_ASSERT(expr) expands to assert(expr). That C++ assert function takes a scalar argument, not bool. Thus, your statement, "the expected expression is a boolean," is not correct.

Classes in C++ can implement operator bool(); the basic_stream classes are examples of such: assert(std::cin) will not work. The !! operator forces the use of std::cin::operator bool(), and bool after !! will be evaluated to int 0 or 1. This is shorter than assert(bool(std::cin)).


If I were a boost author, I would expand BOOST_ASSERT(expr) to assert(!!(expr)) - as is done for ( BOOST_LIKELY(!!(expr)) ? ((void)0) ).

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
273K
  • 29,503
  • 10
  • 41
  • 64
  • I 'tidied up' your post a bit - hope you don't mind. But it *looks* like there's a missing `: ...` clause in your `BOOST_LIKELY` example, which I wasn't really equipped to address. – Adrian Mole Dec 06 '20 at 21:46
  • @AdrianMole it is a small piece of the macro definition. The full definition is quite long. You can add : ... if you wish. You corrections are nice. It is difficult to type grammatically correct sentences in Google gboard with autocorrections. – 273K Dec 06 '20 at 21:52
  • No problem - it's your answer (and a good one). – Adrian Mole Dec 06 '20 at 21:53
-1

Closely related to the question

  1. Warnings.
    Some compilers issue warnings.
  2. Overflow of the integer storing the Boolean.
    I'll just quote the comment mentioning the behaviour

The compiler would treat the values the same either way if it's only used as an operand to an if or &&, but using !! may help on some compilers if if (!!(number & mask)) gets replaced with bit triggered = !!(number & mask); if (triggered); on some embedded compilers with bit types, assigning e.g. 256 to a bit type will yield zero. Without the !!, the apparently-safe transformation (copying the if condition to a variable and then branching) won't be safe.

Related

  1. Some consider defining operator bool() to be "unsafe". And to have an idiomatical way to convert to bool, they define bool operator !().
    So writing !!obj is to support such users. And it doesn't even hurt to do so!
Hrisip
  • 900
  • 4
  • 13