Nathan Worden
Nathan Worden

Reputation: 45

Are there special rules for naming and calling Procs?

I completed a Ruby challenge on Hacker Rank, but I don't understand why a Proc is able to be called with an abbreviated version of its saved name.

The proc was defined as:

proc_sum_array = proc {|arr| arr.reduce(:+)}

But it was called like this:

proc_sum.call(my_array)

...without the "_array" part of the name proc_sum_array

This confused me, so I changed 'proc_sum.call(my_array)' to 'proc_sum_array.call(my_array)' but then I got the error:

undefined local variable or method `proc_sum_array' for main:Object (NameError) 
Did you mean?  proc_sum

So it appears that it is important that the proc is called as proc_sum and not proc_sum_array, as it was named.

def square_of_sum (my_array, proc_square, proc_sum)
    sum = proc_sum.call(my_array) # QUESTION: Why is this proc_sum, and not proc_sum_array ?
    proc_square.call(sum)
end

proc_square_number = proc {|x| x ** 2}
proc_sum_array     = proc {|arr| arr.reduce(:+)} # This is where the proc is defined.
my_array = gets.split().map(&:to_i)

puts square_of_sum(my_array, proc_square_number, proc_sum_array)

I would expect that proc_sum_arry would be called as proc_sum_array.call. Why is this not the case?

Upvotes: 0

Views: 65

Answers (2)

Marek Lipka
Marek Lipka

Reputation: 51161

Ok, now as you linked actual example, I can answer you. The reason why it's referred to as proc_sum, not proc_sum_array is because it's how the argument passed into square_of_sum method is named. It's not magical at all. It's similar to:

a = 2
def sqr(b)
  b * b
end
sqr(a)

You see, you define a local variable, but you pass it as b argument in the sqr method, so inside of this method you refer to it as b.

Upvotes: 1

Jörg W Mittag
Jörg W Mittag

Reputation: 369468

This is called a parameter. A parameter is kind of like a "hole" that you leave in the definition of a subroutine. When you invoke that subroutine, you "fill" that "hole" with an argument. (This is called "passing an argument".)

Here:

def square_of_sum (my_array, proc_square, proc_sum)
#                                         ↑↑↑↑↑↑↑↑

You define a method named square_of_sum with a couple of parameters. The third one of those parameters is called proc_sum.

Here:

puts square_of_sum(my_array, proc_square_number, proc_sum_array)
#                                                ↑↑↑↑↑↑↑↑↑↑↑↑↑↑

You pass the object that is referenced by the local variable proc_sum_array as an argument to the invocation of the square_of_sum method.

What this means is that inside the body of the method, the object that you passed as an argument will be bound to the parameter (this is called binding an argument to a parameter), i.e. when you dereference the parameter proc_sum inside the body of square_of_sum, it will evaluate to whatever object was passed as an argument.

Note that proc_sum_array is a local variable (you know that it is a local variable because 1) it starts with a lowercase letter and 2) it is not a method). Local variables are called "local" variables because they are local to the scope they are defined in. In this particular case, proc_sum_array is local to the script scope, which means that it doesn't even exist inside the method scope of square_of_sum, so you simply can't refer to it at all!

Note also that this is exactly the same as for every other parameter of square_of_sum: you refer to the object that is passed as an argument for the proc_square parameter as proc_square and not as proc_square_number.

Upvotes: 3

Related Questions