Mis-use of the unary not operator (!)

November 7, 2006

Coming from a background in C Programming, I am very familiar with the “!” or unary-not operator. This operator inverts the value of the operand it is applied to, so that a true operand returns false, and a false operand returns true. As a programmer often involved in the maintenance of other people’s code, I am also very familiar with wading through pages and pages of software that appears little better than hieroglyphics.

Unary-not was widely used back in the days of C, and C++ to an extent, because the language didn’t have a built in “null”. Some programmers or libraries would use “0” as the null, some would use “-1”. There was no consistent way to check if a condition was true, so unary-not did the job.

These days, in “modern” languages such as Java, C# and VB.NET we have the null value, which is assigned to any reference type variable by default. This means that we can write sensible statements like this:

if (myReferenceType != null)
{
// do something
}

I like code that says exactly what it’s doing – in the case above, it says “if myReferenceType is not null, do something”. Consider the unary-not approach

if (!myReferenceType)
{
// do something
}

Reading that out, we have “if not myReferenceType, do something”. What does that statement mean? It doesn’t make sense when you read it. What if the unary-not operator has been overloaded?

Unary-not is often also applied to boolean values. Which allows us to do some frankly nasty things. Consider the following:

if (!myClass.IsAvailable())
{
// do something
}

“If not myClass is available, do something”. If myClass isn’t available, do something. Now consider:

if (!myClass.IsNotAvailable())
{
// do something
}

“If not myClass is not available, do something”. If myClass is not not available, do something. Or even:

if (!myClass.IsAvailable()==True)
{
// do somsething
}

“If not myClass is available is true, do something”.

As you can see, we can weave all sorts of syntactical loops that are difficult to get out of. Whilst the choice of names for method calls is important (and I will focus on that in a later post) the unary-not operator is causing problems.

Part of the issue with unary-not is that it doesn’t preclude the programmer from using it with other logic operators – so you can, as above, combine it with a method call that you are comparing against a boolean value, and invert the result of the entire statement to produce your eventual value.

My final beef with unary-not is that it’s very difficult to spot. Unlike an “==False” or a “<>0” it hides itself at the start of a statement, as far as it’s possible to get from the functional parts of the code. As a maintenance programmer it is easy to miss, and of course it changes the whole idea of what you’re reading.

For your own good, and for maintenance programmers who come after you, don’t use unary-not!

Advertisements

3 Responses to “Mis-use of the unary not operator (!)”

  1. Monkeyget said

    I don’t understand the paragraph :
    “Unary-not was widely used back in the days of C, and C++ to an extent, because the language didn’t have a built in “null”. Some programmers or libraries would use “0″ as the null, some would use “-1″. There was no consistent way to check if a condition was true, so unary-not did the job.”
    Uh?
    if a variable is a pointer and has a null value then the value of that pointer will be zero (aka null pointer). Who on earth would use -1 as a null pointer?
    I certainly DO use the not operator when i’m doing C programming. Nothing prevents me from a creating a function returning true or false.

    I’m also surprised by your example “if (!myReferenceType)”, which if I understand correctly is supposed to treat null as false and non-null as true.
    Which langage allows such stupidity? I tried it with C# and it won’t compile. I’m pretty much sure that it won’t work on Java either.

    I also tried with that garbage of VB.net 1.1. It compiles but it has a surprising behaviour :

    Dim test As String = Nothing
    If test Then
    Console.WriteLine(“wow”) ‘executed
    End If
    If Not test Then ‘InvalidCastException : Cast from string “” to type ‘Boolean’ is not valid.
    Console.WriteLine(“wow2”)
    End If
    test = “foo”
    If Not test Then ‘InvalidCastException : Cast from string “foo” to type ‘Long’ is not valid.
    Console.WriteLine(“wow3”)
    End If

    (Sorry if wordpress mangles that)
    But in that case it has probably more to do with VB trying to implicitly convert the String.

    To me “if (myClass.IsAvailable())” is more readable than “if (myClass.IsAvailable() == true)”

    In the same manner “if (!myClass.IsAvailable())” is more readable to me than “if(myClass.IsAvailable() == false)”

    None of your aguments ring true to me but it made me think about the way conditional statement work in programming language.
    I also unshelved my math. book to reread the binary logical proposition part.
    It made me realize that i forgot the name of the rule stating “The contradictory opposite of a disjunctive proposition is a conjunctive proposition composed of the contradictories of the parts of the disjunctive proposition ”
    or “(!a&!b) == !(a|b)” in a more readable way.
    It is called “De morgan”‘s law if you whish to know)

    So your post is not a complete loss to me ;).

  2. progblog said

    Thanks for your comment.

    You’re right about pointers, but the ! operator isn’t just used on pointers. It can also be used on integers, bools, and god-knows what else.

    As for readability, it is much easier to “skip over”

    “if (!myClass.IsAvailable())”

    than the alternative that I offered, and to do so changes the whole way the code operates. Likewise your comment that

    “To me “if (myClass.IsAvailable())” is more readable”

    It may/may not be more readable but it is arguably less specific. When maintaining legacy code, which has probably been touched by dozens of people over several years, more specific is better.

    I’m glad the post inspired you to dig out your maths books. Personally I still break out into a rash whenever confronted with complex boolean algebra.

    Mike

  3. Thanks. I was stuck with it too. What I don’t understand is, if some programmers define NULL to be 0 and the rest -1, then the if conditional will work differently. How do you fix this problem?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: