Friday, November 30, 2007

Ruby, modulus operator and POLS


Since I started my Ruby learning process, one of the most basic and important things I consider, is the POLS (Principle of the Least Surprise).

This week, a new question about “string pattern formatting”, came up on the forum.

Considering this code:

'%0.2f' % ((f.to_f - 32) / 9 * 5)

Which is the meaning of the second “%” ?

After some research, I found two options on that “formatting” subject.

  1. You can format your data immediately, using the printf method.

f = -123.12345

puts sprintf('%0.3f', f)

  1. You can create a template, and interpolate data with it later.

template = '%s, has always been in %s with %s.'

puts template % ['Oceania', 'war', 'Eurasia']

puts template % ['Luke Skywalker', 'love', 'Leia Organa']

OK, there is a nice functionality, but about POLS ?

For sure I have little experience with Ruby, but the fact, you can use the modulus operator over strings, really surprises-me.

I deal with a great assort of programming languages over 2 decades now, and never ever, applied the modulus operator over strings.

Think about this code:

puts 'abc' % 'def' # <= 'abc'

puts 'abc' % 10 # <= 'abc'

And there is another point. Negative numbers:

Witch should be the -5 % 3 result ? 2 ? -2 ?

In fact in Ruby, -5 % 3 = 1

Why ?

Some programming languages adopt the C89 standard about that subject. That is the way Ruby does:

remainder = a % n

is the same of:

remainder = a - n * floor_funtion(a / n)

where floor_function from a decimal value, returns the highest integer, less than or equal to it.

So, in Ruby this is the formula for modulus remainder result:

r = ((a) - ((n) * ((a) / (n))))

* Extra parenthesis, to put negative values easily and clear.

Ahh, take a look at those SuperRubyBoy's operators !

3 comments:

ste said...

You have to keep in mind that in Ruby there are NO operators... just method calls (or rather, messages) "masked" as operators (with the possible exception of the ternary ?: operator).
"abc" % 10 is just syntax sugar for "abc".%(10), just like 1 + 2 is equivalent to 1.+(2) and so on.
Given that, the truth is that you're NOT applying the "modulus" operator to a string, you're just calling a regular method which happens to have a "special" name.
If your really want to bend your mind have a look at this: http://jicksta.com/articles/2007/08/29/superators-add-new-operators-to-ruby

MarcRic said...

Thanks ste,

That is the reason of this blog. To force myself into Ruby thinking way.

Now I realize that I miss something on this Ruby translated formula:

r = ((a) - ((n) * ((a) / (n))))

It is not working with decimals.

Could You help ?

Anonymous said...

-5 mod 3 = 1 because -5 = 3(-2) + 1.