Ruby Parenthesis Syntax Exception with I++ ++I

Ruby Parenthesis syntax exception with i++ ++i

There's no ++ operator in Ruby. Ruby is taking your foo++ + ++foo and taking the first of those plus signs as a binary addition operator, and the rest as unary positive operators on the second foo.

So you are asking Ruby to add 5 and (plus plus plus plus) 5, which is 5, hence the result of 10.

When you add the parentheses, Ruby is looking for a second operand (for the binary addition) before the first closing parenthesis, and complaining because it doesn't find one.

Where did you get the idea that Ruby supported a C-style ++ operator to begin with? Throw that book away.

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.

Ruby Kernel.raise method throws error when enclosing parameters in parenthesis

You probably already know that in idiomatic Ruby one would never insert a space between the end of a method and an argument list in parenthesis. Some style guides explicitly forbid it.

There's a pragmatic reason too.

1.9.2-p290 > def concat(a, b)
1.9.2-p290 > a + b
1.9.2-p290 > end

1.9.2-p290 > concat 'foo', 'bar'
=> "foobar"
1.9.2-p290 > concat('foo', 'bar')
=> "foobar"
1.9.2-p290 > concat ('foo', 'bar')
SyntaxError: (irb):27: syntax error, unexpected ',', expecting ')'

You'll encounter errors calling any method this way, not just Kernel.raise.

I'm not familiar with Ruby internals, but I would imagine the reason for this is that when a space precedes the argument list, Ruby is expecting the "no-parens" style. So of course this works:

1.9.2-p290 :035 > concat ("bar"), ("foo")
=> "barfoo"

Presumably Ruby is trying to evaluate the contents of each parenthesized expression before passing the result to the method. I'd speculate that writing raise (TypeError, "Error message") is asking Ruby to evaluate just TypeError, "Error message", which of course fails.

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.

Idiomatic use of parentheses in Ruby

I'd suggest you take a look at the community-driven Ruby coding style guide, here particularly the section on Syntax.

Omit parentheses around parameters for methods that are part of an internal DSL (e.g. Rake, Rails, RSpec), methods that are with "keyword" status in Ruby (e.g. attr_reader, puts) and attribute access methods. Use parentheses around the arguments of all other method invocations. - excerpt from the guide

class Person
attr_reader :name, :age

# omitted
end

temperance = Person.new('Temperance', 30)
temperance.name

puts temperance.age

x = Math.sin(y)
array.delete(e)

Ruby method call using round brackets throwing syntax error

You cannot pass a block with such a synatx, you would have to do something like this:

a.select(&lambda { |v| v.is_a?(Integer) })

but normally you would just do

a.select { |v| v.is_a?(Integer) }

which is the same as

a.select() { |v| v.is_a?(Integer) }

i.e the block is outside the method parameters.

You could also use the 'stabby' lambda syntax:

is_a_integer = ->(v) { v.is_a?(Integer) }
a.select(&is_a_integer)

So if you want to pass a block as an argument you need to prefix with &, but usually you would have the block outside the parameters for atheistic reasons.

Also notice the difference between these to method signatures and the way they are called:

def call(&block)
yield
end

call { 1 } # => 1

call(lambda { 1 }) # => ArgumentError

call(&lambda { 1 }) # => 1

and

def call(block)
block.call
end

call { 1 } # => ArgumentError

call(lambda { 1 }) # => 1

call(&lambda { 1 }) # => ArgumentError

This is because lambda (and Procs) are objects hence we can do #call to evaluate them, but blocks are not and can be evaluated using the yield keyword. There is more information in this blog post.

lambda { 1 }.class # => Proc

Exceptions: why does adding parenthesis change anything?

Your case 2 is the same as this:

baz = 'a'
(baz, bar = foo) rescue [1, 2]

Since foo raises an error, assignment of values to baz and bar fails, so baz remains to be "a", and bar remains to be nil, a value that was assigned during the parsing stage. Then, the assignment gets rescued, and the return value would be [1, 2].

Your case 4 is the same as this:

(baz = raise Error) rescue 1

Since the righthand side of the assignment raises an error, assignment to baz fails, and baz would remain to be nil, that was assigned during the parsing stage. Then, the assignment is rescued, and the return value is 1.



Related Topics



Leave a reply



Submit