What is Proc in Ruby
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 objects are closures, meaning they remember and can use the entire context in which they were created.
Creation
There are several methods to create a Proc
- Use the Proc class constructor:
- Use the Kernel#proc method as a shorthand of ::new:
- Receiving a block of code into proc argument (note the &):
- Construct a proc with lambda semantics using the Kernel#lambda method (see below for explanations about lambdas):
*Use the Lambda literal syntax (also constructs a proc with lambda semantics):
Lambda and non-lambda semantics
- Procs are coming in two flavors: lambda and non-lambda (regular procs). Differences are:
- In lambdas, return means exit from this lambda;
*In regular procs, return means exit from embracing method (and will throw LocalJumpError if invoked outside the method);
*In lambdas, arguments are treated in the same way as in methods: strict, with ArgumentError for mismatching argument number, and no additional argument processing;
*Regular procs accept arguments more generously: missing arguments are filled with nil, single Array arguments are deconstructed if the proc has multiple arguments, and there is no error raised on extra arguments
Lambdas are useful as self-sufficient functions, in particular useful as arguments to higher-order functions, behaving exactly like Ruby methods.
Procs are useful for implementing iterators:
Inside map, the block of code is treated as a regular (non-lambda) proc, which means that the internal arrays will be deconstructed to pairs of arguments, and return will exit from the method test. That would not be possible with a stricter lambda.
You can tell a lambda from a regular proc by using the lambda? instance method.
Lambda semantics is typically preserved during the proc lifetime, including &-deconstruction to a block of code:
The only exception is dynamic method definition: even if defined by passing a non-lambda proc, methods still have normal semantics of argument checking.
This exception ensures that methods never have unusual argument passing conventions, and makes it easy to have wrappers defining methods that behave as usual.
comments powered by Disqus