Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the precedence of method calls with and without parentheses?

Previous answers

The answer to a similar question is wrong.

Method calls are mentionned neither in Ruby documentation nor in the community wiki.

Method call without parentheses

Higher than or

or seems to have a lower precedence than a method call without parentheses :

puts false or true

is equivalent to

( puts false ) or true

and displays false.

NOTE: I know or shouldn't be used. Still, it's a good example to show that some operators do have lower precedence than method calls.

Lower than ||

puts false || true

is equivalent to

puts (false || true)

and displays true.

Method call with parentheses

The parentheses used for method call don't seem to be grouping :

puts(false or true)
# SyntaxError: unexpected keyword_or
puts((false or true))
#=> true

Question

Where should method calls with and without parentheses be in this precedence table?

Bounty clarification

I'm looking for the exact location of method calls in the table. Preferably with examples proving it's lower than the previous one and higher than the next one.

The current answers also don't seem to mention method calls with parentheses.

Thanks in advance!

like image 223
Eric Duminil Avatar asked Dec 24 '16 12:12

Eric Duminil


People also ask

What is the difference between calling a method with no parenthesis?

the difference is that calling it with no parenthesis is your just calling the method but not the value of that method and calling it with parenthesis your calling the value of that method

What is the difference between callback and parenthesis?

Callback is a more advanced topic but it is good to keep in mind as we go along. the difference is that calling it with no parenthesis is your just calling the method but not the value of that method and calling it with parenthesis your calling the value of that method

Can you have parentheses after returnbalance in a method?

Create a method called askTeller within the Person class that returns the returnBalance method. This means that it returns the method itself and NOT the result of calling that method. So you should NOT have parentheses after returnBalance. If I fire up my console and key in the following function (or method, depending where it is used)…

What is the Order of precedence in Rexx?

The REXX order of precedence usually causes no difficulty because it is the same as in conventional algebra and other computer languages. There are two differences from common notations: The prefix minus operator always has a higher priority than the power operator. Power® operators (like other operators) are evaluated left-to-right.


2 Answers

Prelude

This aims to test all possible scenarios.

Note that when saying "operator X has higher precedence than method invocation" what is meant is in arguments. Aka:

invocation foo X bar

as opposed to (call on object)

X invocation

As far as the second case is concerned, method calls always have higher precedence.


Short answer

It doesn't fit:

  • It causes SyntaxError in some cases
  • It has higher precedence than rescue, but lower than assignment

Summary

  • not can't be used after method invocation regardless of brackets
  • Using brackets (()) with method invocations sometimes causes a SyntaxError. These cases are: and, or, if, unless, until, while and rescue
  • In cases when brackets don't cause an error, they don't change the precedence in any way
  • All operators, except for and, or, postfix if, unless, until, while, rescue have higher precedence than method invocation

Lets try it:

class Noone < BasicObject
  undef_method :!

  def initialize(order)
    @order = order
  end

  def method_missing(name, *args)
    @order << name
    self
  end
end

First unary:

# + and - will become binary
unary_operators = %i(! ~ not defined?)

puts 'No brackets'
unary_operators.each do |operator|
  puts operator

  order = []
  foo = Noone.new order
  bar = Noone.new order
  begin
    eval("foo.meta #{operator} bar")
  rescue SyntaxError => e
    puts e
  end
  p order
  puts '-----------'
end

puts 'Brackets'
unary_operators.each do |operator|
  puts operator

  order = []
  foo = Noone.new order
  bar = Noone.new order
  begin
    eval("foo.meta(#{operator} bar)")
  rescue SyntaxError => e
    puts e
  end
  p order
  puts '-----------'
end

Points taken:

  • not after a method invocation is a SyntaxError
  • all unary operators have higher precedence than method invocation regardless of brackets

Now binary:

binary_operators = %i(
  **
  * / %
  + -
  << >>
  &
  | ^
  > >= < <=
  <=> == === =~
  .. ...
  or and
)

puts 'No brackets'
binary_operators.each do |operator|
  order = []
  foo = Noone.new order
  bar = Noone.new order
  baz = Noone.new order
  begin
    eval("foo.meta bar #{operator} baz")
  rescue SyntaxError => e
    puts e
  end
  p order
end

puts 'Brackets'
binary_operators.each do |operator|
  order = []
  foo = Noone.new order
  bar = Noone.new order
  baz = Noone.new order
  begin
    eval("foo.meta( bar #{operator} baz)")
  rescue SyntaxError => e
    puts e
  end
  p order
end

Points taken:

  • brackets around method invocation with and or or is a SyntaxError
  • we have to test and and or further without brackets
  • .. and ... call <=>. We have to test this further
  • we couldn't test a few other binary operators this way, namely &&, ||, ==, !=, modifier rescue, if, unless, until, while
  • other than the above mentioned, operators have higher precedence, regardless of brackets

def yes
  puts 'yes'
  true
end

def no
  puts 'no'
  false
end

def anything(arg)
  puts 'Anything'
  arg
end

anything yes and no
anything no or yes
anything yes && no
anything no || yes
anything(yes && no)
anything(no || yes)

anything yes == no
anything(yes == no)
anything yes != no
anything(yes != no)

Points taken:

  • and and or have lower precedence without brackets
  • &&, ||, == and != have higher precedence regardless of brackets

def five(*args)
  p args
  5
end

five 2..7
five(2..7)
five 2...7
five(2...7)

Points taken:

  • .. and ... have higher precedence regardless of brackets

anything yes if no
anything(yes if no)
anything no unless yes
anything(no unless yes)

anything no until yes
anything(no until yes)
anything yes while no
anything(yes while no)

Points taken:

  • brackets with if, unless, until, while cause a SyntaxError
  • all of the above have lower precedence than method invocation without brackets

def error
  puts 'Error'
  raise
end

anything error rescue yes
anything(error rescue yes)

Points taken:

  • brackets around rescue cause a SyntaxError
  • rescue has lower precedence if no brackets are present

Ternary:

anything yes ? no : 42
anything(yes ? no : 42)

Points taken:

  • ternary has higher precedence regardless of brackets

Assignment (left for last as it changes yes and no):

anything yes = no
anything(no = five(42))

Points taken:

  • Assignment has higher precedence than invocation

Note that += and the like are just shortcuts for + and = so they exhibit the same behaviour.

like image 169
ndnenkov Avatar answered Oct 25 '22 07:10

ndnenkov


In Ruby, method call precedence seems to be lower than defined? but higher than or.

For example:

puts defined? true
#=> true

puts false or true
#=> prints `false` and returns `true`

Note: puts(not true) and puts(false or true) raise syntax errors.

like image 22
Fede Avatar answered Oct 25 '22 09:10

Fede