...and now, the thrilling conclusion, where we can totally add fractions!
WHOOPS! I made a mistake towards the end of this video, and I will remove this comment once I have shot and inserted a correction into the video itself.
When exploring the behavior of gcd() with a parameter of 0, I make a contract mistake. It happens not to hurt, but it represents a latent risk. In the most generic Fraction constructor, I assume that gcd() never returns 0, and I document that assumption with a CONTRACT comment. Moments later, when I write Learning Tests for gcd() with 0, I verify that gcd(0, 0) == 0, breaking the contract assumption that I'd just documented.
Here we have an interesting philosophical question: since Fraction(0, 0) is undefined (and not a valid value), does gcd() really break its contract with Fraction? It depends: if a contract is broken over inputs that we never use, does it matter? Fraction, by its nature, if built well, will never ask for gcd(0, 0), and so this seems like it should remain a risk and never become a problem.
Of course, as soon as I write those words, my experience reminds me that "this should never become a problem" leads inevitably to that thing becoming a problem.
So, I recommend that we change gcd(0, 0) to return 1 (the most convenient of the arbitrary answers), respecting the CONTRACT comment in Fraction's constructor. I'd like to think that, eventually, if I maintained this code on a project, I'd notice this conflict and fix it, but clearly I missed it. Distractions hurt our work. (I felt eager to produce the video, maybe.) If I had taken a moment to reflect on the work, or if I'd had a pair, then perhaps this mistake wouldn't have slipped by me (or us).
I'm sorry. Remember: when we practise TDD, we don't eliminate mistakes, even though we make them more difficult to make (or miss). In this case, we made a mistake that, at least in this situation, almost literally can't hurt. Maybe we don't need the CONTRACT comment in Fraction's constructor. At worst, that comment has the potential to point to the cause of a future problem, in case gcd() returning 0 starts to hurt us.