How does this create a proc object? - ruby

def makeProc(&obj)
obj
end
puts makeProc{|x,y| x+y}.class
How does obj become a Proc type when a block is passed to it as reference? Is there any reason or it is like some kind of ruby magic?

The & ampersand unary prefix sigil in a parameter list denotes a so-called "block parameter". It basically means something like "wrap the block argument in a proper Proc object and bind it to this parameter name".
Remember: blocks are supposed to be syntactically and semantically lightweight, and one way in which they achieve this, is that they aren't objects and can't be named. The result of this is that you can only do three things with blocks:
ignore them
yield to them
check if a block was passed (using block_given?)
That's it. If you want to do anything beyond that, you need a) an object and b) a name, which is what the & ampersand unary prefix sigil does.
In an argument list, the & ampersand unary prefix operator does the inverse: it unwraps a Proc object into a block (or, if the object is not a Proc already, it sends it the to_proc message to convert it into a Proc).

Related

To which level returns a return inside a Proc Object in Ruby?

As I understood return inside a Proc terminates the current method. So in the following example I would expect to see:
a1 > b1 > proc > a2. But actually it never reaches a2, why?
def a
puts "a1"
l = Proc.new {puts "proc"; return}
b l
puts "a2"
end
def b x
puts "b1"
x.call
puts "b2"
end
a
As a general rule, return always returns from the closest lexically enclosing method definition expression.
In this case, the closest lexically enclosing method definition expression is def a, therefore, return returns from a.
It does not actually matter that the return is inside a block in this case. The general rule is, well, general, so it applies regardless of where the return appears.
If we look more specifically at blocks, though, we can see that it still makes sense: in blocks, local variables are captured lexically, self is captured lexically, so it makes sense that return also behaves lexically. It is a general property of blocks that if you want to understand what is going on in a block, you only need to look lexically outwards.
And if we get even more specific, first going from the general rule to blocks, and now from blocks to Procs, the behavior still makes sense: a Proc is essentially a reified block, so it makes sense for a Proc to behave like a block.
There are some exceptions, though, to the general rule, and one important one are lambdas. Talking about lambdas in Ruby is always a little bit weird because lambdas are Procs but they behave differently from Procs. IMO, lambdas should have a separate class alongside Procs. Since lambdas are Procs, it makes it weird to talk about the differences between lambdas and Procs which are not lambdas (which don't have a standardized name and thus are confusingly also called Procs).
The behavior of a lambda differs from the behavior of a non-lambda Proc in two ways, one of which is relevant to your question:
Parameter binding in non-lambda Procs has the same semantics as parameter binding in blocks, whereas parameter binding in lambdas has the same semantics as parameter binding in message sends / method invocations.
In non-lambda Procs, return returns from the closest lexically enclosing method definition expression, just like in blocks, whereas in lambdas, return returns from the lambda itself, just like return in methods.
So, in both of these aspects, non-lambda Procs behave like blocks and lambdas behave like methods. I memorize it like this: "Proc" rhymes with "block" and both "lambda" and "method" are Greek.
As you probably know, there are some methods which also alter the behavior of blocks that are passed to them. E.g. instance_eval and instance_exec change the value of self, and define_method actually does change the behavior of return.
But since you didn't ask about blocks in general, and also didn't ask about lambdas specifically, and there are no reflective methods in your question, the general rules still applies to non-lambda Procs like the one shown in your question: return returns from the closest lexically enclosing method definition expression.

why proc doesn't need to have a default value if it is an optional argument in ruby

In ruby, if an argument is optional, we should give this argument an default value in the definition, the definition is like below:
def my_function(var = 1)
end
However, if I have a function definition like below, it looks like this function should receive one argument and this argument is a proc, my question is why there is no error if this method is called without a parameter? If this proc argument is optional, why it has no default value?
def my_function(&prc)
end
p my_function
In Ruby, every method implicitly has a single optional block parameter. The & unary prefix ampersand sigil means "take the block that was passed as an argument, roll it up into a Proc object, and bind it to this parameter". Since every block parameter is always optional, and there can be only one, there is no need to explicitly mark it as optional. We already know it is.

Giving parameters to ampersand block

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)?
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.

Ruby difference between send and instance_eval?

I know send takes string or symbol with arguments while instance_eval takes string or block, and their difference could be apparent given receivers.
My question is what the 'under the hood' difference is for the example below?
1234.send 'to_s' # '1234'
1234.instance_eval 'to_s' # '1234'
From the fine manual:
send(symbol [, args...]) → obj
send(string [, args...]) → obj
Invokes the method identified by symbol, passing it any arguments specified. [...] When the method is identified by a string, the string is converted to a symbol.
and for instance_eval:
instance_eval(string [, filename [, lineno]] ) → obj
instance_eval {| | block } → obj
Evaluates a string containing Ruby source code, or the given block, within the context of the receiver (obj). In order to set the context, the variable self is set to obj while the code is executing, giving the code access to obj’s instance variables.
So send executes a method whereas instance_eval executes an arbitrary block of code (as a string or block) with self set to the object that you're calling instance_eval on.
In your case, there isn't much difference as the string you're handing to instance_eval is just a single method. The main difference is that anyone reading your code (including you in six months) will be wondering why you're using instance_eval to call a single method.
You might also be interested in Object#public_send and BasicObject#__send__
Whatever you can do with send is a proper subset of that of instance_eval. Namely, the argument to send has to be a single method (and its arguments), whereas the argument to instance_method is an arbitrary code. So whenever you have send, you can rewrite it with instance_eval, but not vice versa.
However, performancewise, send is much faster than instance_eval since there is no additional parsing required to execute send, whereas instance_eval needs to parse the whole argument.
In your example, the result will be the same, but the first one will run faster.

What does the end.method do in Ruby?

I've seen code like this:
def some_method
# ...
end.another_method
What does the end.another_method part do?
I believe that your example is wrong, as what you are doing here is defining a method and calling a method on the result of a method definition (not a method call), which is always (usually?) nil.
There's a similar form which fmendez is referring to, but end is the end of a block, not a method definition in that case.
So, for example:
array.map do |element|
element * element
end.sum
would, hypothetically, return a sum of squares of elements of given array.
But, if you are doing method chaining like this, it is more common to use bracket style blocks instead of do..end, so the above example would read:
array.map{ |element|
element * element
}.sum
Blocks in Ruby are method arguments, not unlike any other method arguments (apart from the dedicated syntax), so putting dot after end is not different than putting the dot after ) in
'hello'.concat(' world!').capitalize
Which is also an example of method chaining.
In Ruby, the . is the message sending operator. (In other languages, it would be called a method calling operator instead.) So, when you say
foo.bar
it means "evaluate foo and send the message bar to the result of evaluating foo".
In this particular case, you are sending the message another_method to the result of evaluating
def some_method; end
The Ruby Language Specification says that the value of a method definition expression is undefined and should be ignored; and on most Ruby implementations, method definition expressions simply evaluate to nil, which isn't terribly useful.
However, on some implementations, method definition expressions do evaluate to something more useful than nil. On Rubinius, for example, they evaluate to the CompiledMethod object for the method being defined. And CompiledMethod has a rich API, so sending messages to a CompiledMethod object definitely makes sense.
It has also been proposed that method definition expressions should return a Symbol corresponding to the name of the method being defined or a Method object.
Put simply: the dot in this particular case means the exact same thing it always means in Ruby: send a message, call a method, invoke a member function, whatever you want to call it.

Resources