Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I have a condition

if(exists && !isDirectory || !exists)
{}

how can I modify it, so that it may be more understandable.

share|improve this question
1  
what value does isDirectory have when exists is false? –  mcwise Oct 5 '12 at 12:02
1  
exist is Bool type, isDirectory is also BOOL type variables –  Spynet Oct 5 '12 at 12:05
5  
if(!isDirectory) ... (exists || !exists) will always be true. –  Shark Oct 5 '12 at 15:29
    
@Shark - What if exists and isDirectory are both true? –  qegal Oct 6 '12 at 2:13
    
I read the title as "I have a personality problem, can I erase my mind to fix it". Yeah, I'm tired. –  Annan Oct 12 '12 at 1:55
show 2 more comments

7 Answers

up vote 108 down vote accepted

|| is commutative so

if(!exists || (exists && !isDirectory))

is equivalent.

Now because exists is always true in the second part of the || you can drop the &&:

if(!exists || !isDirectory)

Or you can go a step further and do:

if(!(exists && isDirectory))
share|improve this answer
10  
+1 for showing your work :) –  sdg Oct 5 '12 at 12:08
5  
What was implied but not explicitly mentioned here is that && has higher precedence (at least in most well known languages - there may be exceptions) than ||. Thus a && b || c is equivalent to (a && b) || c but not to a && (b || c). –  Péter Török Oct 5 '12 at 12:21
25  
I think, that !exists || !isDirectory is more "understandable", because, isDirectory cannot be true if !exists. So as a human we will say "if it does not exist or it [exists and it] is not a directory". –  duros Oct 5 '12 at 12:39
5  
I prefer !exists || !isDirectory over the last one. –  Monster Truck Oct 5 '12 at 12:40
25  
Anyone who relies on the relative precedence of '&&', '||', '==', '!=', etc and doesn't make their intention clear by using brackets deserves to be shot. In all languages, something like 'a && b || c' is equivalent to a comment saying that the author probably screwed the entire thing up in their rush to avoid typing a few extra characters. –  Brendan Oct 5 '12 at 16:26
show 9 more comments

For better readability, I like to extract boolean conditions to methods:

if(fileNameUnused())
{...}

public boolean fileNameUnused() {
   return exists && !isDirectory || !exists;
}

Or with a better method name. If you can name this method properly, the reader of your code doesn´t need to figure out what the boolean condition means.

share|improve this answer
    
+1 for saying something about useful names. But somewhere you will have to reformat the conditional. –  Monster Truck Oct 5 '12 at 12:41
4  
A less extreme alternative, that still conveys intent, is just to name the condition used: boolean fileNameUnused = !exists || !isDirectory; if (fileNameUnused) { doSomething(); } –  Steven Oct 6 '12 at 20:00
add comment

You could just try to nail the no-go case and bail out if that shows up.

while(someCondition) {

    if(exists && isDirectory)
        continue;
        // maybe "break", depends on what you're after.

        // the rest of the code
}

or even

function processFile(someFile)
{ 
    // ...
    if(exists && isDirectory)
       return false;
    // the rest of the code
    // ...
}
share|improve this answer
    
Aren't break, continue, and more-than-one return statement considered code smells? –  Freiheit Oct 5 '12 at 14:37
8  
@Freiheit It depends on the context. Sometimes an early return statement is used to reduce indentation, thus enhancing readability. –  marco-fiset Oct 5 '12 at 14:57
    
Best answer - complex conditionals waste enormous amounts of time reading and accurately understanding them. As a result often are "taken as read" leading to insidious bugs. –  mattnz Oct 5 '12 at 22:08
add comment

As a process, I suggest building a truth table:

e = exists
d = isDirectory

e | d | (e && !d) || !e
--+---+----------------
0 | 0 | 1
0 | 1 | 1
1 | 0 | 1
1 | 1 | 0

This matches the NAND operation, which is simply:

!(exists && isDirectory)

If you don't remember all your logic gates, wikipedia has a nice reference with the truth tables to boot.


@Christoffer Hammarström brought up an important point about the state of isDirectory being tied to the state of exists. Assuming that they refer to the same reference, and that it's not possible to have a state where the reference doesn't exist and is a directory, the truth table can be written as follows:

e | d | (e && !d) || !e
--+---+----------------
0 | 0 | 1
0 | 1 | n/a
1 | 0 | 1
1 | 1 | 0

The n/a is used to represent a state that doesn't matter. Acceptable reductions could result in either 1 or 0 for states resulting in n/a.

With this in mind, !(exists && isDirectory) is still a valid reduction, resulting in a 1 for !e && d.

However, !isDirectory would be a much simpler reduction, resulting in 0 for !e && d.

share|improve this answer
6  
+1: this is how you teach someone to fish. –  Steve Evers Oct 5 '12 at 22:24
4  
The next step is to realise that isDirectory depends on exists. It can't both be a directory and not exist. –  Christoffer Hammarström Oct 6 '12 at 0:12
    
@ChristofferHammarstrom, Out of context I can't assume that the variables refer to the same thing, but that is a valid point. The result column should be filled with n/a in places where the state is impossible to achieve, and the equation reduced accordingly. –  zzzzBov Oct 6 '12 at 4:24
    
Well, if the variables refer to two different contexts, then they are too terse and need to be renamed. –  Christoffer Hammarström Oct 6 '12 at 13:22
    
But building a truth table and evaluating it is NP-complete! –  Thomas Eding Oct 17 '12 at 20:18
show 3 more comments

You can use a truth table as pointed out. Second step could be a KV-map for minimizing the number of terms.

Using the laws of Boolean algebra is another approach:

A = exists
B = !isDirectory
!A = !exists

&& = *
|| = +

[Edit]
A simpler transform, because the operations AND and OR are mutually distributive :

exists && !isDirectory || !exists
= A*B + !A
= (A + !A) * (B + !A)
= 1*(B + !A)
= B + !A
[/Edit]

exists && !isDirectory || !exists
= A*B + !A
= A*B + !A*1 //Identity
= A*B + !A*(B+1) //Annihilator
= A*B + !A*B + !A //Distributivity and Identity
= B*(A + !A) + !A //Distributivity
= B*1 + !A //Complementation 2
= B + !A //Identity
= !isDirectory || !exists

Or with double complement (!!x = x):

A*B + !A
= !!(A*B + !A)
= !(!(A*B)*A)
= !((!A + !B)*A)
= !(!A*A + !B*A)
= !(0 + !B*A)
= !(!B*A)
= B + !A
= !isDirectory || !exists

share|improve this answer
    
+1 for using formal rules (I never though that I would see one of these after my first year of college). –  Nemanja Boric Oct 5 '12 at 23:48
    
@Burgos: Thanks! They were a lot of fun :) –  Eddie Gasparian Oct 6 '12 at 8:56
    
add comment

I don't like to use "!" when there is more than one condition in the expression. I'll add lines of code to make it more readable.

doesNotExist = !exists;
isFile = exists && !isDirecotry;
if (isFile || doesNotExist) 
   {}
share|improve this answer
    
+1 This makes it easier to read out as "if is file or does not exist" which is a lot closer to English. –  Phil Oct 5 '12 at 22:09
    
This is a refactoring called Introduce Explaining Variable. –  Eddie Gasparian Oct 28 '12 at 15:52
add comment

As previously indicated, the condition can be reduced to:

if (!(exists && isDirectory))

However, I'll bet that being a directory implies existence. If so, we can reduce the condition to:

if (!isDirectory)
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.