Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Giving parameters to ampersand block

Tags:

methods

ruby

proc

If we have a method on a collection that takes a block with another method executed on each element, we can write it shorter using ampersand. For example: if we have an array of integers and we want to remove the odd numbers we can do this:

[1,2,3,4,5,6,7,8].reject {|x| x.odd?}

Using ampersand, we can write this:

[1,2,3,4,5,6,7,8].reject(&:odd?)

Let's say we have an array of strings, and we want to remove the elements containing 'a'. We can write the solution like this:

['abc','cba','cbc','cdc','dca','cad','dc','cc].reject {|x| x.include? 'a'}

How do we write this using the ampersand syntax (if it's possible)?

like image 366
Dmitri Avatar asked Mar 15 '23 12:03

Dmitri


1 Answers

You can't, it is not possible.

& followed by a symbol is is a shortcut for a method that does not take any arguments.

As you said,

.reject(&:odd?)

Is a shortcut for:

 .reject {|x| x.odd?}

Basically, &:SYMBOL is always a shortcut for passing a block {|x| x.SYMBOL}

The reason this works is because calling the #to_proc method on a symbol returns a lambda expression that's a one-argument lambda, which calls the method with the same name as the symbol on it's argument.

And & converts from lambda to a block argument -- but beyond that, will call to_proc on it's operand before converting it to a block argument. So it calls to_proc on the symbol, and then gets a lambda from the symbol. And then passes this as a block argument to your method.

There's no way to use that shortcut when you need a block whose body goes beyond a one-argument block which just calls the method named after a symbol on it's argument.

Just write it out as you did. Nothing at all wrong with .reject {|x| x.include? 'a'}, just write that.

like image 142
jrochkind Avatar answered Mar 23 '23 10:03

jrochkind