fredoverflow
fredoverflow

Reputation: 263118

branching based on two boolean variables

Suppose I have two boolean variables, and I want to do completely different things based on their values. What is the cleanest way to achieve this?

Variant 1:

if (a && b)
{
    // ...
}
else if (a && !b)
{
    // ...
}
else if (!a && b)
{
    // ...
}
else
{
    // ...
}

Variant 2:

if (a)
{
    if (b)
    {
        // ...
    }
    else
    {
        // ...
    }
}
else
{
    if (b)
    {
        // ...
    }
    else
    {
        // ...
    }
}

Variant 3:

switch (a << 1 | b)
{
case 0:
    // ...
    break;

case 1:
    // ...
    break;

case 2:
    // ...
    break;

case 3:
    // ...
    break;
}

Variant 4:

lut[a][b]();

void (*lut[2][2])() = {false_false, false_true, true_false, true_true};

void false_false()
{
    // ...
}

void false_true()
{
    // ...
}

void true_false()
{
    // ...
}

void true_true()
{
    // ...
}

Are variants 3 and 4 too tricky/complicated for the average programmer? Any other variants I have missed?

Upvotes: 3

Views: 983

Answers (4)

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361352

For just two booleans, any of them is good and reasonable. One can choose based on his taste.

However, if there are more than two booleans, say four booleans, then I personally would go with lookup table, and I would do this as:

typedef void (*functype)();

//16 functions to handle 16 cases!
void f0() {}
void f1() {}
//...so on
void f15() {}

//setup lookup table
functype lut[] = 
{
    f0,   //0000 - means all bool are false
    f1,   //0001
    f2,   //0010
    f3,   //0011
    f4,   //0100
    f5,   //0101
    f6,   //0110
    f7,   //0111
    f8,   //1000
    f9,   //1001
    f10,  //1010
    f11,  //1011
    f12,  //1100
    f13,  //1101
    f14,  //1110
    f15   //1111 - means all bool are true
};

lut[MakeInt(b1,b2,b3,b4)](); //call

MakeInt() is easy to write:

int MakeInt(bool b1, bool b2, bool b3, bool b4)
{
   return b1 | (b2<<1) | (b3 <<2) | (b4<<3);
}

Upvotes: 1

iammilind
iammilind

Reputation: 69988

IMHO, I will go for variant 3. Because personally, I don't like if/else when I am checking for equality. It clearly states that there are only 4 possibilities.

One minor edit would be:

inline int STATES(int X, int Y) { return (X<<1) | Y; }
// ...
switch (STATES(a,b))

To make it more fancy, you may replace 0,1,2,3 with an enum as well.

enum States {
  NONE,
  ONLY_B.
  ONLY_A,
  BOTH
}; 

Upvotes: 1

sharptooth
sharptooth

Reputation: 170489

The first variant is the clearest and most readable, but it can be adjusted:

if (a && b) {
    // ...
} else if (a) { // no need to test !b here - b==true would be the first case
    // ...
} else if (b) { //no need to test !a here - that would be the first case
    // ...
} else { // !a&&!b - the last remaining
    // ...
}

Upvotes: 14

Alexandre C.
Alexandre C.

Reputation: 56956

You forgot about:

if (a) a_true(b);
else a_false(b);

which is probably the best choice when appliable, and when you truly need 4 different behaviours.

If you have more than 2 bools, I take this as a code smell if I have 2^n different behaviours which don't factorize well like the above. Then I may think about doing:

enum { case1, case2, ... }

int dispatch_cases(bool a, bool b, bool c, ..., bool z);

switch (dispatch_cases(a, b, ..., z))
{
case case1:
    ...
};

but without context, it is hard to tell whether such complexity is necessary.

Upvotes: 4

Related Questions