• Advertisement
Sign in to follow this  

Double not operator? (!!)

This topic is 3291 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I saw some code today that used two exclamation marks together, !! . I don't really want to call it a double 'not' operator because it didn't appear to be doing logic in the way a 'not' operator would. Unfortunately I don't have a code sample, I just remembered seeing it and thought I'd ask.

Share this post


Link to post
Share on other sites
Advertisement
It's the "not-not idiom", or something equally descriptive; it is one way to coerce a non-boolean into one:

class some_type
{
bool b;
public:
some_type() : b(true) { }
};

some_type st;

if (st) // syntax error, 'st' cannot be used in a boolean expression
{
}


versus:

class some_type
{
bool b;
public:
some_type() : b(true) { }

bool operator!() const { return b; }
};

some_type st;

if (!!st) // no complaint
{
}

Share this post


Link to post
Share on other sites
That is silly - or possibly worse, stupid.

a) write a cast operator (some_type can be castable to bool)

b) write a method that returns a bool ... and call the method.

examples:

if((bool)truthObject)
{
}

if(someObject.is_true())
{
}

Share this post


Link to post
Share on other sites
Quote:
Original post by Xai
a) write a cast operator (some_type can be castable to bool)

if((bool)truthObject)
{
}


If you implement a cast operator, you don't need the explicit cast.


class some_type
{
bool b;

public:
some_type() : b(true) {}

operator bool() const { return b; }
};

int main()
{
some_type foo;

if(foo)
{
// Works
}
}

Share this post


Link to post
Share on other sites
Quote:
Original post by Xai
That is silly - or possibly worse, stupid.
There's an article somewhere highlighting all the different ways to 'convert' to a bool along with their associated benefits or hidden and horrific pitfalls, I can't find the link though which is a shame. I believe the benefit of the not-not idiom is that it's an explicit coercion.

Quote:
a) write a cast operator (some_type can be castable to bool)
Another option is to overload the casting to void* operator, the SC++L streams use this method; it avoids some of the more serious pitfalls of casting to bool directly.

Share this post


Link to post
Share on other sites
Quote:
Original post by dmatter
There's an article somewhere highlighting all the different ways to 'convert' to a bool along with their associated benefits or hidden and horrific pitfalls, I can't find the link though which is a shame. I believe the benefit of the not-not idiom is that it's an explicit coercion.

Could this be the one you are referring to? ...if so, my google-fu isn't that bad after all :)
The Safe Bool Idiom [via]

Share this post


Link to post
Share on other sites
Quote:
Original post by sirGustav
Quote:
Original post by dmatter
There's an article somewhere highlighting all the different ways to 'convert' to a bool along with their associated benefits or hidden and horrific pitfalls, I can't find the link though which is a shame. I believe the benefit of the not-not idiom is that it's an explicit coercion.

Could this be the one you are referring to? ...if so, my google-fu isn't that bad after all :)
The Safe Bool Idiom [via]
That's it [smile]
A quick scan through reveals its name to actually be 'the double-bang trick', although to be honest I prefer my name for it.

Share this post


Link to post
Share on other sites
Quote:
Original post by Xai
That is silly - or possibly worse, stupid.


I think this idiom is actually trying to be a bit too clever.

Quote:
Original post by dmatter
I believe the benefit of the not-not idiom is that it's an explicit coercion.


I can't think of anything more explicit than:


if(someObject.is_true())
{
}



You can replace is_true with is_valid or some other helpfully named function which actually describes what it is you are trying to achieve. !! may be explicit, but it just produces confusing code.

Share this post


Link to post
Share on other sites
How about this:

[source lang=cpp]
int count=0;
while(<condition>)
{
ClassType *ptr=someFunctionForReadingOrGettingThatClass();
count+=!!ptr;
//rest of code
}

Share this post


Link to post
Share on other sites
Quote:
Original post by _moagstar_
Quote:
Original post by Xai
That is silly - or possibly worse, stupid.


I think this idiom is actually trying to be a bit too clever.


I don't know, I think it's useful and perfectly clear when used on primitive types. For example:

void Foo(int x, int y)
{
if(!!x ^ !!y)
{
// x is nonzero and y is zero, or y is nonzero and x is zero
}
}

Share this post


Link to post
Share on other sites
Quote:
Original post by Sc4Freak
void Foo(int x, int y)
{
if(!!x ^ !!y)
{
// x is nonzero and y is zero, or y is nonzero and x is zero
}
}


Well dropping the !! there makes much more sense to me, as it's just a regular XOR..

Share this post


Link to post
Share on other sites
Quote:
Original post by Sc4Freak
I don't know, I think it's useful and perfectly clear when used on primitive types. For example:
My definition of "perfectly clear" is "I get it when I read it", which certainly isn't the case for "!!x ^ !!y". Especially compared to "(x == 0) != (y == 0)".

Share this post


Link to post
Share on other sites
Quote:
Original post by Sc4Freak
I don't know, I think it's useful and perfectly clear when used on primitive types.


Maybe that's a matter of taste, but I would say it's probably better to write code in the simplest and clearest manner possible, so that as many people can understand it as possible. Personally I find (var != 0) much clearer than !!var. If I read the code in my head I hear myself saying 'var is not equal to zero' and 'not not var' respectively.

Share this post


Link to post
Share on other sites
With primitive types (prim!=0) is much more clear than (!!prim). However, is it faster?

Share this post


Link to post
Share on other sites
Quote:
Original post by someboddy
With primitive types (prim!=0) is much more clear than (!!prim). However, is it faster?


In terms of compiled code they are precisely the same, however in terms of performance this is the last thing you should be worrying about, my advice would be to just pick whichever you find clearest and stick with it.

Share this post


Link to post
Share on other sites
The purpose of this idiom really has very little to do with safe-bool. It's mostly to interop with libraries written to be compatible with C. Older versions of C did not have a true boolean type and instead used the convention that 0 meant false and not-0 meant true. "not-0" literally means "anything that isn't 0". So for example 8 is considered to be true. The idiom came about because some compilers (notably MSVC) will complain about assigning an int to a bool even though it will work fine.

Personally I find "!!foo" to be easier to understand than "foo!=0" or "(bool)foo". "!!foo" means "foo is a C-style boolean and I'm converting it to a C++ style boolean". "foo!=0" implies to me that foo is actually an integer, not a boolean. "(bool)foo" just looks like something wierd is going on.

Share this post


Link to post
Share on other sites
And to add to Anon Mike's post, because this is primarily a C idiom, writing C++ patches around it is rather misguided. C++ has a proper boolean type, amonst other things.

Share this post


Link to post
Share on other sites
Quote:
Original post by GraphicsBas
Well dropping the !! there makes much more sense to me, as it's just a regular XOR..

That wouldn't preserve the meaning. ^ is a bitwise xor, not a logical xor.

Share this post


Link to post
Share on other sites
Quote:
Original post by GraphicsBas
Quote:
Original post by Sc4Freak
void Foo(int x, int y)
{
if(!!x ^ !!y)
{
// x is nonzero and y is zero, or y is nonzero and x is zero
}
}


Well dropping the !! there makes much more sense to me, as it's just a regular XOR..


XOR is a bitwise operator. Consider carefully what happens if x == 2 and y == 1.

Share this post


Link to post
Share on other sites
Is C++0x supposed to have explicit conversion operators (conversion would occur only in boolean context, but not where the bool in turn would be implicitly converted to something third)? Does any compiler support that already?

Share this post


Link to post
Share on other sites
I once saw a statement like this:

if(err =! SomeFunction())
{
}

with the spaces in that same way.

And it was even doing what it was supposed to be doing, it wasn't a typo of !=.

Share this post


Link to post
Share on other sites
Quote:
Original post by quasar3d
I once saw a statement like this:

if(err =! SomeFunction())
{
}

with the spaces in that same way.

And it was even doing what it was supposed to be doing, it wasn't a typo of !=.


It is the same as writing:

if(err = !SomeFunction())
{
}


It simple checks if SomeFunction fails(SomeFunction probably returns 0 if it fails) and if so, does the code inside the curly brackets. Also, err will contain 1 if there was a fail and 0 if it worked.

Share this post


Link to post
Share on other sites
Here's another cute trick that plays with the parser:

int x = 10;
//This loop goes until x reaches 0, 10 times in this case.
while( x --> 0 )
{
...
}

Hopefully I didn't screw that up.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement