Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why '&&' and not '&'?

Tags:

operators

c#

In most cases, && and || are preferred over & and | because the former are short-circuited, meaning that the evaluation is canceled as soon as the result is clear.

Example:

if(CanExecute() && CanSave())
{
}

If CanExecute returns false, the complete expression will be false, regardless of the return value of CanSave. Because of this, CanSave is not executed.

This is very handy in the following circumstance:

string value;
if(dict.TryGetValue(key, out value) && value.Contains("test"))
{
    // Do Something
}

TryGetValue returns false if the supplied key is not found in the dictionary. Because of the short-circuiting nature of &&, value.Contains("test") is only executed, when TryGetValue returns true and thus value is not null. If you would use the bitwise AND operator & instead, you would get a NullReferenceException if the key is not found in the dictionary, because the second part of the expression is executed in any case.

A similar but simpler example of this is the following code (as mentioned by TJHeuvel):

if(op != null && op.CanExecute())
{
    // Do Something
}

CanExecute is only executed if op is not null. If op is null, the first part of the expression (op != null) evaluates to false and the evaluation of the rest (op.CanExecute()) is skipped.

Apart from this, technically, they are different, too:
&& and || can only be used on bool whereas & and | can be used on any integral type (bool, int, long, sbyte, ...), because they are bitwise operators. & is the bitwise AND operator and | is the bitwise OR operator.

To be very exact, in C#, those operators (&, | [and ^]) are called "Logical operators" (see the C# spec, chapter 7.11). There are several implementations of these operators:

  1. For integers (int, uint, long and ulong, chapter 7.11.1):
    They are implemented to compute the bitwise result of the operands and the operator, i.e. & is implement to compute the bitwise logical AND etc.
  2. For enumerations (chapter 7.11.2):
    They are implemented to perform the logical operation of the underlying type of the enumeration.
  3. For bools and nullable bools (chapter 7.11.3 and 7.11.4):
    The result is not computed using bitwise calculations. The result is basically looked up based on the values of the two operands, because the number of possibilities is so small.
    Because both values are used for the lookup, this implementation isn't short-circuiting.

To explain very clearly what this means (even though the other answers hint at it - but probably use terminology you don't understand).

The following code:

if (a && b)
{
   Foo();
}

Is really compiled to this:

if (a)
{
    if (b)
    {
        Foo();
    }
}

Where the following code is compiled exactly as it is represented:

if (a & b)
{
   Foo();
}

This is called short-circuiting. In general you should always use && and || in your conditions.

Bonus Marks: There is one scenario when you shouldn't. If you are in a situation where performance is crucial (and this is nano-seconds crucial) only use short-circuiting when you must (e.g. null checking) - as a short-circuit is a branch/jump; which could result in a branch-misprediction on your CPU; an & is much cheaper than &&. There is also a scenario where short-circuiting can actually break logic - have a look at this answer of mine.

Diatribe/Monologue: Regarding the branch mis-prediction that most blissfully ignore. Quoting Andy Firth (who has been working on games for 13 years): "This may be lower level that people think they need to go... but they'd be wrong. Understanding how the hardware you're programming for treats branches can affect performance to a HUGE degree... far more than most programmers may appreciate re: death by a thousand cuts."

  • Game developers (and others working in extreme real-time conditions) go as far as restructuring their logic to better suit the predictor. There is also evidence of this in decompiled mscorlib code.
  • Just because .NET shields you from this type of thing doesn't mean it's not important. A branch mis-prediction is horribly expensive at 60 Hz; or at 10,000 requests/second.
  • Intel wouldn't have tools to identify the location of mis-predictions, nor would Windows have a performance counter for this, nor would there be a word to describe it, were it not a problem.
  • Ignorance about the lower levels and architecture does not make someone who is aware of them wrong.
  • Always try to understand the limitations of the hardware you are working on.

Here is a benchmark for the non-believers. It's best to run the process in RealTime/High to mitigate the scheduler having an effect: https://gist.github.com/1200737


Logical operator (|| and &&) vs. bitwise operator (| and &).

The most crucial difference between a logical operator and bitwise operator is that a logical operator takes two booleans and produces a boolean while a bitwise operator takes two integers and produces an integer (note: integers means any integral data type, not just int).

To be pedantic, a bitwise operator takes a bit-pattern (e.g. 01101011) and does a bit-wise AND/OR on each bits. So, for example if you have two 8-bit integers:

a     = 00110010 (in decimal:    32+16+2   = 50)
b     = 01010011 (in decimal: 64+   16+2+1 = 83)
----------------
a & b = 00010010 (in decimal:       16+2   = 18)
a | b = 01110011 (in decimal: 64+32+16+2+1 = 115)

while a logical operator only works in bool:

a      = true
b      = false
--------------
a && b = false
a || b = true

Second, it is often possible to use a bitwise operator on bool since true and false is equivalent to 1 and 0 respectively, and it happens that if you translate true to 1 and false to 0, then do bitwise operation, then convert non-zero to true and zero to false; it happens that the result will be the same had you just used logical operator (check this for exercise).

Another important distinction is also that a logical operator is short-circuited. Thus, in some circles[1], you often see people doing something like this:

if (person && person.punch()) {
    person.doVictoryDance()
}

which translates to: "if person exists (i.e. is not null), try to punch him/her, and if the punch succeeds (i.e. returns true), then do a victory dance".

Had you used a bitwise operator instead, this:

if (person & person.punch()) {
    person.doVictoryDance()
}

will translate to: "if person exists (i.e. is not null) and the punch succeeds (i.e. returns true), then do a victory dance".

Note that in the short-circuited logical operator, the person.punch() code may not be run at all if person is null. In fact, in this particular case, the second code would produce a null reference error if person is null, since it tries to call person.punch() no matter whether person is null or not. This behavior of not evaluating the right operand is called short-circuiting.

[1] Some programmers will baulk for putting a function call that have a side effect inside an if expression, while for others it's a common and very useful idiom.

Since a bitwise operator works on 32-bits at a time (if you're on a 32-bit machine), it can lead to a more elegant and faster code if you need to compare a huge number of conditions, e.g.

int CAN_PUNCH = 1 << 0, CAN_KICK = 1 << 1, CAN_DRINK = 1 << 2, CAN_SIT = 1 << 3,
    CAN_SHOOT_GUNS = 1 << 4, CAN_TALK = 1 << 5, CAN_SHOOT_CANNONS = 1 << 6;

Person person;
person.abilities = CAN_PUNCH | CAN_KICK | CAN_DRINK | CAN_SIT | CAN_SHOOT_GUNS;

Place bar;
bar.rules = CAN_DRINK | CAN_SIT | CAN_TALK;

Place military;
military.rules = CAN_SHOOT_CANNONS | CAN_PUNCH | CAN_KICK | CAN_SHOOT_GUNS | CAN_SIT;

CurrentLocation cloc1, cloc2;
cloc1.usable_abilities = person_abilities & bar_rules;
cloc2.usable_abilities = person_abilities & military_rules;

// cloc1.usable_abilities will contain the bit pattern that matches `CAN_DRINK | CAN_SIT`
// while cloc2.usable_abilities will contain the bit pattern that matches `CAN_PUNCH | CAN_KICK | CAN_SHOOT_GUNS | CAN_SIT`

Doing the same with logical operators would require an awkward amount of comparisons:

Person person;
person.can_punch = person.can_kick = person.can_drink = person.can_sit = person.can_shoot_guns = true;
person.can_shoot_cannons = false;

Place bar;
bar.rules.can_drink = bar.rules.can_sit = bar.rules.can_talk = true;
bar.rules.can_punch = bar.rules.can_kick = bar.rules.can_shoot_guns = bar.rules.can_shoot_cannons = false;

Place military;
military.rules.can_punch = military.rules.can_kick = military.rules.can_shoot_guns = military.rules.can_shoot_cannons = military.rules.can_sit = true;
military.rules.can_drink = military.rules.can_talk = false;

CurrentLocation cloc1;
bool cloc1.usable_abilities.can_punch         = bar.rules.can_punch         && person.can_punch,
     cloc1.usable_abilities.can_kick          = bar.rules.can_kick          && person.can_kick,
     cloc1.usable_abilities.can_drink         = bar.rules.can_drink         && person.can_drink,
     cloc1.usable_abilities.can_sit           = bar.rules.can_sit           && person.can_sit,
     cloc1.usable_abilities.can_shoot_guns    = bar.rules.can_shoot_guns    && person.can_shoot_guns,
     cloc1.usable_abilities.can_shoot_cannons = bar.rules.can_shoot_cannons && person.can_shoot_cannons
     cloc1.usable_abilities.can_talk          = bar.rules.can_talk          && person.can_talk;

bool cloc2.usable_abilities.can_punch         = military.rules.can_punch         && person.can_punch,
     cloc2.usable_abilities.can_kick          = military.rules.can_kick          && person.can_kick,
     cloc2.usable_abilities.can_drink         = military.rules.can_drink         && person.can_drink,
     cloc2.usable_abilities.can_sit           = military.rules.can_sit           && person.can_sit,
     cloc2.usable_abilities.can_shoot_guns    = military.rules.can_shoot_guns    && person.can_shoot_guns,
     cloc2.usable_abilities.can_talk          = military.rules.can_talk          && person.can_talk,
     cloc2.usable_abilities.can_shoot_cannons = military.rules.can_shoot_cannons && person.can_shoot_cannons;

A classical example where bit-patterns and bitwise operator are used is in Unix/Linux file system permissions.


In the case of:

if (obj != null && obj.Property == true) { }

would work as expected.

But:

if (obj != null & obj.Property == true) { }

could potentially throw a null reference exception.


Short and simple:

1 && 2 = true
because
1 = true (non-zero) in C
2 = true (non-zero) in C

true ANDS logically with true to give true.

But

1 & 2 = 0 = false
because
1 = 0001 in binary
2 = 0010 in binary

0001 ANDs bitwise with 0010 to give 0000 = 0 in decimal.

Likewise for || and | operators too...!


&& is the short circuit version of &.

If we are evaluating false & true, we already know from looking at the first argument that the result will be false. The && version of the operator will return a result as soon as it can, rather than evaluate the whole expression. There is also a similar verion of the | operator, ||.