Truth Value Testing

The truth value testing of RPython is similar with Python.

Any object can be tested for truth value, for use in an if or while condition or as operand of the Boolean operations below. The following values are considered false:

  • None

  • False

  • zero of any numeric type, for example, 0, 0L, 0.0.

  • any empty sequence, for example, '', (), [].

  • any empty mapping, for example, {}.

All other values are considered true — so objects of many types are always true.

Operations and built-in functions that have a Boolean result always return 0 or False for false and 1 or True for true, unless otherwise stated. (Important exception: the Boolean operations or and and always return one of their operands.)

def truth_value_testing():
    if None  or \
       False or \
       0     or \
       0L    or \
       0.0   or \
       ''    or \
       ()    or \
       []    or \
       {}:
        print("Some values are True.")
    else:
        print("None, False, 0, 0L, 0.0, '', (), [], {} are considered False.")

def entry_point(argv):
    truth_value_testing()
    return 0

def target(*args):
    return entry_point

if __name__ == "__main__":
    import sys
    entry_point(sys.argv)

Attention

However, there is one inconsistency. In Python, the following values are considered false:

  • instances of user-defined classes, if the class defines a __nonzero__() or __len__() method, when that method returns the integer zero or bool value False.

In RPython, the above values are considered true.

For example, we have two classes: ZeroLen and NonZero. They define __len__() and __nonzero__() methods respectively. Truth value testing of instances of ZeroLen and NonZero are different in RPython and Python.

class ZeroLen():
    def __len__(self):
        return 0

class NonZero():
    def __nonzero__(self):
        return False

def truth_value_testing_inconsistency():
    zero_len = ZeroLen()
    non_zero = NonZero()

    if zero_len:
        print("zero_len is True in RPython.")     # RPython
    else:
        print("zero_len is False in Python.")     # Python

    if non_zero:
        print("non_zero is True in RPython.")     # RPtyhon
    else:
        print("non_zero is False in Python.")     # Python

def entry_point(argv):
    truth_value_testing_inconsistency()
    return 0

def target(*args):
    return entry_point

if __name__ == "__main__":
    import sys
    entry_point(sys.argv)

However, the execution results are inconsistent using RPython and Python

$ rpython truth_value_testing_inconsistency.py    # compile with RPython
$ ./truth_value_testing_inconsistency-c
zero_len is True in RPython.
non_zero is True in RPython.

$ python truth_value_testing_inconsistency.py    # interpret with Python
zero_len is False in Python.
non_zero is False in Python.