8 ms·
I almost want two different division operations: One where 1/0 = 0, exclusively for use in progress bars and stuff like that, and another one for everything els
by bunderbunder 8y ago
I almost want two different division operations: One where 1/0 = 0, exclusively for use in progress bars and stuff like that, and another one for everything else.
Because frequently division by zero indicates a bug. But similarly frequently, I end up crapping out annoying little bits of code like
if (foo == 0):
return 0
else:
return bar / foo
- spooneybarger 8y agoWe will be introducing two sets of integer math operators in Pony. The current which are non-partial and can over/underflow + division by zero == 0 AND new ones that will be partial functions that cause an error on under/overflow and division by zero.
- gopalv 8y ago> new ones that will be partial functions that cause an error on under/overflow and division by zero. A "strict" mode is usually always an afterthought once we have errors & people run it in strict mode and facepalm. One of the first "utilities" I wrote for PHP was something called "pecl/scream", which turned off all the "unchecked" operations across the whole VM. And in general, this works out poorly for code quality.
- rhencke 8y agoPony is not 1.0 yet. The language is still malleable.
- jeremyjh 8y agoThere is no golden path here. Checked exceptions for division would make a lot of Pony code objectively worse. Unchecked exceptions are great for PHP, Haskell, Rust or Go, but Pony is trying to do something different - to literally make it impossible to panic in an operation without describing that in the type system. The ergonomics of divide by zero in this context are absolutely debatable, not an issue to dismiss out-of-hand.
- garmaine 8y agoWell, except for kernel panics and hardware errors...
- jeremyjh 8y agoYou can write user code in Pony that will cause a kernel panic or hardware error?
- spooneybarger 8y agoYes. Hardware errors, can't really protect from that or a kernel panic. A kernel panic is a panic in non-pony code.
- garmaine 8y agoIt may be forced to error as a result of one.
- mpolsz 8y ago> You can write user code in Pony that will cause a kernel panic or hardware error? You can always (as in OS with lazy allocation) allocate enough memory to get OOM no matter how safe your language is.
- ghayes 8y agoCouldn’t you alternatively introduce total operators that just grow the memory size as necessary instead of overflowing? For me if you’re handling wrapped types, I’d always prefer the numbers to grow into extra memory instead of overflowing or raising exceptions. Erlang, for instance, does this well. Obviously, division may still not be total, though you could define an operator like `//` that is.
- spooneybarger 8y agoA wrapped types library with the corresponding performance tradeoff is something I expect will be added to Pony at some point. There's definitely value in them for a variety of use cases.
- alexkavon 8y ago> But similarly frequently, I end up crapping out annoying little bits of code Isn't this reason the the point of having a utils library with commonly used pieces of code?
- azernik 8y agoThis is actually included in the IEEE754 floating point standard - there's a concept of "trapping" vs. "non-trapping" exceptions, where implementations are allowed to decide which exceptions should trap. Unfortunately, GCC only lets you enable this globally (within a program): see http://www.gnu.org/software/libc/manual/html_node/FP-Exceptions.html#FP-Exceptions http://www.gnu.org/software/libc/manual/html_node/FP-Excepti....
- simias 8y agoI'm reading the "Pony" tweet quoted in TFA and your comment and I'm left very puzzled: is that really that common to want x / 0 == 0 ? In practice where does that crop up? You say that you frequently have to write your little shim but honestly I don't remember writing code like that in recent memory. You talk about progress bars, I suppose it makes sense if you somehow try to copy 0 elements for instance, and you end up dividing by zero when computing the progress, like: pos_percent = (copied_elems * 100) / total_elems And both copied_elems and total_elems are zero. But in this case wouldn't you want the computation to return 100% instead of zero? It's also a bit odd because it introduces a discontinuity: as the divisor goes towards zero the result of the operation gets greater until it reaches exactly zero and it yields 0. Wouldn't it make more sense to return INT_MAX (for integers) or +inf for floats? If you're writing a game for instance it might work better. I guess it just goes to show that it probably makes a lot of sense to leave it undefined and let people write their own wrapper if necessary to do what works best for them in their given scenario.
- huehehue 8y agoPractically, it's quite common to not immediately know the divisor. In cases where the divisor is initially unknown but takes an imperceptible amount of time to compute it's better to render 0%. Otherwise you might get a flash of a full progress bar (for example) while the divisor is determined. Of course, it's context dependent. As others mention, your code might be full of stuff like X / (divisor || 1).
- octalmage 8y agoI’ve run into this a bit with progress related stuff. I bet if you looked at progress bar libraries they’d have similar logic built in.
- adrianratnapala 8y agoThe nicest UX would be to say something like "waiting..." while the denominator is zero. Presenting a zero to the user instead is probably an acceptable short-cut, but at the end of the day, it's a UX decision. Which is why it should be handled in explicit if-else code, that lives as close to the UI as possible, rather than being buried in the semantics of basic numerical operators.
- smallnamespace 8y agoIsn't a ternary here nicer? return (foo == 0) ? 0 : bar / foo or even return bar / max(1, foo) in the case where foo is integer or tiny foo would overflow your range anyway
- KennyCason 8y agoI would say it doesn't really matter much as both are readable. I would prefer either the original if/else or the ternary solution over the last solution as I personally think the intent is not as immediately clear in your "max" form. I would optimize for readability over density, unless there is some reason to write it differently (e.g. performance). just for fun, in kotlin (making use of expressions removes some verbosity): return where(den) { 0 -> 0 else -> num / den } return if (den == 0) { 0 } else { num / den }
- Dylan16807 8y agoTernary doesn't really look any better. I'd do this in a language that supports it though: return foo && bar / foo
- xxbgbqbq 8y agoActually, bar/foo STILL has a gotcha which can throw exception, many developers doesn't think of this. Just try INT_MIN/-1, can blow most "foolproof" divide logic away.
- mehrdadn 8y agoI've run into this a lot, but I'm also not sure what I really want to happen. Even for progress bars, the behavior can be different depending on how exactly you're obtaining the denominator -- does it increase dynamically or is it known from the beginning? Is it one of those fake progress bars that just ignores the fact that it'll stay at 100% for the next hour, or would it filling up genuinely mean that the work is actually done? After all, if you have 0 operations total and you've finished 0 of them, are you really 0% done? Wouldn't it make more sense to say you're 100% done? At the end of the day the user is trying to figure out how long they should keep waiting, to which the answer would be "you don't need to wait, there's no more work left to do".
- deleted 8y ago[deleted]
- arcticbull 8y agoRust has your back: pub fn checked_div(self, rhs: u8) -> Option<u8> Checked integer division. Computes self / rhs, returning None if rhs == 0. You would use this as lhs.checked_div(rhs).unwrap_or(your sane default) This is dramatically better than always returning zero silently, as doing so is bound to be wrong in certain cases. If you run into a situation where you are afraid your RHS may be 0 but still want to do the right thing, this is what you'd use.
- ifdefdebug 8y agoMost of the time when I have to think about what to do with a 0 divisor, I come to the conclusion that if (foo == 0): return MAX_FLOAT else: return bar / foo is more sound for the given algorithm than "return 0" (still crappy, but more sound). Then use MAX_FLOAT as an error flag instead of 0, which could have been the result of a legal operation (with bar==0).
- bluecalm 8y agoWait, when creating a progress Duke you divide in other direction: (things already done) / (all things). Can you give a specific example when it causes problems? My experience of writing code like that is that there a clearer way or I made a mistake somewhere.
- ian1321 8y agoHonest question. What is so annoying about that code? It's handling (in an application-specific manner) the special case of dividing by zero (which the `/` operator doesn't handle). I'm not sure of any other way to handle this.