I'm new to programming, and ruby is my first real run at it. I get blocks, but procs seem like a light method/function concept -- why use them? Why not just use a method?
Thanks for your help.
Procs are objects, blocks are notA proc (notice the lowercase p) is an instance of the Proc class. This lets us call methods on it and assign it to variables. Procs can also return themselves. In contrast, a block is just part of the syntax of a method call.
There are only two main differences. First, a lambda checks the number of arguments passed to it, while a proc does not. This means that a lambda will throw an error if you pass it the wrong number of arguments, whereas a proc will ignore unexpected arguments and assign nil to any that are missing.
A proc is an object that contains a code block. It provides a way to save up a code block and execute it later. A lambda is special kind of proc (more on that later).
A Proc object is an encapsulation of a block of code, which can be stored in a local variable, passed to a method or another Proc, and can be called. Proc is an essential concept in Ruby and a core of its functional programming features.
Proc is a callable piece of code. You can store it in a variable, pass as an argument and otherwise treat it as a first-class value.
Why not just use a method?
Depends on what you mean by "method" here.
class Foo
def bar
puts "hello"
end
end
f = Foo.new
In this code snippet usage of method bar
is pretty limited. You can call it, and that's it. However, if you wanted to store a reference to it (to pass somewhere else and there call it), you can do this:
f = Foo.new
bar_method = f.method(:bar)
Here bar_method
is very similar to lambda (which is similar to Proc). bar_method
is a first-class citizen, f.bar
is not.
For more information, read the article mentioned by @minitech.
Why use procs instead of methods?
A common design pattern involves choosing a method or code block to call based on a runtime value. For example...
case 1
when 0
p :a
when 1
p :b
when 2
p :c
end
This gets kind of clunky when there are many selectors and there is no way to put the dispatch mechanism together incrementally. So instead something like this can be done:
h = [ proc { p :a }, proc { p :b }, proc { p :c } ]
h[1].call
You can also use a Hash
instead of an Array
if your keys are not a sequence of small integers. Although the clunky case-selector design pattern occurs frequently in all languages, the dispatch-table-of-procs is rarely used. Usually, it's possible to store the results themselves in the Array
or Hash
and then just index them directly. But for something complicated, calling a proc
allows the most flexibility.
As you proceed in Ruby you will find that this is the reason Ruby has blocks. Blocks are essentially methods that have been passed as a parameter to another method. This is so easy to do in Ruby and Smalltalk that it gets used all the time. You can do the same thing in C but it's too awkward to be any fun and so it is only seen in C when the code writer is losing a desperate battle with complexity.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With