Why Are Parenthesis Sometimes Required in Ruby

Why are parenthesis sometimes required in Ruby?

Because { ... } has two meanings: hash literal and block.

Consider this:

%w(foo bar baz).select { |x| x[0] == "b" }
# => ["bar", "baz"]

Here, { ... } is a block.

Now imagine that you are calling a method on the current object, so the explicit receiver is not needed:

select { |x| x[0]] == "b" }

Now imagine that you don't care about the parameter:

select { true }

Here, { true } is still a block, not a hash. And so it is in your function call:

redirect_to { action: 'atom' }

is (mostly) equivalent to

redirect_to do
action: 'atom'
end

and it is nonsense. However,

redirect_to({ action: atom' })

has an argument list, consisting of a hash.

Why does ruby require parentheses here?

In the first example, the curly braces are interpreted as delimiting a block. Since dry: true is not a legal expression, you get a SyntaxError.

Ruby - when I should use parenthesis or not when calling a function/method

There isn't an official standard for Ruby code best practices. However, a set of preferred styles has evolved in the Ruby community. It's a good idea to follow those preferred styles, just because it makes your code more easily readable by other Ruby programmers.

Nick Roz has given you a link to the style guide. I would also recommend that you consider installing and using rubocop. It will give you feedback on when and when not to parenthesize arguments, many other formatting matters such as proper indenting, and which of the often several different syntax options to choose in a particular situation.

To answer your specific question about whether or not to use parentheses for method arguments, the answer is yes, in general. Exceptions are, as the guide says, "methods that have 'keyword' status in Ruby." An example is puts (actually the Kernel.puts method). Most people don't use parentheses here, but the guide states that they are optional.

Another example, as Nick has said (although "methods with keyword arguments" isn't quite correct; in that case the arguments are symbols that represent methods rather than keywords), is attr_accessor, which is actually Module.attr_accessor.

So, as a general rule, if it looks like a "command" (a "keyword," if you will), but is actually a method, omit the parentheses. Otherwise, use them. And if you're not sure of the difference, get in the habit of using rubocop.

Why do parentheses affect hashes?

When calling a method, the opening curly bracket directly after the method name is interpreted as the start of a block. This has precedence over the interpretation as a hash. One way to circumvent the issue is to use parenthesis to enforce the interpretation as a method argument. As an example, please note the difference in meaning of these two method calls:

# interpreted as a block
[:a, :b, :c].each { |x| puts x }

# interpreted as a hash
{:a => :b}.merge({:c => :d})

Another way is to just get rid of the curly brackets as you can always skip the brackets on the last argument of a method. Ruby is "clever" enough to interpret everything which looks like an association list at the end of an argument list as a single hash. Please have a look at this example:

def foo(a, b)
puts a.inspect
puts b.inspect
end

foo "hello", :this => "is", :a => "hash"
# prints this:
# "hello"
# {:this=>"is", :a=>"hash"}

method call without parenthesis doesn't forward all arguments while with parenthesis it initializes without any arguments

I know for a fact that in Ruby, parenthesis for method calls are optional.

That is true.

I need to understand why sometimes when a method call is made with parenthesis to initialize a base class, for instance, it doesn't forward all arguments while without parenthesis it does.

Let's look at this again, this time I have emphasized the important bit in bold:

I need to understand why sometimes when a method call is made with parenthesis to initialize a base class, for instance, it doesn't forward all arguments while without parenthesis it does.

Simple: it's not a method call. The super keyword is not a method, it is a keyword, just like class, module, if, unless, while, until, for, case, rescue, yield, in, then, when, do, ensure, else, begin, do, end, etc.

Since it's not a method call, there is no reason for it to follow the rules of a method call. It follows the rules of a super expression.

In particular, you can find the rules for the super expression in Section 11.3.4 The super expression of the ISO Ruby Language Specification, specifically clauses b) 1) i)-iv) of the Semantics subsection:

  • b) Let A be an empty list. Let B be the top of ⟦block⟧.

    • 1) If the super-expression is a super-with-optional-argument, and neither the argument-with-parentheses nor the block is present, construct a list of arguments as follows:

      • i) Let M be the method which corresponds to the current method invocation. Let L be the parameter-list of the method-parameter-part of M. Let S be the set of local variable bindings in ⟦local-variable-bindings⟧ which corresponds to the current method invocation.
      • ii) If the mandatory-parameter-list is present in L, for each mandatory-parameter p, take the following steps:

        • I) Let v be the value of the binding with name p in S.
        • II) Append v to A.
      • iii) If the optional-parameter-list is present in L, for each optional-parameter p, take the following steps:

        • I) Let n be the optional-parameter-name of p.
        • II) Let v be the value of the binding with name n in S.
        • III) Append v to A.
      • iv) If the array-parameter is present in L:

        • I) Let n be the array-parameter-name of the array-parameter.
        • II) Let v be the value of the binding with name n in S. Append each element of v, in the indexing order, to A.

As you can see, super without an argument list means "pass the argument list of the original call". Whereas super with an argument list means "pass exactly this argument list". This second case is described in b) 2)-4), which I will not quote here, since it pretty much says what you expect it would say.

You can also find some information in the ruby/spec project, under language/super_spec.rb:

it "without explicit arguments can accept a block but still pass the original arguments" do
SuperSpecs::ZSuperWithBlock::B.new.a.should == 14
end

it "passes along block via reference to method expecting a reference" do
SuperSpecs::ZSuperWithBlock::B.new.b.should == [14, 15]
end

it "passes along a block via reference to a method that yields" do
SuperSpecs::ZSuperWithBlock::B.new.c.should == 16
end

it "without explicit arguments passes optional arguments that have a default value" do
SuperSpecs::ZSuperWithOptional::B.new.m(1, 2).should == 14
end

it "without explicit arguments passes optional arguments that have a non-default value" do
SuperSpecs::ZSuperWithOptional::B.new.m(1, 2, 3).should == 3
end

it "without explicit arguments passes optional arguments that have a default value but were modified" do
SuperSpecs::ZSuperWithOptional::C.new.m(1, 2).should == 100
end

it "without explicit arguments passes optional arguments that have a non-default value but were modified" do
SuperSpecs::ZSuperWithOptional::C.new.m(1, 2, 3).should == 100
end

it "without explicit arguments passes rest arguments" do
SuperSpecs::ZSuperWithRest::B.new.m(1, 2, 3).should == [1, 2, 3]
end

it "without explicit arguments passes rest arguments including any modifications" do
SuperSpecs::ZSuperWithRest::B.new.m_modified(1, 2, 3).should == [1, 14, 3]
end

it "without explicit arguments passes arguments and rest arguments" do
SuperSpecs::ZSuperWithRestAndOthers::B.new.m(1, 2, 3, 4, 5).should == [3, 4, 5]
end

it "without explicit arguments passes arguments and rest arguments including any modifications" do
SuperSpecs::ZSuperWithRestAndOthers::B.new.m_modified(1, 2, 3, 4, 5).should == [3, 14, 5]
end

it "without explicit arguments that are '_'" do
SuperSpecs::ZSuperWithUnderscores::B.new.m(1, 2).should == [1, 2]
end

it "without explicit arguments that are '_' including any modifications" do
SuperSpecs::ZSuperWithUnderscores::B.new.m_modified(1, 2).should == [14, 2]
end

Why does Ruby sometimes throw an error when a function is called with a space before the parentheses?

Using Ruby 2.6.3 I get the following warning when run with ruby -w.

test.rb:1: warning: parentheses after method name is interpreted as an argument list, not a decomposed argument

This is referring to Array Decomposition where you can unpack the elements of an Array argument into individual variables.

def bar((a,b))
puts "a: #{a}, b: #{b}"
end

# a: first, b: second
bar ['first', 'second', 'third']

What's wrong with def foo (i)? def foo i is legal; parenthesis around the arguments are optional. However def foo (i) is ambiguous. It can be interpreted as a single argument def foo(i) or an array decomposition def foo((i)).

Because this is ambiguous, different interpreters may have different... interpretations. /p>

Ruby parentheses around arguments in a method definition

Another example is when you want to pass a hash as an argument such as to

This does not work:

MyTable.update_all { col_a: 1, col_b: 2 }

because the { } is for a block rather than a hash

Adding the parens does work.

MyTable.update_all({ col_a: 1, col_b: 2 })

In the case of update_all, it takes up to 3 hashes as arguments, so it's important to indicate which values go into which hash.

No Parenthesis in Rails - Good Style?

The downvotes are probably because SO is technically not a good forum for this kind of question - apparently SO community likes clear, answerable, discrete, objective questions, not more general style or technique questions like this. But I love questions like these, so here goes.

Since working with Ruby various little style questions like this drive me absolutely crazy, which is stupid because they're not that big of a deal. But the Ruby community seems obsessed with style questions, maybe it just comes with the territory of having an extremely expressive language.

My answer:

I try to orient everything around making my code as intelligible as possible, without making it unreasonably long. If I'm struggling between two styles, I'll almost always come down on the style that I think will be easier for a more novice developer to understand in the future.

I omit parentheses when either there's no arguments, or when the argument "flows naturally" after the method name. So if the method is describing an action and the first parameter is the object of that method, it's beautiful to omit the parentheses. Like this:

create :user, name: "Topher"
raise "Problem!" unless @thingy.is_a? String
render partial: "filters"

But often the first parameter of the method is a hash of options or is an incidental value or something other than "the object of the action being taken". In these cases, I usually find it looks wrong / jarring to leave out the parentheses. Like in these cases:

@user.disable!(force: true)
@entries.paginate(page: params[:page])

And of course, if you're chaining methods together (like building up an ActiveRecord call), you need to include the parentheses if any params are present, so the question becomes moot.

A more general answer:

If you haven't already, read the Ruby style guide, from start to finish, a couple times. Some rules will appeal to you, some will repulse you, but exposing yourself to it will get you familiar with the styles and patterns used by many many other Rubyists (who debate about those styles ad nauseum) and when you're confronted with similar situations, you'll be more conscious of the different ways to approach it and what tradeoffs of those different styles might be.

Parenthesis for arguments before blocks

This is related to the fact that {...} sometimes delimits a block and sometimes a Hash literal. Disambiguating those two uses has some odd side-effects.

If you use do...end, it works without the parentheses:

test 50 do |x| x*x + 2 end


Related Topics



Leave a reply



Submit