The Perils of Trying to be Clever
- Narrator: Tyler, you are by far the most interesting single-serving friend I've ever met... see I have this thing: everything on a plane is single-serving...
- Tyler: Oh I get it, it's very clever.
- Narrator: Thank you.
- Tyler: How's that working out for you?
- Narrator: What?
- Tyler: Being clever.
- Narrator: Great.
While working on Vittles today, I had a facepalm moment, preceded by an hour of desperate confusion. The feeling will be familiar to many programmers--testing, debugging, head-scratching, more testing and debugging, then finally the moment of realization: "Duh!"
What went wrong? Well, as is the case with many software bugs, I tried too hard to be clever. I have some Recipes, and each Recipe has some Ingredients. Both Recipes and Ingredients keep track of their nutritional information in a related model called NutritionInfo. Whenever a Recipe changes (say, it gets another Ingredient), I want to recalculate the NutritionInfo; I do that by first recalculating all the NutritionInfo for the Ingredients.
I wanted to keep track of the success or failure of each Ingredient's recalculation (indicated by a True/False status). If all Ingredient recalculations were successful, I wanted to know about it. If any one of them failed, I wanted to know that too.
At first, I considered doing something like this:
results = [ ingredient.nutrition_info.recalculate() for ingredient in all_ingredients ] success = all(results)
But to my cleverness-infested brain, this seemed like one step too many. Why not just write this?
success = all( ingredient.nutrition_info.recalculate() for ingredient in all_ingredients )
It seemed like a good idea at the time. But I soon discovered that many ingredients were mysteriously not getting their nutrition info recalculated. What could be wrong? Was some object not getting saved correctly? Was I missing some piece of data that would allow grams to be converted to cups? Finally it dawned on me--something that should have been obvious to a veteran Pythonista like myself--the all
method short-circuits on the first occurrence of False
, which means that as soon as any ingredient failed the recalculation, none of the ones after that would even be attempted.
After switching back to my initial, more-verbose-but-also-more-correct approach, it works as intended.
Moral: Cleverness doesn't always work out so well.