Too Cool for Internet Explorer

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 !


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:

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.

Sitout Blog said...

I have to say that this section has been frustrating to understand......but reading what you wrote has helped me a lot. Thanks! :)

Fernando said...

Hi Ricardo, finally I understood the % concept. Thank you for your explanation!

Anonymous said...

Very Interesting!
Thank You!

Alexey Muranov said...

The string interpolation with percent and percent operator are somewhat surprising to me (i think the importance of the operation is a bit exaggerated by assigning a separate and somewhat random operator to it).

However, what is wrong with -5 % 3 being 1? It is the remainder of division of -5 by 3 (which is the unique number in the interval 0..2 congruent to -5 mod 3). Indeed:

0 <= 1 <= 2, and - 5 - 1 = - 6 is divisible by 3.