Just A Summary

Piers Cawley Practices Punditry

Twice now 4

Posted by Piers Cawley Wed, 25 Nov 2009 16:49:00 GMT

In Ruby, when you’re doing division on integers, things can get a little counter intuitive. For instance, 6/4 is obviously 1. At least, it is until you decide that you’d rather have numbers that behave a little more like ‘real’ numbers and you do require 'mathn', a module in the Ruby standard library (ie, it comes as part of ruby). Then you enter a whole new world of rational maths, where 6 / 4 returns 3/2.

Several very fine and useful Ruby gems rely on the workings of mathn, including ruby-units, which is a spiffy tool for avoiding problems when one team is working in kilometres and the other in miles and it’s no fun at all when your space probe is suddenly incommunicado.

Other fine and dandy Ruby gems include ultrasphinx and webrat. Both of these two (and no doubt others) rely on the the fact that 302/100 == 3.

Hmm… can you see my problem?

Please, if you’re working on a gem that you intend to publish widely, then adopt the practice of never trusting that dividing an integer by another integer will return a third integer. You’re not even making yourself a hostage to some other gem, you’re making yourself a hostage to the standard library. Always do (an_integer / another).to_i and your code will be so much more robust.

I’ve got a pull request and lighthouse ticket in for webrat and, once I’ve hit ‘publish’ on this post, I shall be doing the same thing for ultrasphinx, but I’m sure there are other gems out there with the same problems. Please people, check your assumptions.

Comments

Leave a response

  1. Ovid 6 months later:

    I’ve long thought that both Ruby and Python made a huge mistake by discarding information in integer division. This isn’t C, for cryin’ out loud! Perl, when it detects that information will be discarded, is thoughtful enough to use an SvNV (double) instead of an SvIV (int) for the result. Not discarding information should be the default. If you want integer math, it’s trivial to do so (just use the “integer” pragma), but you should explicitly request it.

    If I recall correctly, Python’s admitted the mistake and are moving away from integer math.

  2. Piers Cawley 6 months later:

    Personally, I wish Perl wouldn’t throw information away by coercing to a float unless I tell it to. I’d much rather it made a rational. And yes, I know I can make it do that.

    Smalltalk wins here, with 5 / 2 = (5/2) and 5 // 2 = 2, but then it freaks my out by spelling ‘modulo’ wrong – \\ instead of %.

  3. nicholas a. evans 6 months later:

    This sort of monkey-patching pitfalls (when one ruby library (stdlib or gem) enhances some standard routine and breaks another library somewhere completely different which never wanted anything changed) is hardly specific to integer vs rational division.

    I keep on holding out hope that the next version of ruby will have selector namespaces or file-level pragmas or something to mitigate the monkey-patching issue. But it hasn’t happened yet. :-(

  4. Moritz 5 months later:

    Well, that’s what you get for not restricting your pragmas to a lexical scope – a lesson which is often learned the hard way.

    Independently of the default, you should be able to control the behaviour somehow within your current scope (or module) without influencing anything on the outside.

Comments



Just A Summary