The Written Versions of the Logical Operators

The written versions of the logical operators

They originated in C in the header <iso646.h>. At the time there were keyboards that couldn't type the required symbols for && (for example), so the header contained #define's that would assist them in doing so, by (in our example) defining and to be &&. Of course, as time went by this became less used.

In C++, they became what are known as alternate tokens. You do not need to include anything to use these tokens in a compliant compiler (as such, the C++-ified version of the C header, <ciso646>, is blank). Alternate tokens are just like regular tokens, except for spelling. So during parsing and is exactly the same as &&, it's just a different way of spelling the same thing.

As for their use: because they are rarely used, using them is often more surprising and confusing than it is helpful. I'm sure if it were normal, they would be much easier to read, but people are so used to && and || anything else just gets distracting.

EDIT: I have seen a very slight increase in their usage since I posted this, however. I still avoid them.

When were the 'and' and 'or' alternative tokens introduced in C++?

MSVC supports them as keywords only if you use the /Za option to disable extensions; this is true from at least VC7.1 (VS2003).

You can get them supported as macros by including iso646.h.

My guess is they believe that making them keywords by default would break too much existing code (and I wouldn't be surprised if they are right).

Logical Operators, Expressions & Condition Statements (boolean values)

We know that (cppreference conversion):

  • zero value evaluates to false.
  • nonzero value evaluates to true. Any nonzero value. -3 is true. 1 is true. INT_MAX is true.

We also know about operator precedence:

  • && has higher precedence than ||
  • which means, first && is evaluated, then ||

We also know that true and false in C are just macros for 1 and 0 defined in stdbool.h, so they have the int type. C does not has "real" boolean values, only boolean _Bool type. The logical operators && || and ! evaluate to int(!) type values 1 or 0 only, see cppreference.

So:

3 && 0 || -3

is equal to:

(true && false) || true

which evaluates to 1.

!5 + !!1

The ! has higher precedence.

The value of ! operator is 1 (true) in case of zero. The value of ! operator is 0 (false) in case of nonzero expression.

So it's:

(! true) + (! (! true) )

false + true

0 + 1

1

C++ and,or,not,xor keywords

They come from C AFAIR from times when it was not known what special symbols are on the keyboard. So to have portable language they were defined so anyone can use C even if they used keyboard with no &, |, or ^ (etc.).

Nowadays when QWERTY is a standard (with AZWERTY & co. as variations) it is no longer an issue.

PS. And of course for obfuscation code competitions ;)

Need clarification on Ruby logical operators

As opposed to other languages like C, in Ruby all values except for nil and false are considered “truthy”. This means, that all these values behave like true in the context of a boolean expression.

Ruby's boolean operators will not return true or false. Instead, they return the first operand that causes the evaluation of the condition to be complete (also known as short-circuit evaluation). For boolean and that means, it will either return the first “falsy” operand or the last one:

false && 1    # => false     (falsy)
nil && 1 # => nil (falsy)
false && nil # => false (falsy)
1 && 2 # => 2 (truthy)

For boolean or that means, it will either return the first “truthy” operand or the last one:

false || 1    # => 1         (truthy)
nil || 1 # => 1 (truthy)
false || nil # => nil (falsy)
1 || 2 # => 1 (truthy)

This allows for some interesting constructs. It is a very common pattern to use || to set default values, for example:

def hello(name)
name = name || 'generic humanoid'
puts "Hello, #{name}!"
end

hello(nil) # Hello, generic humanoid!
hello('Bob') # Hello, Bob!

Another similar way to acheive the same thing is

name || (name = 'generic humanoid')

With the added benefit that if name is truthy, no assignment is performed at all. There is even a shortcut for this assignment of default values:

name ||= 'generic humanoid'

If you paid careful attention you will have noticed that this may cause some trouble, if one valid value is false:

destroy_humans = nil
destroy_humans ||= true
destroy_humans
#=> true

destroy_humans = false
destroy_humans ||= true
destroy_humans
#=> true, OMG run!

This is rarely the desired effect. So if you know that the values can only be a String or nil, using || and ||= is fine. If the variable can be false, you have to be more verbose:

destroy_humans = nil
destroy_humans = true if destroy_humans.nil?
destroy_humans
#=> true

destroy_humans = false
destroy_humans = true if destroy_humans.nil?
destroy_humans
#=> false, extinction of humanity digressed!

That was close! But wait, there is another caveat – specifically with the usage of and and or. These should never be used for boolean expressions, because they have very low operator precedence. That means they will be evaluated last. Consider the following examples:

is_human = true
is_zombie = false
destroy_human = is_human && is_zombie
destroy_human
#=> false

is_human = true
is_zombie = false
destroy_human = is_human and is_zombie
destroy_human
#=> true, Waaaah but I'm not a zombie!

Let me add some parentheses to clarify what's happening here:

destroy_human = is_human && is_zombie
# equivalent to
destroy_human = (is_human && is_zombie)

destroy_human = is_human and is_zombie
# equivalent to
(destroy_human = is_human) and is_zombie

So and and or are really just useful as “control-flow operators”, for example:

join_roboparty or fail 'forever alone :('
# this will raise a RuntimeError when join_roboparty returns a falsy value

join_roboparty and puts 'robotz party hard :)'
# this will only output the message if join_roboparty returns a truthy value

I hope that clarifies everything you need to know about these operators. It takes a bit of getting used to, because it differs from the way other languages handle it. But once you know how to use the different options, you've got some powerful tools at hand.



Related Topics



Leave a reply



Submit