You shouldn’t use truthy tests

I hate truthy tests, and I don’t think you should use them, and I oppose them whenever they appear in a Pull Request.

Why? Because in my experience, more bugs arise from broken truthy tests than from any other class of error. And the bugs from broken truthy tests can also be the worst to track down.

If you don’t know what I mean by a truthy test, it’s this (in Python, but we’ll look at some other languages in a moment):

if some_variable:
do_something()

This asks whether some_variable evaluates to true before carrying out some conditional action.

It’s that word evaluates where all the problems with truthy tests arise. See, some conditions really are true or false, like this:

my_var = True
if my_var: do_something()

my_var really is true because we literally just set it to True.

What about these:

my_var = 0
my_var = 74
my_var = 0.0
my_var = ""
my_var = "false"
my_var = []
my_var = {}

Some of those evaluate to true and others evaluate to false. Here’s a page that tells you which Python values are equivalent to false.

Bugs arise because these things really aren’t the same and attempts to treat them the same necessarily opens the door to unexpected behaviours.

Here’s a short, easy example from JavaScript. It’s common, when passing parameters to a function, to default them like this:

function whatever(params) {
var myparam = params.myparam || 1;
}

This sets myparam to whatever you pass in, and if you don’t pass something in, then it gets set to 1.

Challenge: set myparam to 0.

Solution: you can’t.

The truthy test in JavaScript, of course, treats 0 as false, so the initial test is failed, and myparam is set to 1. This pattern is really meant to check whether params.myparam is undefined (i.e. not specified) which also evaluates to false, but it also catches all other actual values which evaluate to false.

The correct way to do this should be:

function whatever(params) {
var myparam = params.hasOwnProperty("myparam") ?
params.myparam : 1;
}

That is: if we really meant that the parameter should be undefined, then we should say so.

Nonetheless, you see the lazy, error-prone approach everywhere in JavaScript code.

Some reasons I’ve heard developers use to defend the use of truthy tests:

  • They’re quicker to write
  • Because PEP8 says so
  • They are good for when you’re not sure what kind of variable you’re dealing with (i.e. in a duck-typed language)

Let me deal with each of those as quickly as I can:

They’re quicker to write. So? Is that allowed now? I wrote this bit of software for you — it’s broken, but that was quicker than writing something that worked.

Because PEP8 says so. It doesn’t. It says under Programming Recommendations that you shouldn’t compare booleans with True or False using the == operator. That is, you can use a truthy style test where the operand is actually a boolean value.

They are good for when you’re not sure what kind of variable you’re dealing with. It is true that sometimes in a duck-typed language you are not sure what the variable actually is, and a truthy test can be a convenient way to avoid having to find out. My response would be that if you don’t know what kind of variable you are dealing with, how is spread-betting on its value going to improve matters? What if your spread isn’t wide enough? What if the function that gave you the variable uses -1 for “I don’t know the answer” rather than 0 or None or whatever else? In that case, your truthy test won’t save you. Find out what the variable is, treat it appropriately.

One complicating factor for those of us that work across multiple languages is that the rules for truthiness are not shared. As a result it’s easy to make a mistake and test for something that would work in one language but not another. We already linked to the Python list of falsy values, and here’s Ruby, here’s JavaScript, here’s PHP and here’s Perl, for starters.

You’ll see some commonality, but also some key differences. Ruby is relatively sane, for example, and only evaluates false on actual false and nil while most other languages incorporate things like the empty string and 0. Here are some really nasty ones that will definitely cause you problems in your code logic:

  • JavaScript says document.all is false — there are reasons, and they are to do with historical use of the language, rather than any kind of reason.
  • Perl and PHP say that the string "0" is false — if this isn’t a disaster waiting to happen, I don’t know what is.
  • In Python, a user-defined object can decide for itself whether it is truthy or falsy.
  • There’s considerable variation on whether empty lists/dictionaries are truthy or falsy.

If you work in languages where truthiness is a thing, there are a few things you can do to make people’s lives easier if you provide them with code to integrate. For example, your function shouldn’t return the empty string, when you mean false — it should return false. Or you can use exceptions when a function fails to get to a suitable return type.

Consumers of your code, in turn, should treat your function with respect. If they ask you for a list of things, they should expect that the empty list is a valid response, and check the length of that list before moving on.

So let me come back around and wrap this up. You shouldn’t use truthy tests when you don’t know for sure that you’re dealing with a pure boolean, for the following good reasons:

  • There’s no excuse not to know what kind of variable you’re dealing with. If that’s because the function that gave you the variable is vague, then that function sucks and should be fixed. If you can’t fix the function, tough, you still need to figure it out.
  • The empty string, "0", 0 false, an empty list, document.all or whatever are not the same, and treating them the same is a bad idea.
  • It’s such a significant source of bugs, you’ll save yourself time in the longer term by not doing it.

And perhaps most importantly:

Being specific about what you’re testing for is excellent, self-documenting, clean code that future developers will thank you for.

So, seriously. Don’t use them.

Richard is Founder and Senior Partner at Cottage Labs, a software development consultancy specialising in all aspects of the data lifecycle. He’s occasionally on Twitter at @richard_d_jones

ITNEXT

Richard D Jones

Written by

All things data: capture, management, sharing, viz. All-round information systems person. Founder at Cottage Labs. https://cottagelabs.com

ITNEXT

ITNEXT is a platform for IT developers & software engineers to share knowledge, connect, collaborate, learn and experience next-gen technologies.

More From Medium

More from ITNEXT

More from ITNEXT

More from ITNEXT

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store