Yuck. Division by zero is an unfortunate reality but basically nobody with mathematical background thinks that just defining x/0 = 0 is a good solution.
Often in numerical computing, getting an NaN or Inf is a blessing in that it’s a hint that your algorithm is numerically buggy, in the same way that a crash or a exception would indicate a program bug.
This approach is the numeric equivalent of a program continuing on after an undefined variable, just assuming it’s 0. That was tried by scripting languages in the 90s and these days most folks think it was a bad approach.
The divide-by-zero thing is explained here[1]. The relevant bits:
> Gleam does not implicitly throw exceptions, so throwing an exception is not an option. The BEAM VM does not have a Infinity value, so that is not an option. Therefore Gleam returns 0 when dividing by zero.
> The standard library provides functions which return a Result type for division by zero which you can use if that is more suitable for your program.
You can also use Guards[2] to prevent handle a divide-by-zero situation before you attempt it.
I know you are quoting the docs, but Gleam absolutely throws implicit exceptions, for exactly the same reason why it returns 0 when dividing: the Erlang/VM does not support Infinity/NaN, which means floating point operations can also overflow/underflow. For example, any division with a subnormal will raise:
1.0 /. 5.0e-324
Or addition between really large floats:
1.0e308 +. 1.0e308
In fact, even the `float.divide` function, which is meant to be safe, will raise:
float.divide(1.0, 5.0e-324)
In other words, most functions that returns floats have an unmapped codomain and because of how floats work, and it is not simply a matter of checking if one of the inputs is equal to 0.0.
If Gleam wants to be consistent with division, all float operations would have to return a `Result` type (which I assume would have a direct impact in both performance and user convenience). Plus `let assert` provides a hatch for any function to raise too, and that includes matching on unmapped floats:
let assert <<a:float>> = <<0x7FF0000000000000:64>>
I wouldn't call myself a person with a mathematical background, but there are those people who believe it's just fine. [0] I don't have enough knowledge to debate that, but it would seem to disprove "basically nobody". Zero is a convention, like NaN or Inf are conventions.
A problem that Gleam has here is that the Erlang runtime does not have NaN or Inf in its float type (or integer type for that matter). It could be represented with an atom, but that would require an atom and a float having the same type in Gleam, which is not something the type system can do (by design). The operator could, in theory, return a Result(Float, DivisionByZeroError), but that would make using it very inconvenient. Thus zero was chosen, and there is an equivalent function in the stdlib that returns a result instead, if you wish to check for division by zero.
> but there are those people who believe it's just fine. [0]
Just fine mathematically, but Hillel does specify that he's not comfortable with the concept from a safety perspective. The whole piece is a defence against a particular type of criticism, but he leaves wide open the question of whether it's a good idea from a PL perspective.
I have no math background but every line of code I wrote that involved a division, I just wished that division by 0 results in 0, so this actually resonated with me
Because "0" often means "show none", so when dividing by 0, I'm fine "showing none".
I'm sure it doesn't work for everybody, but I never had a specific need to deal with zero in the division that didn't result with "actually let's count it as 0"
There are several domains where 0 is different from none, for example, most computations involving rates.
Imagine that you are running some A/B tests and you want to track conversions. If one of the experiments received 10 users and had 5 conversions, you want to show 50%. If it received 10 users and had no conversions, you will show 0%.
However, if it has received 0 users, while you could show zero conversions, the correct answer is to say that you don't know the conversion rate. Because maybe, if you had had 10 users, they could have all converted, and the rate would be 100%. You simply don't know.
Same logic applies over computing ROI, interest, velocity, etc.
Agree, I'm not saying there aren't counter examples, I'm just stating that making the call of returning zero when dividing by zero it's not an insane call, there are valid reasons for doing that. It's a judgement call (and they do provide a function that does the right thing)
> In python for instance, the developer needs to be prepared to catch a divide by zero exception.
> In gleam, the same consideration is required but the implementation will just differ.
These aren't remotely the same. If a developer fails to catch an exception or a NaN then the program either crashes or returns an obviously wrong result. If a developer fails to guard against a zero returned from division then they get a number out that's wrong in subtle ways that may not be obvious until the wrong numbers are already in use somehow.
The question isn't whether you can work around the error, it's how likely you are to notice that you screwed something up before it's too late.
In Python and languages with similar behavior, a division by 0 will immediately crash your program with a pretty stack trace, showing you exactly where the problem is and how the program got there.
In languages where division by 0 produces infinity, NaN, 0 or similar, your calculation just returns a nonsensical result.
Zero is even worse than inf or NaN, as you may not even realize that there was an error in the first place, as the result of your calculation is a number and not a strange-looking value.
Defining x/0 as 0 doesn’t break anything mathematically; all the relevant field axioms have an x != 0 hypothesis so this really is undefined behavior.
Moreover, it’s actually pretty common for proof assistants to adopt the x/0 = 0 convention, as it turns a partial function into a total one! Having something like NaN or Inf is definitely a better solution in practice, but x/0 = 0 does have its merits!
Yeah you can really get yourself into trouble if you make dividing by zero zero. It's a strong indication that you have done something horribly wrong in your code upstream of that point. Why would you throw away that signal?
very very good