In this case, "x" gets converted to a boolean
truth value to decide which way the "if" goes. It’s up to the language to decide how this
conversion happens, so you can end up with contradictory results like this. In Python 'if "":' will give you false. But in C++ or in C, 'if ("")' will give you
true. Effective programmers need to know the rules
of their language, so let’s take a look at the rules for Python, C++ and C. As a bonus,
we’ll get to see some of the inner workings of how CPython is written. In Python, the rule is that literal True is
true, literal False and None are false, a number-like object is false if it represents
some kind of zero, and a container is false if it represents something that's empty. Everything else by default is true. This explains why Python thinks "" is false,
because it's like an empty container of characters. There are actually 2 ways that a class can
opt-out of the default true conversion though, and a lot of you might not know the second
one. The first way is the obvious one, just define
a "__bool__" magic method of the class and put in your own logic. The second way is by defining a "__len__"
magic method. Basically, if you define a length for your
class, Python assumes it’s a container. So if you return zero you get false, and anything
else you get true. But how do I know that this is the way that
it works? The rule is buried somewhere in the documentation,
but I saw the audience drop-off the last time I tried to show docs on screen, so I found
a better way. In the modern day we have Compiler Explorer
to show us where to look. Yes, Compiler Explorer works with Python,
and a number of other languages, it just shows you bytecode instead of assembly,
though for some reason it only supports up to 3.8 (hint hint). When I put a basic "if x:" into Compiler Explorer,
it shows me the bytecode instruction to look at is called POP_JUMP_IF_FALSE,
so I just need to look in Python’s source for what that code does. This file is "ceval.c" in CPython’s source. Here we see how POP_JUMP_IF_FALSE is handled:
it checks for literal True, and literal False, doing what it's supposed to do in either of
those cases, and then otherwise it calls this function
"PyObject_IsTrue" to determine whether or not the object is true or false. This function "PyObject_IsTrue" is found in
"object.c", and it's where the bulk of the real logic happens. It checks for literal True, False, and None,
and then checks to see if a "__bool__" is defined, calling it if it exists. Otherwise it checks in two places if "__len__"
is defined, calling it if it exists, or just returning 1 to signal the default true. Negative numbers here are for errors. So that’s the final answer for Python, it
uses "__bool__", then "__len__", otherwise you get the default true. What about C++? For numbers the rule is the same as Python,
zeroes are false, and everything else is true. Arrays are treated like pointers to their
first element, and pointers are treated like numbers, so a null pointer is false and all
the other pointers are true. That explains why "" literal is true in C++,
because in C++ "" literal is a single element character array, which points to some valid
nonzero memory location storing a single null-terminator. It’s not treated like an empty container
like in Python. In fact, it’s not common in C++ for a container
to have its truth value determined by whether or not it’s empty. "if (x)" doesn’t even compile for most standard
containers, like std::string or std::vector. But there are some, like std::optional, where
it does compile. By default, if you just define your own class
or struct, "if (x)" is just not going to compile. But if you want “if (x)” to work, all
you need to do is define an "operator bool()" member function. Compiler explorer shows us that this "operator
bool()" is the thing that gets called to do the conversion of "x" into a boolean for the
"if" statement. Pure C on the other hand... Well, C doesn’t do stuff for you. If it’s not a number, pointer, or array,
"if (x)" just isn’t going to compile. Define your own function, be explicit and
convert your "x" to a bool yourself. Hey everyone James Murphy here, thanks for
watching and thanks to my patrons for their support. A huge shoutout to Jameson for becoming my
very first Exponential Tier patron. Thankyou for showing your support. It means a lot to me to see my supporters
willing to support so much. Don’t forget to subscribe, comment, slap
that like button an odd number of times, ring the bell and enable notifications so you can
hear my next ramblings as soon as they come out. See you next time.