How to handle division by zero in a language that doesn't support exceptions?
programmers.stackexchange.com
programmers.stackexchange.com
Things like pocket calculators, Excel, and even web forms, will cough up a lung and quit when they hit an exception. So I think that novices of today are probably amply familiar with this mode of operation, even before learning to program.
I'd definitely incline towards an immediate abort. But for processes that run overnight, presumably because they take a long time, who can say? If there's a 1 day turnaround time, and the results are so important that it absolutely must not stop, and yet inexperienced programmers are responsible for writing the code that runs... well, I'm not sure one thing is going to be a huge improvement over something else. It's probably going to end up a bit painful whatever you do.
For integers that don't have NaN/infinity values the options are less clear. Note that languages with two's complement fixed width signed types like int32 have the same problem with INT32_MIN / -1, since the result is not representable as an int32.
Just to clarify, I think you're talking about the INT_MIN / -1 case?
I think that floating-point division by zero is defined in C and C++.
And for security exploits.
Also, two's complement signed integers have an asymmetry that INT_MIN < -INT_MAX.
Therefore, I were to design a CPU today, I would add arithmetic instructions that treated INT_MIN as a NaN, thus removing the asymmetry, and giving us an integer NaN.
16 bit int values would range from -32767 to +32767, with the bit pattern now used for -32768 being NaN. You would use it for everything that isn't representable as an int (overflow, underflow, 3/2 (as opposed to 3 mod 2), etc)
Yes, that CPU would also would have instructions for doing the regular modulo 2^16 arithmetic, but 'sane ints' would help not penalize programming languages that want to do sane integer arithmetic.
If we use a single bit dedicated to signalling NaN, the overhead might be worth it. Of course, we lose half of our range in doing so.
Also, most CPUs will set an overflow bit if addition overflows or underflows. I don't see how it would be that hard to also force the result to 0b100....000 if that happens.
And 'scarce circuit space'? There are areas where that is still true, but they are getting rarer and rarer. Certainly, for desktop CPUs, x86 shows that one can waste circuit space by keeping around the classical x87 FPU logic, a few variants of SSE that one should not use anymore, a few attempts at vector units, instructions for branching hints that the CPU ignores, etc, and yet be successful.
I think the price paid for the detection of logic errors would be worth it.
You don't need to lose half your range; you can also add a bit. You only need to add a sticky overflow bit to each register, keep the arithmetic hardware as-is, and modify loads to set the sticky overflow when reading the NaN pattern, and modify writes to write 0b1000...000 when writing a register whose sticky overflow bit is set.
Hardware cost would, I think, be very small, as you would only need a bit per register, and keep memory as-is.
Given that Apple has non-wrap around ints in Swift and designs its own CPUs, it wouldn't surprise me if they added something similar or their CPUs, just as I expect them to add instructions for loading from tagged pointers (https://www.mikeash.com/pyblog/friday-qa-2012-07-27-lets-bui...)
It would increase the use of space by the circuit, but not by much. And we already have circuitry doing similar things to set the flags (zero, carry, overflow, parity...).
If you want a real-world system with a single extra bit for every value (on registers at least), see the Itanium and its NaT bit (used for speculative loads).
One more idea I didn't see is to mark the variable as "invalid". A general "this variable doesn't have a value because the program did something bad", which carries a full stack trace with itself. Then, if you ever use that value anywhere, the result is again invalid, with the new operation attempted on top (i.e. if the invalid value ever appears in an expression, the entire expression yields invalid and no function calls are attempted; an exception would be boolean operators - true or invalid is true and false and invalid is false - there may be other exceptions to that, too). Once that value is no longer referenced anywhere, you log a nice long description of the entire chain where things were wrong and continue business as usual. Maybe email the trace to the project lead or something.
Something like the Maybe monad basically. It will work with anything else that can fail, too, and you can allow people to construct their own invalids. And the program will continue to run as long as the error isn't too deep, which is what is really wanted here, I think.
A simple way to handle exceptions like that (and I didn't see it mentioned among the answers) is to return 2-tuple from the function: result value and error information. The latter could be empty, but both could be present.
Though this might be overcomplicating things, given that OP targets the language at novices.
The action to take when dividing by 0 is based on context: it is a business behavior. In my opinion, it is no different than any other business requirement (for example: passwords must be longer than 8 characters, etc.).
A language should allow a developer to configure the action to take when a division by zero occurs within a given context: the default being an exception and/or termination of program execution.
That's what NaN is.
But but but how would they ... don't worry about it, its a programming language for novices. If they knew what to do, they wouldn't be novices using a novice language anyway.
I like this design because its self limiting. If they don't understand the problem, they certainly won't understand how to fix it when it breaks anyway.
The problem with giving 3 year olds matches and knives and guns is not some weird inherent moral argument about the items, its because the kids have no idea how to fix some resulting problems and even the non-noobs can't fix some of the resulting problems. So don't give noobs the ability to shoot themselves in their foot. Its pretty simple.
Of course a logical next extension is removal of logarithms and many other math functions. Thats OK. Its a language for noobs so it doesn't have to have a full set of arithmetic. Unless this guy is implementing the next "mathematica" or "R" or similar, in which case he has big problems.
Won't it be ok that program crashes if :
1. it was likely the error was catch during a simulation before deployment
2. author of code received a mail immediately to let know something bad occurred
Such a language should probably be much bigger than our usual programming language and include at core what is usually added by dev tools (tests and notifications).
There was a discussion on HN a few days ago on "test only development" (link has been marked "dead" since then, though), that is tests that produce code. It reminds me of what "programming" a holodeck looks like in star trek : you describe what you want and computer manage to produce code that achieves it.
Without getting so far, you could ask your users to describe what data looks like in input and what it should looks like on ouput, as a core feature of the language rather than on a separated and optional layer. Then, on build, you run a "simulation" (yes, that is just testing) to ensure code behaves as expected.
And you build notifications (by mail, for exemple) as a core feature of the language too, maybe even include version control (you have to think hard how to make that user friendly for your target) in order everybody has a idea of what changed before the crash (this could be reported in notification).
When you have all of that, it does not matter if division by zero makes program crash.
If it's used in a video game with no save slots, where a crash is just going to lose lots of progress, I'd rather attempt to keep going even if there's an error, but only in release builds. Crash in debug builds to try and alert the programmer.
If it's used to save important work, where the bad divide could lead to data corruption, it's probably better to crash than risk the corruption. Although if you have the capability to ask the user what to do, that would be ideal.
If it's to develop something that handles money or lives, or is eg deployed on a satellite, not even crashing is acceptable. In that case, I'd force the language to have the user test with something like Haskell's "Maybe". For instance:
if(result = x / y) { //x / y returns an object: maybe<int>
z = result.get()
} // } else { handle division by zero case }
(edit: of course even that isn't fool-proof if the user tries hard enough to work around your safeguards. But you can't blame the language if the user is actively thwarting it.)We have two Mars rovers right now, Opportunity and Curiosity. Fittingly, these use PowerPC chips, which are in the moon rover camp: divide-by-zero is zero. Really! Go get a PowerPC Mac, do a divide-by-zero, and you just silently get zero. Solution #1 baked into the ISA. Not many people seem to have noticed, so it can't have caused too much trouble.
(Apologies for reposting my reddit comment here)
So if it's not too much work, I'd like my language to give me the option based on the type of application I want. But if it were forced to be a choice, I'd probably err on the side of safety.
Imagine my surprise when I did a release build for the first time and realized what I'd done :)
But this is generally the kind of thing that happens when you turn a blind eye to errors somewhere where that's not a good way to go. In gamedev, sure, nobody cares, but if you're dealing with crypto and security-sensitive stuff, well, what I did was very, very bad. It's a small proof-of-concept pet project, but if I was ever to release something like that to the public, it would be very irresponsible of me.
Its commerce, and 'just in time' and 'just good enough' is all that sells.
Other technologies designed to render content for web browsers do this also, such as javascript and the django template rendering engine.
https://mail.mozilla.org/pipermail/rust-dev/2014-June/010363...
In order to work with infinitesimals in any reasonable way, you have to define how they work. There is a reasonable way to extend the real numbers in a larger field containing infinitesimals. Such a field is non-Archimedean and has very surprising properties: for example, you can construct a geometry in which Euclid's fifth postulate is false, and yet the angles on a triangle still always add up to 180. These fields also allow you to formalize your intuition about the way infinitesimals like "dx" and "dy" in calculus and analysis work: you can take an equation and multiply both sides by dx, for example. This is ordinarily meaningless, since the term dy/dx is ordinarily just notation that does not actually signify a fraction. In non-standard analysis, it IS a fraction. I think it's a shame that analysis classes in college don't use non-Archimedean fields because the proofs are so much simpler.
However, even in these fields which admit infinitesimals, there is no definition for x/0. You can prove it for yourself.
Suppose x = 10/0.
0*x = 10
(0+0)*x = 10
0*x + 0*x = 10
10 + 10 = 10
20 = 10
So this is just an all-around bad idea, because it permits us to say that 10 = 20. And all we had to say that 10/0 had a value... we didn't even say what that value was.P.S. Although infinitesimals exist, non-standard analysis still does not permit you to, say, plug ∞ into an equation, because there are many different infinite numbers. However, other systems (projective geometry) admit ∞ as a value.
I think it should be possible with appropriate precedence of the evaluation rules?
No, seriously. Quit while you're ahead. Now that you know that dividing by zero and getting a result is not a logically consistent proposition, you can stop trying. That's the awesome thing about logic: once you PROVE something is impossible, you're done.
In combinatorial game theory, the star game is fuzzy with zero: not less or greater, but not equal either.
The zero game is (iirc) the game where neither the left nor the right player have any moves, so whoever's turn it is loses.
The star game (*) is iirc the game where both players have the move to move to the zero game, so whoever starts wins.
But the star game is fuzzy with the zero game, less than the 1 game, and more than the -1 game.
Iirc.
result, err := x / y
if err != nil {
do something
}let x = 1231231 let z = 0
if z == 0 { println("Cant divide by zero") } else { println(x / z) }
But swift doesn't support exceptions either. :/
If when faced with a problem you say "I know, I'll make my own computer language!" Now you have 2 problems.