This post relies heavily on some knowledge from the functional fundamentals series, but is not an essential part of it. Read at your own peril!
A few days ago I had an interesting discussion in the Elm slack about integer division1. What should it return when dividing by 0? And how does this affect the type of division?
I thought division by 0 was simply impossible, and giving 0 as the second input to a division function should be considered an error.
As it turns out, I was wrong. Math doesn't care about dividing by 0. It doesn't even really define division. If we define division as the inverse of multiplication, we are left with a partial definition, as there is no multiplicative inverse for 0.
That means division by 0 requires some kind of special rule, which we are free to define however we want. Since we make our own definition, nobody can prove us wrong! Division by 0 could return e.g. 0, 42, ⊥, a house, Cthulhu or a black hole.
For our type system, that would mean the return type can be
(Int ∨ a), replacing
a with anything.
Something interesting: if we define division by 0 as returning 0, we get 2 nice things: a return type that is just
Int, and an additional axiom for algebra. So saying
x/0 = 0 has some motivation behind it.
While the axioms of numbers do not care what division by 0 returns, type systems do. Remember how a type system is essentially a proof?
If we use only the axioms provided for numbers, we cannot disprove the result of dividing by 0, but we cannot prove it either. Symbolically:
⊬ Int/0 = 0. Ergo division does not constitute a proof of
Int → Int → Int, but only of
Int → IntButNotZero → Int.
We can, however, decide that
Int is more than just a number, by giving it an additional axiom, such as
Int/0 = 0.
This would fundamentally change the meaning of
Int, which would no longer be isomorphic to (capped) Integer.
The discussion, therefore, is really about what
Int should be. While I've learned a lot, my opinion has remained unchanged:
- In theory, I believe we should use as small building blocks as is feasible. That means not giving
Intany additional axioms. Let people make their own type for that.2
- In practice, I expect passing
0as the divisor is almost never intentional (it hasn't been for me), so the type system should catch it.
Int return type for division makes it easier to read certain formulas, I believe that is a faulty solution to the broader problem of formula printing in programming. We have LaTeX for a reason. I've mentioned this problem in an earlier post.
Admittedly, the current tools being what they are, and time being limited, the argument that an
Int return type results in nicer formulas holds, and each language must make its own decision based on intended use.
1 Floats are a bit of a different story: their imitation of infinite precision makes a 0 float value look a lot like a limit, so
Float/0=Infinity makes a lot of sense.
2 I should note that in theory I also don't think
Int has any business being in functional programming in the first place, as it is tightly coupled to the internal workings of an ALU, making it a rather imperative sort of type.