Who has the highest precedence here ?

4 interesting examples using operator precedence in Ruby

In this article, we’re going to explore the following topics:

  • method 'arg' and return
  • method1 || method2 'hello'
  • variable = a or b
  • block {..} vs block do..end

Introduction

Operator precedence is a collection of rules that reflect conventions about which procedures to perform first in order to evaluate a given mathematical expression

It’s a very important layer of any programming language. It can definitely change the way of using a language.

In effect, depending on the priority given to a specific operator, keyword or method call, your program can produce unattended side effects.

In this article, we’re going to detail some idiom that can ease the readability of you code but can also lead to some undesirable side effects in Ruby.

method 'arg' and return

This idiom can ends up to an unattended side effect as the && operator has a higher precedence than the and one

produces

"method1"

Here only the call to method1 calls the p method.

Why the call to method2 doesn’t output "method2" ?

This is due to the fact that && has a higher precedence than the method2 method call when and has a lower one.

Let’s slightly modify the above example to show you how Ruby executes the content of method1 and method2

I added parens to show you how Ruby processes operations in the first example.

We can see that for method1, the and operator has a lower precedence than a method call (p 'method1' in our case).

So the method call is processed then return is called.

For method2 the && operator has a higher precedence than the p ‘method2' method call.

So because there is no parens around the parameter of the p method call then the && operator will apply a LOGICAL AND operation between ‘method2' and return first.

Then the result of this operation will be passed as parameter of the p method call.

But as return exits the method then the call to p will never be processed.

So here a solution is to use and instead of &&.

method1 || method2 'hello'

This pretty common idiom can ends up to an error raising that can be confusing if we are not familiar with the precedence rules for || or and method calls.

Let’s have a look to the following example

The method1 or method2 ‘Jim’ idiom works as expected because method1 returns a string which is not falsy.

Note that here, the or operator has a lower precedence than the method2 'Jim' method call.

So, why the call to method1 || method2 'Jim' raises a SyntaxError ?

Let’s slightly modify the above example to show you how Ruby executes the above code

As the or operator has a lower precedence than the method2 ‘Jim’ method call then there is no syntax error in this idiom. method1 is processed and as it’s not falsy then method2 ‘Jim’ is not processed due to short-circuit evaluation in Ruby.

As the || operator has a higher precedence than the method2 ‘Jim’ method call then it tries to operate a OR between method1 and method2.

The problem is that the 'Jim' string isn’t interpreted as a parameter of the method2.

There is at least 3 solutions to overcome this issue:

  • surrounding the parameter with parens: method1 || method2('Jim')
  • using the or operator instead
  • using modifier-unless keyword: method2 'Jim' unless method1

variable = a or b

Due to the fact that the assignment operator = has a higher precedence than or then this idiom can result to an unattended side effect

Here, the variable a contains the value 42 when the variable b is nil.

Let’s slightly modify the above example to show you how Ruby executes the above code

For the variable a, the || operator has a higher precedence than =.

So nil || 42 is evaluated and the result is assigned to a.

For the variable b, the or operator has a lower precedence than the = operator. So nil is assigned to b first. Then 42 is evaluated.

So here, a solution is to use || instead of or — depending on your needs.

block {..} vs block do..end

Feel free to read Block as method argument in Ruby (2mn) if you’re not familiar with blocks in Ruby

Precedence also matters with Ruby blocks.

Indeed, blocks using brackets have higher precedence than blocks using do..end.

Let’s illustrate this assertion with the following example

produces

method2 received block? true
method1 received block? false
method2 received block? false
method1 received block? true

Here, we can see that with the call to method2 using brackets syntax, the method2 receives the block and not the method1 .

In contrary, we can see that with the call to method2 using do..end syntax, the method1 receives the block and not the method2

Let’s detail what happens in the above example by adding few parens

Here, we can clearly see that for the first call to method1 the block is attached to the inner method call — method2.

For the second call to method1, we can see that the block is attached to the outer method call — method1.

So when we say that {..} block has a higher precedence than do..end block this has an influence on which method call the block will be attached to.

Voilà!

May I have your attention please 🎤🎤

Feel free to subscribe here: www.rubycademy.com


Thank you for taking the time to read this post :-)

Feel free to 👏 and share this article if it has been useful for you. 🚀

Here is a link to my last article: 2018: a year of blogging about Ruby